mirror of
https://github.com/ZetaKebab/MpcNET.git
synced 2025-01-14 22:18:43 +00:00
Merge from refactoringResponse branch
This commit is contained in:
commit
b2e17742c2
@ -24,10 +24,6 @@ Global
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LibMpc.Types;
|
||||
|
||||
namespace LibMpc
|
||||
{
|
||||
@ -11,8 +12,11 @@ namespace LibMpc
|
||||
public class Database
|
||||
{
|
||||
// TODO: count
|
||||
|
||||
public class Find : IMpcCommand<IList<IDictionary<string, string>>>
|
||||
|
||||
/// <summary>
|
||||
/// Finds songs in the database that is exactly "searchText".
|
||||
/// </summary>
|
||||
public class Find : IMpcCommand<IEnumerable<IMpdFile>>
|
||||
{
|
||||
private readonly ITag _tag;
|
||||
private readonly string _searchText;
|
||||
@ -25,22 +29,19 @@ namespace LibMpc
|
||||
|
||||
public string Value => string.Join(" ", "find", _tag.Value, _searchText);
|
||||
|
||||
public IDictionary<string, IList<IDictionary<string, string>>> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<IMpdFile> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var results = new Dictionary<string, IList<IDictionary<string, string>>>
|
||||
{
|
||||
{ "files", new List<IDictionary<string, string>>() }
|
||||
};
|
||||
var results = new List<MpdFile>();
|
||||
|
||||
foreach (var line in response)
|
||||
{
|
||||
if (line.Key.Equals("file"))
|
||||
{
|
||||
results["files"].Add(new Dictionary<string, string> { { "file", line.Value } });
|
||||
results.Add(new MpdFile(line.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
results["files"].Last().Add(line.Key, line.Value);
|
||||
results.Last().AddTag(line.Key, line.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,50 +60,40 @@ namespace LibMpc
|
||||
|
||||
public string Value => string.Join(" ", "list", _tag);
|
||||
|
||||
public IDictionary<string, string> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
public string FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
return response.ToDefaultDictionary();
|
||||
// TODO:
|
||||
return response.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: findadd
|
||||
|
||||
public class ListAll : IMpcCommand<IList<IDictionary<string, IList<string>>>>
|
||||
public class ListAll : IMpcCommand<IEnumerable<MpdDirectory>>
|
||||
{
|
||||
public string Value => "listall";
|
||||
|
||||
public IDictionary<string, IList<IDictionary<string, IList<string>>>> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<MpdDirectory> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var results = new Dictionary<string, IList<IDictionary<string, IList<string>>>>
|
||||
var rootDirectory = new List<MpdDirectory>
|
||||
{
|
||||
{ "directories", new List<IDictionary<string, IList<string>>>() }
|
||||
new MpdDirectory("/") // Add by default the root directory
|
||||
};
|
||||
|
||||
// Add by default the root directory
|
||||
results["directories"].Add(new Dictionary<string, IList<string>>
|
||||
{
|
||||
{ "path", new List<string>() },
|
||||
{ "files", new List<string>() }
|
||||
});
|
||||
|
||||
foreach (var line in response)
|
||||
{
|
||||
if (line.Key.Equals("file"))
|
||||
{
|
||||
results["directories"].Last()["files"].Add(line.Value);
|
||||
rootDirectory.Last().AddFile(line.Value);
|
||||
}
|
||||
|
||||
if (line.Key.Equals("directory"))
|
||||
{
|
||||
results["directories"].Add(new Dictionary<string, IList<string>>
|
||||
{
|
||||
{ "path", new []{ line.Value } },
|
||||
{ "files", new List<string>() }
|
||||
});
|
||||
rootDirectory.Add(new MpdDirectory(line.Value));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
return rootDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,9 +110,10 @@ namespace LibMpc
|
||||
// TODO: Extend command: < update [URI] >
|
||||
public string Value => "update";
|
||||
|
||||
public IDictionary<string, string> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
public string FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
return response.ToDefaultDictionary();
|
||||
// TODO:
|
||||
return response.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using LibMpc.Types;
|
||||
|
||||
namespace LibMpc
|
||||
{
|
||||
@ -23,9 +24,10 @@ namespace LibMpc
|
||||
|
||||
public string Value => string.Join(" ", "disableoutput", _outputId);
|
||||
|
||||
public IDictionary<string, string> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
public string FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
return response.ToDefaultDictionary();
|
||||
// Response should be empty.
|
||||
return string.Join(", ", response);
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,40 +45,52 @@ namespace LibMpc
|
||||
|
||||
public string Value => string.Join(" ", "enableoutput", _outputId);
|
||||
|
||||
public IDictionary<string, string> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
public string FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
return response.ToDefaultDictionary();
|
||||
// Response should be empty.
|
||||
return string.Join(", ", response);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: toggleoutput // Turns an output on or off, depending on the current state.
|
||||
/// <summary>
|
||||
/// Turns an output on or off, depending on the current state.
|
||||
/// </summary>
|
||||
public class ToggleOutput : IMpcCommand<string>
|
||||
{
|
||||
private readonly int _outputId;
|
||||
|
||||
public ToggleOutput(int outputId)
|
||||
{
|
||||
_outputId = outputId;
|
||||
}
|
||||
|
||||
public string Value => string.Join(" ", "toggleoutput", _outputId);
|
||||
|
||||
public string FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
// Response should be empty.
|
||||
return string.Join(", ", response);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows information about all outputs.
|
||||
/// </summary>
|
||||
public class Outputs : IMpcCommand<IList<IDictionary<string, string>>>
|
||||
public class Outputs : IMpcCommand<IEnumerable<MpdOutput>>
|
||||
{
|
||||
public string Value => "outputs";
|
||||
|
||||
public IDictionary<string, IList<IDictionary<string, string>>> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<MpdOutput> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var result = new Dictionary<string, IList<IDictionary<string, string>>>
|
||||
{
|
||||
{ "outputs", new List<IDictionary<string, string>>() }
|
||||
};
|
||||
var result = new List<MpdOutput>();
|
||||
|
||||
for (var i = 0; i < response.Count; i += 3)
|
||||
{
|
||||
var outputId = response[i].Value;
|
||||
var outputId = int.Parse(response[i].Value);
|
||||
var outputName = response[i + 1].Value;
|
||||
var outputEnabled = response[i + 2].Value;
|
||||
var outputEnabled = response[i + 2].Value == "1";
|
||||
|
||||
result["outputs"].Add(new Dictionary<string, string>
|
||||
{
|
||||
{"id", outputId},
|
||||
{"name", outputName},
|
||||
{"enabled", outputEnabled}
|
||||
});
|
||||
result.Add(new MpdOutput(outputId, outputName, outputEnabled));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
103
LibMpc/Commands/Commands.Playlists.cs
Normal file
103
LibMpc/Commands/Commands.Playlists.cs
Normal file
@ -0,0 +1,103 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LibMpc.Types;
|
||||
|
||||
namespace LibMpc
|
||||
{
|
||||
public partial class Commands
|
||||
{
|
||||
public static class Playlists
|
||||
{
|
||||
/// <summary>
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html
|
||||
/// </summary>
|
||||
public static class Current
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://www.musicpd.org/doc/protocol/playlist_files.html
|
||||
/// </summary>
|
||||
public static class Stored
|
||||
{
|
||||
public class ListPlaylist : IMpcCommand<IEnumerable<IMpdFilePath>>
|
||||
{
|
||||
private readonly string _playlistName;
|
||||
|
||||
public ListPlaylist(string playlistName)
|
||||
{
|
||||
_playlistName = playlistName;
|
||||
}
|
||||
|
||||
public string Value => string.Join(" ", "listplaylist", $"\"{_playlistName}\"");
|
||||
|
||||
public IEnumerable<IMpdFilePath> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var results = response.Where(line => line.Key.Equals("file")).Select(line => new MpdFile(line.Value));
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
public class ListPlaylistInfo : IMpcCommand<IEnumerable<IMpdFile>>
|
||||
{
|
||||
private readonly string _playlistName;
|
||||
|
||||
public ListPlaylistInfo(string playlistName)
|
||||
{
|
||||
_playlistName = playlistName;
|
||||
}
|
||||
|
||||
public string Value => string.Join(" ", "listplaylistinfo", $"\"{_playlistName}\"");
|
||||
|
||||
public IEnumerable<IMpdFile> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var results = new List<MpdFile>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints a list of the playlist directory.
|
||||
/// </summary>
|
||||
public class ListPlaylists : IMpcCommand<IEnumerable<MpdPlaylist>>
|
||||
{
|
||||
public string Value => "listplaylists";
|
||||
|
||||
public IEnumerable<MpdPlaylist> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var result = new List<MpdPlaylist>();
|
||||
|
||||
foreach (var line in response)
|
||||
{
|
||||
if (line.Key.Equals("playlist"))
|
||||
{
|
||||
result.Add(new MpdPlaylist(line.Value));
|
||||
}
|
||||
else if (line.Key.Equals("Last-Modified"))
|
||||
{
|
||||
result.Last().AddLastModified(line.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LibMpc.Types;
|
||||
|
||||
namespace LibMpc
|
||||
{
|
||||
@ -10,27 +11,93 @@ namespace LibMpc
|
||||
/// </summary>
|
||||
public static class Reflection
|
||||
{
|
||||
// TODO: config
|
||||
// TODO: commands
|
||||
// TODO: notcommands
|
||||
// config : This command is only permitted to "local" clients (connected via UNIX domain socket).
|
||||
|
||||
public class TagTypes : IMpcCommand<IList<string>>
|
||||
/// <summary>
|
||||
/// Shows which commands the current user has access to.
|
||||
/// </summary>
|
||||
public class Commands : IMpcCommand<IEnumerable<string>>
|
||||
{
|
||||
public string Value => "tagtypes";
|
||||
public string Value => "commands";
|
||||
|
||||
IDictionary<string, IList<string>> IMpcCommand<IList<string>>.FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<string> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var result = new Dictionary<string, IList<string>>
|
||||
{
|
||||
{ "tagtypes", response.Where(item => item.Key.Equals("tagtype")).Select(item => item.Value).ToList() }
|
||||
};
|
||||
var result = response.Where(item => item.Key.Equals("command")).Select(item => item.Value);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: urlhandlers
|
||||
// TODO: decoders
|
||||
// TODO: notcommands : Shows which commands the current user does not have access to.
|
||||
|
||||
/// <summary>
|
||||
/// Shows a list of available song metadata.
|
||||
/// </summary>
|
||||
public class TagTypes : IMpcCommand<IEnumerable<string>>
|
||||
{
|
||||
public string Value => "tagtypes";
|
||||
|
||||
public IEnumerable<string> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var result = response.Where(item => item.Key.Equals("tagtype")).Select(item => item.Value);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of available URL handlers.
|
||||
/// </summary>
|
||||
public class UrlHandlers : IMpcCommand<IEnumerable<string>>
|
||||
{
|
||||
public string Value => "urlhandlers";
|
||||
|
||||
public IEnumerable<string> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var result = response.Where(item => item.Key.Equals("handler")).Select(item => item.Value);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print a list of decoder plugins, followed by their supported suffixes and MIME types.
|
||||
/// </summary>
|
||||
public class Decoders : IMpcCommand<IEnumerable<MpdDecoderPlugin>>
|
||||
{
|
||||
public string Value => "decoders";
|
||||
|
||||
public IEnumerable<MpdDecoderPlugin> FormatResponse(IList<KeyValuePair<string, string>> response)
|
||||
{
|
||||
var result = new List<MpdDecoderPlugin>();
|
||||
|
||||
var mpdDecoderPlugin = MpdDecoderPlugin.Empty;
|
||||
foreach (var line in response)
|
||||
{
|
||||
if (line.Key.Equals("plugin"))
|
||||
{
|
||||
if (mpdDecoderPlugin.IsInitialized)
|
||||
{
|
||||
result.Add(mpdDecoderPlugin);
|
||||
}
|
||||
|
||||
mpdDecoderPlugin = new MpdDecoderPlugin(line.Value);
|
||||
}
|
||||
|
||||
if (line.Key.Equals("suffix") && mpdDecoderPlugin.IsInitialized)
|
||||
{
|
||||
mpdDecoderPlugin.AddSuffix(line.Value);
|
||||
}
|
||||
|
||||
if (line.Key.Equals("mime_type") && mpdDecoderPlugin.IsInitialized)
|
||||
{
|
||||
mpdDecoderPlugin.AddMediaType(line.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,18 +3,10 @@ using System.Linq;
|
||||
|
||||
namespace LibMpc
|
||||
{
|
||||
public interface IMpcCommand<T>
|
||||
public interface IMpcCommand<out T>
|
||||
{
|
||||
string Value { get; }
|
||||
|
||||
IDictionary<string, T> FormatResponse(IList<KeyValuePair<string, string>> response);
|
||||
}
|
||||
|
||||
internal static class MpdCommandExtensions
|
||||
{
|
||||
public static IDictionary<string, string> ToDefaultDictionary(this IList<KeyValuePair<string, string>> items)
|
||||
{
|
||||
return items.ToDictionary(item => item.Key, item => item.Value);
|
||||
}
|
||||
T FormatResponse(IList<KeyValuePair<string, string>> response);
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ namespace LibMpc
|
||||
[DebuggerDisplay("Request: {Request.Command.Value} | Response Status: {Response.State.Status}")]
|
||||
public class MpdMessage<T> : IMpdMessage<T>
|
||||
{
|
||||
private readonly Regex _linePattern = new Regex("^(?<key>[A-Za-z_]*):[ ]{0,1}(?<value>.*)$");
|
||||
private readonly Regex _linePattern = new Regex("^(?<key>[A-Za-z_-]*):[ ]{0,1}(?<value>.*)$");
|
||||
private readonly IList<string> _rawResponse;
|
||||
|
||||
public MpdMessage(IMpcCommand<T> command, bool connected, IReadOnlyCollection<string> response)
|
||||
|
@ -6,19 +6,19 @@ namespace LibMpc
|
||||
public interface IMpdResponse<T>
|
||||
{
|
||||
IMpdResponseState State { get; }
|
||||
IDictionary<string, T> Body { get; }
|
||||
T Body { get; }
|
||||
}
|
||||
|
||||
public class MpdResponse<T> : IMpdResponse<T>
|
||||
{
|
||||
public MpdResponse(string endLine, IDictionary<string, T> body, bool connected)
|
||||
public MpdResponse(string endLine, T body, bool connected)
|
||||
{
|
||||
State = new MpdResponseState(endLine, connected);
|
||||
Body = body;
|
||||
}
|
||||
|
||||
public IMpdResponseState State { get; }
|
||||
public IDictionary<string, T> Body { get; }
|
||||
public T Body { get; }
|
||||
}
|
||||
|
||||
public static class CheckNotNullExtension
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibMpc
|
||||
@ -14,6 +14,7 @@ namespace LibMpc
|
||||
{
|
||||
private static readonly Regex STATUS_AUDIO_REGEX = new Regex("^(?<sampleRate>[0-9]*):(?<bits>[0-9]*):(?<channels>[0-9]*)$");
|
||||
|
||||
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly IPEndPoint _server;
|
||||
private MpcConnection _connection;
|
||||
|
||||
@ -23,6 +24,7 @@ namespace LibMpc
|
||||
}
|
||||
|
||||
public bool IsConnected => _connection?.IsConnected ?? false;
|
||||
public string Version => _connection?.Version ?? "Unknown";
|
||||
|
||||
public async Task<bool> ConnectAsync()
|
||||
{
|
||||
@ -54,9 +56,15 @@ namespace LibMpc
|
||||
|
||||
public async Task<IMpdMessage<T>> SendAsync<T>(IMpcCommand<T> command)
|
||||
{
|
||||
var mpdMessage = await _connection.SendAsync(command);
|
||||
|
||||
return mpdMessage;
|
||||
await _semaphore.WaitAsync();
|
||||
try
|
||||
{
|
||||
return await _connection.SendAsync(command);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Generic;
|
||||
using LibMpc.Types;
|
||||
|
||||
namespace LibMpc
|
||||
{
|
||||
@ -9,13 +10,13 @@ namespace LibMpc
|
||||
/// </summary>
|
||||
public class MpdDirectoryListing
|
||||
{
|
||||
private readonly ReadOnlyCollection<MpdFile> file;
|
||||
private readonly ReadOnlyCollection<IMpdFile> file;
|
||||
private readonly ReadOnlyCollection<string> directory;
|
||||
private readonly ReadOnlyCollection<string> playlist;
|
||||
/// <summary>
|
||||
/// The list of files in the directory.
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<MpdFile> FileList { get { return this.file; } }
|
||||
public ReadOnlyCollection<IMpdFile> FileList { get { return this.file; } }
|
||||
/// <summary>
|
||||
/// The list of subdirectories in the directory.
|
||||
/// </summary>
|
||||
@ -30,7 +31,7 @@ namespace LibMpc
|
||||
/// <param name="file">The list of files in the directory.</param>
|
||||
/// <param name="directory">The list of subdirectories in the directory.</param>
|
||||
/// <param name="playlist">The list of playlists in the directory.</param>
|
||||
public MpdDirectoryListing(List<MpdFile> file, List<string> directory, List<string> playlist)
|
||||
public MpdDirectoryListing(List<IMpdFile> file, List<string> directory, List<string> playlist)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException("file");
|
||||
@ -39,7 +40,7 @@ namespace LibMpc
|
||||
if (playlist == null)
|
||||
throw new ArgumentNullException("playlist");
|
||||
|
||||
this.file = new ReadOnlyCollection<MpdFile>(file);
|
||||
this.file = new ReadOnlyCollection<IMpdFile>(file);
|
||||
this.directory = new ReadOnlyCollection<string>(directory);
|
||||
this.playlist = new ReadOnlyCollection<string>(playlist);
|
||||
}
|
||||
@ -49,7 +50,7 @@ namespace LibMpc
|
||||
/// <param name="file">The list of files in the directory.</param>
|
||||
/// <param name="directory">The list of subdirectories in the directory.</param>
|
||||
/// <param name="playlist">The list of playlists in the directory.</param>
|
||||
public MpdDirectoryListing(ReadOnlyCollection<MpdFile> file, ReadOnlyCollection<string> directory, ReadOnlyCollection<string> playlist)
|
||||
public MpdDirectoryListing(ReadOnlyCollection<IMpdFile> file, ReadOnlyCollection<string> directory, ReadOnlyCollection<string> playlist)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException("file");
|
||||
|
@ -1,544 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LibMpc
|
||||
{
|
||||
/// <summary>
|
||||
/// The MpdFile class contains all meta data for a file of the MPD.
|
||||
/// </summary>
|
||||
public class MpdFile
|
||||
{
|
||||
private const string TAG_FILE = "file";
|
||||
private const string TAG_TIME = "Time";
|
||||
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 const string TAG_POS = "Pos";
|
||||
private const string TAG_ID = "Id";
|
||||
|
||||
private const int NO_TIME = -1;
|
||||
private const string NO_ALBUM = null;
|
||||
private const string NO_ARTIST = null;
|
||||
private const string NO_TITLE = null;
|
||||
private const string NO_TRACK = null;
|
||||
private const string NO_NAME = null;
|
||||
private const string NO_GENRE = null;
|
||||
private const string NO_DATE = null;
|
||||
private const string NO_COMPOSER = null;
|
||||
private const string NO_PERFORMER = null;
|
||||
private const string NO_COMMENT = null;
|
||||
private const int NO_DISC = -1;
|
||||
private const int NO_POS = -1;
|
||||
private const int NO_ID = -1;
|
||||
|
||||
private readonly string file;
|
||||
private readonly int time;
|
||||
private readonly string album;
|
||||
private readonly string artist;
|
||||
private readonly string title;
|
||||
private readonly string track;
|
||||
private readonly string name;
|
||||
private readonly string genre;
|
||||
private readonly string date;
|
||||
private readonly string composer;
|
||||
private readonly string performer;
|
||||
private readonly string comment;
|
||||
private readonly int disc;
|
||||
private readonly int pos;
|
||||
private readonly int id;
|
||||
/// <summary>
|
||||
/// The name and path of the file.
|
||||
/// </summary>
|
||||
public string File { get { return this.file; } }
|
||||
/// <summary>
|
||||
/// The length of the file in seconds.
|
||||
/// </summary>
|
||||
public int Time { get { return this.time; } }
|
||||
/// <summary>
|
||||
/// The album of the file.
|
||||
/// </summary>
|
||||
public string Album { get { return this.album; } }
|
||||
/// <summary>
|
||||
/// The artist of the file.
|
||||
/// </summary>
|
||||
public string Artist { get { return this.artist; } }
|
||||
/// <summary>
|
||||
/// The title of the file.
|
||||
/// </summary>
|
||||
public string Title { get { return this.title; } }
|
||||
/// <summary>
|
||||
/// The value of the track property of the file.
|
||||
/// </summary>
|
||||
public string Track { get { return this.track; } }
|
||||
/// <summary>
|
||||
/// The name of the song.
|
||||
/// </summary>
|
||||
public string Name { get { return this.name; } }
|
||||
/// <summary>
|
||||
/// The genre of the song.
|
||||
/// </summary>
|
||||
public string Genre { get { return this.genre; } }
|
||||
/// <summary>
|
||||
/// The date the song was released.
|
||||
/// </summary>
|
||||
public string Date { get { return this.date; } }
|
||||
/// <summary>
|
||||
/// The composer of the song.
|
||||
/// </summary>
|
||||
public string Composer { get { return this.composer; } }
|
||||
/// <summary>
|
||||
/// The performer of the song.
|
||||
/// </summary>
|
||||
public string Performer { get { return this.performer; } }
|
||||
/// <summary>
|
||||
/// A comment to the file.
|
||||
/// </summary>
|
||||
public string Comment { get { return this.comment; } }
|
||||
/// <summary>
|
||||
/// The number of the disc on a multidisc album.
|
||||
/// </summary>
|
||||
public int Disc { get { return this.disc; } }
|
||||
/// <summary>
|
||||
/// The index of the file in a playlist.
|
||||
/// </summary>
|
||||
public int Pos { get { return this.pos; } }
|
||||
/// <summary>
|
||||
/// The id of the file in a playlist.
|
||||
/// </summary>
|
||||
public int Id { get { return this.id; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Time"/> property set.
|
||||
/// </summary>
|
||||
public bool HasTime { get { return this.time != NO_TIME; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Album"/> property set.
|
||||
/// </summary>
|
||||
public bool HasAlbum { get { return this.album != NO_ALBUM; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Artist"/> property set.
|
||||
/// </summary>
|
||||
public bool HasArtist { get { return this.artist != NO_ARTIST; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Title"/> property set.
|
||||
/// </summary>
|
||||
public bool HasTitle { get { return this.title != NO_TITLE; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Track"/> property set.
|
||||
/// </summary>
|
||||
public bool HasTrack { get { return this.track != NO_TRACK; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Name"/> property set.
|
||||
/// </summary>
|
||||
public bool HasName { get { return this.name != NO_NAME; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Genre"/> property set.
|
||||
/// </summary>
|
||||
public bool HasGenre { get { return this.genre != NO_GENRE; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Date"/> property set.
|
||||
/// </summary>
|
||||
public bool HasDate { get { return this.date != NO_DATE; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Composer"/> property set.
|
||||
/// </summary>
|
||||
public bool HasComposer { get { return this.composer != NO_COMPOSER; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Performer"/> property set.
|
||||
/// </summary>
|
||||
public bool HasPerformer { get { return this.performer != NO_PERFORMER; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Comment"/> property set.
|
||||
/// </summary>
|
||||
public bool HasComment { get { return this.comment != NO_COMMENT; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Disc"/> property set.
|
||||
/// </summary>
|
||||
public bool HasDisc { get { return this.disc != NO_DISC; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Pos"/> property set.
|
||||
/// </summary>
|
||||
public bool HasPos { get { return this.pos != NO_POS; } }
|
||||
/// <summary>
|
||||
/// If the MpdFile has the <see cref="Id"/> property set.
|
||||
/// </summary>
|
||||
public bool HasId { get { return this.id != NO_ID; } }
|
||||
/// <summary>
|
||||
/// Creates a new MpdFile.
|
||||
/// </summary>
|
||||
/// <param name="file">The name and path of the file.</param>
|
||||
/// <param name="time">The length of the file in seconds.</param>
|
||||
/// <param name="album">The album of the file.</param>
|
||||
/// <param name="artist">The artist of the file.</param>
|
||||
/// <param name="title">The title of the file.</param>
|
||||
/// <param name="track">The value of the track property of the file.</param>
|
||||
/// <param name="name">The name of the song.</param>
|
||||
/// <param name="genre">The genre of the song.</param>
|
||||
/// <param name="date">The date the song was released.</param>
|
||||
/// <param name="composer">The composer of the song.</param>
|
||||
/// <param name="performer">The performer of the song.</param>
|
||||
/// <param name="comment">A comment to the file.</param>
|
||||
/// <param name="disc">The number of the disc on a multidisc album.</param>
|
||||
/// <param name="pos">The index of the file in a playlist.</param>
|
||||
/// <param name="id">The id of the file in a playlist.</param>
|
||||
public MpdFile(string file,
|
||||
int time,
|
||||
string album,
|
||||
string artist,
|
||||
string title,
|
||||
string track,
|
||||
string name,
|
||||
string genre,
|
||||
string date,
|
||||
string composer,
|
||||
string performer,
|
||||
string comment,
|
||||
int disc,
|
||||
int pos,
|
||||
int id)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException("file");
|
||||
|
||||
this.file = file;
|
||||
this.time = time;
|
||||
this.album = album;
|
||||
this.artist = artist;
|
||||
this.title = title;
|
||||
this.track = track;
|
||||
this.name = name;
|
||||
this.genre = genre;
|
||||
this.date = date;
|
||||
this.composer = composer;
|
||||
this.performer = performer;
|
||||
this.comment = comment;
|
||||
this.disc = disc;
|
||||
this.pos = pos;
|
||||
this.id = id;
|
||||
}
|
||||
/// <summary>
|
||||
/// A string containing all the properties of the file.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
appendString(builder, TAG_FILE, this.file);
|
||||
if (this.HasTime)
|
||||
appendInt(builder, TAG_TIME, this.time);
|
||||
if (this.HasAlbum)
|
||||
appendString(builder, TAG_ALBUM, this.album);
|
||||
if (this.HasArtist)
|
||||
appendString(builder, TAG_ARTIST, this.artist);
|
||||
if (this.HasTitle)
|
||||
appendString(builder, TAG_TITLE, this.title);
|
||||
if (this.HasTrack)
|
||||
appendString(builder, TAG_TRACK, this.track);
|
||||
if (this.HasName)
|
||||
appendString(builder, TAG_NAME, this.name);
|
||||
if (this.HasGenre)
|
||||
appendString(builder, TAG_GENRE, this.genre);
|
||||
if (this.HasDate)
|
||||
appendString(builder, TAG_DATE, this.date);
|
||||
if (this.HasComposer)
|
||||
appendString(builder, TAG_COMPOSER, this.composer);
|
||||
if (this.HasPerformer)
|
||||
appendString(builder, TAG_PERFORMER, this.performer);
|
||||
if (this.HasComment)
|
||||
appendString(builder, TAG_COMMENT, this.comment);
|
||||
if (this.HasDisc)
|
||||
appendInt(builder, TAG_DISC, this.disc);
|
||||
if (this.HasPos)
|
||||
appendInt(builder, TAG_POS, this.pos);
|
||||
if (this.HasId)
|
||||
appendInt(builder, TAG_ID, this.id);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static void appendString(StringBuilder builder, string name, string value)
|
||||
{
|
||||
builder.Append(name);
|
||||
builder.Append(": ");
|
||||
builder.Append(value);
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
private static void appendInt(StringBuilder builder, string name, int value)
|
||||
{
|
||||
builder.Append(name);
|
||||
builder.Append(": ");
|
||||
builder.Append(value);
|
||||
builder.AppendLine();
|
||||
}
|
||||
/*
|
||||
/// <summary>
|
||||
/// Returns a MpdFile object from a MpdResponse object.
|
||||
/// </summary>
|
||||
/// <param name="response">The response of the MPD server.</param>
|
||||
/// <returns>A new MpdFile object build from the MpdResponse object.</returns>
|
||||
public static MpdFile build(MpdResponse response)
|
||||
{
|
||||
if (response == null)
|
||||
throw new ArgumentNullException("response");
|
||||
|
||||
string file = null;
|
||||
int time = NO_TIME;
|
||||
string album = NO_ALBUM;
|
||||
string artist = NO_ARTIST;
|
||||
string title = NO_TITLE;
|
||||
string track = NO_TRACK;
|
||||
string name = NO_NAME;
|
||||
string genre = NO_GENRE;
|
||||
string date = NO_DATE;
|
||||
string composer = NO_COMPOSER;
|
||||
string performer = NO_PERFORMER;
|
||||
string comment = NO_COMMENT;
|
||||
int disc = NO_DISC;
|
||||
int pos = NO_POS;
|
||||
int id = NO_ID;
|
||||
|
||||
|
||||
foreach (KeyValuePair<string, string> line in response)
|
||||
{
|
||||
if( line.Key != null )
|
||||
switch (line.Key)
|
||||
{
|
||||
case TAG_FILE:
|
||||
file = line.Value;
|
||||
break;
|
||||
case TAG_TIME:
|
||||
int tryTime;
|
||||
if( int.TryParse( line.Value, out tryTime ) )
|
||||
time = tryTime;
|
||||
break;
|
||||
case TAG_ALBUM:
|
||||
album = line.Value;
|
||||
break;
|
||||
case TAG_ARTIST:
|
||||
artist = line.Value;
|
||||
break;
|
||||
case TAG_TITLE:
|
||||
title = line.Value;
|
||||
break;
|
||||
case TAG_TRACK:
|
||||
track = line.Value;
|
||||
break;
|
||||
case TAG_NAME:
|
||||
name = line.Value;
|
||||
break;
|
||||
case TAG_GENRE:
|
||||
genre = line.Value;
|
||||
break;
|
||||
case TAG_DATE:
|
||||
date = line.Value;
|
||||
break;
|
||||
case TAG_COMPOSER:
|
||||
composer = line.Value;
|
||||
break;
|
||||
case TAG_PERFORMER:
|
||||
performer = line.Value;
|
||||
break;
|
||||
case TAG_COMMENT:
|
||||
comment = line.Value;
|
||||
break;
|
||||
case TAG_DISC:
|
||||
int tryDisc;
|
||||
if (int.TryParse(line.Value, out tryDisc))
|
||||
disc = tryDisc;
|
||||
break;
|
||||
case TAG_POS:
|
||||
int tryPos;
|
||||
if (int.TryParse(line.Value, out tryPos))
|
||||
pos = tryPos;
|
||||
break;
|
||||
case TAG_ID:
|
||||
int tryId;
|
||||
if (int.TryParse(line.Value, out tryId))
|
||||
id = tryId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (file == null)
|
||||
return null;
|
||||
else
|
||||
return new MpdFile(
|
||||
file,
|
||||
time,
|
||||
album,
|
||||
artist,
|
||||
title,
|
||||
track,
|
||||
name,
|
||||
genre,
|
||||
date,
|
||||
composer,
|
||||
performer,
|
||||
comment,
|
||||
disc,
|
||||
pos,
|
||||
id);
|
||||
}
|
||||
/// <summary>
|
||||
/// Builds a list of MpdFile objects from a MpdResponse object.
|
||||
/// </summary>
|
||||
/// <param name="response">The MpdResponse object to build the list of MpdFiles from.</param>
|
||||
/// <returns>A list ob MpdFiles built from the MpdResponse object.</returns>
|
||||
public static List<MpdFile> buildList(MpdResponse response)
|
||||
{
|
||||
if (response == null)
|
||||
throw new ArgumentNullException("response");
|
||||
|
||||
List<MpdFile> ret = new List<MpdFile>();
|
||||
|
||||
string file = null;
|
||||
int time = NO_TIME;
|
||||
string album = NO_ALBUM;
|
||||
string artist = NO_ARTIST;
|
||||
string title = NO_TITLE;
|
||||
string track = NO_TRACK;
|
||||
string name = NO_NAME;
|
||||
string genre = NO_GENRE;
|
||||
string date = NO_DATE;
|
||||
string composer = NO_COMPOSER;
|
||||
string performer = NO_PERFORMER;
|
||||
string comment = NO_COMMENT;
|
||||
int disc = NO_DISC;
|
||||
int pos = NO_POS;
|
||||
int id = NO_ID;
|
||||
|
||||
|
||||
foreach (KeyValuePair<string, string> line in response)
|
||||
{
|
||||
if( line.Key != null )
|
||||
switch (line.Key)
|
||||
{
|
||||
case TAG_FILE:
|
||||
if( file != null )
|
||||
ret.Add( new MpdFile(
|
||||
file,
|
||||
time,
|
||||
album,
|
||||
artist,
|
||||
title,
|
||||
track,
|
||||
name,
|
||||
genre,
|
||||
date,
|
||||
composer,
|
||||
performer,
|
||||
comment,
|
||||
disc,
|
||||
pos,
|
||||
id ) );
|
||||
|
||||
file = line.Value;
|
||||
|
||||
time = NO_TIME;
|
||||
album = NO_ALBUM;
|
||||
artist = NO_ARTIST;
|
||||
title = NO_TITLE;
|
||||
track = NO_TRACK;
|
||||
name = NO_NAME;
|
||||
genre = NO_GENRE;
|
||||
date = NO_DATE;
|
||||
composer = NO_COMPOSER;
|
||||
performer = NO_PERFORMER;
|
||||
comment = NO_COMMENT;
|
||||
disc = NO_DISC;
|
||||
pos = NO_POS;
|
||||
id = NO_ID;
|
||||
|
||||
break;
|
||||
case TAG_TIME:
|
||||
int tryTime;
|
||||
if( int.TryParse( line.Value, out tryTime ) )
|
||||
time = tryTime;
|
||||
break;
|
||||
case TAG_ALBUM:
|
||||
album = line.Value;
|
||||
break;
|
||||
case TAG_ARTIST:
|
||||
artist = line.Value;
|
||||
break;
|
||||
case TAG_TITLE:
|
||||
title = line.Value;
|
||||
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;
|
||||
break;
|
||||
case TAG_GENRE:
|
||||
genre = line.Value;
|
||||
break;
|
||||
case TAG_DATE:
|
||||
date = line.Value;
|
||||
break;
|
||||
case TAG_COMPOSER:
|
||||
composer = line.Value;
|
||||
break;
|
||||
case TAG_PERFORMER:
|
||||
performer = line.Value;
|
||||
break;
|
||||
case TAG_COMMENT:
|
||||
comment = line.Value;
|
||||
break;
|
||||
case TAG_DISC:
|
||||
int tryDisc;
|
||||
if (int.TryParse(line.Value, out tryDisc))
|
||||
disc = tryDisc;
|
||||
break;
|
||||
case TAG_POS:
|
||||
int tryPos;
|
||||
if (int.TryParse(line.Value, out tryPos))
|
||||
pos = tryPos;
|
||||
break;
|
||||
case TAG_ID:
|
||||
int tryId;
|
||||
if (int.TryParse(line.Value, out tryId))
|
||||
id = tryId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (file != null)
|
||||
ret.Add(new MpdFile(
|
||||
file,
|
||||
time,
|
||||
album,
|
||||
artist,
|
||||
title,
|
||||
track,
|
||||
name,
|
||||
genre,
|
||||
date,
|
||||
composer,
|
||||
performer,
|
||||
comment,
|
||||
disc,
|
||||
pos,
|
||||
id ));
|
||||
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace LibMpc
|
||||
{
|
||||
/// <summary>
|
||||
/// The MpdOutput class contains all attributes of an output device of the MPD.
|
||||
/// </summary>
|
||||
public class MpdOutput
|
||||
{
|
||||
private readonly int id;
|
||||
private readonly string name;
|
||||
private readonly bool enabled;
|
||||
/// <summary>
|
||||
/// The id of the output.
|
||||
/// </summary>
|
||||
public int Id { get { return this.id; } }
|
||||
/// <summary>
|
||||
/// The name of the output.
|
||||
/// </summary>
|
||||
public string Name { get { return this.name; } }
|
||||
/// <summary>
|
||||
/// If the output is enabled.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get { return this.enabled; } }
|
||||
/// <summary>
|
||||
/// Creates a new MpdOutput object.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the output.</param>
|
||||
/// <param name="name">The name of the output.</param>
|
||||
/// <param name="enabled">If the output is enabled.</param>
|
||||
public MpdOutput(int id, string name, bool enabled)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException("name");
|
||||
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.enabled = enabled;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a string representation of the object mainly for debuging purpose.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the object.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return this.id + "::" + this.name + "::" + this.enabled;
|
||||
}
|
||||
}
|
||||
}
|
28
LibMpc/Types/IMpdFile.cs
Normal file
28
LibMpc/Types/IMpdFile.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LibMpc.Types
|
||||
{
|
||||
public interface IMpdFilePath
|
||||
{
|
||||
string File { get; }
|
||||
}
|
||||
|
||||
public interface IMpdFile : IMpdFilePath
|
||||
{
|
||||
int Time { get; }
|
||||
string Album { get; }
|
||||
string Artist { get; }
|
||||
string Title { get; }
|
||||
string Track { get; }
|
||||
string Name { get; }
|
||||
string Genre { get; }
|
||||
string Date { get; }
|
||||
string Composer { get; }
|
||||
string Performer { get; }
|
||||
string Comment { get; }
|
||||
int Disc { get; }
|
||||
int Pos { get; }
|
||||
int Id { get; }
|
||||
IDictionary<string, string> UnknownMetadata { get; }
|
||||
}
|
||||
}
|
36
LibMpc/Types/MpdDecoderPlugin.cs
Normal file
36
LibMpc/Types/MpdDecoderPlugin.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LibMpc.Types
|
||||
{
|
||||
public class MpdDecoderPlugin
|
||||
{
|
||||
public static readonly MpdDecoderPlugin Empty = new MpdDecoderPlugin(string.Empty);
|
||||
|
||||
private readonly IList<string> _suffixes = new List<string>();
|
||||
private readonly IList<string> _mediaTypes = new List<string>();
|
||||
|
||||
public MpdDecoderPlugin(string name)
|
||||
{
|
||||
name.CheckNotNull();
|
||||
|
||||
Name = name;
|
||||
IsInitialized = !string.IsNullOrEmpty(name);
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public IEnumerable<string> Suffixes => _suffixes;
|
||||
public IEnumerable<string> MediaTypes => _mediaTypes;
|
||||
|
||||
internal bool IsInitialized { get; }
|
||||
|
||||
internal void AddSuffix(string suffix)
|
||||
{
|
||||
_suffixes.Add(suffix);
|
||||
}
|
||||
|
||||
internal void AddMediaType(string type)
|
||||
{
|
||||
_mediaTypes.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
29
LibMpc/Types/MpdDirectory.cs
Normal file
29
LibMpc/Types/MpdDirectory.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibMpc.Types
|
||||
{
|
||||
public class MpdDirectory
|
||||
{
|
||||
private readonly IList<IMpdFilePath> _files = new List<IMpdFilePath>();
|
||||
|
||||
public MpdDirectory(string path)
|
||||
{
|
||||
path.CheckNotNull();
|
||||
|
||||
Path = path;
|
||||
|
||||
var name = path.Split('/').Last();
|
||||
Name = string.IsNullOrEmpty(name) ? "root" : name;
|
||||
}
|
||||
|
||||
public string Path { get; }
|
||||
public string Name { get; }
|
||||
public IEnumerable<IMpdFilePath> Files => _files;
|
||||
|
||||
internal void AddFile(string file)
|
||||
{
|
||||
_files.Add(new MpdFile(file));
|
||||
}
|
||||
}
|
||||
}
|
103
LibMpc/Types/MpdFile.cs
Normal file
103
LibMpc/Types/MpdFile.cs
Normal file
@ -0,0 +1,103 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LibMpc.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// The MpdFile class contains all meta data for a file of the MPD.
|
||||
/// </summary>
|
||||
internal class MpdFile : IMpdFile
|
||||
{
|
||||
private const string TagTime = "Time";
|
||||
private const string TagArtist = "Artist";
|
||||
private const string TagAlbum = "Album";
|
||||
private const string TagTitle = "Title";
|
||||
private const string TagTrack = "Track";
|
||||
private const string TagName = "Name";
|
||||
private const string TagGenre = "Genre";
|
||||
private const string TagDate = "Date";
|
||||
private const string TagComposer = "Composer";
|
||||
private const string TagPerformer = "Performer";
|
||||
private const string TagComment = "Comment";
|
||||
private const string TagDisc = "Disc";
|
||||
private const string TagPos = "Pos";
|
||||
private const string TagId = "Id";
|
||||
|
||||
private readonly IDictionary<string, string> _unknownMetadata = new Dictionary<string, string>();
|
||||
|
||||
internal MpdFile(string file)
|
||||
{
|
||||
file.CheckNotNull();
|
||||
|
||||
File = file;
|
||||
}
|
||||
|
||||
public string File { get; }
|
||||
public int Time { get; private set; } = -1;
|
||||
public string Album { get; private set; } = string.Empty;
|
||||
public string Artist { get; private set; } = string.Empty;
|
||||
public string Title { get; private set; } = string.Empty;
|
||||
public string Track { get; private set; } = string.Empty;
|
||||
public string Name { get; private set; } = string.Empty;
|
||||
public string Genre { get; private set; } = string.Empty;
|
||||
public string Date { get; private set; } = string.Empty;
|
||||
public string Composer { get; private set; } = string.Empty;
|
||||
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 Id { get; private set; } = -1;
|
||||
public IDictionary<string, string> UnknownMetadata => _unknownMetadata;
|
||||
|
||||
internal void AddTag(string tag, string value)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case TagTime:
|
||||
Time = int.Parse(value);
|
||||
break;
|
||||
case TagArtist:
|
||||
Artist = value;
|
||||
break;
|
||||
case TagAlbum:
|
||||
Album = value;
|
||||
break;
|
||||
case TagTitle:
|
||||
Title = value;
|
||||
break;
|
||||
case TagTrack:
|
||||
Track = value;
|
||||
break;
|
||||
case TagName:
|
||||
Name = value;
|
||||
break;
|
||||
case TagGenre:
|
||||
Genre = value;
|
||||
break;
|
||||
case TagDate:
|
||||
Date = value;
|
||||
break;
|
||||
case TagComposer:
|
||||
Composer = value;
|
||||
break;
|
||||
case TagPerformer:
|
||||
Performer = value;
|
||||
break;
|
||||
case TagComment:
|
||||
Comment = value;
|
||||
break;
|
||||
case TagDisc:
|
||||
Disc = int.Parse(value);
|
||||
break;
|
||||
case TagPos:
|
||||
Pos = int.Parse(value);
|
||||
break;
|
||||
case TagId:
|
||||
Id = int.Parse(value);
|
||||
break;
|
||||
default:
|
||||
_unknownMetadata.Add(tag, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
LibMpc/Types/MpdOutput.cs
Normal file
21
LibMpc/Types/MpdOutput.cs
Normal file
@ -0,0 +1,21 @@
|
||||
namespace LibMpc.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// The MpdOutput class contains all attributes of an output device of the MPD.
|
||||
/// </summary>
|
||||
public class MpdOutput
|
||||
{
|
||||
public MpdOutput(int id, string name, bool enabled)
|
||||
{
|
||||
name.CheckNotNull();
|
||||
|
||||
Id = id;
|
||||
Name = name;
|
||||
IsEnabled = enabled;
|
||||
}
|
||||
|
||||
public int Id { get; }
|
||||
public string Name { get; }
|
||||
public bool IsEnabled { get; }
|
||||
}
|
||||
}
|
23
LibMpc/Types/MpdPlaylist.cs
Normal file
23
LibMpc/Types/MpdPlaylist.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace LibMpc.Types
|
||||
{
|
||||
public class MpdPlaylist
|
||||
{
|
||||
public MpdPlaylist(string name)
|
||||
{
|
||||
name.CheckNotNull();
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public DateTime LastModified { get; private set; }
|
||||
|
||||
internal void AddLastModified(string lastModified)
|
||||
{
|
||||
LastModified = DateTime.Parse(lastModified, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using LibMpc;
|
||||
|
||||
namespace LibMpcApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple console app to test commands and parsed responses.
|
||||
/// </summary>
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var mpc = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600));
|
||||
|
||||
var connected = mpc.ConnectAsync().GetAwaiter().GetResult();
|
||||
if (connected)
|
||||
{
|
||||
Console.WriteLine("Connected to MPD.");
|
||||
StartReadCommands(mpc);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Could not connect to MPD.");
|
||||
}
|
||||
|
||||
mpc.DisconnectAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private static void StartReadCommands(Mpc mpc)
|
||||
{
|
||||
int userInput = 0;
|
||||
while ((userInput = DisplayMenu()) != 99)
|
||||
{
|
||||
var response = new object();
|
||||
|
||||
switch (userInput)
|
||||
{
|
||||
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: ");
|
||||
Console.WriteLine(response);
|
||||
}
|
||||
}
|
||||
|
||||
static public int DisplayMenu()
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Commands: ");
|
||||
|
||||
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();
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Windows User")]
|
||||
[assembly: AssemblyProduct("LibMpcApp")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("ff176ad5-d6da-41ee-b27d-1dbef0ce462f")]
|
@ -1,65 +1,15 @@
|
||||
using LibMpc;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace LibMpcTest
|
||||
{
|
||||
public class LibMpcTest : IClassFixture<MpdServerTest>, IDisposable
|
||||
public partial class LibMpcTest : IClassFixture<MpdMock>, IClassFixture<MpcMock>
|
||||
{
|
||||
private readonly MpdServerTest _server;
|
||||
private readonly ITestOutputHelper _output;
|
||||
private readonly Mpc _mpc;
|
||||
|
||||
public LibMpcTest(MpdServerTest server, ITestOutputHelper output)
|
||||
public LibMpcTest(MpcMock mpc)
|
||||
{
|
||||
_server = server;
|
||||
_output = output;
|
||||
|
||||
_mpc = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600));
|
||||
|
||||
var connected = Task.Run(async () => await _mpc.ConnectAsync()).Result;
|
||||
if (connected)
|
||||
{
|
||||
Console.Out.WriteLine("Connected to MPD.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Out.WriteLine("Could not connect to MPD.");
|
||||
}
|
||||
Mpc = mpc.Client;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TagTypesTest()
|
||||
{
|
||||
var response = await _mpc.SendAsync(new Commands.Reflection.TagTypes());
|
||||
|
||||
Console.Out.WriteLine("TagTypesTest Result:");
|
||||
Console.Out.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Keys.Contains("tagtypes"));
|
||||
Assert.True(response.Response.Body.Values.Any());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListAllTest()
|
||||
{
|
||||
var response = await _mpc.SendAsync(new Commands.Database.ListAll());
|
||||
|
||||
Console.Out.WriteLine("ListAllTest Result:");
|
||||
Console.Out.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Keys.Contains("directories"));
|
||||
Assert.True(response.Response.Body["directories"].Count.Equals(5));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_mpc?.DisconnectAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
internal Mpc Mpc { get; }
|
||||
}
|
||||
}
|
||||
|
26
LibMpcTest/MpcMock.cs
Normal file
26
LibMpcTest/MpcMock.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using LibMpc;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibMpcTest
|
||||
{
|
||||
public class MpcMock : IDisposable
|
||||
{
|
||||
public MpcMock()
|
||||
{
|
||||
Client = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600));
|
||||
|
||||
var connected = Task.Run(async () => await Client.ConnectAsync()).Result;
|
||||
TestOutput.WriteLine($"Connected to MPD : {connected}; Version: {Client.Version}");
|
||||
}
|
||||
|
||||
public Mpc Client { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Client?.DisconnectAsync().GetAwaiter().GetResult();
|
||||
TestOutput.WriteLine($"Disconnected from MPD.");
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,20 @@ namespace LibMpcTest
|
||||
builder.AppendLine("port \"6600\"");
|
||||
builder.AppendLine("audio_output {");
|
||||
builder.AppendLine("type \"null\"");
|
||||
builder.AppendLine("name \"No Output\"");
|
||||
builder.AppendLine("name \"Enabled output to be disabled\"");
|
||||
builder.AppendLine("enabled \"true\"");
|
||||
builder.AppendLine("mixer_type \"none\"");
|
||||
builder.AppendLine("}");
|
||||
builder.AppendLine("audio_output {");
|
||||
builder.AppendLine("type \"null\"");
|
||||
builder.AppendLine("name \"Disabled output to be enabled\"");
|
||||
builder.AppendLine("enabled \"false\"");
|
||||
builder.AppendLine("mixer_type \"none\"");
|
||||
builder.AppendLine("}");
|
||||
builder.AppendLine("audio_output {");
|
||||
builder.AppendLine("type \"null\"");
|
||||
builder.AppendLine("name \"Enabled output to be toggled\"");
|
||||
builder.AppendLine("enabled \"true\"");
|
||||
builder.AppendLine("mixer_type \"none\"");
|
||||
builder.AppendLine("}");
|
||||
|
||||
|
@ -5,9 +5,9 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibMpcTest
|
||||
{
|
||||
public class MpdServerTest : IDisposable
|
||||
public class MpdMock : IDisposable
|
||||
{
|
||||
public MpdServerTest()
|
||||
public MpdMock()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
@ -32,11 +32,11 @@ namespace LibMpcTest
|
||||
}
|
||||
};
|
||||
|
||||
Console.Out.WriteLine($"Starting Server: {Process.StartInfo.FileName} {Process.StartInfo.Arguments}");
|
||||
TestOutput.WriteLine($"Starting Server: {Process.StartInfo.FileName} {Process.StartInfo.Arguments}");
|
||||
|
||||
Process.Start();
|
||||
Console.Out.WriteLine($"Output: {Process.StandardOutput.ReadToEnd()}");
|
||||
Console.Out.WriteLine($"Error: {Process.StandardError.ReadToEnd()}");
|
||||
TestOutput.WriteLine($"Output: {Process.StandardOutput.ReadToEnd()}");
|
||||
TestOutput.WriteLine($"Error: {Process.StandardError.ReadToEnd()}");
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
@ -80,15 +80,16 @@ namespace LibMpcTest
|
||||
netcat.Start();
|
||||
netcat.WaitForExit();
|
||||
|
||||
Console.Out.WriteLine(command);
|
||||
Console.Out.WriteLine($"Output: {netcat.StandardOutput.ReadToEnd()}");
|
||||
Console.Out.WriteLine($"Error: {netcat.StandardError.ReadToEnd()}");
|
||||
TestOutput.WriteLine(command);
|
||||
TestOutput.WriteLine($"Output: {netcat.StandardOutput.ReadToEnd()}");
|
||||
TestOutput.WriteLine($"Error: {netcat.StandardError.ReadToEnd()}");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Process?.Kill();
|
||||
Process?.Dispose();
|
||||
TestOutput.WriteLine("Server Stopped.");
|
||||
}
|
||||
|
||||
private class Server
|
5
LibMpcTest/Server/Playlists/Playlist One.m3u
Normal file
5
LibMpcTest/Server/Playlists/Playlist One.m3u
Normal file
@ -0,0 +1,5 @@
|
||||
teaspoon-stirring-mug-of-coffee.mp3
|
||||
whistle-kettle-boiling.mp3
|
||||
wine-glass-double-chink-clink-cheers.mp3
|
||||
Directory With Spaces/coin-spin-light.mp3
|
||||
Directory With Spaces/finger-snap-click.mp3
|
3
LibMpcTest/Server/Playlists/Playlist Two.m3u
Normal file
3
LibMpcTest/Server/Playlists/Playlist Two.m3u
Normal file
@ -0,0 +1,3 @@
|
||||
A long name directory with some spaces/pouring-water-into-mug-of-coffee.mp3
|
||||
A long name directory with some spaces/Sub Directory Two/short-trouser-pants-zip-closing.mp3
|
||||
Directory/2-Kids-Laughing.mp3
|
5
LibMpcTest/Server/Playlists/_My Playlist.m3u
Normal file
5
LibMpcTest/Server/Playlists/_My Playlist.m3u
Normal file
@ -0,0 +1,5 @@
|
||||
A long name directory with some spaces/Ghost-Sounds.mp3
|
||||
Directory/ambient-noise-server-room.mp3
|
||||
Directory With Spaces/SubDirectory One/central-locking-Ford-Mondeo-Mk-3.mp3
|
||||
_My Directory/gas-fire-lighting.mp3
|
||||
A long name directory with some spaces/Sub Directory Two/starting-engine-Ford-Mondeo-Mk-3-diesel.mp3
|
@ -21,23 +21,36 @@ tag: MUSICBRAINZ_ALBUMARTISTID
|
||||
tag: MUSICBRAINZ_TRACKID
|
||||
info_end
|
||||
directory: A long name directory with some spaces
|
||||
mtime: 1481622608
|
||||
mtime: 1482142041
|
||||
begin: A long name directory with some spaces
|
||||
song_begin: pouring-water-into-mug-of-coffee.mp3
|
||||
Time: 4
|
||||
Artist: Geek & Dummy
|
||||
Title: Sound effect: pouring water into mug of coffee
|
||||
Date: 2013
|
||||
Date: 2013
|
||||
mtime: 1481622059
|
||||
song_end
|
||||
directory: Sub Directory Two
|
||||
mtime: 1482142041
|
||||
begin: A long name directory with some spaces/Sub Directory Two
|
||||
song_begin: short-trouser-pants-zip-closing.mp3
|
||||
Time: 1
|
||||
Artist: Geek & Dummy
|
||||
Title: Sound effect: short trouser pants zip closing
|
||||
Date: 2013
|
||||
Date: 2013
|
||||
mtime: 1481622066
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
song_begin: starting-engine-Ford-Mondeo-Mk-3-diesel.mp3
|
||||
Time: 6
|
||||
Artist: Geek & Dummy
|
||||
Title: Sound effect: starting engine - Ford Mondeo Mk 3 diesel
|
||||
Album: Geek & Dummy Sound Library
|
||||
Date: 2014
|
||||
Genre: soundfx
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
end: A long name directory with some spaces/Sub Directory Two
|
||||
song_begin: pouring-water-into-mug-of-coffee.mp3
|
||||
Time: 4
|
||||
Artist: Geek & Dummy
|
||||
Title: Sound effect: pouring water into mug of coffee
|
||||
Date: 2013
|
||||
Date: 2013
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
song_begin: Ghost-Sounds.mp3
|
||||
Time: 95
|
||||
@ -47,20 +60,11 @@ Album: Geek & Dummy Sound Library
|
||||
Date: 2014
|
||||
Date: 2014
|
||||
Genre: soundfx
|
||||
mtime: 1481622054
|
||||
song_end
|
||||
song_begin: starting-engine-Ford-Mondeo-Mk-3-diesel.mp3
|
||||
Time: 6
|
||||
Artist: Geek & Dummy
|
||||
Title: Sound effect: starting engine - Ford Mondeo Mk 3 diesel
|
||||
Album: Geek & Dummy Sound Library
|
||||
Date: 2014
|
||||
Genre: soundfx
|
||||
mtime: 1481622063
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
end: A long name directory with some spaces
|
||||
directory: Directory
|
||||
mtime: 1481622608
|
||||
mtime: 1482142041
|
||||
begin: Directory
|
||||
song_begin: 2-Kids-Laughing.mp3
|
||||
Time: 30
|
||||
@ -70,7 +74,7 @@ Album: Geek & Dummy Sound Library
|
||||
Date: 2014
|
||||
Date: 2014
|
||||
Genre: soundfx
|
||||
mtime: 1481622083
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
song_begin: ambient-noise-server-room.mp3
|
||||
Time: 71
|
||||
@ -80,20 +84,15 @@ Album: Geek & Dummy Sound Library
|
||||
Date: 2014
|
||||
Date: 2014
|
||||
Genre: soundfx
|
||||
mtime: 1481622020
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
end: Directory
|
||||
directory: Directory With Spaces
|
||||
mtime: 1481622608
|
||||
mtime: 1482142041
|
||||
begin: Directory With Spaces
|
||||
song_begin: coin-spin-light.mp3
|
||||
Time: 5
|
||||
Artist: Geek & Dummy
|
||||
Title: Sound effect: coin spin (light coin)
|
||||
Date: 2013
|
||||
Date: 2013
|
||||
mtime: 1481622036
|
||||
song_end
|
||||
directory: SubDirectory One
|
||||
mtime: 1482142041
|
||||
begin: Directory With Spaces/SubDirectory One
|
||||
song_begin: central-locking-Ford-Mondeo-Mk-3.mp3
|
||||
Time: 5
|
||||
Artist: Geek & Dummy
|
||||
@ -102,7 +101,16 @@ Album: Geek & Dummy Sound Library
|
||||
Date: 2014
|
||||
Date: 2014
|
||||
Genre: soundfx
|
||||
mtime: 1481622024
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
end: Directory With Spaces/SubDirectory One
|
||||
song_begin: coin-spin-light.mp3
|
||||
Time: 5
|
||||
Artist: Geek & Dummy
|
||||
Title: Sound effect: coin spin (light coin)
|
||||
Date: 2013
|
||||
Date: 2013
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
song_begin: finger-snap-click.mp3
|
||||
Time: 0
|
||||
@ -112,11 +120,11 @@ Album: Geek & Dummy Sound Library
|
||||
Date: 2014
|
||||
Date: 2014
|
||||
Genre: soundfx
|
||||
mtime: 1481622047
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
end: Directory With Spaces
|
||||
directory: _My Directory
|
||||
mtime: 1481622608
|
||||
mtime: 1482142041
|
||||
begin: _My Directory
|
||||
song_begin: gas-fire-lighting.mp3
|
||||
Time: 58
|
||||
@ -126,7 +134,7 @@ Album: Geek & Dummy Sound Library
|
||||
Date: 2014
|
||||
Date: 2014
|
||||
Genre: soundfx
|
||||
mtime: 1481622051
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
end: _My Directory
|
||||
song_begin: teaspoon-stirring-mug-of-coffee.mp3
|
||||
@ -135,7 +143,7 @@ Artist: Geek & Dummy
|
||||
Title: Sound effect: teaspoon stirring mug of coffee
|
||||
Date: 2013
|
||||
Date: 2013
|
||||
mtime: 1481622029
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
song_begin: whistle-kettle-boiling.mp3
|
||||
Time: 36
|
||||
@ -143,7 +151,7 @@ Artist: Geek & Dummy
|
||||
Title: Sound effect: whistle kettle boiling
|
||||
Date: 2013
|
||||
Date: 2013
|
||||
mtime: 1481622087
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
song_begin: wine-glass-double-chink-clink-cheers.mp3
|
||||
Time: 1
|
||||
@ -151,5 +159,5 @@ Artist: Geek & Dummy
|
||||
Title: Sound effect: wine glass double chink/clink/cheers
|
||||
Date: 2013
|
||||
Date: 2013
|
||||
mtime: 1481622090
|
||||
mtime: 1481623577
|
||||
song_end
|
||||
|
12
LibMpcTest/TestOutput.cs
Normal file
12
LibMpcTest/TestOutput.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace LibMpcTest
|
||||
{
|
||||
internal class TestOutput
|
||||
{
|
||||
internal static void WriteLine(string value)
|
||||
{
|
||||
Console.Out.WriteLine(value);
|
||||
}
|
||||
}
|
||||
}
|
33
LibMpcTest/Tests/DatabaseCommandsTest.cs
Normal file
33
LibMpcTest/Tests/DatabaseCommandsTest.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
using System.Linq;
|
||||
using LibMpc;
|
||||
|
||||
namespace LibMpcTest
|
||||
{
|
||||
public partial class LibMpcTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ListAllTest()
|
||||
{
|
||||
var response = await Mpc.SendAsync(new Commands.Database.ListAll());
|
||||
|
||||
TestOutput.WriteLine("ListAllTest Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Count().Equals(7));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FindGenreTest()
|
||||
{
|
||||
var response = await Mpc.SendAsync(new Commands.Database.Find(MpdTags.Genre, "soundfx"));
|
||||
|
||||
TestOutput.WriteLine("FindGenreTest Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Count().Equals(7));
|
||||
}
|
||||
}
|
||||
}
|
77
LibMpcTest/Tests/OutputCommandsTest.cs
Normal file
77
LibMpcTest/Tests/OutputCommandsTest.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
using LibMpc;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibMpcTest
|
||||
{
|
||||
public partial class LibMpcTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task DisableOutputTest()
|
||||
{
|
||||
var responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs());
|
||||
Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(0)).IsEnabled);
|
||||
|
||||
var response = await Mpc.SendAsync(new Commands.Output.DisableOutput(0));
|
||||
|
||||
TestOutput.WriteLine("DisableOutputTest Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Equals(string.Empty));
|
||||
Assert.True(response.Response.State.Status.Equals("OK"));
|
||||
|
||||
responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs());
|
||||
Assert.False(responseOutputs.Response.Body.Single(output => output.Id.Equals(0)).IsEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EnableOutputTest()
|
||||
{
|
||||
var responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs());
|
||||
// By default should be disable from mpd.config
|
||||
Assert.False(responseOutputs.Response.Body.Single(output => output.Id.Equals(1)).IsEnabled);
|
||||
|
||||
var response = await Mpc.SendAsync(new Commands.Output.EnableOutput(1));
|
||||
|
||||
TestOutput.WriteLine("EnableOutputTest Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Equals(string.Empty));
|
||||
Assert.True(response.Response.State.Status.Equals("OK"));
|
||||
|
||||
responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs());
|
||||
Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(1)).IsEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ToggleOutputTest()
|
||||
{
|
||||
var responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs());
|
||||
Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(2)).IsEnabled);
|
||||
|
||||
var response = await Mpc.SendAsync(new Commands.Output.ToggleOutput(2));
|
||||
|
||||
TestOutput.WriteLine("ToggleOutputTest Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Equals(string.Empty));
|
||||
Assert.True(response.Response.State.Status.Equals("OK"));
|
||||
|
||||
responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs());
|
||||
Assert.False(responseOutputs.Response.Body.Single(output => output.Id.Equals(2)).IsEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LisOutputsTest()
|
||||
{
|
||||
var response = await Mpc.SendAsync(new Commands.Output.Outputs());
|
||||
|
||||
TestOutput.WriteLine("LisOutputsTest Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Count().Equals(3));
|
||||
}
|
||||
}
|
||||
}
|
54
LibMpcTest/Tests/PlaylistsCommandsTest.cs
Normal file
54
LibMpcTest/Tests/PlaylistsCommandsTest.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
using LibMpc;
|
||||
using System.Linq;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace LibMpcTest
|
||||
{
|
||||
public partial class LibMpcTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Playlist One", 5)]
|
||||
[InlineData("Playlist Two", 3)]
|
||||
[InlineData("_My Playlist", 5)]
|
||||
public async Task ListPlaylistTest(string playlistName, int numberOfFiles)
|
||||
{
|
||||
var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylist(playlistName));
|
||||
|
||||
TestOutput.WriteLine($"ListPlaylistTest (playlistName: {playlistName}) Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Count().Equals(numberOfFiles));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Playlist One", 5)]
|
||||
[InlineData("Playlist Two", 3)]
|
||||
[InlineData("_My Playlist", 5)]
|
||||
public async Task ListPlaylistInfoTest(string playlistName, int numberOfFiles)
|
||||
{
|
||||
var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylistInfo(playlistName));
|
||||
|
||||
TestOutput.WriteLine($"ListPlaylistTest (playlistName: {playlistName}) Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Count().Equals(numberOfFiles));
|
||||
Assert.True(response.Response.Body.All(item => !string.IsNullOrEmpty(item.Artist)));
|
||||
Assert.True(response.Response.Body.All(item => !string.IsNullOrEmpty(item.Title)));
|
||||
Assert.True(response.Response.Body.All(item => !string.IsNullOrEmpty(item.Date)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListPlaylistsTest()
|
||||
{
|
||||
var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylists());
|
||||
|
||||
TestOutput.WriteLine($"ListPlaylistsTest Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Count().Equals(3));
|
||||
}
|
||||
}
|
||||
}
|
80
LibMpcTest/Tests/ReflectionCommandsTest.cs
Normal file
80
LibMpcTest/Tests/ReflectionCommandsTest.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
using LibMpc;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibMpcTest
|
||||
{
|
||||
public partial class LibMpcTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task CommandsTest()
|
||||
{
|
||||
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));
|
||||
|
||||
// Different answer from MPD on Windows and on Linux, beacuse of Version.
|
||||
// Check some of the commands.
|
||||
Assert.True(response.Response.Body.Any(command => command.Equals("listall")));
|
||||
Assert.True(response.Response.Body.Any(command => command.Equals("outputs")));
|
||||
Assert.True(response.Response.Body.Any(command => command.Equals("pause")));
|
||||
Assert.True(response.Response.Body.Any(command => command.Equals("play")));
|
||||
Assert.True(response.Response.Body.Any(command => command.Equals("setvol")));
|
||||
Assert.True(response.Response.Body.Any(command => command.Equals("stop")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TagTypesTest()
|
||||
{
|
||||
var response = await Mpc.SendAsync(new Commands.Reflection.TagTypes());
|
||||
|
||||
TestOutput.WriteLine("TagTypesTest Result:");
|
||||
TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
|
||||
Assert.True(response.Response.Body.Count().Equals(17));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UrlHandlersTest()
|
||||
{
|
||||
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));
|
||||
|
||||
// Different answer from MPD on Windows and on Linux.
|
||||
// Check some of the handlers.
|
||||
Assert.True(response.Response.Body.Any(handler => handler.Equals("http://")));
|
||||
Assert.True(response.Response.Body.Any(handler => handler.Equals("mms://")));
|
||||
Assert.True(response.Response.Body.Any(handler => handler.Equals("gopher://")));
|
||||
Assert.True(response.Response.Body.Any(handler => handler.Equals("rtp://")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DecodersTest()
|
||||
{
|
||||
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));
|
||||
|
||||
// Different answer from MPD on Windows and on Linux.
|
||||
// Check some of the decoders.
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.Name.Equals("mad")));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("mp3"))));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/mpeg"))));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.Name.Equals("flac")));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("flac"))));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/flac"))));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/x-flac"))));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.Name.Equals("ffmpeg")));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("aac"))));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("mpeg"))));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/aac"))));
|
||||
Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/mpeg"))));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user