From d1314ddf0da38f1aec613dac24f29eb315f49776 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 9 May 2025 13:25:17 +0200 Subject: [PATCH] Centralized artwork lookup logic for playlists --- .../services/artwork/impl/ArtworkService.cpp | 20 +++++++++++++ .../services/artwork/impl/ArtworkService.hpp | 1 + .../services/artwork/IArtworkService.hpp | 2 ++ .../subsonic/impl/endpoints/Playlists.cpp | 6 ++-- src/libs/subsonic/impl/responses/Playlist.cpp | 30 +++++++++++-------- src/libs/subsonic/impl/responses/Playlist.hpp | 7 +++-- 6 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/libs/services/artwork/impl/ArtworkService.cpp b/src/libs/services/artwork/impl/ArtworkService.cpp index 5d34e9d2..a65a19f6 100644 --- a/src/libs/services/artwork/impl/ArtworkService.cpp +++ b/src/libs/services/artwork/impl/ArtworkService.cpp @@ -260,6 +260,26 @@ namespace lms::cover return res; } + ArtworkService::ImageFindResult ArtworkService::findTrackListImage(db::TrackListId trackListId) + { + db::Session& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; + + ImageFindResult res; + + db::TrackEmbeddedImage::FindParameters params; + params.setTrackList(trackListId); + params.setIsPreferred(true); + params.setSortMethod(db::TrackEmbeddedImageSortMethod::FrontCoverAndSize); + params.setRange(db::Range{ .offset = 0, .size = 1 }); + + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { + res = image->getId(); + }); + + return res; + } + std::shared_ptr ArtworkService::getImage(db::ImageId imageId, std::optional width) { const ImageCache::EntryDesc cacheEntryDesc{ imageId, width }; diff --git a/src/libs/services/artwork/impl/ArtworkService.hpp b/src/libs/services/artwork/impl/ArtworkService.hpp index 91b80177..e1b77906 100644 --- a/src/libs/services/artwork/impl/ArtworkService.hpp +++ b/src/libs/services/artwork/impl/ArtworkService.hpp @@ -50,6 +50,7 @@ namespace lms::cover ImageFindResult findArtistImage(db::ArtistId artistId) override; ImageFindResult findPreferredTrackImage(db::TrackId trackId) override; ImageFindResult findReleaseImage(db::ReleaseId releaseId) override; + ImageFindResult findTrackListImage(db::TrackListId trackListId) override; std::shared_ptr getImage(db::ImageId imageId, std::optional width) override; std::shared_ptr getTrackEmbeddedImage(db::TrackEmbeddedImageId trackEmbeddedImageId, std::optional width) override; diff --git a/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp b/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp index d9dbb161..259474bc 100644 --- a/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp +++ b/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp @@ -29,6 +29,7 @@ #include "database/ReleaseId.hpp" #include "database/TrackEmbeddedImageId.hpp" #include "database/TrackId.hpp" +#include "database/TrackListId.hpp" #include "image/IEncodedImage.hpp" namespace lms::db @@ -48,6 +49,7 @@ namespace lms::cover virtual ImageFindResult findArtistImage(db::ArtistId artistId) = 0; virtual ImageFindResult findPreferredTrackImage(db::TrackId trackId) = 0; virtual ImageFindResult findReleaseImage(db::ReleaseId releaseId) = 0; + virtual ImageFindResult findTrackListImage(db::TrackListId trackListId) = 0; // Image retrieval virtual std::shared_ptr getImage(db::ImageId imageId, std::optional width) = 0; diff --git a/src/libs/subsonic/impl/endpoints/Playlists.cpp b/src/libs/subsonic/impl/endpoints/Playlists.cpp index 5224b988..a3d2e4bb 100644 --- a/src/libs/subsonic/impl/endpoints/Playlists.cpp +++ b/src/libs/subsonic/impl/endpoints/Playlists.cpp @@ -59,7 +59,7 @@ namespace lms::api::subsonic Response::Node& playlistsNode{ response.createNode("playlists") }; auto addTrackList{ [&](const db::TrackList::pointer& trackList) { - playlistsNode.addArrayChild("playlist", createPlaylistNode(trackList, context.dbSession)); + playlistsNode.addArrayChild("playlist", createPlaylistNode(context, trackList)); } }; // First add user's playlists @@ -104,7 +104,7 @@ namespace lms::api::subsonic throw RequestedDataNotFoundError{}; Response response{ Response::createOkResponse(context.serverProtocolVersion) }; - Response::Node playlistNode{ createPlaylistNode(trackList, context.dbSession) }; + Response::Node playlistNode{ createPlaylistNode(context, trackList) }; auto entries{ trackList->getEntries() }; for (const TrackListEntry::pointer& entry : entries.results) @@ -157,7 +157,7 @@ namespace lms::api::subsonic } Response response{ Response::createOkResponse(context.serverProtocolVersion) }; - Response::Node playlistNode{ createPlaylistNode(trackList, context.dbSession) }; + Response::Node playlistNode{ createPlaylistNode(context, trackList) }; auto entries{ trackList->getEntries() }; for (const TrackListEntry::pointer& entry : entries.results) diff --git a/src/libs/subsonic/impl/responses/Playlist.cpp b/src/libs/subsonic/impl/responses/Playlist.cpp index e6a01ff4..4b5e54cb 100644 --- a/src/libs/subsonic/impl/responses/Playlist.cpp +++ b/src/libs/subsonic/impl/responses/Playlist.cpp @@ -19,17 +19,20 @@ #include "Playlist.hpp" +#include "core/Service.hpp" #include "core/String.hpp" -#include "database/TrackEmbeddedImage.hpp" +#include "database/Image.hpp" #include "database/TrackList.hpp" #include "database/User.hpp" +#include "services/artwork/IArtworkService.hpp" #include "CoverArtId.hpp" +#include "RequestContext.hpp" #include "SubsonicId.hpp" namespace lms::api::subsonic { - Response::Node createPlaylistNode(const db::TrackList::pointer& tracklist, db::Session& session) + Response::Node createPlaylistNode(RequestContext& context, const db::TrackList::pointer& tracklist) { Response::Node playlistNode; @@ -43,16 +46,19 @@ namespace lms::api::subsonic if (const db::User::pointer user{ tracklist->getUser() }) playlistNode.setAttribute("owner", user->getLoginName()); - db::TrackEmbeddedImage::FindParameters params; - params.setTrackList(tracklist->getId()); - params.setIsPreferred(true); - params.setSortMethod(db::TrackEmbeddedImageSortMethod::FrontCoverAndSize); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - - db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { - const CoverArtId coverArtId{ image->getId() }; - playlistNode.setAttribute("coverArt", idToString(coverArtId)); - }); + { + const auto imageResult{ core::Service::get()->findTrackListImage(tracklist->getId()) }; + if (const db::ImageId * imageId{ std::get_if(&imageResult) }) + { + if (const db::Image::pointer image{ db::Image::find(context.dbSession, *imageId) }) + { + const CoverArtId coverArtId{ *imageId, image->getLastWriteTime().toTime_t() }; + playlistNode.setAttribute("coverArt", idToString(coverArtId)); + } + } + else if (const db::TrackEmbeddedImageId * embeddedImageId{ std::get_if(&imageResult) }) + playlistNode.setAttribute("coverArt", idToString(*embeddedImageId)); + } return playlistNode; } diff --git a/src/libs/subsonic/impl/responses/Playlist.hpp b/src/libs/subsonic/impl/responses/Playlist.hpp index 07246674..6c6c8e00 100644 --- a/src/libs/subsonic/impl/responses/Playlist.hpp +++ b/src/libs/subsonic/impl/responses/Playlist.hpp @@ -26,10 +26,11 @@ namespace lms::db { class TrackList; - class Session; } // namespace lms::db namespace lms::api::subsonic { - Response::Node createPlaylistNode(const db::ObjectPtr& tracklist, db::Session& session); -} \ No newline at end of file + struct RequestContext; + + Response::Node createPlaylistNode(RequestContext& context, const db::ObjectPtr& tracklist); +} // namespace lms::api::subsonic \ No newline at end of file