mirror of
https://github.com/ZetaKebab/MpcNET.git
synced 2025-07-01 00:37:37 +00:00
Updates from latest Stylophone code
This commit is contained in:
@ -52,9 +52,9 @@
|
||||
return this.command;
|
||||
}
|
||||
|
||||
public IList<string> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IList<string> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var result = response.Select(atrb => $"{atrb.Key}: {atrb.Value}").ToList();
|
||||
var result = response.ResponseValues.Select(atrb => $"{atrb.Key}: {atrb.Value}").ToList();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>MpcNET.Test</AssemblyName>
|
||||
<PackageId>MpcNET.Test</PackageId>
|
||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||
|
Binary file not shown.
@ -4,6 +4,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MpcNET.Commands;
|
||||
using MpcNET.Commands.Queue;
|
||||
|
||||
public partial class LibMpcTest
|
||||
{
|
||||
@ -117,7 +118,7 @@
|
||||
|
||||
private async Task Check_Empty_Queue()
|
||||
{
|
||||
var message = await Mpc.SendAsync(new Commands.Playlist.PlaylistCommand());
|
||||
var message = await Mpc.SendAsync(new PlaylistCommand());
|
||||
Assert.IsTrue(message.HasSuccessResponse());
|
||||
Assert.IsFalse(message.Response.Content.Any());
|
||||
}
|
||||
@ -130,44 +131,44 @@
|
||||
|
||||
private async Task Clear_Queue()
|
||||
{
|
||||
var message = await Mpc.SendAsync(new Commands.Playlist.ClearCommand());
|
||||
var message = await Mpc.SendAsync(new ClearCommand());
|
||||
Assert.IsTrue(message.HasSuccessResponse());
|
||||
}
|
||||
|
||||
private async Task Check_Queue_HasSongs(int nrOfSongs)
|
||||
{
|
||||
var message = await Mpc.SendAsync(new Commands.Playlist.PlaylistCommand());
|
||||
var message = await Mpc.SendAsync(new PlaylistCommand());
|
||||
Assert.IsTrue(message.HasSuccessResponse());
|
||||
Assert.IsTrue(message.Response.Content.Count() == nrOfSongs);
|
||||
}
|
||||
|
||||
private async Task Add_Directory(string directory)
|
||||
{
|
||||
var message = await Mpc.SendAsync(new Commands.Playlist.AddCommand(directory));
|
||||
var message = await Mpc.SendAsync(new AddCommand(directory));
|
||||
Assert.IsTrue(message.HasSuccessResponse());
|
||||
}
|
||||
|
||||
private async Task Add_File(string file)
|
||||
{
|
||||
var message = await Mpc.SendAsync(new Commands.Playlist.AddIdCommand(file));
|
||||
var message = await Mpc.SendAsync(new AddIdCommand(file));
|
||||
Assert.IsTrue(message.HasSuccessResponse());
|
||||
}
|
||||
|
||||
private async Task Remove_Position(int position)
|
||||
{
|
||||
var message = await Mpc.SendAsync(new Commands.Playlist.DeleteCommand(position));
|
||||
var message = await Mpc.SendAsync(new DeleteCommand(position));
|
||||
Assert.IsTrue(message.HasSuccessResponse());
|
||||
}
|
||||
|
||||
private async Task Remove_Id(int songId)
|
||||
{
|
||||
var message = await Mpc.SendAsync(new Commands.Playlist.DeleteIdCommand(songId));
|
||||
var message = await Mpc.SendAsync(new DeleteIdCommand(songId));
|
||||
Assert.IsTrue(message.HasSuccessResponse());
|
||||
}
|
||||
|
||||
private async Task<int> Get_Song_Id()
|
||||
{
|
||||
var message = await Mpc.SendAsync(new Commands.Playlist.PlaylistInfoCommand());
|
||||
var message = await Mpc.SendAsync(new PlaylistInfoCommand());
|
||||
return message.Response.Content.Single().Id;
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ namespace MpcNET.Test
|
||||
TestOutput.WriteLine("TagTypesTest Result:");
|
||||
TestOutput.WriteLine(response);
|
||||
|
||||
Assert.IsTrue(response.Response.Content.Count().Equals(17));
|
||||
Assert.IsTrue(response.Response.Content.Count().Equals(25));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -47,9 +47,7 @@ namespace MpcNET.Test
|
||||
// Different answer from MPD on Windows and on Linux.
|
||||
// Check some of the handlers.
|
||||
Assert.IsTrue(response.Response.Content.Any(handler => handler.Equals("http://")));
|
||||
Assert.IsTrue(response.Response.Content.Any(handler => handler.Equals("mms://")));
|
||||
Assert.IsTrue(response.Response.Content.Any(handler => handler.Equals("gopher://")));
|
||||
Assert.IsTrue(response.Response.Content.Any(handler => handler.Equals("rtp://")));
|
||||
Assert.IsTrue(response.Response.Content.Any(handler => handler.Equals("nfs://")));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -62,7 +60,7 @@ namespace MpcNET.Test
|
||||
|
||||
// Different answer from MPD on Windows and on Linux.
|
||||
// Check some of the decoders.
|
||||
Assert.IsTrue(response.Response.Content.Any(decoder => decoder.Name.Equals("mad")));
|
||||
Assert.IsTrue(response.Response.Content.Any(decoder => decoder.Name.Equals("vorbis")));
|
||||
Assert.IsTrue(response.Response.Content.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("mp3"))));
|
||||
Assert.IsTrue(response.Response.Content.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/mpeg"))));
|
||||
Assert.IsTrue(response.Response.Content.Any(decoder => decoder.Name.Equals("flac")));
|
||||
|
@ -1,13 +1,8 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29324.140
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31710.8
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Utilities", "Solution Utilities", "{83D06F7C-1336-4AC3-82BB-FDE7940D3C10}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.travis.yml = .travis.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MpcNET", "MpcNET\MpcNET.csproj", "{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MpcNET.Test", "MpcNET.Test\MpcNET.Test.csproj", "{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}"
|
||||
@ -15,22 +10,112 @@ EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|iPhone = Debug|iPhone
|
||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|iPhone = Release|iPhone
|
||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
Release-Stable|Any CPU = Release-Stable|Any CPU
|
||||
Release-Stable|ARM = Release-Stable|ARM
|
||||
Release-Stable|ARM64 = Release-Stable|ARM64
|
||||
Release-Stable|iPhone = Release-Stable|iPhone
|
||||
Release-Stable|iPhoneSimulator = Release-Stable|iPhoneSimulator
|
||||
Release-Stable|x64 = Release-Stable|x64
|
||||
Release-Stable|x86 = Release-Stable|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|x86.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
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|Any CPU.ActiveCfg = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|Any CPU.Build.0 = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|ARM.ActiveCfg = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|ARM.Build.0 = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|ARM64.ActiveCfg = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|ARM64.Build.0 = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|iPhone.ActiveCfg = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|iPhone.Build.0 = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|iPhoneSimulator.ActiveCfg = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|iPhoneSimulator.Build.0 = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|x64.ActiveCfg = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|x64.Build.0 = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|x86.ActiveCfg = Release-Stable|Any CPU
|
||||
{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release-Stable|x86.Build.0 = Release-Stable|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}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|Any CPU.ActiveCfg = Release-Stable|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|Any CPU.Build.0 = Release-Stable|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|x64.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|x86.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|Any CPU.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|ARM.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|ARM.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|ARM64.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|ARM64.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|iPhone.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|iPhone.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|x64.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|x64.Build.0 = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|x86.ActiveCfg = Release|Any CPU
|
||||
{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release-Stable|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
52
Sources/MpcNET/Commands/Database/AlbumArtCommand.cs
Normal file
52
Sources/MpcNET/Commands/Database/AlbumArtCommand.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using MpcNET.Types;
|
||||
using System.Linq;
|
||||
|
||||
namespace MpcNET.Commands.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the album art for the given song.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#the-music-database
|
||||
/// </summary>
|
||||
public class AlbumArtCommand : IMpcCommand<MpdBinaryData>
|
||||
{
|
||||
private readonly string path;
|
||||
private readonly long binaryOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AlbumArtCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The URI.</param>
|
||||
/// <param name="offset">Binary data offset if needed</param>
|
||||
public AlbumArtCommand(string path, long offset = 0)
|
||||
{
|
||||
this.path = path;
|
||||
this.binaryOffset = offset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => $"albumart \"{path}\" {binaryOffset}";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public MpdBinaryData Deserialize(SerializedResponse response)
|
||||
{
|
||||
if (response.ResponseValues.Count == 0)
|
||||
return null;
|
||||
|
||||
var totalSize = long.Parse(response.ResponseValues.Where(kvp => kvp.Key == "size").Select(kvp => kvp.Value).First());
|
||||
var payloadSize = long.Parse(response.ResponseValues.Where(kvp => kvp.Key == "binary").Select(kvp => kvp.Value).First());
|
||||
|
||||
return new MpdBinaryData(totalSize, payloadSize, response.BinaryData);
|
||||
}
|
||||
}
|
||||
}
|
207
Sources/MpcNET/Commands/Database/FindAndSearchCommands.cs
Normal file
207
Sources/MpcNET/Commands/Database/FindAndSearchCommands.cs
Normal file
@ -0,0 +1,207 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="FindCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Database
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MpcNET.Tags;
|
||||
using MpcNET.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Finds songs in the database that contain "searchText".
|
||||
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#filters
|
||||
/// </summary>
|
||||
public class SearchCommand : BaseFilterCommand
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override string CommandName => "search";
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override string Operand => "contains";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag.</param>
|
||||
/// <param name="searchText">The search text.</param>
|
||||
/// <param name="windowStart">Start of the portion of the results desired</param>
|
||||
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||
public SearchCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1) : base(tag, searchText, windowStart, windowEnd) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="filters">List of key/value filters</param>
|
||||
/// <param name="windowStart">Start of the portion of the results desired</param>
|
||||
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||
public SearchCommand(List<KeyValuePair<ITag, string>> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds songs in the database that contain "searchText" and adds them to the queue.
|
||||
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#filters
|
||||
/// </summary>
|
||||
public class SearchAddCommand : BaseFilterCommand
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override string CommandName => "searchadd";
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override string Operand => "contains";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag.</param>
|
||||
/// <param name="searchText">The search text.</param>
|
||||
/// <param name="windowStart">Start of the portion of the results desired</param>
|
||||
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||
public SearchAddCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1) : base(tag, searchText, windowStart, windowEnd) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="filters">List of key/value filters</param>
|
||||
/// <param name="windowStart">Start of the portion of the results desired</param>
|
||||
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||
public SearchAddCommand(List<KeyValuePair<ITag, string>> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds songs in the database that is exactly "searchText".
|
||||
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#filters
|
||||
/// </summary>
|
||||
public class FindCommand : BaseFilterCommand
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override string CommandName => "find";
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override string Operand => "==";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FindCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag.</param>
|
||||
/// <param name="searchText">The search text.</param>
|
||||
/// <param name="windowStart">Start of the portion of the results desired</param>
|
||||
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||
public FindCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1) : base(tag, searchText, windowStart, windowEnd) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FindCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="filters">List of key/value filters</param>
|
||||
/// <param name="windowStart">Start of the portion of the results desired</param>
|
||||
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||
public FindCommand(List<KeyValuePair<ITag, string>> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Base class for find/search commands.
|
||||
/// </summary>
|
||||
public abstract class BaseFilterCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
||||
{
|
||||
private readonly List<KeyValuePair<ITag, string>> filters;
|
||||
private readonly int _start;
|
||||
private readonly int _end;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the command to use when deserializing
|
||||
/// </summary>
|
||||
public abstract string CommandName { get; }
|
||||
/// <summary>
|
||||
/// Operand to use between tags and search text. Can be ==, !=, contains...
|
||||
/// </summary>
|
||||
public abstract string Operand { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseFilterCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag.</param>
|
||||
/// <param name="searchText">The search text.</param>
|
||||
/// <param name="windowStart">Start of the portion of the results desired</param>
|
||||
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||
public BaseFilterCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1)
|
||||
{
|
||||
this.filters = new List<KeyValuePair<ITag, string>>();
|
||||
this.filters.Add(new KeyValuePair<ITag, string>(tag, searchText));
|
||||
|
||||
_start = windowStart;
|
||||
_end = windowEnd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseFilterCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="filters">List of key/value filters</param>
|
||||
/// <param name="windowStart">Start of the portion of the results desired</param>
|
||||
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||
public BaseFilterCommand(List<KeyValuePair<ITag, string>> filters, int windowStart = -1, int windowEnd = -1)
|
||||
{
|
||||
this.filters = filters;
|
||||
|
||||
_start = windowStart;
|
||||
_end = windowEnd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize()
|
||||
{
|
||||
var cmd =
|
||||
CommandName + " \"(" +
|
||||
string.Join(" AND ",
|
||||
filters.Select(x => $"({x.Key.Value} {Operand} {escape(x.Value)})")
|
||||
) +
|
||||
")\"";
|
||||
|
||||
if (_start > -1)
|
||||
{
|
||||
cmd += $" window {_start}:{_end}";
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<IMpdFile> Deserialize(SerializedResponse response)
|
||||
{
|
||||
return MpdFile.CreateList(response.ResponseValues);
|
||||
}
|
||||
|
||||
private string escape(string value) => string.Format("\\\"{0}\\\"", value.Replace("\\", "\\\\\\").Replace("'", "\\\\'").Replace("\"", "\\\\\\\""));
|
||||
}
|
||||
// TODO: rescan
|
||||
}
|
@ -11,7 +11,7 @@ namespace MpcNET.Commands.Database
|
||||
using MpcNET.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Lists all songs and directories in URI.
|
||||
/// Lists all songs and directories.
|
||||
/// https://www.musicpd.org/doc/protocol/database.html.
|
||||
/// </summary>
|
||||
public class ListAllCommand : IMpcCommand<IEnumerable<MpdDirectory>>
|
||||
@ -31,14 +31,14 @@ namespace MpcNET.Commands.Database
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<MpdDirectory> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<MpdDirectory> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var rootDirectory = new List<MpdDirectory>
|
||||
{
|
||||
new MpdDirectory("/"), // Add by default the root directory
|
||||
};
|
||||
|
||||
foreach (var line in response)
|
||||
foreach (var line in response.ResponseValues)
|
||||
{
|
||||
if (line.Key.Equals("file"))
|
||||
{
|
||||
|
@ -63,9 +63,9 @@ namespace MpcNET.Commands.Database
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public List<string> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public List<string> Deserialize(SerializedResponse response)
|
||||
{
|
||||
return response.Select(x => x.Value).ToList();
|
||||
return response.ResponseValues.Select(x => x.Value).ToList();
|
||||
}
|
||||
|
||||
private string escape(string value) => string.Format("\"{0}\"", value.Replace("\\", "\\\\").Replace("\"", "\\\""));
|
||||
|
68
Sources/MpcNET/Commands/Database/LsInfoCommand.cs
Normal file
68
Sources/MpcNET/Commands/Database/LsInfoCommand.cs
Normal file
@ -0,0 +1,68 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="LsInfoCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Database
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MpcNET.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Lists the contents of the directory URI. The response contains records starting with file, directory or playlist, each followed by metadata
|
||||
/// https://www.musicpd.org/doc/protocol/database.html.
|
||||
/// </summary>
|
||||
public class LsInfoCommand : IMpcCommand<IEnumerable<IMpdFilePath>>
|
||||
{
|
||||
private readonly string uri;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LsInfoCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="uri">The uri.</param>
|
||||
public LsInfoCommand(string uri)
|
||||
{
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => $"lsinfo \"{uri}\"";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<IMpdFilePath> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var rootDirectory = new List<IMpdFilePath>();
|
||||
|
||||
foreach (var line in response.ResponseValues)
|
||||
{
|
||||
// lsinfo can also return playlists, but this is a deprecated behavior I'm entirely willing to not support.
|
||||
|
||||
if (line.Key.Equals("file"))
|
||||
{
|
||||
rootDirectory.Add(new MpdFile(line.Value));
|
||||
}
|
||||
|
||||
if (line.Key.Equals("directory"))
|
||||
{
|
||||
rootDirectory.Add(new MpdDirectory(line.Value));
|
||||
}
|
||||
}
|
||||
|
||||
return rootDirectory;
|
||||
}
|
||||
}
|
||||
}
|
56
Sources/MpcNET/Commands/Database/ReadPictureCommand.cs
Normal file
56
Sources/MpcNET/Commands/Database/ReadPictureCommand.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using MpcNET.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MpcNET.Commands.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the album art for the given song, using ID3 metadata.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#the-music-database
|
||||
/// </summary>
|
||||
public class ReadPictureCommand : IMpcCommand<MpdBinaryData>
|
||||
{
|
||||
private readonly string path;
|
||||
private readonly long binaryOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReadPictureCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The URI.</param>
|
||||
/// <param name="offset">Binary data offset if needed</param>
|
||||
public ReadPictureCommand(string path, long offset = 0)
|
||||
{
|
||||
this.path = path;
|
||||
this.binaryOffset = offset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => $"readpicture \"{path}\" {binaryOffset}";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public MpdBinaryData Deserialize(SerializedResponse response)
|
||||
{
|
||||
if (response.ResponseValues.Count == 0)
|
||||
return null;
|
||||
|
||||
var totalSize = long.Parse(response.ResponseValues.Where(kvp => kvp.Key == "size").Select(kvp => kvp.Value).First());
|
||||
var payloadSize = long.Parse(response.ResponseValues.Where(kvp => kvp.Key == "binary").Select(kvp => kvp.Value).First());
|
||||
|
||||
return new MpdBinaryData(totalSize, payloadSize, response.BinaryData);
|
||||
}
|
||||
}
|
||||
}
|
@ -67,9 +67,9 @@ namespace MpcNET.Commands.Database
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -40,10 +40,10 @@ namespace MpcNET.Commands.Output
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
// Response should be empty.
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -40,10 +40,10 @@ namespace MpcNET.Commands.Output
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
// Response should be empty.
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
namespace MpcNET.Commands.Output
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MpcNET.Types;
|
||||
|
||||
/// <summary>
|
||||
@ -30,17 +31,21 @@ namespace MpcNET.Commands.Output
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<MpdOutput> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<MpdOutput> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var result = new List<MpdOutput>();
|
||||
|
||||
for (var i = 0; i < response.Count; i += 3)
|
||||
{
|
||||
var outputId = int.Parse(response[i].Value);
|
||||
var outputName = response[i + 1].Value;
|
||||
var outputEnabled = response[i + 2].Value == "1";
|
||||
// Strip out attributes so we can keep parsing the response by blocks of 4
|
||||
var strippedResult = response.ResponseValues.Where(kvp => kvp.Key != "attribute").ToList();
|
||||
|
||||
result.Add(new MpdOutput(outputId, outputName, outputEnabled));
|
||||
for (var i = 0; i < strippedResult.Count; i+=4)
|
||||
{
|
||||
var outputId = int.Parse(strippedResult[i].Value);
|
||||
var outputName = strippedResult[i + 1].Value;
|
||||
var outputPlugin = strippedResult[i + 2].Value;
|
||||
var outputEnabled = strippedResult[i + 3].Value == "1";
|
||||
|
||||
result.Add(new MpdOutput(outputId, outputName, outputPlugin, outputEnabled));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -40,9 +40,9 @@ namespace MpcNET.Commands.Output
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,9 +29,9 @@ namespace MpcNET.Commands.Playback
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,9 +55,9 @@ namespace MpcNET.Commands.Playback
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -49,9 +49,9 @@ namespace MpcNET.Commands.Playback
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -49,9 +49,9 @@ namespace MpcNET.Commands.Playback
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,9 +29,9 @@ namespace MpcNET.Commands.Playback
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
63
Sources/MpcNET/Commands/Playback/RandomCommand.cs
Normal file
63
Sources/MpcNET/Commands/Playback/RandomCommand.cs
Normal file
@ -0,0 +1,63 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PauseResumeCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Playback
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Command to set random state.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#playback-options
|
||||
/// </summary>
|
||||
public class RandomCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string playArgument;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RandomCommand" /> class.
|
||||
/// </summary>
|
||||
/// <param name="random">if set to <c>true</c> [random].</param>
|
||||
public RandomCommand(bool random)
|
||||
{
|
||||
this.playArgument = random ? "1" : "0";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RandomCommand"/> class.
|
||||
/// </summary>
|
||||
public RandomCommand()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize()
|
||||
{
|
||||
if (this.playArgument == null)
|
||||
{
|
||||
return string.Join(" ", "random");
|
||||
}
|
||||
|
||||
return string.Join(" ", "random", this.playArgument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
63
Sources/MpcNET/Commands/Playback/RepeatCommand.cs
Normal file
63
Sources/MpcNET/Commands/Playback/RepeatCommand.cs
Normal file
@ -0,0 +1,63 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PauseResumeCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Playback
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Command to set repeat state.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#status_commands
|
||||
/// </summary>
|
||||
public class RepeatCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string playArgument;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RepeatCommand" /> class.
|
||||
/// </summary>
|
||||
/// <param name="repeat">if set to <c>true</c> [repeat].</param>
|
||||
public RepeatCommand(bool repeat)
|
||||
{
|
||||
this.playArgument = repeat ? "1" : "0";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RepeatCommand"/> class.
|
||||
/// </summary>
|
||||
public RepeatCommand()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize()
|
||||
{
|
||||
if (this.playArgument == null)
|
||||
{
|
||||
return string.Join(" ", "repeat");
|
||||
}
|
||||
|
||||
return string.Join(" ", "repeat", this.playArgument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
52
Sources/MpcNET/Commands/Playback/SeekCurCommand.cs
Normal file
52
Sources/MpcNET/Commands/Playback/SeekCurCommand.cs
Normal file
@ -0,0 +1,52 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="SetVolumeCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace MpcNET.Commands.Playback
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Seeks to the position TIME (in seconds; fractions allowed) within the current song.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#status_commands
|
||||
/// </summary>
|
||||
public class SeekCurCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly double time;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeekCurCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="time">The time.</param>
|
||||
public SeekCurCommand(double time)
|
||||
{
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize()
|
||||
{
|
||||
return string.Join(" ", "seekcur", this.time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -44,9 +44,9 @@ namespace MpcNET.Commands.Playback
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
64
Sources/MpcNET/Commands/Playback/SingleCommand.cs
Normal file
64
Sources/MpcNET/Commands/Playback/SingleCommand.cs
Normal file
@ -0,0 +1,64 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PauseResumeCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Playback
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Command to set single state.
|
||||
/// When single is activated, playback is stopped after current song, or song is repeated if the ‘repeat’ mode is enabled.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#status_commands
|
||||
/// </summary>
|
||||
public class SingleCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string playArgument;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SingleCommand" /> class.
|
||||
/// </summary>
|
||||
/// <param name="single">if set to <c>true</c> [single].</param>
|
||||
public SingleCommand(bool single)
|
||||
{
|
||||
this.playArgument = single ? "1" : "0";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SingleCommand"/> class.
|
||||
/// </summary>
|
||||
public SingleCommand()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize()
|
||||
{
|
||||
if (this.playArgument == null)
|
||||
{
|
||||
return string.Join(" ", "single");
|
||||
}
|
||||
|
||||
return string.Join(" ", "single", this.playArgument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,9 +29,9 @@ namespace MpcNET.Commands.Playback
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -42,9 +42,9 @@ namespace MpcNET.Commands.Playlist
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<IMpdFilePath> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<IMpdFilePath> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var results = response.Where(line => line.Key.Equals("file")).Select(line => new MpdFile(line.Value));
|
||||
var results = response.ResponseValues.Where(line => line.Key.Equals("file")).Select(line => new MpdFile(line.Value));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
@ -41,9 +41,9 @@ namespace MpcNET.Commands.Playlist
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<IMpdFile> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<IMpdFile> Deserialize(SerializedResponse response)
|
||||
{
|
||||
return MpdFile.CreateList(response);
|
||||
return MpdFile.CreateList(response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -31,11 +31,11 @@ namespace MpcNET.Commands.Playlist
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<MpdPlaylist> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<MpdPlaylist> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var result = new List<MpdPlaylist>();
|
||||
|
||||
foreach (var line in response)
|
||||
foreach (var line in response.ResponseValues)
|
||||
{
|
||||
if (line.Key.Equals("playlist"))
|
||||
{
|
||||
|
@ -40,9 +40,9 @@ namespace MpcNET.Commands.Playlist
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
50
Sources/MpcNET/Commands/Playlist/PlaylistAddCommand.cs
Normal file
50
Sources/MpcNET/Commands/Playlist/PlaylistAddCommand.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlaylistAddCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Playlist
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Adds URI to the playlist NAME.m3u. NAME.m3u will be created if it does not exist.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#command-load
|
||||
/// </summary>
|
||||
public class PlaylistAddCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string playlist;
|
||||
private readonly string pathUri;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaylistAddCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="playlistName">The playlistn name.</param>
|
||||
/// <param name="uri">The path to add.</param>
|
||||
public PlaylistAddCommand(string playlistName, string uri)
|
||||
{
|
||||
this.playlist = playlistName;
|
||||
this.pathUri = uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "playlistadd", $"\"{playlist}\"", $"\"{pathUri}\"");
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
50
Sources/MpcNET/Commands/Playlist/PlaylistDeleteCommand.cs
Normal file
50
Sources/MpcNET/Commands/Playlist/PlaylistDeleteCommand.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlaylistDeleteCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Playlist
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Deletes SONGPOS from the playlist NAME.m3u.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#stored-playlists
|
||||
/// </summary>
|
||||
public class PlaylistDeleteCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string playlist;
|
||||
private readonly int songpos;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaylistDeleteCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="playlistName">The playlist name.</param>
|
||||
/// <param name="songpos">Position of the song to remove</param>
|
||||
public PlaylistDeleteCommand(string playlistName, int songpos)
|
||||
{
|
||||
this.playlist = playlistName;
|
||||
this.songpos = songpos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "playlistdelete", $"\"{playlist}\"", songpos);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
53
Sources/MpcNET/Commands/Playlist/PlaylistMoveCommand.cs
Normal file
53
Sources/MpcNET/Commands/Playlist/PlaylistMoveCommand.cs
Normal file
@ -0,0 +1,53 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlaylistMoveCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Playlist
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Moves the song at position FROM in the playlist NAME.m3u to the position TO.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#stored-playlists
|
||||
/// </summary>
|
||||
public class PlaylistMoveCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string playlist;
|
||||
private readonly int from;
|
||||
private readonly int to;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaylistMoveCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="playlistName">The playlist name.</param>
|
||||
/// <param name="from">Position of the song to move</param>
|
||||
/// <param name="to">New position of the song</param>
|
||||
public PlaylistMoveCommand(string playlistName, int from, int to)
|
||||
{
|
||||
this.playlist = playlistName;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "playlistmove", $"\"{playlist}\"", from, to);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
48
Sources/MpcNET/Commands/Playlist/RmCommand.cs
Normal file
48
Sources/MpcNET/Commands/Playlist/RmCommand.cs
Normal file
@ -0,0 +1,48 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="RmCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Playlist
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Removes the playlist NAME.m3u from the playlist directory.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#stored-playlists
|
||||
/// </summary>
|
||||
public class RmCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string playlistName;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RmCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="playlistName">Name of the playlist.</param>
|
||||
public RmCommand(string playlistName)
|
||||
{
|
||||
this.playlistName = playlistName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "rm", $"\"{this.playlistName}\"");
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
48
Sources/MpcNET/Commands/Playlist/SaveCommand.cs
Normal file
48
Sources/MpcNET/Commands/Playlist/SaveCommand.cs
Normal file
@ -0,0 +1,48 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="SaveCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Playlist
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Saves the queue to NAME.m3u in the playlist directory.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#stored-playlists
|
||||
/// </summary>
|
||||
public class SaveCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string playlistName;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SaveCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="playlistName">Name of the playlist.</param>
|
||||
public SaveCommand(string playlistName)
|
||||
{
|
||||
this.playlistName = playlistName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "save", $"\"{this.playlistName}\"");
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
49
Sources/MpcNET/Commands/Queue/AddCommand.cs
Normal file
49
Sources/MpcNET/Commands/Queue/AddCommand.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="AddCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using MpcNET;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Adds the file URI to the playlist (directories add recursively). URI can also be a single file.
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class AddCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string uri;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AddCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="uri">The URI.</param>
|
||||
public AddCommand(string uri)
|
||||
{
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "add", $"\"{uri}\"");
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
49
Sources/MpcNET/Commands/Queue/AddIdCommand.cs
Normal file
49
Sources/MpcNET/Commands/Queue/AddIdCommand.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="AddIdCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using MpcNET;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a song to the playlist (non-recursive) and returns the song id.
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class AddIdCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string uri;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AddIdCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="uri">The URI.</param>
|
||||
public AddIdCommand(string uri)
|
||||
{
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "addid", $"\"{uri}\"");
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
38
Sources/MpcNET/Commands/Queue/ClearCommand.cs
Normal file
38
Sources/MpcNET/Commands/Queue/ClearCommand.cs
Normal file
@ -0,0 +1,38 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="ClearCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current playlist.
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class ClearCommand : IMpcCommand<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => "clear";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
49
Sources/MpcNET/Commands/Queue/DeleteCommand.cs
Normal file
49
Sources/MpcNET/Commands/Queue/DeleteCommand.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="DeleteCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using MpcNET;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a song from the playlist.
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class DeleteCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly int position;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DeleteCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="position">The position.</param>
|
||||
public DeleteCommand(int position)
|
||||
{
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "delete", position);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
49
Sources/MpcNET/Commands/Queue/DeleteIdCommand.cs
Normal file
49
Sources/MpcNET/Commands/Queue/DeleteIdCommand.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="DeleteIdCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using MpcNET;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the song SONGID from the playlist.
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class DeleteIdCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly int songId;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DeleteIdCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="songId">The song identifier.</param>
|
||||
public DeleteIdCommand(int songId)
|
||||
{
|
||||
this.songId = songId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "deleteid", songId);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
53
Sources/MpcNET/Commands/Queue/MoveIdCommand.cs
Normal file
53
Sources/MpcNET/Commands/Queue/MoveIdCommand.cs
Normal file
@ -0,0 +1,53 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="AddCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using MpcNET;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Moves the song with FROM (songid) to TO (playlist index) in the playlist.
|
||||
/// If TO is negative, it is relative to the current song in the playlist (if there is one)
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class MoveIdCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly int from;
|
||||
private readonly int to;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MoveIdCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="from">From (songid)</param>
|
||||
/// <param name="to">To (playlist index)</param>
|
||||
public MoveIdCommand(int from, int to)
|
||||
{
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "moveid", from, to);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
50
Sources/MpcNET/Commands/Queue/PlChangesCommand.cs
Normal file
50
Sources/MpcNET/Commands/Queue/PlChangesCommand.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlChangesCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using MpcNET.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Displays changed songs currently in the playlist since VERSION.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#the-queue.
|
||||
/// </summary>
|
||||
public class PlChangesCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
||||
{
|
||||
private readonly string version;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlChangesCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="version">Version to compare to the current playlist.</param>
|
||||
public PlChangesCommand(int version = -1)
|
||||
{
|
||||
this.version = version.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => $"plchanges {version}";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<IMpdFile> Deserialize(SerializedResponse response)
|
||||
{
|
||||
return MpdFile.CreateList(response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
42
Sources/MpcNET/Commands/Queue/PlaylistCommand.cs
Normal file
42
Sources/MpcNET/Commands/Queue/PlaylistCommand.cs
Normal file
@ -0,0 +1,42 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlaylistCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MpcNET.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Displays the current playlist.
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class PlaylistCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => "playlist";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<IMpdFile> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var results = response.ResponseValues.Select(line => MpdFile.Create(line.Value, int.Parse(line.Key)));
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
50
Sources/MpcNET/Commands/Queue/PlaylistIdCommand.cs
Normal file
50
Sources/MpcNET/Commands/Queue/PlaylistIdCommand.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlaylistIdCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using MpcNET;
|
||||
using MpcNET.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Displays song ID in the playlist.
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class PlaylistIdCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
||||
{
|
||||
private readonly int songId;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaylistIdCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="songId">The song identifier.</param>
|
||||
public PlaylistIdCommand(int songId)
|
||||
{
|
||||
this.songId = songId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", "playlistid", songId);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<IMpdFile> Deserialize(SerializedResponse response)
|
||||
{
|
||||
return MpdFile.CreateList(response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
39
Sources/MpcNET/Commands/Queue/PlaylistInfoCommand.cs
Normal file
39
Sources/MpcNET/Commands/Queue/PlaylistInfoCommand.cs
Normal file
@ -0,0 +1,39 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PlaylistInfoCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace MpcNET.Commands.Queue
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using MpcNET.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Displays a list of all songs in the playlist.
|
||||
/// https://www.musicpd.org/doc/protocol/queue.html.
|
||||
/// </summary>
|
||||
public class PlaylistInfoCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => "playlistinfo";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<IMpdFile> Deserialize(SerializedResponse response)
|
||||
{
|
||||
return MpdFile.CreateList(response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
74
Sources/MpcNET/Commands/Reflection/CommandList.cs
Normal file
74
Sources/MpcNET/Commands/Reflection/CommandList.cs
Normal file
@ -0,0 +1,74 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="CommandList.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Reflection
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
/// <summary>
|
||||
/// To facilitate faster adding of files etc. you can pass a list of commands all at once using a command list.
|
||||
/// The command list begins with command_list_begin or command_list_ok_begin and ends with command_list_end.
|
||||
/// https://www.musicpd.org/doc/html/protocol.html#command-lists.
|
||||
/// </summary>
|
||||
public class CommandList : IMpcCommand<string>
|
||||
{
|
||||
|
||||
private readonly List<IMpcCommand<object>> commands;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="mpcCommands">IMpcCommand items to add to the list.</param>
|
||||
public CommandList(IEnumerable<IMpcCommand<object>> mpcCommands = null)
|
||||
{
|
||||
commands = new List<IMpcCommand<object>>();
|
||||
|
||||
if (mpcCommands != null)
|
||||
AddRange(mpcCommands);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a command to the list.
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
public void Add(IMpcCommand<object> c) => commands.Add(c);
|
||||
|
||||
/// <summary>
|
||||
/// Add a range of commands to the list.
|
||||
/// </summary>
|
||||
/// <param name="r"></param>
|
||||
public void AddRange(IEnumerable<IMpcCommand<object>> r) => commands.AddRange(r);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize()
|
||||
{
|
||||
var serializedCommands = commands.Select(c => c.Serialize()).ToList();
|
||||
|
||||
serializedCommands.Insert(0, "command_list_begin");
|
||||
serializedCommands.Add("command_list_end");
|
||||
|
||||
return string.Join("\n", serializedCommands.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -31,9 +31,9 @@ namespace MpcNET.Commands.Reflection
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<string> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<string> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var result = response.Where(item => item.Key.Equals("command")).Select(item => item.Value);
|
||||
var result = response.ResponseValues.Where(item => item.Key.Equals("command")).Select(item => item.Value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -30,12 +30,12 @@ namespace MpcNET.Commands.Reflection
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<MpdDecoderPlugin> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<MpdDecoderPlugin> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var result = new List<MpdDecoderPlugin>();
|
||||
|
||||
var mpdDecoderPlugin = MpdDecoderPlugin.Empty;
|
||||
foreach (var line in response)
|
||||
foreach (var line in response.ResponseValues)
|
||||
{
|
||||
if (line.Key.Equals("plugin"))
|
||||
{
|
||||
|
53
Sources/MpcNET/Commands/Reflection/PasswordCommand.cs
Normal file
53
Sources/MpcNET/Commands/Reflection/PasswordCommand.cs
Normal file
@ -0,0 +1,53 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PasswordCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Reflection
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Command to authenticate with a password.
|
||||
/// https://mpd.readthedocs.io/en/stable/protocol.html#connection-settings.
|
||||
/// </summary>
|
||||
public class PasswordCommand : IMpcCommand<string>
|
||||
{
|
||||
private readonly string _password;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PasswordCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pass">The password.</param>
|
||||
public PasswordCommand(string pass)
|
||||
{
|
||||
_password = pass;
|
||||
if (_password == "")
|
||||
{
|
||||
throw new ArgumentException("Empty string given to PasswordCommand");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialized command.
|
||||
/// </returns>
|
||||
public string Serialize() => string.Join(" ", new[] { "password", _password });
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -32,9 +32,9 @@ namespace MpcNET.Commands.Reflection
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<string> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<string> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var result = response.Where(item => item.Key.Equals("tagtype")).Select(item => item.Value);
|
||||
var result = response.ResponseValues.Where(item => item.Key.Equals("tagtype")).Select(item => item.Value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ namespace MpcNET.Commands.Reflection
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IEnumerable<string> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IEnumerable<string> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var result = response.Where(item => item.Key.Equals("handler")).Select(item => item.Value);
|
||||
var result = response.ResponseValues.Where(item => item.Key.Equals("handler")).Select(item => item.Value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ namespace MpcNET.Commands.Status
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public IMpdFile Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public IMpdFile Deserialize(SerializedResponse response)
|
||||
{
|
||||
return MpdFile.Create(response, 0).mpdFile;
|
||||
return MpdFile.Create(response.ResponseValues, 0).mpdFile;
|
||||
}
|
||||
}
|
||||
}
|
@ -48,9 +48,9 @@ namespace MpcNET.Commands.Status
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Status
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Cancels idle command.
|
||||
/// https://www.musicpd.org/doc/protocol/command_reference.html#status_commands.
|
||||
@ -29,9 +27,9 @@ namespace MpcNET.Commands.Status
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public string Deserialize(SerializedResponse response)
|
||||
{
|
||||
return string.Join(", ", response);
|
||||
return string.Join(", ", response.ResponseValues);
|
||||
}
|
||||
}
|
||||
}
|
51
Sources/MpcNET/Commands/Status/StatsCommand.cs
Normal file
51
Sources/MpcNET/Commands/Status/StatsCommand.cs
Normal file
@ -0,0 +1,51 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="StatsCommand.cs" company="MpcNET">
|
||||
// Copyright (c) MpcNET. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace MpcNET.Commands.Status
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Get stats from the daemon.
|
||||
/// https://www.musicpd.org/doc/protocol/command_reference.html#status_commands.
|
||||
/// </summary>
|
||||
public class StatsCommand : IMpcCommand<Dictionary<string, string>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The serialize command.
|
||||
/// </returns>
|
||||
public string Serialize() => "stats";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified response text pairs.
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public Dictionary<string, string> Deserialize(SerializedResponse response)
|
||||
{
|
||||
var result = new Dictionary<string, string>();
|
||||
|
||||
foreach (var pair in response.ResponseValues)
|
||||
{
|
||||
// If a similar key has already been added to the result dictionary, add a ' to this second one so it can still be passed through.
|
||||
// (It probably won't be used though...)
|
||||
var key = pair.Key;
|
||||
while (result.ContainsKey(key))
|
||||
{
|
||||
key = key + "'";
|
||||
}
|
||||
|
||||
result.Add(key, pair.Value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ namespace MpcNET.Commands.Status
|
||||
private const string DurationText = "duration";
|
||||
private const string MixrampDbText = "mixrampdb";
|
||||
private const string UpdatingDbText = "updating_db";
|
||||
private const string PartitionText = "partition";
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the command.
|
||||
@ -52,7 +53,7 @@ namespace MpcNET.Commands.Status
|
||||
/// <returns>
|
||||
/// The deserialized response.
|
||||
/// </returns>
|
||||
public MpdStatus Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
||||
public MpdStatus Deserialize(SerializedResponse response)
|
||||
{
|
||||
int volume = -1;
|
||||
bool repeat = false;
|
||||
@ -75,8 +76,9 @@ namespace MpcNET.Commands.Status
|
||||
TimeSpan duration;
|
||||
double mixrampDb = -1;
|
||||
int updatingDb = -1;
|
||||
string partition = string.Empty;
|
||||
string error = string.Empty;
|
||||
foreach (var keyValuePair in response)
|
||||
foreach (var keyValuePair in response.ResponseValues)
|
||||
{
|
||||
var value = keyValuePair.Value;
|
||||
switch (keyValuePair.Key)
|
||||
@ -143,6 +145,9 @@ namespace MpcNET.Commands.Status
|
||||
case UpdatingDbText:
|
||||
int.TryParse(value, out updatingDb);
|
||||
break;
|
||||
case PartitionText:
|
||||
partition = value;
|
||||
break;
|
||||
default:
|
||||
Debug.WriteLine($"Unprocessed status: {keyValuePair.Key} - {keyValuePair.Value}");
|
||||
break;
|
||||
@ -170,6 +175,7 @@ namespace MpcNET.Commands.Status
|
||||
audioBits,
|
||||
audioChannels,
|
||||
updatingDb,
|
||||
partition,
|
||||
error);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Text;
|
||||
|
||||
namespace MpcNET
|
||||
{
|
||||
internal class Constants
|
||||
@ -12,6 +14,13 @@ namespace MpcNET
|
||||
|
||||
public static readonly string Ack = "ACK";
|
||||
|
||||
public static readonly string Binary = "binary: ";
|
||||
|
||||
public static readonly string FirstLinePrefix = "OK MPD ";
|
||||
|
||||
/// <summary>
|
||||
/// Encoding used when reading server responses.
|
||||
/// </summary>
|
||||
public static readonly Encoding Encoding = new UTF8Encoding();
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,6 @@ namespace MpcNET
|
||||
/// </summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <returns>The deserialized response.</returns>
|
||||
TValue Deserialize(IReadOnlyList<KeyValuePair<string, string>> response);
|
||||
TValue Deserialize(SerializedResponse response);
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
namespace MpcNET
|
||||
{
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MpcNET.Message;
|
||||
|
||||
@ -26,7 +27,7 @@ namespace MpcNET
|
||||
/// Connects asynchronously.
|
||||
/// </summary>
|
||||
/// <returns>The connect task.</returns>
|
||||
Task ConnectAsync();
|
||||
Task ConnectAsync(CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects asynchronously.
|
||||
|
@ -19,5 +19,7 @@ namespace MpcNET.Message
|
||||
public IMpdResponse<T> Response { get; }
|
||||
|
||||
public bool IsResponseValid => false;
|
||||
|
||||
public override string ToString() => Response.Result.ErrorMessage;
|
||||
}
|
||||
}
|
@ -14,14 +14,16 @@ namespace MpcNET.Message
|
||||
internal class MpdMessage<T> : IMpdMessage<T>
|
||||
{
|
||||
private readonly Regex linePattern = new Regex(@"^(?<key>[\w-]*):[ ]{0,1}(?<value>.*)$");
|
||||
private readonly IList<string> rawResponse;
|
||||
private readonly IList<string> fullResponse;
|
||||
private readonly byte[] binaryData;
|
||||
|
||||
public MpdMessage(IMpcCommand<T> command, bool connected, IReadOnlyCollection<string> response)
|
||||
public MpdMessage(IMpcCommand<T> command, bool connected, IReadOnlyCollection<string> response, byte[] binaryData)
|
||||
{
|
||||
this.Request = new MpdRequest<T>(command);
|
||||
|
||||
this.binaryData = binaryData;
|
||||
var endLine = response.Skip(response.Count - 1).Single();
|
||||
this.rawResponse = response.Take(response.Count - 1).ToList();
|
||||
this.fullResponse = response.Take(response.Count - 1).ToList();
|
||||
|
||||
var values = this.Request.Command.Deserialize(this.GetValuesFromResponse());
|
||||
this.Response = new MpdResponse<T>(endLine, values, connected);
|
||||
@ -38,11 +40,11 @@ namespace MpcNET.Message
|
||||
return JsonConvert.SerializeObject(this, Formatting.Indented);
|
||||
}
|
||||
|
||||
private IReadOnlyList<KeyValuePair<string, string>> GetValuesFromResponse()
|
||||
private SerializedResponse GetValuesFromResponse()
|
||||
{
|
||||
var result = new List<KeyValuePair<string, string>>();
|
||||
|
||||
foreach (var line in this.rawResponse)
|
||||
foreach (var line in this.fullResponse)
|
||||
{
|
||||
var match = this.linePattern.Match(line);
|
||||
if (match.Success)
|
||||
@ -55,11 +57,12 @@ namespace MpcNET.Message
|
||||
{
|
||||
result.Add(new KeyValuePair<string, string>(mpdKey, mpdValue));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return new SerializedResponse { ResponseValues = result, BinaryData = binaryData };
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ namespace MpcNET.Message
|
||||
if (this.Exception != null)
|
||||
{
|
||||
this.Status = "EXCEPTION";
|
||||
this.ErrorMessage = Exception.ToString();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(this.endLine))
|
||||
@ -60,7 +61,7 @@ namespace MpcNET.Message
|
||||
|
||||
if (match.Groups.Count != 5)
|
||||
{
|
||||
this.ErrorMessage = "Unexpected response from server.";
|
||||
this.ErrorMessage = $"Unexpected response from server: {MpdError}";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -13,11 +13,11 @@ namespace MpcNET
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MpcNET.Commands;
|
||||
using MpcNET.Exceptions;
|
||||
using MpcNET.Message;
|
||||
using Sundew.Base.ControlFlow;
|
||||
using Polly;
|
||||
|
||||
/// <summary>
|
||||
/// Keeps the connection to the MPD server and handels the most basic structure of the MPD protocol.
|
||||
@ -25,8 +25,7 @@ namespace MpcNET
|
||||
/// </summary>
|
||||
public class MpcConnection : IMpcConnection
|
||||
{
|
||||
private static readonly Encoding Encoding = new UTF8Encoding();
|
||||
private readonly IMpcConnectionReporter mpcConnectionReporter;
|
||||
private readonly Encoding Encoding = new UTF8Encoding();
|
||||
private readonly IPEndPoint server;
|
||||
|
||||
private TcpClient tcpClient;
|
||||
@ -36,11 +35,9 @@ namespace MpcNET
|
||||
/// Initializes a new instance of the <see cref="MpcConnection" /> class.
|
||||
/// </summary>
|
||||
/// <param name="server">The server.</param>
|
||||
/// <param name="mpcConnectionReporter">The MPC connection logger.</param>
|
||||
public MpcConnection(IPEndPoint server, IMpcConnectionReporter mpcConnectionReporter = null)
|
||||
public MpcConnection(IPEndPoint server)
|
||||
{
|
||||
this.mpcConnectionReporter = mpcConnectionReporter;
|
||||
this.ClearConnectionFields();
|
||||
ClearConnectionFields();
|
||||
this.server = server ?? throw new ArgumentNullException("Server IPEndPoint not set.", nameof(server));
|
||||
}
|
||||
|
||||
@ -49,22 +46,32 @@ namespace MpcNET
|
||||
/// </summary>
|
||||
public string Version { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this connection active?
|
||||
/// </summary>
|
||||
public bool IsConnected => tcpClient?.Connected ?? false;
|
||||
|
||||
/// <summary>
|
||||
/// Event emitted when the connection is cut.
|
||||
/// </summary>
|
||||
public event EventHandler<EventArgs> Disconnected;
|
||||
|
||||
/// <summary>
|
||||
/// Connects asynchronously.
|
||||
/// </summary>
|
||||
/// <returns>The connect task.</returns>
|
||||
public async Task ConnectAsync()
|
||||
public async Task ConnectAsync(CancellationToken token = default)
|
||||
{
|
||||
if (this.tcpClient != null)
|
||||
if (tcpClient != null)
|
||||
{
|
||||
var pingResult = await this.PingAsync();
|
||||
var pingResult = await PingAsync();
|
||||
if (pingResult)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await this.ReconnectAsync(false);
|
||||
await ReconnectAsync(false, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -73,7 +80,8 @@ namespace MpcNET
|
||||
/// <returns>The disconnect task.</returns>
|
||||
public Task DisconnectAsync()
|
||||
{
|
||||
return this.DisconnectAsync(true);
|
||||
Disconnect(true);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -86,9 +94,9 @@ namespace MpcNET
|
||||
/// </returns>
|
||||
public async Task<IMpdMessage<TResponse>> SendAsync<TResponse>(IMpcCommand<TResponse> mpcCommand)
|
||||
{
|
||||
if (this.tcpClient == null)
|
||||
if (tcpClient == null)
|
||||
{
|
||||
await this.ReconnectAsync(true);
|
||||
await ReconnectAsync(true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (mpcCommand == null)
|
||||
@ -96,74 +104,74 @@ namespace MpcNET
|
||||
throw new CommandNullException();
|
||||
}
|
||||
|
||||
Exception lastException = null;
|
||||
IReadOnlyList<string> response = new List<string>();
|
||||
var sendAttempter = new Attempter(3);
|
||||
byte[] rawResponse = null;
|
||||
|
||||
var commandText = mpcCommand.Serialize();
|
||||
this.mpcConnectionReporter?.Sending(commandText);
|
||||
while (sendAttempter.Attempt())
|
||||
|
||||
Exception finalException = null;
|
||||
|
||||
// Send the command, retrying three times in case of an exception
|
||||
for (var i=0; i < 3; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var writer = new StreamWriter(this.networkStream, Encoding, 512, true) { NewLine = "\n" })
|
||||
using (var writer = new StreamWriter(networkStream, Encoding, 512, true) { NewLine = "\n" })
|
||||
{
|
||||
await writer.WriteLineAsync(commandText);
|
||||
await writer.FlushAsync();
|
||||
}
|
||||
|
||||
response = await this.ReadResponseAsync(commandText);
|
||||
(rawResponse, response) = ReadResponse(commandText);
|
||||
if (response.Any())
|
||||
{
|
||||
lastException = null;
|
||||
finalException = null;
|
||||
break;
|
||||
}
|
||||
|
||||
throw new EmptyResponseException(commandText);
|
||||
}
|
||||
catch (Exception exception)
|
||||
} catch (Exception e)
|
||||
{
|
||||
lastException = exception;
|
||||
this.mpcConnectionReporter?.SendException(commandText, sendAttempter.CurrentAttempt, exception);
|
||||
await this.ReconnectAsync(true);
|
||||
this.mpcConnectionReporter?.RetrySend(commandText, sendAttempter.CurrentAttempt);
|
||||
finalException = e;
|
||||
await ReconnectAsync(true).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastException != null)
|
||||
if (finalException != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.DisconnectAsync(false);
|
||||
Disconnect(false);
|
||||
}
|
||||
catch (Exception)
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return new ErrorMpdMessage<TResponse>(mpcCommand, new ErrorMpdResponse<TResponse>(lastException));
|
||||
return new ErrorMpdMessage<TResponse>(mpcCommand, new ErrorMpdResponse<TResponse>(finalException));
|
||||
}
|
||||
|
||||
return new MpdMessage<TResponse>(mpcCommand, true, response);
|
||||
return new MpdMessage<TResponse>(mpcCommand, true, response, rawResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
void IDisposable.Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
this.DisconnectAsync().Wait();
|
||||
Disconnect(true);
|
||||
}
|
||||
|
||||
private async Task<bool> PingAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var writer = new StreamWriter(this.networkStream, Encoding, 512, true) { NewLine = "\n" })
|
||||
using (var writer = new StreamWriter(networkStream, Encoding, 512, true) { NewLine = "\n" })
|
||||
{
|
||||
await writer.WriteLineAsync("ping");
|
||||
await writer.FlushAsync();
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(this.networkStream, Encoding, true, 512, true))
|
||||
using (var reader = new StreamReader(networkStream, Encoding, true, 512, true))
|
||||
{
|
||||
var responseLine = await reader.ReadLineAsync();
|
||||
return responseLine == "OK";
|
||||
@ -175,81 +183,133 @@ namespace MpcNET
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReconnectAsync(bool isReconnect)
|
||||
private async Task ReconnectAsync(bool isReconnect, CancellationToken token = default)
|
||||
{
|
||||
var connectAttempter = new Attempter(3);
|
||||
while (connectAttempter.Attempt())
|
||||
{
|
||||
this.mpcConnectionReporter?.Connecting(isReconnect, connectAttempter.CurrentAttempt);
|
||||
await this.DisconnectAsync(false);
|
||||
|
||||
this.tcpClient = new TcpClient();
|
||||
await this.tcpClient.ConnectAsync(this.server.Address, this.server.Port);
|
||||
if (this.tcpClient.Connected)
|
||||
var connectResult = await Policy
|
||||
.Handle<Exception>()
|
||||
.RetryAsync(isReconnect ? 0 : 3)
|
||||
.ExecuteAndCaptureAsync(async (t) =>
|
||||
{
|
||||
this.mpcConnectionReporter?.ConnectionAccepted(isReconnect, connectAttempter.CurrentAttempt);
|
||||
break;
|
||||
var client = new TcpClient();
|
||||
using (t.Register(() => client.Close()))
|
||||
{
|
||||
try
|
||||
{
|
||||
await client.ConnectAsync(server.Address, server.Port).ConfigureAwait(false);
|
||||
}
|
||||
catch (ObjectDisposedException) when (t.IsCancellationRequested)
|
||||
{
|
||||
t.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
|
||||
if (client.Connected)
|
||||
{
|
||||
return client;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, token, true).ConfigureAwait(false);
|
||||
|
||||
if (connectResult.Outcome == OutcomeType.Successful && connectResult.Result != null)
|
||||
{
|
||||
Disconnect(false);
|
||||
tcpClient = connectResult.Result;
|
||||
|
||||
networkStream = tcpClient.GetStream();
|
||||
using (var reader = new StreamReader(networkStream, Encoding, true, 512, true))
|
||||
{
|
||||
var firstLine = await reader.ReadLineAsync();
|
||||
if (firstLine != null && !firstLine.StartsWith(Constants.FirstLinePrefix))
|
||||
{
|
||||
await DisconnectAsync();
|
||||
throw new MpcConnectException("Response of mpd does not start with \"" + Constants.FirstLinePrefix + "\".");
|
||||
}
|
||||
|
||||
Version = firstLine?.Substring(Constants.FirstLinePrefix.Length);
|
||||
}
|
||||
}
|
||||
|
||||
this.networkStream = this.tcpClient.GetStream();
|
||||
using (var reader = new StreamReader(this.networkStream, Encoding, true, 512, true))
|
||||
else
|
||||
{
|
||||
var firstLine = await reader.ReadLineAsync();
|
||||
if (!firstLine.StartsWith(Constants.FirstLinePrefix))
|
||||
{
|
||||
await this.DisconnectAsync(false);
|
||||
throw new MpcConnectException("Response of mpd does not start with \"" + Constants.FirstLinePrefix + "\".");
|
||||
}
|
||||
|
||||
this.Version = firstLine.Substring(Constants.FirstLinePrefix.Length);
|
||||
this.mpcConnectionReporter?.Connected(isReconnect, connectAttempter.CurrentAttempt, firstLine);
|
||||
// We couldn't reconnect
|
||||
Disconnected?.Invoke(this, new EventArgs());
|
||||
throw new MpcConnectException(connectResult.FinalException?.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyList<string>> ReadResponseAsync(string commandText)
|
||||
private Tuple<byte[], IReadOnlyList<string>> ReadResponse(string commandText)
|
||||
{
|
||||
var response = new List<string>();
|
||||
using (var reader = new StreamReader(this.networkStream, Encoding, true, 512, true))
|
||||
byte[] binaryResponse = null;
|
||||
|
||||
var reader = new MpdResponseReader(networkStream, Encoding);
|
||||
MpdResponseReader.NextData nextData;
|
||||
|
||||
string responseLine;
|
||||
while ((nextData = reader.ReportNextData()) != MpdResponseReader.NextData.Eof)
|
||||
{
|
||||
string responseLine;
|
||||
do
|
||||
// If the incoming data is binary, read it raw
|
||||
if (nextData == MpdResponseReader.NextData.BinaryData)
|
||||
{
|
||||
responseLine = await reader.ReadLineAsync();
|
||||
this.mpcConnectionReporter?.ReadResponse(responseLine, commandText);
|
||||
// The reader already knows the length of the binary data, so we just tell it to read.
|
||||
// MPD binary responses usually don't go past 8192 bytes.
|
||||
byte[] buf = new byte[8192];
|
||||
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
do
|
||||
{
|
||||
var bytesRead = reader.ReadBinaryData(buf, 0, buf.Length);
|
||||
ms.Write(buf, 0, bytesRead);
|
||||
} while (reader.ReportNextData() == MpdResponseReader.NextData.BinaryData);
|
||||
|
||||
binaryResponse = ms.ToArray();
|
||||
}
|
||||
}
|
||||
else // else, read string as usual
|
||||
{
|
||||
responseLine = reader.ReadString();
|
||||
|
||||
if (responseLine == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
response.Add(responseLine);
|
||||
|
||||
if (responseLine.Equals(Constants.Ok) || responseLine.StartsWith(Constants.Ack))
|
||||
{
|
||||
// Stop reading the stream
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
while (!(responseLine.Equals(Constants.Ok) || responseLine.StartsWith(Constants.Ack)));
|
||||
|
||||
}
|
||||
|
||||
return response;
|
||||
return new Tuple<byte[], IReadOnlyList<string>>(binaryResponse, response);
|
||||
}
|
||||
|
||||
private Task DisconnectAsync(bool isExplicitDisconnect)
|
||||
private void Disconnect(bool isExplicitDisconnect)
|
||||
{
|
||||
if (this.tcpClient == null)
|
||||
if (tcpClient == null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
this.mpcConnectionReporter?.Disconnecting(isExplicitDisconnect);
|
||||
this.ClearConnectionFields();
|
||||
this.mpcConnectionReporter?.Disconnected(isExplicitDisconnect);
|
||||
return Task.CompletedTask;
|
||||
ClearConnectionFields();
|
||||
|
||||
if (isExplicitDisconnect)
|
||||
Disconnected?.Invoke(this, new EventArgs());
|
||||
}
|
||||
|
||||
private void ClearConnectionFields()
|
||||
{
|
||||
this.networkStream?.Dispose();
|
||||
this.tcpClient?.Dispose();
|
||||
this.Version = string.Empty;
|
||||
this.tcpClient = null;
|
||||
this.networkStream = null;
|
||||
networkStream?.Dispose();
|
||||
tcpClient?.Dispose();
|
||||
Version = string.Empty;
|
||||
tcpClient = null;
|
||||
networkStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,12 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<AssemblyName>MpcNET</AssemblyName>
|
||||
<PackageId>MpcNET.SundewFork</PackageId>
|
||||
<PackageId>MpcNET</PackageId>
|
||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
||||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
|
||||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
|
||||
<RootNamespace>MpcNET</RootNamespace>
|
||||
<Version>0.0.2</Version>
|
||||
<Version>1.0.0</Version>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<AssemblyVersion>0.0.1.0</AssemblyVersion>
|
||||
<FileVersion>0.0.1.0</FileVersion>
|
||||
@ -44,12 +44,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Sundew.Base" Version="4.0.0" />
|
||||
<PackageReference Include="Sundew.Build.Publish" Version="1.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Polly" Version="7.2.2" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
250
Sources/MpcNET/MpdResponseReader.cs
Normal file
250
Sources/MpcNET/MpdResponseReader.cs
Normal file
@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace MpcNET
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class MpdResponseReader : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum NextData
|
||||
{
|
||||
#pragma warning disable CS1591
|
||||
Unknown,
|
||||
Eof,
|
||||
String,
|
||||
BinaryData
|
||||
#pragma warning restore CS1591
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Length of the binary part of the response.
|
||||
/// </summary>
|
||||
public int binaryEnd;
|
||||
|
||||
private Stream source;
|
||||
private Encoding encoding;
|
||||
private byte[] byteBuffer;
|
||||
private int bufferOffset;
|
||||
private int bufferEnd;
|
||||
private NextData nextData;
|
||||
private int binaryOffset;
|
||||
private char[] characterBuffer;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="encoding"></param>
|
||||
public MpdResponseReader(Stream source, Encoding encoding)
|
||||
{
|
||||
this.source = source;
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public NextData ReportNextData()
|
||||
{
|
||||
if (nextData != NextData.Unknown)
|
||||
{
|
||||
return nextData;
|
||||
}
|
||||
|
||||
if (!PopulateBufferIfNeeded(1))
|
||||
{
|
||||
return (nextData = NextData.Eof);
|
||||
}
|
||||
|
||||
return (nextData = NextData.String);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string ReadString()
|
||||
{
|
||||
ReportNextData();
|
||||
|
||||
if (nextData == NextData.Eof)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
else if (nextData != NextData.String)
|
||||
{
|
||||
throw new InvalidOperationException("Attempt to read non-string data as string");
|
||||
}
|
||||
|
||||
if (characterBuffer == null)
|
||||
{
|
||||
characterBuffer = new char[4];
|
||||
}
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
Decoder decoder = encoding.GetDecoder();
|
||||
|
||||
while (nextData == NextData.String)
|
||||
{
|
||||
byte b = byteBuffer[bufferOffset];
|
||||
|
||||
if (b == '\n')
|
||||
{
|
||||
// Analyze the obtained string to see if it's a binary data header
|
||||
if (stringBuilder.ToString().StartsWith(Constants.Binary))
|
||||
{
|
||||
nextData = NextData.BinaryData;
|
||||
binaryEnd = int.Parse(stringBuilder.ToString().Replace(Constants.Binary, ""));
|
||||
binaryOffset = 0;
|
||||
} else
|
||||
{
|
||||
nextData = NextData.Unknown;
|
||||
}
|
||||
|
||||
bufferOffset++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
var decodedChars = decoder.GetChars(byteBuffer, bufferOffset++, 1, characterBuffer, 0);
|
||||
if (decodedChars == 1)
|
||||
{
|
||||
stringBuilder.Append(characterBuffer[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
stringBuilder.Append(characterBuffer, 0, decodedChars);
|
||||
}
|
||||
|
||||
if (bufferOffset == bufferEnd && !PopulateBufferIfNeeded(1))
|
||||
{
|
||||
nextData = NextData.Eof;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public int ReadBinaryData(byte[] buffer, int offset, int count)
|
||||
{
|
||||
ReportNextData();
|
||||
|
||||
if (nextData == NextData.Eof)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
else if (nextData != NextData.BinaryData)
|
||||
{
|
||||
throw new InvalidOperationException("Attempt to read non-binary data as binary data");
|
||||
}
|
||||
|
||||
if (count > binaryEnd - binaryOffset)
|
||||
{
|
||||
count = binaryEnd - binaryOffset;
|
||||
//throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
int bytesRead;
|
||||
|
||||
if (bufferOffset < bufferEnd)
|
||||
{
|
||||
bytesRead = Math.Min(count, bufferEnd - bufferOffset);
|
||||
|
||||
Array.Copy(byteBuffer, bufferOffset, buffer, offset, bytesRead);
|
||||
bufferOffset += bytesRead;
|
||||
}
|
||||
else if (count < byteBuffer.Length)
|
||||
{
|
||||
if (!PopulateBufferIfNeeded(1))
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
bytesRead = Math.Min(count, bufferEnd - bufferOffset);
|
||||
|
||||
Array.Copy(byteBuffer, bufferOffset, buffer, offset, bytesRead);
|
||||
bufferOffset += bytesRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesRead = source.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
binaryOffset += bytesRead;
|
||||
|
||||
if (binaryOffset == binaryEnd)
|
||||
{
|
||||
nextData = NextData.Unknown;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
private bool PopulateBufferIfNeeded(int minimumBytes)
|
||||
{
|
||||
if (byteBuffer == null)
|
||||
{
|
||||
byteBuffer = new byte[32768];
|
||||
}
|
||||
|
||||
if (bufferEnd - bufferOffset < minimumBytes)
|
||||
{
|
||||
int shiftCount = bufferEnd - bufferOffset;
|
||||
|
||||
if (shiftCount > 0)
|
||||
{
|
||||
Array.Copy(byteBuffer, bufferOffset, byteBuffer, 0, shiftCount);
|
||||
}
|
||||
|
||||
bufferOffset = 0;
|
||||
bufferEnd = shiftCount;
|
||||
|
||||
while (bufferEnd - bufferOffset < minimumBytes)
|
||||
{
|
||||
int bytesRead = source.Read(byteBuffer, bufferEnd, byteBuffer.Length - bufferEnd);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bufferEnd += bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Stream source = this.source;
|
||||
|
||||
this.source = null;
|
||||
|
||||
if (source != null)
|
||||
{
|
||||
source.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ namespace MpcNET
|
||||
/// <param name="audioBits">The audio bits.</param>
|
||||
/// <param name="audioChannels">The audio channels.</param>
|
||||
/// <param name="updatingDb">The updating database.</param>
|
||||
/// <param name="partition">The partition name.</param>
|
||||
/// <param name="error">The error.</param>
|
||||
public MpdStatus(
|
||||
int volume,
|
||||
@ -59,29 +60,31 @@ namespace MpcNET
|
||||
int audioBits,
|
||||
int audioChannels,
|
||||
int updatingDb,
|
||||
string partition,
|
||||
string error)
|
||||
{
|
||||
this.Volume = volume;
|
||||
this.Repeat = repeat;
|
||||
this.Random = random;
|
||||
this.Consume = consume;
|
||||
this.Single = single;
|
||||
this.Playlist = playlist;
|
||||
this.PlaylistLength = playlistLength;
|
||||
this.XFade = xFade;
|
||||
this.State = state;
|
||||
this.Song = song;
|
||||
this.SongId = songId;
|
||||
this.NextSong = nextSong;
|
||||
this.NextSongId = nextSongId;
|
||||
this.Elapsed = elapsed;
|
||||
this.Duration = duration;
|
||||
this.Bitrate = bitrate;
|
||||
this.AudioSampleRate = audioSampleRate;
|
||||
this.AudioBits = audioBits;
|
||||
this.AudioChannels = audioChannels;
|
||||
this.UpdatingDb = updatingDb;
|
||||
this.Error = error;
|
||||
Volume = volume;
|
||||
Repeat = repeat;
|
||||
Random = random;
|
||||
Consume = consume;
|
||||
Single = single;
|
||||
Playlist = playlist;
|
||||
PlaylistLength = playlistLength;
|
||||
XFade = xFade;
|
||||
State = state;
|
||||
Song = song;
|
||||
SongId = songId;
|
||||
NextSong = nextSong;
|
||||
NextSongId = nextSongId;
|
||||
Elapsed = elapsed;
|
||||
Duration = duration;
|
||||
Bitrate = bitrate;
|
||||
AudioSampleRate = audioSampleRate;
|
||||
AudioBits = audioBits;
|
||||
AudioChannels = audioChannels;
|
||||
UpdatingDb = updatingDb;
|
||||
Partition = partition;
|
||||
Error = error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -184,6 +187,12 @@ namespace MpcNET
|
||||
/// </summary>
|
||||
public int UpdatingDb { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the current partition
|
||||
/// </summary>
|
||||
public string Partition { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error message, if there is an error.
|
||||
/// </summary>
|
||||
@ -197,13 +206,14 @@ namespace MpcNET
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
AppendInt(builder, "volume", this.Volume);
|
||||
AppendBool(builder, "repeat", this.Repeat);
|
||||
AppendBool(builder, "random", this.Random);
|
||||
AppendInt(builder, "playlist", this.Playlist);
|
||||
AppendInt(builder, "playlistlength", this.PlaylistLength);
|
||||
AppendInt(builder, "xfade", this.XFade);
|
||||
switch (this.State)
|
||||
builder.AppendLine($"partition: {Partition}");
|
||||
AppendInt(builder, "volume", Volume);
|
||||
AppendBool(builder, "repeat", Repeat);
|
||||
AppendBool(builder, "random", Random);
|
||||
AppendInt(builder, "playlist", Playlist);
|
||||
AppendInt(builder, "playlistlength", PlaylistLength);
|
||||
AppendInt(builder, "xfade", XFade);
|
||||
switch (State)
|
||||
{
|
||||
case MpdState.Play:
|
||||
builder.AppendLine("state: play");
|
||||
@ -216,34 +226,34 @@ namespace MpcNET
|
||||
break;
|
||||
}
|
||||
|
||||
AppendInt(builder, "song", this.Song);
|
||||
AppendInt(builder, "songid", this.SongId);
|
||||
if (this.Elapsed > TimeSpan.Zero || this.Duration > TimeSpan.Zero)
|
||||
AppendInt(builder, "song", Song);
|
||||
AppendInt(builder, "songid", SongId);
|
||||
if (Elapsed > TimeSpan.Zero || Duration > TimeSpan.Zero)
|
||||
{
|
||||
builder.Append("time: ");
|
||||
builder.Append(this.Elapsed);
|
||||
builder.Append(Elapsed);
|
||||
builder.Append(":");
|
||||
builder.Append(this.Duration);
|
||||
builder.Append(Duration);
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
AppendInt(builder, "bitrate", this.Bitrate);
|
||||
if ((this.AudioSampleRate >= 0) || (this.AudioBits >= 0) || (this.AudioChannels >= 0))
|
||||
AppendInt(builder, "bitrate", Bitrate);
|
||||
if ((AudioSampleRate >= 0) || (AudioBits >= 0) || (AudioChannels >= 0))
|
||||
{
|
||||
builder.Append("audio: ");
|
||||
builder.Append(this.AudioSampleRate);
|
||||
builder.Append(AudioSampleRate);
|
||||
builder.Append(":");
|
||||
builder.Append(this.AudioBits);
|
||||
builder.Append(AudioBits);
|
||||
builder.Append(":");
|
||||
builder.Append(this.AudioChannels);
|
||||
builder.Append(AudioChannels);
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
AppendInt(builder, "updating_db", this.UpdatingDb);
|
||||
if (this.Error != null)
|
||||
AppendInt(builder, "updating_db", UpdatingDb);
|
||||
if (Error != null)
|
||||
{
|
||||
builder.Append("error: ");
|
||||
builder.AppendLine(this.Error);
|
||||
builder.AppendLine(Error);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
|
22
Sources/MpcNET/SerializedResponse.cs
Normal file
22
Sources/MpcNET/SerializedResponse.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MpcNET
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class SerializedResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Response values.
|
||||
/// </summary>
|
||||
public IReadOnlyList<KeyValuePair<string, string>> ResponseValues {get; set;}
|
||||
/// <summary>
|
||||
/// Binary Data that can be present in the response.
|
||||
/// </summary>
|
||||
public byte[] BinaryData { get; set; }
|
||||
|
||||
}
|
||||
}
|
@ -28,19 +28,27 @@ namespace MpcNET.Tags
|
||||
public static ITag File { get; } = new Tag("file");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base tag.
|
||||
/// Gets the title tag.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The base.
|
||||
/// </value>
|
||||
public static ITag Base { get; } = new Tag("base");
|
||||
public static ITag Title { get; } = new Tag("title");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the modified since tag.
|
||||
/// Gets the artist tag.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The modified since.
|
||||
/// </value>
|
||||
public static ITag ModifiedSince { get; } = new Tag("modified-since");
|
||||
public static ITag Artist { get; } = new Tag("artist");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album tag.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The base.
|
||||
/// </value>
|
||||
public static ITag Album { get; } = new Tag("album");
|
||||
}
|
||||
}
|
@ -54,14 +54,6 @@ namespace MpcNET.Types
|
||||
/// </value>
|
||||
string Track { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name.
|
||||
/// </value>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the genre.
|
||||
/// </summary>
|
||||
@ -160,7 +152,7 @@ namespace MpcNET.Types
|
||||
bool HasTrack { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the MpdFile has the <see cref="Name"/> property set.
|
||||
/// Gets a value indicating whether the MpdFile has the <see cref="IMpdFilePath.Name"/> property set.
|
||||
/// </summary>
|
||||
bool HasName { get; }
|
||||
|
||||
|
@ -18,5 +18,13 @@ namespace MpcNET.Types
|
||||
/// The path.
|
||||
/// </value>
|
||||
string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name.
|
||||
/// </value>
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
38
Sources/MpcNET/Types/MpdBinaryData.cs
Normal file
38
Sources/MpcNET/Types/MpdBinaryData.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MpcNET.Types
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class MpdBinaryData
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MpdBinaryData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="size">The total size of the binary data requested</param>
|
||||
/// <param name="binary">The size of the data contained in this response</param>
|
||||
/// <param name="data">The data itself.</param>
|
||||
public MpdBinaryData(long size, long binary, byte[] data)
|
||||
{
|
||||
this.Size = size;
|
||||
this.Binary = binary;
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total size of the binary data requeste
|
||||
/// </summary>
|
||||
public long Size { get; }
|
||||
/// <summary>
|
||||
/// Gets the size of the data contained in this response
|
||||
/// </summary>
|
||||
public long Binary { get; }
|
||||
/// <summary>
|
||||
/// Gets the data contained in this response
|
||||
/// </summary>
|
||||
public byte[] Data { get; }
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ namespace MpcNET.Types
|
||||
/// <summary>
|
||||
/// Represents a MPD directory.
|
||||
/// </summary>
|
||||
public class MpdDirectory
|
||||
public class MpdDirectory: IMpdFilePath
|
||||
{
|
||||
private readonly List<IMpdFilePath> files = new List<IMpdFilePath>();
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
namespace MpcNET.Types
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
/// <summary>
|
||||
/// The MpdFile class contains all meta data for a file of the MPD.
|
||||
@ -182,6 +183,11 @@ namespace MpcNET.Types
|
||||
/// </summary>
|
||||
public bool HasId => this.Id != NoId;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Title ?? Name ?? Path.Split('/').Last();
|
||||
}
|
||||
|
||||
internal static MpdFile Create(string path, int pos)
|
||||
{
|
||||
return new MpdFile(path, pos: pos);
|
||||
@ -305,7 +311,15 @@ namespace MpcNET.Types
|
||||
|
||||
break;
|
||||
default:
|
||||
unknownMetadata.Add(line.Key, line.Value);
|
||||
// If a similar key has already been added to unknown metadata, add a ' to this second one so it can still be passed through.
|
||||
// (It certainly won't be used though)
|
||||
var key = line.Key;
|
||||
while (unknownMetadata.ContainsKey(key))
|
||||
{
|
||||
key = key + "'";
|
||||
}
|
||||
unknownMetadata.Add(key, line.Value);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,13 @@ namespace MpcNET.Types
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="plugin">The plugin name.</param>
|
||||
/// <param name="enabled">if set to <c>true</c> [enabled].</param>
|
||||
public MpdOutput(int id, string name, bool enabled)
|
||||
public MpdOutput(int id, string name, string plugin, bool enabled)
|
||||
{
|
||||
this.Id = id;
|
||||
this.Name = name;
|
||||
this.Plugin = plugin;
|
||||
this.IsEnabled = enabled;
|
||||
}
|
||||
|
||||
@ -40,6 +42,14 @@ namespace MpcNET.Types
|
||||
/// </value>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin name.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The plugin name.
|
||||
/// </value>
|
||||
public string Plugin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is enabled.
|
||||
/// </summary>
|
||||
|
@ -7,6 +7,7 @@
|
||||
namespace MpcNET.Types
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
/// <summary>
|
||||
@ -39,6 +40,29 @@ namespace MpcNET.Types
|
||||
/// </value>
|
||||
public DateTime LastModified { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Equals implementation.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is MpdPlaylist playlist &&
|
||||
Name == playlist.Name &&
|
||||
LastModified == playlist.LastModified;
|
||||
}
|
||||
/// <summary>
|
||||
/// HashCode implementation.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hashCode = 1509980188;
|
||||
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name);
|
||||
hashCode = hashCode * -1521134295 + LastModified.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
internal void AddLastModified(string lastModified)
|
||||
{
|
||||
this.LastModified = DateTime.Parse(lastModified, CultureInfo.InvariantCulture);
|
||||
|
BIN
Sources/MpcNET/icon.png
Normal file
BIN
Sources/MpcNET/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
@ -3,4 +3,4 @@
|
||||
<packageSources>
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
Reference in New Issue
Block a user