diff --git a/LibMpc/Commands/Commands.Database.cs b/LibMpc/Commands/Commands.Database.cs index f09c4a7..164094a 100644 --- a/LibMpc/Commands/Commands.Database.cs +++ b/LibMpc/Commands/Commands.Database.cs @@ -1,4 +1,5 @@ -using System; +using System.Collections.Generic; +using System.Linq; namespace LibMpc { @@ -10,8 +11,8 @@ namespace LibMpc public class Database { // TODO: count - - public class Find : IMpcCommand + + public class Find : IMpcCommand>> { private readonly ITag _tag; private readonly string _searchText; @@ -24,13 +25,30 @@ namespace LibMpc public string Value => string.Join(" ", "find", _tag.Value, _searchText); - public object ParseResponse(object response) + public IDictionary>> FormatResponse(IList> response) { - throw new NotImplementedException(); + var results = new Dictionary>> + { + { "files", new List>() } + }; + + foreach (var line in response) + { + if (line.Key.Equals("file")) + { + results["files"].Add(new Dictionary { { "file", line.Value } }); + } + else + { + results["files"].Last().Add(line.Key, line.Value); + } + } + + return results; } } - public class List : IMpcCommand + public class List : IMpcCommand { private readonly ITag _tag; @@ -41,15 +59,15 @@ namespace LibMpc public string Value => string.Join(" ", "list", _tag); - public object ParseResponse(object response) + public IDictionary FormatResponse(IList> response) { - throw new NotImplementedException(); + return response.ToDefaultDictionary(); } } // TODO: findadd - public class ListAll : IMpcCommand + public class ListAll : IMpcCommand { private readonly string _path; @@ -60,9 +78,9 @@ namespace LibMpc public string Value => string.Join(" ", "listall", _path); - public object ParseResponse(object response) + public IDictionary FormatResponse(IList> response) { - throw new NotImplementedException(); + return response.ToDefaultDictionary(); } } @@ -74,16 +92,17 @@ namespace LibMpc // TODO: searchadd // TODO: searchaddpl - public class Update : IMpcCommand + public class Update : IMpcCommand { + // TODO: Extend command: < update [URI] > public string Value => "update"; - public object ParseResponse(object response) + public IDictionary FormatResponse(IList> response) { - throw new NotImplementedException(); + return response.ToDefaultDictionary(); } } - + // TODO: rescan } } diff --git a/LibMpc/Commands/Commands.Output.cs b/LibMpc/Commands/Commands.Output.cs index c644aea..490428b 100644 --- a/LibMpc/Commands/Commands.Output.cs +++ b/LibMpc/Commands/Commands.Output.cs @@ -1,4 +1,6 @@ -namespace LibMpc +using System.Collections.Generic; + +namespace LibMpc { public partial class Commands { @@ -10,7 +12,7 @@ /// /// Turns an output off. /// - public class DisableOutput : IMpcCommand + public class DisableOutput : IMpcCommand { private readonly int _outputId; @@ -21,16 +23,16 @@ public string Value => string.Join(" ", "disableoutput", _outputId); - public object ParseResponse(object response) + public IDictionary FormatResponse(IList> response) { - throw new System.NotImplementedException(); + return response.ToDefaultDictionary(); } } /// /// Turns an output on. /// - public class EnableOutput : IMpcCommand + public class EnableOutput : IMpcCommand { private readonly int _outputId; @@ -41,9 +43,9 @@ public string Value => string.Join(" ", "enableoutput", _outputId); - public object ParseResponse(object response) + public IDictionary FormatResponse(IList> response) { - throw new System.NotImplementedException(); + return response.ToDefaultDictionary(); } } @@ -52,13 +54,32 @@ /// /// Shows information about all outputs. /// - public class Outputs : IMpcCommand + public class Outputs : IMpcCommand>> { public string Value => "outputs"; - - public object ParseResponse(object response) + + public IDictionary>> FormatResponse(IList> response) { - throw new System.NotImplementedException(); + var result = new Dictionary>> + { + { "outputs", new List>() } + }; + + for (var i = 0; i < response.Count; i += 3) + { + var outputId = response[i].Value; + var outputName = response[i + 1].Value; + var outputEnabled = response[i + 2].Value; + + result["outputs"].Add(new Dictionary + { + {"id", outputId}, + {"name", outputName}, + {"enabled", outputEnabled} + }); + } + + return result; } } } diff --git a/LibMpc/Commands/Commands.Reflection.cs b/LibMpc/Commands/Commands.Reflection.cs index 45def98..68ed3c5 100644 --- a/LibMpc/Commands/Commands.Reflection.cs +++ b/LibMpc/Commands/Commands.Reflection.cs @@ -1,4 +1,7 @@ -namespace LibMpc +using System.Collections.Generic; +using System.Linq; + +namespace LibMpc { public partial class Commands { @@ -11,13 +14,18 @@ // TODO: commands // TODO: notcommands - public class TagTypes : IMpcCommand + public class TagTypes : IMpcCommand> { public string Value => "tagtypes"; - public object ParseResponse(object response) + IDictionary> IMpcCommand>.FormatResponse(IList> response) { - throw new System.NotImplementedException(); + var result = new Dictionary> + { + { "tagtypes", response.Where(item => item.Key.Equals("tagtype")).Select(item => item.Value).ToList() } + }; + + return result; } } diff --git a/LibMpc/Commands/IMpcCommand.cs b/LibMpc/Commands/IMpcCommand.cs index e15db91..008b1f2 100644 --- a/LibMpc/Commands/IMpcCommand.cs +++ b/LibMpc/Commands/IMpcCommand.cs @@ -1,10 +1,20 @@ +using System.Collections.Generic; +using System.Linq; + namespace LibMpc { - public interface IMpcCommand + public interface IMpcCommand { string Value { get; } - // TODO: Return IMpdResponse and create type-safe input. - object ParseResponse(object response); + IDictionary FormatResponse(IList> response); + } + + internal static class MpdCommandExtensions + { + public static IDictionary ToDefaultDictionary(this IList> items) + { + return items.ToDictionary(item => item.Key, item => item.Value); + } } } \ No newline at end of file diff --git a/LibMpc/Constants.cs b/LibMpc/Constants.cs new file mode 100644 index 0000000..d375ee2 --- /dev/null +++ b/LibMpc/Constants.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LibMpc +{ + public class Constants + { + public static readonly string Ok = "OK"; + public static readonly string Ack = "ACK"; + + public static readonly string FirstLinePrefix = "OK MPD "; + } +} diff --git a/LibMpc/Message/MpdMessage.cs b/LibMpc/Message/MpdMessage.cs new file mode 100644 index 0000000..3341d67 --- /dev/null +++ b/LibMpc/Message/MpdMessage.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Newtonsoft.Json; + +namespace LibMpc +{ + public interface IMpdMessage + { + IMpdRequest Request { get; } + IMpdResponse Response { get; } + } + + public class MpdMessage : IMpdMessage + { + private readonly Regex _linePattern = new Regex("^(?[A-Za-z_]*):[ ]{0,1}(?.*)$"); + private readonly IList _rawResponse; + + public MpdMessage(IMpcCommand command, bool connected, IReadOnlyCollection response) + { + Request = new MpdRequest(command); + + var endLine = response.Skip(response.Count - 1).Single(); + _rawResponse = response.Take(response.Count - 1).ToList(); + + var values = Request.Command.FormatResponse(GetValuesFromResponse()); + Response = new MpdResponse(endLine, values, connected); + } + + public IMpdRequest Request { get; } + public IMpdResponse Response { get; } + + private IList> GetValuesFromResponse() + { + var result = new List>(); + + foreach (var line in _rawResponse) + { + var match = _linePattern.Match(line); + if (match.Success) + { + var mpdKey = match.Result("${key}"); + if (!string.IsNullOrEmpty(mpdKey)) + { + var mpdValue = match.Result("${value}"); + if (!string.IsNullOrEmpty(mpdValue)) + { + result.Add(new KeyValuePair(mpdKey, mpdValue)); + } + } + } + } + + return result; + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } + } +} \ No newline at end of file diff --git a/LibMpc/Message/MpdRequest.cs b/LibMpc/Message/MpdRequest.cs new file mode 100644 index 0000000..b769b5e --- /dev/null +++ b/LibMpc/Message/MpdRequest.cs @@ -0,0 +1,17 @@ +namespace LibMpc +{ + public interface IMpdRequest + { + IMpcCommand Command { get; } + } + + public class MpdRequest : IMpdRequest + { + public MpdRequest(IMpcCommand command) + { + Command = command; + } + + public IMpcCommand Command { get; } + } +} \ No newline at end of file diff --git a/LibMpc/Message/MpdResponse.cs b/LibMpc/Message/MpdResponse.cs new file mode 100644 index 0000000..9631d44 --- /dev/null +++ b/LibMpc/Message/MpdResponse.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; + +namespace LibMpc +{ + public interface IMpdResponse + { + IMpdResponseState State { get; } + IDictionary Body { get; } + } + + public class MpdResponse : IMpdResponse + { + public MpdResponse(string endLine, IDictionary body, bool connected) + { + State = new MpdResponseState(endLine, connected); + Body = body; + } + + public IMpdResponseState State { get; } + public IDictionary Body { get; } + } + + public static class CheckNotNullExtension + { + public static void CheckNotNull(this object toBeChecked) + { + if (toBeChecked == null) + { + throw new ArgumentNullException(nameof(toBeChecked)); + } + } + } +} diff --git a/LibMpc/Message/MpdResponseState.cs b/LibMpc/Message/MpdResponseState.cs new file mode 100644 index 0000000..447c87d --- /dev/null +++ b/LibMpc/Message/MpdResponseState.cs @@ -0,0 +1,66 @@ +using System.Text.RegularExpressions; + +namespace LibMpc +{ + public interface IMpdResponseState + { + string Status { get; } + string ErrorMessage { get; } + string MpdError { get; } + bool Error { get; } + bool Connected { get; } + } + + public class MpdResponseState : IMpdResponseState + { + private static readonly Regex ErrorPattern = new Regex("^ACK \\[(?[0-9]*)@(?[0-9]*)] \\{(?[a-z]*)} (?.*)$"); + + private readonly string _endLine; + + public MpdResponseState(string endLine, bool connected) + { + _endLine = endLine; + Connected = connected; + + if (!string.IsNullOrEmpty(_endLine)) + { + if (_endLine.Equals(Constants.Ok)) + { + Status = _endLine; + Error = false; + } + else + { + ParseErrorResponse(); + } + } + } + + public bool Connected { get; } = false; + public bool Error { get; } = true; + public string Status { get; private set; } = "UNKNOWN"; + public string ErrorMessage { get; private set; } = string.Empty; + public string MpdError { get; private set; } = string.Empty; + + private void ParseErrorResponse() + { + Status = "ERROR"; + MpdError = _endLine; + + var match = ErrorPattern.Match(_endLine); + + if (match.Groups.Count != 5) + { + ErrorMessage = "Unexpected response from server."; + } + else + { + var errorCode = match.Result("${code}"); + var commandListItem = match.Result("${nr}"); + var commandFailed = match.Result("${command}"); + var errorMessage = match.Result("${message}"); + ErrorMessage = $"ErrorCode: { errorCode }, CommandListItem: { commandListItem }, CommandFailed: { commandFailed }, ErrorMessage: { errorMessage }"; + } + } + } +} \ No newline at end of file diff --git a/LibMpc/Mpc.cs b/LibMpc/Mpc.cs index a56e0b8..664f75d 100644 --- a/LibMpc/Mpc.cs +++ b/LibMpc/Mpc.cs @@ -52,148 +52,16 @@ namespace LibMpc } } - // TODO: create response type - public async Task SendAsync(IMpcCommand command) + public async Task> SendAsync(IMpcCommand command) { - var mpdResponse = await _connection.Exec(command.Value); - var respose = command.ParseResponse(mpdResponse); + var mpdMessage = await _connection.SendAsync(command); - return respose; + return mpdMessage; } - - - #region Admin Commands - /// - /// Disables an MPD output. - /// - /// The id of the output. - /// If the action was successful. - public async Task DisableOutputAsync(int id) - { - var mpdResponse = await _connection.Exec("disableoutput", new string[] { id.ToString() }); - return !mpdResponse.IsError; - } - - /// - /// Enables an MPD output. - /// - /// The id of the output. - /// If the action was successful. - public async Task EnableOutputAsync(int id) - { - var mpdResponse = await _connection.Exec("enableoutput", new string[] { id.ToString() }); - return !mpdResponse.IsError; - } - - /// - /// Lists all outputs of the MPD. - /// - /// The list of all MPD outputs. - public async Task OutputsAsync() - { - MpdResponse response = await _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 async Task TagTypesAsync() - { - MpdResponse response = await _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 async Task UpdateAsync() - { - MpdResponse response = await _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 async Task> FindAsync(ITag tag, string token) - { - if (token == null) - throw new ArgumentNullException("token"); - - MpdResponse response = await _connection.Exec("find", new string[] { tag.Value, 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. /// @@ -201,9 +69,9 @@ namespace LibMpc /// All values found in files of the MPD for the given attribute. public async Task> ListAsync(ITag tag) { - MpdResponse response = await _connection.Exec("list", new string[] { tag.Value }); + MpdResponse response = await _connection.SendAsync("list", new string[] { tag.Value }); - if (response.IsError) + if (response.State.Error) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); @@ -220,9 +88,9 @@ namespace LibMpc if (searchValue == null) throw new ArgumentNullException("searchValue"); - MpdResponse response = await _connection.Exec("list", new string[] { resultTag.Value, searchTag.Value, searchValue }); + MpdResponse response = await _connection.SendAsync("list", new string[] { resultTag.Value, searchTag.Value, searchValue }); - if (response.IsError) + if (response.State.Error) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); @@ -237,9 +105,9 @@ namespace LibMpc if (path == null) throw new ArgumentNullException("path"); - MpdResponse response = await _connection.Exec("listall", new string[] { path }); + MpdResponse response = await _connection.SendAsync("listall", new string[] { path }); - if (response.IsError) + if (response.State.Error) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return response.getValueList(); @@ -254,9 +122,9 @@ namespace LibMpc if (path == null) throw new ArgumentNullException("path"); - MpdResponse response = await _connection.Exec("listallinfo", new string[] { path }); + MpdResponse response = await _connection.SendAsync("listallinfo", new string[] { path }); - if (response.IsError) + if (response.State.Error) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); @@ -278,11 +146,11 @@ namespace LibMpc { MpdResponse response; if (path == null) - response = await _connection.Exec("lsinfo"); + response = await _connection.SendAsync("lsinfo"); else - response = await _connection.Exec("lsinfo", new string[] { path }); + response = await _connection.SendAsync("lsinfo", new string[] { path }); - if (response.IsError) + if (response.State.Error) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return new MpdDirectoryListing( @@ -301,9 +169,9 @@ namespace LibMpc if (token == null) throw new ArgumentNullException("token"); - MpdResponse response = await _connection.Exec("search", new string[] { tag.Value, token }); + MpdResponse response = await _connection.SendAsync("search", new string[] { tag.Value, token }); - if (response.IsError) + if (response.State.Error) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); return MpdFile.buildList(response); @@ -321,7 +189,7 @@ namespace LibMpc if (filename == null) throw new ArgumentNullException("filename"); - MpdResponse response = await _connection.Exec("add", new string[] { filename }); + MpdResponse response = await _connection.SendAsync("add", new string[] { filename }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -336,7 +204,7 @@ namespace LibMpc if (filename == null) throw new ArgumentNullException("filename"); - MpdResponse response = await _connection.Exec("add", new string[] { filename }); + MpdResponse response = await _connection.SendAsync("add", new string[] { filename }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -358,7 +226,7 @@ namespace LibMpc /// public async Task ClearAsync() { - MpdResponse response = await _connection.Exec("clear"); + MpdResponse response = await _connection.SendAsync("clear"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -369,7 +237,7 @@ namespace LibMpc /// The information of the current song. public async Task CurrentSongAsync() { - MpdResponse response = await _connection.Exec("currentsong"); + MpdResponse response = await _connection.SendAsync("currentsong"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -382,7 +250,7 @@ namespace LibMpc /// The index of the track to remove from the playlist. public async Task DeleteAsync(int nr) { - MpdResponse response = await _connection.Exec("delete", new string[] { nr.ToString() }); + MpdResponse response = await _connection.SendAsync("delete", new string[] { nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -393,7 +261,7 @@ namespace LibMpc /// The id of the track to remove from the playlist. public async Task DeleteIdAsync(int id) { - MpdResponse response = await _connection.Exec("deleteid", new string[] { id.ToString() }); + MpdResponse response = await _connection.SendAsync("deleteid", new string[] { id.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -407,7 +275,7 @@ namespace LibMpc if (name == null) throw new ArgumentNullException("name"); - MpdResponse response = await _connection.Exec("load", new string[] { name }); + MpdResponse response = await _connection.SendAsync("load", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -424,7 +292,7 @@ namespace LibMpc if (newName == null) throw new ArgumentNullException("newName"); - MpdResponse response = await _connection.Exec("rename", new string[] { oldName, newName }); + MpdResponse response = await _connection.SendAsync("rename", new string[] { oldName, newName }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -436,7 +304,7 @@ namespace LibMpc /// The new index of the track in the playlist. public async Task MoveAsync(int oldNr, int newNr) { - MpdResponse response = await _connection.Exec("move", new string[] { oldNr.ToString(), newNr.ToString() }); + MpdResponse response = await _connection.SendAsync("move", new string[] { oldNr.ToString(), newNr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -448,7 +316,7 @@ namespace LibMpc /// The new index of the track in the playlist. public async Task MoveIdAsync(int id, int nr) { - MpdResponse response = await _connection.Exec("moveid", new string[] { id.ToString(), nr.ToString() }); + MpdResponse response = await _connection.SendAsync("moveid", new string[] { id.ToString(), nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -459,7 +327,7 @@ namespace LibMpc /// The meta data of the items in the current playlist. public async Task> PlaylistInfoAsync() { - MpdResponse response = await _connection.Exec("playlistinfo"); + MpdResponse response = await _connection.SendAsync("playlistinfo"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -473,7 +341,7 @@ namespace LibMpc /// The meta data of the track in the current playlist. public async Task PlaylistInfoAsync(int nr) { - MpdResponse response = await _connection.Exec("playlistinfo", new string[] { nr.ToString() }); + MpdResponse response = await _connection.SendAsync("playlistinfo", new string[] { nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -486,7 +354,7 @@ namespace LibMpc /// The meta data of the items in the current playlist. public async Task> PlaylistIdAsync() { - MpdResponse response = await _connection.Exec("playlistid"); + MpdResponse response = await _connection.SendAsync("playlistid"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -500,7 +368,7 @@ namespace LibMpc /// The meta data of the track in the current playlist. public async Task PlaylistIdAsync(int id) { - MpdResponse response = await _connection.Exec("playlistid", new string[] { id.ToString() }); + MpdResponse response = await _connection.SendAsync("playlistid", new string[] { id.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -514,7 +382,7 @@ namespace LibMpc /// All changed songs in the playlist since the given version. public async Task> PlchangesAsync(int version) { - MpdResponse response = await _connection.Exec("plchanges", new string[] { version.ToString() }); + MpdResponse response = await _connection.SendAsync("plchanges", new string[] { version.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -531,7 +399,7 @@ namespace LibMpc /// public async Task>> PlChangesPosIdAsync(int version) { - MpdResponse response = await _connection.Exec("plchangesposid", new string[] { version.ToString() }); + MpdResponse response = await _connection.SendAsync("plchangesposid", new string[] { version.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -578,7 +446,7 @@ namespace LibMpc if (name == null) throw new ArgumentNullException("name"); - MpdResponse response = await _connection.Exec("rm", new string[] { name }); + MpdResponse response = await _connection.SendAsync("rm", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -592,7 +460,7 @@ namespace LibMpc if (name == null) throw new ArgumentNullException("name"); - MpdResponse response = await _connection.Exec("save", new string[] { name }); + MpdResponse response = await _connection.SendAsync("save", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -602,7 +470,7 @@ namespace LibMpc /// public async Task ShuffleAsync() { - MpdResponse response = await _connection.Exec("shuffle"); + MpdResponse response = await _connection.SendAsync("shuffle"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -614,7 +482,7 @@ namespace LibMpc /// The index of the second track. public async Task SwapAsync(int nr1, int nr2) { - MpdResponse response = await _connection.Exec("swap", new string[] { nr1.ToString(), nr2.ToString() }); + MpdResponse response = await _connection.SendAsync("swap", new string[] { nr1.ToString(), nr2.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -626,7 +494,7 @@ namespace LibMpc /// The id of the second track. public async Task SwapIdAsync(int id1, int id2) { - MpdResponse response = await _connection.Exec("swapid", new string[] { id1.ToString(), id2.ToString() }); + MpdResponse response = await _connection.SendAsync("swapid", new string[] { id1.ToString(), id2.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -641,7 +509,7 @@ namespace LibMpc if (name == null) throw new ArgumentNullException("name"); - MpdResponse response = await _connection.Exec("listplaylist", new string[] { name }); + MpdResponse response = await _connection.SendAsync("listplaylist", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -658,7 +526,7 @@ namespace LibMpc if (name == null) throw new ArgumentNullException("name"); - MpdResponse response = await _connection.Exec("listplaylistinfo", new string[] { name }); + MpdResponse response = await _connection.SendAsync("listplaylistinfo", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -677,7 +545,7 @@ namespace LibMpc if (file == null) throw new ArgumentNullException("file"); - MpdResponse response = await _connection.Exec("playlistadd", new string[] { name, file }); + MpdResponse response = await _connection.SendAsync("playlistadd", new string[] { name, file }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -691,7 +559,7 @@ namespace LibMpc if (name == null) throw new ArgumentNullException("name"); - MpdResponse response = await _connection.Exec("playlistclear", new string[] { name }); + MpdResponse response = await _connection.SendAsync("playlistclear", new string[] { name }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -706,7 +574,7 @@ namespace LibMpc if (name == null) throw new ArgumentNullException("name"); - MpdResponse response = await _connection.Exec("playlistdelete", new string[] { name, id.ToString() }); + MpdResponse response = await _connection.SendAsync("playlistdelete", new string[] { name, id.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -722,7 +590,7 @@ namespace LibMpc if (name == null) throw new ArgumentNullException("name"); - MpdResponse response = await _connection.Exec("playlistmove", new string[] { id.ToString(), nr.ToString() }); + MpdResponse response = await _connection.SendAsync("playlistmove", new string[] { id.ToString(), nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -738,7 +606,7 @@ namespace LibMpc if (token == null) throw new ArgumentNullException("token"); - MpdResponse response = await _connection.Exec("playlistfind", new string[] { tag.Value, token }); + MpdResponse response = await _connection.SendAsync("playlistfind", new string[] { tag.Value, token }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -756,7 +624,7 @@ namespace LibMpc if (token == null) throw new ArgumentNullException("token"); - MpdResponse response = await _connection.Exec("playlistsearch", new string[] { tag.Value, token }); + MpdResponse response = await _connection.SendAsync("playlistsearch", new string[] { tag.Value, token }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -772,7 +640,7 @@ namespace LibMpc /// The seconds to crossfade between songs. public async Task CrossfadeAsync(int seconds) { - MpdResponse response = await _connection.Exec("crossfade", new string[] { seconds.ToString() }); + MpdResponse response = await _connection.SendAsync("crossfade", new string[] { seconds.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -782,7 +650,7 @@ namespace LibMpc /// public async Task NextAsync() { - MpdResponse response = await _connection.Exec("next"); + MpdResponse response = await _connection.SendAsync("next"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -793,7 +661,7 @@ namespace LibMpc /// If the playback should be paused or resumed. public async Task PauseAsync(bool pause) { - MpdResponse response = await _connection.Exec("pause", new string[] { pause ? "1" : "0" }); + MpdResponse response = await _connection.SendAsync("pause", new string[] { pause ? "1" : "0" }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -803,7 +671,7 @@ namespace LibMpc /// public async Task PlayAsync() { - MpdResponse response = await _connection.Exec("play"); + MpdResponse response = await _connection.SendAsync("play"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -814,7 +682,7 @@ namespace LibMpc /// The index of the track in the playlist to start playing. public async Task PlayAsync(int nr) { - MpdResponse response = await _connection.Exec("play", new string[] { nr.ToString() }); + MpdResponse response = await _connection.SendAsync("play", new string[] { nr.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -824,7 +692,7 @@ namespace LibMpc /// public async Task PlayIdAsync() { - MpdResponse response = await _connection.Exec("playid"); + MpdResponse response = await _connection.SendAsync("playid"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -835,7 +703,7 @@ namespace LibMpc /// The id of the track to start playing. public async Task PlayIdAsync(int id) { - MpdResponse response = await _connection.Exec("playid", new string[] { id.ToString() }); + MpdResponse response = await _connection.SendAsync("playid", new string[] { id.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -845,7 +713,7 @@ namespace LibMpc /// public async Task PreviousAsync() { - MpdResponse response = await _connection.Exec("previous"); + MpdResponse response = await _connection.SendAsync("previous"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -856,7 +724,7 @@ namespace LibMpc /// If the MPD playlist should be played randomly. public async Task RandomAsync(bool random) { - MpdResponse response = await _connection.Exec("random", new string[] { random ? "1" : "0" }); + MpdResponse response = await _connection.SendAsync("random", new string[] { random ? "1" : "0" }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -867,7 +735,7 @@ namespace LibMpc /// If the MPD should repeat the playlist. public async Task RepeatAsync(bool repeat) { - MpdResponse response = await _connection.Exec("repeat", new string[] { repeat ? "1" : "0" }); + MpdResponse response = await _connection.SendAsync("repeat", new string[] { repeat ? "1" : "0" }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -879,7 +747,7 @@ namespace LibMpc /// The number of seconds to start playback on. public async Task SeekAsync(int nr, int time) { - MpdResponse response = await _connection.Exec("seek", new string[] { nr.ToString(), time.ToString() }); + MpdResponse response = await _connection.SendAsync("seek", new string[] { nr.ToString(), time.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -891,7 +759,7 @@ namespace LibMpc /// The number of seconds to start playback on. public async Task SeekIdAsync(int id, int time) { - MpdResponse response = await _connection.Exec("seekid", new string[] { id.ToString(), time.ToString() }); + MpdResponse response = await _connection.SendAsync("seekid", new string[] { id.ToString(), time.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -907,7 +775,7 @@ namespace LibMpc if (vol > 100) throw new ArgumentException("vol > 100"); - MpdResponse response = await _connection.Exec("setvol", new string[] { vol.ToString() }); + MpdResponse response = await _connection.SendAsync("setvol", new string[] { vol.ToString() }); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -917,7 +785,7 @@ namespace LibMpc /// public async Task StopAsync() { - MpdResponse response = await _connection.Exec("stop"); + MpdResponse response = await _connection.SendAsync("stop"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -931,7 +799,7 @@ namespace LibMpc /// public async Task ClearErrorAsync() { - await _connection.Exec("clearerror"); + await _connection.SendAsync("clearerror"); } /// /// Returns which commands the current user has access to. @@ -939,7 +807,7 @@ namespace LibMpc /// The commands the current user has access to. public async Task> CommandsAsync() { - MpdResponse response = await _connection.Exec("commands"); + MpdResponse response = await _connection.SendAsync("commands"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -952,7 +820,7 @@ namespace LibMpc /// The commands the current user does has access to. public async Task> NotCommandsAsync() { - MpdResponse response = await _connection.Exec("notcommands"); + MpdResponse response = await _connection.SendAsync("notcommands"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -969,7 +837,7 @@ namespace LibMpc if (password == null) throw new ArgumentNullException("password"); - var mpdResponse = await _connection.Exec("password", new string[] { password }); + var mpdResponse = await _connection.SendAsync("password", new string[] { password }); return mpdResponse.IsError; } /// @@ -977,7 +845,7 @@ namespace LibMpc /// public async Task PingAsync() { - await _connection.Exec("ping"); + await _connection.SendAsync("ping"); } /// /// Requests the current statistics from the MPD, @@ -985,7 +853,7 @@ namespace LibMpc /// The current statistics fromt the MPD. public async Task StatsAsync() { - MpdResponse response = await _connection.Exec("stats"); + MpdResponse response = await _connection.SendAsync("stats"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -1063,7 +931,7 @@ namespace LibMpc /// The current status of the MPD. public async Task StatusAsync() { - MpdResponse response = await _connection.Exec("status"); + MpdResponse response = await _connection.SendAsync("status"); if (response.IsError) throw new MpdResponseException(response.ErrorCode, response.ErrorMessage); @@ -1233,5 +1101,6 @@ namespace LibMpc } #endregion + */ } } diff --git a/LibMpc/MpcConnection.cs b/LibMpc/MpcConnection.cs index 5210fa1..5eb067f 100644 --- a/LibMpc/MpcConnection.cs +++ b/LibMpc/MpcConnection.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.IO; using System.Net; using System.Net.Sockets; using System.Text; -using System.Text.RegularExpressions; using System.Threading.Tasks; namespace LibMpc @@ -17,12 +15,6 @@ namespace LibMpc /// public class MpcConnection { - private static readonly string FIRST_LINE_PREFIX = "OK MPD "; - - private static readonly string OK = "OK"; - private static readonly string ACK = "ACK"; - - private readonly IPEndPoint _server; private TcpClient _tcpClient; @@ -61,12 +53,12 @@ namespace LibMpc _writer = new StreamWriter(_networkStream, Encoding.UTF8) { NewLine = "\n" }; var firstLine = _reader.ReadLine(); - if (!firstLine.StartsWith(FIRST_LINE_PREFIX)) + if (!firstLine.StartsWith(Constants.FirstLinePrefix)) { await DisconnectAsync(); - throw new InvalidDataException("Response of mpd does not start with \"" + FIRST_LINE_PREFIX + "\"." ); + throw new InvalidDataException("Response of mpd does not start with \"" + Constants.FirstLinePrefix + "\"." ); } - _version = firstLine.Substring(FIRST_LINE_PREFIX.Length); + _version = firstLine.Substring(Constants.FirstLinePrefix.Length); await _writer.WriteLineAsync(); _writer.Flush(); @@ -86,84 +78,29 @@ namespace LibMpc return Task.CompletedTask; } - /// - /// Executes a simple command without arguments on the MPD server and returns the response. - /// - /// The command to execute. - /// The MPD server response parsed into a basic object. - /// If the command contains a space of a newline charakter. - public async Task Exec(string command) - { - if (command == null) - throw new ArgumentNullException("command"); - if (command.Contains(" ")) - throw new ArgumentException("command contains space"); - if (command.Contains("\n")) - throw new ArgumentException("command contains newline"); + - // TODO: Integrate connection status in MpdResponse - var connectionResult = await CheckConnectionAsync(); + public async Task> SendAsync(IMpcCommand command) + { + command.CheckNotNull(); + + var connected = await CheckConnectionAsync(); + string[] response; try { - _writer.WriteLine(command); + _writer.WriteLine(command.Value); _writer.Flush(); - return await ReadResponseAsync(); + response = await ReadResponseAsync(); } catch (Exception) { try { await DisconnectAsync(); } catch (Exception) { } return null; // TODO: Create Null Object for MpdResponse } - } - /// - /// Executes a MPD command with arguments on the MPD server. - /// - /// The command to execute. - /// The arguments of the command. - /// The MPD server response parsed into a basic object. - /// If the command contains a space of a newline charakter. - public async Task Exec(string command, string[] argument) - { - if (command == null) - throw new ArgumentNullException("command"); - if (command.Contains(" ")) - throw new ArgumentException("command contains space"); - if (command.Contains("\n")) - throw new ArgumentException("command contains newline"); - if (argument == null) - throw new ArgumentNullException("argument"); - for (int i = 0; i < argument.Length; i++) - { - if (argument[i] == null) - throw new ArgumentNullException("argument[" + i + "]"); - if (argument[i].Contains("\n")) - throw new ArgumentException("argument[" + i + "] contains newline"); - } - - // TODO: Integrate connection status in MpdResponse - var connectionResult = await CheckConnectionAsync(); - - try - { - _writer.Write(command); - foreach (string arg in argument) - { - _writer.Write(' '); - WriteToken(arg); - } - _writer.WriteLine(); - _writer.Flush(); - - return await ReadResponseAsync(); - } - catch (Exception) - { - try { await DisconnectAsync(); } catch (Exception) { } - throw; - } + return new MpdMessage(command, connected, response); } private async Task CheckConnectionAsync() @@ -176,41 +113,19 @@ namespace LibMpc return IsConnected; } - private void WriteToken(string token) - { - if (token.Contains(" ")) - { - _writer.Write("\""); - foreach (char chr in token) - if (chr == '"') - _writer.Write("\\\""); - else - _writer.Write(chr); - } - else - _writer.Write(token); - } - - private async Task ReadResponseAsync() + private async Task ReadResponseAsync() { var response = new List(); - var currentLine = _reader.ReadLine(); // Read response untli reach end token (OK or ACK) - while (!(currentLine.Equals(OK) || currentLine.StartsWith(ACK))) + string responseLine; + do { - response.Add(currentLine); - currentLine = await _reader.ReadLineAsync(); - } + responseLine = await _reader.ReadLineAsync(); + response.Add(responseLine); + } while (!(responseLine.Equals(Constants.Ok) || responseLine.StartsWith(Constants.Ack) || string.IsNullOrEmpty(responseLine))); - if (currentLine.Equals(OK)) - { - return new MpdResponse(new ReadOnlyCollection(response)); - } - else - { - return AcknowledgeResponse.Parse(currentLine, response); - } + return response.ToArray(); } private void ClearConnectionFields() @@ -222,24 +137,4 @@ namespace LibMpc _version = string.Empty; } } - - public class AcknowledgeResponse - { - private static readonly Regex AcknowledgePattern = new Regex("^ACK \\[(?[0-9]*)@(?[0-9]*)] \\{(?[a-z]*)} (?.*)$"); - - public static MpdResponse Parse(string acknowledgeResponse, IList payload) - { - var match = AcknowledgePattern.Match(acknowledgeResponse); - - if (match.Groups.Count != 5) - throw new InvalidDataException("Error response not as expected"); - - return new MpdResponse( - int.Parse(match.Result("${code}")), - int.Parse(match.Result("${nr}")), - match.Result("${command}"), - match.Result("${message}"), - new ReadOnlyCollection(payload)); - } - } } diff --git a/LibMpc/MpdFile.cs b/LibMpc/MpdFile.cs index 28e93cf..7809ad5 100644 --- a/LibMpc/MpdFile.cs +++ b/LibMpc/MpdFile.cs @@ -280,6 +280,7 @@ namespace LibMpc builder.Append(value); builder.AppendLine(); } + /* /// /// Returns a MpdFile object from a MpdResponse object. /// @@ -475,11 +476,12 @@ namespace LibMpc break; case TAG_TRACK: track = line.Value; - /* + + // TODO: int tryTrack; if (int.TryParse(line.Value, out tryTrack)) track = tryTrack; - */ + break; case TAG_NAME: name = line.Value; @@ -537,5 +539,6 @@ namespace LibMpc return ret; } + */ } } diff --git a/LibMpc/MpdResponse.cs b/LibMpc/MpdResponse.cs deleted file mode 100644 index 0b1ad21..0000000 --- a/LibMpc/MpdResponse.cs +++ /dev/null @@ -1,308 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Text; -using System.Text.RegularExpressions; - -namespace LibMpc -{ - /// - /// The MpdResponse class parses the response to an MPD command in it's most - /// basic structure. - /// - public class MpdResponse : IEnumerable> - { - private const string OK = "OK"; - private const string ACK = "ACK"; - - private static readonly Regex LINE_REGEX = new Regex("^(?[A-Za-z]*):[ ]{0,1}(?.*)$"); - - private readonly bool isError; - private readonly int errorCode; - private readonly int commandListNum; - private readonly string currentCommand; - private readonly string errorMessage; - private readonly ReadOnlyCollection message; - - private Dictionary dictionary = null; - /// - /// If the response denotes an error in the last command. - /// - public bool IsError { get { return this.isError; } } - /// - /// The error code if an error occured. - /// - public int ErrorCode { get { return this.errorCode; } } - /// - /// If an error occured the index of the invalid command in a command list. - /// - public int CommandListNum { get { return this.commandListNum; } } - /// - /// The command executed. - /// - public string CurrentCommand { get { return this.currentCommand; } } - /// - /// The description of the error, if occured. - /// - public string ErrorMessage { get { return this.errorMessage; } } - /// - /// The lines of the response message. - /// - public ReadOnlyCollection Message { get { return this.message; } } - /// - /// The value of an attribute in the MPD response. - /// - /// The name of the attribute. - /// The value of the attribute - public string this[string key] - { - get - { - if (this.dictionary == null) - { - this.dictionary = new Dictionary(); - - foreach (string line in this.message) - { - Match match = LINE_REGEX.Match(line); - if (match.Success) - this.dictionary[match.Result("$key")] = match.Result("$value"); - } - } - - return this.dictionary[key]; - } - } - /// - /// The number of lines in the response message. - /// - public int Count { get { return this.message.Count; } } - /// - /// A line in the MPD response as KeyValuePair. If the message cannot be separated - /// into key and value according to the MPD protocol spec, a KeyValuePair is returned - /// with the key null and the value the whole text of the line. - /// - /// The index of the line. - /// The requested line as KeyValuePair. - public KeyValuePair this[int line] - { - get - { - Match match = LINE_REGEX.Match(this.message[line]); - if (match.Success) - return new KeyValuePair(match.Result("${key}"), match.Result("${value}")); - else - return new KeyValuePair(null, this.message[line]); - } - } - /// - /// Creates a new MpdResponse from a list of lines in case no error occured. - /// - /// The response to an MPD command. - public MpdResponse( ReadOnlyCollection message ) - { - if (message == null) - throw new ArgumentNullException("message"); - - this.isError = false; - this.errorCode = -1; - this.commandListNum = 0; - this.currentCommand = null; - this.errorMessage = null; - this.message = message; - } - /// - /// Creates a new MpdResponse in case an error occured. - /// - /// The code of the error. - /// The index of the command which raised the error. - /// The command that raised the error. - /// The message describing the error. - /// The text of the standard MPD response. - public MpdResponse( int errorCode, int commandListNum, string currentCommand, string errorMessage, ReadOnlyCollection message) - { - if (currentCommand == null) - throw new ArgumentNullException("currentCommand"); - if (errorMessage == null) - throw new ArgumentNullException("errorMessage"); - if (message == null) - throw new ArgumentNullException("message"); - - this.isError = true; - this.errorCode = errorCode; - this.commandListNum = commandListNum; - this.currentCommand = currentCommand; - this.errorMessage = errorMessage; - this.message = message; - } - /// - /// Returns the values in all lines with the given attribute. - /// - /// The attribute who's values are reguested. - /// The values in all lines with the given attribute. - public List getAttributeValueList(string attribute) - { - List ret = new List(); - - foreach (string line in this.message) - { - Match match = LINE_REGEX.Match(line); - if (match.Success) - { - string key = match.Result("${key}"); - if( ( key != null ) && key.Equals( attribute ) ) - { - string value = match.Result("${value}"); - if( value != null ) - ret.Add( value ); - } - } - } - - return ret; - } - /// - /// Returns only the value parts in all key/value pairs in the response. - /// - /// The list of values in all key/value pairs in the response. - public List getValueList() - { - List ret = new List(); - - foreach (string line in this.message) - { - Match match = LINE_REGEX.Match(line); - if (match.Success) - { - string value = match.Result("${value}"); - if (value != null) - ret.Add(value); - } - } - - return ret; - } - /// - /// Builds the response text of the MPD server from the object. - /// - /// The response text of the MPD server from the object. - public override string ToString() - { - StringBuilder builder = new StringBuilder(); - foreach (string line in this.message) - builder.AppendLine(line); - - if (this.isError) - { - builder.Append(ACK); - builder.Append(" ["); - builder.Append(this.errorMessage); - builder.Append('@'); - builder.Append(this.commandListNum); - builder.Append("] {"); - builder.Append(this.currentCommand); - builder.Append("} "); - builder.Append(this.errorMessage); - //ACK [50@1] {play} song doesn't exist: "10240" - } - else - builder.Append(OK); - - return builder.ToString(); - } - - #region IEnumerable> Members - /// - /// Returns an enumerator for all KeyValuePairs in the MPD response. - /// - /// An enumerator for all KeyValuePairs in the MPD response. - IEnumerator> IEnumerable>.GetEnumerator() - { - return new MpdResponseEnumerator(this); - } - - #endregion - - #region IEnumerable Members - /// - /// Returns an enumerator for all KeyValuePairs in the MPD response. - /// - /// An enumerator for all KeyValuePairs in the MPD response. - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return new MpdResponseEnumerator(this); - } - - #endregion - } - /// - /// A class for enumerating over the KeyValuePairs in the response. - /// - public class MpdResponseEnumerator :IEnumerator> - { - private readonly MpdResponse response; - private int position = -1; - private KeyValuePair current; - /// - /// Creates a new MpdResponseEnumerator. - /// - /// The response to enumerate over. - protected internal MpdResponseEnumerator(MpdResponse response) - { - this.response = response; - } - - #region IEnumerator> Members - /// - /// Returns the current element of the enumerator. - /// - KeyValuePair IEnumerator>.Current - { - get { return this.current; } - } - - #endregion - - #region IDisposable Members - - void IDisposable.Dispose() - { - this.position = -1; - } - - #endregion - - #region IEnumerator Members - /// - /// Returns the current element of the enumerator. - /// - object System.Collections.IEnumerator.Current - { - get { return this.current; } - } - /// - /// Moves the enumerator to the next KeyValuePair in the MPD response. - /// - /// If the enumerator has any values left. - bool System.Collections.IEnumerator.MoveNext() - { - this.position++; - if (this.position < this.response.Count) - { - this.current = this.response[this.position]; - return true; - } - else - return false; - } - /// - /// Sets the enumerator to it's initial state. - /// - void System.Collections.IEnumerator.Reset() - { - this.position = -1; - } - - #endregion - } -} diff --git a/LibMpc/Tags.cs b/LibMpc/Tags.cs deleted file mode 100644 index 0284344..0000000 --- a/LibMpc/Tags.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace LibMpc -{ - /// - /// https://www.musicpd.org/doc/protocol/tags.html - /// - public class Tags - { - internal class Tag : ITag - { - internal Tag(string value) - { - Value = value; - } - - public string Value { get; } - } - - public ITag Artist { get; } = new Tag("artist"); - public ITag ArtistSort { get; } = new Tag("artistsort"); - public ITag Album { get; } = new Tag("album"); - public ITag AlbumSort { get; } = new Tag("albumsort"); - public ITag AlbumArtist { get; } = new Tag("albumartist"); - public ITag AlbumArtistSort { get; } = new Tag("albumartistsort"); - public ITag Title { get; } = new Tag("title"); - public ITag Track { get; } = new Tag("track"); - public ITag Name { get; } = new Tag("name"); - public ITag Genre { get; } = new Tag("genre"); - public ITag Date { get; } = new Tag("date"); - public ITag Composer { get; } = new Tag("composer"); - public ITag Performer { get; } = new Tag("performer"); - public ITag Comment { get; } = new Tag("comment"); - public ITag Disc { get; } = new Tag("disc"); - } - - public interface ITag - { - string Value { get; } - } -} \ No newline at end of file diff --git a/LibMpc/Tags/FindTags.cs b/LibMpc/Tags/FindTags.cs new file mode 100644 index 0000000..ae24d87 --- /dev/null +++ b/LibMpc/Tags/FindTags.cs @@ -0,0 +1,13 @@ +namespace LibMpc +{ + /// + /// https://www.musicpd.org/doc/protocol/database.html : find {TYPE} {WHAT} [...] [window START:END] + /// + public class FindTags + { + public static ITag Any { get; } = new Tag("any"); + public static ITag File { get; } = new Tag("file"); + public static ITag Base { get; } = new Tag("base"); + public static ITag ModifiedSince { get; } = new Tag("modified-since"); + } +} \ No newline at end of file diff --git a/LibMpc/Tags/MpdTags.cs b/LibMpc/Tags/MpdTags.cs new file mode 100644 index 0000000..e313011 --- /dev/null +++ b/LibMpc/Tags/MpdTags.cs @@ -0,0 +1,24 @@ +namespace LibMpc +{ + /// + /// https://www.musicpd.org/doc/protocol/tags.html + /// + public class MpdTags + { + public static ITag Artist { get; } = new Tag("artist"); + public static ITag ArtistSort { get; } = new Tag("artistsort"); + public static ITag Album { get; } = new Tag("album"); + public static ITag AlbumSort { get; } = new Tag("albumsort"); + public static ITag AlbumArtist { get; } = new Tag("albumartist"); + public static ITag AlbumArtistSort { get; } = new Tag("albumartistsort"); + public static ITag Title { get; } = new Tag("title"); + public static ITag Track { get; } = new Tag("track"); + public static ITag Name { get; } = new Tag("name"); + public static ITag Genre { get; } = new Tag("genre"); + public static ITag Date { get; } = new Tag("date"); + public static ITag Composer { get; } = new Tag("composer"); + public static ITag Performer { get; } = new Tag("performer"); + public static ITag Comment { get; } = new Tag("comment"); + public static ITag Disc { get; } = new Tag("disc"); + } +} \ No newline at end of file diff --git a/LibMpc/Tags/Tag.cs b/LibMpc/Tags/Tag.cs new file mode 100644 index 0000000..f129ce4 --- /dev/null +++ b/LibMpc/Tags/Tag.cs @@ -0,0 +1,18 @@ +namespace LibMpc +{ + public interface ITag + { + string Value { get; } + } + + + internal class Tag : ITag + { + internal Tag(string value) + { + Value = value; + } + + public string Value { get; } + } +} \ No newline at end of file diff --git a/LibMpc/project.json b/LibMpc/project.json index 864b9a5..ba4e60a 100644 --- a/LibMpc/project.json +++ b/LibMpc/project.json @@ -1,8 +1,9 @@ -{ +{ "version": "1.0.0-*", "dependencies": { - "NETStandard.Library": "1.6.0" + "NETStandard.Library": "1.6.0", + "Newtonsoft.Json": "9.0.1" }, "frameworks": { diff --git a/LibMpcApp/Program.cs b/LibMpcApp/Program.cs index 7a54497..688f0fa 100644 --- a/LibMpcApp/Program.cs +++ b/LibMpcApp/Program.cs @@ -1,7 +1,6 @@ using System; using System.Net; using LibMpc; -using System.Collections.Generic; namespace LibMpcApp { @@ -10,11 +9,6 @@ namespace LibMpcApp /// public class Program { - private static readonly Dictionary> _commands = new Dictionary> - { - { 1, input => new Commands.Reflection.TagTypes() } - }; - public static void Main(string[] args) { var mpc = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600)); @@ -38,12 +32,27 @@ namespace LibMpcApp int userInput = 0; while ((userInput = DisplayMenu()) != 99) { - Func command; var response = new object(); - if (_commands.TryGetValue(userInput, out command)) + switch (userInput) { - response = mpc.SendAsync(command(null)).GetAwaiter().GetResult(); + case 11: + response = mpc.SendAsync(new Commands.Output.DisableOutput(0)).GetAwaiter().GetResult(); + break; + case 12: + response = mpc.SendAsync(new Commands.Output.EnableOutput(0)).GetAwaiter().GetResult(); + break; + case 13: + response = mpc.SendAsync(new Commands.Output.Outputs()).GetAwaiter().GetResult(); + break; + + case 24: + response = mpc.SendAsync(new Commands.Reflection.TagTypes()).GetAwaiter().GetResult(); + break; + + case 313: + response = mpc.SendAsync(new Commands.Database.Update()).GetAwaiter().GetResult(); + break; } Console.WriteLine("Response: "); @@ -55,7 +64,21 @@ namespace LibMpcApp { Console.WriteLine(); Console.WriteLine("Commands: "); - Console.WriteLine("1. tagtypes"); + + Console.WriteLine(); + Console.WriteLine("11. disableoutput 0"); + Console.WriteLine("12. enableoutput 0"); + Console.WriteLine("13. outputs"); + + Console.WriteLine(); + Console.WriteLine("Reflection"); + Console.WriteLine("24. tagtypes"); + + Console.WriteLine(); + Console.WriteLine("Database"); + Console.WriteLine("313. update"); + + Console.WriteLine(); Console.WriteLine("99. Exit"); Console.WriteLine(); var result = Console.ReadLine();