diff --git a/src/MpcNET.Test/LibMpcTest.cs b/src/MpcNET.Test/LibMpcTest.cs index ff49553..3526276 100644 --- a/src/MpcNET.Test/LibMpcTest.cs +++ b/src/MpcNET.Test/LibMpcTest.cs @@ -1,4 +1,7 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace MpcNET.Test { @@ -23,5 +26,32 @@ namespace MpcNET.Test } internal static Mpc Mpc { get; private set; } + + private static async Task SendCommand(string command) + { + var response = await Mpc.SendAsync(new PassthroughCommand(command)); + TestOutput.WriteLine(response); + } + private static async Task SendCommand(IMpcCommand command) + { + var response = await Mpc.SendAsync(command); + TestOutput.WriteLine(response); + } + + private class PassthroughCommand : IMpcCommand> + { + public PassthroughCommand(string command) + { + Value = command; + } + + public string Value { get; } + + public IList FormatResponse(IList> response) + { + var result = response.Select(atrb => $"{atrb.Key}: {atrb.Value}").ToList(); + return result; + } + } } } diff --git a/src/MpcNET.Test/Properties/AssemblyInfo.cs b/src/MpcNET.Test/Properties/AssemblyInfo.cs index a6987aa..2dfaba7 100644 --- a/src/MpcNET.Test/Properties/AssemblyInfo.cs +++ b/src/MpcNET.Test/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/src/MpcNET.Test/Server/StartLocal.bat b/src/MpcNET.Test/Server/StartLocal.bat new file mode 100644 index 0000000..fad9d33 --- /dev/null +++ b/src/MpcNET.Test/Server/StartLocal.bat @@ -0,0 +1 @@ +mpd.exe mpd.conf -v \ No newline at end of file diff --git a/src/MpcNET.Test/Server/mpd.conf b/src/MpcNET.Test/Server/mpd.conf new file mode 100644 index 0000000..562c229 --- /dev/null +++ b/src/MpcNET.Test/Server/mpd.conf @@ -0,0 +1,30 @@ +log_file "mpd_log.txt" + +db_file "mpd.db" + +bind_to_address "any" + +music_directory "Music" + +playlist_directory "Playlists" + +port "6600" + +audio_output { + type "null" + name "Enabled output to be disabled" + enabled "true" + mixer_type "none" +} +audio_output { + type "null" + name "Disabled output to be enabled" + enabled "false" + mixer_type "none" +} +audio_output { + type "null" + name "Enabled output to be toggled" + enabled "true" + mixer_type "none" +} diff --git a/src/MpcNET.Test/Server/mpd_log.txt b/src/MpcNET.Test/Server/mpd_log.txt new file mode 100644 index 0000000..22fab9f --- /dev/null +++ b/src/MpcNET.Test/Server/mpd_log.txt @@ -0,0 +1,88 @@ +Apr 12 14:17 : client: [0] opened from 127.0.0.1:65192 +Apr 12 14:17 : client: [0] expired +Apr 12 14:17 : client: [0] closed +Apr 12 14:17 : client: [1] opened from 127.0.0.1:65193 +Apr 12 14:17 : client: [1] expired +Apr 12 14:17 : client: [1] closed +Apr 12 14:17 : client: [2] opened from 127.0.0.1:65194 +Apr 12 14:17 : client: [2] expired +Apr 12 14:17 : client: [2] closed +Apr 12 14:17 : client: [3] opened from 127.0.0.1:65195 +Apr 12 14:17 : client: [3] expired +Apr 12 14:17 : client: [3] closed +Apr 12 14:18 : client: [4] opened from 127.0.0.1:65196 +Apr 12 14:18 : client: [4] expired +Apr 12 14:18 : client: [4] closed +Apr 12 14:18 : client: [5] opened from 127.0.0.1:65203 +Apr 12 14:18 : client: [5] expired +Apr 12 14:18 : client: [5] closed +Apr 12 14:19 : client: [6] opened from 127.0.0.1:65204 +Apr 12 14:19 : client: [6] process command "stats" +Apr 12 14:19 : client: [6] command returned 0 +Apr 12 14:19 : client: [6] expired +Apr 12 14:19 : client: [6] closed +Apr 12 14:20 : client: [7] opened from 127.0.0.1:65220 +Apr 12 14:20 : client: [7] process command "stats" +Apr 12 14:20 : client: [7] command returned 0 +Apr 12 14:20 : client: [7] expired +Apr 12 14:20 : client: [7] closed +Apr 12 14:20 : client: [8] opened from 127.0.0.1:65221 +Apr 12 14:20 : client: [8] process command "status" +Apr 12 14:20 : client: [8] command returned 0 +Apr 12 14:20 : client: [8] expired +Apr 12 14:20 : client: [8] closed +Apr 12 14:23 : client: [9] opened from 127.0.0.1:65226 +Apr 12 14:23 : client: [9] process command "stats" +Apr 12 14:23 : client: [9] command returned 0 +Apr 12 14:23 : client: [9] expired +Apr 12 14:23 : client: [9] closed +Apr 12 14:23 : client: [10] opened from 127.0.0.1:65227 +Apr 12 14:23 : client: [10] process command "stats" +Apr 12 14:23 : client: [10] command returned 0 +Apr 12 14:23 : client: [10] expired +Apr 12 14:23 : client: [10] closed +Apr 12 14:23 : client: [11] opened from 127.0.0.1:65228 +Apr 12 14:23 : client: [11] process command "stats" +Apr 12 14:23 : client: [11] command returned 0 +Apr 12 14:23 : client: [11] expired +Apr 12 14:23 : client: [11] closed +Apr 12 14:23 : client: [12] opened from 127.0.0.1:65229 +Apr 12 14:23 : client: [12] process command "status" +Apr 12 14:23 : client: [12] command returned 0 +Apr 12 14:23 : client: [12] expired +Apr 12 14:23 : client: [12] closed +Apr 12 14:23 : client: [13] opened from 127.0.0.1:65230 +Apr 12 14:23 : client: [13] process command "stats" +Apr 12 14:23 : client: [13] command returned 0 +Apr 12 14:23 : client: [13] expired +Apr 12 14:23 : client: [13] closed +Apr 12 14:25 : client: [14] opened from 127.0.0.1:65236 +Apr 12 14:25 : client: [14] process command "listplaylists" +Apr 12 14:25 : client: [14] command returned 0 +Apr 12 14:25 : client: [14] expired +Apr 12 14:25 : client: [14] closed +Apr 12 14:28 : client: [15] opened from 127.0.0.1:65383 +Apr 12 14:28 : client: [15] process command "listplaylists" +Apr 12 14:28 : client: [15] command returned 0 +Apr 12 14:28 : client: [15] expired +Apr 12 14:28 : client: [15] closed +Apr 12 14:29 : client: [16] opened from 127.0.0.1:65385 +Apr 12 14:29 : client: [16] process command "listplaylistinfo Playlist One" +Apr 12 14:29 : client: [16] command returned -1 +Apr 12 14:29 : client: [16] expired +Apr 12 14:29 : client: [16] closed +Apr 12 14:29 : client: [17] opened from 127.0.0.1:65386 +Apr 12 14:29 : client: [17] process command "listplaylistinfo "Playlist One"" +Apr 12 14:29 : database: get song: teaspoon-stirring-mug-of-coffee.mp3 +Apr 12 14:29 : database: get song: whistle-kettle-boiling.mp3 +Apr 12 14:29 : database: get song: wine-glass-double-chink-clink-cheers.mp3 +Apr 12 14:29 : database: get song: Directory With Spaces/coin-spin-light.mp3 +Apr 12 14:29 : database: get song: Directory With Spaces/finger-snap-click.mp3 +Apr 12 14:29 : client: [17] command returned 0 +Apr 12 14:29 : client: [17] expired +Apr 12 14:29 : client: [17] closed +Apr 12 14:32 : client: [18] opened from 127.0.0.1:65446 +Apr 12 14:32 : client: [18] process command "statstastats" +Apr 12 14:32 : client: [18] command returned -1 +Apr 12 14:32 : client: [18] process command "stats" +Apr 12 14:3 \ No newline at end of file diff --git a/src/MpcNET.Test/TestOutput.cs b/src/MpcNET.Test/TestOutput.cs index 7b70802..c99284f 100644 --- a/src/MpcNET.Test/TestOutput.cs +++ b/src/MpcNET.Test/TestOutput.cs @@ -1,12 +1,18 @@ using System; +using MpcNET.Message; namespace MpcNET.Test { - internal class TestOutput + internal static class TestOutput { internal static void WriteLine(string value) { Console.Out.WriteLine(value); } + + internal static void WriteLine(IMpdMessage message) + { + Console.Out.WriteLine(message.ToString()); + } } } \ No newline at end of file diff --git a/src/MpcNET.Test/Tests/DatabaseCommandsTest.cs b/src/MpcNET.Test/Tests/DatabaseCommandsTest.cs index cb20338..972af95 100644 --- a/src/MpcNET.Test/Tests/DatabaseCommandsTest.cs +++ b/src/MpcNET.Test/Tests/DatabaseCommandsTest.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using MpcNET.Tags; -using Newtonsoft.Json; namespace MpcNET.Test { @@ -14,7 +13,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Database.ListAll()); TestOutput.WriteLine("ListAllTest Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Count().Equals(7)); } @@ -22,10 +21,10 @@ namespace MpcNET.Test [TestMethod] public async Task FindGenreTest() { - var response = await Test.LibMpcTest.Mpc.SendAsync(new Commands.Database.Find(MpdTags.Genre, "soundfx")); + var response = await Mpc.SendAsync(new Commands.Database.Find(MpdTags.Genre, "soundfx")); TestOutput.WriteLine("FindGenreTest Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Count().Equals(7)); } diff --git a/src/MpcNET.Test/Tests/MpdMessageExtension.cs b/src/MpcNET.Test/Tests/MpdMessageExtension.cs new file mode 100644 index 0000000..d7696ce --- /dev/null +++ b/src/MpcNET.Test/Tests/MpdMessageExtension.cs @@ -0,0 +1,16 @@ +using MpcNET.Message; + +namespace MpcNET.Test +{ + public static class MpdMessageExtension + { + public static bool HasSuccessResponse(this IMpdMessage message) + { + return message.Response.State.Connected && + message.Response.State.Status == "OK" && + !message.Response.State.Error && + message.Response.State.ErrorMessage == string.Empty && + message.Response.State.MpdError == string.Empty; + } + } +} \ No newline at end of file diff --git a/src/MpcNET.Test/Tests/OutputCommandsTest.cs b/src/MpcNET.Test/Tests/OutputCommandsTest.cs index 1ce7b6f..b50b841 100644 --- a/src/MpcNET.Test/Tests/OutputCommandsTest.cs +++ b/src/MpcNET.Test/Tests/OutputCommandsTest.cs @@ -1,7 +1,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json; namespace MpcNET.Test { @@ -16,7 +15,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Output.DisableOutput(0)); TestOutput.WriteLine("DisableOutputTest Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Equals(string.Empty)); Assert.IsTrue(response.Response.State.Status.Equals("OK")); @@ -35,7 +34,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Output.EnableOutput(1)); TestOutput.WriteLine("EnableOutputTest Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Equals(string.Empty)); Assert.IsTrue(response.Response.State.Status.Equals("OK")); @@ -53,7 +52,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Output.ToggleOutput(2)); TestOutput.WriteLine("ToggleOutputTest Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Equals(string.Empty)); Assert.IsTrue(response.Response.State.Status.Equals("OK")); @@ -68,7 +67,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Output.Outputs()); TestOutput.WriteLine("LisOutputsTest Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Count().Equals(3)); } diff --git a/src/MpcNET.Test/Tests/PlaylistsCommandsTest.cs b/src/MpcNET.Test/Tests/PlaylistsCommandsTest.cs index 9594321..14ce0a0 100644 --- a/src/MpcNET.Test/Tests/PlaylistsCommandsTest.cs +++ b/src/MpcNET.Test/Tests/PlaylistsCommandsTest.cs @@ -1,7 +1,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json; namespace MpcNET.Test { @@ -13,10 +12,10 @@ namespace MpcNET.Test [DataRow("_My Playlist", 5)] public async Task ListPlaylistTest(string playlistName, int numberOfFiles) { - var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylist(playlistName)); + var response = await Mpc.SendAsync(Commands.Playlists.Stored.GetContent(playlistName)); TestOutput.WriteLine($"ListPlaylistTest (playlistName: {playlistName}) Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Count().Equals(numberOfFiles)); } @@ -27,10 +26,10 @@ namespace MpcNET.Test [DataRow("_My Playlist", 5)] public async Task ListPlaylistInfoTest(string playlistName, int numberOfFiles) { - var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylistInfo(playlistName)); + var response = await Mpc.SendAsync(Commands.Playlists.Stored.GetContentWithMetadata(playlistName)); TestOutput.WriteLine($"ListPlaylistTest (playlistName: {playlistName}) Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Count().Equals(numberOfFiles)); Assert.IsTrue(response.Response.Body.All(item => !string.IsNullOrEmpty(item.Artist))); @@ -41,12 +40,134 @@ namespace MpcNET.Test [TestMethod] public async Task ListPlaylistsTest() { - var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylists()); + var response = await Mpc.SendAsync(Commands.Playlists.Stored.GetAll()); TestOutput.WriteLine($"ListPlaylistsTest Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Count().Equals(3)); } + + /// + /// These tests must run sequential because we have only one "Current Queue" + /// + [TestMethod] + public async Task QueueTests() + { + await LoadPlaylistTest(); + await ClearPlaylistTest(); + await AddDirectoryTest(); + await AddFileTest(); + await RemovePositionTest(); + await RemoveIdTest(); + } + + public async Task LoadPlaylistTest() + { + await Clear_Queue(); + await Check_Empty_Queue(); + await Load_Playlist("Playlist One"); + await Check_Queue_HasSongs(5); + } + + public async Task ClearPlaylistTest() + { + await Clear_Queue(); + await Check_Empty_Queue(); + await Load_Playlist("Playlist One"); + await Clear_Queue(); + await Check_Queue_HasSongs(0); + } + + public async Task AddDirectoryTest() + { + await Clear_Queue(); + await Check_Empty_Queue(); + await Add_Directory("Directory With Spaces"); + await Check_Queue_HasSongs(3); + } + + public async Task AddFileTest() + { + await Clear_Queue(); + await Check_Empty_Queue(); + await Add_File("teaspoon-stirring-mug-of-coffee.mp3"); + await Check_Queue_HasSongs(1); + } + + public async Task RemovePositionTest() + { + await Clear_Queue(); + await Check_Empty_Queue(); + await Add_File("teaspoon-stirring-mug-of-coffee.mp3"); + await Remove_Position(0); + await Check_Queue_HasSongs(0); + } + + public async Task RemoveIdTest() + { + await Clear_Queue(); + await Check_Empty_Queue(); + await Add_File("teaspoon-stirring-mug-of-coffee.mp3"); + var id = await Get_Song_Id(); + await Remove_Id(id); + await Check_Queue_HasSongs(0); + } + + private async Task Check_Empty_Queue() + { + var message = await Mpc.SendAsync(Commands.Playlists.Current.GetAllSongsInfo()); + Assert.IsTrue(message.HasSuccessResponse()); + Assert.IsFalse(message.Response.Body.Any()); + } + + private async Task Load_Playlist(string playlistName) + { + var message = await Mpc.SendAsync(Commands.Playlists.Stored.Load(playlistName)); + Assert.IsTrue(message.HasSuccessResponse()); + } + + private async Task Clear_Queue() + { + var message = await Mpc.SendAsync(Commands.Playlists.Current.Clear()); + Assert.IsTrue(message.HasSuccessResponse()); + } + + private async Task Check_Queue_HasSongs(int nrOfSongs) + { + var message = await Mpc.SendAsync(Commands.Playlists.Current.GetAllSongsInfo()); + Assert.IsTrue(message.HasSuccessResponse()); + Assert.IsTrue(message.Response.Body.Count() == nrOfSongs); + } + + private async Task Add_Directory(string directory) + { + var message = await Mpc.SendAsync(Commands.Playlists.Current.AddDirectory(directory)); + Assert.IsTrue(message.HasSuccessResponse()); + } + + private async Task Add_File(string file) + { + var message = await Mpc.SendAsync(Commands.Playlists.Current.AddSong(file)); + Assert.IsTrue(message.HasSuccessResponse()); + } + + private async Task Remove_Position(int position) + { + var message = await Mpc.SendAsync(Commands.Playlists.Current.RemoveSongByPosition(position)); + Assert.IsTrue(message.HasSuccessResponse()); + } + + private async Task Remove_Id(int songId) + { + var message = await Mpc.SendAsync(Commands.Playlists.Current.RemoveSongById(songId)); + Assert.IsTrue(message.HasSuccessResponse()); + } + + private async Task Get_Song_Id() + { + var message = await Mpc.SendAsync(Commands.Playlists.Current.GetAllSongMetadata()); + return message.Response.Body.Single().Id; + } } } diff --git a/src/MpcNET.Test/Tests/ReflectionCommandsTest.cs b/src/MpcNET.Test/Tests/ReflectionCommandsTest.cs index 53ad7ed..169b91b 100644 --- a/src/MpcNET.Test/Tests/ReflectionCommandsTest.cs +++ b/src/MpcNET.Test/Tests/ReflectionCommandsTest.cs @@ -1,7 +1,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json; namespace MpcNET.Test { @@ -13,7 +12,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Reflection.Commands()); TestOutput.WriteLine($"CommandsTest (commands: {response.Response.Body.Count()}) Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); // Different answer from MPD on Windows and on Linux, beacuse of Version. // Check some of the commands. @@ -31,7 +30,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Reflection.TagTypes()); TestOutput.WriteLine("TagTypesTest Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); Assert.IsTrue(response.Response.Body.Count().Equals(17)); } @@ -42,7 +41,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Reflection.UrlHandlers()); TestOutput.WriteLine($"UrlHandlersTest (handlers: {response.Response.Body.Count()}) Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); // Different answer from MPD on Windows and on Linux. // Check some of the handlers. @@ -58,7 +57,7 @@ namespace MpcNET.Test var response = await Mpc.SendAsync(new Commands.Reflection.Decoders()); TestOutput.WriteLine($"DecodersTest (decoders: {response.Response.Body.Count()}) Result:"); - TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine(response); // Different answer from MPD on Windows and on Linux. // Check some of the decoders. diff --git a/src/MpcNET/Commands/Commands.Database.cs b/src/MpcNET/Commands/Commands.Database.cs index 3be6c83..f5c5a22 100644 --- a/src/MpcNET/Commands/Commands.Database.cs +++ b/src/MpcNET/Commands/Commands.Database.cs @@ -5,7 +5,7 @@ using MpcNET.Types; namespace MpcNET { - public partial class Commands + public static partial class Commands { /// /// https://www.musicpd.org/doc/protocol/database.html diff --git a/src/MpcNET/Commands/Commands.Output.cs b/src/MpcNET/Commands/Commands.Output.cs index 1e13e9b..865cbc7 100644 --- a/src/MpcNET/Commands/Commands.Output.cs +++ b/src/MpcNET/Commands/Commands.Output.cs @@ -3,7 +3,7 @@ using MpcNET.Types; namespace MpcNET { - public partial class Commands + public static partial class Commands { /// /// https://www.musicpd.org/doc/protocol/output_commands.html diff --git a/src/MpcNET/Commands/Commands.Playlists.cs b/src/MpcNET/Commands/Commands.Playlists.cs index 1e0066b..b48d6f0 100644 --- a/src/MpcNET/Commands/Commands.Playlists.cs +++ b/src/MpcNET/Commands/Commands.Playlists.cs @@ -4,7 +4,7 @@ using MpcNET.Types; namespace MpcNET { - public partial class Commands + public static partial class Commands { public static class Playlists { @@ -13,7 +13,214 @@ namespace MpcNET /// public static class Current { - + /// + /// Adds the file URI to the playlist (directories add recursively). URI can also be a single file. + /// + private class AddImpl : IMpcCommand + { + private readonly string _uri; + + public AddImpl(string uri) + { + _uri = uri; + } + + public string Value => string.Join(" ", "add", $"\"{_uri}\""); + + public string FormatResponse(IList> response) + { + return string.Join(", ", response); + } + } + + /// + /// Command: add + /// + public static IMpcCommand AddDirectory(string directory) { return new AddImpl(directory); } + + /// + /// Adds a song to the playlist (non-recursive) and returns the song id. + /// + private class AddIdImpl : IMpcCommand + { + private readonly string _uri; + + public AddIdImpl(string uri) + { + _uri = uri; + } + + public string Value => string.Join(" ", "addid", $"\"{_uri}\""); + + public string FormatResponse(IList> response) + { + return string.Join(", ", response); + } + } + + /// + /// Command: addid + /// + public static IMpcCommand AddSong(string songPath) { return new AddIdImpl(songPath); } + + /// + /// Clears the current playlist. + /// + private class ClearImpl : IMpcCommand + { + public string Value => "clear"; + + public string FormatResponse(IList> response) + { + return string.Join(", ", response); + } + } + + /// + /// Command: clear + /// + public static IMpcCommand Clear() { return new ClearImpl(); } + + /// + /// Displays the current playlist. + /// + private class PlaylistImpl : IMpcCommand> + { + public string Value => "playlist"; + + public IEnumerable FormatResponse(IList> response) + { + var results = response.Select(line => new MpdFile(line.Value) { Pos = int.Parse(line.Key) }); + + return results; + } + } + + /// + /// Command: playlist + /// + public static IMpcCommand> GetAllSongsInfo() { return new PlaylistImpl(); } + + /// + /// Deletes a song from the playlist. + /// + private class DeleteImpl : IMpcCommand + { + private readonly int _position; + + public DeleteImpl(int position) + { + _position = position; + } + + public string Value => string.Join(" ", "delete", _position); + + public string FormatResponse(IList> response) + { + return string.Join(", ", response); + } + } + + /// + /// Command: delete + /// + public static IMpcCommand RemoveSongByPosition(int position) { return new DeleteImpl(position); } + + /// + /// Deletes the song SONGID from the playlist + /// + private class DeleteIdImpl : IMpcCommand + { + private readonly int _songId; + + public DeleteIdImpl(int songId) + { + _songId = songId; + } + + public string Value => string.Join(" ", "deleteid", _songId); + + public string FormatResponse(IList> response) + { + return string.Join(", ", response); + } + } + + /// + /// Command: deleteid + /// + public static IMpcCommand RemoveSongById(int songId) { return new DeleteIdImpl(songId); } + + /// + /// Displays song ID in the playlist. + /// + private class PlaylistIdImpl : IMpcCommand> + { + private readonly int _songId; + + public PlaylistIdImpl(int songId) + { + _songId = songId; + } + + public string Value => string.Join(" ", "playlistid", _songId); + + public IEnumerable FormatResponse(IList> response) + { + var results = new List(); + + foreach (var line in response) + { + if (line.Key.Equals("file")) + { + results.Add(new MpdFile(line.Value)); + } + else + { + results.Last().AddTag(line.Key, line.Value); + } + } + + return results; + } + } + + /// + /// Command: playlistid + /// + public static IMpcCommand> GetSongMetadata(int songId) { return new PlaylistIdImpl(songId); } + + /// + /// Displays a list of all songs in the playlist, + /// + private class PlaylistInfoImpl : IMpcCommand> + { + public string Value => "playlistinfo"; + + public IEnumerable FormatResponse(IList> response) + { + var results = new List(); + + foreach (var line in response) + { + if (line.Key.Equals("file")) + { + results.Add(new MpdFile(line.Value)); + } + else + { + results.Last().AddTag(line.Key, line.Value); + } + } + + return results; + } + } + + /// + /// Command: playlistinfo + /// + public static IMpcCommand> GetAllSongMetadata() { return new PlaylistInfoImpl(); } } /// @@ -21,11 +228,39 @@ namespace MpcNET /// public static class Stored { - public class ListPlaylist : IMpcCommand> + /// + /// Loads the playlist into the current queue. + /// + private class LoadImpl : IMpcCommand { private readonly string _playlistName; - public ListPlaylist(string playlistName) + public LoadImpl(string playlistName) + { + _playlistName = playlistName; + } + + public string Value => string.Join(" ", "load", $"\"{_playlistName}\""); + + public string FormatResponse(IList> response) + { + return string.Join(", ", response); + } + } + + /// + /// Command: load + /// + public static IMpcCommand Load(string playlistName) { return new LoadImpl(playlistName); } + + /// + /// Lists the songs in the playlist. + /// + private class ListPlaylistImpl : IMpcCommand> + { + private readonly string _playlistName; + + public ListPlaylistImpl(string playlistName) { _playlistName = playlistName; } @@ -40,11 +275,19 @@ namespace MpcNET } } - public class ListPlaylistInfo : IMpcCommand> + /// + /// Command: listplaylist + /// + public static IMpcCommand> GetContent(string playlistName) { return new ListPlaylistImpl(playlistName); } + + /// + /// Lists the songs with metadata in the playlist. + /// + private class ListPlaylistInfoImpl : IMpcCommand> { private readonly string _playlistName; - public ListPlaylistInfo(string playlistName) + public ListPlaylistInfoImpl(string playlistName) { _playlistName = playlistName; } @@ -71,10 +314,15 @@ namespace MpcNET } } + /// + /// Command: listplaylistinfo + /// + public static IMpcCommand> GetContentWithMetadata(string playlistName) { return new ListPlaylistInfoImpl(playlistName); } + /// /// Prints a list of the playlist directory. /// - public class ListPlaylists : IMpcCommand> + private class ListPlaylistsImpl : IMpcCommand> { public string Value => "listplaylists"; @@ -97,6 +345,11 @@ namespace MpcNET return result; } } + + /// + /// Command: listplaylists + /// + public static IMpcCommand> GetAll() { return new ListPlaylistsImpl(); } } } } diff --git a/src/MpcNET/Commands/Commands.Reflection.cs b/src/MpcNET/Commands/Commands.Reflection.cs index 13022b5..bb6a522 100644 --- a/src/MpcNET/Commands/Commands.Reflection.cs +++ b/src/MpcNET/Commands/Commands.Reflection.cs @@ -4,7 +4,7 @@ using MpcNET.Types; namespace MpcNET { - public partial class Commands + public static partial class Commands { /// /// https://www.musicpd.org/doc/protocol/reflection_commands.html diff --git a/src/MpcNET/Message/MpdMessage.cs b/src/MpcNET/Message/MpdMessage.cs index 2d72054..0cb7115 100644 --- a/src/MpcNET/Message/MpdMessage.cs +++ b/src/MpcNET/Message/MpdMessage.cs @@ -15,7 +15,7 @@ namespace MpcNET.Message [DebuggerDisplay("Request: {Request.Command.Value} | Response Status: {Response.State.Status}")] public class MpdMessage : IMpdMessage { - private readonly Regex _linePattern = new Regex("^(?[A-Za-z_-]*):[ ]{0,1}(?.*)$"); + private readonly Regex _linePattern = new Regex(@"^(?[\w-]*):[ ]{0,1}(?.*)$"); private readonly IList _rawResponse; public MpdMessage(IMpcCommand command, bool connected, IReadOnlyCollection response) diff --git a/src/MpcNET/MpcNET.csproj b/src/MpcNET/MpcNET.csproj index 81a1985..2e967df 100644 --- a/src/MpcNET/MpcNET.csproj +++ b/src/MpcNET/MpcNET.csproj @@ -12,6 +12,10 @@ MpcNET + + + + diff --git a/src/MpcNET/Types/IMpdFile.cs b/src/MpcNET/Types/IMpdFile.cs index 5acce17..bd7366c 100644 --- a/src/MpcNET/Types/IMpdFile.cs +++ b/src/MpcNET/Types/IMpdFile.cs @@ -4,7 +4,7 @@ namespace MpcNET.Types { public interface IMpdFilePath { - string File { get; } + string Path { get; } } public interface IMpdFile : IMpdFilePath diff --git a/src/MpcNET/Types/MpdFile.cs b/src/MpcNET/Types/MpdFile.cs index 85368d1..74803d1 100644 --- a/src/MpcNET/Types/MpdFile.cs +++ b/src/MpcNET/Types/MpdFile.cs @@ -29,10 +29,10 @@ namespace MpcNET.Types { file.CheckNotNull(); - File = file; + Path = file; } - public string File { get; } + public string Path { get; } public int Time { get; private set; } = -1; public string Album { get; private set; } = string.Empty; public string Artist { get; private set; } = string.Empty; @@ -45,7 +45,7 @@ namespace MpcNET.Types public string Performer { get; private set; } = string.Empty; public string Comment { get; private set; } = string.Empty; public int Disc { get; private set; } = -1; - public int Pos { get; private set; } = -1; + public int Pos { get; set; } = -1; public int Id { get; private set; } = -1; public IDictionary UnknownMetadata => _unknownMetadata;