Introduced lmscore lib to centralize services, migrated cover service

This commit is contained in:
emeric
2021-10-16 15:22:59 +02:00
parent 0dcef2e94c
commit 32a944e3d4
26 changed files with 149 additions and 106 deletions
+2 -1
View File
@@ -1,8 +1,9 @@
add_subdirectory(auth) add_subdirectory(auth)
add_subdirectory(av) add_subdirectory(av)
add_subdirectory(cover)
add_subdirectory(database) add_subdirectory(database)
add_subdirectory(image)
add_subdirectory(lmscore)
add_subdirectory(metadata) add_subdirectory(metadata)
add_subdirectory(recommendation) add_subdirectory(recommendation)
add_subdirectory(scanner) add_subdirectory(scanner)
-44
View File
@@ -1,44 +0,0 @@
add_library(lmscover SHARED
impl/CoverService.cpp
)
target_include_directories(lmscover INTERFACE
include
)
target_include_directories(lmscover PRIVATE
include
impl
)
target_link_libraries(lmscover PRIVATE
lmsav
)
target_link_libraries(lmscover PUBLIC
lmsdatabase
lmsutils
std::filesystem
)
if (IMAGE_LIBRARY STREQUAL STB)
target_sources(lmscover PRIVATE
impl/stb/JPEGImage.cpp
impl/stb/RawImage.cpp
)
target_compile_options(lmscover PRIVATE "-DLMS_SUPPORT_IMAGE_STB")
target_include_directories(lmscover PRIVATE ${STB_INCLUDE_DIR})
elseif (IMAGE_LIBRARY STREQUAL GraphicsMagick++)
target_sources(lmscover PRIVATE
impl/graphicsmagick/JPEGImage.cpp
impl/graphicsmagick/RawImage.cpp
)
target_compile_options(lmscover PRIVATE "-DLMS_SUPPORT_IMAGE_GM")
target_link_libraries(lmscover PRIVATE PkgConfig::GraphicsMagick++)
else ()
message(FATAL_ERROR "Invalid IMAGE_LIBRARY provided")
endif()
install(TARGETS lmscover DESTINATION lib)
+38
View File
@@ -0,0 +1,38 @@
add_library(lmsimage SHARED
)
target_include_directories(lmsimage INTERFACE
include
)
target_include_directories(lmsimage PRIVATE
include
impl
)
target_link_libraries(lmsimage PUBLIC
lmsutils
std::filesystem
)
if (IMAGE_LIBRARY STREQUAL STB)
target_sources(lmsimage PRIVATE
impl/stb/JPEGImage.cpp
impl/stb/RawImage.cpp
)
target_compile_options(lmsimage PRIVATE "-DLMS_SUPPORT_IMAGE_STB")
target_include_directories(lmsimage PRIVATE ${STB_INCLUDE_DIR})
elseif (IMAGE_LIBRARY STREQUAL GraphicsMagick++)
target_sources(lmsimage PRIVATE
impl/graphicsmagick/JPEGImage.cpp
impl/graphicsmagick/RawImage.cpp
)
target_compile_options(lmsimage PRIVATE "-DLMS_SUPPORT_IMAGE_GM")
target_link_libraries(lmsimage PRIVATE PkgConfig::GraphicsMagick++)
else ()
message(FATAL_ERROR "Invalid IMAGE_LIBRARY provided")
endif()
install(TARGETS lmsimage DESTINATION lib)
@@ -25,7 +25,16 @@
#include "JPEGImage.hpp" #include "JPEGImage.hpp"
#include "Exception.hpp" #include "Exception.hpp"
namespace CoverArt::GraphicsMagick { namespace Image::GraphicsMagick
{
std::unique_ptr<IRawImage> decodeImage(const std::byte* encodedData, std::size_t encodedDataSize)
{
return std::make_unique<RawImage>(encodedData, encodedDataSize);
}
std::unique_ptr<IRawImage> decodeImage(const std::filesystem::path& path)
{
void void
init(const std::filesystem::path& path) init(const std::filesystem::path& path)
@@ -116,5 +125,5 @@ RawImage::getMagickImage() const
return _image; return _image;
} }
} // namespace CoverArt::GraphicsMagick } // namespace Image::GraphicsMagick
@@ -22,10 +22,10 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb/stb_image_write.h> #include <stb/stb_image_write.h>
#include "image/Exception.hpp"
#include "RawImage.hpp" #include "RawImage.hpp"
#include "Exception.hpp"
namespace Cover::STB namespace Image::STB
{ {
JPEGImage::JPEGImage(const RawImage& rawImage, unsigned quality) JPEGImage::JPEGImage(const RawImage& rawImage, unsigned quality)
{ {
@@ -21,9 +21,9 @@
#include <vector> #include <vector>
#include "cover/IEncodedImage.hpp" #include "image/IEncodedImage.hpp"
namespace Cover::STB namespace Image::STB
{ {
class RawImage; class RawImage;
class JPEGImage : public IEncodedImage class JPEGImage : public IEncodedImage
@@ -30,9 +30,22 @@
#include "JPEGImage.hpp" #include "JPEGImage.hpp"
#include "Exception.hpp" #include "image/Exception.hpp"
namespace Cover::STB namespace Image
{
std::unique_ptr<IRawImage> decodeImage(const std::byte* encodedData, std::size_t encodedDataSize)
{
return std::make_unique<STB::RawImage>(encodedData, encodedDataSize);
}
std::unique_ptr<IRawImage> decodeImage(const std::filesystem::path& path)
{
return std::make_unique<STB::RawImage>(path);
}
}
namespace Image::STB
{ {
RawImage::RawImage(const std::byte* encodedData, std::size_t encodedDataSize) RawImage::RawImage(const std::byte* encodedData, std::size_t encodedDataSize)
{ {
@@ -26,10 +26,10 @@
#include <cstddef> #include <cstddef>
#include <filesystem> #include <filesystem>
#include "cover/IEncodedImage.hpp" #include "image/IEncodedImage.hpp"
#include "IRawImage.hpp" #include "image/IRawImage.hpp"
namespace Cover::STB namespace Image::STB
{ {
class RawImage : public IRawImage class RawImage : public IRawImage
{ {
@@ -21,7 +21,7 @@
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
namespace Cover namespace Image
{ {
// internal use only // internal use only
class ImageException : public LmsException class ImageException : public LmsException
@@ -22,7 +22,7 @@
#include <cstddef> #include <cstddef>
#include <string_view> #include <string_view>
namespace Cover namespace Image
{ {
using ImageSize = std::size_t; using ImageSize = std::size_t;
@@ -21,9 +21,9 @@
#include <memory> #include <memory>
#include "cover/IEncodedImage.hpp" #include "image/IEncodedImage.hpp"
namespace Cover namespace Image
{ {
class IRawImage class IRawImage
{ {
@@ -32,5 +32,8 @@ namespace Cover
virtual void resize(ImageSize width) = 0; virtual void resize(ImageSize width) = 0;
virtual std::unique_ptr<IEncodedImage> encodeToJPEG(unsigned quality) const = 0; virtual std::unique_ptr<IEncodedImage> encodeToJPEG(unsigned quality) const = 0;
}; };
std::unique_ptr<IRawImage> decodeImage(const std::byte* encodedData, std::size_t encodedDataSize);
std::unique_ptr<IRawImage> decodeImage(const std::filesystem::path& path);
} }
+28
View File
@@ -0,0 +1,28 @@
add_library(lmscore SHARED
impl/CoverService.cpp
)
target_include_directories(lmscore INTERFACE
include
)
target_include_directories(lmscore PRIVATE
include
impl
)
target_link_libraries(lmscore PRIVATE
lmsav
lmsimage
)
target_link_libraries(lmscore PUBLIC
lmsdatabase
lmsimage
lmsutils
std::filesystem
)
install(TARGETS lmscore DESTINATION lib)
@@ -26,19 +26,12 @@
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#if LMS_SUPPORT_IMAGE_STB #include "image/Exception.hpp"
#include "stb/RawImage.hpp" #include "image/IRawImage.hpp"
using RawImage = Cover::STB::RawImage;
#elif LMS_SUPPORT_IMAGE_GM
#include "graphicsmagick/RawImage.hpp"
using RawImage = Cover::GraphicsMagick::RawImage;
#endif
#include "utils/IConfig.hpp" #include "utils/IConfig.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/Random.hpp" #include "utils/Random.hpp"
#include "utils/Utils.hpp" #include "utils/Utils.hpp"
#include "Exception.hpp"
namespace namespace
{ {
@@ -79,6 +72,8 @@ namespace
namespace Cover { namespace Cover {
using namespace Image;
static static
bool bool
isFileSupported(const std::filesystem::path& file, const std::vector<std::filesystem::path>& extensions) isFileSupported(const std::filesystem::path& file, const std::vector<std::filesystem::path>& extensions)
@@ -117,7 +112,7 @@ CoverService::CoverService(Database::Db& db,
{ {
getDefault(512); getDefault(512);
} }
catch (const ImageException& e) catch (const Image::ImageException& e)
{ {
throw LmsException("Cannot read default cover file '" + _defaultCoverPath.string() + "': " + e.what()); throw LmsException("Cannot read default cover file '" + _defaultCoverPath.string() + "': " + e.what());
} }
@@ -135,11 +130,11 @@ CoverService::getFromAvMediaFile(const Av::IAudioFile& input, ImageSize width) c
try try
{ {
RawImage rawImage {picture.data, picture.dataSize}; std::unique_ptr<IRawImage> rawImage {decodeImage(picture.data, picture.dataSize)};
rawImage.resize(width); rawImage->resize(width);
image = rawImage.encodeToJPEG(_jpegQuality); image = rawImage->encodeToJPEG(_jpegQuality);
} }
catch (const ImageException& e) catch (const Image::ImageException& e)
{ {
LMS_LOG(COVER, ERROR) << "Cannot read embedded cover: " << e.what(); LMS_LOG(COVER, ERROR) << "Cannot read embedded cover: " << e.what();
} }
@@ -155,9 +150,9 @@ CoverService::getFromCoverFile(const std::filesystem::path& p, ImageSize width)
try try
{ {
RawImage rawImage {p}; std::unique_ptr<IRawImage> rawImage {decodeImage(p)};
rawImage.resize(width); rawImage->resize(width);
image = rawImage.encodeToJPEG(_jpegQuality); image = rawImage->encodeToJPEG(_jpegQuality);
} }
catch (const ImageException& e) catch (const ImageException& e)
{ {
@@ -29,8 +29,8 @@
#include <variant> #include <variant>
#include <vector> #include <vector>
#include "cover/ICoverService.hpp" #include "lmscore/services/ICoverService.hpp"
#include "cover/IEncodedImage.hpp" #include "image/IEncodedImage.hpp"
#include "database/Types.hpp" #include "database/Types.hpp"
namespace Database namespace Database
@@ -96,34 +96,34 @@ namespace Cover
CoverService& operator=(CoverService&&) = delete; CoverService& operator=(CoverService&&) = delete;
private: private:
std::shared_ptr<IEncodedImage> getFromTrack(Database::TrackId trackId, ImageSize width) override; std::shared_ptr<Image::IEncodedImage> getFromTrack(Database::TrackId trackId, Image::ImageSize width) override;
std::shared_ptr<IEncodedImage> getFromRelease(Database::ReleaseId releaseId, ImageSize width) override; std::shared_ptr<Image::IEncodedImage> getFromRelease(Database::ReleaseId releaseId, Image::ImageSize width) override;
void flushCache() override; void flushCache() override;
void setJpegQuality(unsigned quality) override; void setJpegQuality(unsigned quality) override;
std::shared_ptr<IEncodedImage> getFromTrack(Database::Session& dbSession, Database::TrackId trackId, ImageSize width, bool allowReleaseFallback); std::shared_ptr<Image::IEncodedImage> getFromTrack(Database::Session& dbSession, Database::TrackId trackId, Image::ImageSize width, bool allowReleaseFallback);
std::unique_ptr<IEncodedImage> getFromAvMediaFile(const Av::IAudioFile& input, ImageSize width) const; std::unique_ptr<Image::IEncodedImage> getFromAvMediaFile(const Av::IAudioFile& input, Image::ImageSize width) const;
std::unique_ptr<IEncodedImage> getFromCoverFile(const std::filesystem::path& p, ImageSize width) const; std::unique_ptr<Image::IEncodedImage> getFromCoverFile(const std::filesystem::path& p, Image::ImageSize width) const;
std::unique_ptr<IEncodedImage> getFromTrack(const std::filesystem::path& path, ImageSize width) const; std::unique_ptr<Image::IEncodedImage> getFromTrack(const std::filesystem::path& path, Image::ImageSize width) const;
std::multimap<std::string, std::filesystem::path> getCoverPaths(const std::filesystem::path& directoryPath) const; std::multimap<std::string, std::filesystem::path> getCoverPaths(const std::filesystem::path& directoryPath) const;
std::unique_ptr<IEncodedImage> getFromDirectory(const std::filesystem::path& directory, ImageSize width) const; std::unique_ptr<Image::IEncodedImage> getFromDirectory(const std::filesystem::path& directory, Image::ImageSize width) const;
std::unique_ptr<IEncodedImage> getFromSameNamedFile(const std::filesystem::path& filePath, ImageSize width) const; std::unique_ptr<Image::IEncodedImage> getFromSameNamedFile(const std::filesystem::path& filePath, Image::ImageSize width) const;
std::shared_ptr<IEncodedImage> getDefault(ImageSize width); std::shared_ptr<Image::IEncodedImage> getDefault(Image::ImageSize width);
bool checkCoverFile(const std::filesystem::path& directoryPath) const; bool checkCoverFile(const std::filesystem::path& directoryPath) const;
Database::Db& _db; Database::Db& _db;
std::shared_mutex _cacheMutex; std::shared_mutex _cacheMutex;
std::unordered_map<CacheEntryDesc, std::shared_ptr<IEncodedImage>> _cache; std::unordered_map<CacheEntryDesc, std::shared_ptr<Image::IEncodedImage>> _cache;
std::unordered_map<ImageSize, std::shared_ptr<IEncodedImage>> _defaultCoverCache; std::unordered_map<Image::ImageSize, std::shared_ptr<Image::IEncodedImage>> _defaultCoverCache;
std::atomic<std::size_t> _cacheMisses {}; std::atomic<std::size_t> _cacheMisses {};
std::atomic<std::size_t> _cacheHits {}; std::atomic<std::size_t> _cacheHits {};
std::size_t _cacheSize {}; std::size_t _cacheSize {};
void saveToCache(const CacheEntryDesc& entryDesc, std::shared_ptr<IEncodedImage> image); void saveToCache(const CacheEntryDesc& entryDesc, std::shared_ptr<Image::IEncodedImage> image);
std::shared_ptr<IEncodedImage> loadFromCache(const CacheEntryDesc& entryDesc); std::shared_ptr<Image::IEncodedImage> loadFromCache(const CacheEntryDesc& entryDesc);
const std::filesystem::path _defaultCoverPath; const std::filesystem::path _defaultCoverPath;
const std::size_t _maxCacheSize; const std::size_t _maxCacheSize;
@@ -23,7 +23,7 @@
#include <memory> #include <memory>
#include "database/Types.hpp" #include "database/Types.hpp"
#include "cover/IEncodedImage.hpp" #include "image/IEncodedImage.hpp"
namespace Database namespace Database
{ {
@@ -37,8 +37,8 @@ namespace Cover
public: public:
virtual ~ICoverService() = default; virtual ~ICoverService() = default;
virtual std::shared_ptr<IEncodedImage> getFromTrack(Database::TrackId trackId, ImageSize width) = 0; virtual std::shared_ptr<Image::IEncodedImage> getFromTrack(Database::TrackId trackId, Image::ImageSize width) = 0;
virtual std::shared_ptr<IEncodedImage> getFromRelease(Database::ReleaseId releaseId, ImageSize width) = 0; virtual std::shared_ptr<Image::IEncodedImage> getFromRelease(Database::ReleaseId releaseId, Image::ImageSize width) = 0;
virtual void flushCache() = 0; virtual void flushCache() = 0;
+1 -1
View File
@@ -19,7 +19,7 @@ target_include_directories(lmssubsonic PRIVATE
target_link_libraries(lmssubsonic PRIVATE target_link_libraries(lmssubsonic PRIVATE
lmsauth lmsauth
lmsav lmsav
lmscover lmscore
lmsdatabase lmsdatabase
lmsrecommendation lmsrecommendation
lmsscanner lmsscanner
+2 -2
View File
@@ -28,7 +28,7 @@
#include "auth/IPasswordService.hpp" #include "auth/IPasswordService.hpp"
#include "auth/IEnvService.hpp" #include "auth/IEnvService.hpp"
#include "cover/ICoverService.hpp" #include "lmscore/services/ICoverService.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Db.hpp" #include "database/Db.hpp"
@@ -1802,7 +1802,7 @@ handleGetCoverArt(RequestContext& context, const Wt::Http::Request& /*request*/,
std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").value_or(256)}; std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").value_or(256)};
size = Utils::clamp(size, std::size_t {32}, std::size_t {1024}); size = Utils::clamp(size, std::size_t {32}, std::size_t {1024});
std::shared_ptr<Cover::IEncodedImage> cover; std::shared_ptr<Image::IEncodedImage> cover;
if (trackId) if (trackId)
cover = Service<Cover::ICoverService>::get()->getFromTrack(*trackId, size); cover = Service<Cover::ICoverService>::get()->getFromTrack(*trackId, size);
else if (releaseId) else if (releaseId)
+1 -1
View File
@@ -51,7 +51,7 @@ target_include_directories(lms PRIVATE
target_link_libraries(lms PRIVATE target_link_libraries(lms PRIVATE
lmsav lmsav
lmsauth lmsauth
lmscover lmscore
lmsdatabase lmsdatabase
lmsrecommendation lmsrecommendation
lmsscanner lmsscanner
+1 -1
View File
@@ -28,7 +28,7 @@
#include "auth/IAuthTokenService.hpp" #include "auth/IAuthTokenService.hpp"
#include "auth/IPasswordService.hpp" #include "auth/IPasswordService.hpp"
#include "auth/IEnvService.hpp" #include "auth/IEnvService.hpp"
#include "cover/ICoverService.hpp" #include "lmscore/services/ICoverService.hpp"
#include "database/Db.hpp" #include "database/Db.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "scanner/IScanner.hpp" #include "scanner/IScanner.hpp"
+1 -1
View File
@@ -30,7 +30,7 @@
#include "auth/IEnvService.hpp" #include "auth/IEnvService.hpp"
#include "auth/IPasswordService.hpp" #include "auth/IPasswordService.hpp"
#include "cover/ICoverService.hpp" #include "lmscore/services/ICoverService.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Db.hpp" #include "database/Db.hpp"
+2 -2
View File
@@ -22,7 +22,7 @@
#include <Wt/WApplication.h> #include <Wt/WApplication.h>
#include <Wt/Http/Response.h> #include <Wt/Http/Response.h>
#include "cover/ICoverService.hpp" #include "lmscore/services/ICoverService.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
@@ -83,7 +83,7 @@ CoverResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons
return; return;
} }
std::shared_ptr<Cover::IEncodedImage> cover; std::shared_ptr<Image::IEncodedImage> cover;
if (trackIdStr) if (trackIdStr)
{ {
+1 -1
View File
@@ -4,7 +4,7 @@ add_executable(lms-cover
) )
target_link_libraries(lms-cover PRIVATE target_link_libraries(lms-cover PRIVATE
lmscover lmscore
Boost::program_options Boost::program_options
) )
+2 -2
View File
@@ -24,7 +24,7 @@
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include "cover/ICoverService.hpp" #include "lmscore/services/ICoverService.hpp"
#include "database/Db.hpp" #include "database/Db.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
@@ -36,7 +36,7 @@
static static
void void
dumpTrackCovers(Database::Session& session, Cover::ImageSize width) dumpTrackCovers(Database::Session& session, Image::ImageSize width)
{ {
std::vector<Database::TrackId> trackIds; std::vector<Database::TrackId> trackIds;
{ {