using System; using System.Collections.Generic; using System.Net; using System.Text.RegularExpressions; namespace LibMpc { public interface IMpc { bool IsConnected { get; } bool Connect(); event EventHandler Connected; event EventHandler Disconnected; MpdOutput[] Outputs(); MpdStatistics Stats(); } /// /// The Mpc class implements all commands for the MPD. It takes care of command building /// and parsing the response into .net objects. /// public class Mpc : IMpc { private const string TAG_ANY = "any"; private const string TAG_FILENAME = "filename"; private const string TAG_ARTIST = "artist"; private const string TAG_ALBUM = "album"; private const string TAG_TITLE = "title"; private const string TAG_TRACK = "track"; private const string TAG_NAME = "name"; private const string TAG_GENRE = "genre"; private const string TAG_DATE = "date"; private const string TAG_COMPOSER = "composer"; private const string TAG_PERFORMER = "performer"; private const string TAG_COMMENT = "comment"; private const string TAG_DISC = "disc"; private static readonly Regex STATUS_AUDIO_REGEX = new Regex("^(?[0-9]*):(?[0-9]*):(?[0-9]*)$"); private MpcConnection _connection; private IPEndPoint _server; public Mpc(IPEndPoint server) { _server = server; } /// /// Is fired when a connection to a MPD server is established. /// public event EventHandler Connected { add { ConnectedRelayEvent += value; } remove { ConnectedRelayEvent -= value; } } private event EventHandler ConnectedRelayEvent; /// /// Is fired when the connection to the MPD server is closed. /// public event EventHandler Disconnected { add { DisconnectedRelayEvent += value; } remove { DisconnectedRelayEvent -= value; } } private event EventHandler DisconnectedRelayEvent; /// /// Connection status to MPD Server. /// public bool IsConnected => _connection?.IsConnected ?? false; public bool Connect() { if (_connection == null) { _connection = new MpcConnection(_server); _connection.Connected += OnConnected; _connection.Disconnected += OnDisconnected; } if (!_connection.IsConnected) { _connection.Connect(); } return _connection.IsConnected; } private void OnConnected(object sender, EventArgs e) { ConnectedRelayEvent?.Invoke(this, e); } private void OnDisconnected(object sender, EventArgs e) { DisconnectedRelayEvent?.Invoke(this, e); } #region Admin Commands /// /// Disables an MPD output. /// /// The id of the output. /// If the action was successful. public bool DisableOutput(int id) { return !_connection.Exec("disableoutput", new string[] { id.ToString() }).IsError; } /// /// Enables an MPD output. /// /// The id of the output. /// If the action was successful. public bool EnableOutput(int id) { return !_connection.Exec("enableoutput", new string[] { id.ToString() }).IsError; } /// /// Lists all outputs of the MPD. /// /// The list of all MPD outputs. public MpdOutput[] Outputs() { MpdResponse response = _connection.Exec("outputs"); if (response.Message.Count % 3 != 0) throw new InvalidMpdResponseException(); MpdOutput[] ret = new MpdOutput[response.Message.Count / 3]; for (int i = 0; i < ret.Length; i++) { int id; string name; int enabled; KeyValuePair idLine = response[i * 3]; if (idLine.Key == null) throw new InvalidMpdResponseException("Invalid form of line " + (i * 3)); if (!idLine.Key.Equals("outputid")) throw new InvalidMpdResponseException("Key of line " + (i * 3) + " is not 'outputid'"); if (!int.TryParse(idLine.Value, out id)) throw new InvalidMpdResponseException("Value of line " + (i * 3) + " is not a number"); KeyValuePair nameLine = response[i * 3 + 1]; if (nameLine.Key == null) throw new InvalidMpdResponseException("Invalid form of line " + (i * 3 + 1)); if (!nameLine.Key.Equals("outputname")) throw new InvalidMpdResponseException("Key of line " + (i * 3 + 1) + " is not 'outputname'"); name = nameLine.Value; KeyValuePair enabledLine = response[i * 3 + 2]; if (enabledLine.Key == null) throw new InvalidMpdResponseException("Invalid form of line " + (i * 3 + 2)); if (!enabledLine.Key.Equals("outputenabled")) throw new InvalidMpdResponseException("Key of line " + (i * 3 + 2) + " is not 'outputenabled'"); if (!int.TryParse(enabledLine.Value, out enabled)) throw new InvalidMpdResponseException("Value of line " + (i * 3 + 2) + " is not a number"); ret[i] = new MpdOutput(id, name, enabled > 0); } return ret; } /// /// Returns the list of tag types the MPD supports. /// /// The list of tag types the MPD supports. public string[] TagTypes() { MpdResponse response = _connection.Exec("tagtypes"); string[] ret = new string[response.Message.Count]; for (int i = 0; i < ret.Length; i++) { KeyValuePair line = response[i]; if (!line.Key.Equals("tagtype")) throw new InvalidMpdResponseException("Key of line " + (i) + " is not 'tagtype'"); ret[i] = line.Value; } return ret; } /// /// Starts an update of the MPD database. /// /// An sequential number of the update process. public int Update() { MpdResponse response = _connection.Exec("update"); if (response.Message.Count != 1) throw new InvalidMpdResponseException("Respose message has more than one line."); int ret; KeyValuePair line = response[0]; if (!line.Key.Equals("updating_db")) throw new InvalidMpdResponseException("Key of line 0 is not 'updating_db'"); if (!int.TryParse(line.Value, out ret)) throw new InvalidMpdResponseException("Value of line 0 is not a number"); return ret; } #endregion #region Database Commands /// /// Returns all files in the database who's attribute matches the given token. Works like the Search command but is case sensitive. /// /// Specifies the attribute to search for. /// The value the files attribute must have to be included in the result. /// All files in the database who's attribute matches the given token. public List Find(ScopeSpecifier scopeSpecifier, string token) { if (token == null) throw new ArgumentNullException("token"); MpdResponse response = _connection.Exec("find", new string[] { toTag(scopeSpecifier), token }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } /// /// Returns all values found in files of the MPD for the given attribute. /// /// The attribute who's values are requested. /// All values found in files of the MPD for the given attribute. public List List(ScopeSpecifier scopeSpecifier) { MpdResponse response = _connection.Exec("list", new string[] { toTag(scopeSpecifier) }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); } /// /// Returns all values for the given attribute found in files of the MPD where another attribute matches a given value. /// /// The attribute whos values are returns. /// The attribute whos value should match a given value for the file to be included in the result. /// The value the searchTag attribute must match for the file to be included in the result. /// All values found in files of the MPD for the given attribute. public List List(ScopeSpecifier resultTag, ScopeSpecifier searchTag, string searchValue) { if (searchValue == null) throw new ArgumentNullException("searchValue"); MpdResponse response = _connection.Exec("list", new string[] { toTag(resultTag), toTag(searchTag), searchValue }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); } /// /// Returns the names of all files and directory found under the given path. /// /// The path whos subdirectories and their files are requested. /// The names of all files and directory found under the given path. public List ListAll(string path) { if (path == null) throw new ArgumentNullException("path"); MpdResponse response = _connection.Exec("listall", new string[] { path }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); } /// /// Returns the information of all files found in the given path and its subdirectories. /// /// The path of which the file information is requested. /// The information of all files found in the given path and its subdirectories. public List ListAllInfo(string path) { if (path == null) throw new ArgumentNullException("path"); MpdResponse response = _connection.Exec("listallinfo", new string[] { path }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } /// /// Returns the directory listing of the root directory. /// /// The listing of the root directory. public MpdDirectoryListing LsInfo() { return LsInfo(null); } /// /// Returns the directory listing of the given path. /// /// The path whos listing is requested. /// The directory listing of the given path. public MpdDirectoryListing LsInfo(string path) { MpdResponse response; if (path == null) response = _connection.Exec("lsinfo"); else response = _connection.Exec("lsinfo", new string[] { path }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return new MpdDirectoryListing( MpdFile.buildList(response), response.getAttributeValueList("directory"), response.getAttributeValueList("playlist")); } /// /// Returns all files in the database who's attribute matches the given token. Works like the Find command but is case insensitive. /// /// Specifies the attribute to search for. /// The value the files attribute must have to be included in the result. /// All files in the database who's attribute matches the given token. public List Search(ScopeSpecifier scopeSpecifier, string token) { if (token == null) throw new ArgumentNullException("token"); MpdResponse response = _connection.Exec("search", new string[] { toTag(scopeSpecifier), token }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } #endregion #region Playlist Commands /// /// Adds a file to the playlist. /// /// The name and path of the file to add. public void Add(string filename) { if (filename == null) throw new ArgumentNullException("filename"); MpdResponse response = _connection.Exec("add", new string[] { filename }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Adds a file to the playlist and returns the id. /// /// The name and path of the file to add. /// The id of the file in the playlist. public int AddId(string filename) { if (filename == null) throw new ArgumentNullException("filename"); MpdResponse response = _connection.Exec("add", new string[] { filename }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); if (response.Count != 1) throw new InvalidMpdResponseException("Returned more than one line for command addid."); string id = response["Id"]; if (id == null) throw new InvalidMpdResponseException("Tag Id missing in response to command addid."); int tryId = -1; if (!int.TryParse(id, out tryId)) throw new InvalidMpdResponseException("Tag Id in response to command addid does not contain an number."); return tryId; } /// /// Clears the playlist. /// public void Clear() { MpdResponse response = _connection.Exec("clear"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Returns the information of the current song. /// /// The information of the current song. public MpdFile CurrentSong() { MpdResponse response = _connection.Exec("currentsong"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.build(response); } /// /// Deletes the track with the given index from the current playlist. /// /// The index of the track to remove from the playlist. public void Delete(int nr) { MpdResponse response = _connection.Exec("delete", new string[] { nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Deletes the track with the given id from the current playlist. /// /// The id of the track to remove from the playlist. public void DeleteId(int id) { MpdResponse response = _connection.Exec("deleteid", new string[] { id.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Loads the playlist with the given name. /// /// The name of the playlist to load. public void Load(string name) { if (name == null) throw new ArgumentNullException("name"); MpdResponse response = _connection.Exec("load", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Renames a playlist. /// /// The old name of the playlist. /// The new name of the playlist. public void Rename(string oldName, string newName) { if (oldName == null) throw new ArgumentNullException("oldName"); if (newName == null) throw new ArgumentNullException("newName"); MpdResponse response = _connection.Exec("rename", new string[] { oldName, newName }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Moves a track within the playlist. /// /// The old index of the track in the playlist. /// The new index of the track in the playlist. public void Move(int oldNr, int newNr) { MpdResponse response = _connection.Exec("move", new string[] { oldNr.ToString(), newNr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Moves a track within the playlist. /// /// The id of the track to move. /// The new index of the track in the playlist. public void MoveId(int id, int nr) { MpdResponse response = _connection.Exec("moveid", new string[] { id.ToString(), nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Returns the meta data of the items in the current playlist. /// /// The meta data of the items in the current playlist. public List PlaylistInfo() { MpdResponse response = _connection.Exec("playlistinfo"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } /// /// Returns the meta data of a track in the current playlist. /// /// The index of the track in the playlist. /// The meta data of the track in the current playlist. public MpdFile PlaylistInfo(int nr) { MpdResponse response = _connection.Exec("playlistinfo", new string[] { nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.build(response); } /// /// Returns the meta data of the items in the current playlist. /// /// The meta data of the items in the current playlist. public List PlaylistId() { MpdResponse response = _connection.Exec("playlistid"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } /// /// Returns the meta data of a track in the current playlist. /// /// The id of the track in the playlist. /// The meta data of the track in the current playlist. public MpdFile PlaylistId(int id) { MpdResponse response = _connection.Exec("playlistid", new string[] { id.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.build(response); } /// /// Returns all changed tracks in the playlist since the given version. /// /// The version number. /// All changed songs in the playlist since the given version. public List Plchanges(int version) { MpdResponse response = _connection.Exec("plchanges", new string[] { version.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } /// /// Returns the ids and positions of the changed tracks in the playlist since the given version. /// /// /// /// The ids and positions of the changed tracks in the playlist since the given version as KeyValuePairs. /// The key is the index and the id is the value. /// public List> PlChangesPosId(int version) { MpdResponse response = _connection.Exec("plchangesposid", new string[] { version.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); if (response.Count % 2 != 0) throw new InvalidMpdResponseException("Response to command plchangesposid contains an odd number of lines!"); List> ret = new List>(); for (int i = 0; i < response.Count; i += 2) { KeyValuePair posLine = response[i]; KeyValuePair idLine = response[i + 1]; if ((posLine.Key == null) || (posLine.Value == null)) throw new InvalidMpdResponseException("Invalid format of line " + i + "!"); if ((idLine.Key == null) || (idLine.Value == null)) throw new InvalidMpdResponseException("Invalid format of line " + (i + 1) + "!"); if (!posLine.Key.Equals("cpos")) throw new InvalidMpdResponseException("Line " + i + " does not start with \"cpos\"!"); if (!idLine.Key.Equals("Id")) throw new InvalidMpdResponseException("Line " + (i + 1) + " does not start with \"Id\"!"); int tryPos = -1; if (!int.TryParse(posLine.Value, out tryPos)) throw new InvalidMpdResponseException("Tag value on line " + i + " is not a number."); int tryId = -1; if (!int.TryParse(idLine.Value, out tryId)) throw new InvalidMpdResponseException("Tag value on line " + (i + 1) + " is not a number."); ret.Add(new KeyValuePair(tryPos, tryId)); } return ret; } /// /// Removes the playlist with the given name. /// /// The name of the playlist to remove. public void Rm(string name) { if (name == null) throw new ArgumentNullException("name"); MpdResponse response = _connection.Exec("rm", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Saves the current playlist with the given name. /// /// The name to the save the currenty playlist. public void Save(string name) { if (name == null) throw new ArgumentNullException("name"); MpdResponse response = _connection.Exec("save", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Shuffles the current playlist. /// public void Shuffle() { MpdResponse response = _connection.Exec("shuffle"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Swaps the to tracks in the current playlist. /// /// The index of the first track. /// The index of the second track. public void Swap(int nr1, int nr2) { MpdResponse response = _connection.Exec("swap", new string[] { nr1.ToString(), nr2.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Swaps the to tracks in the current playlist. /// /// The id of the first track. /// The id of the second track. public void SwapId(int id1, int id2) { MpdResponse response = _connection.Exec("swapid", new string[] { id1.ToString(), id2.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Returns the filenames of the tracks in the given playlist. /// /// The playlist whos filename are requested. /// The filenames of the tracks in the given playlist. public List ListPlaylist(string name) { if (name == null) throw new ArgumentNullException("name"); MpdResponse response = _connection.Exec("listplaylist", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); } /// /// Return the meta data of the tracks in the given playlist. /// /// The playlist whos files meta data are requested. /// The meta data of the tracks in the given playlist. public List ListPlaylistInfo(string name) { if (name == null) throw new ArgumentNullException("name"); MpdResponse response = _connection.Exec("listplaylistinfo", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } /// /// Add a file to a playlist. /// /// The name of the playlist. /// The path and name of the file to add. public void PlaylistAdd(string name, string file) { if (name == null) throw new ArgumentNullException("name"); if (file == null) throw new ArgumentNullException("file"); MpdResponse response = _connection.Exec("playlistadd", new string[] { name, file }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Clears all tracks from a playlist. /// /// The name of the playlist to clear. public void PlaylistClear(string name) { if (name == null) throw new ArgumentNullException("name"); MpdResponse response = _connection.Exec("playlistclear", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Delete a file from a playlist. /// /// The name of the playlist /// The id of the track to delete. public void PlaylistDelete(string name, int id) { if (name == null) throw new ArgumentNullException("name"); MpdResponse response = _connection.Exec("playlistdelete", new string[] { name, id.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Moves a track in a playlist. /// /// The name of the playlist. /// The id of the track to move. /// The position to move the track to. public void PlaylistMove(string name, int id, int nr) { if (name == null) throw new ArgumentNullException("name"); MpdResponse response = _connection.Exec("playlistmove", new string[] { id.ToString(), nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Returns the meta data for all tracks in the current playlist whos attribute equals the given value. /// /// The attribute to search for the given value. /// The value to search for in the given attribute. /// The meta data for all tracks in the current playlist whos attribute equals the given value. public List PlaylistFind(ScopeSpecifier scopeSpecifier, string token) { if (token == null) throw new ArgumentNullException("token"); MpdResponse response = _connection.Exec("playlistfind", new string[] { toTag(scopeSpecifier), token }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } /// /// Returns the meta data for all tracks in the current playlist whos attribute contains the given value. /// /// The attribute to search for the given value. /// The value to search for in the given attribute. /// The meta data for all tracks in the current playlist whos attribute contains the given value. public List PlaylistSearch(ScopeSpecifier scopeSpecifier, string token) { if (token == null) throw new ArgumentNullException("token"); MpdResponse response = _connection.Exec("playlistsearch", new string[] { toTag(scopeSpecifier), token }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); } #endregion #region Playback Commands /// /// Sets the seconds to crossfade between songs. /// /// The seconds to crossfade between songs. public void Crossfade(int seconds) { MpdResponse response = _connection.Exec("crossfade", new string[] { seconds.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Starts the playback of the next song in the playlist- /// public void Next() { MpdResponse response = _connection.Exec("next"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Sets the MPD to pause or resume the playback. /// /// If the playback should be paused or resumed. public void Pause(bool pause) { MpdResponse response = _connection.Exec("pause", new string[] { pause ? "1" : "0" }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Starts the playback of the current item in the playlist. /// public void Play() { MpdResponse response = _connection.Exec("play"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Starts the playback of the item with the given index in the playlist. /// /// The index of the track in the playlist to start playing. public void Play(int nr) { MpdResponse response = _connection.Exec("play", new string[] { nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Starts the playback of the track in the playlist with the id 0. /// public void PlayId() { MpdResponse response = _connection.Exec("playid"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Starts the playback of the track in the playlist with the given id. /// /// The id of the track to start playing. public void PlayId(int id) { MpdResponse response = _connection.Exec("playid", new string[] { id.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Starts the playback of the previous track in the playlist. /// public void Previous() { MpdResponse response = _connection.Exec("previous"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Sets the MPD to random or sequential playback. /// /// If the MPD playlist should be played randomly. public void Random(bool random) { MpdResponse response = _connection.Exec("random", new string[] { random ? "1" : "0" }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Sets if the MPD should repeat the playlist. /// /// If the MPD should repeat the playlist. public void Repeat(bool repeat) { MpdResponse response = _connection.Exec("repeat", new string[] { repeat ? "1" : "0" }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Starts playback of a given song at the give position. /// /// The index of the song in the playlist. /// The number of seconds to start playback on. public void Seek(int nr, int time) { MpdResponse response = _connection.Exec("seek", new string[] { nr.ToString(), time.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Starts playback of a given song at the give position. /// /// The id of the song in the playlist. /// The number of seconds to start playback on. public void SeekId(int id, int time) { MpdResponse response = _connection.Exec("seekid", new string[] { id.ToString(), time.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Sets the output volume of the MPD. /// /// The output volume of the MPD between 0 and 100. public void SetVol(int vol) { if (vol < 0) throw new ArgumentException("vol < 0"); if (vol > 100) throw new ArgumentException("vol > 100"); MpdResponse response = _connection.Exec("setvol", new string[] { vol.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } /// /// Stops the playback of the MPD. /// public void Stop() { MpdResponse response = _connection.Exec("stop"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); } #endregion #region Misc Commands /// /// Clears the error message set in the MPD. /// public void ClearError() { _connection.Exec("clearerror"); } /// /// Returns which commands the current user has access to. /// /// The commands the current user has access to. public List Commands() { MpdResponse response = _connection.Exec("commands"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); } /// /// Returns which commands the current user does has access to. /// /// The commands the current user does has access to. public List NotCommands() { MpdResponse response = _connection.Exec("notcommands"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); } /// /// Send the password to the server allow access to the server if enabled in the MPD. /// /// The password to authorize to the server. /// If the password is valid. public bool Password(string password) { if (password == null) throw new ArgumentNullException("password"); return _connection.Exec("password", new string[] { password }).IsError; } /// /// Sends a ping command to the server and waits for the response. /// public void Ping() { _connection.Exec("ping"); } /// /// Requests the current statistics from the MPD, /// /// The current statistics fromt the MPD. public MpdStatistics Stats() { MpdResponse response = _connection.Exec("stats"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); int artists = -1; int albums = -1; int songs = -1; int uptime = -1; int playtime = -1; int db_playtime = -1; int db_update = -1; foreach (KeyValuePair line in response) { if ((line.Key != null) && (line.Value != null)) switch (line.Key) { case "artists": { int tryValue; if (int.TryParse(line.Value, out tryValue)) artists = tryValue; } break; case "albums": { int tryValue; if (int.TryParse(line.Value, out tryValue)) albums = tryValue; } break; case "songs": { int tryValue; if (int.TryParse(line.Value, out tryValue)) songs = tryValue; } break; case "uptime": { int tryValue; if (int.TryParse(line.Value, out tryValue)) uptime = tryValue; } break; case "playtime": { int tryValue; if (int.TryParse(line.Value, out tryValue)) playtime = tryValue; } break; case "db_playtime": { int tryValue; if (int.TryParse(line.Value, out tryValue)) db_playtime = tryValue; } break; case "db_update": { int tryValue; if (int.TryParse(line.Value, out tryValue)) db_update = tryValue; } break; } } return new MpdStatistics(artists, albums, songs, uptime, playtime, db_playtime, db_update); } /// /// Returns the current status of the MPD. /// /// The current status of the MPD. public MpdStatus Status() { MpdResponse response = _connection.Exec("status"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); int volume = -1; bool repeat = false; bool random = false; int playlist = -1; int playlistLength = -1; int playlistQueue = -1; int xFade = -1; MpdState state = MpdState.Unknown; int song = -1; int songId = -1; int timeElapsed = -1; int timeTotal = -1; int bitrate = -1; int audioSampleRate = -1; int audioBits = -1; int audioChannels = -1; int updatingDb = -1; string error = null; foreach (KeyValuePair line in response) { if ((line.Key != null) && (line.Value != null)) switch (line.Key) { case "volume": { int tryValue; if (int.TryParse(line.Value, out tryValue)) { volume = tryValue; if (volume < 0) volume = 0; if (volume > 100) volume = 100; } } break; case "repeat": repeat = (line.Value != null) && (line.Value.Equals("1")); break; case "random": random = (line.Value != null) && (line.Value.Equals("1")); break; case "playlist": { int tryValue; if (int.TryParse(line.Value, out tryValue)) playlist = tryValue; } break; case "playlistlength": { int tryValue; if (int.TryParse(line.Value, out tryValue)) playlistLength = tryValue; } break; case "playlistqueue": { int tryValue; if (int.TryParse(line.Value, out tryValue)) playlistQueue = tryValue; } break; case "xfade": { int tryValue; if (int.TryParse(line.Value, out tryValue)) xFade = tryValue; } break; case "state": switch (line.Value) { case "play": state = MpdState.Play; break; case "pause": state = MpdState.Pause; break; case "stop": state = MpdState.Stop; break; } break; case "song": { int tryValue; if (int.TryParse(line.Value, out tryValue)) song = tryValue; } break; case "songid": { int tryValue; if (int.TryParse(line.Value, out tryValue)) songId = tryValue; } break; case "time": int index = line.Value.IndexOf(':'); if (index >= 0) { int tryValue; if (int.TryParse(line.Value.Substring(0, index), out tryValue)) timeElapsed = tryValue; if (int.TryParse(line.Value.Substring(index + 1), out tryValue)) timeTotal = tryValue; } break; case "bitrate": { int tryValue; if (int.TryParse(line.Value, out tryValue)) bitrate = tryValue; } break; case "audio": Match match = STATUS_AUDIO_REGEX.Match(line.Value); if (match.Success) { int tryValue; if (int.TryParse(match.Result("$sampleRate"), out tryValue)) audioSampleRate = tryValue; if (int.TryParse(match.Result("$bits"), out tryValue)) audioBits = tryValue; if (int.TryParse(match.Result("$channels"), out tryValue)) audioChannels = tryValue; } break; case "updating_db": { int tryValue; if (int.TryParse(line.Value, out tryValue)) updatingDb = tryValue; } break; case "error": error = line.Value; break; } } return new MpdStatus( volume, repeat, random, playlist, playlistLength, xFade, state, song, songId, timeElapsed, timeTotal, bitrate, audioSampleRate, audioBits, audioChannels, updatingDb, error ); } #endregion private string toTag(ScopeSpecifier scopeSpecifier) { switch (scopeSpecifier) { default: throw new ArgumentException("scopeSpecifier"); case ScopeSpecifier.Any: return TAG_ANY; case ScopeSpecifier.Filename: return TAG_FILENAME; case ScopeSpecifier.Artist: return TAG_ARTIST; case ScopeSpecifier.Album: return TAG_ALBUM; case ScopeSpecifier.Title: return TAG_TITLE; case ScopeSpecifier.Track: return TAG_TRACK; case ScopeSpecifier.Name: return TAG_NAME; case ScopeSpecifier.Genre: return TAG_GENRE; case ScopeSpecifier.Date: return TAG_DATE; case ScopeSpecifier.Composer: return TAG_COMPOSER; case ScopeSpecifier.Performer: return TAG_PERFORMER; case ScopeSpecifier.Comment: return TAG_COMMENT; case ScopeSpecifier.Disc: return TAG_DISC; } } } }