diff --git a/NEWS b/NEWS index b978d3bff..e40919c0b 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ ver 0.24 (not yet released) - apply Unicode normalization to case-insensitive filter expressions - stickers on playlists and some tag types - new command "stickernames" + - new "search"/"find" filter "added-since" * database - attribute "added" shows when each song was added to the database - proxy: require MPD 0.21 or later diff --git a/src/song/AddedSinceSongFilter.cxx b/src/song/AddedSinceSongFilter.cxx new file mode 100644 index 000000000..4b0639f21 --- /dev/null +++ b/src/song/AddedSinceSongFilter.cxx @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright The Music Player Daemon Project + +#include "AddedSinceSongFilter.hxx" +#include "LightSong.hxx" +#include "time/ISO8601.hxx" +#include "util/StringBuffer.hxx" + +std::string +AddedSinceSongFilter::ToExpression() const noexcept +{ + return std::string("(added-since \"") + FormatISO8601(value).c_str() + "\")"; +} + +bool +AddedSinceSongFilter::Match(const LightSong &song) const noexcept +{ + return song.added >= value; +} diff --git a/src/song/AddedSinceSongFilter.hxx b/src/song/AddedSinceSongFilter.hxx new file mode 100644 index 000000000..c325e0e77 --- /dev/null +++ b/src/song/AddedSinceSongFilter.hxx @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright The Music Player Daemon Project + +#ifndef MPD_ADDED_SINCE_SONG_FILTER_HXX +#define MPD_ADDED_SINCE_SONG_FILTER_HXX + +#include "ISongFilter.hxx" + +#include + +class AddedSinceSongFilter final : public ISongFilter { + std::chrono::system_clock::time_point value; + +public: + explicit AddedSinceSongFilter(std::chrono::system_clock::time_point _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; +}; + +#endif diff --git a/src/song/Filter.cxx b/src/song/Filter.cxx index 29ef2beec..047389da9 100644 --- a/src/song/Filter.cxx +++ b/src/song/Filter.cxx @@ -8,6 +8,7 @@ #include "BaseSongFilter.hxx" #include "TagSongFilter.hxx" #include "ModifiedSinceSongFilter.hxx" +#include "AddedSinceSongFilter.hxx" #include "AudioFormatSongFilter.hxx" #include "PrioritySongFilter.hxx" #include "pcm/AudioParser.hxx" @@ -40,6 +41,7 @@ enum { LOCATE_TAG_PRIORITY, LOCATE_TAG_FILE_TYPE, LOCATE_TAG_ANY_TYPE, + LOCATE_TAG_ADDED_SINCE, }; /** @@ -62,6 +64,9 @@ locate_parse_type(const char *str) noexcept if (strcmp(str, "modified-since") == 0) return LOCATE_TAG_MODIFIED_SINCE; + if (strcmp(str, "added-since") == 0) + return LOCATE_TAG_ADDED_SINCE; + if (StringEqualsCaseASCII(str, "AudioFormat")) return LOCATE_TAG_AUDIO_FORMAT; @@ -322,6 +327,12 @@ SongFilter::ParseExpression(const char *&s, bool fold_case) throw std::runtime_error("')' expected"); s = StripLeft(s + 1); return std::make_unique(ParseTimeStamp(value_s.c_str())); + } else if (type == LOCATE_TAG_ADDED_SINCE) { + const auto value_s = ExpectQuoted(s); + if (*s != ')') + throw std::runtime_error("')' expected"); + s = StripLeft(s + 1); + return std::make_unique(ParseTimeStamp(value_s.c_str())); } else if (type == LOCATE_TAG_BASE_TYPE) { auto value = ExpectQuoted(s); if (*s != ')') @@ -406,6 +417,10 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) case LOCATE_TAG_MODIFIED_SINCE: and_filter.AddItem(std::make_unique(ParseTimeStamp(value))); break; + + case LOCATE_TAG_ADDED_SINCE: + and_filter.AddItem(std::make_unique(ParseTimeStamp(value))); + break; case LOCATE_TAG_FILE_TYPE: /* for compatibility with MPD 0.20 and older, diff --git a/src/song/meson.build b/src/song/meson.build index bb1ed3283..1f6863dca 100644 --- a/src/song/meson.build +++ b/src/song/meson.build @@ -7,6 +7,7 @@ song = static_library( 'BaseSongFilter.cxx', 'TagSongFilter.cxx', 'ModifiedSinceSongFilter.cxx', + 'AddedSinceSongFilter.cxx', 'PrioritySongFilter.cxx', 'AudioFormatSongFilter.cxx', 'AndSongFilter.cxx',