mirror of
https://github.com/ZetaKebab/MpcNET.git
synced 2025-01-14 22:18:43 +00:00
Filters: organization, typos, remove old tag handling
This commit is contained in:
parent
b732457a34
commit
316cfb0a31
@ -7,248 +7,15 @@
|
|||||||
namespace MpcNET.Commands.Database
|
namespace MpcNET.Commands.Database
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MpcNET.Tags;
|
using MpcNET.Tags;
|
||||||
using MpcNET.Types;
|
using MpcNET.Types;
|
||||||
|
using MpcNET.Types.Filters;
|
||||||
/// <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>
|
|
||||||
/// Gets the formatted command
|
|
||||||
/// </summary>
|
|
||||||
public string GetFormattedCommand()
|
|
||||||
{
|
|
||||||
string make = "";
|
|
||||||
|
|
||||||
if (Negation)
|
|
||||||
make += "(!";
|
|
||||||
|
|
||||||
make += "(" + Name + " ";
|
|
||||||
make += Operator.GetDescription();
|
|
||||||
make += " " + "\\\"" + Value + "\\\"" + ")";
|
|
||||||
|
|
||||||
if (Negation)
|
|
||||||
make += ")";
|
|
||||||
|
|
||||||
return make;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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
|
||||||
{
|
{
|
||||||
@ -256,16 +23,12 @@ 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.
|
||||||
/// </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>
|
||||||
/// <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 SearchCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1) : base(tag, searchText, windowStart, windowEnd) { }
|
public SearchCommand(ITag tag, string searchText, int windowStart = -1, int windowEnd = -1) : base(tag, searchText, windowStart, windowEnd) { }
|
||||||
@ -299,7 +62,7 @@ namespace MpcNET.Commands.Database
|
|||||||
/// <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
|
||||||
{
|
{
|
||||||
@ -307,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>
|
||||||
@ -322,7 +81,7 @@ 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>
|
||||||
@ -330,7 +89,7 @@ namespace MpcNET.Commands.Database
|
|||||||
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>
|
/// <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="filter">Filter</param>
|
/// <param name="filter">Filter</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>
|
||||||
@ -338,7 +97,7 @@ namespace MpcNET.Commands.Database
|
|||||||
public SearchAddCommand(IFilter filter, int windowStart = -1, int windowEnd = -1) : base(filter, windowStart, windowEnd) { }
|
public SearchAddCommand(IFilter filter, int windowStart = -1, int windowEnd = -1) : base(filter, 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 filters</param>
|
/// <param name="filters">List of 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>
|
||||||
@ -349,7 +108,7 @@ namespace MpcNET.Commands.Database
|
|||||||
/// <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
|
||||||
{
|
{
|
||||||
@ -357,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.
|
||||||
@ -402,8 +157,7 @@ namespace MpcNET.Commands.Database
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseFilterCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
public abstract class BaseFilterCommand : IMpcCommand<IEnumerable<IMpdFile>>
|
||||||
{
|
{
|
||||||
private readonly List<KeyValuePair<ITag, string>> tagFilters;
|
private readonly List<IFilter> _filters;
|
||||||
private readonly List<IFilter> completeFilters;
|
|
||||||
private readonly int _start;
|
private readonly int _start;
|
||||||
private readonly int _end;
|
private readonly int _end;
|
||||||
|
|
||||||
@ -411,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.
|
||||||
@ -424,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)
|
||||||
{
|
{
|
||||||
tagFilters = new List<KeyValuePair<ITag, string>>();
|
_filters = new List<IFilter>();
|
||||||
tagFilters.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;
|
||||||
@ -439,9 +190,11 @@ 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)
|
||||||
{
|
{
|
||||||
tagFilters = filters;
|
_filters = new List<IFilter>();
|
||||||
|
_filters.AddRange(filters.Select(filter => new FilterTag(filter.Key, filter.Value, operand)).ToList());
|
||||||
|
|
||||||
_start = windowStart;
|
_start = windowStart;
|
||||||
_end = windowEnd;
|
_end = windowEnd;
|
||||||
@ -455,8 +208,8 @@ 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 BaseFilterCommand(IFilter filters, int windowStart = -1, int windowEnd = -1)
|
public BaseFilterCommand(IFilter filters, int windowStart = -1, int windowEnd = -1)
|
||||||
{
|
{
|
||||||
completeFilters = new List<IFilter>();
|
_filters = new List<IFilter>();
|
||||||
completeFilters.Add(filters);
|
_filters.Add(filters);
|
||||||
|
|
||||||
_start = windowStart;
|
_start = windowStart;
|
||||||
_end = windowEnd;
|
_end = windowEnd;
|
||||||
@ -470,7 +223,7 @@ 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 BaseFilterCommand(List<IFilter> filters, int windowStart = -1, int windowEnd = -1)
|
public BaseFilterCommand(List<IFilter> filters, int windowStart = -1, int windowEnd = -1)
|
||||||
{
|
{
|
||||||
completeFilters = filters;
|
_filters = filters;
|
||||||
|
|
||||||
_start = windowStart;
|
_start = windowStart;
|
||||||
_end = windowEnd;
|
_end = windowEnd;
|
||||||
@ -486,18 +239,10 @@ namespace MpcNET.Commands.Database
|
|||||||
{
|
{
|
||||||
string cmd = "";
|
string cmd = "";
|
||||||
|
|
||||||
if (tagFilters != null)
|
if (_filters != null)
|
||||||
{
|
{
|
||||||
var serializedFilters = string.Join(" AND ",
|
var serializedFilters = string.Join(" AND ",
|
||||||
tagFilters.Select(x => $"({x.Key.Value} {Operand} {escape(x.Value)})")
|
_filters.Select(x => $"{x.GetFormattedCommand()}")
|
||||||
);
|
|
||||||
cmd = $@"{CommandName} ""({serializedFilters})""";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (completeFilters != null)
|
|
||||||
{
|
|
||||||
var serializedFilters = string.Join(" AND ",
|
|
||||||
completeFilters.Select(x => $"{x.GetFormattedCommand()}")
|
|
||||||
);
|
);
|
||||||
cmd = $@"{CommandName} ""({serializedFilters})""";
|
cmd = $@"{CommandName} ""({serializedFilters})""";
|
||||||
}
|
}
|
||||||
@ -521,31 +266,6 @@ namespace MpcNET.Commands.Database
|
|||||||
{
|
{
|
||||||
return MpdFile.CreateList(response.ResponseValues);
|
return MpdFile.CreateList(response.ResponseValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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#filter-syntax)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">Value to escape</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private string escape(string value)
|
|
||||||
{
|
|
||||||
var escapedValue = value.Replace(@"\", @"\\\\")
|
|
||||||
.Replace("'", @"\\'")
|
|
||||||
.Replace(@"""", @"\\\""");
|
|
||||||
|
|
||||||
return $@"\""{escapedValue}\""";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// TODO: rescan
|
// TODO: rescan
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
Sources/MpcNET/Types/IFilter.cs
Normal file
135
Sources/MpcNET/Types/IFilter.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
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>
|
||||||
|
/// Gets the formatted command
|
||||||
|
///
|
||||||
|
/// 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>
|
||||||
|
public string GetFormattedCommand()
|
||||||
|
{
|
||||||
|
string make = "";
|
||||||
|
|
||||||
|
if (Negation)
|
||||||
|
make += "(!";
|
||||||
|
|
||||||
|
make += "(" + Name + " ";
|
||||||
|
make += Operator.GetDescription();
|
||||||
|
make += " " + "\\\"" + Value + "\\\"" + ")";
|
||||||
|
|
||||||
|
if (Negation)
|
||||||
|
make += ")";
|
||||||
|
|
||||||
|
return make;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user