diff --git a/src/libs/cover/impl/CoverArtGrabber.cpp b/src/libs/cover/impl/CoverArtGrabber.cpp index 226d28a1..58fff328 100644 --- a/src/libs/cover/impl/CoverArtGrabber.cpp +++ b/src/libs/cover/impl/CoverArtGrabber.cpp @@ -21,6 +21,7 @@ #include "av/IAudioFile.hpp" +#include "database/Db.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -33,6 +34,7 @@ using RawImage = CoverArt::STB::RawImage; using RawImage = CoverArt::GraphicsMagick::RawImage; #endif +#include "utils/IConfig.hpp" #include "utils/Logger.hpp" #include "utils/Random.hpp" #include "utils/Utils.hpp" @@ -85,27 +87,25 @@ isFileSupported(const std::filesystem::path& file, const std::vector -createGrabber(const std::filesystem::path& execPath, - const std::filesystem::path& defaultCoverPath, - std::size_t maxCacheSize, std::size_t maxFileSize, unsigned jpegQuality) +createGrabber(Database::Db& db, const std::filesystem::path& execPath, const std::filesystem::path& defaultCoverPath) { - return std::make_unique(execPath, defaultCoverPath, maxCacheSize, maxFileSize, jpegQuality); + return std::make_unique(db, execPath, defaultCoverPath); } -Grabber::Grabber(const std::filesystem::path& execPath, - const std::filesystem::path& defaultCoverPath, - std::size_t maxCacheSize, - std::size_t maxFileSize, - unsigned jpegQuality) - : _defaultCoverPath {defaultCoverPath} - , _maxCacheSize {maxCacheSize} - , _maxFileSize {maxFileSize} - , _jpegQuality {Utils::clamp(jpegQuality, 1, 100)} +Grabber::Grabber(Database::Db& db, + const std::filesystem::path& execPath, + const std::filesystem::path& defaultCoverPath) + : _db {db} + , _defaultCoverPath {defaultCoverPath} + , _maxCacheSize {Service::get()->getULong("cover-max-cache-size", 30) * 1000 * 1000} + , _maxFileSize {Service::get()->getULong("cover-max-file-size", 10) * 1000 * 1000} + { + setJpegQuality(Service::get()->getULong("cover-jpeg-quality", 75)); + LMS_LOG(COVER, INFO) << "Default cover path = '" << _defaultCoverPath.string() << "'"; LMS_LOG(COVER, INFO) << "Max cache size = " << _maxCacheSize; LMS_LOG(COVER, INFO) << "Max file size = " << _maxFileSize; - LMS_LOG(COVER, INFO) << "JPEG export quality = " << _jpegQuality; #if LMS_SUPPORT_IMAGE_GM GraphicsMagick::init(execPath); @@ -313,9 +313,9 @@ Grabber::getFromTrack(const std::filesystem::path& p, ImageSize width) const } std::shared_ptr -Grabber::getFromTrack(Database::Session& dbSession, Database::TrackId trackId, ImageSize width) +Grabber::getFromTrack(Database::TrackId trackId, ImageSize width) { - return getFromTrack(dbSession, trackId, width, true /* allow release fallback*/); + return getFromTrack(_db.getTLSSession(), trackId, width, true /* allow release fallback*/); } std::shared_ptr @@ -338,7 +338,7 @@ Grabber::getFromTrack(Database::Session& dbSession, Database::TrackId trackId, I cover = getFromSameNamedFile(trackInfo->trackPath, width); if (!cover && trackInfo->releaseId && allowReleaseFallback) - cover = getFromRelease(dbSession, *trackInfo->releaseId, width); + cover = getFromRelease(*trackInfo->releaseId, width); if (!cover && trackInfo->isMultiDisc) { @@ -357,7 +357,7 @@ Grabber::getFromTrack(Database::Session& dbSession, Database::TrackId trackId, I } std::shared_ptr -Grabber::getFromRelease(Database::Session& session, Database::ReleaseId releaseId, ImageSize width) +Grabber::getFromRelease(Database::ReleaseId releaseId, ImageSize width) { const CacheEntryDesc cacheEntryDesc {releaseId, width}; @@ -371,6 +371,8 @@ Grabber::getFromRelease(Database::Session& session, Database::ReleaseId releaseI std::filesystem::path releaseDirectory; }; + Database::Session& session {_db.getTLSSession()}; + auto getReleaseInfo {[&] { std::optional res; @@ -418,6 +420,14 @@ Grabber::flushCache() _cache.clear(); } +void +Grabber::setJpegQuality(unsigned quality) +{ + _jpegQuality = Utils::clamp(quality, 1, 100); + + LMS_LOG(COVER, INFO) << "JPEG export quality = " << _jpegQuality; +} + void Grabber::saveToCache(const CacheEntryDesc& entryDesc, std::shared_ptr image) { diff --git a/src/libs/cover/impl/CoverArtGrabber.hpp b/src/libs/cover/impl/CoverArtGrabber.hpp index e5c33fb8..15e5f1ec 100644 --- a/src/libs/cover/impl/CoverArtGrabber.hpp +++ b/src/libs/cover/impl/CoverArtGrabber.hpp @@ -86,11 +86,9 @@ namespace CoverArt class Grabber : public IGrabber { public: - Grabber(const std::filesystem::path& execPath, - const std::filesystem::path& defaultCoverPath, - std::size_t maxCacheEntries, - std::size_t maxFileSize, - unsigned jpegQuality); + Grabber(Database::Db& db, + const std::filesystem::path& execPath, + const std::filesystem::path& defaultCoverPath); Grabber(const Grabber&) = delete; Grabber& operator=(const Grabber&) = delete; @@ -98,9 +96,10 @@ namespace CoverArt Grabber& operator=(Grabber&&) = delete; private: - std::shared_ptr getFromTrack(Database::Session& dbSession, Database::TrackId trackId, ImageSize width) override; - std::shared_ptr getFromRelease(Database::Session& dbSession, Database::ReleaseId releaseId, ImageSize width) override; + std::shared_ptr getFromTrack(Database::TrackId trackId, ImageSize width) override; + std::shared_ptr getFromRelease(Database::ReleaseId releaseId, ImageSize width) override; void flushCache() override; + void setJpegQuality(unsigned quality) override; std::shared_ptr getFromTrack(Database::Session& dbSession, Database::TrackId trackId, ImageSize width, bool allowReleaseFallback); std::unique_ptr getFromAvMediaFile(const Av::IAudioFile& input, ImageSize width) const; @@ -114,6 +113,8 @@ namespace CoverArt bool checkCoverFile(const std::filesystem::path& directoryPath) const; + Database::Db& _db; + std::shared_mutex _cacheMutex; std::unordered_map> _cache; std::unordered_map> _defaultCoverCache; @@ -129,7 +130,7 @@ namespace CoverArt static inline const std::vector _fileExtensions {".jpg", ".jpeg", ".png", ".bmp"}; // TODO parametrize const std::size_t _maxFileSize; static inline const std::vector _preferredFileNames {"cover", "front"}; // TODO parametrize - const unsigned _jpegQuality; + unsigned _jpegQuality; }; } // namespace CoverArt diff --git a/src/libs/cover/include/cover/ICoverArtGrabber.hpp b/src/libs/cover/include/cover/ICoverArtGrabber.hpp index 544cee7a..d6bcdf67 100644 --- a/src/libs/cover/include/cover/ICoverArtGrabber.hpp +++ b/src/libs/cover/include/cover/ICoverArtGrabber.hpp @@ -27,7 +27,7 @@ namespace Database { - class Session; + class Db; } namespace CoverArt @@ -37,17 +37,17 @@ namespace CoverArt public: virtual ~IGrabber() = default; - virtual std::shared_ptr getFromTrack(Database::Session& dbSession, Database::TrackId trackId, ImageSize width) = 0; - virtual std::shared_ptr getFromRelease(Database::Session& dbSession, Database::ReleaseId releaseId, ImageSize width) = 0; + virtual std::shared_ptr getFromTrack(Database::TrackId trackId, ImageSize width) = 0; + virtual std::shared_ptr getFromRelease(Database::ReleaseId releaseId, ImageSize width) = 0; virtual void flushCache() = 0; + + virtual void setJpegQuality(unsigned quality) = 0; // from 1 to 100 }; - std::unique_ptr createGrabber(const std::filesystem::path& execPath, - const std::filesystem::path& defaultCoverPath, - std::size_t maxCacheEntries, - std::size_t maxFileSize, - unsigned jpegQuality); + std::unique_ptr createGrabber(Database::Db& db, + const std::filesystem::path& execPath, + const std::filesystem::path& defaultCoverPath); } // namespace CoverArt diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index c3c4ba04..3fc97965 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -1795,9 +1795,9 @@ handleGetCoverArt(RequestContext& context, const Wt::Http::Request& /*request*/, std::shared_ptr cover; if (trackId) - cover = Service::get()->getFromTrack(context.dbSession, *trackId, size); + cover = Service::get()->getFromTrack(*trackId, size); else if (releaseId) - cover = Service::get()->getFromRelease(context.dbSession, *releaseId, size); + cover = Service::get()->getFromRelease(*releaseId, size); response.out().write(reinterpret_cast(cover->getData()), cover->getDataSize()); response.setMimeType(std::string {cover->getMimeType()}); diff --git a/src/lms/main.cpp b/src/lms/main.cpp index 98c0cec6..e14c3573 100644 --- a/src/lms/main.cpp +++ b/src/lms/main.cpp @@ -250,13 +250,9 @@ int main(int argc, char* argv[]) else throw LmsException {"Bad value '" + authenticationBackend + "' for 'authentication-backend'"}; - Service coverArtService {CoverArt::createGrabber(argv[0], - server.appRoot() + "/images/unknown-cover.jpg", - config->getULong("cover-max-cache-size", 30) * 1000 * 1000, - config->getULong("cover-max-file-size", 10) * 1000 * 1000, - config->getULong("cover-jpeg-quality", 75))}; + Service coverArtService {CoverArt::createGrabber(database, argv[0], server.appRoot() + "/images/unknown-cover.jpg")}; Service recommendationEngineService {Recommendation::createEngine(database)}; - Service scannerService {Scanner::createScanner(/*ioContext,*/ database, *recommendationEngineService)}; + Service scannerService {Scanner::createScanner(database, *recommendationEngineService)}; scannerService->getEvents().scanComplete.connect([&] { diff --git a/src/lms/ui/resource/CoverResource.cpp b/src/lms/ui/resource/CoverResource.cpp index a2978c6b..2ed89d9e 100644 --- a/src/lms/ui/resource/CoverResource.cpp +++ b/src/lms/ui/resource/CoverResource.cpp @@ -96,7 +96,7 @@ CoverResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons return; } - cover = Service::get()->getFromTrack(LmsApp->getDbSession(), *trackId, *size); + cover = Service::get()->getFromTrack(*trackId, *size); } else if (releaseIdStr) { @@ -106,7 +106,7 @@ CoverResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons if (!releaseId) return; - cover = Service::get()->getFromRelease(LmsApp->getDbSession(), *releaseId, *size); + cover = Service::get()->getFromRelease(*releaseId, *size); } else { diff --git a/src/tools/cover/LmsCover.cpp b/src/tools/cover/LmsCover.cpp index 6a9e2767..f1b44c97 100644 --- a/src/tools/cover/LmsCover.cpp +++ b/src/tools/cover/LmsCover.cpp @@ -47,7 +47,7 @@ dumpTrackCovers(Database::Session& session, CoverArt::ImageSize width) for (const Database::TrackId trackId : trackIds) { std::cout << "Getting cover for track id " << trackId.toString() << std::endl; - Service::get()->getFromTrack(session, trackId, width); + Service::get()->getFromTrack(trackId, width); } } @@ -82,15 +82,11 @@ int main(int argc, char *argv[]) } Service config {createConfig(vm["conf"].as())}; - - Service coverArtService {CoverArt::createGrabber(argv[0], - vm["default-cover"].as(), - config->getULong("cover-max-cache-size", 30) * 1000 * 1000, - config->getULong("cover-max-file-size", 10) * 1000 * 1000, - config->getULong("cover-jpeg-quality", vm["quality"].as()) - )}; - Database::Db db {config->getPath("working-dir") / "lms.db"}; + Service coverArtService {CoverArt::createGrabber(db, argv[0], vm["default-cover"].as())}; + + coverArtService->setJpegQuality(config->getULong("cover-jpeg-quality", vm["quality"].as())); + Database::Session session {db}; if (vm.count("tracks"))