From 2aed7378ccc9b9abd9efae3417e15c44478e6556 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 14 Mar 2022 17:44:39 +0100 Subject: [PATCH] TagAny: support CUE tracks Closes https://github.com/MusicPlayerDaemon/MPD/issues/1482 --- NEWS | 1 + src/TagAny.cxx | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/NEWS b/NEWS index cdc114954..d1276ce49 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ ver 0.23.6 (not yet released) * protocol - support filename "cover.webp" for "albumart" command + - support "readcomments" and "readpicture" on CUE tracks * decoder - ffmpeg: fix end-of-file check (update stuck at empty files) - opus: fix "readpicture" on Opus files diff --git a/src/TagAny.cxx b/src/TagAny.cxx index 6f875846e..2fd573fae 100644 --- a/src/TagAny.cxx +++ b/src/TagAny.cxx @@ -21,12 +21,16 @@ #include "TagStream.hxx" #include "TagFile.hxx" #include "tag/Generic.hxx" +#include "song/LightSong.hxx" +#include "db/Interface.hxx" #include "storage/StorageInterface.hxx" #include "client/Client.hxx" #include "protocol/Ack.hxx" #include "fs/AllocatedPath.hxx" #include "input/InputStream.hxx" #include "util/Compiler.h" +#include "util/ScopeExit.hxx" +#include "util/StringCompare.hxx" #include "util/UriExtract.hxx" #include "LocateUri.hxx" @@ -51,10 +55,67 @@ TagScanFile(const Path path_fs, TagHandler &handler) ScanGenericTags(path_fs, handler); } +#ifdef ENABLE_DATABASE + +/** + * Collapse "../" prefixes in a URI relative to the specified base + * URI. + */ +static std::string +ResolveUri(std::string_view base, const char *relative) +{ + while (true) { + const char *rest = StringAfterPrefix(relative, "../"); + if (rest == nullptr) + break; + + if (base == ".") + throw ProtocolError(ACK_ERROR_NO_EXIST, "Bad real URI"); + + base = PathTraitsUTF8::GetParent(base); + relative = rest; + } + + return PathTraitsUTF8::Build(base, relative); +} + +/** + * Look up the specified song in the database and return its + * (resolved) "real" URI. + */ +static std::string +GetRealSongUri(Client &client, std::string_view uri) +{ + const auto &db = client.GetDatabaseOrThrow(); + + const auto *song = db.GetSong(uri); + if (song == nullptr) + throw ProtocolError(ACK_ERROR_NO_EXIST, "No such song"); + + AtScopeExit(&db, song) { db.ReturnSong(song); }; + + if (song->real_uri == nullptr) + return {}; + + return ResolveUri(PathTraitsUTF8::GetParent(uri), song->real_uri); +} + +#endif + static void TagScanDatabase(Client &client, const char *uri, TagHandler &handler) { #ifdef ENABLE_DATABASE + const auto real_uri = GetRealSongUri(client, uri); + + if (!real_uri.empty()) { + uri = real_uri.c_str(); + + // TODO: support absolute paths? + if (uri_has_scheme(uri)) + return TagScanStream(uri, handler); + } + const Storage *storage = client.GetStorage(); if (storage == nullptr) { #else