1
0
mirror of https://github.com/ZetaKebab/MpcNET.git synced 2024-09-16 05:30:09 +00:00

Merge from refactoringResponse branch

This commit is contained in:
glucaci 2017-04-12 09:55:35 +02:00
commit b2e17742c2
37 changed files with 871 additions and 891 deletions

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;

View 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;
}
}
}
}
}
}

View File

@ -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;
}
}
}
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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

View File

@ -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();
}
}
/*

View File

@ -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");

View 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;
}
*/
}
}

View File

@ -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
View 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; }
}
}

View 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);
}
}
}

View 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
View 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
View 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; }
}
}

View 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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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")]

View File

@ -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
View 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.");
}
}
}

View File

@ -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("}");

View File

@ -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

View 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

View 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

View 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

View File

@ -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
View File

@ -0,0 +1,12 @@
using System;
namespace LibMpcTest
{
internal class TestOutput
{
internal static void WriteLine(string value)
{
Console.Out.WriteLine(value);
}
}
}

View 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));
}
}
}

View 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));
}
}
}

View 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));
}
}
}

View 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"))));
}
}
}