Subsonic API: added timestamps into coverart ids, Made use of image ids to save a lookup, ref #558

This commit is contained in:
emeric
2024-12-08 15:48:52 +01:00
parent 38efdfaf87
commit 4a8754a7fa
18 changed files with 253 additions and 179 deletions
@@ -192,6 +192,31 @@ namespace lms::cover
return image;
}
std::shared_ptr<image::IEncodedImage> ArtworkService::getImage(db::ImageId imageId, std::optional<image::ImageSize> width)
{
const ImageCache::EntryDesc cacheEntryDesc{ imageId, width };
std::shared_ptr<image::IEncodedImage> cover{ _cache.getImage(cacheEntryDesc) };
if (cover)
return cover;
std::filesystem::path imageFile;
{
db::Session& session{ _db.getTLSSession() };
auto transaction{ session.createReadTransaction() };
const db::Image::pointer image{ db::Image::find(session, imageId) };
if (image)
imageFile = image->getAbsoluteFilePath();
}
cover = getFromImageFile(imageFile, width);
if (cover)
_cache.addImage(cacheEntryDesc, cover);
return cover;
}
std::shared_ptr<image::IEncodedImage> ArtworkService::getTrackImage(db::TrackId trackId, std::optional<image::ImageSize> width)
{
const ImageCache::EntryDesc cacheEntryDesc{ trackId, width };
@@ -217,62 +242,6 @@ namespace lms::cover
return cover;
}
std::shared_ptr<image::IEncodedImage> ArtworkService::getReleaseCover(db::ReleaseId releaseId, std::optional<image::ImageSize> width)
{
const ImageCache::EntryDesc cacheEntryDesc{ releaseId, width };
std::shared_ptr<image::IEncodedImage> image{ _cache.getImage(cacheEntryDesc) };
if (image)
return image;
std::filesystem::path imagePath;
{
db::Session& session{ _db.getTLSSession() };
auto transaction{ session.createReadTransaction() };
const db::Release::pointer release{ db::Release::find(session, releaseId) };
if (release)
{
if (const db::Image::pointer dbImage{ release->getImage() })
imagePath = dbImage->getAbsoluteFilePath();
}
}
image = getFromImageFile(imagePath, width);
if (image)
_cache.addImage(cacheEntryDesc, image);
return image;
}
std::shared_ptr<image::IEncodedImage> ArtworkService::getArtistImage(db::ArtistId artistId, std::optional<image::ImageSize> width)
{
const ImageCache::EntryDesc cacheEntryDesc{ artistId, width };
std::shared_ptr<image::IEncodedImage> artistImage{ _cache.getImage(cacheEntryDesc) };
if (artistImage)
return artistImage;
std::filesystem::path imagePath;
{
db::Session& session{ _db.getTLSSession() };
auto transaction{ session.createReadTransaction() };
if (const db::Artist::pointer artist{ db::Artist::find(session, artistId) })
{
if (const db::Image::pointer image{ artist->getImage() })
imagePath = image->getAbsoluteFilePath();
}
}
artistImage = getFromImageFile(imagePath, width);
if (artistImage)
_cache.addImage(cacheEntryDesc, artistImage);
return artistImage;
}
void ArtworkService::flushCache()
{
_cache.flush();
@@ -48,9 +48,8 @@ namespace lms::cover
ArtworkService& operator=(const ArtworkService&) = delete;
private:
std::shared_ptr<image::IEncodedImage> getImage(db::ImageId imageId, std::optional<image::ImageSize> width) override;
std::shared_ptr<image::IEncodedImage> getTrackImage(db::TrackId trackId, std::optional<image::ImageSize> width) override;
std::shared_ptr<image::IEncodedImage> getReleaseCover(db::ReleaseId releaseId, std::optional<image::ImageSize> width) override;
std::shared_ptr<image::IEncodedImage> getArtistImage(db::ArtistId artistId, std::optional<image::ImageSize> width) override;
std::shared_ptr<image::IEncodedImage> getDefaultReleaseCover() override;
std::shared_ptr<image::IEncodedImage> getDefaultArtistImage() override;
@@ -25,8 +25,7 @@
#include <unordered_map>
#include <variant>
#include "database/ArtistId.hpp"
#include "database/ReleaseId.hpp"
#include "database/ImageId.hpp"
#include "database/TrackId.hpp"
#include "image/IEncodedImage.hpp"
@@ -39,7 +38,7 @@ namespace lms::cover
struct EntryDesc
{
using VariantType = std::variant<db::ArtistId, db::ReleaseId, db::TrackId>;
using VariantType = std::variant<db::TrackId, db::ImageId>;
VariantType id;
std::optional<std::size_t> size;
@@ -23,8 +23,7 @@
#include <memory>
#include <optional>
#include "database/ArtistId.hpp"
#include "database/ReleaseId.hpp"
#include "database/ImageId.hpp"
#include "database/TrackId.hpp"
#include "image/IEncodedImage.hpp"
@@ -40,14 +39,11 @@ namespace lms::cover
public:
virtual ~IArtworkService() = default;
virtual std::shared_ptr<image::IEncodedImage> getArtistImage(db::ArtistId artistId, std::optional<image::ImageSize> width) = 0;
virtual std::shared_ptr<image::IEncodedImage> getImage(db::ImageId imageId, std::optional<image::ImageSize> width) = 0;
// no logic to fallback to release here
virtual std::shared_ptr<image::IEncodedImage> getTrackImage(db::TrackId trackId, std::optional<image::ImageSize> width) = 0;
// no logic to fallback to track here
virtual std::shared_ptr<image::IEncodedImage> getReleaseCover(db::ReleaseId releaseId, std::optional<image::ImageSize> width) = 0;
// Svg images dont have image "size"
virtual std::shared_ptr<image::IEncodedImage> getDefaultReleaseCover() = 0;
virtual std::shared_ptr<image::IEncodedImage> getDefaultArtistImage() = 0;
+1
View File
@@ -25,6 +25,7 @@ add_library(lmssubsonic SHARED
impl/responses/ReplayGain.cpp
impl/responses/Song.cpp
impl/responses/User.cpp
impl/CoverArtId.cpp
impl/ResponseFormat.cpp
impl/ProtocolVersion.cpp
impl/ParameterParsing.cpp
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2024 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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 3 of the License, or
* (at your option) any later version.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CoverArtId.hpp"
#include "SubsonicId.hpp"
#include "core/String.hpp"
namespace lms::api::subsonic
{
namespace
{
constexpr char timestampSeparatorChar{ ':' };
}
std::string idToString(db::ImageId id)
{
return "im-" + id.toString();
}
std::string idToString(CoverArtId coverId)
{
// produce "id:timestamp"
std::string res{ std::visit([](auto&& id) {
return idToString(id);
},
coverId.id) };
res += timestampSeparatorChar;
res += std::to_string(coverId.timestamp);
return res;
}
} // namespace lms::api::subsonic
// Used to parse parameters
namespace lms::core::stringUtils
{
template<>
std::optional<db::ImageId> readAs(std::string_view str)
{
std::vector<std::string_view> values{ core::stringUtils::splitString(str, '-') };
if (values.size() != 2)
return std::nullopt;
if (values[0] != "im")
return std::nullopt;
if (const auto value{ core::stringUtils::readAs<db::ReleaseId::ValueType>(values[1]) })
return db::ImageId{ *value };
return std::nullopt;
}
template<>
std::optional<api::subsonic::CoverArtId> readAs(std::string_view str)
{
// expect "id:timestamp"
auto timeStampSeparator{ str.find_last_of(api::subsonic::timestampSeparatorChar) };
if (timeStampSeparator == std::string_view::npos)
return std::nullopt;
std::string_view strId{ str.substr(0, timeStampSeparator) };
std::string_view strTimestamp{ str.substr(timeStampSeparator + 1) };
api::subsonic::CoverArtId cover;
if (const auto imagetId{ readAs<db::ImageId>(strId) })
cover.id = *imagetId;
else if (const auto trackId{ readAs<db::TrackId>(strId) })
cover.id = *trackId;
else
return std::nullopt;
if (const auto timestamp{ readAs<std::time_t>(strTimestamp) })
cover.timestamp = *timestamp;
else
return std::nullopt;
return cover;
}
} // namespace lms::core::stringUtils
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2024 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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 3 of the License, or
* (at your option) any later version.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <ctime>
#include <variant>
#include "core/String.hpp"
#include "database/ImageId.hpp"
#include "database/TrackId.hpp"
namespace lms::api::subsonic
{
struct CoverArtId
{
std::variant<db::ImageId, db::TrackId> id;
std::time_t timestamp;
};
std::string idToString(CoverArtId coverId);
std::string idToString(db::ImageId imageId);
} // namespace lms::api::subsonic
// Used to parse parameters
namespace lms::core::stringUtils
{
template<>
std::optional<db::ImageId> readAs(std::string_view str);
template<>
std::optional<api::subsonic::CoverArtId> readAs(std::string_view str);
} // namespace lms::core::stringUtils
@@ -47,6 +47,5 @@ namespace lms::api::subsonic
ProtocolVersion serverProtocolVersion;
ResponseFormat responseFormat;
bool enableOpenSubsonic{ true };
bool enableDefaultCover{};
};
} // namespace lms::api::subsonic
@@ -85,19 +85,6 @@ namespace lms::api::subsonic
return res;
}
std::unordered_set<std::string> readDefaultCoverClients()
{
std::unordered_set<std::string> res;
core::Service<core::IConfig>::get()->visitStrings("api-subsonic-default-cover-clients",
[&](std::string_view client) {
res.emplace(std::string{ client });
},
{ "DSub", "substreamer" });
return res;
}
std::string parameterMapToDebugString(const Wt::Http::ParameterMap& parameterMap)
{
auto censorValue = [](const std::string& type, const std::string& value) -> std::string {
@@ -307,7 +294,6 @@ namespace lms::api::subsonic
SubsonicResource::SubsonicResource(db::Db& db)
: _serverProtocolVersionsByClient{ readConfigProtocolVersions() }
, _openSubsonicDisabledClients{ readOpenSubsonicDisabledClients() }
, _defaultReleaseCoverClients{ readDefaultCoverClients() }
, _supportUserPasswordAuthentication{ core::Service<core::IConfig>::get()->getBool("api-subsonic-support-user-password-auth", true) }
, _db{ db }
{
@@ -425,7 +411,6 @@ namespace lms::api::subsonic
const Wt::Http::ParameterMap& parameters{ request.getParameterMap() };
const ClientInfo clientInfo{ getClientInfo(request) };
bool enableOpenSubsonic{ !_openSubsonicDisabledClients.contains(clientInfo.name) };
bool enableDefaultCover{ _defaultReleaseCoverClients.contains(clientInfo.name) };
const ResponseFormat format{ getParameterAs<std::string>(request.getParameterMap(), "f").value_or("xml") == "json" ? ResponseFormat::json : ResponseFormat::xml };
return RequestContext{
@@ -437,7 +422,6 @@ namespace lms::api::subsonic
.serverProtocolVersion = getServerProtocolVersion(clientInfo.name),
.responseFormat = format,
.enableOpenSubsonic = enableOpenSubsonic,
.enableDefaultCover = enableDefaultCover
};
}
@@ -51,7 +51,6 @@ namespace lms::api::subsonic
const std::unordered_map<std::string, ProtocolVersion> _serverProtocolVersionsByClient;
const std::unordered_set<std::string> _openSubsonicDisabledClients;
const std::unordered_set<std::string> _defaultReleaseCoverClients;
const bool _supportUserPasswordAuthentication;
db::Db& _db;
@@ -24,7 +24,6 @@
#include "av/TranscodingParameters.hpp"
#include "av/TranscodingResourceHandlerCreator.hpp"
#include "av/Types.hpp"
#include "core/FileResourceHandlerCreator.hpp"
#include "core/ILogger.hpp"
#include "core/IResourceHandler.hpp"
#include "core/String.hpp"
@@ -35,6 +34,7 @@
#include "database/User.hpp"
#include "services/artwork/IArtworkService.hpp"
#include "CoverArtId.hpp"
#include "ParameterParsing.hpp"
#include "RequestContext.hpp"
#include "SubsonicId.hpp"
@@ -326,36 +326,26 @@ namespace lms::api::subsonic
void handleGetCoverArt(RequestContext& context, const Wt::Http::Request& /*request*/, Wt::Http::Response& response)
{
// Mandatory params
const auto trackId{ getParameterAs<TrackId>(context.parameters, "id") };
const auto releaseId{ getParameterAs<ReleaseId>(context.parameters, "id") };
const auto artistId{ getParameterAs<ArtistId>(context.parameters, "id") };
if (!trackId && !releaseId && !artistId)
throw BadParameterGenericError{ "id" };
const CoverArtId coverArtId{ getMandatoryParameterAs<CoverArtId>(context.parameters, "id") };
std::optional<std::size_t> size{ getParameterAs<std::size_t>(context.parameters, "size") };
if (size)
*size = core::utils::clamp(*size, std::size_t{ 32 }, std::size_t{ 2048 });
std::shared_ptr<image::IEncodedImage> cover;
if (trackId)
cover = core::Service<cover::IArtworkService>::get()->getTrackImage(*trackId, size);
else if (releaseId)
cover = core::Service<cover::IArtworkService>::get()->getReleaseCover(*releaseId, size);
else if (artistId)
cover = core::Service<cover::IArtworkService>::get()->getArtistImage(*artistId, size);
std::shared_ptr<image::IEncodedImage> image;
if (const db::TrackId * trackId{ std::get_if<db::TrackId>(&coverArtId.id) })
image = core::Service<cover::IArtworkService>::get()->getTrackImage(*trackId, size);
else if (const db::ImageId * imageId{ std::get_if<db::ImageId>(&coverArtId.id) })
image = core::Service<cover::IArtworkService>::get()->getImage(*imageId, size);
if (!cover && context.enableDefaultCover && !artistId)
cover = core::Service<cover::IArtworkService>::get()->getDefaultReleaseCover();
if (!cover)
if (!image)
{
response.setStatus(404);
return;
}
response.out().write(reinterpret_cast<const char*>(cover->getData().data()), cover->getData().size());
response.setMimeType(std::string{ cover->getMimeType() });
response.out().write(reinterpret_cast<const char*>(image->getData().data()), image->getData().size());
response.setMimeType(std::string{ image->getMimeType() });
}
} // namespace lms::api::subsonic
+6 -3
View File
@@ -32,6 +32,7 @@
#include "services/feedback/IFeedbackService.hpp"
#include "services/scrobbling/IScrobblingService.hpp"
#include "CoverArtId.hpp"
#include "RequestContext.hpp"
#include "SubsonicId.hpp"
#include "responses/Artist.hpp"
@@ -84,9 +85,10 @@ namespace lms::api::subsonic
}
albumNode.setAttribute("created", core::stringUtils::toISO8601String(release->getLastWritten()));
if (release->getImage())
if (const auto image{ release->getImage() })
{
albumNode.setAttribute("coverArt", idToString(release->getId()));
const CoverArtId coverArtId{ image->getId(), image->getLastWriteTime().toTime_t() };
albumNode.setAttribute("coverArt", idToString(coverArtId));
}
else
{
@@ -96,7 +98,8 @@ namespace lms::api::subsonic
params.setRange(db::Range{ 0, 1 });
db::Track::find(context.dbSession, params, [&](const db::Track::pointer& track) {
albumNode.setAttribute("coverArt", idToString(track->getId()));
const CoverArtId coverArtId{ track->getId(), track->getLastWriteTime().toTime_t() };
albumNode.setAttribute("coverArt", idToString(coverArtId));
});
}
if (const auto year{ release->getYear() })
+6 -2
View File
@@ -29,6 +29,7 @@
#include "database/User.hpp"
#include "services/feedback/IFeedbackService.hpp"
#include "CoverArtId.hpp"
#include "RequestContext.hpp"
#include "SubsonicId.hpp"
@@ -94,8 +95,11 @@ namespace lms::api::subsonic
artistNode.setAttribute("id", idToString(artist->getId()));
artistNode.setAttribute("name", artist->getName());
if (artist->getImage())
artistNode.setAttribute("coverArt", idToString(artist->getId()));
if (const auto image{ artist->getImage() })
{
const CoverArtId coverArtId{ image->getId(), image->getLastWriteTime().toTime_t() };
artistNode.setAttribute("coverArt", idToString(coverArtId));
}
const std::size_t count{ Release::getCount(context.dbSession, Release::FindParameters{}.setArtist(artist->getId())) };
artistNode.setAttribute("albumCount", count);
@@ -23,6 +23,7 @@
#include "database/TrackList.hpp"
#include "database/User.hpp"
#include "CoverArtId.hpp"
#include "SubsonicId.hpp"
namespace lms::api::subsonic
@@ -50,7 +51,8 @@ namespace lms::api::subsonic
params.setSortMethod(TrackSortMethod::TrackList);
db::Track::find(session, params, [&](const db::Track::pointer& track) {
playlistNode.setAttribute("coverArt", idToString(track->getId()));
const CoverArtId coverArtId{ track->getId(), track->getLastWriteTime().toTime_t() };
playlistNode.setAttribute("coverArt", idToString(coverArtId));
});
return playlistNode;
+13 -3
View File
@@ -36,6 +36,7 @@
#include "services/feedback/IFeedbackService.hpp"
#include "services/scrobbling/IScrobblingService.hpp"
#include "CoverArtId.hpp"
#include "RequestContext.hpp"
#include "SubsonicId.hpp"
#include "responses/Artist.hpp"
@@ -109,9 +110,18 @@ namespace lms::api::subsonic
const Release::pointer release{ track->getRelease() };
if (track->hasCover())
trackResponse.setAttribute("coverArt", idToString(track->getId()));
else if (release && release->getImage())
trackResponse.setAttribute("coverArt", idToString(release->getId()));
{
const CoverArtId coverArtId{ track->getId(), track->getLastWriteTime().toTime_t() };
trackResponse.setAttribute("coverArt", idToString(coverArtId));
}
else if (release)
{
if (const db::Image::pointer image{ release->getImage() })
{
const CoverArtId coverArtId{ image->getId(), image->getLastWriteTime().toTime_t() };
trackResponse.setAttribute("coverArt", idToString(coverArtId));
}
}
const std::vector<Artist::pointer>& artists{ track->getArtists({ TrackArtistLinkType::Artist }) };
if (!artists.empty())
+35 -59
View File
@@ -60,8 +60,11 @@ namespace lms::ui
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
const db::Artist::pointer artist{ db::Artist::find(LmsApp->getDbSession(), artistId) };
if (artist && artist->getImage())
url = getArtistIdImageUrl(artistId, size);
if (artist)
{
if (const db::Image::pointer image{ artist->getImage() })
url = getImageUrl(image->getId(), size, "artist");
}
}
if (url.empty())
@@ -80,9 +83,9 @@ namespace lms::ui
const db::Release::pointer release{ db::Release::find(LmsApp->getDbSession(), releaseId) };
if (release)
{
if (release->getImage())
if (const db::Image::pointer image{ release->getImage() })
{
url = getReleaseIdCoverUrl(release->getId(), size);
url = getImageUrl(image->getId(), size, "release");
}
else
{
@@ -92,7 +95,7 @@ namespace lms::ui
params.setRange(db::Range{ 0, 1 });
db::Track::find(LmsApp->getDbSession(), params, [&](const db::Track::pointer& track) {
url = getTrackIdImageUrl(track->getId(), size);
url = getImageUrl(track->getId(), size, "release");
});
}
}
@@ -115,9 +118,14 @@ namespace lms::ui
if (track)
{
if (track->hasCover())
url = getTrackIdImageUrl(trackId, size);
else if (const db::Release::pointer release{ track->getRelease() }; release && release->getImage())
url = getReleaseIdCoverUrl(release->getId(), size);
{
url = getImageUrl(trackId, size, "release");
}
else if (const db::Release::pointer release{ track->getRelease() })
{
if (const db::Image::pointer image{ release->getImage() })
url = getImageUrl(image->getId(), size, "release");
}
}
}
@@ -127,29 +135,24 @@ namespace lms::ui
return url;
}
std::string ArtworkResource::getArtistIdImageUrl(db::ArtistId artistId, Size size) const
std::string ArtworkResource::getImageUrl(db::ImageId imageId, Size size, std::string_view type) const
{
return url() + "&artistid=" + artistId.toString() + "&size=" + std::to_string(static_cast<std::size_t>(size));
return url() + "&imageid=" + imageId.toString() + "&size=" + std::to_string(static_cast<std::size_t>(size)) + "&type=" + std::string{ type };
}
std::string ArtworkResource::getReleaseIdCoverUrl(db::ReleaseId releaseId, Size size) const
std::string ArtworkResource::getImageUrl(db::TrackId trackId, Size size, std::string_view type) const
{
return url() + "&releaseid=" + releaseId.toString() + "&size=" + std::to_string(static_cast<std::size_t>(size));
}
std::string ArtworkResource::getTrackIdImageUrl(db::TrackId trackId, Size size) const
{
return url() + "&trackid=" + trackId.toString() + "&size=" + std::to_string(static_cast<std::size_t>(size));
return url() + "&trackid=" + trackId.toString() + "&size=" + std::to_string(static_cast<std::size_t>(size)) + "&type=" + std::string{ type };
}
std::string ArtworkResource::getDefaultArtistImageUrl() const
{
return url() + "&type=defaultartistimage";
return url() + "&type=artist";
}
std::string ArtworkResource::getDefaultReleaseCoverUrl() const
{
return url() + "&type=defaultreleasecover";
return url() + "&type=release";
}
void ArtworkResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response)
@@ -157,58 +160,32 @@ namespace lms::ui
LMS_SCOPED_TRACE_OVERVIEW("UI", "HandleCoverRequest");
// Retrieve parameters
const std::string* artistIdStr = request.getParameter("artistid");
const std::string* imageIdStr = request.getParameter("imageid");
const std::string* trackIdStr = request.getParameter("trackid");
const std::string* releaseIdStr = request.getParameter("releaseid");
const std::string* sizeStr = request.getParameter("size");
const std::string* typeStr = request.getParameter("type");
std::shared_ptr<image::IEncodedImage> image;
// Mandatory parameter size
if ((artistIdStr || trackIdStr || releaseIdStr))
if ((imageIdStr || trackIdStr))
{
if (!sizeStr)
{
LOG(DEBUG, "no size provided!");
return;
}
const auto size{ core::stringUtils::readAs<std::size_t>(*sizeStr) };
if (!size || *size > maxSize)
const auto size{ sizeStr ? core::stringUtils::readAs<std::size_t>(*sizeStr) : std::nullopt };
if (size && *size > maxSize)
{
LOG(DEBUG, "invalid size provided!");
return;
}
if (artistIdStr)
if (imageIdStr)
{
LOG(DEBUG, "Requested cover for track " << *artistIdStr << ", size = " << *size);
const std::optional<db::ArtistId> artistId{ core::stringUtils::readAs<db::ArtistId::ValueType>(*artistIdStr) };
if (!artistId)
const std::optional<db::ImageId> imageId{ core::stringUtils::readAs<db::ImageId::ValueType>(*imageIdStr) };
if (!imageId)
return;
image = core::Service<cover::IArtworkService>::get()->getArtistImage(*artistId, *size);
if (!image)
image = core::Service<cover::IArtworkService>::get()->getDefaultArtistImage();
}
else if (releaseIdStr)
{
LOG(DEBUG, "Requested cover for release " << *releaseIdStr << ", size = " << *size);
const std::optional<db::ReleaseId> releaseId{ core::stringUtils::readAs<db::ReleaseId::ValueType>(*releaseIdStr) };
if (!releaseId)
return;
image = core::Service<cover::IArtworkService>::get()->getReleaseCover(*releaseId, *size);
if (!image)
image = core::Service<cover::IArtworkService>::get()->getDefaultReleaseCover();
image = core::Service<cover::IArtworkService>::get()->getImage(*imageId, size);
}
else if (trackIdStr)
{
LOG(DEBUG, "Requested cover for track " << *trackIdStr << ", size = " << *size);
const std::optional<db::TrackId> trackId{ core::stringUtils::readAs<db::TrackId::ValueType>(*trackIdStr) };
if (!trackId)
{
@@ -216,16 +193,15 @@ namespace lms::ui
return;
}
image = core::Service<cover::IArtworkService>::get()->getTrackImage(*trackId, *size);
if (!image)
image = core::Service<cover::IArtworkService>::get()->getDefaultReleaseCover();
image = core::Service<cover::IArtworkService>::get()->getTrackImage(*trackId, size);
}
}
else if (typeStr)
if (!image)
{
if (*typeStr == "defaultreleasecover")
if (*typeStr == "release")
image = core::Service<cover::IArtworkService>::get()->getDefaultReleaseCover();
else if (*typeStr == "defaultartistimage")
else if (*typeStr == "artist")
image = core::Service<cover::IArtworkService>::get()->getDefaultArtistImage();
}
+3 -3
View File
@@ -22,6 +22,7 @@
#include <Wt/WResource.h>
#include "database/ArtistId.hpp"
#include "database/ImageId.hpp"
#include "database/ReleaseId.hpp"
#include "database/TrackId.hpp"
@@ -46,9 +47,8 @@ namespace lms::ui
std::string getTrackImageUrl(db::TrackId trackId, Size size) const;
private:
std::string getArtistIdImageUrl(db::ArtistId artistId, Size size) const;
std::string getReleaseIdCoverUrl(db::ReleaseId releaseId, Size size) const;
std::string getTrackIdImageUrl(db::TrackId trackId, Size size) const;
std::string getImageUrl(db::ImageId imageId, Size size, std::string_view type) const;
std::string getImageUrl(db::TrackId trackId, Size size, std::string_view type) const;
std::string getDefaultArtistImageUrl() const;
std::string getDefaultReleaseCoverUrl() const;