diff --git a/NEWS b/NEWS index fa66df85a..53d81eeed 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ ver 0.21.2 (not yet released) * protocol - operator "=~" matches a regular expression + - operator "contains" matches substrings * decoder - ffmpeg: require FFmpeg 3.1 or later - ffmpeg: fix broken sound with certain codecs diff --git a/doc/protocol.rst b/doc/protocol.rst index 4818b55fb..e0d750f29 100644 --- a/doc/protocol.rst +++ b/doc/protocol.rst @@ -154,6 +154,9 @@ of: ``AlbumArtist`` does not exist. ``VALUE`` is what to find. +- ``(TAG contains 'VALUE')`` checks if the given value is a substring + of the tag value. + - ``(TAG =~ 'VALUE')`` and ``(TAG !~ 'VALUE')`` use a Perl-compatible regular expression instead of doing a simple string comparison. (This feature is only available if :program:`MPD` was compiled with diff --git a/src/song/Filter.cxx b/src/song/Filter.cxx index 2c47ebb59..0725083a6 100644 --- a/src/song/Filter.cxx +++ b/src/song/Filter.cxx @@ -206,6 +206,20 @@ ExpectQuoted(const char *&s) static StringFilter ParseStringFilter(const char *&s, bool fold_case) { + if (auto after_contains = StringAfterPrefixIgnoreCase(s, "contains ")) { + s = StripLeft(after_contains); + auto value = ExpectQuoted(s); + return StringFilter(std::move(value), + fold_case, true, false); + } + + if (auto after_not_contains = StringAfterPrefixIgnoreCase(s, "!contains ")) { + s = StripLeft(after_not_contains); + auto value = ExpectQuoted(s); + return StringFilter(std::move(value), + fold_case, true, true); + } + bool negated = false; #ifdef HAVE_PCRE diff --git a/src/song/StringFilter.hxx b/src/song/StringFilter.hxx index 0c7c3f5e8..b01a419a5 100644 --- a/src/song/StringFilter.hxx +++ b/src/song/StringFilter.hxx @@ -96,7 +96,9 @@ public: const char *GetOperator() const noexcept { return IsRegex() ? (negated ? "!~" : "=~") - : (negated ? "!=" : "=="); + : (substring + ? (negated ? "!contains" : "contains") + : (negated ? "!=" : "==")); } gcc_pure