mirror of
https://github.com/ZetaKebab/MpcNET.git
synced 2025-07-01 16:47:37 +00:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
d907f9b6e3 | |||
316cfb0a31 | |||
b732457a34 | |||
6bcc61b57b | |||
28e5dbd334 | |||
585baf96ac | |||
17e41c07cb | |||
374249840b | |||
0194291779 | |||
cc0aa24324 | |||
133571023e | |||
7a0a28dbe9 | |||
1f61079811 | |||
95a81a0afd | |||
a6b575ecd8 | |||
154c4b8b18 | |||
312a73dc66 | |||
588bc92c00 | |||
c0d2ac48f6 | |||
61b6e33b79 | |||
2c245acaad |
27
.github/workflows/build-and-test.yml
vendored
27
.github/workflows/build-and-test.yml
vendored
@ -10,15 +10,11 @@ jobs:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
|
|
||||||
strategy:
|
runs-on: windows-latest
|
||||||
matrix:
|
|
||||||
configuration: [Debug, Release]
|
|
||||||
|
|
||||||
runs-on: windows-latest # For a list of available runner types, refer to
|
|
||||||
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
Solution_Name: MpcNET
|
Solution_Name: MpcNET
|
||||||
|
Configuration: Release
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@ -35,11 +31,18 @@ jobs:
|
|||||||
working-directory: ./Sources
|
working-directory: ./Sources
|
||||||
run: |
|
run: |
|
||||||
msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration
|
msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration
|
||||||
msbuild $env:Uap_Project_Directory /t:Restore /p:Configuration=$env:Configuration
|
|
||||||
env:
|
# Build package and upload to github packages
|
||||||
Configuration: ${{ matrix.configuration }}
|
- name: Build package
|
||||||
|
working-directory: ./Sources
|
||||||
|
run: |
|
||||||
|
dotnet nuget add source --username Difegue --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/Difegue/index.json"
|
||||||
|
dotnet build $env:Solution_Name --configuration $env:Configuration
|
||||||
|
dotnet pack --configuration $env:Configuration -o ./
|
||||||
|
dotnet nuget push *.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source "github" --skip-duplicate
|
||||||
|
|
||||||
# Execute all unit tests in the solution
|
# Execute all unit tests in the solution
|
||||||
- name: Execute unit tests
|
#- name: Execute unit tests
|
||||||
working-directory: ./Sources
|
# working-directory: ./Sources
|
||||||
run: dotnet test
|
# run: dotnet test
|
||||||
|
|
||||||
|
39
.github/workflows/release.yml
vendored
Normal file
39
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
name: New Version Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
Solution_Name: MpcNET
|
||||||
|
Configuration: Release
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||||
|
- name: Setup MSBuild.exe
|
||||||
|
uses: microsoft/setup-msbuild@v1.0.2
|
||||||
|
|
||||||
|
# Restore the application
|
||||||
|
- name: Restore the application
|
||||||
|
working-directory: ./Sources
|
||||||
|
run: |
|
||||||
|
msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration
|
||||||
|
|
||||||
|
# Build package and upload to github packages
|
||||||
|
- name: Build package
|
||||||
|
working-directory: ./Sources
|
||||||
|
run: |
|
||||||
|
dotnet build $env:Solution_Name --configuration $env:Configuration
|
||||||
|
dotnet pack --configuration $env:Configuration -o ./
|
||||||
|
dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET_API }} --source "nuget.org"
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -34,3 +34,4 @@ Sources/.DS_Store
|
|||||||
Sources/Stylophone.iOS/bin
|
Sources/Stylophone.iOS/bin
|
||||||
Sources/Stylophone.iOS/obj
|
Sources/Stylophone.iOS/obj
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
/Sources/MpcNET.1.0.0.nupkg
|
||||||
|
82
README.md
82
README.md
@ -1,10 +1,14 @@
|
|||||||
<img src="Sources/MpcNET/icon.png" width="128">
|
<img src="icon.png" width="128">
|
||||||
|
|
||||||
MpcNET
|
MpcNET
|
||||||
===========
|
===========
|
||||||
Pure .NET Client Library for [**Music Player Daemon**](https://www.musicpd.org/) Servers.
|
Pure .NET Client Library for [**Music Player Daemon**](https://www.musicpd.org/) Servers.
|
||||||
|
The heart and soul of [Stylophone](https://github.com/Difegue/Stylophone).
|
||||||
|
|
||||||
|
[**Nightly Packages**](https://github.com/Difegue/MpcNET/packages/) - [**Stable Versions**](https://www.nuget.org/packages/MpcNET/)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Connection
|
### Connection
|
||||||
To create a client for MPD, you must first create a `IPEndPoint` for the Server with the right IP and Port.
|
To create a client for MPD, you must first create a `IPEndPoint` for the Server with the right IP and Port.
|
||||||
````C#
|
````C#
|
||||||
@ -12,7 +16,7 @@ var mpdEndpoint = new IPEndPoint(IPAddress.Loopback, 6600);
|
|||||||
````
|
````
|
||||||
Then create a Client and Connect to MPD.
|
Then create a Client and Connect to MPD.
|
||||||
````C#
|
````C#
|
||||||
var client = new Mpc(mpdEndpoint);
|
var client = new MpcConnection(mpdEndpoint);
|
||||||
var connected = await client.ConnectAsync();
|
var connected = await client.ConnectAsync();
|
||||||
````
|
````
|
||||||
The `ConnectAsync()` method is returning a bool to indicate if the connection was successfully. However, this can be queried directly on the Client also:
|
The `ConnectAsync()` method is returning a bool to indicate if the connection was successfully. However, this can be queried directly on the Client also:
|
||||||
@ -27,6 +31,78 @@ To disconnect the Client use the follow method:
|
|||||||
````C#
|
````C#
|
||||||
await client.DisconnectAsync();
|
await client.DisconnectAsync();
|
||||||
````
|
````
|
||||||
|
or just dispose the client:
|
||||||
|
````C#
|
||||||
|
client.Dispose();
|
||||||
|
````
|
||||||
### Send Command
|
### Send Command
|
||||||
|
|
||||||
## API Content
|
````C#
|
||||||
|
using (var client = new MpcConnection(mpdEndpoint)) {
|
||||||
|
await client.ConnectAsync();
|
||||||
|
|
||||||
|
// Look in /Commands to see everything that implements IMpcCommand
|
||||||
|
var request = await client.SendAsync(new IMpcCommand<List<string>>(parameters));
|
||||||
|
|
||||||
|
if (!request.IsResponseValid) {
|
||||||
|
var mpdError = request.Response?.Result?.MpdError;
|
||||||
|
if (mpdError != null && mpdError != "")
|
||||||
|
Console.WriteLine($"Error: {mpdError}");
|
||||||
|
else
|
||||||
|
Console.WriteLine($"Invalid server response: {response}.");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
List<string> response = request.Response.Content;
|
||||||
|
// do stuff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
### Command Lists
|
||||||
|
|
||||||
|
````C#
|
||||||
|
var commandList = new CommandList();
|
||||||
|
|
||||||
|
commandList.Add(new IMpcCommand<?>(firstCommandArgument);
|
||||||
|
commandList.Add(new IMpcCommand<?>(secondCommandArgument);
|
||||||
|
commandList.Add(new IMpcCommand<?>(thirdCommandArgument);
|
||||||
|
|
||||||
|
using (var client = new MpcConnection(mpdEndpoint)) {
|
||||||
|
await client.ConnectAsync();
|
||||||
|
var request = await client.SendAsync(commandList);
|
||||||
|
|
||||||
|
// Response string contains responses of all the commands, split by commas
|
||||||
|
string response = request.Response?.Content;
|
||||||
|
}
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
### Binary Responses
|
||||||
|
|
||||||
|
````C#
|
||||||
|
// Get albumart from MPD
|
||||||
|
List<byte> data = new List<byte>();
|
||||||
|
|
||||||
|
using (var client = new MpcConnection(mpdEndpoint))
|
||||||
|
{
|
||||||
|
long totalBinarySize = 9999;
|
||||||
|
long currentSize = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var albumReq = await client.SendAsync(new AlbumArtCommand(f.Path, currentSize));
|
||||||
|
if (!albumReq.IsResponseValid) break;
|
||||||
|
|
||||||
|
var response = albumReq.Response.Content;
|
||||||
|
if (response.Binary == 0) break; // MPD isn't giving us any more data, let's roll with what we have.
|
||||||
|
|
||||||
|
totalBinarySize = response.Size;
|
||||||
|
currentSize += response.Binary;
|
||||||
|
data.AddRange(response.Data);
|
||||||
|
|
||||||
|
Debug.WriteLine($"Downloading albumart: {currentSize}/{totalBinarySize}");
|
||||||
|
} while (currentSize < totalBinarySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
@ -10,11 +10,12 @@ namespace MpcNET.Commands.Database
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MpcNET.Tags;
|
using MpcNET.Tags;
|
||||||
using MpcNET.Types;
|
using MpcNET.Types;
|
||||||
|
using MpcNET.Types.Filters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds songs in the database that contain "searchText".
|
/// Finds songs in the database that contain "searchText".
|
||||||
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
||||||
/// https://www.musicpd.org/doc/html/protocol.html#filters
|
/// https://mpd.readthedocs.io/en/stable/protocol.html#filters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SearchCommand : BaseFilterCommand
|
public class SearchCommand : BaseFilterCommand
|
||||||
{
|
{
|
||||||
@ -22,10 +23,6 @@ namespace MpcNET.Commands.Database
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override string CommandName => "search";
|
public override string CommandName => "search";
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public override string Operand => "contains";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
||||||
@ -44,12 +41,28 @@ namespace MpcNET.Commands.Database
|
|||||||
/// <param name="windowEnd">End 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) { }
|
public SearchCommand(List<KeyValuePair<ITag, string>> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">Filter</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(IFilter filter, int windowStart = -1, int windowEnd = -1) : base(filter, windowStart, windowEnd) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">List of 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<IFilter> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds songs in the database that contain "searchText" and adds them to the queue.
|
/// Finds songs in the database that contain "searchText" and adds them to the queue.
|
||||||
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
||||||
/// https://www.musicpd.org/doc/html/protocol.html#filters
|
/// https://mpd.readthedocs.io/en/stable/protocol.html#filters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SearchAddCommand : BaseFilterCommand
|
public class SearchAddCommand : BaseFilterCommand
|
||||||
{
|
{
|
||||||
@ -57,13 +70,9 @@ namespace MpcNET.Commands.Database
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override string CommandName => "searchadd";
|
public override string CommandName => "searchadd";
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public override string Operand => "contains";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
/// Initializes a new instance of the <see cref="SearchAddCommand"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tag">The tag.</param>
|
/// <param name="tag">The tag.</param>
|
||||||
/// <param name="searchText">The search text.</param>
|
/// <param name="searchText">The search text.</param>
|
||||||
@ -72,19 +81,34 @@ namespace MpcNET.Commands.Database
|
|||||||
public SearchAddCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1) : base(tag, searchText, windowStart, windowEnd) { }
|
public SearchAddCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1) : base(tag, searchText, windowStart, windowEnd) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SearchCommand"/> class.
|
/// Initializes a new instance of the <see cref="SearchAddCommand"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filters">List of key/value filters</param>
|
/// <param name="filters">List of key/value filters</param>
|
||||||
/// <param name="windowStart">Start of the portion of the results desired</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>
|
/// <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) { }
|
public SearchAddCommand(List<KeyValuePair<ITag, string>> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SearchAddCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">Filter</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(IFilter filter, int windowStart = -1, int windowEnd = -1) : base(filter, windowStart, windowEnd) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SearchAddCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">List of 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<IFilter> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds songs in the database that is exactly "searchText".
|
/// Finds songs in the database that is exactly "searchText".
|
||||||
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
/// Since MPD 0.21, search syntax is now (TAG == 'VALUE').
|
||||||
/// https://www.musicpd.org/doc/html/protocol.html#filters
|
/// https://mpd.readthedocs.io/en/stable/protocol.html#filters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FindCommand : BaseFilterCommand
|
public class FindCommand : BaseFilterCommand
|
||||||
{
|
{
|
||||||
@ -92,10 +116,6 @@ namespace MpcNET.Commands.Database
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override string CommandName => "find";
|
public override string CommandName => "find";
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public override string Operand => "==";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="FindCommand"/> class.
|
/// Initializes a new instance of the <see cref="FindCommand"/> class.
|
||||||
@ -114,15 +134,30 @@ namespace MpcNET.Commands.Database
|
|||||||
/// <param name="windowEnd">End 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) { }
|
public FindCommand(List<KeyValuePair<ITag, string>> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||||
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FindCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">Filter</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(IFilter filter, int windowStart = -1, int windowEnd = -1) : base(filter, windowStart, windowEnd) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FindCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">List of 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<IFilter> filters, int windowStart = -1, int windowEnd = -1) : base(filters, windowStart, windowEnd) { }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for find/search commands.
|
/// Base class for find/search commands.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseFilterCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
public abstract class BaseFilterCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
||||||
{
|
{
|
||||||
private readonly List<KeyValuePair<ITag, string>> filters;
|
private readonly List<IFilter> _filters;
|
||||||
private readonly int _start;
|
private readonly int _start;
|
||||||
private readonly int _end;
|
private readonly int _end;
|
||||||
|
|
||||||
@ -130,11 +165,6 @@ namespace MpcNET.Commands.Database
|
|||||||
/// Name of the command to use when deserializing
|
/// Name of the command to use when deserializing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract string CommandName { get; }
|
public abstract string CommandName { get; }
|
||||||
/// <summary>
|
|
||||||
/// Operand to use between tags and search text. Can be ==, !=, contains...
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Operand { get; }
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BaseFilterCommand"/> class.
|
/// Initializes a new instance of the <see cref="BaseFilterCommand"/> class.
|
||||||
@ -143,10 +173,12 @@ namespace MpcNET.Commands.Database
|
|||||||
/// <param name="searchText">The search text.</param>
|
/// <param name="searchText">The search text.</param>
|
||||||
/// <param name="windowStart">Start of the portion of the results desired</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>
|
/// <param name="windowEnd">End of the portion of the results desired</param>
|
||||||
public BaseFilterCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1)
|
/// <param name="operand">Operator of the filter</param>
|
||||||
|
public BaseFilterCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1, FilterOperator operand = FilterOperator.Equal)
|
||||||
{
|
{
|
||||||
this.filters = new List<KeyValuePair<ITag, string>>();
|
_filters = new List<IFilter>();
|
||||||
this.filters.Add(new KeyValuePair<ITag, string>(tag, searchText));
|
FilterTag Tag = new FilterTag(tag, searchText, operand);
|
||||||
|
_filters.Add(Tag);
|
||||||
|
|
||||||
_start = windowStart;
|
_start = windowStart;
|
||||||
_end = windowEnd;
|
_end = windowEnd;
|
||||||
@ -158,9 +190,40 @@ namespace MpcNET.Commands.Database
|
|||||||
/// <param name="filters">List of key/value filters</param>
|
/// <param name="filters">List of key/value filters</param>
|
||||||
/// <param name="windowStart">Start of the portion of the results desired</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>
|
/// <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)
|
/// <param name="operand">Operator of the filter</param>
|
||||||
|
public BaseFilterCommand(List<KeyValuePair<ITag, string>> filters, int windowStart = -1, int windowEnd = -1, FilterOperator operand = FilterOperator.Equal)
|
||||||
{
|
{
|
||||||
this.filters = filters;
|
_filters = new List<IFilter>();
|
||||||
|
_filters.AddRange(filters.Select(filter => new FilterTag(filter.Key, filter.Value, operand)).ToList());
|
||||||
|
|
||||||
|
_start = windowStart;
|
||||||
|
_end = windowEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BaseFilterCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">Filter</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(IFilter filters, int windowStart = -1, int windowEnd = -1)
|
||||||
|
{
|
||||||
|
_filters = new List<IFilter>();
|
||||||
|
_filters.Add(filters);
|
||||||
|
|
||||||
|
_start = windowStart;
|
||||||
|
_end = windowEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BaseFilterCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">List of 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<IFilter> filters, int windowStart = -1, int windowEnd = -1)
|
||||||
|
{
|
||||||
|
_filters = filters;
|
||||||
|
|
||||||
_start = windowStart;
|
_start = windowStart;
|
||||||
_end = windowEnd;
|
_end = windowEnd;
|
||||||
@ -170,16 +233,19 @@ namespace MpcNET.Commands.Database
|
|||||||
/// Serializes the command.
|
/// Serializes the command.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// The serialize command.
|
/// The serialized command.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public string Serialize()
|
public string Serialize()
|
||||||
{
|
{
|
||||||
var cmd =
|
string cmd = "";
|
||||||
CommandName + " \"(" +
|
|
||||||
string.Join(" AND ",
|
if (_filters != null)
|
||||||
filters.Select(x => $"({x.Key.Value} {Operand} {escape(x.Value)})")
|
{
|
||||||
) +
|
var serializedFilters = string.Join(" AND ",
|
||||||
")\"";
|
_filters.Select(x => $"{x.GetFormattedCommand()}")
|
||||||
|
);
|
||||||
|
cmd = $@"{CommandName} ""({serializedFilters})""";
|
||||||
|
}
|
||||||
|
|
||||||
if (_start > -1)
|
if (_start > -1)
|
||||||
{
|
{
|
||||||
@ -200,8 +266,6 @@ namespace MpcNET.Commands.Database
|
|||||||
{
|
{
|
||||||
return MpdFile.CreateList(response.ResponseValues);
|
return MpdFile.CreateList(response.ResponseValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string escape(string value) => string.Format("\\\"{0}\\\"", value.Replace("\\", "\\\\\\").Replace("'", "\\\\'").Replace("\"", "\\\\\\\""));
|
|
||||||
}
|
}
|
||||||
// TODO: rescan
|
// TODO: rescan
|
||||||
}
|
}
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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 is exactly "searchText".
|
|
||||||
/// https://www.musicpd.org/doc/protocol/database.html.
|
|
||||||
/// </summary>
|
|
||||||
public class FindCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
|
||||||
{
|
|
||||||
private readonly List<KeyValuePair<ITag, string>> filters;
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
public FindCommand(ITag tag, string searchText)
|
|
||||||
{
|
|
||||||
this.filters = new List<KeyValuePair<ITag, string>>();
|
|
||||||
this.filters.Add(new KeyValuePair<ITag, string>(tag, searchText));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="FindCommand"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filters">List of key/value filters</param>
|
|
||||||
public FindCommand(List<KeyValuePair<ITag, string>> filters)
|
|
||||||
{
|
|
||||||
this.filters = filters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Serializes the command.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>
|
|
||||||
/// The serialize command.
|
|
||||||
/// </returns>
|
|
||||||
public string Serialize() =>
|
|
||||||
string.Join(" ",
|
|
||||||
"find",
|
|
||||||
string.Join(" ",
|
|
||||||
this.filters
|
|
||||||
.Select(x => string.Join(" ",
|
|
||||||
x.Key.Value, escape(x.Value)))
|
|
||||||
.ToArray()));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the specified response text pairs.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="response">The response.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The deserialized response.
|
|
||||||
/// </returns>
|
|
||||||
public IEnumerable<IMpdFile> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return MpdFile.CreateList(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string escape(string value) => string.Format("\"{0}\"", value.Replace("\\", "\\\\").Replace("\"", "\\\""));
|
|
||||||
}
|
|
||||||
// TODO: rescan
|
|
||||||
}
|
|
64
Sources/MpcNET/Commands/Playback/ConsumeCommand.cs
Normal file
64
Sources/MpcNET/Commands/Playback/ConsumeCommand.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
// <copyright file="ConsumeCommand.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 consume state.
|
||||||
|
/// Sets consume state to STATE, STATE should be 0 or 1. When consume is activated, each song played is removed from playlist.
|
||||||
|
/// https://mpd.readthedocs.io/en/stable/protocol.html#playback-options
|
||||||
|
/// </summary>
|
||||||
|
public class ConsumeCommand : IMpcCommand<string>
|
||||||
|
{
|
||||||
|
private readonly string single;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ConsumeCommand" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="single">if set to <c>true</c> [consume].</param>
|
||||||
|
public ConsumeCommand(bool single)
|
||||||
|
{
|
||||||
|
this.single = single ? "1" : "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ConsumeCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ConsumeCommand()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serializes the command.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// The serialize command.
|
||||||
|
/// </returns>
|
||||||
|
public string Serialize()
|
||||||
|
{
|
||||||
|
if (this.single == null)
|
||||||
|
{
|
||||||
|
return string.Join(" ", "consume");
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join(" ", "consume", this.single);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
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", $"\"{this.uri}\"");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the specified response text pairs.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="response">The response.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The deserialized response.
|
|
||||||
/// </returns>
|
|
||||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return string.Join(", ", response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
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", $"\"{this.uri}\"");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the specified response text pairs.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="response">The response.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The deserialized response.
|
|
||||||
/// </returns>
|
|
||||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return string.Join(", ", response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
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(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return string.Join(", ", response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
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", this.position);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the specified response text pairs.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="response">The response.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The deserialized response.
|
|
||||||
/// </returns>
|
|
||||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return string.Join(", ", response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
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", this.songId);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the specified response text pairs.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="response">The response.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The deserialized response.
|
|
||||||
/// </returns>
|
|
||||||
public string Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return string.Join(", ", response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
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(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return string.Join(", ", response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
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(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
var results = response.Select(line => MpdFile.Create(line.Value, int.Parse(line.Key)));
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
using System.Collections.Generic;
|
|
||||||
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(" ", new[] { "playlistid" }, this.songId);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the specified response text pairs.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="response">The response.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The deserialized response.
|
|
||||||
/// </returns>
|
|
||||||
public IEnumerable<IMpdFile> Deserialize(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return MpdFile.CreateList(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <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.Playlist
|
|
||||||
{
|
|
||||||
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(IReadOnlyList<KeyValuePair<string, string>> response)
|
|
||||||
{
|
|
||||||
return MpdFile.CreateList(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
// --------------------------------------------------------------------------------------------------------------------
|
|
||||||
// <copyright file="IMpcConnectionReporter.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
|
|
||||||
{
|
|
||||||
using System;
|
|
||||||
using Sundew.Base.Reporting;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Interface for implementing an observer for <see cref="MpcConnection"/>.
|
|
||||||
/// </summary>
|
|
||||||
public interface IMpcConnectionReporter : IReporter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called when connecting.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isReconnect">if set to <c>true</c> [is reconnect].</param>
|
|
||||||
/// <param name="connectAttempt">The connect attempt.</param>
|
|
||||||
void Connecting(bool isReconnect, int connectAttempt);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when connection is accepted.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isReconnect">if set to <c>true</c> [is reconnect].</param>
|
|
||||||
/// <param name="connectAttempt">The connect attempt.</param>
|
|
||||||
void ConnectionAccepted(bool isReconnect, int connectAttempt);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when connected.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isReconnect">if set to <c>true</c> [is reconnect].</param>
|
|
||||||
/// <param name="connectAttempt">The connect attempt.</param>
|
|
||||||
/// <param name="connectionInfo">The connection information.</param>
|
|
||||||
void Connected(bool isReconnect, int connectAttempt, string connectionInfo);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when sending command.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="command">The command.</param>
|
|
||||||
void Sending(string command);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when send exception occured.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="commandText">The command text.</param>
|
|
||||||
/// <param name="sendAttempt">The send attempt.</param>
|
|
||||||
/// <param name="exception">The exception.</param>
|
|
||||||
void SendException(string commandText, int sendAttempt, Exception exception);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when send is retried.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="command">The command.</param>
|
|
||||||
/// <param name="sendAttempt">The send attempt.</param>
|
|
||||||
void RetrySend(string command, int sendAttempt);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when response is read.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="responseLine">The response line.</param>
|
|
||||||
/// <param name="commandText">The command text.</param>
|
|
||||||
void ReadResponse(string responseLine, string commandText);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when disconnecting.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isExplicitDisconnect">if set to <c>true</c> the disconnect was explicitly called.</param>
|
|
||||||
void Disconnecting(bool isExplicitDisconnect);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when disconnected.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isExplicitDisconnect">if set to <c>true</c> the disconnect was explicitly called.</param>
|
|
||||||
void Disconnected(bool isExplicitDisconnect);
|
|
||||||
}
|
|
||||||
}
|
|
@ -190,7 +190,8 @@ namespace MpcNET
|
|||||||
.RetryAsync(isReconnect ? 0 : 3)
|
.RetryAsync(isReconnect ? 0 : 3)
|
||||||
.ExecuteAndCaptureAsync(async (t) =>
|
.ExecuteAndCaptureAsync(async (t) =>
|
||||||
{
|
{
|
||||||
var client = new TcpClient();
|
var client = new TcpClient(AddressFamily.InterNetworkV6);
|
||||||
|
client.Client.DualMode = true; // Enable both IPv4 and IPv6
|
||||||
using (t.Register(() => client.Close()))
|
using (t.Register(() => client.Close()))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -13,6 +13,19 @@
|
|||||||
<AssemblyVersion>0.0.1.0</AssemblyVersion>
|
<AssemblyVersion>0.0.1.0</AssemblyVersion>
|
||||||
<FileVersion>0.0.1.0</FileVersion>
|
<FileVersion>0.0.1.0</FileVersion>
|
||||||
<Configurations>Debug;Release;Release-Stable</Configurations>
|
<Configurations>Debug;Release;Release-Stable</Configurations>
|
||||||
|
<Company>TVC-16</Company>
|
||||||
|
<Authors>Difegue</Authors>
|
||||||
|
<Description>Pure .NET Client Library for Music Player Daemon Servers.</Description>
|
||||||
|
<Copyright>2021 Difegue</Copyright>
|
||||||
|
<PackageProjectUrl>https://github.com/Difegue/MpcNET</PackageProjectUrl>
|
||||||
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<RepositoryUrl>https://github.com/Difegue/MpcNET</RepositoryUrl>
|
||||||
|
<PackageTags>mpd;client;mpcNET</PackageTags>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||||
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
@ -44,9 +57,30 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="..\..\icon.png">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath></PackagePath>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\README.md">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath></PackagePath>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MinVer" Version="2.5.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="Polly" Version="7.2.2" />
|
<PackageReference Include="Polly" Version="7.2.2" />
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="icon.png">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
25
Sources/MpcNET/Types/Filters/FilterAudioFormat.cs
Normal file
25
Sources/MpcNET/Types/Filters/FilterAudioFormat.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace MpcNET.Types.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Filter "AudioFormat"
|
||||||
|
/// </summary>
|
||||||
|
public class FilterAudioFormat : IFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FilterAudioFormat"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Operator">Operator of the filter</param>
|
||||||
|
/// <param name="Value">Value to test</param>
|
||||||
|
/// <param name="Negation">If the expression is negated</param>
|
||||||
|
public FilterAudioFormat(string Value, FilterOperator Operator, bool Negation = false) : base("AudioFormat", Operator, Value, Negation)
|
||||||
|
{
|
||||||
|
if (Operator != FilterOperator.Equal && Operator != FilterOperator.Mask)
|
||||||
|
throw new System.ArgumentException("Operator is not compatible: for \"AudioFormat\" use FilterOperator.Equal or FilterOperator.Mask.");
|
||||||
|
|
||||||
|
this.Name = "AudioFormat";
|
||||||
|
this.Value = Value;
|
||||||
|
this.Operator = Operator;
|
||||||
|
this.Negation = Negation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
Sources/MpcNET/Types/Filters/FilterBase.cs
Normal file
25
Sources/MpcNET/Types/Filters/FilterBase.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace MpcNET.Types.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Filter "base" (not the interface base class, the base command: restrict search songs to a directory)
|
||||||
|
/// </summary>
|
||||||
|
public class FilterBase : IFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FilterBase"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Operator">Operator of the filter</param>
|
||||||
|
/// <param name="Value">Value to test</param>
|
||||||
|
/// <param name="Negation">If the expression is negated</param>
|
||||||
|
public FilterBase(string Value, FilterOperator Operator, bool Negation = false) : base("base", Operator, Value, Negation)
|
||||||
|
{
|
||||||
|
if (Operator != FilterOperator.None)
|
||||||
|
throw new System.ArgumentException("Operator is not compatible: for \"base\" use FilterOperator.None.");
|
||||||
|
|
||||||
|
this.Name = "base";
|
||||||
|
this.Value = Value;
|
||||||
|
this.Operator = Operator;
|
||||||
|
this.Negation = Negation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
Sources/MpcNET/Types/Filters/FilterFile.cs
Normal file
25
Sources/MpcNET/Types/Filters/FilterFile.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace MpcNET.Types.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Filter "file"
|
||||||
|
/// </summary>
|
||||||
|
public class FilterFile : IFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FilterFile"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Operator">Operator of the filter</param>
|
||||||
|
/// <param name="Value">Value to test</param>
|
||||||
|
/// <param name="Negation">If the expression is negated</param>
|
||||||
|
public FilterFile(string Value, FilterOperator Operator, bool Negation = false) : base("file", Operator, Value, Negation)
|
||||||
|
{
|
||||||
|
if (Operator != FilterOperator.Equal)
|
||||||
|
throw new System.ArgumentException("Operator is not compatible: for \"File\" use FilterOperator.Equal.");
|
||||||
|
|
||||||
|
this.Name = "file";
|
||||||
|
this.Value = Value;
|
||||||
|
this.Operator = Operator;
|
||||||
|
this.Negation = Negation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
Sources/MpcNET/Types/Filters/FilterModifiedSince.cs
Normal file
25
Sources/MpcNET/Types/Filters/FilterModifiedSince.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace MpcNET.Types.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Filter "modified-since"
|
||||||
|
/// </summary>
|
||||||
|
public class FilterModifiedSince : IFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FilterModifiedSince"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Operator">Operator of the filter</param>
|
||||||
|
/// <param name="Value">Value to test</param>
|
||||||
|
/// <param name="Negation">If the expression is negated</param>
|
||||||
|
public FilterModifiedSince(string Value, FilterOperator Operator, bool Negation = false) : base("modified-since", Operator, Value, Negation)
|
||||||
|
{
|
||||||
|
if (Operator != FilterOperator.None)
|
||||||
|
throw new System.ArgumentException("Operator is not compatible: for \"ModifiedSince\" use FilterOperator.None.");
|
||||||
|
|
||||||
|
this.Name = "modified-since";
|
||||||
|
this.Value = Value;
|
||||||
|
this.Operator = Operator;
|
||||||
|
this.Negation = Negation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
Sources/MpcNET/Types/Filters/FilterTag.cs
Normal file
27
Sources/MpcNET/Types/Filters/FilterTag.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using MpcNET.Tags;
|
||||||
|
|
||||||
|
namespace MpcNET.Types.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Filter "TAG"
|
||||||
|
/// </summary>
|
||||||
|
public class FilterTag : IFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FilterTag"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Tag">The tag.</param>
|
||||||
|
/// <param name="Operator">Operator of the filter</param>
|
||||||
|
/// <param name="Value">Value to test</param>
|
||||||
|
/// <param name="Negation">If the expression is negated</param>
|
||||||
|
public FilterTag(ITag Tag, string Value, FilterOperator Operator, bool Negation = false) : base(Tag.Value, Operator, Value, Negation)
|
||||||
|
{
|
||||||
|
if (Operator != FilterOperator.Equal && Operator != FilterOperator.Different && Operator != FilterOperator.Contains)
|
||||||
|
throw new System.ArgumentException("Operator is not compatible: for \"TAG\" use FilterOperator.Equal, FilterOperator.Different or FilterOperator.Contains.");
|
||||||
|
|
||||||
|
this.Value = Value;
|
||||||
|
this.Operator = Operator;
|
||||||
|
this.Negation = Negation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
140
Sources/MpcNET/Types/IFilter.cs
Normal file
140
Sources/MpcNET/Types/IFilter.cs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace MpcNET.Types
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Operators available for filters in the protocol
|
||||||
|
/// </summary>
|
||||||
|
public enum FilterOperator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Equal (==)
|
||||||
|
/// </summary>
|
||||||
|
[Description("==")]
|
||||||
|
Equal,
|
||||||
|
/// <summary>
|
||||||
|
/// Different (!=)
|
||||||
|
/// </summary>
|
||||||
|
[Description("!=")]
|
||||||
|
Different,
|
||||||
|
/// <summary>
|
||||||
|
/// Contains (contains)
|
||||||
|
/// </summary>
|
||||||
|
[Description("contains")]
|
||||||
|
Contains,
|
||||||
|
/// <summary>
|
||||||
|
/// Mask (=~)
|
||||||
|
/// </summary>
|
||||||
|
[Description("=~")]
|
||||||
|
Mask,
|
||||||
|
/// <summary>
|
||||||
|
/// None ("")
|
||||||
|
/// </summary>
|
||||||
|
[Description("")]
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
public static class EnumHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="GetDescription"/> of the enum
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enumValue"></param>
|
||||||
|
public static string GetDescription<T>(this T enumValue)
|
||||||
|
where T : struct, System.IConvertible
|
||||||
|
{
|
||||||
|
if (!typeof(T).IsEnum)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
string description = enumValue.ToString();
|
||||||
|
System.Reflection.FieldInfo fieldInfo = enumValue.GetType().GetField(enumValue.ToString());
|
||||||
|
|
||||||
|
if (fieldInfo != null)
|
||||||
|
{
|
||||||
|
object[] attributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), true);
|
||||||
|
if (attributes != null && attributes.Length > 0)
|
||||||
|
description = ((DescriptionAttribute)attributes[0]).Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter interface specialized by filters in the protocol
|
||||||
|
/// </summary>
|
||||||
|
public abstract class IFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the filter
|
||||||
|
/// </summary>
|
||||||
|
public string Name;
|
||||||
|
/// <summary>
|
||||||
|
/// Operator of the filter
|
||||||
|
/// </summary>
|
||||||
|
public FilterOperator Operator;
|
||||||
|
/// <summary>
|
||||||
|
/// Value to test
|
||||||
|
/// </summary>
|
||||||
|
public string Value;
|
||||||
|
/// <summary>
|
||||||
|
/// If the expression is negated
|
||||||
|
/// </summary>
|
||||||
|
public bool Negation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="IFilter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Name">Name of the filter</param>
|
||||||
|
/// <param name="Operator">Operator of the filter</param>
|
||||||
|
/// <param name="Value">Value to test</param>
|
||||||
|
/// <param name="Negation">If the expression is negated</param>
|
||||||
|
public IFilter(string Name, FilterOperator Operator, string Value, bool Negation = false)
|
||||||
|
{
|
||||||
|
this.Name = Name;
|
||||||
|
this.Operator = Operator;
|
||||||
|
this.Value = Value;
|
||||||
|
this.Negation = Negation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// String values are quoted with single or double quotes,
|
||||||
|
/// and special characters within those values must be escaped with the backslash (\).
|
||||||
|
/// Keep in mind that the backslash is also the escape character on the protocol level,
|
||||||
|
/// which means you may need to use double backslash.
|
||||||
|
///
|
||||||
|
/// Example expression which matches an artist named foo'bar":
|
||||||
|
/// (Artist == "foo\'bar\"")
|
||||||
|
///
|
||||||
|
/// At the protocol level, the command must look like this:
|
||||||
|
/// find "(Artist == \"foo\\'bar\\\"\")"
|
||||||
|
///
|
||||||
|
/// (https://mpd.readthedocs.io/en/stable/protocol.html#filters)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value to escape</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private string escape(string value)
|
||||||
|
{
|
||||||
|
var escapedValue = value.Replace(@"\", @"\\\\")
|
||||||
|
.Replace("'", @"\\'")
|
||||||
|
.Replace(@"""", @"\\\""");
|
||||||
|
|
||||||
|
return $@"\""{escapedValue}\""";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the formatted command
|
||||||
|
/// </summary>
|
||||||
|
public string GetFormattedCommand()
|
||||||
|
{
|
||||||
|
string command = $"({Name} {Operator.GetDescription()} {escape(Value)})";
|
||||||
|
|
||||||
|
if (Negation)
|
||||||
|
return $"(!{command})";
|
||||||
|
else
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Reference in New Issue
Block a user