diff --git a/doc/protocol.xml b/doc/protocol.xml index 480fbf90a..16f6b0683 100644 --- a/doc/protocol.xml +++ b/doc/protocol.xml @@ -1702,7 +1702,8 @@ OK "ArtistSort", "AlbumSort" or "AlbumArtistSort" instead. These will automatically fall back to the former if "*Sort" doesn't exist. "AlbumArtist" falls back to just - "Artist". + "Artist". The type "Last-Modified" can sort by file + modification time. diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx index b18d7a184..1dfffeeab 100644 --- a/src/SongFilter.hxx +++ b/src/SongFilter.hxx @@ -35,6 +35,11 @@ #define LOCATE_TAG_BASE_TYPE (TAG_NUM_OF_ITEM_TYPES + 1) #define LOCATE_TAG_MODIFIED_SINCE (TAG_NUM_OF_ITEM_TYPES + 2) +/** + * Special value for the db_selection_print() sort parameter. + */ +#define SORT_TAG_LAST_MODIFIED (TAG_NUM_OF_ITEM_TYPES + 3) + #define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10 #define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20 diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx index a6e56dfc6..9ab41958b 100644 --- a/src/command/DatabaseCommands.cxx +++ b/src/command/DatabaseCommands.cxx @@ -55,6 +55,19 @@ handle_lsinfo2(Client &client, const char *uri, Response &r) return CommandResult::OK; } +static TagType +ParseSortTag(const char *s) +{ + if (StringIsEqualIgnoreCase(s, "Last-Modified")) + return TagType(SORT_TAG_LAST_MODIFIED); + + TagType tag = tag_name_parse_i(s); + if (tag == TAG_NUM_OF_ITEM_TYPES) + throw ProtocolError(ACK_ERROR_ARG, "Unknown sort tag"); + + return tag; +} + static CommandResult handle_match(Client &client, Request args, Response &r, bool fold_case) { @@ -76,9 +89,7 @@ handle_match(Client &client, Request args, Response &r, bool fold_case) ++s; } - sort = tag_name_parse_i(s); - if (sort == TAG_NUM_OF_ITEM_TYPES) - throw ProtocolError(ACK_ERROR_ARG, "Unknown sort tag"); + sort = ParseSortTag(s); args.pop_back(); args.pop_back(); diff --git a/src/db/DatabasePrint.cxx b/src/db/DatabasePrint.cxx index a8f32aeb1..45ad05d68 100644 --- a/src/db/DatabasePrint.cxx +++ b/src/db/DatabasePrint.cxx @@ -220,13 +220,21 @@ db_selection_print(Response &r, Partition &partition, db.Visit(selection, d, collect_songs, p); } - std::stable_sort(songs.begin(), songs.end(), - [sort, descending](const DetachedSong &a, - const DetachedSong &b){ - return CompareTags(sort, descending, - a.GetTag(), - b.GetTag()); - }); + if (sort == TagType(SORT_TAG_LAST_MODIFIED)) + std::stable_sort(songs.begin(), songs.end(), + [descending](const DetachedSong &a, const DetachedSong &b){ + return descending + ? a.GetLastModified() > b.GetLastModified() + : a.GetLastModified() < b.GetLastModified(); + }); + else + std::stable_sort(songs.begin(), songs.end(), + [sort, descending](const DetachedSong &a, + const DetachedSong &b){ + return CompareTags(sort, descending, + a.GetTag(), + b.GetTag()); + }); if (window_end < songs.size()) songs.erase(std::next(songs.begin(), window_end), diff --git a/src/db/DatabasePrint.hxx b/src/db/DatabasePrint.hxx index 7612b9319..7026308b7 100644 --- a/src/db/DatabasePrint.hxx +++ b/src/db/DatabasePrint.hxx @@ -38,6 +38,10 @@ db_selection_print(Response &r, Partition &partition, const DatabaseSelection &selection, bool full, bool base); +/** + * @param sort the sort tag; TAG_NUM_OF_ITEM_TYPES means don't sort; + * LOCATE_TAG_MODIFIED_SINCE means sort by file modification time + */ void db_selection_print(Response &r, Partition &partition, const DatabaseSelection &selection,