From 2172aaf1ce2a1004c262742d53e1b98adfa72745 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 14 Feb 2022 13:35:08 +0100 Subject: [PATCH] song/PrioritySongFilter: new filter Closes https://github.com/MusicPlayerDaemon/MPD/issues/1412 --- NEWS | 1 + doc/protocol.rst | 3 +++ src/queue/Queue.cxx | 1 + src/song/Filter.cxx | 26 ++++++++++++++++++++++ src/song/LightSong.hxx | 5 +++++ src/song/PrioritySongFilter.cxx | 37 +++++++++++++++++++++++++++++++ src/song/PrioritySongFilter.hxx | 39 +++++++++++++++++++++++++++++++++ src/song/meson.build | 2 ++ 8 files changed, 114 insertions(+) create mode 100644 src/song/PrioritySongFilter.cxx create mode 100644 src/song/PrioritySongFilter.hxx diff --git a/NEWS b/NEWS index ca663fa23..9b36b4573 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ ver 0.24 (not yet released) * protocol - "playlistfind"/"playlistsearch" have "sort" and "window" parameters + - filter "prio" (for "playlistfind"/"playlistsearch") * player - add option "mixramp_analyzer" to scan MixRamp tags on-the-fly * tags diff --git a/doc/protocol.rst b/doc/protocol.rst index 53702a7b1..009a0a4da 100644 --- a/doc/protocol.rst +++ b/doc/protocol.rst @@ -220,6 +220,9 @@ of: matches the audio format with the given mask (i.e. one or more attributes may be ``*``). +- ``(priority >= 42)``: + compares the priority of queued songs. + - ``(!EXPRESSION)``: negate an expression. Note that each expression must be enclosed in parentheses, e.g. :code:`(!(artist == 'VALUE'))` (which is equivalent to :code:`(artist != 'VALUE')`) diff --git a/src/queue/Queue.cxx b/src/queue/Queue.cxx index 719732cc3..72c515bce 100644 --- a/src/queue/Queue.cxx +++ b/src/queue/Queue.cxx @@ -45,6 +45,7 @@ Queue::GetLight(unsigned position) const noexcept assert(position < length); LightSong song{Get(position)}; + song.priority = GetPriorityAtPosition(position); return song; } diff --git a/src/song/Filter.cxx b/src/song/Filter.cxx index f767491cb..8720d34f5 100644 --- a/src/song/Filter.cxx +++ b/src/song/Filter.cxx @@ -25,6 +25,7 @@ #include "TagSongFilter.hxx" #include "ModifiedSinceSongFilter.hxx" #include "AudioFormatSongFilter.hxx" +#include "PrioritySongFilter.hxx" #include "pcm/AudioParser.hxx" #include "tag/ParseName.hxx" #include "time/ISO8601.hxx" @@ -53,6 +54,7 @@ enum { LOCATE_TAG_MODIFIED_SINCE, LOCATE_TAG_AUDIO_FORMAT, + LOCATE_TAG_PRIORITY, LOCATE_TAG_FILE_TYPE, LOCATE_TAG_ANY_TYPE, }; @@ -80,6 +82,9 @@ locate_parse_type(const char *str) noexcept if (StringEqualsCaseASCII(str, "AudioFormat")) return LOCATE_TAG_AUDIO_FORMAT; + if (StringEqualsCaseASCII(str, "prio")) + return LOCATE_TAG_PRIORITY; + return tag_name_parse_i(str); } @@ -322,6 +327,27 @@ SongFilter::ParseExpression(const char *&s, bool fold_case) s = StripLeft(s + 1); return std::make_unique(value); + } else if (type == LOCATE_TAG_PRIORITY) { + if (s[0] == '>' && s[1] == '=') { + // TODO support more operators + } else + throw std::runtime_error("'>=' expected"); + + s = StripLeft(s + 2); + + char *endptr; + const auto value = strtoul(s, &endptr, 10); + if (endptr == s) + throw std::runtime_error("Number expected"); + + if (value > 0xff) + throw std::runtime_error("Invalid priority value"); + + if (*endptr != ')') + throw std::runtime_error("')' expected"); + s = StripLeft(endptr + 1); + + return std::make_unique(value); } else { auto string_filter = ParseStringFilter(s, fold_case); if (*s != ')') diff --git a/src/song/LightSong.hxx b/src/song/LightSong.hxx index 3d004d855..e3459c764 100644 --- a/src/song/LightSong.hxx +++ b/src/song/LightSong.hxx @@ -84,6 +84,11 @@ struct LightSong { */ AudioFormat audio_format = AudioFormat::Undefined(); + /** + * Copy of Queue::Item::priority. + */ + uint8_t priority = 0; + LightSong(const char *_uri, const Tag &_tag) noexcept :uri(_uri), tag(_tag) {} diff --git a/src/song/PrioritySongFilter.cxx b/src/song/PrioritySongFilter.cxx new file mode 100644 index 000000000..971ca8c82 --- /dev/null +++ b/src/song/PrioritySongFilter.cxx @@ -0,0 +1,37 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "PrioritySongFilter.hxx" +#include "LightSong.hxx" +#include "time/ISO8601.hxx" +#include "util/StringBuffer.hxx" + +#include + +std::string +PrioritySongFilter::ToExpression() const noexcept +{ + return fmt::format(FMT_STRING("(prio >= {})"), value); +} + +bool +PrioritySongFilter::Match(const LightSong &song) const noexcept +{ + return song.priority >= value; +} diff --git a/src/song/PrioritySongFilter.hxx b/src/song/PrioritySongFilter.hxx new file mode 100644 index 000000000..e425540ed --- /dev/null +++ b/src/song/PrioritySongFilter.hxx @@ -0,0 +1,39 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include "ISongFilter.hxx" + +#include + +class PrioritySongFilter final : public ISongFilter { + const uint8_t value; + +public: + explicit PrioritySongFilter(uint8_t _value) noexcept + :value(_value) {} + + ISongFilterPtr Clone() const noexcept override { + return std::make_unique(*this); + } + + std::string ToExpression() const noexcept override; + bool Match(const LightSong &song) const noexcept override; +}; diff --git a/src/song/meson.build b/src/song/meson.build index d8b443656..bb1ed3283 100644 --- a/src/song/meson.build +++ b/src/song/meson.build @@ -7,6 +7,7 @@ song = static_library( 'BaseSongFilter.cxx', 'TagSongFilter.cxx', 'ModifiedSinceSongFilter.cxx', + 'PrioritySongFilter.cxx', 'AudioFormatSongFilter.cxx', 'AndSongFilter.cxx', 'OptimizeFilter.cxx', @@ -15,6 +16,7 @@ song = static_library( include_directories: inc, dependencies: [ pcre_dep, + fmt_dep, ], )