From 6e4fbdc3532d6545aa8d8c5810a5039edefc6b43 Mon Sep 17 00:00:00 2001 From: emeric Date: Tue, 24 Jun 2025 22:04:37 +0200 Subject: [PATCH 01/46] Fixed bad translation, ref #639 --- approot/messages_fr.xml | 2 +- approot/messages_it.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml index 54a216c9..5f332410 100644 --- a/approot/messages_fr.xml +++ b/approot/messages_fr.xml @@ -74,7 +74,7 @@ Permettre la fusion des artistes sans MBID avec ceux qui en ont un -Utilizza un'immagine dell'album se non è disponibile un'immagine dell'artista +Utiliser une image d'album si aucune image de l'artiste n'est disponible Délimiteurs à utiliser pour séparer les tags d'artistes Artistes à ne pas séparer en utilisant les délimiteurs (un artiste par ligne) Tous les jours diff --git a/approot/messages_it.xml b/approot/messages_it.xml index 95638714..00b3d031 100644 --- a/approot/messages_it.xml +++ b/approot/messages_it.xml @@ -74,7 +74,7 @@ Consentire la fusione degli artisti senza MBID con quelli che ne hanno uno -Usa l'immagine dell'album se non è disponibile un'immagine dell'artista +Utilizza un'immagine dell'album se non è disponibile un'immagine dell'artista Delimitatori da utilizzare per separare i tag degli artisti Artisti da non suddividere utilizzando i delimitatori (un artista per riga) Giornaliera From d1caed200b1b6ce8ca2a6d78e29e0746a3c5c77a Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 25 Jun 2025 13:55:45 +0200 Subject: [PATCH 02/46] Fixed bad handling of utf8 bom for playslit files, fixes #694 --- src/libs/metadata/impl/Lyrics.cpp | 15 ++++++++++----- src/libs/metadata/impl/PlayList.cpp | 10 ++++++++++ src/libs/metadata/test/PlayList.cpp | 13 +++++++++++++ .../steps/ScanStepAssociatePlayListTracks.cpp | 2 -- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/libs/metadata/impl/Lyrics.cpp b/src/libs/metadata/impl/Lyrics.cpp index 028d7cbf..45b66cc8 100644 --- a/src/libs/metadata/impl/Lyrics.cpp +++ b/src/libs/metadata/impl/Lyrics.cpp @@ -155,15 +155,20 @@ namespace lms::metadata accumulatedLyrics.clear(); }; + bool firstLine{ true }; std::string line; while (std::getline(is, line)) { - std::string_view trimmedLine{ core::stringUtils::stringTrimEnd(line) }; - // Remove potential UTF8 BOM - constexpr std::string_view utf8BOM{ "\xEF\xBB\xBF" }; - if (trimmedLine.starts_with(utf8BOM)) - trimmedLine = trimmedLine.substr(utf8BOM.size()); + if (firstLine) + { + firstLine = false; + constexpr std::string_view utf8BOM{ "\xEF\xBB\xBF" }; + if (line.starts_with(utf8BOM)) + line.erase(0, utf8BOM.size()); + } + + std::string_view trimmedLine{ core::stringUtils::stringTrimEnd(line) }; // Skip comments if (!trimmedLine.empty() && trimmedLine.front() == '#') diff --git a/src/libs/metadata/impl/PlayList.cpp b/src/libs/metadata/impl/PlayList.cpp index 4d15f9eb..ca0fadb5 100644 --- a/src/libs/metadata/impl/PlayList.cpp +++ b/src/libs/metadata/impl/PlayList.cpp @@ -63,11 +63,21 @@ namespace lms::metadata PlayList parsePlayList(std::istream& is) { + bool firstLine{ true }; PlayList playlist; std::string line; while (std::getline(is, line)) { + // Remove potential UTF8 BOM + if (firstLine) + { + firstLine = false; + constexpr std::string_view utf8BOM{ "\xEF\xBB\xBF" }; + if (line.starts_with(utf8BOM)) + line.erase(0, utf8BOM.size()); + } + const std::string_view trimmedLine{ core::stringUtils::stringTrim(line) }; if (trimmedLine.empty()) continue; diff --git a/src/libs/metadata/test/PlayList.cpp b/src/libs/metadata/test/PlayList.cpp index 165963a5..03be747c 100644 --- a/src/libs/metadata/test/PlayList.cpp +++ b/src/libs/metadata/test/PlayList.cpp @@ -19,6 +19,7 @@ */ #include +#include #include "metadata/PlayList.hpp" @@ -51,4 +52,16 @@ one to be/../one to be/normalized/foo.mp3)" }; EXPECT_EQ(playlist.files[4], "and another one/with relative path/foo.mp3"); EXPECT_EQ(playlist.files[5], "one to be/normalized/foo.mp3"); } + + TEST(PlayList, UTF8_bom) + { + const unsigned char content[] = { 0xEF, 0xBB, 0xBF, '#', 'E', 'X', 'T', 'M', '3', 'U', '\r', '\n', '\r', '\n', '.', '.', '/', 't', 'e', 's', 't', '.', 'm', 'p', '3', '\r', '\n' }; + std::istringstream is{ std::string(reinterpret_cast(content), sizeof(content)) }; + + const PlayList playlist{ parsePlayList(is) }; + EXPECT_EQ(playlist.name, ""); + ASSERT_EQ(playlist.files.size(), 1); + EXPECT_EQ(playlist.files[0], "../test.mp3"); + } + } // namespace lms::metadata::tests \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp index 7e058cb5..24308574 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp @@ -134,9 +134,7 @@ namespace lms::scanner if (track) playListAssociation.tracks.push_back(TrackInfo{ .trackId = track->getId(), .releaseId = track->getReleaseId() }); else - { pendingErrors.emplace_back(std::make_shared(playListFile->getAbsoluteFilePath(), file)); - } } if (pendingErrors.size() == files.size()) From ac84b891f618c32db3cef4f22efa9c36aa12c374 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 25 Jun 2025 22:59:55 +0200 Subject: [PATCH 03/46] Removed some useless columns in the track table --- src/libs/database/impl/Migration.cpp | 13 ++++++++++- src/libs/database/impl/Session.cpp | 2 -- src/libs/database/impl/Track.cpp | 23 ++----------------- src/libs/database/include/database/Track.hpp | 21 ----------------- src/libs/database/include/database/Types.hpp | 2 +- src/libs/database/test/Track.cpp | 2 -- .../impl/scanners/AudioFileScanOperation.cpp | 1 - .../steps/ScanStepAssociateExternalLyrics.cpp | 6 +++-- src/libs/subsonic/impl/endpoints/Browsing.cpp | 2 +- src/libs/subsonic/impl/responses/Song.cpp | 14 ++++++++++- 10 files changed, 33 insertions(+), 53 deletions(-) diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index 31532b5f..4d47cc69 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -35,7 +35,7 @@ namespace lms::db { namespace { - static constexpr Version LMS_DATABASE_VERSION{ 94 }; + static constexpr Version LMS_DATABASE_VERSION{ 95 }; } VersionInfo::VersionInfo() @@ -1386,6 +1386,16 @@ FROM artist)"); utils::executeCommand(*session.getDboSession(), "ALTER TABLE scan_settings ADD COLUMN artist_image_fallback_to_release BOOLEAN NOT NULL DEFAULT(false)"); } + void migrateFromV94(Session& session) + { + // Removed not that useful columns in track + dropIndexes(session); + + utils::executeCommand(*session.getDboSession(), "ALTER TABLE track DROP COLUMN relative_file_path"); + utils::executeCommand(*session.getDboSession(), "ALTER TABLE track DROP COLUMN file_stem"); + utils::executeCommand(*session.getDboSession(), "ALTER TABLE track DROP COLUMN file_name"); + } + bool doDbMigration(Session& session) { constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" }; @@ -1456,6 +1466,7 @@ FROM artist)"); { 91, migrateFromV91 }, { 92, migrateFromV92 }, { 93, migrateFromV93 }, + { 94, migrateFromV94 }, }; bool migrationPerformed{}; diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index deac39c9..45a4e3b9 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -275,12 +275,10 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_absolute_path_idx ON track(absolute_file_path)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_date_idx ON track(date)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_directory_release_idx ON track(directory_id, release_id);"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_directory_file_stem_idx ON track(directory_id, file_stem);"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_added_idx ON track(file_added)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_added_desc_idx ON track(file_added DESC)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_last_write_idx ON track(file_last_write)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_last_write_desc_idx ON track(file_last_write DESC)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_name_idx ON track(file_name COLLATE NOCASE)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_media_library_idx ON track(media_library_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_media_library_release_idx ON track(media_library_id, release_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_mbid_idx ON track(mbid)"); diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp index ae308b53..fc47cdcd 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/Track.cpp @@ -58,12 +58,6 @@ namespace lms::db for (std::string_view keyword : params.keywords) query.where("t.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeLikeKeyword(keyword) + "%"); - if (!params.fileStem.empty()) - query.where("t.file_stem = ?").bind(params.fileStem); - - if (!params.fileName.empty()) - query.where("t.file_name = ?").bind(params.fileName); - if (!params.name.empty()) query.where("t.name = ?").bind(params.name); @@ -212,8 +206,8 @@ namespace lms::db case TrackSortMethod::Name: query.orderBy("t.name COLLATE NOCASE"); break; - case TrackSortMethod::FileName: - query.orderBy("t.file_name COLLATE NOCASE"); + case TrackSortMethod::AbsoluteFilePath: + query.orderBy("t.absolute_file_path COLLATE NOCASE"); break; case TrackSortMethod::DateDescAndRelease: query.orderBy("t.date DESC,t.release_id,t.disc_number,t.track_number"); @@ -456,20 +450,7 @@ namespace lms::db void Track::setAbsoluteFilePath(const std::filesystem::path& filePath) { assert(filePath.is_absolute()); - _absoluteFilePath = filePath; - _fileStem = filePath.stem(); - _fileName = filePath.filename(); - } - - void Track::setRelativeFilePath(const std::filesystem::path& filePath) - { - assert(filePath.is_relative()); - - assert(_absoluteFilePath.filename() == filePath.filename()); // must be compatible with previous setAbsoluteFilePath call - _fileStem = filePath.stem(); // lazy migration (_fileStem added later, could be set only with setAbsoluteFilePath) - _fileName = filePath.filename(); // lazy migration (_fileName added later, could be set only with setAbsoluteFilePath) - _relativeFilePath = filePath; } void Track::setName(std::string_view name) diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp index f7b4cf80..9a2be947 100644 --- a/src/libs/database/include/database/Track.hpp +++ b/src/libs/database/include/database/Track.hpp @@ -72,8 +72,6 @@ namespace lms::db Filters filters; std::vector keywords; // if non empty, name must match all of these keywords std::string name; // if non empty, must match this name (title) - std::string fileStem; // if non empty, must match this file stem - std::string fileName; // if non empty, must match this file name TrackSortMethod sortMethod{ TrackSortMethod::None }; std::optional range; Wt::WDateTime writtenAfter; @@ -107,17 +105,6 @@ namespace lms::db name = _name; return *this; } - FindParameters& setFileStem(std::string_view _fileStem) - { - fileStem = _fileStem; - return *this; - } - FindParameters& setFileName(std::string_view _fileName) - { - fileName = _fileName; - return *this; - } - FindParameters& setSortMethod(TrackSortMethod _method) { sortMethod = _method; @@ -229,7 +216,6 @@ namespace lms::db void setDiscSubtitle(std::string_view name) { _discSubtitle = name; } void setName(std::string_view name); void setAbsoluteFilePath(const std::filesystem::path& filePath); - void setRelativeFilePath(const std::filesystem::path& filePath); void setFileSize(std::size_t fileSize) { _fileSize = fileSize; } void setLastWriteTime(const Wt::WDateTime& time) { _fileLastWrite = time; } void setAddedTime(const Wt::WDateTime& time) { _fileAdded = time; } @@ -270,7 +256,6 @@ namespace lms::db const std::string& getDiscSubtitle() const { return _discSubtitle; } std::string getName() const { return _name; } const std::filesystem::path& getAbsoluteFilePath() const { return _absoluteFilePath; } - const std::filesystem::path& getRelativeFilePath() const { return _relativeFilePath; } long long getFileSize() const { return _fileSize; } std::size_t getBitrate() const { return _bitrate; } std::size_t getBitsPerSample() const { return _bitsPerSample; } @@ -329,9 +314,6 @@ namespace lms::db Wt::Dbo::field(a, _date, "date"); Wt::Dbo::field(a, _originalDate, "original_date"); Wt::Dbo::field(a, _absoluteFilePath, "absolute_file_path"); - Wt::Dbo::field(a, _relativeFilePath, "relative_file_path"); - Wt::Dbo::field(a, _fileStem, "file_stem"); - Wt::Dbo::field(a, _fileName, "file_name"); Wt::Dbo::field(a, _fileSize, "file_size"); Wt::Dbo::field(a, _fileLastWrite, "file_last_write"); Wt::Dbo::field(a, _fileAdded, "file_added"); @@ -378,9 +360,6 @@ namespace lms::db core::PartialDateTime _date; core::PartialDateTime _originalDate; std::filesystem::path _absoluteFilePath; // full path - std::filesystem::path _relativeFilePath; // relative to root (that may be deleted) - std::filesystem::path _fileStem; - std::filesystem::path _fileName; long long _fileSize{}; Wt::WDateTime _fileLastWrite; Wt::WDateTime _fileAdded; diff --git a/src/libs/database/include/database/Types.hpp b/src/libs/database/include/database/Types.hpp index f7fb08dd..14a00328 100644 --- a/src/libs/database/include/database/Types.hpp +++ b/src/libs/database/include/database/Types.hpp @@ -193,7 +193,7 @@ namespace lms::db LastWrittenDesc, AddedDesc, StarredDateDesc, - FileName, + AbsoluteFilePath, Name, DateDescAndRelease, Release, // order by disc/track number diff --git a/src/libs/database/test/Track.cpp b/src/libs/database/test/Track.cpp index 3f1744e0..89bf32a6 100644 --- a/src/libs/database/test/Track.cpp +++ b/src/libs/database/test/Track.cpp @@ -343,13 +343,11 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; track.get().modify()->setAbsoluteFilePath("/root/foo/file.path"); - track.get().modify()->setRelativeFilePath("foo/file.path"); } { auto transaction{ session.createReadTransaction() }; EXPECT_EQ(track->getAbsoluteFilePath(), "/root/foo/file.path"); - EXPECT_EQ(track->getRelativeFilePath(), "foo/file.path"); } } diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index e5fcf43b..5be41052 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -650,7 +650,6 @@ namespace lms::scanner track.modify()->setDuration(_parsedTrack->audioProperties.duration); track.modify()->setSampleRate(_parsedTrack->audioProperties.sampleRate); - track.modify()->setRelativeFilePath(getRelativeFilePath()); track.modify()->setFileSize(getFileSize()); track.modify()->setLastWriteTime(getLastWriteTime()); diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp index 7765eb58..e54349a9 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp @@ -58,9 +58,11 @@ namespace lms::scanner assert(!lyrics->getFileStem().empty()); params.setDirectory(lyrics->getDirectory()->getId()); - params.setFileStem(stem); db::Track::find(session, params, [&](const db::Track::pointer& track) { + if (track->getAbsoluteFilePath().filename().stem() != stem) + return; + if (matchingTrack) LMS_LOG(DBUPDATER, DEBUG, "External lyrics '" << lyrics->getAbsoluteFilePath() << "' already matched with '" << matchingTrack->getAbsoluteFilePath() << "', replaced by '" << track->getAbsoluteFilePath() << "'"); @@ -68,7 +70,7 @@ namespace lms::scanner }); }; - // First try with the stem. If it does not match, try again with the parent steam, if it exists, to handle the file.laguagecode.lrc case + // First try with the stem. If it does not match, try again with the parent steam, if it exists, to handle the file.languagecode.lrc case tryMatch(lyrics->getFileStem()); if (!matchingTrack) { diff --git a/src/libs/subsonic/impl/endpoints/Browsing.cpp b/src/libs/subsonic/impl/endpoints/Browsing.cpp index cc1b1a5e..d36a7053 100644 --- a/src/libs/subsonic/impl/endpoints/Browsing.cpp +++ b/src/libs/subsonic/impl/endpoints/Browsing.cpp @@ -341,7 +341,7 @@ namespace lms::api::subsonic { Track::FindParameters params; params.setDirectory(directory->getId()); - params.setSortMethod(TrackSortMethod::FileName); + params.setSortMethod(TrackSortMethod::AbsoluteFilePath); Track::find(context.dbSession, params, [&](const Track::pointer& track) { directoryNode.addArrayChild("child", createSongNode(context, track, context.user)); diff --git a/src/libs/subsonic/impl/responses/Song.cpp b/src/libs/subsonic/impl/responses/Song.cpp index 7e762666..093cdc7a 100644 --- a/src/libs/subsonic/impl/responses/Song.cpp +++ b/src/libs/subsonic/impl/responses/Song.cpp @@ -19,7 +19,9 @@ #include "responses/Song.hpp" +#include #include +#include #include "core/ITraceLogger.hpp" #include "core/MimeTypes.hpp" @@ -29,6 +31,7 @@ #include "database/Artwork.hpp" #include "database/Cluster.hpp" #include "database/Directory.hpp" +#include "database/MediaLibrary.hpp" #include "database/Release.hpp" #include "database/Track.hpp" #include "database/TrackArtistLink.hpp" @@ -93,7 +96,16 @@ namespace lms::api::subsonic if (track->getYear()) trackResponse.setAttribute("year", *track->getYear()); trackResponse.setAttribute("playCount", core::Service::get()->getCount(context.user->getId(), track->getId())); - trackResponse.setAttribute("path", track->getRelativeFilePath().string()); + + // maybe not available if user just removed the library without rescanning + if (const db::MediaLibrary::pointer library{ track->getMediaLibrary() }) + { + std::error_code ec; + const std::filesystem::path relativeTrackPath{ std::filesystem::relative(track->getAbsoluteFilePath(), library->getPath(), ec) }; + if (!ec && !relativeTrackPath.empty()) + trackResponse.setAttribute("path", relativeTrackPath.c_str()); + } + trackResponse.setAttribute("size", track->getFileSize()); if (track->getAbsoluteFilePath().has_extension()) From 917c1b55b94eac6fba31a750fb9bdd21e77bac7b Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 29 Jun 2025 11:58:41 +0200 Subject: [PATCH 04/46] Added missing indexes --- src/libs/database/impl/Session.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 45a4e3b9..76012da3 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -254,6 +254,7 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS media_library_id_idx ON media_library(id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS playlist_file_id_idx ON playlist_file(id)"); + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS playlist_file_directory_idx ON playlist_file(directory_id);"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS playlist_file_absolute_file_path_idx ON playlist_file(absolute_file_path)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS rated_artist_user_artist_idx ON rated_artist(user_id,artist_id)"); @@ -316,6 +317,7 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_lyrics_id_idx ON track_lyrics(id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_lyrics_absolute_file_path_idx ON track_lyrics(absolute_file_path)"); + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_lyrics_directory_idx ON track_lyrics(directory_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_lyrics_track_idx ON track_lyrics(track_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_bookmark_user_idx ON track_bookmark(user_id)"); From d89f50d81151025b75975a955bc639803cf31120 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 29 Jun 2025 12:05:16 +0200 Subject: [PATCH 05/46] Removed useless join in query --- src/libs/database/impl/Cluster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/database/impl/Cluster.cpp b/src/libs/database/impl/Cluster.cpp index 720e040e..589b2f15 100644 --- a/src/libs/database/impl/Cluster.cpp +++ b/src/libs/database/impl/Cluster.cpp @@ -167,7 +167,7 @@ namespace lms::db { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id)); + return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(DISTINCT t.release_id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id)); } void Cluster::addTrack(ObjectPtr track) From e6f0f55b95323e81d9848733efff1540fd90b8c9 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 29 Jun 2025 18:26:44 +0200 Subject: [PATCH 06/46] Optimized artwork association with tracks --- src/libs/database/impl/Artwork.cpp | 14 ++++ src/libs/database/impl/Session.cpp | 1 + .../database/include/database/Artwork.hpp | 3 + .../database/TrackEmbeddedImageLink.hpp | 2 - src/libs/database/test/Artwork.cpp | 4 ++ .../scanner/impl/steps/ArtworkUtils.cpp | 45 ------------- .../scanner/impl/steps/ArtworkUtils.hpp | 2 - .../steps/ScanStepAssociateArtistImages.cpp | 2 +- .../steps/ScanStepAssociateReleaseImages.cpp | 2 +- .../steps/ScanStepAssociateTrackImages.cpp | 64 ++++++++----------- 10 files changed, 51 insertions(+), 88 deletions(-) diff --git a/src/libs/database/impl/Artwork.cpp b/src/libs/database/impl/Artwork.cpp index e9264f06..4dd62d4d 100644 --- a/src/libs/database/impl/Artwork.cpp +++ b/src/libs/database/impl/Artwork.cpp @@ -27,6 +27,7 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +#include "traits/PathTraits.hpp" namespace lms::db { @@ -87,4 +88,17 @@ namespace lms::db return utils::fetchQuerySingleResult(query); } + + std::filesystem::path Artwork::getAbsoluteFilePath() const + { + auto query{ session()->query("SELECT COALESCE(image.absolute_file_path, track.absolute_file_path) AS absolute_file_path FROM artwork") }; + query.leftJoin("image ON artwork.image_id = image.id"); + query.leftJoin("track_embedded_image ON artwork.track_embedded_image_id = track_embedded_image.id"); + query.leftJoin("track_embedded_image_link ON track_embedded_image.id = track_embedded_image_link.track_embedded_image_id"); + query.leftJoin("track ON track.id = track_embedded_image_link.track_id"); + query.limit(1); // there may be several tracks matching this artwork... + query.where("artwork.id = ?").bind(getId()); + + return utils::fetchQuerySingleResult(query); + } } // namespace lms::db diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 76012da3..be8d334e 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -234,6 +234,7 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_id_idx ON track_embedded_image_link(id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_track_id_idx ON track_embedded_image_link(track_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_track_embedded_image_id_track_id_idx ON track_embedded_image_link(track_embedded_image_id, track_id)"); + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_track_type_track_embedded_image_id_idx ON track_embedded_image_link(track_id, type, track_embedded_image_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_type_track_embedded_image_id_track_id_idx ON track_embedded_image_link(type,track_embedded_image_id,track_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS image_directory_stem_idx ON image(directory_id, stem COLLATE NOCASE)"); diff --git a/src/libs/database/include/database/Artwork.hpp b/src/libs/database/include/database/Artwork.hpp index 581dcc00..4873e45b 100644 --- a/src/libs/database/include/database/Artwork.hpp +++ b/src/libs/database/include/database/Artwork.hpp @@ -19,6 +19,8 @@ #pragma once +#include + #include #include @@ -48,6 +50,7 @@ namespace lms::db TrackEmbeddedImageId getTrackEmbeddedImageId() const { return _trackEmbeddedImage.id(); } ImageId getImageId() const { return _image.id(); } Wt::WDateTime getLastWrittenTime() const; + std::filesystem::path getAbsoluteFilePath() const; template void persist(Action& a) diff --git a/src/libs/database/include/database/TrackEmbeddedImageLink.hpp b/src/libs/database/include/database/TrackEmbeddedImageLink.hpp index 77dd0d2e..69335195 100644 --- a/src/libs/database/include/database/TrackEmbeddedImageLink.hpp +++ b/src/libs/database/include/database/TrackEmbeddedImageLink.hpp @@ -40,8 +40,6 @@ namespace lms::db public: TrackEmbeddedImageLink() = default; - using HashType = std::uint64_t; - // find static std::size_t getCount(Session& session); static pointer find(Session& session, TrackEmbeddedImageLinkId id); diff --git a/src/libs/database/test/Artwork.cpp b/src/libs/database/test/Artwork.cpp index 832aba0d..e0a2745e 100644 --- a/src/libs/database/test/Artwork.cpp +++ b/src/libs/database/test/Artwork.cpp @@ -48,11 +48,13 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; image.get().modify()->setLastWriteTime(dateTime); + image.get().modify()->setAbsoluteFilePath("/tmp/foo"); } { auto transaction{ session.createReadTransaction() }; EXPECT_EQ(artwork.get()->getLastWrittenTime(), dateTime); + EXPECT_EQ(artwork.get()->getAbsoluteFilePath(), "/tmp/foo"); } } @@ -73,11 +75,13 @@ namespace lms::db::tests auto transaction{ session.createWriteTransaction() }; session.create(track.get(), image.get()); track.get().modify()->setLastWriteTime(dateTime); + track.get().modify()->setAbsoluteFilePath("/tmp/foo"); } { auto transaction{ session.createReadTransaction() }; EXPECT_EQ(artwork.get()->getLastWrittenTime(), dateTime); + EXPECT_EQ(artwork.get()->getAbsoluteFilePath(), "/tmp/foo"); } } } // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/ArtworkUtils.cpp b/src/libs/services/scanner/impl/steps/ArtworkUtils.cpp index 153aca0d..e74c6095 100644 --- a/src/libs/services/scanner/impl/steps/ArtworkUtils.cpp +++ b/src/libs/services/scanner/impl/steps/ArtworkUtils.cpp @@ -27,34 +27,6 @@ namespace lms::scanner::utils { - namespace - { - std::filesystem::path toPath(db::Session& session, const db::TrackEmbeddedImageId trackEmbeddedImageId) - { - session.checkReadTransaction(); - - std::filesystem::path res; - - db::Track::FindParameters params; - params.setEmbeddedImage(trackEmbeddedImageId); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::Track::find(session, params, [&](const db::Track::pointer& track) { - res = track->getAbsoluteFilePath(); - }); - - return res; - } - - std::filesystem::path toPath(db::Session& session, db::ImageId imageId) - { - session.checkReadTransaction(); - - db::Image::pointer image{ db::Image::find(session, imageId) }; - return image ? image->getAbsoluteFilePath() : std::filesystem::path{}; - } - - } // namespace - db::ObjectPtr getOrCreateArtworkFromTrackEmbeddedImage(db::Session& session, db::TrackEmbeddedImageId trackEmbeddedImageId) { assert(trackEmbeddedImageId.isValid()); @@ -84,21 +56,4 @@ namespace lms::scanner::utils } return artwork; } - - std::filesystem::path toPath(db::Session& session, db::ArtworkId artworkId) - { - session.checkReadTransaction(); - - db::Artwork::pointer artwork{ db::Artwork::find(session, artworkId) }; - if (!artwork) - return std::filesystem::path{}; - - if (artwork->getTrackEmbeddedImageId().isValid()) - return toPath(session, artwork->getTrackEmbeddedImageId()); - if (artwork->getImageId().isValid()) - return toPath(session, artwork->getImageId()); - - return std::filesystem::path{}; - } - } // namespace lms::scanner::utils \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/ArtworkUtils.hpp b/src/libs/services/scanner/impl/steps/ArtworkUtils.hpp index 8d18b009..4dc0722b 100644 --- a/src/libs/services/scanner/impl/steps/ArtworkUtils.hpp +++ b/src/libs/services/scanner/impl/steps/ArtworkUtils.hpp @@ -36,6 +36,4 @@ namespace lms::scanner::utils { db::ObjectPtr getOrCreateArtworkFromTrackEmbeddedImage(db::Session& session, db::TrackEmbeddedImageId trackEmbeddedImageId); db::ObjectPtr getOrCreateArtworkFromImage(db::Session& session, db::ImageId imageId); - - std::filesystem::path toPath(db::Session& session, db::ArtworkId artworkId); } // namespace lms::scanner::utils \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index 5eff245d..d3e4146f 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -271,7 +271,7 @@ namespace lms::scanner artist.modify()->setPreferredArtwork(artwork); if (artwork) - LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork for artist '" << artist->getName() << "' with image in " << utils::toPath(session, artwork->getId())); + LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork for artist '" << artist->getName() << "' with image in " << artwork->getAbsoluteFilePath()); else LMS_LOG(DBUPDATER, DEBUG, "Removed preferred artwork from artist '" << artist->getName() << "'"); } diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index b6ce83d2..adba6876 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -222,7 +222,7 @@ namespace lms::scanner release.modify()->setPreferredArtwork(artwork); if (artwork) - LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork in release '" << release->getName() << "' with image in " << utils::toPath(session, artwork->getId())); + LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork in release '" << release->getName() << "' with image in " << artwork->getAbsoluteFilePath()); else LMS_LOG(DBUPDATER, DEBUG, "Removed preferred artwork from release '" << release->getName() << "'"); } diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp index 6d32e21f..035c505d 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp @@ -49,10 +49,16 @@ namespace lms::scanner return !artwork; if (const db::TrackEmbeddedImageId* trackEmbeddedImageId = std::get_if(&preferredArtwork)) + { + assert(trackEmbeddedImageId->isValid()); return artwork && *trackEmbeddedImageId == artwork->getTrackEmbeddedImageId(); + } if (const db::ArtworkId* artworkId = std::get_if(&preferredArtwork)) + { + assert(artworkId->isValid()); return artwork && *artworkId == artwork->getId(); + } return false; } @@ -77,36 +83,9 @@ namespace lms::scanner std::size_t processedTrackCount{}; }; - TrackArtwork computePreferredTrackArtwork(SearchTrackArtworkContext& searchContext, const db::Track::pointer& track) + TrackArtwork computePreferredTrackArtwork(SearchTrackArtworkContext& searchContext, const db::Track::pointer& track, TrackArtwork preferredMediaArtwork) { - // Try to get a media image - TrackArtwork res; - { - db::TrackEmbeddedImage::FindParameters params; - params.setTrack(track->getId()); - params.setImageTypes({ db::ImageType::Media }); - params.setSortMethod(db::TrackEmbeddedImageSortMethod::SizeDesc); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(searchContext.session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = image->getId(); }); - } - - if (isValid(res)) - return res; - - // Fallback on another track of the same disc - const db::ReleaseId releaseId{ track->getReleaseId() }; - if (!releaseId.isValid()) - return res; - - { - db::TrackEmbeddedImage::FindParameters params; - params.setRelease(releaseId); - params.setDiscNumber(track->getDiscNumber()); - params.setImageTypes({ db::ImageType::Media }); - params.setSortMethod(db::TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(searchContext.session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = image->getId(); }); - } + TrackArtwork res{ preferredMediaArtwork }; if (isValid(res)) return res; @@ -125,8 +104,15 @@ namespace lms::scanner return res; // Fallback on the artwork already resolved for the release + const db::ReleaseId releaseId{ track->getReleaseId() }; + if (!releaseId.isValid()) + return res; + if (const db::Release::pointer release{ db::Release::find(searchContext.session, releaseId) }) - res = release->getPreferredArtworkId(); + { + if (const db::ArtworkId releaseArtworkId{ release->getPreferredArtworkId() }; releaseArtworkId.isValid()) + res = releaseArtworkId; + } return res; } @@ -147,11 +133,15 @@ namespace lms::scanner return res; // fallback on another track of the same disc - if (const db::ReleaseId releaseId{ track->getReleaseId() }; releaseId.isValid()) + const db::ReleaseId releaseId{ track->getReleaseId() }; + if (!releaseId.isValid()) + return res; + + if (const auto discNumber{ track->getDiscNumber() }) { db::TrackEmbeddedImage::FindParameters params; params.setRelease(releaseId); - params.setDiscNumber(track->getDiscNumber()); + params.setDiscNumber(discNumber); params.setImageTypes({ db::ImageType::Media }); params.setSortMethod(db::TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); @@ -171,8 +161,8 @@ namespace lms::scanner auto transaction{ searchContext.session.createReadTransaction() }; db::Track::find(searchContext.session, searchContext.lastRetrievedTrackId, readBatchSize, [&](const db::Track::pointer& track) { - const TrackArtwork preferredArtwork{ computePreferredTrackArtwork(searchContext, track) }; const TrackArtwork preferredMediaArtwork{ computePreferredTrackMediaArtwork(searchContext, track) }; + const TrackArtwork preferredArtwork{ computePreferredTrackArtwork(searchContext, track, preferredMediaArtwork) }; const db::Artwork::pointer currentPreferredArtwork{ track->getPreferredArtwork() }; const db::Artwork::pointer currentPreferredMediaArtwork{ track->getPreferredMediaArtwork() }; @@ -180,7 +170,7 @@ namespace lms::scanner if (!isSameArtwork(preferredArtwork, currentPreferredArtwork) || !isSameArtwork(preferredMediaArtwork, currentPreferredMediaArtwork)) { - TrackArtworksAssociations.push_back(TrackArtworksAssociation{ track, preferredArtwork, preferredMediaArtwork }); + TrackArtworksAssociations.push_back(TrackArtworksAssociation{ .track = track, .preferredArtwork = preferredArtwork, .preferredMediaArtwork = preferredMediaArtwork }); } searchContext.processedTrackCount++; @@ -201,7 +191,7 @@ namespace lms::scanner // Using track.modify() is quite CPU intensive as the track class has too many fields db::Track::updatePreferredArtwork(session, track->getId(), artwork ? artwork->getId() : db::ArtworkId{}); if (artwork) - LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork in track " << track->getAbsoluteFilePath() << " with image in " << utils::toPath(session, artwork->getId())); + LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork in track " << track->getAbsoluteFilePath() << " with image in " << artwork->getAbsoluteFilePath()); else LMS_LOG(DBUPDATER, DEBUG, "Removed preferred artwork from track " << track->getAbsoluteFilePath()); } @@ -217,9 +207,9 @@ namespace lms::scanner // Using track.modify() is quite CPU intensive as the track class has too many fields db::Track::updatePreferredMediaArtwork(session, track->getId(), artwork ? artwork->getId() : db::ArtworkId{}); if (artwork) - LMS_LOG(DBUPDATER, DEBUG, "Updated preferred media artwork in track '" << track->getAbsoluteFilePath() << "' with image in " << utils::toPath(session, artwork->getId())); + LMS_LOG(DBUPDATER, DEBUG, "Updated preferred media artwork in track " << track->getAbsoluteFilePath() << " with image in " << artwork->getAbsoluteFilePath()); else - LMS_LOG(DBUPDATER, DEBUG, "Removed preferred media artwork from track '" << track->getAbsoluteFilePath() << "'"); + LMS_LOG(DBUPDATER, DEBUG, "Removed preferred media artwork from track " << track->getAbsoluteFilePath()); } void updateTrackPreferredArtworks(db::Session& session, const TrackArtworksAssociation& TrackArtworksAssociation) From 5bed2320bc1e330f8e980c711906b90963e7d158 Mon Sep 17 00:00:00 2001 From: emeric Date: Tue, 1 Jul 2025 21:15:04 +0200 Subject: [PATCH 07/46] Made some small optims when checking if files are removed --- src/libs/database/impl/ArtistInfo.cpp | 12 ++++++++ src/libs/database/impl/Image.cpp | 18 ++++++++++-- src/libs/database/impl/PlayListFile.cpp | 12 ++++++++ src/libs/database/impl/Session.cpp | 6 ++++ src/libs/database/impl/Track.cpp | 18 ++++++++++-- src/libs/database/impl/TrackLyrics.cpp | 12 ++++++++ src/libs/database/impl/Utils.hpp | 7 +++-- .../database/include/database/ArtistInfo.hpp | 1 + src/libs/database/include/database/Image.hpp | 3 +- .../include/database/PlayListFile.hpp | 1 + .../database/include/database/Session.hpp | 29 ++++++++++++++----- src/libs/database/include/database/Track.hpp | 4 ++- .../database/include/database/TrackLyrics.hpp | 1 + src/libs/database/test/ArtistInfo.cpp | 25 ++++++++++++++++ src/libs/database/test/Image.cpp | 24 +++++++++++++++ src/libs/database/test/PlayListFile.cpp | 18 ++++++++++++ src/libs/database/test/Track.cpp | 24 +++++++++++++++ src/libs/database/test/TrackLyrics.cpp | 26 +++++++++++++++++ .../steps/ScanStepCheckForRemovedFiles.cpp | 27 ++++++++--------- .../steps/ScanStepRemoveOrphanedDbEntries.cpp | 11 ++----- 20 files changed, 237 insertions(+), 42 deletions(-) diff --git a/src/libs/database/impl/ArtistInfo.cpp b/src/libs/database/impl/ArtistInfo.cpp index 9ae1a6cd..a534d307 100644 --- a/src/libs/database/impl/ArtistInfo.cpp +++ b/src/libs/database/impl/ArtistInfo.cpp @@ -124,6 +124,18 @@ namespace lms::db }); } + void ArtistInfo::findAbsoluteFilePath(Session& session, ArtistInfoId& lastRetrievedId, std::size_t count, const std::function& func) + { + session.checkReadTransaction(); + + auto query{ session.getDboSession()->query>("SELECT a_i.id, a_i.absolute_file_path FROM artist_info a_i").orderBy("a_i.id").where("a_i.id > ?").bind(lastRetrievedId).limit(static_cast(count)) }; + + utils::forEachQueryResult(query, [&](const auto& res) { + func(std::get<0>(res), std::get<1>(res)); + lastRetrievedId = std::get<0>(res); + }); + } + Artist::pointer ArtistInfo::getArtist() const { return _artist; diff --git a/src/libs/database/impl/Image.cpp b/src/libs/database/impl/Image.cpp index e0d43c4d..4b5bbd5a 100644 --- a/src/libs/database/impl/Image.cpp +++ b/src/libs/database/impl/Image.cpp @@ -77,15 +77,15 @@ namespace lms::db return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT i from image i").where("i.absolute_file_path = ?").bind(file)); } - void Image::find(Session& session, ImageId& lastRetrievedImage, std::size_t count, const std::function& func) + void Image::find(Session& session, ImageId& lastRetrievedId, std::size_t count, const std::function& func) { session.checkReadTransaction(); - auto query{ session.getDboSession()->query>("SELECT i from image i").orderBy("i.id").where("i.id > ?").bind(lastRetrievedImage).limit(static_cast(count)) }; + auto query{ session.getDboSession()->query>("SELECT i from image i").orderBy("i.id").where("i.id > ?").bind(lastRetrievedId).limit(static_cast(count)) }; utils::forEachQueryResult(query, [&](const Image::pointer& image) { func(image); - lastRetrievedImage = image->getId(); + lastRetrievedId = image->getId(); }); } @@ -105,6 +105,18 @@ namespace lms::db }); } + void Image::findAbsoluteFilePath(Session& session, ImageId& lastRetrievedId, std::size_t count, const std::function& func) + { + session.checkReadTransaction(); + + auto query{ session.getDboSession()->query>("SELECT i.id,i.absolute_file_path from image i").orderBy("i.id").where("i.id > ?").bind(lastRetrievedId).limit(static_cast(count)) }; + + utils::forEachQueryResult(query, [&](const auto& res) { + func(std::get<0>(res), std::get<1>(res)); + lastRetrievedId = std::get<0>(res); + }); + } + void Image::setAbsoluteFilePath(const std::filesystem::path& p) { assert(p.is_absolute()); diff --git a/src/libs/database/impl/PlayListFile.cpp b/src/libs/database/impl/PlayListFile.cpp index 8d60ed03..49226d58 100644 --- a/src/libs/database/impl/PlayListFile.cpp +++ b/src/libs/database/impl/PlayListFile.cpp @@ -71,6 +71,18 @@ namespace lms::db }); } + void PlayListFile::findAbsoluteFilePath(Session& session, PlayListFileId& lastRetrievedId, std::size_t count, const std::function& func) + { + session.checkReadTransaction(); + + auto query{ session.getDboSession()->query>("SELECT pl_f.id, pl_f.absolute_file_path FROM playlist_file pl_f").orderBy("pl_f.id").where("pl_f.id > ?").bind(lastRetrievedId).limit(static_cast(count)) }; + + utils::forEachQueryResult(query, [&](const auto& res) { + func(std::get<0>(res), std::get<1>(res)); + lastRetrievedId = std::get<0>(res); + }); + } + PlayListFile::pointer PlayListFile::find(Session& session, PlayListFileId id) { session.checkReadTransaction(); diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index be8d334e..48b89a13 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -427,4 +427,10 @@ namespace lms::db } LMS_LOG(DB, DEBUG, "Analyzing " << entry << ": done!"); } + + void Session::execute(std::string_view query, long long id) + { + utils::executeCommand(_session, query, id); + } + } // namespace lms::db diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp index fc47cdcd..63220d86 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/Track.cpp @@ -265,18 +265,30 @@ namespace lms::db return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT t from track t").where("t.id = ?").bind(id)); } - void Track::find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function& func, MediaLibraryId library) + void Track::find(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func, MediaLibraryId library) { session.checkReadTransaction(); - auto query{ session.getDboSession()->query>("SELECT t from track t").orderBy("t.id").where("t.id > ?").bind(lastRetrievedTrack).limit(static_cast(count)) }; + auto query{ session.getDboSession()->query>("SELECT t from track t").orderBy("t.id").where("t.id > ?").bind(lastRetrievedId).limit(static_cast(count)) }; if (library.isValid()) query.where("media_library_id = ?").bind(library); utils::forEachQueryResult(query, [&](const Track::pointer& track) { func(track); - lastRetrievedTrack = track->getId(); + lastRetrievedId = track->getId(); + }); + } + + void Track::findAbsoluteFilePath(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func) + { + session.checkReadTransaction(); + + auto query{ session.getDboSession()->query>("SELECT t.id,t.absolute_file_path from track t").orderBy("t.id").where("t.id > ?").bind(lastRetrievedId).limit(static_cast(count)) }; + + utils::forEachQueryResult(query, [&](const auto& res) { + func(std::get<0>(res), std::get<1>(res)); + lastRetrievedId = std::get<0>(res); }); } diff --git a/src/libs/database/impl/TrackLyrics.cpp b/src/libs/database/impl/TrackLyrics.cpp index 18779f55..2f71e8fd 100644 --- a/src/libs/database/impl/TrackLyrics.cpp +++ b/src/libs/database/impl/TrackLyrics.cpp @@ -126,6 +126,18 @@ namespace lms::db return utils::execRangeQuery(query, range); } + void TrackLyrics::findAbsoluteFilePath(Session& session, TrackLyricsId& lastRetrievedId, std::size_t count, const std::function& func) + { + session.checkReadTransaction(); + + auto query{ session.getDboSession()->query>("SELECT t_lrc.id,t_lrc.absolute_file_path from track_lyrics t_lrc").orderBy("t_lrc.id").where("t_lrc.id > ?").bind(lastRetrievedId).limit(static_cast(count)) }; + + utils::forEachQueryResult(query, [&](const auto& res) { + func(std::get<0>(res), std::get<1>(res)); + lastRetrievedId = std::get<0>(res); + }); + } + TrackLyrics::SynchronizedLines TrackLyrics::getSynchronizedLines() const { SynchronizedLines synchronizedLines; diff --git a/src/libs/database/impl/Utils.hpp b/src/libs/database/impl/Utils.hpp index 59e83a81..1fe3fc19 100644 --- a/src/libs/database/impl/Utils.hpp +++ b/src/libs/database/impl/Utils.hpp @@ -175,10 +175,13 @@ namespace lms::db::utils template void executeCommand(Wt::Dbo::Session& session, std::string_view command, const Args&... args) { - LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ExecuteCommand", "Command", command); - Wt::Dbo::Call call{ session.execute(std::string{ command }) }; (call.bind(args), ...); + + { + LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ExecuteCommand", "Command", command); + call.run(); + } } Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime); diff --git a/src/libs/database/include/database/ArtistInfo.hpp b/src/libs/database/include/database/ArtistInfo.hpp index 381fbca2..7f6b95a6 100644 --- a/src/libs/database/include/database/ArtistInfo.hpp +++ b/src/libs/database/include/database/ArtistInfo.hpp @@ -53,6 +53,7 @@ namespace lms::db static void find(Session& session, ArtistInfoId& lastRetrievedId, std::size_t count, const std::function& func); static void findArtistNameNoLongerMatch(Session& session, std::optional range, const std::function& func); static void findWithArtistNameAmbiguity(Session& session, std::optional range, bool allowArtistMBIDFallback, const std::function& func); + static void findAbsoluteFilePath(Session& session, ArtistInfoId& lastRetrievedId, std::size_t count, const std::function& func); // getters std::size_t getScanVersion() const { return _scanVersion; } diff --git a/src/libs/database/include/database/Image.hpp b/src/libs/database/include/database/Image.hpp index 5361fabc..a8eeb195 100644 --- a/src/libs/database/include/database/Image.hpp +++ b/src/libs/database/include/database/Image.hpp @@ -69,7 +69,8 @@ namespace lms::db static pointer find(Session& session, const std::filesystem::path& file); static RangeResults find(Session& session, const FindParameters& params); static void find(Session& session, const FindParameters& parameters, const std::function& func); - static void find(Session& session, ImageId& lastRetrievedImage, std::size_t count, const std::function& func); + static void find(Session& session, ImageId& lastRetrievedId, std::size_t count, const std::function& func); + static void findAbsoluteFilePath(Session& session, ImageId& lastRetrievedId, std::size_t count, const std::function& func); // getters const std::filesystem::path& getAbsoluteFilePath() const { return _fileAbsolutePath; } diff --git a/src/libs/database/include/database/PlayListFile.hpp b/src/libs/database/include/database/PlayListFile.hpp index 0eaccae3..568d4dbb 100644 --- a/src/libs/database/include/database/PlayListFile.hpp +++ b/src/libs/database/include/database/PlayListFile.hpp @@ -49,6 +49,7 @@ namespace lms::db static pointer find(Session& session, PlayListFileId id); static pointer find(Session& session, const std::filesystem::path& path); static void find(Session& session, PlayListFileId& lastRetrievedId, std::size_t count, const std::function& func); + static void findAbsoluteFilePath(Session& session, PlayListFileId& lastRetrievedId, std::size_t count, const std::function& func); // getters const std::filesystem::path& getAbsoluteFilePath() const { return _absoluteFilePath; } diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index e1b4cd66..663231be 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -106,14 +107,8 @@ namespace lms::db void refreshTracingLoggerStats(); // returning a ptr here to ease further wrapping using operator-> - Wt::Dbo::Session* getDboSession() - { - return &_session; - } - Db& getDb() - { - return _db; - } + Wt::Dbo::Session* getDboSession() { return &_session; } + Db& getDb() { return _db; } template typename Object::pointer create(Args&&... args) @@ -126,7 +121,25 @@ namespace lms::db return res; } + template + void destroy(typename Object::IdType id) + { + destroy(std::span{ &id, 1 }); + } + + template + void destroy(std::span ids) + { + checkWriteTransaction(); + + const std::string query{ std::string{ "DELETE FROM " } + _session.tableName() + " WHERE id = ?" }; + for (typename Object::IdType id : ids) + execute(query, id.getValue()); + } + private: + void execute(std::string_view query, long long id); + Db& _db; Wt::Dbo::Session _session; }; diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp index 9a2be947..293d1055 100644 --- a/src/libs/database/include/database/Track.hpp +++ b/src/libs/database/include/database/Track.hpp @@ -191,7 +191,9 @@ namespace lms::db static std::size_t getCount(Session& session); static pointer findByPath(Session& session, const std::filesystem::path& p); static pointer find(Session& session, TrackId id); - static void find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function& func, MediaLibraryId library = {}); + static void find(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func, MediaLibraryId library = {}); + static void findAbsoluteFilePath(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func); + static bool exists(Session& session, TrackId id); static std::vector findByRecordingMBID(Session& session, const core::UUID& MBID); static std::vector findByMBID(Session& session, const core::UUID& MBID); diff --git a/src/libs/database/include/database/TrackLyrics.hpp b/src/libs/database/include/database/TrackLyrics.hpp index fbb49629..d89c46d8 100644 --- a/src/libs/database/include/database/TrackLyrics.hpp +++ b/src/libs/database/include/database/TrackLyrics.hpp @@ -82,6 +82,7 @@ namespace lms::db static void find(Session& session, const FindParameters& params, const std::function& func); static void find(Session& session, TrackLyricsId& lastRetrievedId, std::size_t count, const std::function& func); static RangeResults findOrphanIds(Session& session, std::optional range); + static void findAbsoluteFilePath(Session& session, TrackLyricsId& lastRetrievedId, std::size_t count, const std::function& func); using SynchronizedLines = std::map; diff --git a/src/libs/database/test/ArtistInfo.cpp b/src/libs/database/test/ArtistInfo.cpp index ced776ed..3146e05f 100644 --- a/src/libs/database/test/ArtistInfo.cpp +++ b/src/libs/database/test/ArtistInfo.cpp @@ -208,4 +208,29 @@ namespace lms::db::tests ASSERT_TRUE(visited); } } + + TEST_F(DatabaseFixture, ArtistInfo_findAbsoluteFilePath) + { + ScopedArtistInfo artistInfo{ session }; + + const std::filesystem::path absoluteFilePath{ "/path/to/artist.nfo" }; + { + auto transaction{ session.createWriteTransaction() }; + artistInfo.get().modify()->setAbsoluteFilePath(absoluteFilePath); + } + + { + auto transaction{ session.createReadTransaction() }; + + ArtistInfoId lastRetrievedId; + + std::filesystem::path retrievedFilePath; + ArtistInfo::findAbsoluteFilePath(session, lastRetrievedId, 1, [&](ArtistInfoId artistInfoId, const std::filesystem::path& filePath) { + EXPECT_EQ(artistInfoId, artistInfo.getId()); + retrievedFilePath = filePath; + }); + + EXPECT_EQ(retrievedFilePath, absoluteFilePath); + } + } } // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/Image.cpp b/src/libs/database/test/Image.cpp index b32cdd5f..1bed6697 100644 --- a/src/libs/database/test/Image.cpp +++ b/src/libs/database/test/Image.cpp @@ -98,4 +98,28 @@ namespace lms::db::tests EXPECT_EQ(results.front()->getId(), image.getId()); } } + + TEST_F(DatabaseFixture, Image_findAbsoluteFilePath) + { + ScopedImage image{ session, "/path/to/image" }; + + const std::filesystem::path absoluteFilePath{ "/path/to/image" }; + { + auto transaction{ session.createWriteTransaction() }; + image.get().modify()->setAbsoluteFilePath(absoluteFilePath); + } + + { + auto transaction{ session.createReadTransaction() }; + ImageId lastRetrievedImageId; + std::filesystem::path retrievedPath; + Image::findAbsoluteFilePath(session, lastRetrievedImageId, 1, [&](ImageId id, const std::filesystem::path& path) { + EXPECT_EQ(id, image.getId()); + retrievedPath = path; + }); + + EXPECT_EQ(retrievedPath, absoluteFilePath); + } + } + } // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/PlayListFile.cpp b/src/libs/database/test/PlayListFile.cpp index e0011eeb..c508c79d 100644 --- a/src/libs/database/test/PlayListFile.cpp +++ b/src/libs/database/test/PlayListFile.cpp @@ -85,6 +85,24 @@ namespace lms::db::tests } } + TEST_F(DatabaseFixture, PlayListFile_findAbsoluteFilePath) + { + ScopedPlayListFile playlist{ session, "/tmp/foo.m3u" }; + + { + auto transaction{ session.createReadTransaction() }; + + PlayListFileId lastRetrievedId; + std::filesystem::path retrievedFilePath; + PlayListFile::findAbsoluteFilePath(session, lastRetrievedId, 1, [&](PlayListFileId playListFileId, const std::filesystem::path& filePath) { + EXPECT_EQ(playListFileId, playlist.getId()); + retrievedFilePath = filePath; + }); + + EXPECT_EQ(retrievedFilePath, "/tmp/foo.m3u"); + } + } + TEST_F(DatabaseFixture, PlayListFile_deleteTrackList) { { diff --git a/src/libs/database/test/Track.cpp b/src/libs/database/test/Track.cpp index 89bf32a6..517900d9 100644 --- a/src/libs/database/test/Track.cpp +++ b/src/libs/database/test/Track.cpp @@ -151,6 +151,30 @@ namespace lms::db::tests } } + TEST_F(DatabaseFixture, Track_findAbsoluteFilePath) + { + ScopedTrack track{ session }; + const std::filesystem::path absoluteFilePath{ "/path/to/track.mp3" }; + { + auto transaction{ session.createWriteTransaction() }; + track.get().modify()->setAbsoluteFilePath(absoluteFilePath); + } + + { + auto transaction{ session.createReadTransaction() }; + + TrackId lastRetrievedTrackId; + std::vector> visitedTracks; + Track::findAbsoluteFilePath(session, lastRetrievedTrackId, 10, [&](TrackId trackId, const std::filesystem::path& filePath) { + visitedTracks.emplace_back(trackId, filePath); + }); + ASSERT_EQ(visitedTracks.size(), 1); + EXPECT_EQ(visitedTracks[0].first, track.getId()); + EXPECT_EQ(visitedTracks[0].second, absoluteFilePath); + EXPECT_EQ(lastRetrievedTrackId, track.getId()); + } + } + TEST_F(DatabaseFixture, Track_MediaLibrary) { ScopedTrack track{ session }; diff --git a/src/libs/database/test/TrackLyrics.cpp b/src/libs/database/test/TrackLyrics.cpp index 323c69cc..79e91824 100644 --- a/src/libs/database/test/TrackLyrics.cpp +++ b/src/libs/database/test/TrackLyrics.cpp @@ -26,6 +26,32 @@ namespace lms::db::tests { using ScopedTrackLyrics = ScopedEntity; + TEST_F(DatabaseFixture, TrackLyrics_findAbsoluteFilePath) + { + ScopedTrack track{ session }; + ScopedTrackLyrics lyrics{ session }; + + { + auto transaction{ session.createWriteTransaction() }; + + TrackLyrics::pointer dbLyrics{ lyrics.get() }; + + dbLyrics.modify()->setAbsoluteFilePath("/tmp/test.lrc"); + dbLyrics.modify()->setTrack(track.get()); + } + { + auto transaction{ session.createReadTransaction() }; + + TrackLyricsId lastRetrievedId; + std::filesystem::path retrievedFilePath; + TrackLyrics::findAbsoluteFilePath(session, lastRetrievedId, 1, [&](TrackLyricsId trackLyricsId, const std::filesystem::path& absoluteFilePath) { + EXPECT_EQ(trackLyricsId, lyrics.getId()); + retrievedFilePath = absoluteFilePath; + }); + EXPECT_EQ(retrievedFilePath, "/tmp/test.lrc"); + } + } + TEST_F(DatabaseFixture, TrackLyrics_synchronized) { using namespace std::chrono_literals; diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index e1707efb..3ab0c0c8 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -74,7 +74,7 @@ namespace lms::scanner Session& session{ _db.getTLSSession() }; - std::vector objectsToRemove; + std::vector objectIdsToRemove; typename Object::IdType lastCheckedId; bool endReached{}; @@ -83,39 +83,36 @@ namespace lms::scanner if (_abortScan) break; - objectsToRemove.clear(); + objectIdsToRemove.clear(); { - constexpr std::size_t batchSize = 100; + constexpr std::size_t batchSize = 200; auto transaction{ session.createReadTransaction() }; endReached = true; - Object::find(session, lastCheckedId, batchSize, [&](const typename Object::pointer& object) { + Object::findAbsoluteFilePath(session, lastCheckedId, batchSize, [&](Object::IdType objectId, const std::filesystem::path& filePath) { endReached = false; // special case for track lyrics, only check external lyrics if constexpr (std::is_same_v) { - if (object->getAbsoluteFilePath().empty()) + if (filePath.empty()) return; } - if (!checkFile(object->getAbsoluteFilePath())) - objectsToRemove.push_back(object); + if (!checkFile(filePath)) + objectIdsToRemove.push_back(objectId); context.currentStepStats.processedElems++; }); } - if (!objectsToRemove.empty()) + if (!objectIdsToRemove.empty()) { auto transaction{ session.createWriteTransaction() }; - for (typename Object::pointer& object : objectsToRemove) - { - object.remove(); - context.stats.deletions++; - } + session.destroy(objectIdsToRemove); + context.stats.deletions += objectIdsToRemove.size(); } _progressCallback(context.currentStepStats); @@ -145,7 +142,7 @@ namespace lms::scanner if (!selectFileScanner(p)) { - LMS_LOG(DBUPDATER, DEBUG, "Removing " << p.string() << ": file format no longer handled"); + LMS_LOG(DBUPDATER, DEBUG, "Removing " << p << ": file format no longer handled"); return false; } @@ -153,7 +150,7 @@ namespace lms::scanner } catch (std::filesystem::filesystem_error& e) { - LMS_LOG(DBUPDATER, ERROR, "Caught exception while checking file '" << p.string() << "': " << e.what()); + LMS_LOG(DBUPDATER, ERROR, "Caught exception while checking file " << p << ": " << e.what()); return false; } } diff --git a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp index 360331bd..e665422a 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp @@ -109,7 +109,7 @@ namespace lms::scanner template void ScanStepRemoveOrphanedDbEntries::removeOrphanedEntries(ScanContext& context) { - constexpr std::size_t batchSize = 100; + constexpr std::size_t batchSize = 200; using IdType = typename T::IdType; @@ -130,14 +130,7 @@ namespace lms::scanner { auto transaction{ session.createWriteTransaction() }; - for (const IdType objectId : entries.results) - { - if (_abortScan) - break; - - typename T::pointer entry{ T::find(session, objectId) }; - entry.remove(); - } + session.destroy(entries.results); } context.currentStepStats.processedElems += entries.results.size(); From 7989b68603271cf9c34fcf72ec2104b30f52e2e2 Mon Sep 17 00:00:00 2001 From: emeric Date: Tue, 1 Jul 2025 21:15:31 +0200 Subject: [PATCH 08/46] Bumped packages --- Dockerfile-release | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile-release b/Dockerfile-release index 69ae0be3..2521139e 100644 --- a/Dockerfile-release +++ b/Dockerfile-release @@ -1,4 +1,4 @@ -FROM alpine:3.21.3 AS build +FROM alpine:3.22 AS build WORKDIR /tmp/workdir @@ -79,7 +79,7 @@ RUN \ make -j$(nproc) install # WT -ARG WT_VERSION=4.11.3 +ARG WT_VERSION=4.11.4 ARG WT_DEBUG=OFF RUN \ DIR=/tmp/wt && mkdir -p ${DIR} && cd ${DIR} && \ @@ -101,7 +101,7 @@ RUN \ cp ./*.h ${PREFIX}/include/stb # TAGLIB -ARG TAGLIB_VERSION=v2.0.2 +ARG TAGLIB_VERSION=v2.1.1 RUN \ DIR=/tmp/taglib && mkdir -p ${DIR} && cd ${DIR} && \ curl -sLO https://github.com/taglib/taglib/archive/${TAGLIB_VERSION}.tar.gz && \ @@ -145,7 +145,7 @@ RUN \ rm -rf /tmp/fakeroot/share/Wt/resources/themes ## Release Stage -FROM alpine:3.21.3 AS release +FROM alpine:3.22 AS release LABEL maintainer="Emeric Poupon " ARG RUNTIME_PACKAGES=" \ From c9395fefa5e8eec9bc4bb1b75b94382de9e9cc93 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 2 Jul 2025 13:39:22 +0200 Subject: [PATCH 09/46] Subsonic API: added missing releaseDate in Album node, fixes #701 --- src/libs/subsonic/impl/responses/Album.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/subsonic/impl/responses/Album.cpp b/src/libs/subsonic/impl/responses/Album.cpp index 914d79f1..767e5fa3 100644 --- a/src/libs/subsonic/impl/responses/Album.cpp +++ b/src/libs/subsonic/impl/responses/Album.cpp @@ -198,6 +198,7 @@ namespace lms::api::subsonic albumNode.setAttribute("displayArtist", ""); } albumNode.addChild("originalReleaseDate", createItemDateNode(release->getOriginalDate())); + albumNode.addChild("releaseDate", createItemDateNode(release->getDate())); albumNode.setAttribute("isCompilation", release->isCompilation()); From 376316da149f6e50d4544cc9643e4d5547cc5c93 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 2 Jul 2025 21:18:04 +0200 Subject: [PATCH 10/46] Moved code to scan files in parallel at upper level to ease reuse --- conf/lms.conf | 4 +- src/libs/core/CMakeLists.txt | 1 + src/libs/core/impl/JobScheduler.cpp | 129 ++++++++++++++++++ src/libs/core/impl/JobScheduler.hpp | 61 +++++++++ src/libs/core/include/core/IJob.hpp | 32 +++++ src/libs/core/include/core/IJobScheduler.hpp | 48 +++++++ src/libs/core/test/CMakeLists.txt | 1 + src/libs/core/test/JobScheduler.cpp | 90 ++++++++++++ .../database/include/database/Session.hpp | 10 +- src/libs/services/scanner/CMakeLists.txt | 1 - .../services/scanner/impl/ScannerService.cpp | 17 +++ .../services/scanner/impl/ScannerService.hpp | 10 +- .../scanner/impl/steps/FileScanQueue.cpp | 111 --------------- .../scanner/impl/steps/FileScanQueue.hpp | 62 --------- .../scanner/impl/steps/ScanStepBase.cpp | 1 + .../scanner/impl/steps/ScanStepBase.hpp | 8 ++ .../scanner/impl/steps/ScanStepScanFiles.cpp | 80 +++++++---- .../scanner/impl/steps/ScanStepScanFiles.hpp | 11 +- 18 files changed, 467 insertions(+), 210 deletions(-) create mode 100644 src/libs/core/impl/JobScheduler.cpp create mode 100644 src/libs/core/impl/JobScheduler.hpp create mode 100644 src/libs/core/include/core/IJob.hpp create mode 100644 src/libs/core/include/core/IJobScheduler.hpp create mode 100644 src/libs/core/test/JobScheduler.cpp delete mode 100644 src/libs/services/scanner/impl/steps/FileScanQueue.cpp delete mode 100644 src/libs/services/scanner/impl/steps/FileScanQueue.hpp diff --git a/conf/lms.conf b/conf/lms.conf index 1c2dfa12..0ae9ebea 100644 --- a/conf/lms.conf +++ b/conf/lms.conf @@ -118,5 +118,5 @@ scanner-skip-duplicate-mbid = false; # Scanner read style for metadata, may be 'fast', 'average' or 'accurate' scanner-parser-read-style = "average"; -# Number of threads to use for scanning file metadata (0 means number of logical CPUs / 2) -scanner-metadata-thread-count = 0; \ No newline at end of file +# Number of threads to use for parallelized tasks (e.g., scanning file metadata). 0 means half the number of logical CPUs. +scanner-thread-count = 0; \ No newline at end of file diff --git a/src/libs/core/CMakeLists.txt b/src/libs/core/CMakeLists.txt index 8ce177b5..0eb0675e 100644 --- a/src/libs/core/CMakeLists.txt +++ b/src/libs/core/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(lmscore STATIC impl/ChildProcessManager.cpp impl/Config.cpp impl/FileResourceHandler.cpp + impl/JobScheduler.cpp impl/IOContextRunner.cpp impl/Logger.cpp impl/MimeTypes.cpp diff --git a/src/libs/core/impl/JobScheduler.cpp b/src/libs/core/impl/JobScheduler.cpp new file mode 100644 index 00000000..49e97b46 --- /dev/null +++ b/src/libs/core/impl/JobScheduler.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include "JobScheduler.hpp" + +#include + +#include "core/ITraceLogger.hpp" + +#include "core/IJob.hpp" + +namespace lms::core +{ + std::unique_ptr createJobScheduler(core::LiteralString name, std::size_t threadCount) + { + return std::make_unique(name, threadCount); + } + + JobScheduler::JobScheduler(core::LiteralString name, std::size_t threadCount) + : _name{ name } + , _ioContextRunner{ _ioContext, threadCount, name.str() } + { + } + + JobScheduler::~JobScheduler() = default; + + void JobScheduler::setShouldAbortCallback(ShouldAbortCallback callback) + { + _abortCallback = callback; + } + + std::size_t JobScheduler::getThreadCount() const + { + return _ioContextRunner.getThreadCount(); + } + + void JobScheduler::scheduleJob(std::unique_ptr job) + { + { + std::scoped_lock lock{ _mutex }; + _ongoingJobCount += 1; + } + + auto jobHandler{ [job = std::move(job), this]() mutable { + if (_abortCallback && _abortCallback()) + { + std::scoped_lock lock{ _mutex }; + _ongoingJobCount -= 1; + } + else + { + { + LMS_SCOPED_TRACE_OVERVIEW(_name, job->getName()); + job->run(); + } + + { + std::scoped_lock lock{ _mutex }; + + _doneJobs.emplace_back(std::move(job)); + _ongoingJobCount -= 1; + } + } + + _condVar.notify_all(); + } }; + + boost::asio::post(_ioContext, std::move(jobHandler)); + } + + std::size_t JobScheduler::getJobsDoneCount() const + { + std::scoped_lock lock{ _mutex }; + return _doneJobs.size(); + } + + size_t JobScheduler::popJobsDone(std::vector>& doneJobs, std::size_t maxCount) + { + doneJobs.clear(); + doneJobs.reserve(maxCount); + + { + std::scoped_lock lock{ _mutex }; + + while (doneJobs.size() < maxCount && !_doneJobs.empty()) + { + doneJobs.push_back(std::move(_doneJobs.front())); + _doneJobs.pop_front(); + } + } + + return doneJobs.size(); + } + + void JobScheduler::waitUntilJobCountAtMost(std::size_t maxOngoingJobs) + { + if (_ongoingJobCount <= maxOngoingJobs) + return; + + { + LMS_SCOPED_TRACE_OVERVIEW(_name, "WaitJobs"); + + std::unique_lock lock{ _mutex }; + _condVar.wait(lock, [=, this] { return _ongoingJobCount <= maxOngoingJobs; }); + } + } + + void JobScheduler::wait() + { + waitUntilJobCountAtMost(0); + } + +} // namespace lms::core diff --git a/src/libs/core/impl/JobScheduler.hpp b/src/libs/core/impl/JobScheduler.hpp new file mode 100644 index 00000000..2511fef6 --- /dev/null +++ b/src/libs/core/impl/JobScheduler.hpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include +#include +#include +#include + +#include "core/IJobScheduler.hpp" +#include "core/IOContextRunner.hpp" + +namespace lms::core +{ + class JobScheduler : public IJobScheduler + { + public: + JobScheduler(core::LiteralString name, std::size_t threadCount); + ~JobScheduler() override; + JobScheduler(const JobScheduler&) = delete; + JobScheduler& operator=(const JobScheduler&) = delete; + + private: + void setShouldAbortCallback(ShouldAbortCallback callback) override; + + std::size_t getThreadCount() const override; + void scheduleJob(std::unique_ptr job) override; + + std::size_t getJobsDoneCount() const override; + size_t popJobsDone(std::vector>& jobs, std::size_t maxCount) override; + + void waitUntilJobCountAtMost(std::size_t maxOngoingJobs) override; + void wait() override; + + core::LiteralString _name; + boost::asio::io_context _ioContext; + core::IOContextRunner _ioContextRunner; + + ShouldAbortCallback _abortCallback; + + mutable std::mutex _mutex; + std::atomic _ongoingJobCount; + std::deque> _doneJobs; + std::condition_variable _condVar; + }; +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/IJob.hpp b/src/libs/core/include/core/IJob.hpp new file mode 100644 index 00000000..eba2ea44 --- /dev/null +++ b/src/libs/core/include/core/IJob.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include "core/LiteralString.hpp" + +namespace lms::core +{ + class IJob + { + public: + virtual ~IJob() = default; + + virtual LiteralString getName() const = 0; + virtual void run() = 0; + }; +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/IJobScheduler.hpp b/src/libs/core/include/core/IJobScheduler.hpp new file mode 100644 index 00000000..f8eed21e --- /dev/null +++ b/src/libs/core/include/core/IJobScheduler.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include +#include +#include + +#include "core/LiteralString.hpp" + +namespace lms::core +{ + class IJob; + class IJobScheduler + { + public: + virtual ~IJobScheduler() = default; + + using ShouldAbortCallback = std::function; + virtual void setShouldAbortCallback(ShouldAbortCallback callback) = 0; + + virtual std::size_t getThreadCount() const = 0; + virtual void scheduleJob(std::unique_ptr job) = 0; + + virtual std::size_t getJobsDoneCount() const = 0; + virtual size_t popJobsDone(std::vector>& jobs, std::size_t maxCount) = 0; + + virtual void waitUntilJobCountAtMost(std::size_t maxOngoingJobs) = 0; + virtual void wait() = 0; + }; + + std::unique_ptr createJobScheduler(core::LiteralString name, std::size_t threadCount); +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/test/CMakeLists.txt b/src/libs/core/test/CMakeLists.txt index 3e89617a..82ee61a3 100644 --- a/src/libs/core/test/CMakeLists.txt +++ b/src/libs/core/test/CMakeLists.txt @@ -2,6 +2,7 @@ include(GoogleTest) add_executable(test-core EnumSet.cpp + JobScheduler.cpp LiteralString.cpp PartialDateTime.cpp Path.cpp diff --git a/src/libs/core/test/JobScheduler.cpp b/src/libs/core/test/JobScheduler.cpp new file mode 100644 index 00000000..d1cedaa5 --- /dev/null +++ b/src/libs/core/test/JobScheduler.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include + +#include + +#include "core/IJob.hpp" +#include "core/IJobScheduler.hpp" + +namespace lms::core +{ + namespace + { + class TestJob : public IJob + { + public: + TestJob(std::atomic& count) + : workCount(count) {} + + private: + LiteralString getName() const override { return "test"; }; + void run() override + { + // Simulate some work + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + ++workCount; + } + + std::atomic& workCount; + }; + + } // namespace + TEST(JobScheduler, basic) + { + std::atomic workCount{ 0 }; + + auto scheduler{ createJobScheduler("TestScheduler", 2) }; + ASSERT_NE(scheduler, nullptr); + + for (int i = 0; i < 10; ++i) + scheduler->scheduleJob(std::make_unique(workCount)); + + // Wait for all jobs to complete + scheduler->wait(); + EXPECT_EQ(workCount.load(), 10); + + std::vector> doneJobs; + scheduler->popJobsDone(doneJobs, 10); + EXPECT_EQ(doneJobs.size(), 10); + } + + TEST(JobScheduler, abort) + { + std::atomic workCount{ 0 }; + + auto scheduler{ createJobScheduler("TestScheduler", 2) }; + ASSERT_NE(scheduler, nullptr); + + scheduler->setShouldAbortCallback([] { return true; }); + + for (int i = 0; i < 10; ++i) + scheduler->scheduleJob(std::make_unique(workCount)); + + // Wait for all jobs to complete + scheduler->wait(); + EXPECT_EQ(workCount.load(), 0); // nothing was done + + std::vector> doneJobs; + scheduler->popJobsDone(doneJobs, 10); + EXPECT_EQ(doneJobs.size(), 0); + } + +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index 663231be..88b0c7d9 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -107,8 +107,14 @@ namespace lms::db void refreshTracingLoggerStats(); // returning a ptr here to ease further wrapping using operator-> - Wt::Dbo::Session* getDboSession() { return &_session; } - Db& getDb() { return _db; } + Wt::Dbo::Session* getDboSession() + { + return &_session; + } + Db& getDb() + { + return _db; + } template typename Object::pointer create(Args&&... args) diff --git a/src/libs/services/scanner/CMakeLists.txt b/src/libs/services/scanner/CMakeLists.txt index 62d6f0f2..26976852 100644 --- a/src/libs/services/scanner/CMakeLists.txt +++ b/src/libs/services/scanner/CMakeLists.txt @@ -9,7 +9,6 @@ add_library(lmsscanner STATIC impl/scanners/PlayListFileScanner.cpp impl/scanners/Utils.cpp impl/steps/ArtworkUtils.cpp - impl/steps/FileScanQueue.cpp impl/steps/ScanErrorLogger.cpp impl/steps/ScanStepArtistReconciliation.cpp impl/steps/ScanStepAssociateArtistImages.cpp diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index f5bc18b8..db70e71c 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -24,6 +24,7 @@ #include #include "core/IConfig.hpp" +#include "core/IJobScheduler.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" #include "database/MediaLibrary.hpp" @@ -139,6 +140,17 @@ namespace lms::scanner scanSettings.modify()->setSkipSingleReleasePlayLists(settings.skipSingleReleasePlayLists); // TODO add more fields } + + std::size_t getScannerThreadCount() + { + std::size_t threadCount{ core::Service::get()->getULong("scanner-thread-count", 0) }; + + if (threadCount == 0) + threadCount = std::max(std::thread::hardware_concurrency() / 2, 1); + + return threadCount; + } + } // namespace std::unique_ptr createScannerService(Db& db) @@ -148,9 +160,13 @@ namespace lms::scanner ScannerService::ScannerService(Db& db) : _db{ db } + , _jobScheduler{ core::createJobScheduler("Scanner", getScannerThreadCount()) } { _ioService.setThreadCount(1); + LMS_LOG(DBUPDATER, INFO, "Using " << _jobScheduler->getThreadCount() << " thread(s) for jobs"); + _jobScheduler->setShouldAbortCallback([this]() { return _abortScan; }); + refreshScanSettings(); start(); @@ -447,6 +463,7 @@ namespace lms::scanner std::transform(std::cbegin(_fileScanners), std::cend(_fileScanners), std::back_inserter(fileScanners), [](const std::unique_ptr& scanner) { return scanner.get(); }); ScanStepBase::InitParams params{ + .jobScheduler = *_jobScheduler, .settings = _settings, .lastScanSettings = _lastScanSettings.has_value() ? &(_lastScanSettings.value()) : nullptr, .progressCallback = cbFunc, diff --git a/src/libs/services/scanner/impl/ScannerService.hpp b/src/libs/services/scanner/impl/ScannerService.hpp index fd615dc5..d3598a36 100644 --- a/src/libs/services/scanner/impl/ScannerService.hpp +++ b/src/libs/services/scanner/impl/ScannerService.hpp @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include #include @@ -36,6 +37,11 @@ #include "services/scanner/IScannerService.hpp" #include "steps/IScanStep.hpp" +namespace lms::core +{ + class IJobScheduler; +} + namespace lms::scanner { class IFileScanner; @@ -79,6 +85,9 @@ namespace lms::scanner void notifyInProgressIfNeeded(const ScanStepStats& stats); void notifyInProgress(const ScanStepStats& stats); + db::Db& _db; + std::unique_ptr _jobScheduler; + std::vector> _fileScanners; std::vector> _scanSteps; @@ -88,7 +97,6 @@ namespace lms::scanner boost::asio::system_timer _scheduleTimer{ _ioService }; Events _events; std::chrono::system_clock::time_point _lastScanInProgressEmit; - db::Db& _db; mutable std::shared_mutex _statusMutex; State _curState{ State::NotScheduled }; diff --git a/src/libs/services/scanner/impl/steps/FileScanQueue.cpp b/src/libs/services/scanner/impl/steps/FileScanQueue.cpp deleted file mode 100644 index 9b61a808..00000000 --- a/src/libs/services/scanner/impl/steps/FileScanQueue.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 . - */ - -#include "FileScanQueue.hpp" - -#include - -#include "core/ILogger.hpp" -#include "core/ITraceLogger.hpp" - -#include "scanners/IFileScanOperation.hpp" - -namespace lms::scanner -{ - FileScanQueue::FileScanQueue(std::size_t threadCount, bool& abort) - : _scanContextRunner{ _scanIoContext, threadCount, "FileScan" } - , _abort{ abort } - { - } - - FileScanQueue::~FileScanQueue() = default; - - void FileScanQueue::pushScanRequest(std::unique_ptr operation) - { - { - std::scoped_lock lock{ _mutex }; - _ongoingScanCount += 1; - } - - auto operationHandler{ [operation = std::move(operation), this]() mutable { - if (_abort) - { - std::scoped_lock lock{ _mutex }; - _ongoingScanCount -= 1; - } - else - { - { - LMS_SCOPED_TRACE_OVERVIEW("Scanner", operation->getName()); - LMS_LOG(DBUPDATER, DEBUG, operation->getName() << ": scanning file " << operation->getFilePath()); - operation->scan(); - } - - { - std::scoped_lock lock{ _mutex }; - - _scanResults.emplace_back(std::move(operation)); - _ongoingScanCount -= 1; - } - } - - _condVar.notify_all(); - } }; - - boost::asio::post(_scanIoContext, std::move(operationHandler)); - } - - std::size_t FileScanQueue::getResultsCount() const - { - std::scoped_lock lock{ _mutex }; - return _scanResults.size(); - } - - size_t FileScanQueue::popResults(std::vector>& results, std::size_t maxCount) - { - results.clear(); - results.reserve(maxCount); - - { - std::scoped_lock lock{ _mutex }; - - while (results.size() < maxCount && !_scanResults.empty()) - { - results.push_back(std::move(_scanResults.front())); - _scanResults.pop_front(); - } - } - - return results.size(); - } - - void FileScanQueue::wait(std::size_t maxScanRequestCount) - { - if (_ongoingScanCount <= maxScanRequestCount) - return; - - { - LMS_SCOPED_TRACE_OVERVIEW("Scanner", "WaitParseResults"); - - std::unique_lock lock{ _mutex }; - _condVar.wait(lock, [=, this] { return _ongoingScanCount <= maxScanRequestCount; }); - } - } - -} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/FileScanQueue.hpp b/src/libs/services/scanner/impl/steps/FileScanQueue.hpp deleted file mode 100644 index 0cf4259e..00000000 --- a/src/libs/services/scanner/impl/steps/FileScanQueue.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 . - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "core/IOContextRunner.hpp" - -namespace lms::scanner -{ - class IFileScanOperation; - - class FileScanQueue - { - public: - FileScanQueue(std::size_t threadCount, bool& abort); - ~FileScanQueue(); - FileScanQueue(const FileScanQueue&) = delete; - FileScanQueue& operator=(const FileScanQueue&) = delete; - - std::size_t getThreadCount() const { return _scanContextRunner.getThreadCount(); } - - void pushScanRequest(std::unique_ptr operation); - - std::size_t getResultsCount() const; - size_t popResults(std::vector>& results, std::size_t maxCount); - - void wait(std::size_t maxScanRequestCount = 0); // wait until ongoing scan request count <= maxScanRequestCount - - private: - boost::asio::io_context _scanIoContext; - core::IOContextRunner _scanContextRunner; - - mutable std::mutex _mutex; - std::atomic _ongoingScanCount{}; - std::deque> _scanResults; - std::condition_variable _condVar; - bool& _abort; - }; -} // namespace lms::scanner \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/ScanStepBase.cpp b/src/libs/services/scanner/impl/steps/ScanStepBase.cpp index a82d7fb7..bde21dde 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepBase.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepBase.cpp @@ -31,6 +31,7 @@ namespace lms::scanner , _progressCallback{ initParams.progressCallback } , _abortScan{ initParams.abortScan } , _db{ initParams.db } + , _jobScheduler{ initParams.jobScheduler } , _fileScanners(std::cbegin(initParams.fileScanners), std::cend(initParams.fileScanners)) , _lastScanSettings{ initParams.lastScanSettings } { diff --git a/src/libs/services/scanner/impl/steps/ScanStepBase.hpp b/src/libs/services/scanner/impl/steps/ScanStepBase.hpp index a467ddab..2677726d 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepBase.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepBase.hpp @@ -27,6 +27,11 @@ #include "IScanStep.hpp" #include "ScanErrorLogger.hpp" +namespace lms::core +{ + class IJobScheduler; +} + namespace lms::db { class Db; @@ -46,6 +51,7 @@ namespace lms::scanner struct InitParams { + core::IJobScheduler& jobScheduler; const ScannerSettings& settings; const ScannerSettings* lastScanSettings{}; ProgressCallback progressCallback; @@ -59,6 +65,7 @@ namespace lms::scanner ScanStepBase& operator=(const ScanStepBase&) = delete; protected: + core::IJobScheduler& getJobScheduler() { return _jobScheduler; }; const ScannerSettings* getLastScanSettings() const { return _lastScanSettings; } IFileScanner* selectFileScanner(const std::filesystem::path& filePath) const; void visitFileScanners(const std::function& visitor) const; @@ -78,6 +85,7 @@ namespace lms::scanner db::Db& _db; private: + core::IJobScheduler& _jobScheduler; std::unordered_map _scannerByFile; std::unordered_map _scannerByExtension; std::vector _fileScanners; diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index 1ed23520..5ed9873e 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -19,9 +19,9 @@ #include "ScanStepScanFiles.hpp" -#include "FileScanQueue.hpp" #include "ScannerSettings.hpp" -#include "core/IConfig.hpp" +#include "core/IJob.hpp" +#include "core/IJobScheduler.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" #include "core/Path.hpp" @@ -39,15 +39,32 @@ namespace lms::scanner namespace { - std::size_t getScanMetaDataThreadCount() + class FileScanJob : public core::IJob { - std::size_t threadCount{ core::Service::get()->getULong("scanner-metadata-thread-count", 0) }; + public: + FileScanJob(std::unique_ptr scanOperation) + : _scanOperation{ std::move(scanOperation) } + { + } - if (threadCount == 0) - threadCount = std::max(std::thread::hardware_concurrency() / 2, 1); + IFileScanOperation& getScanOperation() + { + return *_scanOperation; + } - return threadCount; - } + private: + core::LiteralString getName() const override + { + return _scanOperation->getName(); + } + + void run() override + { + _scanOperation->scan(); + } + + std::unique_ptr _scanOperation; + }; FileToScan retrieveFileInfo(const std::filesystem::path& file, const MediaLibraryInfo& mediaLibrary, std::error_code& ec) { @@ -71,7 +88,6 @@ namespace lms::scanner ScanStepScanFiles::ScanStepScanFiles(InitParams& initParams) : ScanStepBase{ initParams } - , _fileScanQueue{ getScanMetaDataThreadCount(), _abortScan } { visitFileScanners([](IFileScanner* scanner) { for (const std::filesystem::path& file : scanner->getSupportedFiles()) @@ -80,8 +96,6 @@ namespace lms::scanner for (const std::filesystem::path& extension : scanner->getSupportedExtensions()) LMS_LOG(DBUPDATER, INFO, scanner->getName() << ": supporting file extension " << extension); }); - - LMS_LOG(DBUPDATER, INFO, "Using " << _fileScanQueue.getThreadCount() << " thread(s) for scanning file metadata"); } bool ScanStepScanFiles::needProcess([[maybe_unused]] const ScanContext& context) const @@ -100,9 +114,13 @@ namespace lms::scanner void ScanStepScanFiles::process(ScanContext& context, const MediaLibraryInfo& mediaLibrary) { - const std::size_t scanQueueMaxScanRequestCount{ 100 * _fileScanQueue.getThreadCount() }; - const std::size_t processFileResultsBatchSize{ 10 }; + core::IJobScheduler& jobScheduler{ getJobScheduler() }; + assert(jobScheduler.getJobsDoneCount() == 0); + const std::size_t scanQueueMaxScanRequestCount{ 100 * jobScheduler.getThreadCount() }; + constexpr std::size_t processFileResultsBatchSize{ 10 }; + + std::vector> jobsDone; std::vector> scanOperations; core::pathUtils::exploreFilesRecursive( @@ -130,7 +148,7 @@ namespace lms::scanner if (context.scanOptions.fullScan || scanner->needsScan(fileToScan)) { auto scanOperation{ scanner->createScanOperation(std::move(fileToScan)) }; - _fileScanQueue.pushScanRequest(std::move(scanOperation)); + jobScheduler.scheduleJob(std::make_unique(std::move(scanOperation))); } } @@ -138,38 +156,48 @@ namespace lms::scanner _progressCallback(context.currentStepStats); } - while (_fileScanQueue.getResultsCount() > (scanQueueMaxScanRequestCount / 2)) + while (jobScheduler.getJobsDoneCount() > (scanQueueMaxScanRequestCount / 2)) { - _fileScanQueue.popResults(scanOperations, processFileResultsBatchSize); - processFileScanResults(context, scanOperations); + jobScheduler.popJobsDone(jobsDone, processFileResultsBatchSize); + processFileScanResults(context, jobsDone); + jobsDone.clear(); } - _fileScanQueue.wait(scanQueueMaxScanRequestCount); + jobScheduler.waitUntilJobCountAtMost(scanQueueMaxScanRequestCount); return true; }, &excludeDirFileName); - _fileScanQueue.wait(); + jobScheduler.wait(); - while (!_abortScan && _fileScanQueue.popResults(scanOperations, processFileResultsBatchSize) > 0) - processFileScanResults(context, scanOperations); + while (jobScheduler.popJobsDone(jobsDone, processFileResultsBatchSize) > 0) + { + if (!_abortScan) + processFileScanResults(context, jobsDone); + + jobsDone.clear(); + } + + assert(jobScheduler.getJobsDoneCount() == 0); } - void ScanStepScanFiles::processFileScanResults(ScanContext& context, std::span> scanOperations) + void ScanStepScanFiles::processFileScanResults(ScanContext& context, std::span> scanJobs) { LMS_SCOPED_TRACE_OVERVIEW("Scanner", "ProcessScanResults"); db::Session& dbSession{ _db.getTLSSession() }; auto transaction{ dbSession.createWriteTransaction() }; - for (auto& scanOperation : scanOperations) + for (auto& scanJob : scanJobs) { if (_abortScan) return; - LMS_LOG(DBUPDATER, DEBUG, scanOperation->getName() << ": processing result for " << scanOperation->getFilePath()); - const IFileScanOperation::OperationResult res{ scanOperation->processResult() }; + IFileScanOperation& scanOperation{ static_cast(*scanJob).getScanOperation() }; + + LMS_LOG(DBUPDATER, DEBUG, scanOperation.getName() << ": processing result for " << scanOperation.getFilePath()); + const IFileScanOperation::OperationResult res{ scanOperation.processResult() }; switch (res) { case IFileScanOperation::OperationResult::Added: @@ -187,7 +215,7 @@ namespace lms::scanner } context.stats.scans++; - for (const auto& error : scanOperation->getErrors()) + for (const auto& error : scanOperation.getErrors()) addError(context, error); } } diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp index 90e9ce87..1dfc315b 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp @@ -19,12 +19,15 @@ #pragma once -#include #include -#include "FileScanQueue.hpp" #include "ScanStepBase.hpp" +namespace lms::core +{ + class IJob; +} + namespace lms::scanner { class IFileScanner; @@ -42,8 +45,6 @@ namespace lms::scanner void process(ScanContext& context) override; void process(ScanContext& context, const MediaLibraryInfo& mediaLibrary); - void processFileScanResults(ScanContext& context, std::span> scanOperations); - - FileScanQueue _fileScanQueue; + void processFileScanResults(ScanContext& context, std::span> scanJobs); }; } // namespace lms::scanner From 427f777c44ca3a6aa5baa8a12d653b0f9fcad501 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 2 Jul 2025 23:34:54 +0200 Subject: [PATCH 11/46] Added missing pragmas --- src/libs/core/include/core/IJob.hpp | 2 ++ src/libs/core/include/core/IJobScheduler.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/libs/core/include/core/IJob.hpp b/src/libs/core/include/core/IJob.hpp index eba2ea44..4cf73268 100644 --- a/src/libs/core/include/core/IJob.hpp +++ b/src/libs/core/include/core/IJob.hpp @@ -17,6 +17,8 @@ * along with LMS. If not, see . */ +#pragma once + #include "core/LiteralString.hpp" namespace lms::core diff --git a/src/libs/core/include/core/IJobScheduler.hpp b/src/libs/core/include/core/IJobScheduler.hpp index f8eed21e..40644c17 100644 --- a/src/libs/core/include/core/IJobScheduler.hpp +++ b/src/libs/core/include/core/IJobScheduler.hpp @@ -17,6 +17,8 @@ * along with LMS. If not, see . */ +#pragma once + #include #include #include From 204a4a885702f53160858ba23493b9a65af0789a Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 4 Jul 2025 23:05:35 +0200 Subject: [PATCH 12/46] Scanner: parallelized processing within artwork association steps --- src/libs/database/impl/Artist.cpp | 31 +++ src/libs/database/impl/Migration.cpp | 19 +- src/libs/database/impl/Release.cpp | 31 +++ src/libs/database/impl/Track.cpp | 21 ++ src/libs/database/include/database/Artist.hpp | 6 + .../include/database/IdRange.hpp} | 26 +- .../database/include/database/Release.hpp | 6 + src/libs/database/include/database/Track.hpp | 3 + src/libs/database/test/Artist.cpp | 117 ++++++++ src/libs/database/test/Release.cpp | 118 ++++++++ src/libs/database/test/Track.cpp | 87 ++++++ src/libs/services/scanner/CMakeLists.txt | 2 +- .../services/scanner/impl/ScannerService.cpp | 8 +- .../services/scanner/impl/ScannerService.hpp | 2 +- .../impl/scanners/AudioFileScanOperation.cpp | 3 + .../impl/scanners/ImageFileScanner.cpp | 4 + .../scanner/impl/steps/ArtworkUtils.cpp | 59 ---- .../services/scanner/impl/steps/JobQueue.cpp | 70 +++++ .../services/scanner/impl/steps/JobQueue.hpp | 57 ++++ .../steps/ScanStepAssociateArtistImages.cpp | 246 +++++++++-------- .../steps/ScanStepAssociateReleaseImages.cpp | 230 ++++++++-------- .../steps/ScanStepAssociateTrackImages.cpp | 254 +++++++++--------- .../scanner/impl/steps/ScanStepScanFiles.cpp | 40 +-- 23 files changed, 982 insertions(+), 458 deletions(-) rename src/libs/{services/scanner/impl/steps/ArtworkUtils.hpp => database/include/database/IdRange.hpp} (56%) delete mode 100644 src/libs/services/scanner/impl/steps/ArtworkUtils.cpp create mode 100644 src/libs/services/scanner/impl/steps/JobQueue.cpp create mode 100644 src/libs/services/scanner/impl/steps/JobQueue.hpp diff --git a/src/libs/database/impl/Artist.cpp b/src/libs/database/impl/Artist.cpp index 57ff3c50..d3b106fe 100644 --- a/src/libs/database/impl/Artist.cpp +++ b/src/libs/database/impl/Artist.cpp @@ -237,6 +237,17 @@ namespace lms::db }); } + void Artist::find(Session& session, const IdRange& idRange, const std::function& func) + { + assert(idRange.isValid()); + + auto query{ session.getDboSession()->query>("SELECT a from artist a").orderBy("a.id").where("a.id BETWEEN ? AND ?").bind(idRange.first).bind(idRange.last) }; + + utils::forEachQueryResult(query, [&](const Artist::pointer& artist) { + func(artist); + }); + } + std::vector Artist::find(Session& session, std::string_view name) { session.checkReadTransaction(); @@ -280,6 +291,16 @@ namespace lms::db utils::forEachQueryRangeResult(query, params.range, func); } + IdRange Artist::findNextRange(Session& session, ArtistId lastRetrievedId, std::size_t count) + { + auto query{ session.getDboSession()->query>("SELECT MIN(sub.id) AS first_id, MAX(sub.id) AS last_id FROM (SELECT a.id FROM artist a WHERE a.id > ? ORDER BY a.id LIMIT ?) sub") }; + query.bind(lastRetrievedId); + query.bind(static_cast(count)); + + auto res{ utils::fetchQuerySingleResult(query) }; + return IdRange{ .first = std::get<0>(res), .last = std::get<1>(res) }; + } + RangeResults Artist::findOrphanIds(Session& session, std::optional range) { session.checkReadTransaction(); @@ -304,6 +325,16 @@ AND NOT EXISTS ( return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT 1 FROM artist").where("id = ?").bind(id)) == 1; } + void Artist::updatePreferredArtwork(Session& session, ArtistId artistId, ArtworkId artworkId) + { + session.checkWriteTransaction(); + + if (artworkId.isValid()) + utils::executeCommand(*session.getDboSession(), "UPDATE artist SET preferred_artwork_id = ? WHERE id = ?", artworkId, artistId); + else + utils::executeCommand(*session.getDboSession(), "UPDATE artist SET preferred_artwork_id = NULL WHERE id = ?", artistId); + } + std::optional Artist::getMBID() const { return core::UUID::fromString(_mbid); diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index 4d47cc69..c7c8510d 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -35,7 +35,7 @@ namespace lms::db { namespace { - static constexpr Version LMS_DATABASE_VERSION{ 95 }; + static constexpr Version LMS_DATABASE_VERSION{ 96 }; } VersionInfo::VersionInfo() @@ -1396,6 +1396,22 @@ FROM artist)"); utils::executeCommand(*session.getDboSession(), "ALTER TABLE track DROP COLUMN file_name"); } + void migrateFromV95(Session& session) + { + // Make sure each image and each embessed image has an artwork object + utils::executeCommand(*session.getDboSession(), R"(INSERT INTO artwork (version, track_embedded_image_id) +SELECT 1 AS version, tei.id +FROM track_embedded_image tei +LEFT JOIN artwork art ON tei.id = art.track_embedded_image_id +WHERE art.track_embedded_image_id IS NULL)"); + + utils::executeCommand(*session.getDboSession(), R"(INSERT INTO artwork (version, image_id) +SELECT 1 AS version, img.id +FROM image img +LEFT JOIN artwork art ON img.id = art.image_id +WHERE art.image_id IS NULL)"); + } + bool doDbMigration(Session& session) { constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" }; @@ -1467,6 +1483,7 @@ FROM artist)"); { 92, migrateFromV92 }, { 93, migrateFromV93 }, { 94, migrateFromV94 }, + { 95, migrateFromV95 }, }; bool migrationPerformed{}; diff --git a/src/libs/database/impl/Release.cpp b/src/libs/database/impl/Release.cpp index 12c85d6b..d78d6f26 100644 --- a/src/libs/database/impl/Release.cpp +++ b/src/libs/database/impl/Release.cpp @@ -504,6 +504,27 @@ namespace lms::db }); } + void Release::find(Session& session, const IdRange& idRange, const std::function& func) + { + assert(idRange.isValid()); + + auto query{ session.getDboSession()->query>("SELECT r from release r").orderBy("r.id").where("r.id BETWEEN ? AND ?").bind(idRange.first).bind(idRange.last) }; + + utils::forEachQueryResult(query, [&](const Release::pointer& release) { + func(release); + }); + } + + IdRange Release::findNextRange(Session& session, ReleaseId lastRetrievedId, std::size_t count) + { + auto query{ session.getDboSession()->query>("SELECT MIN(sub.id) AS first_id, MAX(sub.id) AS last_id FROM (SELECT r.id FROM release r WHERE r.id > ? ORDER BY r.id LIMIT ?) sub") }; + query.bind(lastRetrievedId); + query.bind(static_cast(count)); + + auto res{ utils::fetchQuerySingleResult(query) }; + return IdRange{ .first = std::get<0>(res), .last = std::get<1>(res) }; + } + RangeResults Release::find(Session& session, const FindParameters& params) { session.checkReadTransaction(); @@ -528,6 +549,16 @@ namespace lms::db return utils::execRangeQuery(query, params.range); } + void Release::updatePreferredArtwork(Session& session, ReleaseId releaseId, ArtworkId artworkId) + { + session.checkWriteTransaction(); + + if (artworkId.isValid()) + utils::executeCommand(*session.getDboSession(), "UPDATE release SET preferred_artwork_id = ? WHERE id = ?", artworkId, releaseId); + else + utils::executeCommand(*session.getDboSession(), "UPDATE release SET preferred_artwork_id = NULL WHERE id = ?", releaseId); + } + std::size_t Release::getCount(Session& session, const FindParameters& params) { session.checkReadTransaction(); diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp index 63220d86..9b6384fd 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/Track.cpp @@ -292,6 +292,27 @@ namespace lms::db }); } + void Track::find(Session& session, const IdRange& idRange, const std::function& func) + { + assert(idRange.isValid()); + + auto query{ session.getDboSession()->query>("SELECT t from track t").orderBy("t.id").where("t.id BETWEEN ? AND ?").bind(idRange.first).bind(idRange.last) }; + + utils::forEachQueryResult(query, [&](const Track::pointer& track) { + func(track); + }); + } + + IdRange Track::findNextRange(Session& session, TrackId lastRetrievedId, std::size_t count) + { + auto query{ session.getDboSession()->query>("SELECT MIN(sub.id) AS first_id, MAX(sub.id) AS last_id FROM (SELECT t.id FROM track t WHERE t.id > ? ORDER BY t.id LIMIT ?) sub") }; + query.bind(lastRetrievedId); + query.bind(static_cast(count)); + + auto res{ utils::fetchQuerySingleResult(query) }; + return IdRange{ .first = std::get<0>(res), .last = std::get<1>(res) }; + } + bool Track::exists(Session& session, TrackId id) { session.checkReadTransaction(); diff --git a/src/libs/database/include/database/Artist.hpp b/src/libs/database/include/database/Artist.hpp index 86972a75..dd38ed0c 100644 --- a/src/libs/database/include/database/Artist.hpp +++ b/src/libs/database/include/database/Artist.hpp @@ -34,6 +34,7 @@ #include "database/ArtworkId.hpp" #include "database/ClusterId.hpp" #include "database/Filters.hpp" +#include "database/IdRange.hpp" #include "database/MediaLibraryId.hpp" #include "database/Object.hpp" #include "database/ReleaseId.hpp" @@ -125,12 +126,17 @@ namespace lms::db static pointer find(Session& session, ArtistId id); static std::vector find(Session& session, std::string_view name); // exact match on name field static void find(Session& session, ArtistId& lastRetrievedArtist, std::size_t count, const std::function& func, MediaLibraryId library = {}); + static void find(Session& session, const IdRange& idRange, const std::function& func); static RangeResults find(Session& session, const FindParameters& params); static void find(Session& session, const FindParameters& params, std::function func); + static IdRange findNextRange(Session& session, ArtistId lastRetrievedId, std::size_t count); static RangeResults findIds(Session& session, const FindParameters& params); static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // No track related static bool exists(Session& session, ArtistId id); + // Updates + static void updatePreferredArtwork(Session& session, ArtistId artistId, ArtworkId artworkId); + // Accessors const std::string& getName() const { return _name; } const std::string& getSortName() const { return _sortName; } diff --git a/src/libs/services/scanner/impl/steps/ArtworkUtils.hpp b/src/libs/database/include/database/IdRange.hpp similarity index 56% rename from src/libs/services/scanner/impl/steps/ArtworkUtils.hpp rename to src/libs/database/include/database/IdRange.hpp index 4dc0722b..cc7f7434 100644 --- a/src/libs/services/scanner/impl/steps/ArtworkUtils.hpp +++ b/src/libs/database/include/database/IdRange.hpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Emeric Poupon + * Copyright (C) 2025 Emeric Poupon * * This file is part of LMS. * @@ -19,21 +19,15 @@ #pragma once -#include - -#include "database/ArtworkId.hpp" -#include "database/ImageId.hpp" -#include "database/Object.hpp" -#include "database/TrackEmbeddedImageId.hpp" - namespace lms::db { - class Artwork; - class Session; -} // namespace lms::db + template + struct IdRange + { + public: + IdType first; + IdType last; -namespace lms::scanner::utils -{ - db::ObjectPtr getOrCreateArtworkFromTrackEmbeddedImage(db::Session& session, db::TrackEmbeddedImageId trackEmbeddedImageId); - db::ObjectPtr getOrCreateArtworkFromImage(db::Session& session, db::ImageId imageId); -} // namespace lms::scanner::utils \ No newline at end of file + bool isValid() const { return first.isValid() && last.isValid(); } + }; +} // namespace lms::db diff --git a/src/libs/database/include/database/Release.hpp b/src/libs/database/include/database/Release.hpp index 1f55173a..7316b179 100644 --- a/src/libs/database/include/database/Release.hpp +++ b/src/libs/database/include/database/Release.hpp @@ -35,6 +35,7 @@ #include "database/CountryId.hpp" #include "database/DirectoryId.hpp" #include "database/Filters.hpp" +#include "database/IdRange.hpp" #include "database/LabelId.hpp" #include "database/MediaLibraryId.hpp" #include "database/Object.hpp" @@ -249,12 +250,17 @@ namespace lms::db static pointer find(Session& session, const core::UUID& MBID); static pointer find(Session& session, ReleaseId id); static void find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function& func, MediaLibraryId library = {}); + static void find(Session& session, const IdRange& idRange, const std::function& func); + static IdRange findNextRange(Session& session, ReleaseId lastRetrievedId, std::size_t count); static RangeResults find(Session& session, const FindParameters& parameters); static void find(Session& session, const FindParameters& parameters, const std::function& func); static RangeResults findIds(Session& session, const FindParameters& parameters); static std::size_t getCount(Session& session, const FindParameters& parameters); static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // not track related + // Updates + static void updatePreferredArtwork(Session& session, ReleaseId id, ArtworkId artworkId); + // Get the cluster of the tracks that belong to this release // Each clusters are grouped by cluster type, sorted by the number of occurence (max to min) // size is the max number of cluster per cluster type diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp index 293d1055..e967596e 100644 --- a/src/libs/database/include/database/Track.hpp +++ b/src/libs/database/include/database/Track.hpp @@ -39,6 +39,7 @@ #include "database/ClusterId.hpp" #include "database/DirectoryId.hpp" #include "database/Filters.hpp" +#include "database/IdRange.hpp" #include "database/MediaLibraryId.hpp" #include "database/Object.hpp" #include "database/ReleaseId.hpp" @@ -192,6 +193,8 @@ namespace lms::db static pointer findByPath(Session& session, const std::filesystem::path& p); static pointer find(Session& session, TrackId id); static void find(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func, MediaLibraryId library = {}); + static void find(Session& session, const IdRange& idRange, const std::function& func); + static IdRange findNextRange(Session& session, TrackId lastRetrievedId, std::size_t count); static void findAbsoluteFilePath(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func); static bool exists(Session& session, TrackId id); diff --git a/src/libs/database/test/Artist.cpp b/src/libs/database/test/Artist.cpp index 1b82997b..2e53657d 100644 --- a/src/libs/database/test/Artist.cpp +++ b/src/libs/database/test/Artist.cpp @@ -608,6 +608,93 @@ namespace lms::db::tests } } + TEST_F(DatabaseFixture, Artist_findNextRange) + { + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Artist::findNextRange(session, ArtistId{}, 0) }; + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, ArtistId{}); + EXPECT_EQ(range.last, ArtistId{}); + + range = Artist::findNextRange(session, ArtistId{}, 100); + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, ArtistId{}); + EXPECT_EQ(range.last, ArtistId{}); + } + + ScopedArtist artist1{ session, "Artist1" }; + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Artist::findNextRange(session, ArtistId{}, 0) }; + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, ArtistId{}); + EXPECT_EQ(range.last, ArtistId{}); + + range = Artist::findNextRange(session, ArtistId{}, 1); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, artist1.getId()); + EXPECT_EQ(range.last, artist1.getId()); + + range = Artist::findNextRange(session, range.last, 1); + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, ArtistId{}); + EXPECT_EQ(range.last, ArtistId{}); + + range = Artist::findNextRange(session, ArtistId{}, 100); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, artist1.getId()); + EXPECT_EQ(range.last, artist1.getId()); + } + + ScopedArtist artist2{ session, "Artist2" }; + ScopedArtist artist3{ session, "Artist3" }; + + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Artist::findNextRange(session, ArtistId{}, 2) }; + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, artist1.getId()); + EXPECT_EQ(range.last, artist2.getId()); + + range = Artist::findNextRange(session, artist2.getId(), 2); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, artist3.getId()); + EXPECT_EQ(range.last, artist3.getId()); + } + } + + TEST_F(DatabaseFixture, Artist_findByRange) + { + ScopedArtist artist1{ session, "Artist1" }; + ScopedArtist artist2{ session, "Artist2" }; + ScopedArtist artist3{ session, "Artist3" }; + + { + auto transaction{ session.createReadTransaction() }; + + std::size_t count{}; + Artist::find(session, IdRange{ .first = artist1.getId(), .last = artist1.getId() }, [&](const db::Artist::pointer& artist) { + count++; + EXPECT_EQ(artist->getId(), artist1.getId()); + }); + EXPECT_EQ(count, 1); + } + + { + auto transaction{ session.createReadTransaction() }; + + std::size_t count{}; + Artist::find(session, IdRange{ .first = artist1.getId(), .last = artist3.getId() }, [&](const db::Artist::pointer&) { + count++; + }); + EXPECT_EQ(count, 3); + } + } + TEST_F(DatabaseFixture, Artist_sortMethod) { ScopedArtist artistA{ session, "artistA" }; @@ -817,4 +904,34 @@ namespace lms::db::tests EXPECT_EQ(artists.results[3], artistC.getId()); } } + + TEST_F(DatabaseFixture, Artist_updateArtwork) + { + ScopedArtist artist{ session, "MyArtist" }; + { + auto transaction{ session.createReadTransaction() }; + EXPECT_EQ(artist->getPreferredArtwork(), Artwork::pointer{}); + } + + ScopedImage image{ session, "/image1.jpg" }; + ScopedArtwork artwork{ session, image.lockAndGet() }; + + { + auto transaction{ session.createWriteTransaction() }; + Artist::updatePreferredArtwork(session, artist->getId(), artwork.getId()); + } + { + auto transaction{ session.createReadTransaction() }; + EXPECT_EQ(artist->getPreferredArtwork()->getId(), artwork.getId()); + } + + { + auto transaction{ session.createWriteTransaction() }; + Artist::updatePreferredArtwork(session, artist.getId(), ArtworkId{}); + } + { + auto transaction{ session.createReadTransaction() }; + EXPECT_EQ(artist->getPreferredArtwork(), Artwork::pointer{}); + } + } } // namespace lms::db::tests diff --git a/src/libs/database/test/Release.cpp b/src/libs/database/test/Release.cpp index 3d3b3a11..fc7cbc44 100644 --- a/src/libs/database/test/Release.cpp +++ b/src/libs/database/test/Release.cpp @@ -173,6 +173,93 @@ namespace lms::db::tests } } + TEST_F(DatabaseFixture, Release_findNextRange) + { + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Release::findNextRange(session, ReleaseId{}, 0) }; + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, ReleaseId{}); + EXPECT_EQ(range.last, ReleaseId{}); + + range = Release::findNextRange(session, ReleaseId{}, 100); + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, ReleaseId{}); + EXPECT_EQ(range.last, ReleaseId{}); + } + + ScopedRelease release1{ session, "Artist1" }; + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Release::findNextRange(session, ReleaseId{}, 0) }; + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, ReleaseId{}); + EXPECT_EQ(range.last, ReleaseId{}); + + range = Release::findNextRange(session, ReleaseId{}, 1); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, release1.getId()); + EXPECT_EQ(range.last, release1.getId()); + + range = Release::findNextRange(session, range.last, 1); + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, ReleaseId{}); + EXPECT_EQ(range.last, ReleaseId{}); + + range = Release::findNextRange(session, ReleaseId{}, 100); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, release1.getId()); + EXPECT_EQ(range.last, release1.getId()); + } + + ScopedRelease release2{ session, "Artist2" }; + ScopedRelease release3{ session, "Artist3" }; + + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Release::findNextRange(session, ReleaseId{}, 2) }; + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, release1.getId()); + EXPECT_EQ(range.last, release2.getId()); + + range = Release::findNextRange(session, release2.getId(), 2); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, release3.getId()); + EXPECT_EQ(range.last, release3.getId()); + } + } + + TEST_F(DatabaseFixture, Release_findByRange) + { + ScopedRelease release1{ session, "Artist1" }; + ScopedRelease release2{ session, "Artist2" }; + ScopedRelease release3{ session, "Artist3" }; + + { + auto transaction{ session.createReadTransaction() }; + + std::size_t count{}; + Release::find(session, IdRange{ .first = release1.getId(), .last = release1.getId() }, [&](const db::Release::pointer& release) { + count++; + EXPECT_EQ(release->getId(), release1.getId()); + }); + EXPECT_EQ(count, 1); + } + + { + auto transaction{ session.createReadTransaction() }; + + std::size_t count{}; + Release::find(session, IdRange{ .first = release1.getId(), .last = release3.getId() }, [&](const db::Release::pointer&) { + count++; + }); + EXPECT_EQ(count, 3); + } + } + TEST_F(DatabaseFixture, Release_singleTrack) { ScopedRelease release{ session, "MyRelease" }; @@ -1431,4 +1518,35 @@ namespace lms::db::tests EXPECT_EQ(releases.results[1]->getId(), release1->getId()); } } + + TEST_F(DatabaseFixture, Release_updateArtwork) + { + ScopedRelease release{ session, "MyRelease" }; + { + auto transaction{ session.createReadTransaction() }; + EXPECT_EQ(release->getPreferredArtwork(), Artwork::pointer{}); + } + + ScopedImage image{ session, "/image1.jpg" }; + ScopedArtwork artwork{ session, image.lockAndGet() }; + + { + auto transaction{ session.createWriteTransaction() }; + Release::updatePreferredArtwork(session, release->getId(), artwork.getId()); + } + { + auto transaction{ session.createReadTransaction() }; + EXPECT_EQ(release->getPreferredArtwork()->getId(), artwork.getId()); + } + + { + auto transaction{ session.createWriteTransaction() }; + Release::updatePreferredArtwork(session, release.getId(), ArtworkId{}); + } + { + auto transaction{ session.createReadTransaction() }; + EXPECT_EQ(release->getPreferredArtwork(), Artwork::pointer{}); + } + } + } // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/Track.cpp b/src/libs/database/test/Track.cpp index 517900d9..e88b6ce2 100644 --- a/src/libs/database/test/Track.cpp +++ b/src/libs/database/test/Track.cpp @@ -151,6 +151,93 @@ namespace lms::db::tests } } + TEST_F(DatabaseFixture, Track_findNextRange) + { + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Track::findNextRange(session, TrackId{}, 0) }; + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, TrackId{}); + EXPECT_EQ(range.last, TrackId{}); + + range = Track::findNextRange(session, TrackId{}, 100); + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, TrackId{}); + EXPECT_EQ(range.last, TrackId{}); + } + + ScopedTrack track1{ session }; + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Track::findNextRange(session, TrackId{}, 0) }; + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, TrackId{}); + EXPECT_EQ(range.last, TrackId{}); + + range = Track::findNextRange(session, TrackId{}, 1); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, track1.getId()); + EXPECT_EQ(range.last, track1.getId()); + + range = Track::findNextRange(session, range.last, 1); + EXPECT_FALSE(range.isValid()); + EXPECT_EQ(range.first, TrackId{}); + EXPECT_EQ(range.last, TrackId{}); + + range = Track::findNextRange(session, TrackId{}, 100); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, track1.getId()); + EXPECT_EQ(range.last, track1.getId()); + } + + ScopedTrack track2{ session }; + ScopedTrack track3{ session }; + + { + auto transaction{ session.createReadTransaction() }; + + auto range{ Track::findNextRange(session, TrackId{}, 2) }; + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, track1.getId()); + EXPECT_EQ(range.last, track2.getId()); + + range = Track::findNextRange(session, track2.getId(), 2); + EXPECT_TRUE(range.isValid()); + EXPECT_EQ(range.first, track3.getId()); + EXPECT_EQ(range.last, track3.getId()); + } + } + + TEST_F(DatabaseFixture, Track_findByRange) + { + ScopedTrack track1{ session }; + ScopedTrack track2{ session }; + ScopedTrack track3{ session }; + + { + auto transaction{ session.createReadTransaction() }; + + std::size_t count{}; + Track::find(session, IdRange{ .first = track1.getId(), .last = track1.getId() }, [&](const db::Track::pointer& track) { + count++; + EXPECT_EQ(track->getId(), track1.getId()); + }); + EXPECT_EQ(count, 1); + } + + { + auto transaction{ session.createReadTransaction() }; + + std::size_t count{}; + Track::find(session, IdRange{ .first = track1.getId(), .last = track3.getId() }, [&](const db::Track::pointer&) { + count++; + }); + EXPECT_EQ(count, 3); + } + } + TEST_F(DatabaseFixture, Track_findAbsoluteFilePath) { ScopedTrack track{ session }; diff --git a/src/libs/services/scanner/CMakeLists.txt b/src/libs/services/scanner/CMakeLists.txt index 26976852..a09c1fbb 100644 --- a/src/libs/services/scanner/CMakeLists.txt +++ b/src/libs/services/scanner/CMakeLists.txt @@ -8,7 +8,7 @@ add_library(lmsscanner STATIC impl/scanners/LyricsFileScanner.cpp impl/scanners/PlayListFileScanner.cpp impl/scanners/Utils.cpp - impl/steps/ArtworkUtils.cpp + impl/steps/JobQueue.cpp impl/steps/ScanErrorLogger.cpp impl/steps/ScanStepArtistReconciliation.cpp impl/steps/ScanStepAssociateArtistImages.cpp diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index db70e71c..c5a002f0 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -448,7 +448,7 @@ namespace lms::scanner if (!_lastScanSettings) _lastScanSettings = readScannerSettings(_db.getTLSSession(), lastScanSettingsName); - auto cbFunc{ [this](const ScanStepStats& stats) { + auto progressFunc{ [this](const ScanStepStats& stats) { notifyInProgressIfNeeded(stats); } }; @@ -466,7 +466,7 @@ namespace lms::scanner .jobScheduler = *_jobScheduler, .settings = _settings, .lastScanSettings = _lastScanSettings.has_value() ? &(_lastScanSettings.value()) : nullptr, - .progressCallback = cbFunc, + .progressCallback = progressFunc, .abortScan = _abortScan, .db = _db, .fileScanners = fileScanners, @@ -500,14 +500,14 @@ namespace lms::scanner _currentScanStepStats = stepStats; } - const std::chrono::system_clock::time_point now{ std::chrono::system_clock::now() }; + const auto now{ std::chrono::steady_clock::now() }; _events.scanInProgress.emit(stepStats); _lastScanInProgressEmit = now; } void ScannerService::notifyInProgressIfNeeded(const ScanStepStats& stepStats) { - std::chrono::system_clock::time_point now{ std::chrono::system_clock::now() }; + const auto now{ std::chrono::steady_clock::now() }; if (now - _lastScanInProgressEmit >= std::chrono::seconds{ 1 }) notifyInProgress(stepStats); diff --git a/src/libs/services/scanner/impl/ScannerService.hpp b/src/libs/services/scanner/impl/ScannerService.hpp index d3598a36..c3705905 100644 --- a/src/libs/services/scanner/impl/ScannerService.hpp +++ b/src/libs/services/scanner/impl/ScannerService.hpp @@ -96,7 +96,7 @@ namespace lms::scanner Wt::WIOService _ioService; boost::asio::system_timer _scheduleTimer{ _ioService }; Events _events; - std::chrono::system_clock::time_point _lastScanInProgressEmit; + std::chrono::steady_clock::time_point _lastScanInProgressEmit; mutable std::shared_mutex _statusMutex; State _curState{ State::NotScheduled }; diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index 5be41052..ff57a281 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -25,6 +25,7 @@ #include "core/Path.hpp" #include "core/XxHash3.hpp" #include "database/Artist.hpp" +#include "database/Artwork.hpp" #include "database/Cluster.hpp" #include "database/Db.hpp" #include "database/Directory.hpp" @@ -332,6 +333,8 @@ namespace lms::scanner image.modify()->setWidth(imageInfo.properties.width); image.modify()->setHeight(imageInfo.properties.height); image.modify()->setMimeType(imageInfo.mimeType); + + session.create(image); } return image; diff --git a/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp b/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp index 7869e938..d4d512e8 100644 --- a/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp @@ -22,6 +22,7 @@ #include #include "core/ILogger.hpp" +#include "database/Artwork.hpp" #include "database/Db.hpp" #include "database/Image.hpp" #include "database/MediaLibrary.hpp" @@ -84,7 +85,10 @@ namespace lms::scanner const bool added{ !image }; if (!image) + { image = dbSession.create(getFilePath()); + dbSession.create(image); + } image.modify()->setLastWriteTime(getLastWriteTime()); image.modify()->setFileSize(getFileSize()); diff --git a/src/libs/services/scanner/impl/steps/ArtworkUtils.cpp b/src/libs/services/scanner/impl/steps/ArtworkUtils.cpp deleted file mode 100644 index e74c6095..00000000 --- a/src/libs/services/scanner/impl/steps/ArtworkUtils.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 . - */ - -#include "ArtworkUtils.hpp" - -#include "database/Artwork.hpp" -#include "database/Image.hpp" -#include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackEmbeddedImage.hpp" - -namespace lms::scanner::utils -{ - db::ObjectPtr getOrCreateArtworkFromTrackEmbeddedImage(db::Session& session, db::TrackEmbeddedImageId trackEmbeddedImageId) - { - assert(trackEmbeddedImageId.isValid()); - session.checkWriteTransaction(); - - db::ObjectPtr artwork{ db::Artwork::find(session, trackEmbeddedImageId) }; - if (!artwork) - { - db::TrackEmbeddedImage::pointer trackEmbeddedImage{ db::TrackEmbeddedImage::find(session, trackEmbeddedImageId) }; - assert(trackEmbeddedImage); - artwork = session.create(trackEmbeddedImage); - } - return artwork; - } - - db::ObjectPtr getOrCreateArtworkFromImage(db::Session& session, db::ImageId imageId) - { - assert(imageId.isValid()); - session.checkWriteTransaction(); - - db::ObjectPtr artwork{ db::Artwork::find(session, imageId) }; - if (!artwork) - { - db::Image::pointer image{ db::Image::find(session, imageId) }; - assert(image); - artwork = session.create(image); - } - return artwork; - } -} // namespace lms::scanner::utils \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/JobQueue.cpp b/src/libs/services/scanner/impl/steps/JobQueue.cpp new file mode 100644 index 00000000..aa5db125 --- /dev/null +++ b/src/libs/services/scanner/impl/steps/JobQueue.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include "JobQueue.hpp" + +#include + +#include "core/IJob.hpp" +#include "core/IJobScheduler.hpp" + +namespace lms::scanner +{ + JobQueue::JobQueue(core::IJobScheduler& scheduler, std::size_t maxQueueSize, ProcessFunction processJobsDoneFunc, std::size_t batchSize, float _drainThreshold) + : _scheduler{ scheduler } + , _maxQueueSize{ maxQueueSize } + , _processJobsDoneFunc{ std::move(processJobsDoneFunc) } + , _batchSize{ batchSize } + , _drainThreshold{ _drainThreshold } + { + assert(_scheduler.getJobsDoneCount() == 0); + } + + JobQueue::~JobQueue() + { + finish(); + } + + void JobQueue::push(std::unique_ptr job) + { + _scheduler.scheduleJob(std::move(job)); + drainIfNeeded(); + } + + void JobQueue::finish() + { + _scheduler.wait(); + while (_scheduler.popJobsDone(_jobsDone, _batchSize) > 0) + { + _processJobsDoneFunc(std::span{ _jobsDone }); + _jobsDone.clear(); + } + } + + void JobQueue::drainIfNeeded() + { + while (_scheduler.getJobsDoneCount() > static_cast(_maxQueueSize * _drainThreshold)) + { + _scheduler.popJobsDone(_jobsDone, _batchSize); + _processJobsDoneFunc(std::span{ _jobsDone }); + _jobsDone.clear(); + } + _scheduler.waitUntilJobCountAtMost(_maxQueueSize); + } +} // namespace lms::scanner \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/JobQueue.hpp b/src/libs/services/scanner/impl/steps/JobQueue.hpp new file mode 100644 index 00000000..59ce792f --- /dev/null +++ b/src/libs/services/scanner/impl/steps/JobQueue.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2025 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 . + */ +#include +#include +#include +#include + +namespace lms::core +{ + class IJob; + class IJobScheduler; +} // namespace lms::core + +namespace lms::scanner +{ + class JobQueue + { + public: + using ProcessFunction = std::function>)>; + + JobQueue(core::IJobScheduler& scheduler, std::size_t maxQueueSize, ProcessFunction processJobsDoneFunc, std::size_t batchSize, float drainThreshold); + ~JobQueue(); + JobQueue(const JobQueue&) = delete; + JobQueue& operator=(const JobQueue&) = delete; + + // push can wait and invoke the supplied ProcessFunction + void push(std::unique_ptr job); + void finish(); + + private: + void drainIfNeeded(); + + core::IJobScheduler& _scheduler; + const std::size_t _maxQueueSize; + ProcessFunction _processJobsDoneFunc; + const std::size_t _batchSize; + const float _drainThreshold; + std::vector> _jobsDone; + }; + +} // namespace lms::scanner \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index d3e4146f..ed9d4b30 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -24,9 +24,9 @@ #include #include #include -#include #include "core/IConfig.hpp" +#include "core/IJob.hpp" #include "core/ILogger.hpp" #include "core/Path.hpp" #include "core/String.hpp" @@ -41,7 +41,7 @@ #include "database/Session.hpp" #include "database/Track.hpp" -#include "ArtworkUtils.hpp" +#include "JobQueue.hpp" #include "ScanContext.hpp" #include "ScannerSettings.hpp" @@ -49,42 +49,24 @@ namespace lms::scanner { namespace { - using ArtistArtwork = std::variant; // TODO handle embedded images in tracks? - bool isSameArtwork(ArtistArtwork preferredArtwork, const db::ObjectPtr& artwork) - { - if (std::holds_alternative(preferredArtwork)) - return !artwork; - - if (const db::ImageId* imageId = std::get_if(&preferredArtwork)) - return artwork && *imageId == artwork->getImageId(); - - if (const db::ArtworkId* artworkId = std::get_if(&preferredArtwork)) - return artwork && *artworkId == artwork->getId(); - - return false; - } - struct ArtistArtworkAssociation { - db::Artist::pointer artist; - ArtistArtwork preferredArtwork; + db::ArtistId artistId; + db::ArtworkId preferredArtworkId; }; using ArtistArtworkAssociationContainer = std::deque; - struct SearchArtistImageContext + struct SearchArtistArtworkParams { - db::Session& session; - db::ArtistId lastRetrievedArtistId; - std::size_t processedArtistCount{}; std::span artistFileNames; const ScannerSettings& settings; }; - db::Image::pointer findImageInDirectory(SearchArtistImageContext& searchContext, const std::filesystem::path& directoryPath, std::span fileStemsToSearch) + db::Image::pointer findImageInDirectory(db::Session& session, const std::filesystem::path& directoryPath, std::span fileStemsToSearch) { db::Image::pointer image; - const db::Directory::pointer directory{ db::Directory::find(searchContext.session, directoryPath) }; + const db::Directory::pointer directory{ db::Directory::find(session, directoryPath) }; if (directory) // may not exist for artists that are split on different media libraries { for (std::string_view fileStem : fileStemsToSearch) @@ -93,7 +75,7 @@ namespace lms::scanner params.setDirectory(directory->getId()); params.setFileStem(fileStem); - db::Image::find(searchContext.session, params, [&](const db::Image::pointer foundImg) { + db::Image::find(session, params, [&](const db::Image::pointer foundImg) { if (!image) image = foundImg; }); @@ -106,38 +88,38 @@ namespace lms::scanner return image; } - db::ImageId getImageFromMbid(SearchArtistImageContext& searchContext, const core::UUID& mbid) + db::Image::pointer getImageFromMbid(db::Session& session, const core::UUID& mbid) { db::Image::pointer image; // Find anywhere, since it is supposed to be unique! - db::Image::find(searchContext.session, db::Image::FindParameters{}.setFileStem(mbid.getAsString()), [&](const db::Image::pointer foundImg) { + db::Image::find(session, db::Image::FindParameters{}.setFileStem(mbid.getAsString()), [&](const db::Image::pointer foundImg) { if (!image) image = foundImg; }); - return image ? image->getId() : db::ImageId{}; + return image; } - db::ImageId searchImageInArtistInfoDirectory(SearchArtistImageContext& searchContext, db::ArtistId artistId) + db::Image::pointer searchImageInArtistInfoDirectory(db::Session& session, db::ArtistId artistId) { db::Image::pointer image; std::vector fileInfoPaths; - db::ArtistInfo::find(searchContext.session, artistId, [&](const db::ArtistInfo::pointer& artistInfo) { + db::ArtistInfo::find(session, artistId, [&](const db::ArtistInfo::pointer& artistInfo) { fileInfoPaths.push_back(artistInfo->getAbsoluteFilePath()); if (!image) - image = findImageInDirectory(searchContext, artistInfo->getDirectory()->getAbsolutePath(), std::array{ "thumb", "folder" }); + image = findImageInDirectory(session, artistInfo->getDirectory()->getAbsolutePath(), std::array{ "thumb", "folder" }); }); if (fileInfoPaths.size() > 1) LMS_LOG(DBUPDATER, DEBUG, "Found " << fileInfoPaths.size() << " artist info files for same artist: " << core::stringUtils::joinStrings(fileInfoPaths, ", ")); - return image ? image->getId() : db::ImageId{}; + return image; } - db::ImageId searchImageInDirectories(SearchArtistImageContext& searchContext, db::ArtistId artistId) + db::Image::pointer searchImageInDirectories(db::Session& session, const SearchArtistArtworkParams& searchParams, db::ArtistId artistId) { db::Image::pointer image; @@ -145,7 +127,7 @@ namespace lms::scanner db::Directory::FindParameters params; params.setArtist(artistId, { db::TrackArtistLinkType::ReleaseArtist }); - db::Directory::find(searchContext.session, params, [&](const db::Directory::pointer& directory) { + db::Directory::find(session, params, [&](const db::Directory::pointer& directory) { releasePaths.insert(directory->getAbsolutePath()); }); @@ -164,9 +146,9 @@ namespace lms::scanner std::filesystem::path directoryToInspect{ core::pathUtils::getLongestCommonPath(std::cbegin(releasePaths), std::cend(releasePaths)) }; while (true) { - image = findImageInDirectory(searchContext, directoryToInspect, searchContext.artistFileNames); + image = findImageInDirectory(session, directoryToInspect, searchParams.artistFileNames); if (image) - return image->getId(); + return image; std::filesystem::path parentPath{ directoryToInspect.parent_path() }; if (parentPath == directoryToInspect) @@ -181,106 +163,74 @@ namespace lms::scanner // /someOtherUserConfiguredArtistFile.jpg for (const std::filesystem::path& releasePath : releasePaths) { - image = findImageInDirectory(searchContext, releasePath, searchContext.artistFileNames); + image = findImageInDirectory(session, releasePath, searchParams.artistFileNames); if (image) - return image->getId(); + return image; } } - return image ? image->getId() : db::ImageId{}; + return image; } - db::ArtworkId getFirstReleaseArtwork(db::Session& session, const db::Artist::pointer& artist) + db::Artwork::pointer getFirstReleaseArtwork(db::Session& session, const db::Artist::pointer& artist) { - db::ArtworkId artworkId; + db::Artwork::pointer artwork; db::Release::FindParameters params; params.setArtist(artist->getId(), { db::TrackArtistLinkType::ReleaseArtist }); params.setSortMethod(db::ReleaseSortMethod::OriginalDate); db::Release::find(session, params, [&](const db::Release::pointer& release) { - if (artworkId.isValid()) + if (artwork) return; - artworkId = release->getPreferredArtworkId(); + artwork = release->getPreferredArtwork(); }); - return artworkId; + return artwork; } - ArtistArtwork computePreferredArtwork(SearchArtistImageContext& searchContext, const db::Artist::pointer& artist) + db::Artwork::pointer computePreferredArtistArtwork(db::Session& session, const SearchArtistArtworkParams& searchParams, const db::Artist::pointer& artist) { - db::ImageId imageId; - if (const auto mbid{ artist->getMBID() }) { - imageId = getImageFromMbid(searchContext, *mbid); - if (imageId.isValid()) - return ArtistArtwork{ imageId }; + const db::Image::pointer image{ getImageFromMbid(session, *mbid) }; + if (image) + return db::Artwork::find(session, image->getId()); } - imageId = searchImageInArtistInfoDirectory(searchContext, artist->getId()); - if (imageId.isValid()) - return ArtistArtwork{ imageId }; - - imageId = searchImageInDirectories(searchContext, artist->getId()); - if (imageId.isValid()) - return ArtistArtwork{ imageId }; - - if (searchContext.settings.artistImageFallbackToRelease) - { - db::ArtworkId artworkId{ getFirstReleaseArtwork(searchContext.session, artist) }; - if (artworkId.isValid()) - return ArtistArtwork{ artworkId }; - } - - return ArtistArtwork{}; - } - - bool fetchNextArtistArtworksToUpdate(SearchArtistImageContext& searchContext, ArtistArtworkAssociationContainer& ArtistArtworkAssociations) - { - const db::ArtistId artistId{ searchContext.lastRetrievedArtistId }; - { - constexpr std::size_t readBatchSize{ 100 }; - - auto transaction{ searchContext.session.createReadTransaction() }; - - db::Artist::find(searchContext.session, searchContext.lastRetrievedArtistId, readBatchSize, [&](const db::Artist::pointer& artist) { - ArtistArtwork preferredArtwork{ computePreferredArtwork(searchContext, artist) }; - - if (!isSameArtwork(preferredArtwork, artist->getPreferredArtwork())) - ArtistArtworkAssociations.push_back(ArtistArtworkAssociation{ artist, preferredArtwork }); - - searchContext.processedArtistCount++; - }); + const db::Image::pointer image{ searchImageInArtistInfoDirectory(session, artist->getId()) }; + if (image) + return db::Artwork::find(session, image->getId()); } - return artistId != searchContext.lastRetrievedArtistId; + { + const db::Image::pointer image{ searchImageInDirectories(session, searchParams, artist->getId()) }; + if (image) + return db::Artwork::find(session, image->getId()); + } + + if (searchParams.settings.artistImageFallbackToRelease) + { + const db::Artwork::pointer artwork{ getFirstReleaseArtwork(session, artist) }; + if (artwork) + return artwork; + } + + return db::Artwork::pointer{}; } - void updateArtistPreferredArtwork(db::Session& session, const ArtistArtworkAssociation& ArtistArtworkAssociation) + void updateArtistPreferredArtwork(db::Session& session, const ArtistArtworkAssociation& artistArtworkAssociation) { - db::Artist::pointer artist{ ArtistArtworkAssociation.artist }; - - db::Artwork::pointer artwork; - if (const db::ImageId * imageId{ std::get_if(&ArtistArtworkAssociation.preferredArtwork) }) - artwork = utils::getOrCreateArtworkFromImage(session, *imageId); - else if (const db::ArtworkId * artworkId{ std::get_if(&ArtistArtworkAssociation.preferredArtwork) }) - artwork = db::Artwork::find(session, *artworkId); - - artist.modify()->setPreferredArtwork(artwork); - if (artwork) - LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork for artist '" << artist->getName() << "' with image in " << artwork->getAbsoluteFilePath()); - else - LMS_LOG(DBUPDATER, DEBUG, "Removed preferred artwork from artist '" << artist->getName() << "'"); + db::Artist::updatePreferredArtwork(session, artistArtworkAssociation.artistId, artistArtworkAssociation.preferredArtworkId); } - void updateArtistArtworks(db::Session& session, ArtistArtworkAssociationContainer& imageAssociations) + void updateArtistPreferredArtworks(db::Session& session, ArtistArtworkAssociationContainer& imageAssociations, bool forceFullBatch) { constexpr std::size_t writeBatchSize{ 50 }; - while (!imageAssociations.empty()) + while ((forceFullBatch && imageAssociations.size() >= writeBatchSize) || !imageAssociations.empty()) { auto transaction{ session.createWriteTransaction() }; @@ -305,6 +255,62 @@ namespace lms::scanner return res; } + bool fetchNextArtistIdRange(db::Session& session, db::ArtistId& lastRetrievedId, db::IdRange& idRange) + { + constexpr std::size_t readBatchSize{ 100 }; + + auto transaction{ session.createReadTransaction() }; + + idRange = db::Artist::findNextRange(session, lastRetrievedId, readBatchSize); + lastRetrievedId = idRange.last; + + return idRange.isValid(); + } + + class ComputeArtistArtworkAssociationsJob : public core::IJob + { + public: + ComputeArtistArtworkAssociationsJob(db::Db& db, const SearchArtistArtworkParams& searchParams, db::IdRange artistIdRange) + : _db{ db } + , _searchParams{ searchParams } + , _artistIdRange{ artistIdRange } + { + } + + std::span getAssociations() const { return _associations; } + std::size_t getProcessedArtistCount() const { return _processedArtistCount; } + + private: + core::LiteralString getName() const override { return "Associate Track Artworks"; } + void run() override + { + auto& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; + + db::Artist::find(session, _artistIdRange, [this, &session](const db::Artist::pointer& artist) { + const db::Artwork::pointer preferredArtwork{ computePreferredArtistArtwork(session, _searchParams, artist) }; + + if (artist->getPreferredArtwork() != preferredArtwork) + { + _associations.push_back(ArtistArtworkAssociation{ artist->getId(), preferredArtwork ? preferredArtwork->getId() : db::ArtworkId{} }); + + if (preferredArtwork) + LMS_LOG(DBUPDATER, DEBUG, "Updating preferred artwork for artist '" << artist->getName() << "' with image in " << preferredArtwork->getAbsoluteFilePath()); + else + LMS_LOG(DBUPDATER, DEBUG, "Removing preferred artwork from artist '" << artist->getName() << "'"); + } + + _processedArtistCount++; + }); + } + + db::Db& _db; + const SearchArtistArtworkParams& _searchParams; + db::IdRange _artistIdRange; + std::vector _associations; + std::size_t _processedArtistCount{}; + }; + } // namespace ScanStepAssociateArtistImages::ScanStepAssociateArtistImages(InitParams& initParams) @@ -333,22 +339,40 @@ namespace lms::scanner context.currentStepStats.totalElems = db::Artist::getCount(session); } - SearchArtistImageContext searchContext{ - .session = session, - .lastRetrievedArtistId = {}, + const SearchArtistArtworkParams searchParams{ .artistFileNames = _artistFileNames, .settings = _settings, }; - ArtistArtworkAssociationContainer ArtistArtworkAssociations; - while (fetchNextArtistArtworksToUpdate(searchContext, ArtistArtworkAssociations)) - { + ArtistArtworkAssociationContainer artistArtworkAssociations; + auto processJobsDone = [&](std::span> jobs) { if (_abortScan) return; - updateArtistArtworks(session, ArtistArtworkAssociations); - context.currentStepStats.processedElems = searchContext.processedArtistCount; + for (const auto& job : jobs) + { + const auto& associationJob{ static_cast(*job) }; + const auto& artistAssociations{ associationJob.getAssociations() }; + + artistArtworkAssociations.insert(std::end(artistArtworkAssociations), std::cbegin(artistAssociations), std::cend(artistAssociations)); + + context.currentStepStats.processedElems += associationJob.getProcessedArtistCount(); + } + + updateArtistPreferredArtworks(session, artistArtworkAssociations, true); _progressCallback(context.currentStepStats); - } + }; + + JobQueue queue{ getJobScheduler(), 20, processJobsDone, 1, 0.85F }; + + db::ArtistId lastRetrievedArtistId{}; + db::IdRange artistIdRange; + while (fetchNextArtistIdRange(session, lastRetrievedArtistId, artistIdRange)) + queue.push(std::make_unique(_db, searchParams, artistIdRange)); + + queue.finish(); + + // process all remaining associations + updateArtistPreferredArtworks(session, artistArtworkAssociations, false); } } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index adba6876..b6a03229 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -23,9 +23,9 @@ #include #include #include -#include #include "core/IConfig.hpp" +#include "core/IJob.hpp" #include "core/ILogger.hpp" #include "core/Path.hpp" #include "database/Artwork.hpp" @@ -36,92 +36,73 @@ #include "database/Session.hpp" #include "database/Track.hpp" #include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageId.hpp" -#include "ArtworkUtils.hpp" +#include "JobQueue.hpp" #include "ScanContext.hpp" namespace lms::scanner { namespace { - using ReleaseArtwork = std::variant; - bool isSameArtwork(ReleaseArtwork preferredArtwork, const db::ObjectPtr& artwork) - { - if (std::holds_alternative(preferredArtwork)) - return !artwork; - - if (const db::TrackEmbeddedImageId* trackEmbeddedImageId = std::get_if(&preferredArtwork)) - return artwork && *trackEmbeddedImageId == artwork->getTrackEmbeddedImageId(); - - if (const db::ImageId* imageId = std::get_if(&preferredArtwork)) - return artwork && *imageId == artwork->getImageId(); - - return false; - } - struct ReleaseArtworkAssociation { - db::Release::pointer release; - ReleaseArtwork preferredArtwork; + db::ReleaseId releaseId; + db::ArtworkId preferredArtworkId; }; using ReleaseArtworkAssociationContainer = std::deque; - struct SearchReleaseArtworkContext + struct SearchReleaseArtworkParams { - db::Session& session; - db::ReleaseId lastRetrievedReleaseId; - std::size_t processedReleaseCount{}; const std::vector& releaseImageFileNames; }; - db::Image::pointer findImageInDirectory(SearchReleaseArtworkContext& searchContext, const std::filesystem::path& directoryPath) + db::Artwork::pointer findImageInDirectory(db::Session& session, const SearchReleaseArtworkParams& searchParams, const std::filesystem::path& directoryPath) { - db::Image::pointer image; + db::Artwork::pointer artwork; - const db::Directory::pointer directory{ db::Directory::find(searchContext.session, directoryPath) }; + const db::Directory::pointer directory{ db::Directory::find(session, directoryPath) }; if (directory) // may not exist for releases that are split on different media libraries { - for (std::string_view fileStem : searchContext.releaseImageFileNames) + for (std::string_view fileStem : searchParams.releaseImageFileNames) { db::Image::FindParameters params; params.setDirectory(directory->getId()); params.setFileStem(fileStem); - db::Image::find(searchContext.session, params, [&](const db::Image::pointer foundImg) { - if (!image) - image = foundImg; + db::Image::find(session, params, [&](const db::Image::pointer& image) { + if (!artwork) + artwork = db::Artwork::find(session, image->getId()); }); - if (image) + if (artwork) break; } } - return image; + return artwork; } - db::Image::pointer computePreferredReleaseImage(SearchReleaseArtworkContext& searchContext, const db::Release::pointer& release) + db::Artwork::pointer computePreferredReleaseImage(db::Session& session, const SearchReleaseArtworkParams& searchParams, const db::Release::pointer& release) { - db::Image::pointer image; + db::Artwork::pointer artwork; const auto mbid{ release->getMBID() }; if (mbid) { // Find anywhere, since it is suppoed to be unique! - db::Image::find(searchContext.session, db::Image::FindParameters{}.setFileStem(mbid->getAsString()), [&](const db::Image::pointer foundImg) { - if (!image) - image = foundImg; + db::Image::find(session, db::Image::FindParameters{}.setFileStem(mbid->getAsString()), [&](const db::Image::pointer& image) { + if (!artwork) + artwork = db::Artwork::find(session, image->getId()); }); } - if (!image) + if (!artwork) { std::set releasePaths; db::Directory::FindParameters params; params.setRelease(release->getId()); - db::Directory::find(searchContext.session, params, [&](const db::Directory::pointer& directory) { + db::Directory::find(session, params, [&](const db::Directory::pointer& directory) { releasePaths.insert(directory->getAbsolutePath()); }); @@ -132,31 +113,30 @@ namespace lms::scanner if (releasePaths.size() > 1) { const std::filesystem::path releasePath{ core::pathUtils::getLongestCommonPath(std::cbegin(releasePaths), std::cend(releasePaths)) }; - image = findImageInDirectory(searchContext, releasePath); + artwork = findImageInDirectory(session, searchParams, releasePath); } - if (!image) + if (!artwork) { for (const std::filesystem::path& releasePath : releasePaths) { - image = findImageInDirectory(searchContext, releasePath); - if (image) + artwork = findImageInDirectory(session, searchParams, releasePath); + if (artwork) break; } } } - return image; + return artwork; } - ReleaseArtwork computePreferredReleaseArtwork(SearchReleaseArtworkContext& searchContext, const db::Release::pointer& release) + db::Artwork::pointer computePreferredReleaseArtwork(db::Session& session, const SearchReleaseArtworkParams& searchParams, const db::Release::pointer& release) { - const db::Image::pointer image{ computePreferredReleaseImage(searchContext, release) }; - if (image) - return ReleaseArtwork{ image->getId() }; + db::Artwork::pointer artwork{ computePreferredReleaseImage(session, searchParams, release) }; + if (artwork) + return artwork; // Fallback on embedded Front image - db::TrackEmbeddedImageId trackEmbeddedImageId; { db::TrackEmbeddedImage::FindParameters params; params.setRelease(release->getId()); @@ -164,11 +144,11 @@ namespace lms::scanner params.setSortMethod(db::TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(searchContext.session, params, [&](const db::TrackEmbeddedImage::pointer& image) { trackEmbeddedImageId = image->getId(); }); + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { artwork = db::Artwork::find(session, image->getId()); }); } - if (trackEmbeddedImageId.isValid()) - return ReleaseArtwork{ trackEmbeddedImageId }; + if (artwork) + return artwork; // Fallback on embedded media image { @@ -178,66 +158,28 @@ namespace lms::scanner params.setSortMethod(db::TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(searchContext.session, params, [&](const db::TrackEmbeddedImage::pointer& image) { trackEmbeddedImageId = image->getId(); }); + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { artwork = db::Artwork::find(session, image->getId()); }); } - if (trackEmbeddedImageId.isValid()) - return ReleaseArtwork{ trackEmbeddedImageId }; - - return ReleaseArtwork{}; + return artwork; } - bool fetchNextReleaseArtworksToUpdate(SearchReleaseArtworkContext& searchContext, ReleaseArtworkAssociationContainer& ReleaseArtworkAssociations) + void updateReleasePreferredArtwork(db::Session& session, const ReleaseArtworkAssociation& releaseArtworkAssociation) { - const db::ReleaseId releaseId{ searchContext.lastRetrievedReleaseId }; - - { - constexpr std::size_t readBatchSize{ 100 }; - - auto transaction{ searchContext.session.createReadTransaction() }; - - db::Release::find(searchContext.session, searchContext.lastRetrievedReleaseId, readBatchSize, [&](const db::Release::pointer& release) { - const ReleaseArtwork preferredArtwork{ computePreferredReleaseArtwork(searchContext, release) }; - const db::Artwork::pointer currentPreferredArtwork{ release->getPreferredArtwork() }; - - if (!isSameArtwork(preferredArtwork, currentPreferredArtwork)) - ReleaseArtworkAssociations.push_back(ReleaseArtworkAssociation{ release, preferredArtwork }); - searchContext.processedReleaseCount++; - }); - } - - return releaseId != searchContext.lastRetrievedReleaseId; + db::Release::updatePreferredArtwork(session, releaseArtworkAssociation.releaseId, releaseArtworkAssociation.preferredArtworkId); } - void updateReleaseArtwork(db::Session& session, const ReleaseArtworkAssociation& ReleaseArtworkAssociation) - { - db::Release::pointer release{ ReleaseArtworkAssociation.release }; - - db::Artwork::pointer artwork; - if (const db::TrackEmbeddedImageId * trackEmbeddedImageId{ std::get_if(&ReleaseArtworkAssociation.preferredArtwork) }) - artwork = utils::getOrCreateArtworkFromTrackEmbeddedImage(session, *trackEmbeddedImageId); - else if (const db::ImageId * imageId{ std::get_if(&ReleaseArtworkAssociation.preferredArtwork) }) - artwork = utils::getOrCreateArtworkFromImage(session, *imageId); - - release.modify()->setPreferredArtwork(artwork); - - if (artwork) - LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork in release '" << release->getName() << "' with image in " << artwork->getAbsoluteFilePath()); - else - LMS_LOG(DBUPDATER, DEBUG, "Removed preferred artwork from release '" << release->getName() << "'"); - } - - void updateReleaseArtworks(db::Session& session, ReleaseArtworkAssociationContainer& imageAssociations) + void updateReleasePreferredArtworks(db::Session& session, ReleaseArtworkAssociationContainer& imageAssociations, bool forceFullBatch) { constexpr std::size_t writeBatchSize{ 50 }; - while (!imageAssociations.empty()) + while ((forceFullBatch && imageAssociations.size() >= writeBatchSize) || !imageAssociations.empty()) { auto transaction{ session.createWriteTransaction() }; for (std::size_t i{}; !imageAssociations.empty() && i < writeBatchSize; ++i) { - updateReleaseArtwork(session, imageAssociations.front()); + updateReleasePreferredArtwork(session, imageAssociations.front()); imageAssociations.pop_front(); } } @@ -256,6 +198,62 @@ namespace lms::scanner return res; } + bool fetchNextReleaseIdRange(db::Session& session, db::ReleaseId& lastRetrievedId, db::IdRange& idRange) + { + constexpr std::size_t readBatchSize{ 100 }; + + auto transaction{ session.createReadTransaction() }; + + idRange = db::Release::findNextRange(session, lastRetrievedId, readBatchSize); + lastRetrievedId = idRange.last; + + return idRange.isValid(); + } + + class ComputeReleaseArtworkAssociationsJob : public core::IJob + { + public: + ComputeReleaseArtworkAssociationsJob(db::Db& db, const SearchReleaseArtworkParams& searchParams, db::IdRange artistIdRange) + : _db{ db } + , _searchParams{ searchParams } + , _artistIdRange{ artistIdRange } + { + } + + std::span getAssociations() const { return _associations; } + std::size_t getProcessedReleaseCount() const { return _processedReleaseCount; } + + private: + core::LiteralString getName() const override { return "Associate Track Artworks"; } + void run() override + { + auto& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; + + db::Release::find(session, _artistIdRange, [this, &session](const db::Release::pointer& release) { + const db::Artwork::pointer preferredArtwork{ computePreferredReleaseArtwork(session, _searchParams, release) }; + + if (release->getPreferredArtwork() != preferredArtwork) + { + _associations.push_back(ReleaseArtworkAssociation{ release->getId(), preferredArtwork ? preferredArtwork->getId() : db::ArtworkId{} }); + + if (preferredArtwork) + LMS_LOG(DBUPDATER, DEBUG, "Updating preferred artwork for release '" << release->getName() << "' with image in " << preferredArtwork->getAbsoluteFilePath()); + else + LMS_LOG(DBUPDATER, DEBUG, "Removing preferred artwork from release '" << release->getName() << "'"); + } + + _processedReleaseCount++; + }); + } + + db::Db& _db; + const SearchReleaseArtworkParams& _searchParams; + db::IdRange _artistIdRange; + std::vector _associations; + std::size_t _processedReleaseCount{}; + }; + } // namespace ScanStepAssociateReleaseImages::ScanStepAssociateReleaseImages(InitParams& initParams) @@ -278,21 +276,39 @@ namespace lms::scanner context.currentStepStats.totalElems = db::Release::getCount(session); } - SearchReleaseArtworkContext searchContext{ - .session = session, - .lastRetrievedReleaseId = {}, + const SearchReleaseArtworkParams searchParams{ .releaseImageFileNames = _releaseImageFileNames, }; - ReleaseArtworkAssociationContainer ReleaseArtworkAssociations; - while (fetchNextReleaseArtworksToUpdate(searchContext, ReleaseArtworkAssociations)) - { + ReleaseArtworkAssociationContainer artistArtworkAssociations; + auto processJobsDone = [&](std::span> jobs) { if (_abortScan) return; - updateReleaseArtworks(session, ReleaseArtworkAssociations); - context.currentStepStats.processedElems = searchContext.processedReleaseCount; + for (const auto& job : jobs) + { + const auto& associationJob{ static_cast(*job) }; + const auto& artistAssociations{ associationJob.getAssociations() }; + + artistArtworkAssociations.insert(std::end(artistArtworkAssociations), std::cbegin(artistAssociations), std::cend(artistAssociations)); + + context.currentStepStats.processedElems += associationJob.getProcessedReleaseCount(); + } + + updateReleasePreferredArtworks(session, artistArtworkAssociations, true); _progressCallback(context.currentStepStats); - } + }; + + JobQueue queue{ getJobScheduler(), 20, processJobsDone, 1, 0.85F }; + + db::ReleaseId lastRetrievedReleaseId{}; + db::IdRange artistIdRange; + while (fetchNextReleaseIdRange(session, lastRetrievedReleaseId, artistIdRange)) + queue.push(std::make_unique(_db, searchParams, artistIdRange)); + + queue.finish(); + + // process all remaining associations + updateReleasePreferredArtworks(session, artistArtworkAssociations, false); } } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp index 035c505d..7514d85f 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp @@ -21,20 +21,23 @@ #include #include -#include +#include +#include "core/IJob.hpp" +#include "core/IJobScheduler.hpp" #include "core/ILogger.hpp" +#include "core/LiteralString.hpp" #include "database/Artwork.hpp" #include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IdRange.hpp" #include "database/Image.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageId.hpp" -#include "ArtworkUtils.hpp" +#include "JobQueue.hpp" #include "ScanContext.hpp" namespace lms::scanner @@ -42,37 +45,11 @@ namespace lms::scanner namespace { // May come from an embedded image in a track, or from what has been previously resolved for the release - using TrackArtwork = std::variant; - bool isSameArtwork(TrackArtwork preferredArtwork, const db::ObjectPtr& artwork) - { - if (std::holds_alternative(preferredArtwork)) - return !artwork; - - if (const db::TrackEmbeddedImageId* trackEmbeddedImageId = std::get_if(&preferredArtwork)) - { - assert(trackEmbeddedImageId->isValid()); - return artwork && *trackEmbeddedImageId == artwork->getTrackEmbeddedImageId(); - } - - if (const db::ArtworkId* artworkId = std::get_if(&preferredArtwork)) - { - assert(artworkId->isValid()); - return artwork && *artworkId == artwork->getId(); - } - - return false; - } - - bool isValid(const TrackArtwork& res) - { - return !std::holds_alternative(res); - } - struct TrackArtworksAssociation { - db::Track::pointer track; - TrackArtwork preferredArtwork; - TrackArtwork preferredMediaArtwork; + db::TrackId trackId; + std::optional preferredArtworkId; + std::optional preferredMediaArtworkId; }; using TrackArtworksAssociationContainer = std::deque; @@ -83,11 +60,10 @@ namespace lms::scanner std::size_t processedTrackCount{}; }; - TrackArtwork computePreferredTrackArtwork(SearchTrackArtworkContext& searchContext, const db::Track::pointer& track, TrackArtwork preferredMediaArtwork) + db::Artwork::pointer computePreferredTrackArtwork(db::Session& session, const db::Track::pointer& track, const db::Artwork::pointer& preferredMediaArtwork) { - TrackArtwork res{ preferredMediaArtwork }; - - if (isValid(res)) + db::Artwork::pointer res{ preferredMediaArtwork }; + if (res) return res; // Fallback on front cover for this track @@ -97,10 +73,10 @@ namespace lms::scanner params.setImageTypes({ db::ImageType::FrontCover }); params.setSortMethod(db::TrackEmbeddedImageSortMethod::SizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(searchContext.session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = image->getId(); }); + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); } - if (isValid(res)) + if (res) return res; // Fallback on the artwork already resolved for the release @@ -108,28 +84,26 @@ namespace lms::scanner if (!releaseId.isValid()) return res; - if (const db::Release::pointer release{ db::Release::find(searchContext.session, releaseId) }) - { - if (const db::ArtworkId releaseArtworkId{ release->getPreferredArtworkId() }; releaseArtworkId.isValid()) - res = releaseArtworkId; - } + if (const db::Release::pointer release{ db::Release::find(session, releaseId) }) + res = release->getPreferredArtwork(); return res; } - TrackArtwork computePreferredTrackMediaArtwork(SearchTrackArtworkContext& searchContext, const db::Track::pointer& track) + db::Artwork::pointer computePreferredTrackMediaArtwork(db::Session& session, const db::Track::pointer& track) { - TrackArtwork res; + db::Artwork::pointer res; + { db::TrackEmbeddedImage::FindParameters params; params.setTrack(track->getId()); params.setImageTypes({ db::ImageType::Media }); params.setSortMethod(db::TrackEmbeddedImageSortMethod::SizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(searchContext.session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = image->getId(); }); + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); } - if (isValid(res)) + if (res) return res; // fallback on another track of the same disc @@ -145,95 +119,28 @@ namespace lms::scanner params.setImageTypes({ db::ImageType::Media }); params.setSortMethod(db::TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(searchContext.session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = image->getId(); }); + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); } return res; } - bool fetchNextTrackArtworksToUpdate(SearchTrackArtworkContext& searchContext, TrackArtworksAssociationContainer& TrackArtworksAssociations) + void updateTrackPreferredArtworks(db::Session& session, const TrackArtworksAssociation& trackArtworksAssociation) { - const db::TrackId trackId{ searchContext.lastRetrievedTrackId }; + assert(trackArtworksAssociation.preferredArtworkId || trackArtworksAssociation.preferredMediaArtworkId); - { - constexpr std::size_t readBatchSize{ 100 }; + if (trackArtworksAssociation.preferredArtworkId) + db::Track::updatePreferredArtwork(session, trackArtworksAssociation.trackId, *trackArtworksAssociation.preferredArtworkId); - auto transaction{ searchContext.session.createReadTransaction() }; - - db::Track::find(searchContext.session, searchContext.lastRetrievedTrackId, readBatchSize, [&](const db::Track::pointer& track) { - const TrackArtwork preferredMediaArtwork{ computePreferredTrackMediaArtwork(searchContext, track) }; - const TrackArtwork preferredArtwork{ computePreferredTrackArtwork(searchContext, track, preferredMediaArtwork) }; - - const db::Artwork::pointer currentPreferredArtwork{ track->getPreferredArtwork() }; - const db::Artwork::pointer currentPreferredMediaArtwork{ track->getPreferredMediaArtwork() }; - - if (!isSameArtwork(preferredArtwork, currentPreferredArtwork) - || !isSameArtwork(preferredMediaArtwork, currentPreferredMediaArtwork)) - { - TrackArtworksAssociations.push_back(TrackArtworksAssociation{ .track = track, .preferredArtwork = preferredArtwork, .preferredMediaArtwork = preferredMediaArtwork }); - } - - searchContext.processedTrackCount++; - }); - } - - return trackId != searchContext.lastRetrievedTrackId; + if (trackArtworksAssociation.preferredMediaArtworkId) + db::Track::updatePreferredMediaArtwork(session, trackArtworksAssociation.trackId, *trackArtworksAssociation.preferredMediaArtworkId); } - void updateTrackPreferredArtwork(db::Session& session, db::Track::pointer& track, TrackArtwork preferredArtwork) - { - db::Artwork::pointer artwork; - if (const db::TrackEmbeddedImageId * trackEmbeddedImageId{ std::get_if(&preferredArtwork) }) - artwork = utils::getOrCreateArtworkFromTrackEmbeddedImage(session, *trackEmbeddedImageId); - else if (const db::ArtworkId * artworkId{ std::get_if(&preferredArtwork) }) - artwork = db::Artwork::find(session, *artworkId); - - // Using track.modify() is quite CPU intensive as the track class has too many fields - db::Track::updatePreferredArtwork(session, track->getId(), artwork ? artwork->getId() : db::ArtworkId{}); - if (artwork) - LMS_LOG(DBUPDATER, DEBUG, "Updated preferred artwork in track " << track->getAbsoluteFilePath() << " with image in " << artwork->getAbsoluteFilePath()); - else - LMS_LOG(DBUPDATER, DEBUG, "Removed preferred artwork from track " << track->getAbsoluteFilePath()); - } - - void updateTrackPreferredMediaArtwork(db::Session& session, db::Track::pointer& track, TrackArtwork preferredArtwork) - { - db::Artwork::pointer artwork; - if (const db::TrackEmbeddedImageId * trackEmbeddedImageId{ std::get_if(&preferredArtwork) }) - artwork = utils::getOrCreateArtworkFromTrackEmbeddedImage(session, *trackEmbeddedImageId); - else if (const db::ArtworkId * artworkId{ std::get_if(&preferredArtwork) }) - artwork = db::Artwork::find(session, *artworkId); - - // Using track.modify() is quite CPU intensive as the track class has too many fields - db::Track::updatePreferredMediaArtwork(session, track->getId(), artwork ? artwork->getId() : db::ArtworkId{}); - if (artwork) - LMS_LOG(DBUPDATER, DEBUG, "Updated preferred media artwork in track " << track->getAbsoluteFilePath() << " with image in " << artwork->getAbsoluteFilePath()); - else - LMS_LOG(DBUPDATER, DEBUG, "Removed preferred media artwork from track " << track->getAbsoluteFilePath()); - } - - void updateTrackPreferredArtworks(db::Session& session, const TrackArtworksAssociation& TrackArtworksAssociation) - { - db::Track::pointer track{ TrackArtworksAssociation.track }; - - { - const db::Artwork::pointer currentPreferredArtwork{ track->getPreferredArtwork() }; - if (!isSameArtwork(TrackArtworksAssociation.preferredArtwork, currentPreferredArtwork)) - updateTrackPreferredArtwork(session, track, TrackArtworksAssociation.preferredArtwork); - } - - { - const db::Artwork::pointer currentPreferredMediaArtwork{ track->getPreferredMediaArtwork() }; - if (!isSameArtwork(TrackArtworksAssociation.preferredMediaArtwork, currentPreferredMediaArtwork)) - updateTrackPreferredMediaArtwork(session, track, TrackArtworksAssociation.preferredMediaArtwork); - } - } - - void updateTrackPreferredArtworks(db::Session& session, TrackArtworksAssociationContainer& imageAssociations) + void updateTrackPreferredArtworks(db::Session& session, TrackArtworksAssociationContainer& imageAssociations, bool forceFullBatch) { constexpr std::size_t writeBatchSize{ 50 }; - while (!imageAssociations.empty()) + while ((forceFullBatch && imageAssociations.size() >= writeBatchSize) || !imageAssociations.empty()) { auto transaction{ session.createWriteTransaction() }; @@ -244,6 +151,76 @@ namespace lms::scanner } } } + + bool fetchNextTrackIdRange(SearchTrackArtworkContext& searchContext, db::IdRange& trackIdRange) + { + constexpr std::size_t readBatchSize{ 100 }; + + auto transaction{ searchContext.session.createReadTransaction() }; + + trackIdRange = db::Track::findNextRange(searchContext.session, searchContext.lastRetrievedTrackId, readBatchSize); + searchContext.lastRetrievedTrackId = trackIdRange.last; + + return trackIdRange.isValid(); + } + + class ComputeTrackArtworkAssociationsJob : public core::IJob + { + public: + ComputeTrackArtworkAssociationsJob(db::Db& db, db::IdRange trackIdRange) + : _db{ db } + , _trackIdRange{ trackIdRange } + { + } + + std::span getTrackAssociations() const { return _trackAssociations; } + std::size_t getProcessedTrackCount() const { return _processedTrackCount; } + + private: + core::LiteralString getName() const override { return "Associate Track Artworks"; } + void run() override + { + auto& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; + + db::Track::find(session, _trackIdRange, [&](const db::Track::pointer& track) { + const db::Artwork::pointer preferredMediaArtwork{ computePreferredTrackMediaArtwork(session, track) }; + const db::Artwork::pointer preferredArtwork{ computePreferredTrackArtwork(session, track, preferredMediaArtwork) }; + + TrackArtworksAssociation artworksAssociation{ .trackId = track->getId(), .preferredArtworkId = std::nullopt, .preferredMediaArtworkId = std::nullopt }; + + if (track->getPreferredArtwork() != preferredArtwork) + { + artworksAssociation.preferredArtworkId = preferredArtwork ? preferredArtwork->getId() : db::ArtworkId{}; + + if (preferredArtwork) + LMS_LOG(DBUPDATER, DEBUG, "Updating preferred artwork in track " << track->getAbsoluteFilePath() << " with image in " << preferredArtwork->getAbsoluteFilePath()); + else + LMS_LOG(DBUPDATER, DEBUG, "Removing preferred artwork from track " << track->getAbsoluteFilePath()); + } + + if (track->getPreferredMediaArtwork() != preferredMediaArtwork) + { + artworksAssociation.preferredMediaArtworkId = preferredMediaArtwork ? preferredMediaArtwork->getId() : db::ArtworkId{}; + + if (preferredMediaArtwork) + LMS_LOG(DBUPDATER, DEBUG, "Updating preferred media artwork in track " << track->getAbsoluteFilePath() << " with image in " << preferredMediaArtwork->getAbsoluteFilePath()); + else + LMS_LOG(DBUPDATER, DEBUG, "Removing preferred media artwork from track " << track->getAbsoluteFilePath()); + } + + if (artworksAssociation.preferredArtworkId || artworksAssociation.preferredMediaArtworkId) + _trackAssociations.push_back(artworksAssociation); + + _processedTrackCount++; + }); + } + + db::Db& _db; + db::IdRange _trackIdRange; + std::vector _trackAssociations; + std::size_t _processedTrackCount{}; + }; } // namespace ScanStepAssociateTrackImages::ScanStepAssociateTrackImages(InitParams& initParams) @@ -270,15 +247,34 @@ namespace lms::scanner .lastRetrievedTrackId = {}, }; - TrackArtworksAssociationContainer TrackArtworksAssociations; - while (fetchNextTrackArtworksToUpdate(searchContext, TrackArtworksAssociations)) - { + TrackArtworksAssociationContainer trackArtworksAssociations; + auto processTracks = [&](std::span> jobs) { if (_abortScan) return; - updateTrackPreferredArtworks(session, TrackArtworksAssociations); - context.currentStepStats.processedElems = searchContext.processedTrackCount; + for (const auto& job : jobs) + { + const auto& associationJob{ static_cast(*job) }; + const auto& trackAssociations{ associationJob.getTrackAssociations() }; + + trackArtworksAssociations.insert(std::end(trackArtworksAssociations), std::cbegin(trackAssociations), std::cend(trackAssociations)); + + context.currentStepStats.processedElems += associationJob.getProcessedTrackCount(); + } + + updateTrackPreferredArtworks(session, trackArtworksAssociations, true); _progressCallback(context.currentStepStats); - } + }; + + JobQueue queue{ getJobScheduler(), 20, processTracks, 1, 0.85F }; + + db::IdRange trackIdRange; + while (fetchNextTrackIdRange(searchContext, trackIdRange)) + queue.push(std::make_unique(_db, trackIdRange)); + + queue.finish(); + + // process all remaining associations + updateTrackPreferredArtworks(session, trackArtworksAssociations, false); } } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index 5ed9873e..27f13d50 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -31,6 +31,7 @@ #include "scanners/IFileScanOperation.hpp" #include "scanners/IFileScanner.hpp" +#include "JobQueue.hpp" #include "ScanContext.hpp" namespace lms::scanner @@ -114,11 +115,16 @@ namespace lms::scanner void ScanStepScanFiles::process(ScanContext& context, const MediaLibraryInfo& mediaLibrary) { - core::IJobScheduler& jobScheduler{ getJobScheduler() }; - assert(jobScheduler.getJobsDoneCount() == 0); - - const std::size_t scanQueueMaxScanRequestCount{ 100 * jobScheduler.getThreadCount() }; + const std::size_t scanQueueMaxScanRequestCount{ 50 * getJobScheduler().getThreadCount() }; constexpr std::size_t processFileResultsBatchSize{ 10 }; + constexpr float drainRatio{ 0.85 }; + + auto processDoneJobs = [&](std::span> jobsDone) { + if (!_abortScan) + processFileScanResults(context, jobsDone); + }; + + JobQueue queue{ getJobScheduler(), scanQueueMaxScanRequestCount, processDoneJobs, processFileResultsBatchSize, drainRatio }; std::vector> jobsDone; std::vector> scanOperations; @@ -148,7 +154,7 @@ namespace lms::scanner if (context.scanOptions.fullScan || scanner->needsScan(fileToScan)) { auto scanOperation{ scanner->createScanOperation(std::move(fileToScan)) }; - jobScheduler.scheduleJob(std::make_unique(std::move(scanOperation))); + queue.push(std::make_unique(std::move(scanOperation))); } } @@ -156,30 +162,9 @@ namespace lms::scanner _progressCallback(context.currentStepStats); } - while (jobScheduler.getJobsDoneCount() > (scanQueueMaxScanRequestCount / 2)) - { - jobScheduler.popJobsDone(jobsDone, processFileResultsBatchSize); - processFileScanResults(context, jobsDone); - jobsDone.clear(); - } - - jobScheduler.waitUntilJobCountAtMost(scanQueueMaxScanRequestCount); - return true; }, &excludeDirFileName); - - jobScheduler.wait(); - - while (jobScheduler.popJobsDone(jobsDone, processFileResultsBatchSize) > 0) - { - if (!_abortScan) - processFileScanResults(context, jobsDone); - - jobsDone.clear(); - } - - assert(jobScheduler.getJobsDoneCount() == 0); } void ScanStepScanFiles::processFileScanResults(ScanContext& context, std::span> scanJobs) @@ -191,9 +176,6 @@ namespace lms::scanner for (auto& scanJob : scanJobs) { - if (_abortScan) - return; - IFileScanOperation& scanOperation{ static_cast(*scanJob).getScanOperation() }; LMS_LOG(DBUPDATER, DEBUG, scanOperation.getName() << ": processing result for " << scanOperation.getFilePath()); From 41504c92e0c97c557d3d3cfc07c05220093e7482 Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 5 Jul 2025 10:25:29 +0200 Subject: [PATCH 13/46] Fixed unity build --- src/libs/services/scanner/impl/steps/JobQueue.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/services/scanner/impl/steps/JobQueue.hpp b/src/libs/services/scanner/impl/steps/JobQueue.hpp index 59ce792f..a7d16c9b 100644 --- a/src/libs/services/scanner/impl/steps/JobQueue.hpp +++ b/src/libs/services/scanner/impl/steps/JobQueue.hpp @@ -16,6 +16,9 @@ * You should have received a copy of the GNU General Public License * along with LMS. If not, see . */ + +#pragma once + #include #include #include From 1b73ae1e8c48766c0bc9694b43c1b3e6fc7069ff Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 5 Jul 2025 19:28:18 +0200 Subject: [PATCH 14/46] Scanner: parallelized processing within the playlist/track association step --- src/libs/database/impl/Artist.cpp | 2 +- src/libs/database/impl/PlayListFile.cpp | 21 ++ src/libs/database/impl/Release.cpp | 2 +- src/libs/database/impl/Track.cpp | 2 +- src/libs/database/include/database/Artist.hpp | 2 +- .../include/database/PlayListFile.hpp | 3 + .../database/include/database/Release.hpp | 2 +- src/libs/database/include/database/Track.hpp | 2 +- src/libs/database/test/Artist.cpp | 18 +- src/libs/database/test/Release.cpp | 18 +- src/libs/database/test/Track.cpp | 18 +- .../steps/ScanStepAssociateArtistImages.cpp | 4 +- .../steps/ScanStepAssociatePlayListTracks.cpp | 207 +++++++++++------- .../steps/ScanStepAssociateReleaseImages.cpp | 4 +- .../steps/ScanStepAssociateTrackImages.cpp | 33 +-- 15 files changed, 194 insertions(+), 144 deletions(-) diff --git a/src/libs/database/impl/Artist.cpp b/src/libs/database/impl/Artist.cpp index d3b106fe..04e44676 100644 --- a/src/libs/database/impl/Artist.cpp +++ b/src/libs/database/impl/Artist.cpp @@ -291,7 +291,7 @@ namespace lms::db utils::forEachQueryRangeResult(query, params.range, func); } - IdRange Artist::findNextRange(Session& session, ArtistId lastRetrievedId, std::size_t count) + IdRange Artist::findNextIdRange(Session& session, ArtistId lastRetrievedId, std::size_t count) { auto query{ session.getDboSession()->query>("SELECT MIN(sub.id) AS first_id, MAX(sub.id) AS last_id FROM (SELECT a.id FROM artist a WHERE a.id > ? ORDER BY a.id LIMIT ?) sub") }; query.bind(lastRetrievedId); diff --git a/src/libs/database/impl/PlayListFile.cpp b/src/libs/database/impl/PlayListFile.cpp index 49226d58..1f408f4c 100644 --- a/src/libs/database/impl/PlayListFile.cpp +++ b/src/libs/database/impl/PlayListFile.cpp @@ -83,6 +83,27 @@ namespace lms::db }); } + void PlayListFile::find(Session& session, const IdRange& idRange, const std::function& func) + { + assert(idRange.isValid()); + + auto query{ session.getDboSession()->query>("SELECT pl_f from playlist_file pl_f").orderBy("pl_f.id").where("pl_f.id BETWEEN ? AND ?").bind(idRange.first).bind(idRange.last) }; + + utils::forEachQueryResult(query, [&](const PlayListFile::pointer& release) { + func(release); + }); + } + + IdRange PlayListFile::findNextIdRange(Session& session, PlayListFileId lastRetrievedId, std::size_t count) + { + auto query{ session.getDboSession()->query>("SELECT MIN(sub.id) AS first_id, MAX(sub.id) AS last_id FROM (SELECT pl_f.id FROM playlist_file pl_f WHERE pl_f.id > ? ORDER BY pl_f.id LIMIT ?) sub") }; + query.bind(lastRetrievedId); + query.bind(static_cast(count)); + + auto res{ utils::fetchQuerySingleResult(query) }; + return IdRange{ .first = std::get<0>(res), .last = std::get<1>(res) }; + } + PlayListFile::pointer PlayListFile::find(Session& session, PlayListFileId id) { session.checkReadTransaction(); diff --git a/src/libs/database/impl/Release.cpp b/src/libs/database/impl/Release.cpp index d78d6f26..9b740d21 100644 --- a/src/libs/database/impl/Release.cpp +++ b/src/libs/database/impl/Release.cpp @@ -515,7 +515,7 @@ namespace lms::db }); } - IdRange Release::findNextRange(Session& session, ReleaseId lastRetrievedId, std::size_t count) + IdRange Release::findNextIdRange(Session& session, ReleaseId lastRetrievedId, std::size_t count) { auto query{ session.getDboSession()->query>("SELECT MIN(sub.id) AS first_id, MAX(sub.id) AS last_id FROM (SELECT r.id FROM release r WHERE r.id > ? ORDER BY r.id LIMIT ?) sub") }; query.bind(lastRetrievedId); diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp index 9b6384fd..c6d6cadb 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/Track.cpp @@ -303,7 +303,7 @@ namespace lms::db }); } - IdRange Track::findNextRange(Session& session, TrackId lastRetrievedId, std::size_t count) + IdRange Track::findNextIdRange(Session& session, TrackId lastRetrievedId, std::size_t count) { auto query{ session.getDboSession()->query>("SELECT MIN(sub.id) AS first_id, MAX(sub.id) AS last_id FROM (SELECT t.id FROM track t WHERE t.id > ? ORDER BY t.id LIMIT ?) sub") }; query.bind(lastRetrievedId); diff --git a/src/libs/database/include/database/Artist.hpp b/src/libs/database/include/database/Artist.hpp index dd38ed0c..051b7025 100644 --- a/src/libs/database/include/database/Artist.hpp +++ b/src/libs/database/include/database/Artist.hpp @@ -129,7 +129,7 @@ namespace lms::db static void find(Session& session, const IdRange& idRange, const std::function& func); static RangeResults find(Session& session, const FindParameters& params); static void find(Session& session, const FindParameters& params, std::function func); - static IdRange findNextRange(Session& session, ArtistId lastRetrievedId, std::size_t count); + static IdRange findNextIdRange(Session& session, ArtistId lastRetrievedId, std::size_t count); static RangeResults findIds(Session& session, const FindParameters& params); static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // No track related static bool exists(Session& session, ArtistId id); diff --git a/src/libs/database/include/database/PlayListFile.hpp b/src/libs/database/include/database/PlayListFile.hpp index 568d4dbb..bc53f7ce 100644 --- a/src/libs/database/include/database/PlayListFile.hpp +++ b/src/libs/database/include/database/PlayListFile.hpp @@ -28,6 +28,7 @@ #include #include "database/DirectoryId.hpp" +#include "database/IdRange.hpp" #include "database/Object.hpp" LMS_DECLARE_IDTYPE(PlayListFileId) @@ -50,6 +51,8 @@ namespace lms::db static pointer find(Session& session, const std::filesystem::path& path); static void find(Session& session, PlayListFileId& lastRetrievedId, std::size_t count, const std::function& func); static void findAbsoluteFilePath(Session& session, PlayListFileId& lastRetrievedId, std::size_t count, const std::function& func); + static void find(Session& session, const IdRange& idRange, const std::function& func); + static IdRange findNextIdRange(Session& session, PlayListFileId lastRetrievedId, std::size_t count); // getters const std::filesystem::path& getAbsoluteFilePath() const { return _absoluteFilePath; } diff --git a/src/libs/database/include/database/Release.hpp b/src/libs/database/include/database/Release.hpp index 7316b179..44a10eae 100644 --- a/src/libs/database/include/database/Release.hpp +++ b/src/libs/database/include/database/Release.hpp @@ -251,7 +251,7 @@ namespace lms::db static pointer find(Session& session, ReleaseId id); static void find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function& func, MediaLibraryId library = {}); static void find(Session& session, const IdRange& idRange, const std::function& func); - static IdRange findNextRange(Session& session, ReleaseId lastRetrievedId, std::size_t count); + static IdRange findNextIdRange(Session& session, ReleaseId lastRetrievedId, std::size_t count); static RangeResults find(Session& session, const FindParameters& parameters); static void find(Session& session, const FindParameters& parameters, const std::function& func); static RangeResults findIds(Session& session, const FindParameters& parameters); diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp index e967596e..3ab58cd5 100644 --- a/src/libs/database/include/database/Track.hpp +++ b/src/libs/database/include/database/Track.hpp @@ -194,7 +194,7 @@ namespace lms::db static pointer find(Session& session, TrackId id); static void find(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func, MediaLibraryId library = {}); static void find(Session& session, const IdRange& idRange, const std::function& func); - static IdRange findNextRange(Session& session, TrackId lastRetrievedId, std::size_t count); + static IdRange findNextIdRange(Session& session, TrackId lastRetrievedId, std::size_t count); static void findAbsoluteFilePath(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func); static bool exists(Session& session, TrackId id); diff --git a/src/libs/database/test/Artist.cpp b/src/libs/database/test/Artist.cpp index 2e53657d..5b52344a 100644 --- a/src/libs/database/test/Artist.cpp +++ b/src/libs/database/test/Artist.cpp @@ -608,17 +608,17 @@ namespace lms::db::tests } } - TEST_F(DatabaseFixture, Artist_findNextRange) + TEST_F(DatabaseFixture, Artist_findNextIdRange) { { auto transaction{ session.createReadTransaction() }; - auto range{ Artist::findNextRange(session, ArtistId{}, 0) }; + auto range{ Artist::findNextIdRange(session, ArtistId{}, 0) }; EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, ArtistId{}); EXPECT_EQ(range.last, ArtistId{}); - range = Artist::findNextRange(session, ArtistId{}, 100); + range = Artist::findNextIdRange(session, ArtistId{}, 100); EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, ArtistId{}); EXPECT_EQ(range.last, ArtistId{}); @@ -628,22 +628,22 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto range{ Artist::findNextRange(session, ArtistId{}, 0) }; + auto range{ Artist::findNextIdRange(session, ArtistId{}, 0) }; EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, ArtistId{}); EXPECT_EQ(range.last, ArtistId{}); - range = Artist::findNextRange(session, ArtistId{}, 1); + range = Artist::findNextIdRange(session, ArtistId{}, 1); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, artist1.getId()); EXPECT_EQ(range.last, artist1.getId()); - range = Artist::findNextRange(session, range.last, 1); + range = Artist::findNextIdRange(session, range.last, 1); EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, ArtistId{}); EXPECT_EQ(range.last, ArtistId{}); - range = Artist::findNextRange(session, ArtistId{}, 100); + range = Artist::findNextIdRange(session, ArtistId{}, 100); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, artist1.getId()); EXPECT_EQ(range.last, artist1.getId()); @@ -655,12 +655,12 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto range{ Artist::findNextRange(session, ArtistId{}, 2) }; + auto range{ Artist::findNextIdRange(session, ArtistId{}, 2) }; EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, artist1.getId()); EXPECT_EQ(range.last, artist2.getId()); - range = Artist::findNextRange(session, artist2.getId(), 2); + range = Artist::findNextIdRange(session, artist2.getId(), 2); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, artist3.getId()); EXPECT_EQ(range.last, artist3.getId()); diff --git a/src/libs/database/test/Release.cpp b/src/libs/database/test/Release.cpp index fc7cbc44..4d134964 100644 --- a/src/libs/database/test/Release.cpp +++ b/src/libs/database/test/Release.cpp @@ -173,17 +173,17 @@ namespace lms::db::tests } } - TEST_F(DatabaseFixture, Release_findNextRange) + TEST_F(DatabaseFixture, Release_findNextIdRange) { { auto transaction{ session.createReadTransaction() }; - auto range{ Release::findNextRange(session, ReleaseId{}, 0) }; + auto range{ Release::findNextIdRange(session, ReleaseId{}, 0) }; EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, ReleaseId{}); EXPECT_EQ(range.last, ReleaseId{}); - range = Release::findNextRange(session, ReleaseId{}, 100); + range = Release::findNextIdRange(session, ReleaseId{}, 100); EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, ReleaseId{}); EXPECT_EQ(range.last, ReleaseId{}); @@ -193,22 +193,22 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto range{ Release::findNextRange(session, ReleaseId{}, 0) }; + auto range{ Release::findNextIdRange(session, ReleaseId{}, 0) }; EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, ReleaseId{}); EXPECT_EQ(range.last, ReleaseId{}); - range = Release::findNextRange(session, ReleaseId{}, 1); + range = Release::findNextIdRange(session, ReleaseId{}, 1); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, release1.getId()); EXPECT_EQ(range.last, release1.getId()); - range = Release::findNextRange(session, range.last, 1); + range = Release::findNextIdRange(session, range.last, 1); EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, ReleaseId{}); EXPECT_EQ(range.last, ReleaseId{}); - range = Release::findNextRange(session, ReleaseId{}, 100); + range = Release::findNextIdRange(session, ReleaseId{}, 100); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, release1.getId()); EXPECT_EQ(range.last, release1.getId()); @@ -220,12 +220,12 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto range{ Release::findNextRange(session, ReleaseId{}, 2) }; + auto range{ Release::findNextIdRange(session, ReleaseId{}, 2) }; EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, release1.getId()); EXPECT_EQ(range.last, release2.getId()); - range = Release::findNextRange(session, release2.getId(), 2); + range = Release::findNextIdRange(session, release2.getId(), 2); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, release3.getId()); EXPECT_EQ(range.last, release3.getId()); diff --git a/src/libs/database/test/Track.cpp b/src/libs/database/test/Track.cpp index e88b6ce2..5fb48041 100644 --- a/src/libs/database/test/Track.cpp +++ b/src/libs/database/test/Track.cpp @@ -151,17 +151,17 @@ namespace lms::db::tests } } - TEST_F(DatabaseFixture, Track_findNextRange) + TEST_F(DatabaseFixture, Track_findNextIdRange) { { auto transaction{ session.createReadTransaction() }; - auto range{ Track::findNextRange(session, TrackId{}, 0) }; + auto range{ Track::findNextIdRange(session, TrackId{}, 0) }; EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, TrackId{}); EXPECT_EQ(range.last, TrackId{}); - range = Track::findNextRange(session, TrackId{}, 100); + range = Track::findNextIdRange(session, TrackId{}, 100); EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, TrackId{}); EXPECT_EQ(range.last, TrackId{}); @@ -171,22 +171,22 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto range{ Track::findNextRange(session, TrackId{}, 0) }; + auto range{ Track::findNextIdRange(session, TrackId{}, 0) }; EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, TrackId{}); EXPECT_EQ(range.last, TrackId{}); - range = Track::findNextRange(session, TrackId{}, 1); + range = Track::findNextIdRange(session, TrackId{}, 1); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, track1.getId()); EXPECT_EQ(range.last, track1.getId()); - range = Track::findNextRange(session, range.last, 1); + range = Track::findNextIdRange(session, range.last, 1); EXPECT_FALSE(range.isValid()); EXPECT_EQ(range.first, TrackId{}); EXPECT_EQ(range.last, TrackId{}); - range = Track::findNextRange(session, TrackId{}, 100); + range = Track::findNextIdRange(session, TrackId{}, 100); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, track1.getId()); EXPECT_EQ(range.last, track1.getId()); @@ -198,12 +198,12 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto range{ Track::findNextRange(session, TrackId{}, 2) }; + auto range{ Track::findNextIdRange(session, TrackId{}, 2) }; EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, track1.getId()); EXPECT_EQ(range.last, track2.getId()); - range = Track::findNextRange(session, track2.getId(), 2); + range = Track::findNextIdRange(session, track2.getId(), 2); EXPECT_TRUE(range.isValid()); EXPECT_EQ(range.first, track3.getId()); EXPECT_EQ(range.last, track3.getId()); diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index ed9d4b30..a25b83c0 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -261,7 +261,7 @@ namespace lms::scanner auto transaction{ session.createReadTransaction() }; - idRange = db::Artist::findNextRange(session, lastRetrievedId, readBatchSize); + idRange = db::Artist::findNextIdRange(session, lastRetrievedId, readBatchSize); lastRetrievedId = idRange.last; return idRange.isValid(); @@ -281,7 +281,7 @@ namespace lms::scanner std::size_t getProcessedArtistCount() const { return _processedArtistCount; } private: - core::LiteralString getName() const override { return "Associate Track Artworks"; } + core::LiteralString getName() const override { return "Associate Artist Artworks"; } void run() override { auto& session{ _db.getTLSSession() }; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp index 24308574..5d009edb 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp @@ -21,7 +21,9 @@ #include #include +#include +#include "core/IJob.hpp" #include "core/ILogger.hpp" #include "database/Db.hpp" #include "database/Directory.hpp" @@ -32,6 +34,7 @@ #include "database/TrackList.hpp" #include "services/scanner/ScanErrors.hpp" +#include "JobQueue.hpp" #include "ScanContext.hpp" #include "ScannerSettings.hpp" @@ -53,15 +56,6 @@ namespace lms::scanner }; using PlayListFileAssociationContainer = std::deque; - struct SearchPlayListFileContext - { - db::Session& session; - db::PlayListFileId lastRetrievedPlayListFileId; - std::size_t processedPlayListFileCount{}; - const ScannerSettings& settings; - std::vector> errors; - }; - db::Track::pointer getMatchingTrack(db::Session& session, const std::filesystem::path& filePath, const db::Directory::pointer& playListDirectory) { db::Track::pointer matchingTrack; @@ -110,64 +104,7 @@ namespace lms::scanner return needUpdate; } - bool fetchNextPlayListFilesToUpdate(SearchPlayListFileContext& searchContext, PlayListFileAssociationContainer& playListFileAssociations) - { - const db::PlayListFileId playListFileIdId{ searchContext.lastRetrievedPlayListFileId }; - - { - constexpr std::size_t readBatchSize{ 20 }; - - auto transaction{ searchContext.session.createReadTransaction() }; - - db::PlayListFile::find(searchContext.session, searchContext.lastRetrievedPlayListFileId, readBatchSize, [&](const db::PlayListFile::pointer& playListFile) { - PlayListFileAssociation playListAssociation; - - playListAssociation.playListFileIdId = playListFile->getId(); - - std::vector> pendingErrors; - - const auto files{ playListFile->getFiles() }; - for (const std::filesystem::path& file : files) - { - // TODO optim: no need to fetch the whole track - const db::Track::pointer track{ getMatchingTrack(searchContext.session, file, playListFile->getDirectory()) }; - if (track) - playListAssociation.tracks.push_back(TrackInfo{ .trackId = track->getId(), .releaseId = track->getReleaseId() }); - else - pendingErrors.emplace_back(std::make_shared(playListFile->getAbsoluteFilePath(), file)); - } - - if (pendingErrors.size() == files.size()) - { - pendingErrors.clear(); - pendingErrors.emplace_back(std::make_shared(playListFile->getAbsoluteFilePath())); - } - searchContext.errors.insert(std::end(searchContext.errors), std::begin(pendingErrors), std::end(pendingErrors)); - - if (playListAssociation.tracks.empty() - || (searchContext.settings.skipSingleReleasePlayLists && isSingleReleasePlayList(playListAssociation.tracks))) - { - playListAssociation.tracks.clear(); - } - - bool needUpdate{ true }; - if (const db::TrackList::pointer trackList{ playListFile->getTrackList() }) - { - if (!playListAssociation.tracks.empty()) - needUpdate = trackListNeedsUpdate(searchContext.session, playListFile->getName(), playListAssociation.tracks, trackList); - } - - if (needUpdate) - playListFileAssociations.emplace_back(std::move(playListAssociation)); - - searchContext.processedPlayListFileCount++; - }); - } - - return playListFileIdId != searchContext.lastRetrievedPlayListFileId; - } - - void updatePlayListFile(db::Session& session, const PlayListFileAssociation& playListFileAssociation) + void updatePlayList(db::Session& session, const PlayListFileAssociation& playListFileAssociation) { db::PlayListFile::pointer playListFile{ db::PlayListFile::find(session, playListFileAssociation.playListFileIdId) }; assert(playListFile); @@ -198,6 +135,7 @@ namespace lms::scanner trackList.modify()->clear(); for (const TrackInfo trackInfo : playListFileAssociation.tracks) { + // TODO no need to fetch the whole track for that if (db::Track::pointer track{ db::Track::find(session, trackInfo.trackId) }) session.create(track, trackList, playListFile->getLastWriteTime()); } @@ -205,21 +143,110 @@ namespace lms::scanner LMS_LOG(DBUPDATER, DEBUG, std::string_view{ createTrackList ? "Created" : "Updated" } << " associated tracklist for " << playListFile->getAbsoluteFilePath() << " (" << playListFileAssociation.tracks.size() << " tracks)"); } - void updatePlayListFiles(db::Session& session, PlayListFileAssociationContainer& playListFileAssociations) + void updatePlayLists(db::Session& session, PlayListFileAssociationContainer& playListFileAssociations, bool forceFullBatch) { constexpr std::size_t writeBatchSize{ 5 }; - while (!playListFileAssociations.empty()) + while ((forceFullBatch && playListFileAssociations.size() >= writeBatchSize) || !playListFileAssociations.empty()) { auto transaction{ session.createWriteTransaction() }; for (std::size_t i{}; !playListFileAssociations.empty() && i < writeBatchSize; ++i) { - updatePlayListFile(session, playListFileAssociations.front()); + updatePlayList(session, playListFileAssociations.front()); playListFileAssociations.pop_front(); } } } + + bool fetchNextPlayListFileIdRange(db::Session& session, db::PlayListFileId& lastPlayListFileId, db::IdRange& idRange) + { + constexpr std::size_t readBatchSize{ 100 }; + + auto transaction{ session.createReadTransaction() }; + + idRange = db::PlayListFile::findNextIdRange(session, lastPlayListFileId, readBatchSize); + lastPlayListFileId = idRange.last; + + return idRange.isValid(); + } + + class ComputePlayListFileAssociationsJob : public core::IJob + { + public: + ComputePlayListFileAssociationsJob(db::Db& db, const ScannerSettings& settings, db::IdRange playListFileIdRange) + : _db{ db } + , _settings{ settings } + , _playListFileIdRange{ playListFileIdRange } + { + } + + std::span getAssociations() const { return _associations; } + std::size_t getProcessedCount() const { return _processedCount; } + std::span> getErrors() const { return _errors; } + + private: + core::LiteralString getName() const override { return "Associate PlayList Tracks"; } + void run() override + { + auto& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; + + db::PlayListFile::find(session, _playListFileIdRange, [&](const db::PlayListFile::pointer& playListFile) { + PlayListFileAssociation playListAssociation; + + playListAssociation.playListFileIdId = playListFile->getId(); + + std::vector> pendingErrors; + + const auto& files{ playListFile->getFiles() }; + for (const std::filesystem::path& file : files) + { + // TODO optim: no need to fetch the whole track + const db::Track::pointer track{ getMatchingTrack(session, file, playListFile->getDirectory()) }; + if (track) + playListAssociation.tracks.push_back(TrackInfo{ .trackId = track->getId(), .releaseId = track->getReleaseId() }); + else + pendingErrors.emplace_back(std::make_shared(playListFile->getAbsoluteFilePath(), file)); + } + + if (pendingErrors.size() == files.size()) + { + pendingErrors.clear(); + pendingErrors.emplace_back(std::make_shared(playListFile->getAbsoluteFilePath())); + } + _errors.insert(std::end(_errors), std::begin(pendingErrors), std::end(pendingErrors)); + + if (playListAssociation.tracks.empty() + || (_settings.skipSingleReleasePlayLists && isSingleReleasePlayList(playListAssociation.tracks))) + { + playListAssociation.tracks.clear(); + } + + bool needUpdate{ true }; + if (const db::TrackList::pointer trackList{ playListFile->getTrackList() }) + { + if (!playListAssociation.tracks.empty()) + needUpdate = trackListNeedsUpdate(session, playListFile->getName(), playListAssociation.tracks, trackList); + } + else if (playListAssociation.tracks.empty()) + needUpdate = false; + + if (needUpdate) + _associations.emplace_back(std::move(playListAssociation)); + + _processedCount++; + }); + } + + db::Db& _db; + const ScannerSettings& _settings; + db::IdRange _playListFileIdRange; + std::vector _associations; + std::vector> _errors; + std::size_t _processedCount{}; + }; + } // namespace bool ScanStepAssociatePlayListTracks::needProcess(const ScanContext& context) const @@ -242,27 +269,37 @@ namespace lms::scanner context.currentStepStats.totalElems = db::PlayListFile::getCount(session); } - SearchPlayListFileContext searchContext{ - .session = session, - .lastRetrievedPlayListFileId = {}, - .settings = _settings, - .errors = context.stats.errors - }; - - PlayListFileAssociationContainer playListFileAssociations; - while (fetchNextPlayListFilesToUpdate(searchContext, playListFileAssociations)) - { + PlayListFileAssociationContainer playListTrackAssociations; + auto processJobsDone = [&](std::span> jobs) { if (_abortScan) return; - updatePlayListFiles(session, playListFileAssociations); + for (const auto& job : jobs) + { + const auto& associationJob{ static_cast(*job) }; + const auto& associations{ associationJob.getAssociations() }; - context.currentStepStats.processedElems = searchContext.processedPlayListFileCount; - for (const std::shared_ptr& error : searchContext.errors) - addError(context, error); - searchContext.errors.clear(); + playListTrackAssociations.insert(std::end(playListTrackAssociations), std::cbegin(associations), std::cend(associations)); + for (const std::shared_ptr& error : associationJob.getErrors()) + addError(context, error); + context.currentStepStats.processedElems += associationJob.getProcessedCount(); + } + + updatePlayLists(session, playListTrackAssociations, true); _progressCallback(context.currentStepStats); + }; + + { + JobQueue queue{ getJobScheduler(), 20, processJobsDone, 1, 0.85F }; + + db::PlayListFileId lastPlayListFileId; + db::IdRange playListFileIdRange; + while (fetchNextPlayListFileIdRange(session, lastPlayListFileId, playListFileIdRange)) + queue.push(std::make_unique(_db, _settings, playListFileIdRange)); } + + // process all remaining associations + updatePlayLists(session, playListTrackAssociations, false); } } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index b6a03229..93fa4512 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -204,7 +204,7 @@ namespace lms::scanner auto transaction{ session.createReadTransaction() }; - idRange = db::Release::findNextRange(session, lastRetrievedId, readBatchSize); + idRange = db::Release::findNextIdRange(session, lastRetrievedId, readBatchSize); lastRetrievedId = idRange.last; return idRange.isValid(); @@ -224,7 +224,7 @@ namespace lms::scanner std::size_t getProcessedReleaseCount() const { return _processedReleaseCount; } private: - core::LiteralString getName() const override { return "Associate Track Artworks"; } + core::LiteralString getName() const override { return "Associate Release Artworks"; } void run() override { auto& session{ _db.getTLSSession() }; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp index 7514d85f..9c1475cd 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp @@ -53,13 +53,6 @@ namespace lms::scanner }; using TrackArtworksAssociationContainer = std::deque; - struct SearchTrackArtworkContext - { - db::Session& session; - db::TrackId lastRetrievedTrackId; - std::size_t processedTrackCount{}; - }; - db::Artwork::pointer computePreferredTrackArtwork(db::Session& session, const db::Track::pointer& track, const db::Artwork::pointer& preferredMediaArtwork) { db::Artwork::pointer res{ preferredMediaArtwork }; @@ -152,14 +145,14 @@ namespace lms::scanner } } - bool fetchNextTrackIdRange(SearchTrackArtworkContext& searchContext, db::IdRange& trackIdRange) + bool fetchNextTrackIdRange(db::Session& session, db::TrackId& lastRetrievedTrackId, db::IdRange& trackIdRange) { constexpr std::size_t readBatchSize{ 100 }; - auto transaction{ searchContext.session.createReadTransaction() }; + auto transaction{ session.createReadTransaction() }; - trackIdRange = db::Track::findNextRange(searchContext.session, searchContext.lastRetrievedTrackId, readBatchSize); - searchContext.lastRetrievedTrackId = trackIdRange.last; + trackIdRange = db::Track::findNextIdRange(session, lastRetrievedTrackId, readBatchSize); + lastRetrievedTrackId = trackIdRange.last; return trackIdRange.isValid(); } @@ -242,11 +235,6 @@ namespace lms::scanner context.currentStepStats.totalElems = db::Track::getCount(session); } - SearchTrackArtworkContext searchContext{ - .session = session, - .lastRetrievedTrackId = {}, - }; - TrackArtworksAssociationContainer trackArtworksAssociations; auto processTracks = [&](std::span> jobs) { if (_abortScan) @@ -266,13 +254,14 @@ namespace lms::scanner _progressCallback(context.currentStepStats); }; - JobQueue queue{ getJobScheduler(), 20, processTracks, 1, 0.85F }; + { + JobQueue queue{ getJobScheduler(), 20, processTracks, 1, 0.85F }; - db::IdRange trackIdRange; - while (fetchNextTrackIdRange(searchContext, trackIdRange)) - queue.push(std::make_unique(_db, trackIdRange)); - - queue.finish(); + db::TrackId lastRetrievedTrackId; + db::IdRange trackIdRange; + while (fetchNextTrackIdRange(session, lastRetrievedTrackId, trackIdRange)) + queue.push(std::make_unique(_db, trackIdRange)); + } // process all remaining associations updateTrackPreferredArtworks(session, trackArtworksAssociations, false); From 25073b3ebc63e5b33906076df6a9c0b03c402e38 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 6 Jul 2025 11:36:28 +0200 Subject: [PATCH 15/46] Optimized diff scan by not pulling the whole track columns --- src/libs/database/impl/Track.cpp | 19 +++++++++++++++++++ src/libs/database/include/database/Track.hpp | 1 + src/libs/database/include/database/Types.hpp | 6 ++++++ .../impl/scanners/AudioFileScanner.cpp | 9 +++++---- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp index c6d6cadb..394689fe 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/Track.cpp @@ -258,6 +258,25 @@ namespace lms::db return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT t from track t").where("t.absolute_file_path = ?").bind(p)); } + std::optional Track::findFileInfo(Session& session, const std::filesystem::path& p) + { + session.checkReadTransaction(); + + auto query{ session.getDboSession()->query>("SELECT t.scan_version, t.file_last_write FROM track t WHERE t.absolute_file_path = ?") }; + query.bind(p); + + std::optional result; + + utils::forEachQueryResult(query, [&](const auto& row) { + FileInfo info; + info.scanVersion = std::get<0>(row); + info.lastWrittenTime = std::get<1>(row); + result = info; + }); + + return result; + } + Track::pointer Track::find(Session& session, TrackId id) { session.checkReadTransaction(); diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp index 3ab58cd5..c6b62524 100644 --- a/src/libs/database/include/database/Track.hpp +++ b/src/libs/database/include/database/Track.hpp @@ -191,6 +191,7 @@ namespace lms::db // Find utility functions static std::size_t getCount(Session& session); static pointer findByPath(Session& session, const std::filesystem::path& p); + static std::optional findFileInfo(Session& session, const std::filesystem::path& p); static pointer find(Session& session, TrackId id); static void find(Session& session, TrackId& lastRetrievedId, std::size_t count, const std::function& func, MediaLibraryId library = {}); static void find(Session& session, const IdRange& idRange, const std::function& func); diff --git a/src/libs/database/include/database/Types.hpp b/src/libs/database/include/database/Types.hpp index 14a00328..c2103044 100644 --- a/src/libs/database/include/database/Types.hpp +++ b/src/libs/database/include/database/Types.hpp @@ -114,6 +114,12 @@ namespace lms::db std::string name; }; + struct FileInfo + { + Wt::WDateTime lastWrittenTime; + std::size_t scanVersion{}; + }; + enum class ArtistSortMethod { None, diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp index 476bfea9..7c68d3fd 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp @@ -63,6 +63,7 @@ namespace lms::scanner } } // namespace + AudioFileScanner::AudioFileScanner(db::Db& db, const ScannerSettings& settings) : _db{ db } , _settings{ settings } @@ -92,10 +93,10 @@ namespace lms::scanner db::Session& dbSession{ _db.getTLSSession() }; auto transaction{ dbSession.createReadTransaction() }; - const db::Track::pointer track{ db::Track::findByPath(dbSession, file.filePath) }; - return !track - || track->getLastWriteTime() != file.lastWriteTime - || track->getScanVersion() != _settings.audioScanVersion; + std::optional fileInfo{ db::Track::findFileInfo(dbSession, file.filePath) }; + return !fileInfo + || fileInfo->lastWrittenTime != file.lastWriteTime + || fileInfo->scanVersion != _settings.audioScanVersion; } std::unique_ptr AudioFileScanner::createScanOperation(FileToScan&& fileToScan) const From 7b67b5c08bc49d33a234c4fc4587093fdc9ec493 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 6 Jul 2025 12:18:38 +0200 Subject: [PATCH 16/46] Adding missing producer mapping, fixes #703 --- .../services/scanner/impl/scanners/AudioFileScanOperation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index ff57a281..d29a2731 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -686,6 +686,7 @@ namespace lms::scanner createTrackArtistLinks(dbSession, track, db::TrackArtistLinkType::Composer, _parsedTrack->composerArtists, allowFallback); createTrackArtistLinks(dbSession, track, db::TrackArtistLinkType::Lyricist, _parsedTrack->lyricistArtists, allowFallback); createTrackArtistLinks(dbSession, track, db::TrackArtistLinkType::Mixer, _parsedTrack->mixerArtists, allowFallback); + createTrackArtistLinks(dbSession, track, db::TrackArtistLinkType::Producer, _parsedTrack->producerArtists, allowFallback); createTrackArtistLinks(dbSession, track, db::TrackArtistLinkType::Remixer, _parsedTrack->remixerArtists, allowFallback); for (const auto& [role, performers] : _parsedTrack->performerArtists) From 4fcdf2003c6255de108ad63744bc7bead8c97a8e Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 6 Jul 2025 16:23:47 +0200 Subject: [PATCH 17/46] Simplified a query --- src/libs/database/impl/TrackEmbeddedImage.cpp | 17 +++-------------- .../include/database/TrackEmbeddedImage.hpp | 6 +++--- src/libs/database/test/TrackEmbeddedImage.cpp | 19 ++++++++++++++++--- .../steps/ScanStepAssociateReleaseImages.cpp | 4 ++-- .../steps/ScanStepAssociateTrackImages.cpp | 6 +++--- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/libs/database/impl/TrackEmbeddedImage.cpp b/src/libs/database/impl/TrackEmbeddedImage.cpp index 9b844b8d..6c7b388c 100644 --- a/src/libs/database/impl/TrackEmbeddedImage.cpp +++ b/src/libs/database/impl/TrackEmbeddedImage.cpp @@ -43,7 +43,7 @@ namespace lms::db || params.track.isValid() || params.release.isValid() || params.trackList.isValid() - || !params.imageTypes.empty() + || params.imageType.has_value() || params.sortMethod == TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc || params.sortMethod == TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc) { @@ -90,19 +90,8 @@ namespace lms::db query.where("t_l_e.tracklist_id = ?").bind(params.trackList); } - if (!params.imageTypes.empty()) - { - std::string clause{ "t_e_i_l.type IN (" }; - for (const auto& type : params.imageTypes) - { - if (clause.back() != '(') - clause += ","; - clause += "?"; - query.bind(type); - } - clause += ")"; - query.where(clause); - } + if (params.imageType.has_value()) + query.where("t_e_i_l.type = ?").bind(params.imageType.value()); } switch (params.sortMethod) diff --git a/src/libs/database/include/database/TrackEmbeddedImage.hpp b/src/libs/database/include/database/TrackEmbeddedImage.hpp index 47e8fae8..83261073 100644 --- a/src/libs/database/include/database/TrackEmbeddedImage.hpp +++ b/src/libs/database/include/database/TrackEmbeddedImage.hpp @@ -54,7 +54,7 @@ namespace lms::db ReleaseId release; std::optional discNumber; TrackListId trackList; - core::EnumSet imageTypes; + std::optional imageType; TrackEmbeddedImageSortMethod sortMethod{ TrackEmbeddedImageSortMethod::None }; FindParameters& setRange(std::optional _range) @@ -89,9 +89,9 @@ namespace lms::db trackList = _trackList; return *this; } - FindParameters& setImageTypes(core::EnumSet _imageTypes) + FindParameters& setImageType(std::optional _imageType) { - imageTypes = _imageTypes; + imageType = _imageType; return *this; } FindParameters& setSortMethod(TrackEmbeddedImageSortMethod _sortMethod) diff --git a/src/libs/database/test/TrackEmbeddedImage.cpp b/src/libs/database/test/TrackEmbeddedImage.cpp index 16169592..0e1855c3 100644 --- a/src/libs/database/test/TrackEmbeddedImage.cpp +++ b/src/libs/database/test/TrackEmbeddedImage.cpp @@ -198,7 +198,7 @@ namespace lms::db::tests TrackEmbeddedImage::FindParameters params; params.setRelease(release.getId()); - params.setImageTypes({ ImageType::Media }); + params.setImageType(ImageType::Media); params.setSortMethod(TrackEmbeddedImageSortMethod::SizeDesc); std::vector visitedIds; @@ -214,7 +214,7 @@ namespace lms::db::tests TrackEmbeddedImage::FindParameters params; params.setRelease(release.getId()); - params.setImageTypes({ ImageType::Media }); + params.setImageType(ImageType::Media); params.setSortMethod(TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc); std::vector visitedIds; @@ -230,7 +230,7 @@ namespace lms::db::tests TrackEmbeddedImage::FindParameters params; params.setRelease(release.getId()); - params.setImageTypes({ ImageType::Media }); + params.setImageType(ImageType::Media); params.setSortMethod(TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc); std::vector visitedIds; @@ -240,6 +240,19 @@ namespace lms::db::tests EXPECT_EQ(visitedIds[1], image3.getId()); EXPECT_EQ(visitedIds[2], image2.getId()); } + + { + auto transaction{ session.createReadTransaction() }; + + TrackEmbeddedImage::FindParameters params; + params.setRelease(release.getId()); + params.setImageType(ImageType::BackCover); + params.setSortMethod(TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc); + + std::vector visitedIds; + TrackEmbeddedImage::find(session, params, [&](const TrackEmbeddedImage::pointer& image) { visitedIds.push_back(image->getId()); }); + ASSERT_EQ(visitedIds.size(), 0); + } } TEST_F(DatabaseFixture, TrackEmbeddedImage_findByParams_artist) diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index 93fa4512..61a9aa0c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -140,7 +140,7 @@ namespace lms::scanner { db::TrackEmbeddedImage::FindParameters params; params.setRelease(release->getId()); - params.setImageTypes({ db::ImageType::FrontCover }); + params.setImageType(db::ImageType::FrontCover); params.setSortMethod(db::TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); @@ -154,7 +154,7 @@ namespace lms::scanner { db::TrackEmbeddedImage::FindParameters params; params.setRelease(release->getId()); - params.setImageTypes({ db::ImageType::Media }); + params.setImageType(db::ImageType::Media); params.setSortMethod(db::TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp index 9c1475cd..76d2dc30 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp @@ -63,7 +63,7 @@ namespace lms::scanner { db::TrackEmbeddedImage::FindParameters params; params.setTrack(track->getId()); - params.setImageTypes({ db::ImageType::FrontCover }); + params.setImageType(db::ImageType::FrontCover); params.setSortMethod(db::TrackEmbeddedImageSortMethod::SizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); @@ -90,7 +90,7 @@ namespace lms::scanner { db::TrackEmbeddedImage::FindParameters params; params.setTrack(track->getId()); - params.setImageTypes({ db::ImageType::Media }); + params.setImageType(db::ImageType::Media); params.setSortMethod(db::TrackEmbeddedImageSortMethod::SizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); @@ -109,7 +109,7 @@ namespace lms::scanner db::TrackEmbeddedImage::FindParameters params; params.setRelease(releaseId); params.setDiscNumber(discNumber); - params.setImageTypes({ db::ImageType::Media }); + params.setImageType(db::ImageType::Media); params.setSortMethod(db::TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc); params.setRange(db::Range{ .offset = 0, .size = 1 }); db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); From 385625b6f7e09072190f32e7ed506139b382c478 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 6 Jul 2025 23:38:05 +0200 Subject: [PATCH 18/46] Added embedded image support in the db generator --- src/tools/db-generator/LmsDbGenerator.cpp | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/tools/db-generator/LmsDbGenerator.cpp b/src/tools/db-generator/LmsDbGenerator.cpp index f251facb..29d56103 100644 --- a/src/tools/db-generator/LmsDbGenerator.cpp +++ b/src/tools/db-generator/LmsDbGenerator.cpp @@ -40,6 +40,8 @@ #include "database/Session.hpp" #include "database/Track.hpp" #include "database/TrackArtistLink.hpp" +#include "database/TrackEmbeddedImage.hpp" +#include "database/TrackEmbeddedImageLink.hpp" namespace lms { @@ -52,6 +54,7 @@ namespace lms float compilationRatio{ 0.1 }; std::size_t genreCountPerTrack{ 3 }; std::size_t moodCountPerTrack{ 3 }; + std::size_t trackEmbeddedImagePerRelease{ 1 }; // usual case: one same image saved on each track std::size_t genreCount{ 50 }; std::size_t moodCount{ 25 }; std::filesystem::path trackPath; @@ -94,6 +97,10 @@ namespace lms if (!context.mediaLibraries.empty()) mediaLibrary = *core::random::pickRandom(context.mediaLibraries); + std::vector trackEmbeddedImages; + for (std::size_t i{}; i < params.trackEmbeddedImagePerRelease; ++i) + trackEmbeddedImages.push_back(context.session.create()); + for (std::size_t i{}; i < params.trackCountPerRelease; ++i) { Track::pointer track{ context.session.create() }; @@ -112,6 +119,9 @@ namespace lms TrackArtistLink::create(context.session, track, artist, TrackArtistLinkType::Artist); TrackArtistLink::create(context.session, track, artist, TrackArtistLinkType::ReleaseArtist); + if (!trackEmbeddedImages.empty()) + context.session.create(track, *core::random::pickRandom(trackEmbeddedImages)); + std::vector> clusters; if (!context.genres.empty()) clusters.push_back(*core::random::pickRandom(context.genres)); @@ -177,7 +187,19 @@ int main(int argc, char* argv[]) const GeneratorParameters defaultParams; program_options::options_description options{ "Options" }; - options.add_options()("conf,c", program_options::value()->default_value(core::sysconfDirectory / "lms.conf"), "lms config file")("media-library-count", program_options::value()->default_value(defaultParams.mediaLibraryCount), "Number of media libraries to use")("release-count-per-batch", program_options::value()->default_value(defaultParams.releaseCountPerBatch), "Number of releases to generate before committing transaction")("release-count", program_options::value()->default_value(defaultParams.releaseCount), "Number of releases to generate")("track-count-per-release", program_options::value()->default_value(defaultParams.trackCountPerRelease), "Number of tracks per release")("compilation-ratio", program_options::value()->default_value(defaultParams.compilationRatio), "Compilation ratio (compilation means all tracks have a different artist)")("track-path", program_options::value()->required(), "Path of a valid track file, that will be used for all generated tracks")("genre-count", program_options::value()->default_value(defaultParams.genreCount), "Number of genres to generate")("genre-count-per-track", program_options::value()->default_value(defaultParams.genreCountPerTrack), "Number of genres to assign to each track")("mood-count", program_options::value()->default_value(defaultParams.moodCount), "Number of moods to generate")("mood-count-per-track", program_options::value()->default_value(defaultParams.moodCountPerTrack), "Number of moods to assign to each track")("help,h", "produce help message"); + + // clang-format off + options.add_options() + ("conf,c", program_options::value()->default_value(core::sysconfDirectory / "lms.conf"), "lms config file") + ("media-library-count", program_options::value()->default_value(defaultParams.mediaLibraryCount), "Number of media libraries to use") + ("release-count-per-batch",program_options::value()->default_value(defaultParams.releaseCountPerBatch), "Number of releases to generate before committing transaction") + ("release-count",program_options::value()->default_value(defaultParams.releaseCount), "Number of releases to generate") + ("track-count-per-release", program_options::value()->default_value(defaultParams.trackCountPerRelease), "Number of tracks per release") + ("track-embedded-image-count",program_options::value()->default_value(defaultParams.trackEmbeddedImagePerRelease), "Number of different embedded track images for the whole release (each track has one different embedded image)") + ("compilation-ratio",program_options::value()->default_value(defaultParams.compilationRatio), "Compilation ratio (compilation means all tracks have a different artist)") + ("track-path",program_options::value()->required(), "Path of a valid track file, that will be used for all generated tracks")("genre-count", program_options::value()->default_value(defaultParams.genreCount), "Number of genres to generate")("genre-count-per-track", program_options::value()->default_value(defaultParams.genreCountPerTrack), "Number of genres to assign to each track")("mood-count", program_options::value()->default_value(defaultParams.moodCount), "Number of moods to generate") + ("mood-count-per-track", program_options::value()->default_value(defaultParams.moodCountPerTrack), "Number of moods to assign to each track")("help,h", "produce help message"); + // clang-format on program_options::variables_map vm; program_options::store(program_options::parse_command_line(argc, argv, options), vm); @@ -197,6 +219,7 @@ int main(int argc, char* argv[]) genParams.releaseCount = vm["release-count"].as(); genParams.trackCountPerRelease = vm["track-count-per-release"].as(); genParams.compilationRatio = vm["compilation-ratio"].as(); + genParams.trackEmbeddedImagePerRelease = vm["track-embedded-image-count"].as(); genParams.trackPath = std::filesystem::path{ vm["track-path"].as() }; if (!std::filesystem::exists(genParams.trackPath)) From 747b5ef6e86e199008c3d9ba3937a1bd7d36b07d Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 7 Jul 2025 00:11:12 +0200 Subject: [PATCH 19/46] Scanner: removed the file discover step, as it brings an important time penalty for remote file systems, for big databases (up to several minutes) --- approot/messages.xml | 2 +- approot/messages_es.xml | 3 +- approot/messages_fr.xml | 3 +- approot/messages_it.xml | 3 +- approot/messages_pl.xml | 11 ++- approot/messages_zh.xml | 3 +- src/libs/services/scanner/CMakeLists.txt | 1 - .../services/scanner/impl/ScannerService.cpp | 2 - .../impl/steps/ScanStepDiscoverFiles.cpp | 69 ------------------- .../impl/steps/ScanStepDiscoverFiles.hpp | 37 ---------- .../scanner/impl/steps/ScanStepScanFiles.cpp | 4 +- .../include/services/scanner/ScannerStats.hpp | 3 +- src/lms/ui/admin/ScannerController.cpp | 9 +-- 13 files changed, 14 insertions(+), 136 deletions(-) delete mode 100644 src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.cpp delete mode 100644 src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.hpp diff --git a/approot/messages.xml b/approot/messages.xml index d3df21c2..dd550f6e 100644 --- a/approot/messages.xml +++ b/approot/messages.xml @@ -145,7 +145,7 @@ Reconciliating artists: {1} entries... Reloading similarity engine: {1}%... Removing orphaned entries: {1} entries... -Scanning files: {1}/{2} ({3}%)... +Library analysis: {1} files... Step status Updating library fields: {1} entries diff --git a/approot/messages_es.xml b/approot/messages_es.xml index 2811c7bd..9d90a2f6 100644 --- a/approot/messages_es.xml +++ b/approot/messages_es.xml @@ -139,13 +139,12 @@ Comprobando ficheros eliminados... {1}% Compactando la base de datos... Calculando estadísticas... {1}% -Descubriendo ficheros: {1} ficheros Accediendo a las características de la pista desde AcousticBrainz : {1}/{2} ficheros ({3}%)... Optimizando la base de datos... {1}%... Reconciliando artistas: {1} entradas... Recargando el motor de similitud: {1}%... Borrando entradas huérfanas: {1} entradas... -Escaneando ficheros: {1} / {2} ({3}%)... +Análisis de bibliotecas: {1} ficheros... Estado de las etapas Actualizando campos de la biblioteca: {1} entradas diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml index 5f332410..b7c94d7a 100644 --- a/approot/messages_fr.xml +++ b/approot/messages_fr.xml @@ -139,13 +139,12 @@ Vérification des fichiers supprimés... {1}% Compactage de la base de données... Calcul des statistiques... {1}% -Découverte des fichiers : {1} fichiers Récupération des métadonnées AcousticBrainz : {1}/{2} fichiers ({3}%)... Optimisation de la base de données... {1}%... Reconciliation des artistes: {1} entrées... Rechargement du moteur de recommandation : {1}%... Retrait des entrées orphelines: {1} entrées... -Scan des fichiers : {1}/{2} ({3}%)... +Analyse des bibliothèques : {1} fichiers... Statut de l'étape Mise à jour des champs des bibliothèques: {1} entrées diff --git a/approot/messages_it.xml b/approot/messages_it.xml index 00b3d031..30894331 100644 --- a/approot/messages_it.xml +++ b/approot/messages_it.xml @@ -139,13 +139,12 @@ Controllo file... {1}% Compattazione del database... Calcolo statistiche... {1}% -File trovati: {1} files Recupero metadati da AcousticBrainz: {1}/{2} tracce ({3}%)... Ottimizzazione del database... {1}%... Riconciliazione artisti: {1} voci... Ricarica motore di tracce simili: {1}%... Rimozione voci orfane: {1} voci... -Scansione dei file: {1}/{2} ({3}%)... +Analisi delle librerie: {1} file... Stato passo Aggiornamento dei campi della libreria: {1} voci diff --git a/approot/messages_pl.xml b/approot/messages_pl.xml index 8a117a43..5bd2eed0 100644 --- a/approot/messages_pl.xml +++ b/approot/messages_pl.xml @@ -152,17 +152,16 @@ Sprawdzanie plików... {1}% Prasowanie bazy danych... Obliczanie statystyk... {1}% - - Odkrywanie plików: {1} plik - Odkrywanie plików: {1} pliki - Odkrywanie plików: {1} plików - Pobieranie danych o ścieżce z AcousticBrainz: {1}/{2} ścieżek ({3}%)... Optymalizowanie bazy danych... {1}%... Uzgodnianie artystów: {1} wpisów... Przeładowywanie silnika podobieństw: {1}%... Usuwanie osieroconych wpisów: {1} wpisów... -Skanowanie plików: {1}/{2} ({3}%)... + + Analiza bibliotek: {1} plik + Analiza bibliotek: {1} pliki + Analiza bibliotek: {1} plików + Obecny krok Aktualizowanie pól biblioteki: {1} wpisów diff --git a/approot/messages_zh.xml b/approot/messages_zh.xml index 4825aea7..ce6bbebb 100644 --- a/approot/messages_zh.xml +++ b/approot/messages_zh.xml @@ -137,13 +137,12 @@ 检查文件中... {1}% -检索文件中: {1} 文件 从 AcousticBrainz 获取音轨特征: {1}/{2} 音轨 ({3}%)... 重载相似引擎中 {1}%... -扫描文件中: {1}/{2} 个文件 ({3}%)... + 当前步骤状态 diff --git a/src/libs/services/scanner/CMakeLists.txt b/src/libs/services/scanner/CMakeLists.txt index a09c1fbb..3aab7cc5 100644 --- a/src/libs/services/scanner/CMakeLists.txt +++ b/src/libs/services/scanner/CMakeLists.txt @@ -21,7 +21,6 @@ add_library(lmsscanner STATIC impl/steps/ScanStepCheckForRemovedFiles.cpp impl/steps/ScanStepCompact.cpp impl/steps/ScanStepComputeClusterStats.cpp - impl/steps/ScanStepDiscoverFiles.cpp impl/steps/ScanStepOptimize.cpp impl/steps/ScanStepRemoveOrphanedDbEntries.cpp impl/steps/ScanStepScanFiles.cpp diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index c5a002f0..3bb087ee 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -47,7 +47,6 @@ #include "steps/ScanStepCheckForRemovedFiles.hpp" #include "steps/ScanStepCompact.hpp" #include "steps/ScanStepComputeClusterStats.hpp" -#include "steps/ScanStepDiscoverFiles.hpp" #include "steps/ScanStepOptimize.hpp" #include "steps/ScanStepRemoveOrphanedDbEntries.hpp" #include "steps/ScanStepScanFiles.hpp" @@ -474,7 +473,6 @@ namespace lms::scanner // Order is important: steps are sequential _scanSteps.clear(); - _scanSteps.emplace_back(std::make_unique(params)); _scanSteps.emplace_back(std::make_unique(params)); _scanSteps.emplace_back(std::make_unique(params)); _scanSteps.emplace_back(std::make_unique(params)); diff --git a/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.cpp deleted file mode 100644 index 61056433..00000000 --- a/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2023 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 . - */ - -#include "ScanStepDiscoverFiles.hpp" - -#include "core/ILogger.hpp" -#include "core/Path.hpp" - -#include "MediaLibraryInfo.hpp" -#include "ScannerSettings.hpp" - -#include "ScanContext.hpp" - -namespace lms::scanner -{ - bool ScanStepDiscoverFiles::needProcess([[maybe_unused]] const ScanContext& context) const - { - // always discover files - return true; - } - - void ScanStepDiscoverFiles::process(ScanContext& context) - { - context.stats.totalFileCount = 0; - - for (const MediaLibraryInfo& mediaLibrary : _settings.mediaLibraries) - { - std::size_t currentDirectoryProcessElemsCount{}; - core::pathUtils::exploreFilesRecursive( - mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path) { - if (_abortScan) - return false; - - // we don't report errors here (done in the actual scan step) - if (!ec && selectFileScanner(path)) - { - context.currentStepStats.processedElems++; - currentDirectoryProcessElemsCount++; - _progressCallback(context.currentStepStats); - } - - return true; - }, - &excludeDirFileName); - - LMS_LOG(DBUPDATER, DEBUG, "Discovered " << currentDirectoryProcessElemsCount << " files in " << mediaLibrary.rootDirectory); - } - - context.stats.totalFileCount = context.currentStepStats.processedElems; - - LMS_LOG(DBUPDATER, DEBUG, "Discovered " << context.stats.totalFileCount << " files in all directories"); - } -} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.hpp b/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.hpp deleted file mode 100644 index ab8baeff..00000000 --- a/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2023 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 . - */ - -#pragma once - -#include "ScanStepBase.hpp" - -namespace lms::scanner -{ - class ScanStepDiscoverFiles : public ScanStepBase - { - public: - using ScanStepBase::ScanStepBase; - - private: - ScanStep getStep() const override { return ScanStep::DiscoverFiles; } - core::LiteralString getStepName() const override { return "Discover files"; } - bool needProcess(const ScanContext& context) const override; - void process(ScanContext& context) override; - }; -} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index 27f13d50..19c4ed85 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -107,8 +107,6 @@ namespace lms::scanner void ScanStepScanFiles::process(ScanContext& context) { - context.currentStepStats.totalElems = context.stats.totalFileCount; - for (const MediaLibraryInfo& mediaLibrary : _settings.mediaLibraries) process(context, mediaLibrary); } @@ -165,6 +163,8 @@ namespace lms::scanner return true; }, &excludeDirFileName); + + context.stats.totalFileCount = context.currentStepStats.totalElems; } void ScanStepScanFiles::processFileScanResults(ScanContext& context, std::span> scanJobs) diff --git a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp index 2de12172..7d1633df 100644 --- a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp +++ b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp @@ -54,7 +54,6 @@ namespace lms::scanner CheckForRemovedFiles, ComputeClusterStats, Compact, - DiscoverFiles, FetchTrackFeatures, Optimize, ReconciliateArtists, @@ -84,7 +83,7 @@ namespace lms::scanner Wt::WDateTime startTime; Wt::WDateTime stopTime; - std::size_t totalFileCount{}; // Total number of files (estimated) + std::size_t totalFileCount{}; // Total number of files (only valid after the file scan step) std::size_t skips{}; // no change since last scan std::size_t scans{}; // count of scanned files diff --git a/src/lms/ui/admin/ScannerController.cpp b/src/lms/ui/admin/ScannerController.cpp index 2f3e196e..5931b8a9 100644 --- a/src/lms/ui/admin/ScannerController.cpp +++ b/src/lms/ui/admin/ScannerController.cpp @@ -212,11 +212,6 @@ namespace lms::ui .arg(stepStats.progress())); break; - case ScanStep::DiscoverFiles: - _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-discovering-files") - .arg(stepStats.processedElems)); - break; - case ScanStep::FetchTrackFeatures: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-fetching-track-features") .arg(stepStats.processedElems) @@ -246,9 +241,7 @@ namespace lms::ui case ScanStep::ScanFiles: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-scanning-files") - .arg(stepStats.processedElems) - .arg(stepStats.totalElems) - .arg(stepStats.progress())); + .arg(stepStats.processedElems)); break; case ScanStep::UpdateLibraryFields: From 49afdb3db607139ec8f9e38282611049de69b1d6 Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 7 Jul 2025 13:44:50 +0200 Subject: [PATCH 20/46] Removed useless stat call --- src/libs/core/impl/Path.cpp | 10 ++++++---- src/libs/core/include/core/Path.hpp | 7 ++++++- .../services/scanner/impl/steps/ScanStepScanFiles.cpp | 10 ++++------ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libs/core/impl/Path.cpp b/src/libs/core/impl/Path.cpp index 248042c7..47f717a3 100644 --- a/src/libs/core/impl/Path.cpp +++ b/src/libs/core/impl/Path.cpp @@ -67,9 +67,9 @@ namespace lms::core::pathUtils return std::filesystem::create_directory(dir); } - Wt::WDateTime getLastWriteTime(const std::filesystem::path& file, std::error_code& ec) + FileInfo getFileInfo(const std::filesystem::path& file, std::error_code& ec) { - Wt::WDateTime res; + FileInfo fileInfo; struct stat sb { @@ -81,10 +81,11 @@ namespace lms::core::pathUtils else { ec = std::error_code{}; - res = Wt::WDateTime::fromTime_t(sb.st_mtime); + fileInfo.lastWriteTime = Wt::WDateTime::fromTime_t(sb.st_mtime); + fileInfo.fileSize = sb.st_size; } - return res; + return fileInfo; } bool exploreFilesRecursive(const std::filesystem::path& directory, std::function cb, const std::filesystem::path* excludeDirFileName) @@ -120,6 +121,7 @@ namespace lms::core::pathUtils } else { + // TODO get status once and then test regular file/directory if (std::filesystem::is_regular_file(*itPath, ec)) { continueExploring = cb(ec, *itPath); diff --git a/src/libs/core/include/core/Path.hpp b/src/libs/core/include/core/Path.hpp index 1d9688bd..704c5e77 100644 --- a/src/libs/core/include/core/Path.hpp +++ b/src/libs/core/include/core/Path.hpp @@ -34,8 +34,13 @@ namespace lms::core::pathUtils // Create it if needed bool ensureDirectory(const std::filesystem::path& dir); + struct FileInfo + { + Wt::WDateTime lastWriteTime; // Last write time of the file since Epoch + std::uint64_t fileSize{}; // Size of the file in bytes + }; // Get the last write time since Epoch - Wt::WDateTime getLastWriteTime(const std::filesystem::path& file, std::error_code& ec); + FileInfo getFileInfo(const std::filesystem::path& file, std::error_code& ec); // returns false if aborted by user bool exploreFilesRecursive(const std::filesystem::path& directory, std::function cb, const std::filesystem::path* excludeDirFileName = {}); diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index 19c4ed85..69128b98 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -71,16 +71,14 @@ namespace lms::scanner { FileToScan res; - res.lastWriteTime = core::pathUtils::getLastWriteTime(file, ec); - if (!ec) - res.relativePath = std::filesystem::relative(file, mediaLibrary.rootDirectory, ec); - if (!ec) - res.fileSize = std::filesystem::file_size(file, ec); - + const core::pathUtils::FileInfo fileInfo{ core::pathUtils::getFileInfo(file, ec) }; if (!ec) { res.filePath = file; res.mediaLibrary = mediaLibrary; + res.relativePath = std::filesystem::relative(file, mediaLibrary.rootDirectory, ec); + res.lastWriteTime = fileInfo.lastWriteTime; + res.fileSize = fileInfo.fileSize; } return res; From 1800aaf32efbe9b04f4b16618248a9729d4d25d2 Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 7 Jul 2025 23:07:51 +0200 Subject: [PATCH 21/46] Explore files in the filesystem with a single stat for each file --- src/libs/core/impl/Path.cpp | 80 ++++--------------- src/libs/core/include/core/Path.hpp | 8 +- .../impl/scanners/AudioFileScanOperation.cpp | 6 +- .../impl/scanners/FileScanOperationBase.hpp | 1 - .../scanner/impl/scanners/FileToScan.hpp | 1 - .../scanner/impl/steps/ScanStepScanFiles.cpp | 43 +++------- 6 files changed, 32 insertions(+), 107 deletions(-) diff --git a/src/libs/core/impl/Path.cpp b/src/libs/core/impl/Path.cpp index 47f717a3..fc7c188a 100644 --- a/src/libs/core/impl/Path.cpp +++ b/src/libs/core/impl/Path.cpp @@ -20,45 +20,13 @@ #include "core/Path.hpp" #include -#include -#include -#include -#include #include -#include - -#include "core/Crc32Calculator.hpp" -#include "core/Exception.hpp" #include "core/ILogger.hpp" #include "core/String.hpp" namespace lms::core::pathUtils { - std::uint32_t computeCrc32(const std::filesystem::path& p) - { - core::Crc32Calculator crc32; - - std::ifstream ifs{ p, std::ios_base::binary }; - if (ifs) - { - do - { - std::array buffer; - - ifs.read(buffer.data(), buffer.size()); - crc32.processBytes(reinterpret_cast(buffer.data()), ifs.gcount()); - } while (ifs); - } - else - { - LMS_LOG(DBUPDATER, ERROR, "Failed to open file " << p); - throw LmsException("Failed to open file '" + p.string() + "'"); - } - - return crc32.getResult(); - } - bool ensureDirectory(const std::filesystem::path& dir) { if (std::filesystem::exists(dir)) @@ -67,35 +35,14 @@ namespace lms::core::pathUtils return std::filesystem::create_directory(dir); } - FileInfo getFileInfo(const std::filesystem::path& file, std::error_code& ec) - { - FileInfo fileInfo; - - struct stat sb - { - }; - if (stat(file.c_str(), &sb) == -1) - { - ec = std::error_code{ errno, std::generic_category() }; - } - else - { - ec = std::error_code{}; - fileInfo.lastWriteTime = Wt::WDateTime::fromTime_t(sb.st_mtime); - fileInfo.fileSize = sb.st_size; - } - - return fileInfo; - } - - bool exploreFilesRecursive(const std::filesystem::path& directory, std::function cb, const std::filesystem::path* excludeDirFileName) + bool exploreFilesRecursive(const std::filesystem::path& directory, ExploreFileCallback cb, const std::filesystem::path* excludeDirFileName) { std::error_code ec; std::filesystem::directory_iterator itPath{ directory, std::filesystem::directory_options::follow_directory_symlink, ec }; if (ec) { - cb(ec, directory); + cb(ec, directory, nullptr); return true; // try to continue exploring anyway } @@ -105,6 +52,7 @@ namespace lms::core::pathUtils if (std::filesystem::exists(excludePath, ec)) { + // TODO: handle exclude another way + remove this log LMS_LOG(DBUPDATER, DEBUG, "Found " << excludePath << ": skipping directory"); return true; } @@ -117,22 +65,22 @@ namespace lms::core::pathUtils if (ec) { - continueExploring = cb(ec, *itPath); + continueExploring = cb(ec, *itPath, nullptr); } else { - // TODO get status once and then test regular file/directory - if (std::filesystem::is_regular_file(*itPath, ec)) + const std::filesystem::directory_entry& entry{ *itPath }; + + if (entry.is_regular_file()) { - continueExploring = cb(ec, *itPath); - } - else if (std::filesystem::is_directory(*itPath, ec)) - { - if (!ec) - continueExploring = exploreFilesRecursive(*itPath, cb, excludeDirFileName); - else - continueExploring = cb(ec, *itPath); + FileInfo fileInfo; + fileInfo.fileSize = entry.file_size(); + fileInfo.lastWriteTime = Wt::WDateTime{ std::chrono::file_clock::to_sys(entry.last_write_time()) }; + + continueExploring = cb(ec, *itPath, &fileInfo); } + else if (entry.is_directory()) + continueExploring = exploreFilesRecursive(*itPath, cb, excludeDirFileName); } if (!continueExploring) diff --git a/src/libs/core/include/core/Path.hpp b/src/libs/core/include/core/Path.hpp index 704c5e77..ccc4c64b 100644 --- a/src/libs/core/include/core/Path.hpp +++ b/src/libs/core/include/core/Path.hpp @@ -28,8 +28,6 @@ namespace lms::core::pathUtils { - std::uint32_t computeCrc32(const std::filesystem::path& p); - // Make sure the given path is a directory // Create it if needed bool ensureDirectory(const std::filesystem::path& dir); @@ -39,11 +37,9 @@ namespace lms::core::pathUtils Wt::WDateTime lastWriteTime; // Last write time of the file since Epoch std::uint64_t fileSize{}; // Size of the file in bytes }; - // Get the last write time since Epoch - FileInfo getFileInfo(const std::filesystem::path& file, std::error_code& ec); - + using ExploreFileCallback = std::function; // returns false if aborted by user - bool exploreFilesRecursive(const std::filesystem::path& directory, std::function cb, const std::filesystem::path* excludeDirFileName = {}); + bool exploreFilesRecursive(const std::filesystem::path& directory, ExploreFileCallback cb, const std::filesystem::path* excludeDirFileName = {}); // Check if file's extension is one of provided extensions bool hasFileAnyExtension(const std::filesystem::path& file, std::span extensions); diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index d29a2731..4406e91b 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -379,7 +379,7 @@ namespace lms::scanner return db::Advisory::UnSet; } - db::Track::pointer findMovedTrackBySizeAndMetaData(db::Session& session, const metadata::Track& parsedTrack, size_t fileSize, const std::filesystem::path& relativePath) + db::Track::pointer findMovedTrackBySizeAndMetaData(db::Session& session, const metadata::Track& parsedTrack, const std::filesystem::path& trackPath, size_t fileSize) { db::Track::FindParameters params; // Add as many fields as possible to limit errors @@ -405,7 +405,7 @@ namespace lms::scanner if (res) { - LMS_LOG(DBUPDATER, DEBUG, "Found too many candidates for file move. New file = " << relativePath << ", candidate = " << track->getAbsoluteFilePath() << ", previous candidate = " << res->getAbsoluteFilePath()); + LMS_LOG(DBUPDATER, DEBUG, "Found too many candidates for file move. New file = " << trackPath << ", candidate = " << track->getAbsoluteFilePath() << ", previous candidate = " << res->getAbsoluteFilePath()); error = true; } res = track; @@ -598,7 +598,7 @@ namespace lms::scanner if (!track) { // maybe the file just moved? - track = findMovedTrackBySizeAndMetaData(dbSession, *_parsedTrack, getFileSize(), getRelativeFilePath()); + track = findMovedTrackBySizeAndMetaData(dbSession, *_parsedTrack, getFilePath(), getFileSize()); if (track) { LMS_LOG(DBUPDATER, DEBUG, "Considering track " << getFilePath() << " moved from " << track->getAbsoluteFilePath()); diff --git a/src/libs/services/scanner/impl/scanners/FileScanOperationBase.hpp b/src/libs/services/scanner/impl/scanners/FileScanOperationBase.hpp index 6d3b717d..33482190 100644 --- a/src/libs/services/scanner/impl/scanners/FileScanOperationBase.hpp +++ b/src/libs/services/scanner/impl/scanners/FileScanOperationBase.hpp @@ -50,7 +50,6 @@ namespace lms::scanner const ScannerSettings& getScannerSettings() const { return _settings; } Wt::WDateTime getLastWriteTime() const { return _file.lastWriteTime; } std::size_t getFileSize() const { return _file.fileSize; } - const std::filesystem::path& getRelativeFilePath() const { return _file.relativePath; } template void addError(CtrArgs&&... args) diff --git a/src/libs/services/scanner/impl/scanners/FileToScan.hpp b/src/libs/services/scanner/impl/scanners/FileToScan.hpp index 8f44015d..4996b26e 100644 --- a/src/libs/services/scanner/impl/scanners/FileToScan.hpp +++ b/src/libs/services/scanner/impl/scanners/FileToScan.hpp @@ -30,7 +30,6 @@ namespace lms::scanner struct FileToScan { std::filesystem::path filePath; - std::filesystem::path relativePath; MediaLibraryInfo mediaLibrary; Wt::WDateTime lastWriteTime; std::size_t fileSize{}; diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index 69128b98..5b1f91e7 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -66,23 +66,6 @@ namespace lms::scanner std::unique_ptr _scanOperation; }; - - FileToScan retrieveFileInfo(const std::filesystem::path& file, const MediaLibraryInfo& mediaLibrary, std::error_code& ec) - { - FileToScan res; - - const core::pathUtils::FileInfo fileInfo{ core::pathUtils::getFileInfo(file, ec) }; - if (!ec) - { - res.filePath = file; - res.mediaLibrary = mediaLibrary; - res.relativePath = std::filesystem::relative(file, mediaLibrary.rootDirectory, ec); - res.lastWriteTime = fileInfo.lastWriteTime; - res.fileSize = fileInfo.fileSize; - } - - return res; - } } // namespace ScanStepScanFiles::ScanStepScanFiles(InitParams& initParams) @@ -126,9 +109,11 @@ namespace lms::scanner std::vector> scanOperations; core::pathUtils::exploreFilesRecursive( - mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path) { + mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path, const core::pathUtils::FileInfo* fileInfo) { LMS_SCOPED_TRACE_DETAILED("Scanner", "OnExploreFile"); + assert((ec && !fileInfo) || (!ec && fileInfo)); + if (_abortScan) return false; // stop iterating @@ -139,19 +124,17 @@ namespace lms::scanner } else if (IFileScanner * scanner{ selectFileScanner(path) }) { - FileToScan fileToScan{ retrieveFileInfo(path, mediaLibrary, ec) }; - if (ec) + FileToScan fileToScan; + + fileToScan.filePath = path; + fileToScan.mediaLibrary = mediaLibrary; + fileToScan.lastWriteTime.setTime_t(fileInfo->lastWriteTime.toTime_t()); // sec resolution, as stored in the database + fileToScan.fileSize = fileInfo->fileSize; + + if (context.scanOptions.fullScan || scanner->needsScan(fileToScan)) { - addError(context, path, ec); - context.stats.skips++; - } - else - { - if (context.scanOptions.fullScan || scanner->needsScan(fileToScan)) - { - auto scanOperation{ scanner->createScanOperation(std::move(fileToScan)) }; - queue.push(std::make_unique(std::move(scanOperation))); - } + auto scanOperation{ scanner->createScanOperation(std::move(fileToScan)) }; + queue.push(std::make_unique(std::move(scanOperation))); } context.currentStepStats.processedElems++; From ecdfa8d68d755d5f29daa797781128f9f33b4448 Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 7 Jul 2025 23:43:54 +0200 Subject: [PATCH 22/46] Removed offending indexes on bad columns --- src/libs/database/impl/Migration.cpp | 9 ++++++++- src/libs/database/impl/Session.cpp | 5 ++--- src/libs/database/impl/TrackEmbeddedImage.cpp | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index c7c8510d..2d1752bc 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -35,7 +35,7 @@ namespace lms::db { namespace { - static constexpr Version LMS_DATABASE_VERSION{ 96 }; + static constexpr Version LMS_DATABASE_VERSION{ 97 }; } VersionInfo::VersionInfo() @@ -1412,6 +1412,12 @@ LEFT JOIN artwork art ON img.id = art.image_id WHERE art.image_id IS NULL)"); } + void migrateFromV96(Session& session) + { + // Removed not that useful indexes + dropIndexes(session); + } + bool doDbMigration(Session& session) { constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" }; @@ -1484,6 +1490,7 @@ WHERE art.image_id IS NULL)"); { 93, migrateFromV93 }, { 94, migrateFromV94 }, { 95, migrateFromV95 }, + { 96, migrateFromV96 }, }; bool migrationPerformed{}; diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 48b89a13..4e0c841d 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -234,8 +234,7 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_id_idx ON track_embedded_image_link(id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_track_id_idx ON track_embedded_image_link(track_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_track_embedded_image_id_track_id_idx ON track_embedded_image_link(track_embedded_image_id, track_id)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_track_type_track_embedded_image_id_idx ON track_embedded_image_link(track_id, type, track_embedded_image_id)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_type_track_embedded_image_id_track_id_idx ON track_embedded_image_link(type,track_embedded_image_id,track_id)"); + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_link_track_track_embedded_image_id_idx ON track_embedded_image_link(track_id, track_embedded_image_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS image_directory_stem_idx ON image(directory_id, stem COLLATE NOCASE)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS image_id_idx ON image(id)"); @@ -289,7 +288,7 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_name_nocase_idx ON track(name COLLATE NOCASE)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_original_date_idx ON track(original_date)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_recording_mbid_idx ON track(recording_mbid)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_idx ON track(release_id)"); + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_disc_idx ON track(release_id, disc_number)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_date_idx ON track(release_id, date)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_date_desc_idx ON track(release_id, date DESC)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_last_write_idx ON track(release_id, file_last_write)"); diff --git a/src/libs/database/impl/TrackEmbeddedImage.cpp b/src/libs/database/impl/TrackEmbeddedImage.cpp index 6c7b388c..55509420 100644 --- a/src/libs/database/impl/TrackEmbeddedImage.cpp +++ b/src/libs/database/impl/TrackEmbeddedImage.cpp @@ -91,7 +91,7 @@ namespace lms::db } if (params.imageType.has_value()) - query.where("t_e_i_l.type = ?").bind(params.imageType.value()); + query.where("+t_e_i_l.type = ?").bind(params.imageType.value()); // hack: type is a bad way to reduce the result space } switch (params.sortMethod) From 764c92698c42f7832240651ae2b9dd5bfe16204b Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 9 Jul 2025 00:29:16 +0200 Subject: [PATCH 23/46] Created an interface for the Db class --- src/libs/database/impl/Db.cpp | 9 ++++- .../{include/database => impl}/Db.hpp | 14 ++++--- src/libs/database/impl/Migration.cpp | 6 +-- src/libs/database/impl/Session.cpp | 10 ++--- src/libs/database/include/database/IDb.hpp | 39 +++++++++++++++++++ .../database/include/database/Session.hpp | 8 ++-- src/libs/database/test/Common.cpp | 7 ++-- src/libs/database/test/Common.hpp | 6 +-- src/libs/database/test/Migration.cpp | 1 - .../services/artwork/impl/ArtworkService.cpp | 6 +-- .../services/artwork/impl/ArtworkService.hpp | 4 +- .../services/artwork/IArtworkService.hpp | 4 +- .../services/auth/impl/AuthServiceBase.cpp | 4 +- .../services/auth/impl/AuthServiceBase.hpp | 6 +-- .../services/auth/impl/AuthTokenService.cpp | 4 +- .../services/auth/impl/AuthTokenService.hpp | 2 +- src/libs/services/auth/impl/EnvService.cpp | 2 +- .../auth/impl/PasswordServiceBase.cpp | 4 +- .../auth/impl/PasswordServiceBase.hpp | 4 +- .../http-headers/HttpHeadersEnvService.cpp | 2 +- .../http-headers/HttpHeadersEnvService.hpp | 2 +- .../impl/internal/InternalPasswordService.cpp | 2 +- .../impl/internal/InternalPasswordService.hpp | 2 +- .../services/auth/IAuthTokenService.hpp | 4 +- .../include/services/auth/IEnvService.hpp | 4 +- .../services/auth/IPasswordService.hpp | 4 +- .../feedback/impl/FeedbackService.cpp | 8 ++-- .../feedback/impl/FeedbackService.hpp | 6 +-- .../feedback/impl/FeedbackService.impl.hpp | 2 +- .../impl/internal/InternalBackend.cpp | 4 +- .../impl/internal/InternalBackend.hpp | 6 +-- .../listenbrainz/FeedbacksSynchronizer.cpp | 4 +- .../listenbrainz/FeedbacksSynchronizer.hpp | 6 +-- .../impl/listenbrainz/ListenBrainzBackend.cpp | 4 +- .../impl/listenbrainz/ListenBrainzBackend.hpp | 6 +-- .../services/feedback/IFeedbackService.hpp | 4 +- .../impl/ClustersEngineCreator.hpp | 4 +- .../impl/FeaturesEngineCreator.hpp | 4 +- .../services/recommendation/impl/IEngine.hpp | 4 +- .../impl/PlaylistGeneratorService.cpp | 6 +-- .../impl/PlaylistGeneratorService.hpp | 4 +- .../impl/RecommendationService.cpp | 6 +-- .../impl/RecommendationService.hpp | 6 +-- .../impl/clusters/ClustersEngine.cpp | 5 +-- .../impl/clusters/ClustersEngine.hpp | 4 +- .../impl/features/FeaturesEngine.cpp | 4 +- .../impl/features/FeaturesEngine.hpp | 4 +- .../ConsecutiveArtists.cpp | 4 +- .../ConsecutiveArtists.hpp | 6 +-- .../ConsecutiveReleases.cpp | 4 +- .../ConsecutiveReleases.hpp | 6 +-- .../IPlaylistGeneratorService.hpp | 4 +- .../recommendation/IRecommendationService.hpp | 4 +- .../services/scanner/impl/ScannerService.cpp | 4 +- .../services/scanner/impl/ScannerService.hpp | 6 +-- .../impl/scanners/ArtistInfoFileScanner.cpp | 4 +- .../impl/scanners/ArtistInfoFileScanner.hpp | 13 +++---- .../impl/scanners/AudioFileScanOperation.cpp | 4 +- .../impl/scanners/AudioFileScanOperation.hpp | 4 +- .../impl/scanners/AudioFileScanner.cpp | 4 +- .../impl/scanners/AudioFileScanner.hpp | 6 +-- .../impl/scanners/FileScanOperationBase.cpp | 2 +- .../impl/scanners/FileScanOperationBase.hpp | 8 ++-- .../impl/scanners/ImageFileScanner.cpp | 4 +- .../impl/scanners/ImageFileScanner.hpp | 13 +++---- .../impl/scanners/LyricsFileScanner.cpp | 4 +- .../impl/scanners/LyricsFileScanner.hpp | 13 +++---- .../impl/scanners/PlayListFileScanner.cpp | 4 +- .../impl/scanners/PlayListFileScanner.hpp | 13 +++---- .../steps/ScanStepArtistReconciliation.cpp | 2 +- .../steps/ScanStepAssociateArtistImages.cpp | 6 +-- .../steps/ScanStepAssociateExternalLyrics.cpp | 2 +- .../steps/ScanStepAssociatePlayListTracks.cpp | 6 +-- .../steps/ScanStepAssociateReleaseImages.cpp | 6 +-- .../steps/ScanStepAssociateTrackImages.cpp | 6 +-- .../scanner/impl/steps/ScanStepBase.hpp | 6 +-- .../steps/ScanStepCheckForDuplicatedFiles.cpp | 2 +- .../steps/ScanStepCheckForRemovedFiles.cpp | 2 +- .../scanner/impl/steps/ScanStepCompact.cpp | 2 +- .../steps/ScanStepComputeClusterStats.cpp | 2 +- .../scanner/impl/steps/ScanStepOptimize.cpp | 2 +- .../steps/ScanStepRemoveOrphanedDbEntries.cpp | 2 +- .../scanner/impl/steps/ScanStepScanFiles.cpp | 2 +- .../steps/ScanStepUpdateLibraryFields.cpp | 2 +- .../services/scanner/IScannerService.hpp | 4 +- .../scrobbling/impl/ScrobblingService.cpp | 6 +-- .../scrobbling/impl/ScrobblingService.hpp | 4 +- .../impl/internal/InternalBackend.cpp | 4 +- .../impl/internal/InternalBackend.hpp | 6 +-- .../impl/listenbrainz/ListenBrainzBackend.cpp | 4 +- .../impl/listenbrainz/ListenBrainzBackend.hpp | 6 +-- .../impl/listenbrainz/ListensSynchronizer.cpp | 4 +- .../impl/listenbrainz/ListensSynchronizer.hpp | 6 +-- .../scrobbling/IScrobblingService.hpp | 4 +- .../transcoding/impl/TranscodingService.cpp | 6 +-- .../transcoding/impl/TranscodingService.hpp | 4 +- .../transcoding/ITranscodingService.hpp | 4 +- src/libs/subsonic/impl/SubsonicResource.cpp | 6 +-- src/libs/subsonic/impl/SubsonicResource.hpp | 6 +-- .../include/subsonic/SubsonicResource.hpp | 4 +- src/lms/main.cpp | 36 ++++++++--------- src/lms/ui/LmsApplication.cpp | 8 ++-- src/lms/ui/LmsApplication.hpp | 10 ++--- src/tools/db-generator/LmsDbGenerator.cpp | 6 +-- .../recommendation/LmsRecommendation.cpp | 14 +++---- .../LmsSimilarityParameters.cpp | 2 +- 106 files changed, 315 insertions(+), 284 deletions(-) rename src/libs/database/{include/database => impl}/Db.hpp (91%) create mode 100644 src/libs/database/include/database/IDb.hpp diff --git a/src/libs/database/impl/Db.cpp b/src/libs/database/impl/Db.cpp index 0bb7e46a..91787a7e 100644 --- a/src/libs/database/impl/Db.cpp +++ b/src/libs/database/impl/Db.cpp @@ -17,8 +17,6 @@ * along with LMS. If not, see . */ -#include "database/Db.hpp" - #include #include @@ -31,6 +29,8 @@ #include "database/Session.hpp" #include "database/User.hpp" +#include "Db.hpp" + namespace lms::db { namespace @@ -134,6 +134,11 @@ namespace lms::db } } // namespace + std::unique_ptr createDb(const std::filesystem::path& dbPath, std::size_t connectionCount) + { + return std::make_unique(dbPath, connectionCount); + } + // Session living class handling the database and the login Db::Db(const std::filesystem::path& dbPath, std::size_t connectionCount) { diff --git a/src/libs/database/include/database/Db.hpp b/src/libs/database/impl/Db.hpp similarity index 91% rename from src/libs/database/include/database/Db.hpp rename to src/libs/database/impl/Db.hpp index 352bdf03..60002d26 100644 --- a/src/libs/database/include/database/Db.hpp +++ b/src/libs/database/impl/Db.hpp @@ -19,23 +19,25 @@ #pragma once -#include +#include +#include #include #include "core/RecursiveSharedMutex.hpp" +#include "database/IDb.hpp" + namespace lms::db { - class Session; - class Db + class Db : public IDb { public: - Db(const std::filesystem::path& dbPath, std::size_t connectionCount = 10); + Db(const std::filesystem::path& dbPath, std::size_t connectionCount); - Session& getTLSSession(); + Session& getTLSSession() override; - void executeSql(const std::string& sql); + void executeSql(const std::string& sql) override; private: Db(const Db&) = delete; diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index 2d1752bc..d6664c87 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -24,11 +24,11 @@ #include "core/Exception.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" -#include "database/Db.hpp" #include "database/ScanSettings.hpp" #include "database/Session.hpp" #include "database/User.hpp" +#include "Db.hpp" #include "Utils.hpp" namespace lms::db @@ -67,7 +67,7 @@ namespace lms::db::Migration class ScopedNoForeignKeys { public: - ScopedNoForeignKeys(Db& db) + ScopedNoForeignKeys(IDb& db) : _db{ db } { _db.executeSql("PRAGMA foreign_keys=OFF"); @@ -83,7 +83,7 @@ namespace lms::db::Migration ScopedNoForeignKeys& operator=(const ScopedNoForeignKeys&) = delete; ScopedNoForeignKeys& operator=(ScopedNoForeignKeys&&) = delete; - Db& _db; + IDb& _db; }; namespace diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 4e0c841d..3ebcebc7 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -26,7 +26,6 @@ #include "database/Artwork.hpp" #include "database/AuthToken.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" #include "database/Image.hpp" #include "database/Listen.hpp" @@ -53,6 +52,7 @@ #include "database/UIState.hpp" #include "database/User.hpp" +#include "Db.hpp" #include "Migration.hpp" #include "Utils.hpp" #include "traits/EnumSetTraits.hpp" @@ -96,10 +96,10 @@ namespace lms::db #endif } - Session::Session(Db& db) + Session::Session(IDb& db) : _db{ db } { - _session.setConnectionPool(_db.getConnectionPool()); + _session.setConnectionPool(static_cast(_db).getConnectionPool()); _session.mapClass("artist"); _session.mapClass("artist_info"); @@ -140,7 +140,7 @@ namespace lms::db WriteTransaction Session::createWriteTransaction() { - return WriteTransaction{ _db.getMutex(), _session }; + return WriteTransaction{ static_cast(_db).getMutex(), _session }; } ReadTransaction Session::createReadTransaction() @@ -359,7 +359,7 @@ namespace lms::db // We manually take a lock here since vacuum cannot be inside a transaction { - std::unique_lock lock{ _db.getMutex() }; + std::unique_lock lock{ static_cast(_db).getMutex() }; _db.executeSql("VACUUM"); } diff --git a/src/libs/database/include/database/IDb.hpp b/src/libs/database/include/database/IDb.hpp new file mode 100644 index 00000000..1823275a --- /dev/null +++ b/src/libs/database/include/database/IDb.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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 . + */ + +#pragma once + +#include +#include + +namespace lms::db +{ + class Session; + class IDb + { + public: + virtual ~IDb() = default; + + virtual Session& getTLSSession() = 0; + + virtual void executeSql(const std::string& sql) = 0; // TODO make this private + }; + + std::unique_ptr createDb(const std::filesystem::path& dbPath, std::size_t connectionCount = 10); +} // namespace lms::db diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index 88b0c7d9..82586461 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -65,11 +65,11 @@ namespace lms::db Wt::Dbo::Transaction _transaction; }; - class Db; + class IDb; class Session { public: - Session(Db& db); + Session(IDb& db); ~Session() = default; Session(const Session&) = delete; Session& operator=(const Session&) = delete; @@ -111,7 +111,7 @@ namespace lms::db { return &_session; } - Db& getDb() + IDb& getDb() { return _db; } @@ -146,7 +146,7 @@ namespace lms::db private: void execute(std::string_view query, long long id); - Db& _db; + IDb& _db; Wt::Dbo::Session _session; }; } // namespace lms::db diff --git a/src/libs/database/test/Common.cpp b/src/libs/database/test/Common.cpp index 2a59b829..7817b3dc 100644 --- a/src/libs/database/test/Common.cpp +++ b/src/libs/database/test/Common.cpp @@ -19,7 +19,6 @@ #include "Common.hpp" -#include "database/Db.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Types.hpp" @@ -29,13 +28,13 @@ namespace lms::db::tests TmpDatabase::TmpDatabase() : _tmpFile{ std::tmpnam(nullptr) } , _fileDeleter{ _tmpFile } - , _db{ _tmpFile } + , _db{ createDb(_tmpFile) } { } - db::Db& TmpDatabase::getDb() + db::IDb& TmpDatabase::getDb() { - return _db; + return *_db; } DatabaseFixture::~DatabaseFixture() diff --git a/src/libs/database/test/Common.hpp b/src/libs/database/test/Common.hpp index 45f53db5..1c7d92fc 100644 --- a/src/libs/database/test/Common.hpp +++ b/src/libs/database/test/Common.hpp @@ -26,7 +26,7 @@ #include "database/Artist.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Listen.hpp" #include "database/MediaLibrary.hpp" #include "database/Release.hpp" @@ -131,12 +131,12 @@ namespace lms::db::tests public: TmpDatabase(); - db::Db& getDb(); + IDb& getDb(); private: const std::filesystem::path _tmpFile; ScopedFileDeleter _fileDeleter; - db::Db _db; + std::unique_ptr _db; }; class DatabaseFixture : public ::testing::Test diff --git a/src/libs/database/test/Migration.cpp b/src/libs/database/test/Migration.cpp index da3b66d4..84c78238 100644 --- a/src/libs/database/test/Migration.cpp +++ b/src/libs/database/test/Migration.cpp @@ -23,7 +23,6 @@ #include "database/Artist.hpp" #include "database/ArtistInfo.hpp" #include "database/AuthToken.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" #include "database/Image.hpp" #include "database/PlayListFile.hpp" diff --git a/src/libs/services/artwork/impl/ArtworkService.cpp b/src/libs/services/artwork/impl/ArtworkService.cpp index fa3a7467..23b697db 100644 --- a/src/libs/services/artwork/impl/ArtworkService.cpp +++ b/src/libs/services/artwork/impl/ArtworkService.cpp @@ -24,7 +24,7 @@ #include "core/Utils.hpp" #include "database/Artist.hpp" #include "database/Artwork.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Image.hpp" #include "database/ImageId.hpp" #include "database/Release.hpp" @@ -40,12 +40,12 @@ namespace lms::artwork { - std::unique_ptr createArtworkService(db::Db& db, const std::filesystem::path& defaultReleaseCoverSvgPath, const std::filesystem::path& defaultArtistImageSvgPath) + std::unique_ptr createArtworkService(db::IDb& db, const std::filesystem::path& defaultReleaseCoverSvgPath, const std::filesystem::path& defaultArtistImageSvgPath) { return std::make_unique(db, defaultReleaseCoverSvgPath, defaultArtistImageSvgPath); } - ArtworkService::ArtworkService(db::Db& db, + ArtworkService::ArtworkService(db::IDb& db, const std::filesystem::path& defaultReleaseCoverSvgPath, const std::filesystem::path& defaultArtistImageSvgPath) : _db{ db } diff --git a/src/libs/services/artwork/impl/ArtworkService.hpp b/src/libs/services/artwork/impl/ArtworkService.hpp index a0aa24d5..f08b8a6d 100644 --- a/src/libs/services/artwork/impl/ArtworkService.hpp +++ b/src/libs/services/artwork/impl/ArtworkService.hpp @@ -43,7 +43,7 @@ namespace lms::artwork class ArtworkService : public IArtworkService { public: - ArtworkService(db::Db& db, const std::filesystem::path& defaultReleaseCoverSvgPath, const std::filesystem::path& defaultArtistImageSvgPath); + ArtworkService(db::IDb& db, const std::filesystem::path& defaultReleaseCoverSvgPath, const std::filesystem::path& defaultArtistImageSvgPath); ~ArtworkService() override; ArtworkService(const ArtworkService&) = delete; ArtworkService& operator=(const ArtworkService&) = delete; @@ -65,7 +65,7 @@ namespace lms::artwork std::unique_ptr getFromImageFile(const std::filesystem::path& p, std::optional width) const; std::unique_ptr getTrackImage(const std::filesystem::path& path, std::size_t index, std::optional width) const; - db::Db& _db; + db::IDb& _db; std::unique_ptr _audioFileParser; ImageCache _cache; diff --git a/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp b/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp index 4d8c1605..7577f640 100644 --- a/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp +++ b/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp @@ -29,7 +29,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::artwork @@ -54,6 +54,6 @@ namespace lms::artwork virtual void setJpegQuality(unsigned quality) = 0; // from 1 to 100 }; - std::unique_ptr createArtworkService(db::Db& db, const std::filesystem::path& defaultReleaseCoverSvgPath, const std::filesystem::path& defaultArtistImageSvgPath); + std::unique_ptr createArtworkService(db::IDb& db, const std::filesystem::path& defaultReleaseCoverSvgPath, const std::filesystem::path& defaultArtistImageSvgPath); } // namespace lms::artwork diff --git a/src/libs/services/auth/impl/AuthServiceBase.cpp b/src/libs/services/auth/impl/AuthServiceBase.cpp index 3dfed8d2..9164716a 100644 --- a/src/libs/services/auth/impl/AuthServiceBase.cpp +++ b/src/libs/services/auth/impl/AuthServiceBase.cpp @@ -20,7 +20,7 @@ #include "AuthServiceBase.hpp" #include "core/ILogger.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/User.hpp" @@ -28,7 +28,7 @@ namespace lms::auth { using namespace db; - AuthServiceBase::AuthServiceBase(Db& db) + AuthServiceBase::AuthServiceBase(db::IDb& db) : _db{ db } { } diff --git a/src/libs/services/auth/impl/AuthServiceBase.hpp b/src/libs/services/auth/impl/AuthServiceBase.hpp index ec066fb1..4b9956b1 100644 --- a/src/libs/services/auth/impl/AuthServiceBase.hpp +++ b/src/libs/services/auth/impl/AuthServiceBase.hpp @@ -25,7 +25,7 @@ namespace lms::db { - class Db; + class IDb; class Session; } // namespace lms::db @@ -34,7 +34,7 @@ namespace lms::auth class AuthServiceBase { protected: - AuthServiceBase(db::Db& db); + AuthServiceBase(db::IDb& db); ~AuthServiceBase() = default; AuthServiceBase(const AuthServiceBase&) = delete; AuthServiceBase& operator=(const AuthServiceBase&) = delete; @@ -45,6 +45,6 @@ namespace lms::auth db::Session& getDbSession(); private: - db::Db& _db; + db::IDb& _db; }; } // namespace lms::auth diff --git a/src/libs/services/auth/impl/AuthTokenService.cpp b/src/libs/services/auth/impl/AuthTokenService.cpp index da31cbe2..2e1fca8f 100644 --- a/src/libs/services/auth/impl/AuthTokenService.cpp +++ b/src/libs/services/auth/impl/AuthTokenService.cpp @@ -44,12 +44,12 @@ namespace lms::auth } } // namespace - std::unique_ptr createAuthTokenService(db::Db& db, std::size_t maxThrottlerEntryCount) + std::unique_ptr createAuthTokenService(db::IDb& db, std::size_t maxThrottlerEntryCount) { return std::make_unique(db, maxThrottlerEntryCount); } - AuthTokenService::AuthTokenService(db::Db& db, std::size_t maxThrottlerEntryCount) + AuthTokenService::AuthTokenService(db::IDb& db, std::size_t maxThrottlerEntryCount) : AuthServiceBase{ db } , _loginThrottler{ maxThrottlerEntryCount } { diff --git a/src/libs/services/auth/impl/AuthTokenService.hpp b/src/libs/services/auth/impl/AuthTokenService.hpp index c7f3e5c0..c0206774 100644 --- a/src/libs/services/auth/impl/AuthTokenService.hpp +++ b/src/libs/services/auth/impl/AuthTokenService.hpp @@ -37,7 +37,7 @@ namespace lms::auth class AuthTokenService : public IAuthTokenService, public AuthServiceBase { public: - AuthTokenService(db::Db& db, std::size_t maxThrottlerEntryCount); + AuthTokenService(db::IDb& db, std::size_t maxThrottlerEntryCount); ~AuthTokenService() override = default; AuthTokenService(const AuthTokenService&) = delete; diff --git a/src/libs/services/auth/impl/EnvService.cpp b/src/libs/services/auth/impl/EnvService.cpp index 486616ad..74d0283d 100644 --- a/src/libs/services/auth/impl/EnvService.cpp +++ b/src/libs/services/auth/impl/EnvService.cpp @@ -25,7 +25,7 @@ namespace lms::auth { - std::unique_ptr createEnvService(std::string_view backendName, db::Db& db) + std::unique_ptr createEnvService(std::string_view backendName, db::IDb& db) { if (backendName == "http-headers") return std::make_unique(db); diff --git a/src/libs/services/auth/impl/PasswordServiceBase.cpp b/src/libs/services/auth/impl/PasswordServiceBase.cpp index 6972a954..c9f0da03 100644 --- a/src/libs/services/auth/impl/PasswordServiceBase.cpp +++ b/src/libs/services/auth/impl/PasswordServiceBase.cpp @@ -35,7 +35,7 @@ namespace lms::auth { static const Wt::Auth::SHA1HashFunction sha1Function; - std::unique_ptr createPasswordService(std::string_view backend, db::Db& db, std::size_t maxThrottlerEntryCount) + std::unique_ptr createPasswordService(std::string_view backend, db::IDb& db, std::size_t maxThrottlerEntryCount) { if (backend == "internal") return std::make_unique(db, maxThrottlerEntryCount); @@ -46,7 +46,7 @@ namespace lms::auth throw Exception{ "Authentication backend '" + std::string{ backend } + "' not supported!" }; } - PasswordServiceBase::PasswordServiceBase(db::Db& db, std::size_t maxThrottlerEntries) + PasswordServiceBase::PasswordServiceBase(db::IDb& db, std::size_t maxThrottlerEntries) : AuthServiceBase{ db } , _loginThrottler{ maxThrottlerEntries } { diff --git a/src/libs/services/auth/impl/PasswordServiceBase.hpp b/src/libs/services/auth/impl/PasswordServiceBase.hpp index 8743e707..3c5be452 100644 --- a/src/libs/services/auth/impl/PasswordServiceBase.hpp +++ b/src/libs/services/auth/impl/PasswordServiceBase.hpp @@ -27,7 +27,7 @@ namespace lms::db { - class Db; + class IDb; class Session; } // namespace lms::db @@ -36,7 +36,7 @@ namespace lms::auth class PasswordServiceBase : public IPasswordService, public AuthServiceBase { public: - PasswordServiceBase(db::Db& db, std::size_t maxThrottlerEntries); + PasswordServiceBase(db::IDb& db, std::size_t maxThrottlerEntries); ~PasswordServiceBase() override = default; PasswordServiceBase(const PasswordServiceBase&) = delete; diff --git a/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.cpp b/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.cpp index 9c065e7f..7bc60b04 100644 --- a/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.cpp +++ b/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.cpp @@ -27,7 +27,7 @@ namespace lms::auth { - HttpHeadersEnvService::HttpHeadersEnvService(db::Db& db) + HttpHeadersEnvService::HttpHeadersEnvService(db::IDb& db) : AuthServiceBase{ db } , _fieldName{ core::Service::get()->getString("http-headers-login-field", "X-Forwarded-User") } { diff --git a/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.hpp b/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.hpp index 0e3f9ffe..e8334130 100644 --- a/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.hpp +++ b/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.hpp @@ -28,7 +28,7 @@ namespace lms::auth class HttpHeadersEnvService : public IEnvService, public AuthServiceBase { public: - HttpHeadersEnvService(db::Db& db); + HttpHeadersEnvService(db::IDb& db); private: CheckResult processEnv(const Wt::WEnvironment& env) override; diff --git a/src/libs/services/auth/impl/internal/InternalPasswordService.cpp b/src/libs/services/auth/impl/internal/InternalPasswordService.cpp index 013923e0..2b3e5bc0 100644 --- a/src/libs/services/auth/impl/internal/InternalPasswordService.cpp +++ b/src/libs/services/auth/impl/internal/InternalPasswordService.cpp @@ -29,7 +29,7 @@ namespace lms::auth { - InternalPasswordService::InternalPasswordService(db::Db& db, std::size_t maxThrottlerEntries) + InternalPasswordService::InternalPasswordService(db::IDb& db, std::size_t maxThrottlerEntries) : PasswordServiceBase{ db, maxThrottlerEntries } , _bcryptRoundCount{ static_cast(core::Service::get()->getULong("internal-password-bcrypt-round", 12)) } { diff --git a/src/libs/services/auth/impl/internal/InternalPasswordService.hpp b/src/libs/services/auth/impl/internal/InternalPasswordService.hpp index 105fd746..1c05e3d8 100644 --- a/src/libs/services/auth/impl/internal/InternalPasswordService.hpp +++ b/src/libs/services/auth/impl/internal/InternalPasswordService.hpp @@ -32,7 +32,7 @@ namespace lms::auth class InternalPasswordService : public PasswordServiceBase { public: - InternalPasswordService(db::Db& db, std::size_t maxThrottlerEntries); + InternalPasswordService(db::IDb& db, std::size_t maxThrottlerEntries); private: bool checkUserPassword(std::string_view loginName, std::string_view password) override; diff --git a/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp b/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp index 12763ac5..22739642 100644 --- a/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp +++ b/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp @@ -32,7 +32,7 @@ namespace lms::db { - class Db; + class IDb; } // namespace lms::db namespace lms::auth @@ -81,5 +81,5 @@ namespace lms::auth virtual void clearAuthTokens(core::LiteralString domain, db::UserId userid) = 0; }; - std::unique_ptr createAuthTokenService(db::Db& db, std::size_t maxThrottlerEntryCount); + std::unique_ptr createAuthTokenService(db::IDb& db, std::size_t maxThrottlerEntryCount); } // namespace lms::auth diff --git a/src/libs/services/auth/include/services/auth/IEnvService.hpp b/src/libs/services/auth/include/services/auth/IEnvService.hpp index 4c84dc4f..502d9f19 100644 --- a/src/libs/services/auth/include/services/auth/IEnvService.hpp +++ b/src/libs/services/auth/include/services/auth/IEnvService.hpp @@ -26,7 +26,7 @@ namespace lms::db { - class Db; + class IDb; class Session; } // namespace lms::db @@ -65,5 +65,5 @@ namespace lms::auth virtual CheckResult processRequest(const Wt::Http::Request& request) = 0; }; - std::unique_ptr createEnvService(std::string_view backend, db::Db& db); + std::unique_ptr createEnvService(std::string_view backend, db::IDb& db); } // namespace lms::auth diff --git a/src/libs/services/auth/include/services/auth/IPasswordService.hpp b/src/libs/services/auth/include/services/auth/IPasswordService.hpp index a1a90d68..1986883b 100644 --- a/src/libs/services/auth/include/services/auth/IPasswordService.hpp +++ b/src/libs/services/auth/include/services/auth/IPasswordService.hpp @@ -30,7 +30,7 @@ namespace lms::db { - class Db; + class IDb; class User; } // namespace lms::db @@ -69,5 +69,5 @@ namespace lms::auth virtual void setPassword(db::UserId userId, std::string_view newPassword) = 0; }; - std::unique_ptr createPasswordService(std::string_view backend, db::Db& db, std::size_t maxThrottlerEntryCount); + std::unique_ptr createPasswordService(std::string_view backend, db::IDb& db, std::size_t maxThrottlerEntryCount); } // namespace lms::auth diff --git a/src/libs/services/feedback/impl/FeedbackService.cpp b/src/libs/services/feedback/impl/FeedbackService.cpp index 448234d8..69e80df9 100644 --- a/src/libs/services/feedback/impl/FeedbackService.cpp +++ b/src/libs/services/feedback/impl/FeedbackService.cpp @@ -22,7 +22,7 @@ #include "core/ILogger.hpp" #include "database/Artist.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/RatedArtist.hpp" #include "database/RatedRelease.hpp" #include "database/RatedTrack.hpp" @@ -39,12 +39,12 @@ namespace lms::feedback { - std::unique_ptr createFeedbackService(boost::asio::io_context& ioContext, Db& db) + std::unique_ptr createFeedbackService(boost::asio::io_context& ioContext, db::IDb& db) { return std::make_unique(ioContext, db); } - FeedbackService::FeedbackService(boost::asio::io_context& ioContext, Db& db) + FeedbackService::FeedbackService(boost::asio::io_context& ioContext, db::IDb& db) : _db{ db } { LMS_LOG(SCROBBLING, INFO, "Starting service..."); @@ -58,7 +58,7 @@ namespace lms::feedback LMS_LOG(SCROBBLING, INFO, "Service stopped!"); } - std::optional FeedbackService::getUserFeedbackBackend(UserId userId) + std::optional FeedbackService::getUserFeedbackBackend(db::UserId userId) { std::optional feedbackBackend; diff --git a/src/libs/services/feedback/impl/FeedbackService.hpp b/src/libs/services/feedback/impl/FeedbackService.hpp index 6c5add69..e8407c7f 100644 --- a/src/libs/services/feedback/impl/FeedbackService.hpp +++ b/src/libs/services/feedback/impl/FeedbackService.hpp @@ -28,7 +28,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::feedback @@ -36,7 +36,7 @@ namespace lms::feedback class FeedbackService : public IFeedbackService { public: - FeedbackService(boost::asio::io_context& ioContext, db::Db& db); + FeedbackService(boost::asio::io_context& ioContext, db::IDb& db); ~FeedbackService() override; FeedbackService(const FeedbackService&) = delete; FeedbackService& operator=(const FeedbackService&) = delete; @@ -86,7 +86,7 @@ namespace lms::feedback template std::optional getRating(db::UserId userId, ObjIdType objectId); - db::Db& _db; + db::IDb& _db; std::unordered_map> _backends; }; diff --git a/src/libs/services/feedback/impl/FeedbackService.impl.hpp b/src/libs/services/feedback/impl/FeedbackService.impl.hpp index 29307983..2db429ce 100644 --- a/src/libs/services/feedback/impl/FeedbackService.impl.hpp +++ b/src/libs/services/feedback/impl/FeedbackService.impl.hpp @@ -19,7 +19,7 @@ #pragma once -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/User.hpp" diff --git a/src/libs/services/feedback/impl/internal/InternalBackend.cpp b/src/libs/services/feedback/impl/internal/InternalBackend.cpp index 7d3f1b9a..847e24ac 100644 --- a/src/libs/services/feedback/impl/internal/InternalBackend.cpp +++ b/src/libs/services/feedback/impl/internal/InternalBackend.cpp @@ -19,7 +19,7 @@ #include "InternalBackend.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/StarredArtist.hpp" #include "database/StarredRelease.hpp" @@ -48,7 +48,7 @@ namespace lms::feedback } } // namespace details - InternalBackend::InternalBackend(db::Db& db) + InternalBackend::InternalBackend(db::IDb& db) : _db{ db } { } diff --git a/src/libs/services/feedback/impl/internal/InternalBackend.hpp b/src/libs/services/feedback/impl/internal/InternalBackend.hpp index 0d41be4e..1839b498 100644 --- a/src/libs/services/feedback/impl/internal/InternalBackend.hpp +++ b/src/libs/services/feedback/impl/internal/InternalBackend.hpp @@ -23,7 +23,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::feedback @@ -31,7 +31,7 @@ namespace lms::feedback class InternalBackend final : public IFeedbackBackend { public: - InternalBackend(db::Db& db); + InternalBackend(db::IDb& db); ~InternalBackend() override = default; InternalBackend(const InternalBackend&) = delete; InternalBackend& operator=(const InternalBackend&) = delete; @@ -44,6 +44,6 @@ namespace lms::feedback void onStarred(db::StarredTrackId trackId) override; void onUnstarred(db::StarredTrackId trackId) override; - db::Db& _db; + db::IDb& _db; }; } // namespace lms::feedback diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp index a0a80c66..40123058 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp @@ -29,7 +29,7 @@ #include "core/IConfig.hpp" #include "core/Service.hpp" #include "core/http/IClient.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/StarredTrack.hpp" #include "database/Track.hpp" @@ -60,7 +60,7 @@ namespace lms::feedback::listenBrainz } } // namespace - FeedbacksSynchronizer::FeedbacksSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client) + FeedbacksSynchronizer::FeedbacksSynchronizer(boost::asio::io_context& ioContext, db::IDb& db, core::http::IClient& client) : _ioContext{ ioContext } , _db{ db } , _client{ client } diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp index 0371de51..ae9153ea 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp @@ -39,7 +39,7 @@ namespace lms } namespace db { - class Db; + class IDb; } } // namespace lms @@ -48,7 +48,7 @@ namespace lms::feedback::listenBrainz class FeedbacksSynchronizer { public: - FeedbacksSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client); + FeedbacksSynchronizer(boost::asio::io_context& ioContext, db::IDb& db, core::http::IClient& client); ~FeedbacksSynchronizer() = default; FeedbacksSynchronizer(const FeedbacksSynchronizer&) = delete; FeedbacksSynchronizer& operator=(const FeedbacksSynchronizer&) = delete; @@ -95,7 +95,7 @@ namespace lms::feedback::listenBrainz boost::asio::io_context& _ioContext; boost::asio::io_context::strand _strand{ _ioContext }; - db::Db& _db; + db::IDb& _db; boost::asio::steady_timer _syncTimer{ _ioContext }; core::http::IClient& _client; diff --git a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp index bb7347ad..f3a45527 100644 --- a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp @@ -22,7 +22,7 @@ #include "core/IConfig.hpp" #include "core/Service.hpp" #include "core/http/IClient.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/StarredArtist.hpp" #include "database/StarredRelease.hpp" @@ -56,7 +56,7 @@ namespace lms::feedback::listenBrainz } } // namespace details - ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, db::Db& db) + ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, db::IDb& db) : _ioContext{ ioContext } , _db{ db } , _baseAPIUrl{ core::Service::get()->getString("listenbrainz-api-base-url", "https://api.listenbrainz.org") } diff --git a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.hpp b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.hpp index f7359095..88ff7419 100644 --- a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.hpp @@ -28,7 +28,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::feedback::listenBrainz @@ -36,7 +36,7 @@ namespace lms::feedback::listenBrainz class ListenBrainzBackend final : public IFeedbackBackend { public: - ListenBrainzBackend(boost::asio::io_context& ioContext, db::Db& db); + ListenBrainzBackend(boost::asio::io_context& ioContext, db::IDb& db); ~ListenBrainzBackend() override; private: @@ -51,7 +51,7 @@ namespace lms::feedback::listenBrainz void onUnstarred(db::StarredTrackId starredTrackId) override; boost::asio::io_context& _ioContext; - db::Db& _db; + db::IDb& _db; std::string _baseAPIUrl; std::unique_ptr _client; FeedbacksSynchronizer _feedbacksSynchronizer; diff --git a/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp b/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp index b88c8102..10fa960b 100644 --- a/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp +++ b/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp @@ -34,7 +34,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::feedback @@ -125,6 +125,6 @@ namespace lms::feedback virtual std::optional getRating(db::UserId userId, db::TrackId trackId) = 0; }; - std::unique_ptr createFeedbackService(boost::asio::io_context& ioContext, db::Db& db); + std::unique_ptr createFeedbackService(boost::asio::io_context& ioContext, db::IDb& db); } // namespace lms::feedback diff --git a/src/libs/services/recommendation/impl/ClustersEngineCreator.hpp b/src/libs/services/recommendation/impl/ClustersEngineCreator.hpp index d83328c8..7d157526 100644 --- a/src/libs/services/recommendation/impl/ClustersEngineCreator.hpp +++ b/src/libs/services/recommendation/impl/ClustersEngineCreator.hpp @@ -23,11 +23,11 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::recommendation { class IEngine; - std::unique_ptr createClustersEngine(db::Db& db); + std::unique_ptr createClustersEngine(db::IDb& db); } // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/FeaturesEngineCreator.hpp b/src/libs/services/recommendation/impl/FeaturesEngineCreator.hpp index 107e250a..3d9bcb2e 100644 --- a/src/libs/services/recommendation/impl/FeaturesEngineCreator.hpp +++ b/src/libs/services/recommendation/impl/FeaturesEngineCreator.hpp @@ -25,10 +25,10 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::recommendation { - std::unique_ptr createFeaturesEngine(db::Db& db); + std::unique_ptr createFeaturesEngine(db::IDb& db); } diff --git a/src/libs/services/recommendation/impl/IEngine.hpp b/src/libs/services/recommendation/impl/IEngine.hpp index 890631dc..d4229a8f 100644 --- a/src/libs/services/recommendation/impl/IEngine.hpp +++ b/src/libs/services/recommendation/impl/IEngine.hpp @@ -28,7 +28,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::recommendation @@ -47,6 +47,6 @@ namespace lms::recommendation virtual ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const = 0; }; - std::unique_ptr createEngine(db::Db& db); + std::unique_ptr createEngine(db::IDb& db); } // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp b/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp index 5256e2d7..1315bbd6 100644 --- a/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp +++ b/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp @@ -22,7 +22,7 @@ #include #include "core/ILogger.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "services/recommendation/IRecommendationService.hpp" @@ -35,12 +35,12 @@ namespace lms::recommendation { using namespace db; - std::unique_ptr createPlaylistGeneratorService(Db& db, IRecommendationService& recommendationService) + std::unique_ptr createPlaylistGeneratorService(db::IDb& db, IRecommendationService& recommendationService) { return std::make_unique(db, recommendationService); } - PlaylistGeneratorService::PlaylistGeneratorService(Db& db, IRecommendationService& recommendationService) + PlaylistGeneratorService::PlaylistGeneratorService(db::IDb& db, IRecommendationService& recommendationService) : _db{ db } , _recommendationService{ recommendationService } { diff --git a/src/libs/services/recommendation/impl/PlaylistGeneratorService.hpp b/src/libs/services/recommendation/impl/PlaylistGeneratorService.hpp index 6287d778..0e6f88f0 100644 --- a/src/libs/services/recommendation/impl/PlaylistGeneratorService.hpp +++ b/src/libs/services/recommendation/impl/PlaylistGeneratorService.hpp @@ -29,14 +29,14 @@ namespace lms::recommendation class PlaylistGeneratorService : public IPlaylistGeneratorService { public: - PlaylistGeneratorService(db::Db& db, IRecommendationService& recommendationService); + PlaylistGeneratorService(db::IDb& db, IRecommendationService& recommendationService); private: TrackContainer extendPlaylist(db::TrackListId tracklistId, std::size_t maxCount) const override; TrackContainer getTracksFromTrackList(db::TrackListId tracklistId) const; - db::Db& _db; + db::IDb& _db; IRecommendationService& _recommendationService; std::vector> _constraints; }; diff --git a/src/libs/services/recommendation/impl/RecommendationService.cpp b/src/libs/services/recommendation/impl/RecommendationService.cpp index 51a7e365..b5498f9f 100644 --- a/src/libs/services/recommendation/impl/RecommendationService.cpp +++ b/src/libs/services/recommendation/impl/RecommendationService.cpp @@ -21,7 +21,7 @@ #include -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/ScanSettings.hpp" #include "database/Session.hpp" @@ -40,12 +40,12 @@ namespace lms::recommendation } } // namespace - std::unique_ptr createRecommendationService(db::Db& db) + std::unique_ptr createRecommendationService(db::IDb& db) { return std::make_unique(db); } - RecommendationService::RecommendationService(db::Db& db) + RecommendationService::RecommendationService(db::IDb& db) : _db{ db } { load(); diff --git a/src/libs/services/recommendation/impl/RecommendationService.hpp b/src/libs/services/recommendation/impl/RecommendationService.hpp index d5cde868..8424e528 100644 --- a/src/libs/services/recommendation/impl/RecommendationService.hpp +++ b/src/libs/services/recommendation/impl/RecommendationService.hpp @@ -27,7 +27,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::recommendation @@ -41,7 +41,7 @@ namespace lms::recommendation class RecommendationService : public IRecommendationService { public: - RecommendationService(db::Db& db); + RecommendationService(db::IDb& db); ~RecommendationService() override = default; RecommendationService(const RecommendationService&) = delete; RecommendationService& operator=(const RecommendationService&) = delete; @@ -58,7 +58,7 @@ namespace lms::recommendation void clearEngines(); void loadPendingEngine(EngineType engineType, std::unique_ptr engine, bool forceReload, const ProgressCallback& progressCallback); - db::Db& _db; + db::IDb& _db; std::optional _engineType; std::unique_ptr _engine; }; diff --git a/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp b/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp index 662d9da6..2a001500 100644 --- a/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp +++ b/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp @@ -21,7 +21,7 @@ #include "database/Artist.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -29,10 +29,9 @@ namespace lms::recommendation { - using namespace db; - std::unique_ptr createClustersEngine(Db& db) + std::unique_ptr createClustersEngine(db::IDb& db) { return std::make_unique(db); } diff --git a/src/libs/services/recommendation/impl/clusters/ClustersEngine.hpp b/src/libs/services/recommendation/impl/clusters/ClustersEngine.hpp index 7cf50846..4ae10610 100644 --- a/src/libs/services/recommendation/impl/clusters/ClustersEngine.hpp +++ b/src/libs/services/recommendation/impl/clusters/ClustersEngine.hpp @@ -27,7 +27,7 @@ namespace lms::recommendation class ClusterEngine : public IEngine { public: - ClusterEngine(db::Db& db) + ClusterEngine(db::IDb& db) : _db{ db } {} ~ClusterEngine() override = default; @@ -45,7 +45,7 @@ namespace lms::recommendation ReleaseContainer getSimilarReleases(db::ReleaseId releaseId, std::size_t maxCount) const override; ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const override; - db::Db& _db; + db::IDb& _db; }; } // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp b/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp index cca183fc..181f6c3f 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp +++ b/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp @@ -24,7 +24,7 @@ #include "core/ILogger.hpp" #include "core/Random.hpp" #include "database/Artist.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -37,7 +37,7 @@ namespace lms::recommendation { using namespace db; - std::unique_ptr createFeaturesEngine(Db& db) + std::unique_ptr createFeaturesEngine(db::IDb& db) { return std::make_unique(db); } diff --git a/src/libs/services/recommendation/impl/features/FeaturesEngine.hpp b/src/libs/services/recommendation/impl/features/FeaturesEngine.hpp index 1e0c91fa..3633a9f2 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesEngine.hpp +++ b/src/libs/services/recommendation/impl/features/FeaturesEngine.hpp @@ -46,7 +46,7 @@ namespace lms::recommendation class FeaturesEngine : public IEngine { public: - FeaturesEngine(db::Db& db) + FeaturesEngine(db::IDb& db) : _db{ db } {} FeaturesEngine(const FeaturesEngine&) = delete; @@ -105,7 +105,7 @@ namespace lms::recommendation const ObjectPositions& objectPositions, std::size_t maxCount) const; - db::Db& _db; + db::IDb& _db; bool _loadCancelled{}; std::unique_ptr _network; double _networkRefVectorsDistanceMedian{}; diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp index 731cddd8..9aaaae0c 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp @@ -21,7 +21,7 @@ #include -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -42,7 +42,7 @@ namespace lms::recommendation::PlaylistGeneratorConstraint } } // namespace - ConsecutiveArtists::ConsecutiveArtists(db::Db& db) + ConsecutiveArtists::ConsecutiveArtists(db::IDb& db) : _db{ db } { } diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.hpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.hpp index 15ce02f4..4082b927 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.hpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.hpp @@ -23,7 +23,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::recommendation::PlaylistGeneratorConstraint @@ -31,7 +31,7 @@ namespace lms::recommendation::PlaylistGeneratorConstraint class ConsecutiveArtists : public IConstraint { public: - ConsecutiveArtists(db::Db& db); + ConsecutiveArtists(db::IDb& db); ~ConsecutiveArtists() override = default; ConsecutiveArtists(const ConsecutiveArtists&) = delete; ConsecutiveArtists& operator=(const ConsecutiveArtists&) = delete; @@ -40,6 +40,6 @@ namespace lms::recommendation::PlaylistGeneratorConstraint float computeScore(const TrackContainer& trackIds, std::size_t trackIndex) override; ArtistContainer getArtists(db::TrackId trackId); - db::Db& _db; + db::IDb& _db; }; } // namespace lms::recommendation::PlaylistGeneratorConstraint diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp index 9e072f07..9d8a4760 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp @@ -19,14 +19,14 @@ #include "ConsecutiveReleases.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" namespace lms::recommendation::PlaylistGeneratorConstraint { - ConsecutiveReleases::ConsecutiveReleases(db::Db& db) + ConsecutiveReleases::ConsecutiveReleases(db::IDb& db) : _db{ db } { } diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp index 11480ae7..6055e21d 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp @@ -25,7 +25,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::recommendation::PlaylistGeneratorConstraint @@ -33,7 +33,7 @@ namespace lms::recommendation::PlaylistGeneratorConstraint class ConsecutiveReleases : public IConstraint { public: - ConsecutiveReleases(db::Db& db); + ConsecutiveReleases(db::IDb& db); ~ConsecutiveReleases() override = default; ConsecutiveReleases(const ConsecutiveReleases&) = delete; ConsecutiveReleases& operator=(const ConsecutiveReleases&) = delete; @@ -43,6 +43,6 @@ namespace lms::recommendation::PlaylistGeneratorConstraint db::ReleaseId getReleaseId(db::TrackId trackId); - db::Db& _db; + db::IDb& _db; }; } // namespace lms::recommendation::PlaylistGeneratorConstraint diff --git a/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp b/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp index 58bda161..3fd5168b 100644 --- a/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp +++ b/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp @@ -26,7 +26,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::recommendation @@ -41,5 +41,5 @@ namespace lms::recommendation virtual TrackContainer extendPlaylist(db::TrackListId tracklistId, std::size_t maxCount) const = 0; }; - std::unique_ptr createPlaylistGeneratorService(db::Db& db, IRecommendationService& recommendationService); + std::unique_ptr createPlaylistGeneratorService(db::IDb& db, IRecommendationService& recommendationService); } // namespace lms::recommendation diff --git a/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp b/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp index 0872cc69..92849eec 100644 --- a/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp +++ b/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp @@ -31,7 +31,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::recommendation @@ -49,5 +49,5 @@ namespace lms::recommendation virtual ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const = 0; }; - std::unique_ptr createRecommendationService(db::Db& db); + std::unique_ptr createRecommendationService(db::IDb& db); } // namespace lms::recommendation diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index 3bb087ee..cc770bd2 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -152,12 +152,12 @@ namespace lms::scanner } // namespace - std::unique_ptr createScannerService(Db& db) + std::unique_ptr createScannerService(db::IDb& db) { return std::make_unique(db); } - ScannerService::ScannerService(Db& db) + ScannerService::ScannerService(db::IDb& db) : _db{ db } , _jobScheduler{ core::createJobScheduler("Scanner", getScannerThreadCount()) } { diff --git a/src/libs/services/scanner/impl/ScannerService.hpp b/src/libs/services/scanner/impl/ScannerService.hpp index c3705905..35599da9 100644 --- a/src/libs/services/scanner/impl/ScannerService.hpp +++ b/src/libs/services/scanner/impl/ScannerService.hpp @@ -32,7 +32,7 @@ #include #include "ScannerSettings.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "services/scanner/IScannerService.hpp" #include "steps/IScanStep.hpp" @@ -52,7 +52,7 @@ namespace lms::scanner class ScannerService : public IScannerService { public: - ScannerService(db::Db& db); + ScannerService(db::IDb& db); ~ScannerService() override; ScannerService(const ScannerService&) = delete; ScannerService& operator=(const ScannerService&) = delete; @@ -85,7 +85,7 @@ namespace lms::scanner void notifyInProgressIfNeeded(const ScanStepStats& stats); void notifyInProgress(const ScanStepStats& stats); - db::Db& _db; + db::IDb& _db; std::unique_ptr _jobScheduler; std::vector> _fileScanners; diff --git a/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.cpp b/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.cpp index 21469e80..7fade649 100644 --- a/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.cpp @@ -26,7 +26,7 @@ #include "core/String.hpp" #include "database/Artist.hpp" #include "database/ArtistInfo.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/MediaLibrary.hpp" #include "database/Session.hpp" #include "metadata/ArtistInfo.hpp" @@ -137,7 +137,7 @@ namespace lms::scanner } } // namespace - ArtistInfoFileScanner::ArtistInfoFileScanner(db::Db& db, const ScannerSettings& settings) + ArtistInfoFileScanner::ArtistInfoFileScanner(db::IDb& db, const ScannerSettings& settings) : _db{ db } , _settings{ settings } { diff --git a/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.hpp b/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.hpp index 4d0af151..8036d4e9 100644 --- a/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.hpp +++ b/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.hpp @@ -21,13 +21,10 @@ #include "IFileScanner.hpp" -namespace lms +namespace lms::db { - namespace db - { - class Db; - } -} // namespace lms + class IDb; +} namespace lms::scanner { @@ -36,7 +33,7 @@ namespace lms::scanner class ArtistInfoFileScanner : public IFileScanner { public: - ArtistInfoFileScanner(db::Db& db, const ScannerSettings& _settings); + ArtistInfoFileScanner(db::IDb& db, const ScannerSettings& _settings); ~ArtistInfoFileScanner() override = default; ArtistInfoFileScanner(const ArtistInfoFileScanner&) = delete; ArtistInfoFileScanner& operator=(const ArtistInfoFileScanner&) = delete; @@ -48,7 +45,7 @@ namespace lms::scanner bool needsScan(const FileToScan& file) const override; std::unique_ptr createScanOperation(FileToScan&& fileToScan) const override; - db::Db& _db; + db::IDb& _db; const ScannerSettings& _settings; }; } // namespace lms::scanner \ No newline at end of file diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index 4406e91b..6c3d1221 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -27,8 +27,8 @@ #include "database/Artist.hpp" #include "database/Artwork.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IDb.hpp" #include "database/MediaLibrary.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -466,7 +466,7 @@ namespace lms::scanner } } // namespace - AudioFileScanOperation::AudioFileScanOperation(FileToScan&& fileToScan, db::Db& db, const ScannerSettings& settings, metadata::IAudioFileParser& parser) + AudioFileScanOperation::AudioFileScanOperation(FileToScan&& fileToScan, db::IDb& db, const ScannerSettings& settings, metadata::IAudioFileParser& parser) : FileScanOperationBase{ std::move(fileToScan), db, settings } , _parser{ parser } { diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.hpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.hpp index a6bf3c54..20344ee9 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.hpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.hpp @@ -32,7 +32,7 @@ namespace lms::db { - class Db; + class IDb; } // namespace lms::db namespace lms::metadata @@ -56,7 +56,7 @@ namespace lms::scanner class AudioFileScanOperation : public FileScanOperationBase { public: - AudioFileScanOperation(FileToScan&& fileToScan, db::Db& db, const ScannerSettings& settings, metadata::IAudioFileParser& parser); + AudioFileScanOperation(FileToScan&& fileToScan, db::IDb& db, const ScannerSettings& settings, metadata::IAudioFileParser& parser); ~AudioFileScanOperation() override; AudioFileScanOperation(const AudioFileScanOperation&) = delete; AudioFileScanOperation& operator=(const AudioFileScanOperation&) = delete; diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp index 7c68d3fd..5bd20f8a 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp @@ -21,7 +21,7 @@ #include "core/IConfig.hpp" #include "core/Service.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/MediaLibrary.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -64,7 +64,7 @@ namespace lms::scanner } // namespace - AudioFileScanner::AudioFileScanner(db::Db& db, const ScannerSettings& settings) + AudioFileScanner::AudioFileScanner(db::IDb& db, const ScannerSettings& settings) : _db{ db } , _settings{ settings } , _metadataParser{ metadata::createAudioFileParser(createAudioFileParserParameters(settings)) } // For now, always use TagLib diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanner.hpp b/src/libs/services/scanner/impl/scanners/AudioFileScanner.hpp index 3fa46cbf..924f4baf 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanner.hpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanner.hpp @@ -25,7 +25,7 @@ namespace lms { namespace db { - class Db; + class IDb; } namespace metadata @@ -41,7 +41,7 @@ namespace lms::scanner class AudioFileScanner : public IFileScanner { public: - AudioFileScanner(db::Db& db, const ScannerSettings& settings); + AudioFileScanner(db::IDb& db, const ScannerSettings& settings); ~AudioFileScanner() override; AudioFileScanner(const AudioFileScanner&) = delete; AudioFileScanner& operator=(const AudioFileScanner&) = delete; @@ -53,7 +53,7 @@ namespace lms::scanner bool needsScan(const FileToScan& file) const override; std::unique_ptr createScanOperation(FileToScan&& fileToScan) const override; - db::Db& _db; + db::IDb& _db; const ScannerSettings& _settings; std::unique_ptr _metadataParser; }; diff --git a/src/libs/services/scanner/impl/scanners/FileScanOperationBase.cpp b/src/libs/services/scanner/impl/scanners/FileScanOperationBase.cpp index ca3ca660..5275be53 100644 --- a/src/libs/services/scanner/impl/scanners/FileScanOperationBase.cpp +++ b/src/libs/services/scanner/impl/scanners/FileScanOperationBase.cpp @@ -23,7 +23,7 @@ namespace lms::scanner { - FileScanOperationBase::FileScanOperationBase(FileToScan&& fileToScan, db::Db& db, const ScannerSettings& settings) + FileScanOperationBase::FileScanOperationBase(FileToScan&& fileToScan, db::IDb& db, const ScannerSettings& settings) : _file{ std::move(fileToScan) } , _db{ db } , _settings{ settings } diff --git a/src/libs/services/scanner/impl/scanners/FileScanOperationBase.hpp b/src/libs/services/scanner/impl/scanners/FileScanOperationBase.hpp index 33482190..f8318a52 100644 --- a/src/libs/services/scanner/impl/scanners/FileScanOperationBase.hpp +++ b/src/libs/services/scanner/impl/scanners/FileScanOperationBase.hpp @@ -27,7 +27,7 @@ namespace lms::db { - class Db; + class IDb; } // namespace lms::db namespace lms::scanner @@ -38,7 +38,7 @@ namespace lms::scanner class FileScanOperationBase : public IFileScanOperation { public: - FileScanOperationBase(FileToScan&& fileToScan, db::Db& db, const ScannerSettings& settings); + FileScanOperationBase(FileToScan&& fileToScan, db::IDb& db, const ScannerSettings& settings); ~FileScanOperationBase() override; FileScanOperationBase(const FileScanOperationBase&) = delete; FileScanOperationBase& operator=(const FileScanOperationBase&) = delete; @@ -46,7 +46,7 @@ namespace lms::scanner protected: const std::filesystem::path& getFilePath() const override { return _file.filePath; } const MediaLibraryInfo& getMediaLibrary() const { return _file.mediaLibrary; } - db::Db& getDb() { return _db; } + db::IDb& getDb() { return _db; } const ScannerSettings& getScannerSettings() const { return _settings; } Wt::WDateTime getLastWriteTime() const { return _file.lastWriteTime; } std::size_t getFileSize() const { return _file.fileSize; } @@ -61,7 +61,7 @@ namespace lms::scanner private: const FileToScan _file; - db::Db& _db; + db::IDb& _db; const ScannerSettings& _settings; ScanErrorVector _errors; }; diff --git a/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp b/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp index d4d512e8..8910f07d 100644 --- a/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp @@ -23,7 +23,7 @@ #include "core/ILogger.hpp" #include "database/Artwork.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Image.hpp" #include "database/MediaLibrary.hpp" #include "database/Session.hpp" @@ -108,7 +108,7 @@ namespace lms::scanner } } // namespace - ImageFileScanner::ImageFileScanner(db::Db& db, ScannerSettings& settings) + ImageFileScanner::ImageFileScanner(db::IDb& db, ScannerSettings& settings) : _db{ db } , _settings{ settings } { diff --git a/src/libs/services/scanner/impl/scanners/ImageFileScanner.hpp b/src/libs/services/scanner/impl/scanners/ImageFileScanner.hpp index 4e34b0cb..7c4f8974 100644 --- a/src/libs/services/scanner/impl/scanners/ImageFileScanner.hpp +++ b/src/libs/services/scanner/impl/scanners/ImageFileScanner.hpp @@ -21,13 +21,10 @@ #include "IFileScanner.hpp" -namespace lms +namespace lms::db { - namespace db - { - class Db; - } -} // namespace lms + class IDb; +} namespace lms::scanner { @@ -36,7 +33,7 @@ namespace lms::scanner class ImageFileScanner : public IFileScanner { public: - ImageFileScanner(db::Db& db, ScannerSettings& settings); + ImageFileScanner(db::IDb& db, ScannerSettings& settings); ~ImageFileScanner() override = default; ImageFileScanner(const ImageFileScanner&) = delete; ImageFileScanner& operator=(const ImageFileScanner&) = delete; @@ -48,7 +45,7 @@ namespace lms::scanner bool needsScan(const FileToScan& file) const override; std::unique_ptr createScanOperation(FileToScan&& fileToScan) const override; - db::Db& _db; + db::IDb& _db; ScannerSettings& _settings; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/scanners/LyricsFileScanner.cpp b/src/libs/services/scanner/impl/scanners/LyricsFileScanner.cpp index f88e3563..d077802b 100644 --- a/src/libs/services/scanner/impl/scanners/LyricsFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/LyricsFileScanner.cpp @@ -25,7 +25,7 @@ #include "FileScanOperationBase.hpp" #include "ScannerSettings.hpp" #include "core/ILogger.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/MediaLibrary.hpp" #include "database/Session.hpp" #include "database/TrackLyrics.hpp" @@ -122,7 +122,7 @@ namespace lms::scanner } } // namespace - LyricsFileScanner::LyricsFileScanner(db::Db& db, ScannerSettings& _settings) + LyricsFileScanner::LyricsFileScanner(db::IDb& db, ScannerSettings& _settings) : _db{ db } , _settings{ _settings } { diff --git a/src/libs/services/scanner/impl/scanners/LyricsFileScanner.hpp b/src/libs/services/scanner/impl/scanners/LyricsFileScanner.hpp index 3bcb4f0d..0b265b77 100644 --- a/src/libs/services/scanner/impl/scanners/LyricsFileScanner.hpp +++ b/src/libs/services/scanner/impl/scanners/LyricsFileScanner.hpp @@ -21,13 +21,10 @@ #include "IFileScanner.hpp" -namespace lms +namespace lms::db { - namespace db - { - class Db; - } -} // namespace lms + class IDb; +} namespace lms::scanner { @@ -36,7 +33,7 @@ namespace lms::scanner class LyricsFileScanner : public IFileScanner { public: - LyricsFileScanner(db::Db& db, ScannerSettings& settings); + LyricsFileScanner(db::IDb& db, ScannerSettings& settings); ~LyricsFileScanner() override = default; LyricsFileScanner(const LyricsFileScanner&) = delete; LyricsFileScanner& operator=(const LyricsFileScanner&) = delete; @@ -48,7 +45,7 @@ namespace lms::scanner bool needsScan(const FileToScan& file) const override; std::unique_ptr createScanOperation(FileToScan&& fileToScan) const override; - db::Db& _db; + db::IDb& _db; ScannerSettings& _settings; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/scanners/PlayListFileScanner.cpp b/src/libs/services/scanner/impl/scanners/PlayListFileScanner.cpp index ca168dab..0be759d6 100644 --- a/src/libs/services/scanner/impl/scanners/PlayListFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/PlayListFileScanner.cpp @@ -23,7 +23,7 @@ #include #include "core/ILogger.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/MediaLibrary.hpp" #include "database/PlayListFile.hpp" #include "database/Session.hpp" @@ -121,7 +121,7 @@ namespace lms::scanner } } // namespace - PlayListFileScanner::PlayListFileScanner(db::Db& db, ScannerSettings& settings) + PlayListFileScanner::PlayListFileScanner(db::IDb& db, ScannerSettings& settings) : _db{ db } , _settings{ settings } { diff --git a/src/libs/services/scanner/impl/scanners/PlayListFileScanner.hpp b/src/libs/services/scanner/impl/scanners/PlayListFileScanner.hpp index db0f2333..0bbfb8a4 100644 --- a/src/libs/services/scanner/impl/scanners/PlayListFileScanner.hpp +++ b/src/libs/services/scanner/impl/scanners/PlayListFileScanner.hpp @@ -21,13 +21,10 @@ #include "IFileScanner.hpp" -namespace lms +namespace lms::db { - namespace db - { - class Db; - } -} // namespace lms + class IDb; +} namespace lms::scanner { @@ -36,7 +33,7 @@ namespace lms::scanner class PlayListFileScanner : public IFileScanner { public: - PlayListFileScanner(db::Db& db, ScannerSettings& settings); + PlayListFileScanner(db::IDb& db, ScannerSettings& settings); ~PlayListFileScanner() override = default; PlayListFileScanner(const PlayListFileScanner&) = delete; PlayListFileScanner& operator=(const PlayListFileScanner&) = delete; @@ -48,7 +45,7 @@ namespace lms::scanner bool needsScan(const FileToScan& file) const override; std::unique_ptr createScanOperation(FileToScan&& fileToScan) const override; - db::Db& _db; + db::IDb& _db; ScannerSettings& _settings; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp index c39bc2ba..4513ea96 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp @@ -25,7 +25,7 @@ #include "core/ILogger.hpp" #include "database/Artist.hpp" #include "database/ArtistInfo.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "database/TrackArtistLink.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index a25b83c0..9e3490d5 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -34,8 +34,8 @@ #include "database/ArtistInfo.hpp" #include "database/Artwork.hpp" #include "database/ArtworkId.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IDb.hpp" #include "database/Image.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -270,7 +270,7 @@ namespace lms::scanner class ComputeArtistArtworkAssociationsJob : public core::IJob { public: - ComputeArtistArtworkAssociationsJob(db::Db& db, const SearchArtistArtworkParams& searchParams, db::IdRange artistIdRange) + ComputeArtistArtworkAssociationsJob(db::IDb& db, const SearchArtistArtworkParams& searchParams, db::IdRange artistIdRange) : _db{ db } , _searchParams{ searchParams } , _artistIdRange{ artistIdRange } @@ -304,7 +304,7 @@ namespace lms::scanner }); } - db::Db& _db; + db::IDb& _db; const SearchArtistArtworkParams& _searchParams; db::IdRange _artistIdRange; std::vector _associations; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp index e54349a9..03dc6cbe 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp @@ -22,8 +22,8 @@ #include #include "core/ILogger.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "database/TrackLyrics.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp index 5d009edb..f8f740b6 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp @@ -25,8 +25,8 @@ #include "core/IJob.hpp" #include "core/ILogger.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IDb.hpp" #include "database/PlayListFile.hpp" #include "database/ReleaseId.hpp" #include "database/Session.hpp" @@ -174,7 +174,7 @@ namespace lms::scanner class ComputePlayListFileAssociationsJob : public core::IJob { public: - ComputePlayListFileAssociationsJob(db::Db& db, const ScannerSettings& settings, db::IdRange playListFileIdRange) + ComputePlayListFileAssociationsJob(db::IDb& db, const ScannerSettings& settings, db::IdRange playListFileIdRange) : _db{ db } , _settings{ settings } , _playListFileIdRange{ playListFileIdRange } @@ -239,7 +239,7 @@ namespace lms::scanner }); } - db::Db& _db; + db::IDb& _db; const ScannerSettings& _settings; db::IdRange _playListFileIdRange; std::vector _associations; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index 61a9aa0c..3e15d1ad 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -29,8 +29,8 @@ #include "core/ILogger.hpp" #include "core/Path.hpp" #include "database/Artwork.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IDb.hpp" #include "database/Image.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -213,7 +213,7 @@ namespace lms::scanner class ComputeReleaseArtworkAssociationsJob : public core::IJob { public: - ComputeReleaseArtworkAssociationsJob(db::Db& db, const SearchReleaseArtworkParams& searchParams, db::IdRange artistIdRange) + ComputeReleaseArtworkAssociationsJob(db::IDb& db, const SearchReleaseArtworkParams& searchParams, db::IdRange artistIdRange) : _db{ db } , _searchParams{ searchParams } , _artistIdRange{ artistIdRange } @@ -247,7 +247,7 @@ namespace lms::scanner }); } - db::Db& _db; + db::IDb& _db; const SearchReleaseArtworkParams& _searchParams; db::IdRange _artistIdRange; std::vector _associations; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp index 76d2dc30..dd361328 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp @@ -28,8 +28,8 @@ #include "core/ILogger.hpp" #include "core/LiteralString.hpp" #include "database/Artwork.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IDb.hpp" #include "database/IdRange.hpp" #include "database/Image.hpp" #include "database/Release.hpp" @@ -160,7 +160,7 @@ namespace lms::scanner class ComputeTrackArtworkAssociationsJob : public core::IJob { public: - ComputeTrackArtworkAssociationsJob(db::Db& db, db::IdRange trackIdRange) + ComputeTrackArtworkAssociationsJob(db::IDb& db, db::IdRange trackIdRange) : _db{ db } , _trackIdRange{ trackIdRange } { @@ -209,7 +209,7 @@ namespace lms::scanner }); } - db::Db& _db; + db::IDb& _db; db::IdRange _trackIdRange; std::vector _trackAssociations; std::size_t _processedTrackCount{}; diff --git a/src/libs/services/scanner/impl/steps/ScanStepBase.hpp b/src/libs/services/scanner/impl/steps/ScanStepBase.hpp index 2677726d..a544274a 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepBase.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepBase.hpp @@ -34,7 +34,7 @@ namespace lms::core namespace lms::db { - class Db; + class IDb; } namespace lms::scanner @@ -56,7 +56,7 @@ namespace lms::scanner const ScannerSettings* lastScanSettings{}; ProgressCallback progressCallback; bool& abortScan; - db::Db& db; + db::IDb& db; std::span fileScanners; }; ScanStepBase(InitParams& initParams); @@ -82,7 +82,7 @@ namespace lms::scanner const ScannerSettings& _settings; ProgressCallback _progressCallback; bool& _abortScan; - db::Db& _db; + db::IDb& _db; private: core::IJobScheduler& _jobScheduler; diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp index cea51cc6..b78918f9 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp @@ -20,7 +20,7 @@ #include "ScanStepCheckForDuplicatedFiles.hpp" #include "core/ILogger.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/Track.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index 3ab0c0c8..c91c8b2c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -24,7 +24,7 @@ #include "core/ILogger.hpp" #include "core/Path.hpp" #include "database/ArtistInfo.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Image.hpp" #include "database/PlayListFile.hpp" #include "database/Session.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepCompact.cpp b/src/libs/services/scanner/impl/steps/ScanStepCompact.cpp index 130d3408..e231bc7e 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCompact.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCompact.cpp @@ -19,7 +19,7 @@ #include "ScanStepCompact.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp index e2fd438a..60cb53b1 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp @@ -20,7 +20,7 @@ #include "ScanStepComputeClusterStats.hpp" #include "core/ILogger.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp b/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp index 576f79d9..98acc7ea 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp @@ -20,7 +20,7 @@ #include "ScanStepOptimize.hpp" #include "core/ILogger.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp index e665422a..dba7c06c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp @@ -22,8 +22,8 @@ #include "core/ILogger.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IDb.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index 5b1f91e7..e0183444 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -25,7 +25,7 @@ #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" #include "core/Path.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "scanners/FileToScan.hpp" #include "scanners/IFileScanOperation.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp b/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp index 1e9b52fd..14958504 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp @@ -19,8 +19,8 @@ #include "ScanStepUpdateLibraryFields.hpp" -#include "database/Db.hpp" #include "database/Directory.hpp" +#include "database/IDb.hpp" #include "database/MediaLibrary.hpp" #include "database/Session.hpp" diff --git a/src/libs/services/scanner/include/services/scanner/IScannerService.hpp b/src/libs/services/scanner/include/services/scanner/IScannerService.hpp index b811ce29..fa272396 100644 --- a/src/libs/services/scanner/include/services/scanner/IScannerService.hpp +++ b/src/libs/services/scanner/include/services/scanner/IScannerService.hpp @@ -27,7 +27,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::scanner @@ -61,5 +61,5 @@ namespace lms::scanner virtual Events& getEvents() = 0; }; - std::unique_ptr createScannerService(db::Db& db); + std::unique_ptr createScannerService(db::IDb& db); } // namespace lms::scanner diff --git a/src/libs/services/scrobbling/impl/ScrobblingService.cpp b/src/libs/services/scrobbling/impl/ScrobblingService.cpp index 7ace3afd..162cf523 100644 --- a/src/libs/services/scrobbling/impl/ScrobblingService.cpp +++ b/src/libs/services/scrobbling/impl/ScrobblingService.cpp @@ -21,7 +21,7 @@ #include "core/ILogger.hpp" #include "database/Artist.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Listen.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -55,12 +55,12 @@ namespace lms::scrobbling } } // namespace - std::unique_ptr createScrobblingService(boost::asio::io_context& ioContext, Db& db) + std::unique_ptr createScrobblingService(boost::asio::io_context& ioContext, db::IDb& db) { return std::make_unique(ioContext, db); } - ScrobblingService::ScrobblingService(boost::asio::io_context& ioContext, Db& db) + ScrobblingService::ScrobblingService(boost::asio::io_context& ioContext, db::IDb& db) : _db{ db } { LMS_LOG(SCROBBLING, INFO, "Starting service..."); diff --git a/src/libs/services/scrobbling/impl/ScrobblingService.hpp b/src/libs/services/scrobbling/impl/ScrobblingService.hpp index 1bde3e49..6fc26444 100644 --- a/src/libs/services/scrobbling/impl/ScrobblingService.hpp +++ b/src/libs/services/scrobbling/impl/ScrobblingService.hpp @@ -32,7 +32,7 @@ namespace lms::scrobbling class ScrobblingService : public IScrobblingService { public: - ScrobblingService(boost::asio::io_context& ioContext, db::Db& db); + ScrobblingService(boost::asio::io_context& ioContext, db::IDb& db); ~ScrobblingService(); private: @@ -56,7 +56,7 @@ namespace lms::scrobbling std::optional getUserBackend(db::UserId userId); - db::Db& _db; + db::IDb& _db; std::unordered_map> _scrobblingBackends; }; diff --git a/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp b/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp index b70ab4b7..70ae072d 100644 --- a/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp +++ b/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp @@ -19,7 +19,7 @@ #include "InternalBackend.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Listen.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -27,7 +27,7 @@ namespace lms::scrobbling { - InternalBackend::InternalBackend(db::Db& db) + InternalBackend::InternalBackend(db::IDb& db) : _db{ db } { } diff --git a/src/libs/services/scrobbling/impl/internal/InternalBackend.hpp b/src/libs/services/scrobbling/impl/internal/InternalBackend.hpp index a0fd45d7..6a952373 100644 --- a/src/libs/services/scrobbling/impl/internal/InternalBackend.hpp +++ b/src/libs/services/scrobbling/impl/internal/InternalBackend.hpp @@ -23,7 +23,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::scrobbling @@ -31,13 +31,13 @@ namespace lms::scrobbling class InternalBackend final : public IScrobblingBackend { public: - InternalBackend(db::Db& db); + InternalBackend(db::IDb& db); private: void listenStarted(const Listen& listen) override; void listenFinished(const Listen& listen, std::optional duration) override; void addTimedListen(const TimedListen& listen) override; - db::Db& _db; + db::IDb& _db; }; } // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp index 1d0ac7a5..19adf19e 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp @@ -23,7 +23,7 @@ #include "core/ILogger.hpp" #include "core/Service.hpp" #include "core/http/IClient.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -51,7 +51,7 @@ namespace lms::scrobbling::listenBrainz } } // namespace - ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, Db& db) + ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, db::IDb& db) : _ioContext{ ioContext } , _db{ db } , _baseAPIUrl{ core::Service::get()->getString("listenbrainz-api-base-url", "https://api.listenbrainz.org") } diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.hpp b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.hpp index 3ab08fd5..e04a5be4 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.hpp @@ -29,7 +29,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::scrobbling::listenBrainz @@ -37,7 +37,7 @@ namespace lms::scrobbling::listenBrainz class ListenBrainzBackend final : public IScrobblingBackend { public: - ListenBrainzBackend(boost::asio::io_context& ioContext, db::Db& db); + ListenBrainzBackend(boost::asio::io_context& ioContext, db::IDb& db); ~ListenBrainzBackend() override; private: @@ -52,7 +52,7 @@ namespace lms::scrobbling::listenBrainz void enqueListen(const Listen& listen, const Wt::WDateTime& timePoint); boost::asio::io_context& _ioContext; - db::Db& _db; + db::IDb& _db; std::string _baseAPIUrl; std::unique_ptr _client; ListensSynchronizer _listensSynchronizer; diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp index e08baab2..2e9a81e3 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp @@ -31,7 +31,7 @@ #include "core/Service.hpp" #include "core/http/IClient.hpp" #include "database/Artist.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Listen.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -210,7 +210,7 @@ namespace lms::scrobbling::listenBrainz } } // namespace - ListensSynchronizer::ListensSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client) + ListensSynchronizer::ListensSynchronizer(boost::asio::io_context& ioContext, db::IDb& db, core::http::IClient& client) : _ioContext{ ioContext } , _db{ db } , _client{ client } diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp index dd851e45..2751272f 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp @@ -39,7 +39,7 @@ namespace lms } namespace db { - class Db; + class IDb; } } // namespace lms @@ -48,7 +48,7 @@ namespace lms::scrobbling::listenBrainz class ListensSynchronizer { public: - ListensSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client); + ListensSynchronizer(boost::asio::io_context& ioContext, db::IDb& db, core::http::IClient& client); void enqueListen(const TimedListen& listen); void enqueListenNow(const Listen& listen); @@ -94,7 +94,7 @@ namespace lms::scrobbling::listenBrainz boost::asio::io_context& _ioContext; boost::asio::io_context::strand _strand{ _ioContext }; - db::Db& _db; + db::IDb& _db; boost::asio::steady_timer _syncTimer{ _ioContext }; core::http::IClient& _client; diff --git a/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp b/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp index 9eb60100..35f3e8bc 100644 --- a/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp +++ b/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp @@ -35,7 +35,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::scrobbling @@ -126,5 +126,5 @@ namespace lms::scrobbling virtual TrackContainer getTopTracks(const FindParameters& params) = 0; }; - std::unique_ptr createScrobblingService(boost::asio::io_context& ioContext, db::Db& db); + std::unique_ptr createScrobblingService(boost::asio::io_context& ioContext, db::IDb& db); } // namespace lms::scrobbling diff --git a/src/libs/services/transcoding/impl/TranscodingService.cpp b/src/libs/services/transcoding/impl/TranscodingService.cpp index 09270a19..56fa18dc 100644 --- a/src/libs/services/transcoding/impl/TranscodingService.cpp +++ b/src/libs/services/transcoding/impl/TranscodingService.cpp @@ -21,7 +21,7 @@ #include "av/ITranscoder.hpp" #include "core/ILogger.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -43,12 +43,12 @@ namespace lms::transcoding } } // namespace - std::unique_ptr createTranscodingService(db::Db& db, core::IChildProcessManager& childProcessManager) + std::unique_ptr createTranscodingService(db::IDb& db, core::IChildProcessManager& childProcessManager) { return std::make_unique(db, childProcessManager); } - TranscodingService::TranscodingService(db::Db& db, core::IChildProcessManager& childProcessManager) + TranscodingService::TranscodingService(db::IDb& db, core::IChildProcessManager& childProcessManager) : _db{ db } , _childProcessManager(childProcessManager) { diff --git a/src/libs/services/transcoding/impl/TranscodingService.hpp b/src/libs/services/transcoding/impl/TranscodingService.hpp index cfa45eaf..d5ea4471 100644 --- a/src/libs/services/transcoding/impl/TranscodingService.hpp +++ b/src/libs/services/transcoding/impl/TranscodingService.hpp @@ -26,7 +26,7 @@ namespace lms::transcoding class TranscodingService : public ITranscodingService { public: - explicit TranscodingService(db::Db& db, core::IChildProcessManager& childProcessManager); + explicit TranscodingService(db::IDb& db, core::IChildProcessManager& childProcessManager); ~TranscodingService() override; TranscodingService(const TranscodingService&) = delete; @@ -35,7 +35,7 @@ namespace lms::transcoding private: std::unique_ptr createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength) override; - db::Db& _db; + db::IDb& _db; core::IChildProcessManager& _childProcessManager; }; } // namespace lms::transcoding diff --git a/src/libs/services/transcoding/include/services/transcoding/ITranscodingService.hpp b/src/libs/services/transcoding/include/services/transcoding/ITranscodingService.hpp index c6fccd01..e1b478d3 100644 --- a/src/libs/services/transcoding/include/services/transcoding/ITranscodingService.hpp +++ b/src/libs/services/transcoding/include/services/transcoding/ITranscodingService.hpp @@ -35,7 +35,7 @@ namespace lms namespace db { - class Db; + class IDb; } } // namespace lms @@ -72,5 +72,5 @@ namespace lms::transcoding virtual std::unique_ptr createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength) = 0; }; - std::unique_ptr createTranscodingService(db::Db& db, core::IChildProcessManager& childProcessManager); + std::unique_ptr createTranscodingService(db::IDb& db, core::IChildProcessManager& childProcessManager); } // namespace lms::transcoding diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index 8d5e95fe..67718981 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -29,7 +29,7 @@ #include "core/LiteralString.hpp" #include "core/Service.hpp" #include "core/String.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "database/User.hpp" #include "services/auth/IAuthTokenService.hpp" @@ -52,7 +52,7 @@ namespace lms::api::subsonic { - std::unique_ptr createSubsonicResource(db::Db& db) + std::unique_ptr createSubsonicResource(db::IDb& db) { return std::make_unique(db); } @@ -295,7 +295,7 @@ namespace lms::api::subsonic } } // namespace - SubsonicResource::SubsonicResource(db::Db& db) + SubsonicResource::SubsonicResource(db::IDb& db) : _serverProtocolVersionsByClient{ readConfigProtocolVersions() } , _openSubsonicDisabledClients{ readOpenSubsonicDisabledClients() } , _supportUserPasswordAuthentication{ core::Service::get()->getBool("api-subsonic-support-user-password-auth", true) } diff --git a/src/libs/subsonic/impl/SubsonicResource.hpp b/src/libs/subsonic/impl/SubsonicResource.hpp index af8ace3d..4433d1ab 100644 --- a/src/libs/subsonic/impl/SubsonicResource.hpp +++ b/src/libs/subsonic/impl/SubsonicResource.hpp @@ -31,7 +31,7 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::api::subsonic @@ -39,7 +39,7 @@ namespace lms::api::subsonic class SubsonicResource final : public Wt::WResource { public: - SubsonicResource(db::Db& db); + SubsonicResource(db::IDb& db); private: void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response) override; @@ -53,6 +53,6 @@ namespace lms::api::subsonic const std::unordered_set _openSubsonicDisabledClients; const bool _supportUserPasswordAuthentication; - db::Db& _db; + db::IDb& _db; }; } // namespace lms::api::subsonic diff --git a/src/libs/subsonic/include/subsonic/SubsonicResource.hpp b/src/libs/subsonic/include/subsonic/SubsonicResource.hpp index 2c52bac4..d719c3c5 100644 --- a/src/libs/subsonic/include/subsonic/SubsonicResource.hpp +++ b/src/libs/subsonic/include/subsonic/SubsonicResource.hpp @@ -24,10 +24,10 @@ namespace lms::db { - class Db; + class IDb; } namespace lms::api::subsonic { - std::unique_ptr createSubsonicResource(db::Db& db); + std::unique_ptr createSubsonicResource(db::IDb& db); } // namespace lms::api::subsonic diff --git a/src/lms/main.cpp b/src/lms/main.cpp index 0a96921e..9110af3e 100644 --- a/src/lms/main.cpp +++ b/src/lms/main.cpp @@ -32,7 +32,7 @@ #include "core/String.hpp" #include "core/SystemPaths.hpp" #include "core/WtLogger.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Session.hpp" #include "image/Image.hpp" #include "services/artwork/IArtworkService.hpp" @@ -316,9 +316,9 @@ namespace lms core::IOContextRunner ioContextRunner{ ioContext, getThreadCount(), "Misc" }; // Connection pool size must be twice the number of threads: we have at least 2 io pools with getThreadCount() each and they all may access the database - db::Db database{ config->getPath("working-dir", "/var/lms") / "lms.db", getThreadCount() * 2 }; + auto database{ db::createDb(config->getPath("working-dir", "/var/lms") / "lms.db", getThreadCount() * 2) }; { - db::Session session{ database }; + db::Session session{ *database }; session.prepareTablesIfNeeded(); bool migrationPerformed{ session.migrateSchemaIfNeeded() }; session.createIndexesIfNeeded(); @@ -332,7 +332,7 @@ namespace lms // force optimize in case scanner aborted during a large import: // queries may be too slow to even be able to relaunch a scan using the web interface session.fullAnalyze(); - database.getTLSSession().refreshTracingLoggerStats(); + database->getTLSSession().refreshTracingLoggerStats(); } ui::LmsApplicationManager appManager; @@ -342,7 +342,7 @@ namespace lms core::Service childProcessManagerService{ core::createChildProcessManager(ioContext) }; const ui::AuthenticationBackend uiAuthenticationBackend{ getUIAuthenticationBackend() }; - core::Service authTokenService{ auth::createAuthTokenService(database, config->getULong("login-throttler-max-entriees", 10'000)) }; + core::Service authTokenService{ auth::createAuthTokenService(*database, config->getULong("login-throttler-max-entriees", 10'000)) }; core::Service authPasswordService; core::Service authEnvService; @@ -359,32 +359,32 @@ namespace lms switch (uiAuthenticationBackend) { case ui::AuthenticationBackend::Internal: - authPasswordService.assign(auth::createPasswordService("internal", database, loginThrottlerMaxEntries)); + authPasswordService.assign(auth::createPasswordService("internal", *database, loginThrottlerMaxEntries)); break; case ui::AuthenticationBackend::PAM: - authPasswordService.assign(auth::createPasswordService("PAM", database, loginThrottlerMaxEntries)); + authPasswordService.assign(auth::createPasswordService("PAM", *database, loginThrottlerMaxEntries)); break; case ui::AuthenticationBackend::Env: - authEnvService.assign(auth::createEnvService("http-headers", database)); + authEnvService.assign(auth::createEnvService("http-headers", *database)); break; } image::init(argv[0]); - core::Service artworkService{ artwork::createArtworkService(database, server.appRoot() + "/images/unknown-cover.svg", server.appRoot() + "/images/unknown-artist.svg") }; - core::Service recommendationService{ recommendation::createRecommendationService(database) }; - core::Service playlistGeneratorService{ recommendation::createPlaylistGeneratorService(database, *recommendationService.get()) }; - core::Service scannerService{ scanner::createScannerService(database) }; - core::Service transcodingService{ transcoding::createTranscodingService(database, *childProcessManagerService.get()) }; + core::Service artworkService{ artwork::createArtworkService(*database, server.appRoot() + "/images/unknown-cover.svg", server.appRoot() + "/images/unknown-artist.svg") }; + core::Service recommendationService{ recommendation::createRecommendationService(*database) }; + core::Service playlistGeneratorService{ recommendation::createPlaylistGeneratorService(*database, *recommendationService) }; + core::Service scannerService{ scanner::createScannerService(*database) }; + core::Service transcodingService{ transcoding::createTranscodingService(*database, *childProcessManagerService) }; scannerService->getEvents().scanComplete.connect([&] { // Flush cover cache even if no changes: // covers may be external files that changed and we don't keep track of them for now (but we should) artworkService->flushCache(); - database.getTLSSession().refreshTracingLoggerStats(); + database->getTLSSession().refreshTracingLoggerStats(); }); - core::Service feedbackService{ feedback::createFeedbackService(ioContext, database) }; - core::Service scrobblingService{ scrobbling::createScrobblingService(ioContext, database) }; + core::Service feedbackService{ feedback::createFeedbackService(ioContext, *database) }; + core::Service scrobblingService{ scrobbling::createScrobblingService(ioContext, *database) }; LMS_LOG(MAIN, INFO, "Stopping init web server..."); server.stop(); @@ -395,14 +395,14 @@ namespace lms // bind API resources if (config->getBool("api-subsonic", true)) { - subsonicResource = api::subsonic::createSubsonicResource(database); + subsonicResource = api::subsonic::createSubsonicResource(*database); server.addResource(subsonicResource.get(), "/rest"); } // bind UI entry point server.addEntryPoint(Wt::EntryPointType::Application, [&database, &appManager, uiAuthenticationBackend](const Wt::WEnvironment& env) { - return ui::LmsApplication::create(env, database, appManager, uiAuthenticationBackend); + return ui::LmsApplication::create(env, *database, appManager, uiAuthenticationBackend); }); proxyScannerEventsToApplication(*scannerService, server); diff --git a/src/lms/ui/LmsApplication.cpp b/src/lms/ui/LmsApplication.cpp index 01ecca92..437bed35 100644 --- a/src/lms/ui/LmsApplication.cpp +++ b/src/lms/ui/LmsApplication.cpp @@ -31,7 +31,7 @@ #include "core/Service.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/TrackList.hpp" @@ -183,7 +183,7 @@ namespace lms::ui } } // namespace - std::unique_ptr LmsApplication::create(const Wt::WEnvironment& env, db::Db& db, LmsApplicationManager& appManager, AuthenticationBackend authBackend) + std::unique_ptr LmsApplication::create(const Wt::WEnvironment& env, db::IDb& db, LmsApplicationManager& appManager, AuthenticationBackend authBackend) { return std::make_unique(env, db, appManager, authBackend); } @@ -193,7 +193,7 @@ namespace lms::ui return static_cast(Wt::WApplication::instance()); } - db::Db& LmsApplication::getDb() + db::IDb& LmsApplication::getDb() { return _db; } @@ -235,7 +235,7 @@ namespace lms::ui return _user->userLoginName; } - LmsApplication::LmsApplication(const Wt::WEnvironment& env, db::Db& db, LmsApplicationManager& appManager, AuthenticationBackend authBackend) + LmsApplication::LmsApplication(const Wt::WEnvironment& env, db::IDb& db, LmsApplicationManager& appManager, AuthenticationBackend authBackend) : Wt::WApplication{ env } , _db{ db } , _appManager{ appManager } diff --git a/src/lms/ui/LmsApplication.hpp b/src/lms/ui/LmsApplication.hpp index 8f943561..166716cf 100644 --- a/src/lms/ui/LmsApplication.hpp +++ b/src/lms/ui/LmsApplication.hpp @@ -35,7 +35,7 @@ namespace lms::db { - class Db; + class IDb; class Session; class User; } // namespace lms::db @@ -53,15 +53,15 @@ namespace lms::ui class LmsApplication : public Wt::WApplication { public: - LmsApplication(const Wt::WEnvironment& env, db::Db& db, LmsApplicationManager& appManager, AuthenticationBackend authBackend); + LmsApplication(const Wt::WEnvironment& env, db::IDb& db, LmsApplicationManager& appManager, AuthenticationBackend authBackend); ~LmsApplication(); - static std::unique_ptr create(const Wt::WEnvironment& env, db::Db& db, LmsApplicationManager& appManager, AuthenticationBackend authBackend); + static std::unique_ptr create(const Wt::WEnvironment& env, db::IDb& db, LmsApplicationManager& appManager, AuthenticationBackend authBackend); static LmsApplication* instance(); // Session application data std::shared_ptr getArtworkResource() { return _artworkResource; } - db::Db& getDb(); + db::IDb& getDb(); db::Session& getDbSession(); // always thread safe db::ObjectPtr getUser(); @@ -105,7 +105,7 @@ namespace lms::ui void setUserInfo(db::UserId userId, bool strongAuth); void createHome(); - db::Db& _db; + db::IDb& _db; Wt::Signal<> _preQuit; LmsApplicationManager& _appManager; const AuthenticationBackend _authBackend; diff --git a/src/tools/db-generator/LmsDbGenerator.cpp b/src/tools/db-generator/LmsDbGenerator.cpp index 29d56103..f9aaf881 100644 --- a/src/tools/db-generator/LmsDbGenerator.cpp +++ b/src/tools/db-generator/LmsDbGenerator.cpp @@ -34,7 +34,7 @@ #include "core/SystemPaths.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/MediaLibrary.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -226,8 +226,8 @@ int main(int argc, char* argv[]) throw std::runtime_error{ "File '" + genParams.trackPath.string() + "' does not exist!" }; core::Service config{ core::createConfig(vm["conf"].as()) }; - db::Db db{ config->getPath("working-dir", "/var/lms") / "lms.db" }; - db::Session session{ db }; + auto db{ db::createDb(config->getPath("working-dir", "/var/lms") / "lms.db") }; + db::Session session{ *db }; std::cout << "Starting generation..." << std::endl; GenerationContext genContext{ session }; diff --git a/src/tools/recommendation/LmsRecommendation.cpp b/src/tools/recommendation/LmsRecommendation.cpp index 42acf637..067b3062 100644 --- a/src/tools/recommendation/LmsRecommendation.cpp +++ b/src/tools/recommendation/LmsRecommendation.cpp @@ -29,7 +29,7 @@ #include "core/SystemPaths.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" @@ -145,11 +145,11 @@ int main(int argc, char* argv[]) core::Service config{ core::createConfig(vm["conf"].as()) }; - Db db{ config->getPath("working-dir", "/var/lms") / "lms.db" }; - Session session{ db }; + auto db{ db::createDb(config->getPath("working-dir", "/var/lms") / "lms.db") }; + Session session{ *db }; std::cout << "Creating recommendation service..." << std::endl; - const auto recommendationService{ recommendation::createRecommendationService(db) }; + const auto recommendationService{ recommendation::createRecommendationService(*db) }; std::cout << "Recommendation service created!" << std::endl; std::cout << "Loading recommendation service..." << std::endl; @@ -160,13 +160,13 @@ int main(int argc, char* argv[]) std::cout << "Recommendation service loaded!" << std::endl; if (vm.count("tracks")) - dumpTracksRecommendation(db, *recommendationService, maxSimilarityCount); + dumpTracksRecommendation(*db, *recommendationService, maxSimilarityCount); if (vm.count("releases")) - dumpReleasesRecommendation(db, *recommendationService, maxSimilarityCount); + dumpReleasesRecommendation(*db, *recommendationService, maxSimilarityCount); if (vm.count("artists")) - dumpArtistsRecommendation(db, *recommendationService, maxSimilarityCount); + dumpArtistsRecommendation(*db, *recommendationService, maxSimilarityCount); } catch (std::exception& e) { diff --git a/src/tools/similarity-parameters/LmsSimilarityParameters.cpp b/src/tools/similarity-parameters/LmsSimilarityParameters.cpp index 65fe041b..ea0e2fa7 100644 --- a/src/tools/similarity-parameters/LmsSimilarityParameters.cpp +++ b/src/tools/similarity-parameters/LmsSimilarityParameters.cpp @@ -26,7 +26,7 @@ #include "core/StreamLogger.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" -#include "database/Db.hpp" +#include "database/IDb.hpp" #include "database/Release.hpp" #include "database/SessionPool.hpp" #include "database/Track.hpp" From ef42bba0b08af22215e2e4af18cd5be97dc283ac Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 9 Jul 2025 07:54:54 +0200 Subject: [PATCH 24/46] Removed method from public interface --- src/libs/database/impl/Db.hpp | 3 ++- src/libs/database/impl/Migration.cpp | 6 +++--- src/libs/database/impl/Session.cpp | 2 +- src/libs/database/include/database/IDb.hpp | 2 -- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libs/database/impl/Db.hpp b/src/libs/database/impl/Db.hpp index 60002d26..98299b0e 100644 --- a/src/libs/database/impl/Db.hpp +++ b/src/libs/database/impl/Db.hpp @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include @@ -37,7 +38,7 @@ namespace lms::db Session& getTLSSession() override; - void executeSql(const std::string& sql) override; + void executeSql(const std::string& sql); private: Db(const Db&) = delete; diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index d6664c87..194d1500 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -67,7 +67,7 @@ namespace lms::db::Migration class ScopedNoForeignKeys { public: - ScopedNoForeignKeys(IDb& db) + ScopedNoForeignKeys(Db& db) : _db{ db } { _db.executeSql("PRAGMA foreign_keys=OFF"); @@ -83,7 +83,7 @@ namespace lms::db::Migration ScopedNoForeignKeys& operator=(const ScopedNoForeignKeys&) = delete; ScopedNoForeignKeys& operator=(ScopedNoForeignKeys&&) = delete; - IDb& _db; + Db& _db; }; namespace @@ -1422,7 +1422,7 @@ WHERE art.image_id IS NULL)"); { constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" }; - ScopedNoForeignKeys noPragmaKeys{ session.getDb() }; + ScopedNoForeignKeys noPragmaKeys{ static_cast(session.getDb()) }; using MigrationFunction = std::function; diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 3ebcebc7..4d7475be 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -360,7 +360,7 @@ namespace lms::db // We manually take a lock here since vacuum cannot be inside a transaction { std::unique_lock lock{ static_cast(_db).getMutex() }; - _db.executeSql("VACUUM"); + static_cast(_db).executeSql("VACUUM"); } LMS_LOG(DB, INFO, "Vacuum complete!"); diff --git a/src/libs/database/include/database/IDb.hpp b/src/libs/database/include/database/IDb.hpp index 1823275a..aa332f34 100644 --- a/src/libs/database/include/database/IDb.hpp +++ b/src/libs/database/include/database/IDb.hpp @@ -31,8 +31,6 @@ namespace lms::db virtual ~IDb() = default; virtual Session& getTLSSession() = 0; - - virtual void executeSql(const std::string& sql) = 0; // TODO make this private }; std::unique_ptr createDb(const std::filesystem::path& dbPath, std::size_t connectionCount = 10); From 43842a45830d2ff2e3aa205e73c4cc411027d23d Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 9 Jul 2025 19:02:57 +0200 Subject: [PATCH 25/46] Reduced includes --- src/libs/database/CMakeLists.txt | 2 + src/libs/database/impl/Object.cpp | 32 +++++++++ src/libs/database/impl/Session.cpp | 49 ++++---------- src/libs/database/impl/Transaction.cpp | 63 +++++++++++++++++ src/libs/database/impl/TransactionChecker.cpp | 24 +++---- .../database => impl}/TransactionChecker.hpp | 27 ++++---- .../include/database/MediaLibrary.hpp | 1 + src/libs/database/include/database/Object.hpp | 19 +++--- .../database/include/database/Session.hpp | 67 +++---------------- .../database/include/database/Transaction.hpp | 67 +++++++++++++++++++ 10 files changed, 224 insertions(+), 127 deletions(-) create mode 100644 src/libs/database/impl/Object.cpp create mode 100644 src/libs/database/impl/Transaction.cpp rename src/libs/database/{include/database => impl}/TransactionChecker.hpp (58%) create mode 100644 src/libs/database/include/database/Transaction.hpp diff --git a/src/libs/database/CMakeLists.txt b/src/libs/database/CMakeLists.txt index 29b07d8b..e282a328 100644 --- a/src/libs/database/CMakeLists.txt +++ b/src/libs/database/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(lmsdatabase STATIC impl/Listen.cpp impl/MediaLibrary.cpp impl/Migration.cpp + impl/Object.cpp impl/PlayListFile.cpp impl/PlayQueue.cpp impl/TrackArtistLink.cpp @@ -31,6 +32,7 @@ add_library(lmsdatabase STATIC impl/TrackEmbeddedImage.cpp impl/TrackEmbeddedImageLink.cpp impl/TrackLyrics.cpp + impl/Transaction.cpp impl/Types.cpp impl/UIState.cpp impl/User.cpp diff --git a/src/libs/database/impl/Object.cpp b/src/libs/database/impl/Object.cpp new file mode 100644 index 00000000..18e56f77 --- /dev/null +++ b/src/libs/database/impl/Object.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include "database/Object.hpp" + +#include "TransactionChecker.hpp" + +namespace lms::db +{ + void ObjectPtrBase::checkWriteTransaction(Wt::Dbo::Session& session) + { +#if LMS_CHECK_TRANSACTION_ACCESSES + TransactionChecker::checkWriteTransaction(session); +#endif + } +} // namespace lms::db diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 4d7475be..64f4e19f 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -48,12 +48,12 @@ #include "database/TrackFeatures.hpp" #include "database/TrackList.hpp" #include "database/TrackLyrics.hpp" -#include "database/TransactionChecker.hpp" #include "database/UIState.hpp" #include "database/User.hpp" #include "Db.hpp" #include "Migration.hpp" +#include "TransactionChecker.hpp" #include "Utils.hpp" #include "traits/EnumSetTraits.hpp" #include "traits/ImageHashTypeTraits.hpp" @@ -62,40 +62,6 @@ namespace lms::db { - WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session) - : _lock{ mutex } - , _transaction{ session } - { -#if LMS_CHECK_TRANSACTION_ACCESSES - TransactionChecker::pushWriteTransaction(_transaction.session()); -#endif - } - - WriteTransaction::~WriteTransaction() - { -#if LMS_CHECK_TRANSACTION_ACCESSES - TransactionChecker::popWriteTransaction(_transaction.session()); -#endif - - core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "Commit" }; - _transaction.commit(); - } - - ReadTransaction::ReadTransaction(Wt::Dbo::Session& session) - : _transaction{ session } - { -#if LMS_CHECK_TRANSACTION_ACCESSES - TransactionChecker::pushReadTransaction(_transaction.session()); -#endif - } - - ReadTransaction::~ReadTransaction() - { -#if LMS_CHECK_TRANSACTION_ACCESSES - TransactionChecker::popReadTransaction(_transaction.session()); -#endif - } - Session::Session(IDb& db) : _db{ db } { @@ -148,6 +114,19 @@ namespace lms::db return ReadTransaction{ _session }; } + void Session::checkWriteTransaction() const + { +#if LMS_CHECK_TRANSACTION_ACCESSES + TransactionChecker::checkWriteTransaction(_session); +#endif + } + void Session::checkReadTransaction() const + { +#if LMS_CHECK_TRANSACTION_ACCESSES + TransactionChecker::checkReadTransaction(_session); +#endif + } + void Session::execute(std::string_view statement) { utils::executeCommand(_session, std::string{ statement }); diff --git a/src/libs/database/impl/Transaction.cpp b/src/libs/database/impl/Transaction.cpp new file mode 100644 index 00000000..af6b5373 --- /dev/null +++ b/src/libs/database/impl/Transaction.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include "database/Transaction.hpp" + +#include "core/RecursiveSharedMutex.hpp" + +#include "TransactionChecker.hpp" + +namespace lms::db +{ + WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session) + : _lock{ mutex } + , _trace{ "Database", core::tracing::Level::Detailed, "WriteTransaction" } + , _transaction{ session } + { +#if LMS_CHECK_TRANSACTION_ACCESSES + TransactionChecker::pushWriteTransaction(_transaction.session()); +#endif + } + + WriteTransaction::~WriteTransaction() + { +#if LMS_CHECK_TRANSACTION_ACCESSES + TransactionChecker::popWriteTransaction(_transaction.session()); +#endif + + core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "Commit" }; + _transaction.commit(); + } + + ReadTransaction::ReadTransaction(Wt::Dbo::Session& session) + : _trace{ "Database", core::tracing::Level::Detailed, "ReadTransaction" } + , _transaction{ session } + { +#if LMS_CHECK_TRANSACTION_ACCESSES + TransactionChecker::pushReadTransaction(_transaction.session()); +#endif + } + + ReadTransaction::~ReadTransaction() + { +#if LMS_CHECK_TRANSACTION_ACCESSES + TransactionChecker::popReadTransaction(_transaction.session()); +#endif + } +} // namespace lms::db diff --git a/src/libs/database/impl/TransactionChecker.cpp b/src/libs/database/impl/TransactionChecker.cpp index 003e84bf..89d1f45c 100644 --- a/src/libs/database/impl/TransactionChecker.cpp +++ b/src/libs/database/impl/TransactionChecker.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/TransactionChecker.hpp" +#include "TransactionChecker.hpp" static_assert(LMS_CHECK_TRANSACTION_ACCESSES, "File should be excluded from build"); @@ -32,39 +32,39 @@ namespace lms::db struct StackEntry { TransactionChecker::TransactionType type; - Wt::Dbo::Session* session{}; + const Wt::Dbo::Session* session{}; }; static thread_local std::vector transactionStack; } // namespace - void TransactionChecker::pushWriteTransaction(Wt::Dbo::Session& session) + void TransactionChecker::pushWriteTransaction(const Wt::Dbo::Session& session) { pushTransaction(TransactionType::Write, session); } - void TransactionChecker::pushReadTransaction(Wt::Dbo::Session& session) + void TransactionChecker::pushReadTransaction(const Wt::Dbo::Session& session) { pushTransaction(TransactionType::Read, session); } - void TransactionChecker::popWriteTransaction(Wt::Dbo::Session& session) + void TransactionChecker::popWriteTransaction(const Wt::Dbo::Session& session) { popTransaction(TransactionType::Write, session); } - void TransactionChecker::popReadTransaction(Wt::Dbo::Session& session) + void TransactionChecker::popReadTransaction(const Wt::Dbo::Session& session) { popTransaction(TransactionType::Read, session); } - void TransactionChecker::pushTransaction(TransactionType type, Wt::Dbo::Session& session) + void TransactionChecker::pushTransaction(TransactionType type, const Wt::Dbo::Session& session) { assert(transactionStack.empty() || transactionStack.back().session == &session); transactionStack.push_back(StackEntry{ type, &session }); } - void TransactionChecker::popTransaction(TransactionType type, Wt::Dbo::Session& session) + void TransactionChecker::popTransaction(TransactionType type, const Wt::Dbo::Session& session) { assert(!transactionStack.empty()); assert(transactionStack.back().type == type); @@ -72,25 +72,25 @@ namespace lms::db transactionStack.pop_back(); } - void TransactionChecker::checkWriteTransaction(Wt::Dbo::Session& session) + void TransactionChecker::checkWriteTransaction(const Wt::Dbo::Session& session) { assert(!transactionStack.empty()); assert(transactionStack.back().type == TransactionType::Write); assert(transactionStack.back().session == &session); } - void TransactionChecker::checkWriteTransaction(Session& session) + void TransactionChecker::checkWriteTransaction(const Session& session) { checkWriteTransaction(*session.getDboSession()); } - void TransactionChecker::checkReadTransaction(Wt::Dbo::Session& session) + void TransactionChecker::checkReadTransaction(const Wt::Dbo::Session& session) { assert(!transactionStack.empty()); assert(transactionStack.back().session == &session); } - void TransactionChecker::checkReadTransaction(Session& session) + void TransactionChecker::checkReadTransaction(const Session& session) { checkReadTransaction(*session.getDboSession()); } diff --git a/src/libs/database/include/database/TransactionChecker.hpp b/src/libs/database/impl/TransactionChecker.hpp similarity index 58% rename from src/libs/database/include/database/TransactionChecker.hpp rename to src/libs/database/impl/TransactionChecker.hpp index fffeedb7..1076f33d 100644 --- a/src/libs/database/include/database/TransactionChecker.hpp +++ b/src/libs/database/impl/TransactionChecker.hpp @@ -26,8 +26,11 @@ #endif #if LMS_CHECK_TRANSACTION_ACCESSES - #include - #include + +namespace Wt::Dbo +{ + class Session; +} namespace lms::db { @@ -42,20 +45,20 @@ namespace lms::db Write, }; - static void pushWriteTransaction(Wt::Dbo::Session& session); - static void pushReadTransaction(Wt::Dbo::Session& session); + static void pushWriteTransaction(const Wt::Dbo::Session& session); + static void pushReadTransaction(const Wt::Dbo::Session& session); - static void popWriteTransaction(Wt::Dbo::Session& session); - static void popReadTransaction(Wt::Dbo::Session& session); + static void popWriteTransaction(const Wt::Dbo::Session& session); + static void popReadTransaction(const Wt::Dbo::Session& session); - static void checkWriteTransaction(Wt::Dbo::Session& session); - static void checkWriteTransaction(Session& session); - static void checkReadTransaction(Wt::Dbo::Session& session); - static void checkReadTransaction(Session& session); + static void checkWriteTransaction(const Wt::Dbo::Session& session); + static void checkWriteTransaction(const Session& session); + static void checkReadTransaction(const Wt::Dbo::Session& session); + static void checkReadTransaction(const Session& session); private: - static void pushTransaction(TransactionType type, Wt::Dbo::Session& session); - static void popTransaction(TransactionType type, Wt::Dbo::Session& session); + static void pushTransaction(TransactionType type, const Wt::Dbo::Session& session); + static void popTransaction(TransactionType type, const Wt::Dbo::Session& session); }; } // namespace lms::db diff --git a/src/libs/database/include/database/MediaLibrary.hpp b/src/libs/database/include/database/MediaLibrary.hpp index 0649674e..d26b0336 100644 --- a/src/libs/database/include/database/MediaLibrary.hpp +++ b/src/libs/database/include/database/MediaLibrary.hpp @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include diff --git a/src/libs/database/include/database/Object.hpp b/src/libs/database/include/database/Object.hpp index 6ea23173..90456b0b 100644 --- a/src/libs/database/include/database/Object.hpp +++ b/src/libs/database/include/database/Object.hpp @@ -20,15 +20,19 @@ #pragma once #include -#include #include "database/IdType.hpp" -#include "database/TransactionChecker.hpp" namespace lms::db { + class ObjectPtrBase + { + protected: + static void checkWriteTransaction(Wt::Dbo::Session& session); + }; + template - class ObjectPtr + class ObjectPtr : public ObjectPtrBase { public: ObjectPtr() = default; @@ -45,18 +49,13 @@ namespace lms::db auto modify() { -#if LMS_CHECK_TRANSACTION_ACCESSES - TransactionChecker::checkWriteTransaction(*_obj.session()); -#endif + checkWriteTransaction(*_obj.session()); return _obj.modify(); } void remove() { -#if LMS_CHECK_TRANSACTION_ACCESSES - TransactionChecker::checkWriteTransaction(*_obj.session()); -#endif - + checkWriteTransaction(*_obj.session()); _obj.remove(); } diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index 82586461..c07f43c5 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -19,52 +19,17 @@ #pragma once -#include -#include +#include #include #include +#include #include -#include "core/ITraceLogger.hpp" -#include "core/RecursiveSharedMutex.hpp" -#include "database/TransactionChecker.hpp" +#include "database/Transaction.hpp" namespace lms::db { - class WriteTransaction - { - public: - ~WriteTransaction(); - - private: - friend class Session; - WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session); - - WriteTransaction(const WriteTransaction&) = delete; - WriteTransaction& operator=(const WriteTransaction&) = delete; - - const std::unique_lock _lock; - const core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "WriteTransaction" }; // before actual transaction - Wt::Dbo::Transaction _transaction; - }; - - class ReadTransaction - { - public: - ~ReadTransaction(); - - private: - friend class Session; - ReadTransaction(Wt::Dbo::Session& session); - - ReadTransaction(const ReadTransaction&) = delete; - ReadTransaction& operator=(const ReadTransaction&) = delete; - - const core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "ReadTransaction" }; // before actual transaction - Wt::Dbo::Transaction _transaction; - }; - class IDb; class Session { @@ -77,18 +42,8 @@ namespace lms::db [[nodiscard]] WriteTransaction createWriteTransaction(); [[nodiscard]] ReadTransaction createReadTransaction(); - void checkWriteTransaction() - { -#if LMS_CHECK_TRANSACTION_ACCESSES - TransactionChecker::checkWriteTransaction(_session); -#endif - } - void checkReadTransaction() - { -#if LMS_CHECK_TRANSACTION_ACCESSES - TransactionChecker::checkReadTransaction(_session); -#endif - } + void checkWriteTransaction() const; + void checkReadTransaction() const; void execute(std::string_view statement); @@ -107,14 +62,10 @@ namespace lms::db void refreshTracingLoggerStats(); // returning a ptr here to ease further wrapping using operator-> - Wt::Dbo::Session* getDboSession() - { - return &_session; - } - IDb& getDb() - { - return _db; - } + Wt::Dbo::Session* getDboSession() { return &_session; } + const Wt::Dbo::Session* getDboSession() const { return &_session; } + + IDb& getDb() { return _db; } template typename Object::pointer create(Args&&... args) diff --git a/src/libs/database/include/database/Transaction.hpp b/src/libs/database/include/database/Transaction.hpp new file mode 100644 index 00000000..095e628d --- /dev/null +++ b/src/libs/database/include/database/Transaction.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2025 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 . + */ + +#pragma once + +#include + +#include + +#include "core/ITraceLogger.hpp" + +namespace lms::core +{ + class RecursiveSharedMutex; +} + +namespace lms::db +{ + class WriteTransaction + { + public: + ~WriteTransaction(); + + private: + friend class Session; + WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session); + + WriteTransaction(const WriteTransaction&) = delete; + WriteTransaction& operator=(const WriteTransaction&) = delete; + + const std::unique_lock _lock; + const core::tracing::ScopedTrace _trace; // before actual transaction + Wt::Dbo::Transaction _transaction; + }; + + class ReadTransaction + { + public: + ~ReadTransaction(); + + private: + friend class Session; + ReadTransaction(Wt::Dbo::Session& session); + + ReadTransaction(const ReadTransaction&) = delete; + ReadTransaction& operator=(const ReadTransaction&) = delete; + + const core::tracing::ScopedTrace _trace; // before actual transaction + Wt::Dbo::Transaction _transaction; + }; +} // namespace lms::db \ No newline at end of file From 2fd7d9767b5ed2473a7c33a1ec8f1c65aa819d09 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 9 Jul 2025 19:36:26 +0200 Subject: [PATCH 26/46] Placed db object related files in a subdirectory --- src/libs/database/CMakeLists.txt | 59 ++++++++++--------- src/libs/database/impl/Db.cpp | 2 +- src/libs/database/impl/Migration.cpp | 4 +- src/libs/database/impl/Session.cpp | 58 +++++++++--------- .../database/impl/{ => objects}/Artist.cpp | 14 ++--- .../impl/{ => objects}/ArtistInfo.cpp | 8 +-- .../database/impl/{ => objects}/Artwork.cpp | 7 +-- .../database/impl/{ => objects}/AuthToken.cpp | 4 +- .../database/impl/{ => objects}/Cluster.cpp | 16 ++--- .../database/impl/{ => objects}/Directory.cpp | 4 +- .../database/impl/{ => objects}/Image.cpp | 6 +- .../database/impl/{ => objects}/Listen.cpp | 6 +- .../impl/{ => objects}/MediaLibrary.cpp | 6 +- .../impl/{ => objects}/PlayListFile.cpp | 10 ++-- .../database/impl/{ => objects}/PlayQueue.cpp | 14 ++--- .../impl/{ => objects}/RatedArtist.cpp | 6 +- .../impl/{ => objects}/RatedRelease.cpp | 6 +- .../impl/{ => objects}/RatedTrack.cpp | 6 +- .../database/impl/{ => objects}/Release.cpp | 14 ++--- .../impl/{ => objects}/ScanSettings.cpp | 4 +- .../impl/{ => objects}/StarredArtist.cpp | 6 +- .../impl/{ => objects}/StarredRelease.cpp | 6 +- .../impl/{ => objects}/StarredTrack.cpp | 6 +- .../database/impl/{ => objects}/Track.cpp | 26 ++++---- .../impl/{ => objects}/TrackArtistLink.cpp | 6 +- .../impl/{ => objects}/TrackBookmark.cpp | 6 +- .../impl/{ => objects}/TrackEmbeddedImage.cpp | 6 +- .../{ => objects}/TrackEmbeddedImageLink.cpp | 6 +- .../impl/{ => objects}/TrackFeatures.cpp | 6 +- .../database/impl/{ => objects}/TrackList.cpp | 10 ++-- .../impl/{ => objects}/TrackLyrics.cpp | 10 ++-- .../database/impl/{ => objects}/UIState.cpp | 4 +- src/libs/database/impl/{ => objects}/User.cpp | 10 ++-- .../include/database/{ => objects}/Artist.hpp | 16 ++--- .../database/{ => objects}/ArtistId.hpp | 0 .../database/{ => objects}/ArtistInfo.hpp | 6 +- .../database/{ => objects}/ArtistInfoId.hpp | 0 .../database/{ => objects}/Artwork.hpp | 6 +- .../database/{ => objects}/ArtworkId.hpp | 0 .../database/{ => objects}/AuthToken.hpp | 4 +- .../database/{ => objects}/AuthTokenId.hpp | 0 .../database/{ => objects}/Cluster.hpp | 6 +- .../database/{ => objects}/ClusterId.hpp | 0 .../database/{ => objects}/CountryId.hpp | 0 .../database/{ => objects}/Directory.hpp | 8 +-- .../database/{ => objects}/DirectoryId.hpp | 0 .../database/{ => objects}/Filters.hpp | 8 +-- .../include/database/{ => objects}/Image.hpp | 4 +- .../database/{ => objects}/ImageId.hpp | 0 .../database/{ => objects}/LabelId.hpp | 0 .../include/database/{ => objects}/Listen.hpp | 12 ++-- .../database/{ => objects}/ListenId.hpp | 0 .../database/{ => objects}/MediaLibrary.hpp | 2 +- .../database/{ => objects}/MediaLibraryId.hpp | 0 .../database/{ => objects}/PlayListFile.hpp | 2 +- .../database/{ => objects}/PlayQueue.hpp | 4 +- .../database/{ => objects}/RatedArtist.hpp | 6 +- .../database/{ => objects}/RatedArtistId.hpp | 0 .../database/{ => objects}/RatedRelease.hpp | 6 +- .../database/{ => objects}/RatedReleaseId.hpp | 0 .../database/{ => objects}/RatedTrack.hpp | 6 +- .../database/{ => objects}/RatedTrackId.hpp | 0 .../database/{ => objects}/Release.hpp | 20 +++---- .../database/{ => objects}/ReleaseId.hpp | 0 .../database/{ => objects}/ReleaseTypeId.hpp | 0 .../database/{ => objects}/ScanSettings.hpp | 0 .../database/{ => objects}/StarredArtist.hpp | 6 +- .../{ => objects}/StarredArtistId.hpp | 0 .../database/{ => objects}/StarredRelease.hpp | 6 +- .../{ => objects}/StarredReleaseId.hpp | 0 .../database/{ => objects}/StarredTrack.hpp | 6 +- .../database/{ => objects}/StarredTrackId.hpp | 0 .../include/database/{ => objects}/Track.hpp | 22 +++---- .../{ => objects}/TrackArtistLink.hpp | 6 +- .../database/{ => objects}/TrackBookmark.hpp | 4 +- .../{ => objects}/TrackEmbeddedImage.hpp | 10 ++-- .../{ => objects}/TrackEmbeddedImageId.hpp | 0 .../{ => objects}/TrackEmbeddedImageLink.hpp | 4 +- .../TrackEmbeddedImageLinkId.hpp | 0 .../database/{ => objects}/TrackFeatures.hpp | 2 +- .../database/{ => objects}/TrackId.hpp | 0 .../database/{ => objects}/TrackList.hpp | 8 +-- .../database/{ => objects}/TrackListId.hpp | 0 .../database/{ => objects}/TrackLyrics.hpp | 2 +- .../database/{ => objects}/UIState.hpp | 4 +- .../database/{ => objects}/UIStateId.hpp | 0 .../include/database/{ => objects}/User.hpp | 2 +- .../include/database/{ => objects}/UserId.hpp | 0 src/libs/database/test/Artist.cpp | 4 +- src/libs/database/test/ArtistInfo.cpp | 6 +- src/libs/database/test/Artwork.cpp | 8 +-- src/libs/database/test/AuthToken.cpp | 2 +- src/libs/database/test/Common.cpp | 2 +- src/libs/database/test/Common.hpp | 24 ++++---- src/libs/database/test/Directory.cpp | 2 +- src/libs/database/test/Image.cpp | 4 +- src/libs/database/test/Listen.cpp | 2 +- src/libs/database/test/Migration.cpp | 40 ++++++------- src/libs/database/test/PlayListFile.cpp | 4 +- src/libs/database/test/RatedArtist.cpp | 2 +- src/libs/database/test/RatedRelease.cpp | 2 +- src/libs/database/test/RatedTrack.cpp | 2 +- src/libs/database/test/Release.cpp | 4 +- src/libs/database/test/ScanSettings.cpp | 2 +- src/libs/database/test/StarredArtist.cpp | 2 +- src/libs/database/test/StarredRelease.cpp | 2 +- src/libs/database/test/StarredTrack.cpp | 2 +- src/libs/database/test/Track.cpp | 4 +- src/libs/database/test/TrackArtistLink.cpp | 2 +- src/libs/database/test/TrackBookmark.cpp | 2 +- src/libs/database/test/TrackEmbeddedImage.cpp | 6 +- src/libs/database/test/TrackFeatures.cpp | 2 +- src/libs/database/test/TrackLyrics.cpp | 4 +- .../services/artwork/impl/ArtworkService.cpp | 18 +++--- .../services/artwork/impl/ArtworkService.hpp | 4 +- src/libs/services/artwork/impl/ImageCache.hpp | 2 +- .../services/artwork/IArtworkService.hpp | 4 +- .../services/auth/impl/AuthServiceBase.cpp | 2 +- .../services/auth/impl/AuthServiceBase.hpp | 2 +- .../services/auth/impl/AuthTokenService.cpp | 4 +- .../impl/internal/InternalPasswordService.cpp | 2 +- .../impl/internal/InternalPasswordService.hpp | 2 +- .../services/auth/IAuthTokenService.hpp | 2 +- .../include/services/auth/IEnvService.hpp | 2 +- .../services/auth/IPasswordService.hpp | 2 +- .../feedback/impl/FeedbackService.cpp | 20 +++---- .../feedback/impl/FeedbackService.impl.hpp | 2 +- .../feedback/impl/IFeedbackBackend.hpp | 6 +- .../impl/internal/InternalBackend.cpp | 6 +- .../listenbrainz/FeedbacksSynchronizer.cpp | 6 +- .../listenbrainz/FeedbacksSynchronizer.hpp | 4 +- .../impl/listenbrainz/ListenBrainzBackend.cpp | 6 +- .../feedback/impl/listenbrainz/Utils.cpp | 2 +- .../feedback/impl/listenbrainz/Utils.hpp | 2 +- .../services/feedback/IFeedbackService.hpp | 10 ++-- .../services/recommendation/impl/IEngine.hpp | 2 +- .../impl/PlaylistGeneratorService.cpp | 2 +- .../impl/RecommendationService.cpp | 2 +- .../impl/clusters/ClustersEngine.cpp | 10 ++-- .../impl/features/FeaturesEngine.cpp | 12 ++-- .../impl/features/FeaturesEngineCache.hpp | 2 +- .../ConsecutiveArtists.cpp | 4 +- .../ConsecutiveReleases.cpp | 4 +- .../ConsecutiveReleases.hpp | 2 +- .../IPlaylistGeneratorService.hpp | 2 +- .../recommendation/IRecommendationService.hpp | 6 +- .../include/services/recommendation/Types.hpp | 6 +- .../scanner/impl/MediaLibraryInfo.hpp | 2 +- .../services/scanner/impl/ScannerService.cpp | 4 +- .../services/scanner/impl/ScannerSettings.hpp | 2 +- .../scanner/impl/helpers/ArtistHelpers.hpp | 2 +- .../impl/scanners/ArtistInfoFileScanner.cpp | 6 +- .../impl/scanners/AudioFileScanOperation.cpp | 24 ++++---- .../impl/scanners/AudioFileScanner.cpp | 4 +- .../impl/scanners/ImageFileScanner.cpp | 7 ++- .../impl/scanners/LyricsFileScanner.cpp | 4 +- .../impl/scanners/PlayListFileScanner.cpp | 4 +- .../services/scanner/impl/scanners/Utils.cpp | 4 +- .../steps/ScanStepArtistReconciliation.cpp | 10 ++-- .../steps/ScanStepAssociateArtistImages.cpp | 16 ++--- .../steps/ScanStepAssociateExternalLyrics.cpp | 6 +- .../steps/ScanStepAssociatePlayListTracks.cpp | 10 ++-- .../steps/ScanStepAssociateReleaseImages.cpp | 12 ++-- .../steps/ScanStepAssociateTrackImages.cpp | 12 ++-- .../steps/ScanStepCheckForDuplicatedFiles.cpp | 2 +- .../steps/ScanStepCheckForRemovedFiles.cpp | 10 ++-- .../steps/ScanStepComputeClusterStats.cpp | 2 +- .../steps/ScanStepRemoveOrphanedDbEntries.cpp | 12 ++-- .../steps/ScanStepUpdateLibraryFields.cpp | 4 +- .../include/services/scanner/ScannerStats.hpp | 2 +- .../scrobbling/impl/ScrobblingService.cpp | 10 ++-- .../impl/internal/InternalBackend.cpp | 6 +- .../impl/listenbrainz/ListenBrainzBackend.cpp | 2 +- .../impl/listenbrainz/ListensSynchronizer.cpp | 10 ++-- .../impl/listenbrainz/ListensSynchronizer.hpp | 2 +- .../scrobbling/impl/listenbrainz/Utils.cpp | 2 +- .../scrobbling/impl/listenbrainz/Utils.hpp | 2 +- .../scrobbling/IScrobblingService.hpp | 8 +-- .../include/services/scrobbling/Listen.hpp | 4 +- .../transcoding/impl/TranscodingService.cpp | 2 +- .../transcoding/ITranscodingService.hpp | 2 +- src/libs/subsonic/impl/CoverArtId.cpp | 2 +- src/libs/subsonic/impl/CoverArtId.hpp | 2 +- src/libs/subsonic/impl/SubsonicId.hpp | 12 ++-- src/libs/subsonic/impl/SubsonicResource.cpp | 2 +- src/libs/subsonic/impl/SubsonicResource.hpp | 2 +- .../impl/endpoints/AlbumSongLists.cpp | 10 ++-- .../subsonic/impl/endpoints/Bookmarks.cpp | 8 +-- src/libs/subsonic/impl/endpoints/Browsing.cpp | 16 ++--- .../impl/endpoints/MediaAnnotation.cpp | 10 ++-- .../impl/endpoints/MediaRetrieval.cpp | 8 +-- .../subsonic/impl/endpoints/Playlists.cpp | 6 +- .../subsonic/impl/endpoints/Searching.cpp | 10 ++-- .../impl/endpoints/UserManagement.cpp | 2 +- src/libs/subsonic/impl/responses/Album.cpp | 14 ++--- .../subsonic/impl/responses/AlbumInfo.cpp | 2 +- src/libs/subsonic/impl/responses/Artist.cpp | 10 ++-- src/libs/subsonic/impl/responses/Bookmark.cpp | 4 +- .../subsonic/impl/responses/Contributor.cpp | 2 +- src/libs/subsonic/impl/responses/Genre.cpp | 2 +- src/libs/subsonic/impl/responses/ItemDate.cpp | 2 +- .../subsonic/impl/responses/ItemGenre.cpp | 2 +- src/libs/subsonic/impl/responses/Lyrics.cpp | 2 +- src/libs/subsonic/impl/responses/Playlist.cpp | 6 +- .../subsonic/impl/responses/RecordLabel.cpp | 2 +- .../subsonic/impl/responses/ReplayGain.cpp | 2 +- src/libs/subsonic/impl/responses/Song.cpp | 18 +++--- src/libs/subsonic/impl/responses/User.cpp | 4 +- src/lms/ui/Auth.cpp | 2 +- src/lms/ui/Auth.hpp | 2 +- src/lms/ui/LmsApplication.cpp | 10 ++-- src/lms/ui/LmsApplication.hpp | 2 +- src/lms/ui/LmsApplicationManager.hpp | 2 +- src/lms/ui/MediaPlayer.cpp | 10 ++-- src/lms/ui/MediaPlayer.hpp | 2 +- src/lms/ui/PlayQueue.cpp | 10 ++-- src/lms/ui/PlayQueue.hpp | 4 +- src/lms/ui/SettingsView.cpp | 2 +- src/lms/ui/State.cpp | 4 +- src/lms/ui/Utils.cpp | 14 ++--- src/lms/ui/Utils.hpp | 8 +-- src/lms/ui/admin/InitWizardView.cpp | 2 +- src/lms/ui/admin/MediaLibrariesView.cpp | 2 +- src/lms/ui/admin/MediaLibrariesView.hpp | 2 +- src/lms/ui/admin/MediaLibraryModal.cpp | 2 +- src/lms/ui/admin/MediaLibraryModal.hpp | 2 +- src/lms/ui/admin/ScanSettingsView.cpp | 2 +- src/lms/ui/admin/ScannerReportResource.cpp | 2 +- src/lms/ui/admin/UserView.cpp | 2 +- src/lms/ui/admin/UsersView.cpp | 2 +- src/lms/ui/common/LoginNameValidator.cpp | 2 +- src/lms/ui/explore/ArtistCollector.cpp | 6 +- src/lms/ui/explore/ArtistCollector.hpp | 2 +- src/lms/ui/explore/ArtistListHelpers.cpp | 2 +- src/lms/ui/explore/ArtistView.cpp | 16 ++--- src/lms/ui/explore/ArtistView.hpp | 6 +- src/lms/ui/explore/ArtistsView.cpp | 4 +- src/lms/ui/explore/Filters.cpp | 10 ++-- src/lms/ui/explore/Filters.hpp | 2 +- src/lms/ui/explore/PlayQueueController.cpp | 4 +- src/lms/ui/explore/PlayQueueController.hpp | 8 +-- src/lms/ui/explore/ReleaseCollector.cpp | 4 +- src/lms/ui/explore/ReleaseCollector.hpp | 2 +- src/lms/ui/explore/ReleaseHelpers.cpp | 4 +- src/lms/ui/explore/ReleaseView.cpp | 14 ++--- src/lms/ui/explore/ReleaseView.hpp | 4 +- src/lms/ui/explore/ReleasesView.cpp | 2 +- src/lms/ui/explore/TrackCollector.cpp | 6 +- src/lms/ui/explore/TrackCollector.hpp | 2 +- src/lms/ui/explore/TrackListHelpers.cpp | 12 ++-- src/lms/ui/explore/TrackListHelpers.hpp | 4 +- src/lms/ui/explore/TrackListView.cpp | 8 +-- src/lms/ui/explore/TrackListView.hpp | 2 +- src/lms/ui/explore/TrackListsView.cpp | 2 +- src/lms/ui/explore/TrackListsView.hpp | 2 +- src/lms/ui/explore/TracksView.cpp | 2 +- src/lms/ui/resource/ArtworkResource.hpp | 2 +- src/lms/ui/resource/AudioFileResource.cpp | 2 +- src/lms/ui/resource/AudioFileResource.hpp | 2 +- .../ui/resource/AudioTranscodingResource.cpp | 4 +- .../ui/resource/AudioTranscodingResource.hpp | 2 +- src/lms/ui/resource/DownloadResource.cpp | 8 +-- src/lms/ui/resource/DownloadResource.hpp | 8 +-- src/tools/db-generator/LmsDbGenerator.cpp | 16 ++--- .../recommendation/LmsRecommendation.cpp | 8 +-- .../LmsSimilarityParameters.cpp | 10 ++-- 266 files changed, 759 insertions(+), 758 deletions(-) rename src/libs/database/impl/{ => objects}/Artist.cpp (98%) rename src/libs/database/impl/{ => objects}/ArtistInfo.cpp (97%) rename src/libs/database/impl/{ => objects}/Artwork.cpp (97%) rename src/libs/database/impl/{ => objects}/AuthToken.cpp (97%) rename src/libs/database/impl/{ => objects}/Cluster.cpp (96%) rename src/libs/database/impl/{ => objects}/Directory.cpp (99%) rename src/libs/database/impl/{ => objects}/Image.cpp (97%) rename src/libs/database/impl/{ => objects}/Listen.cpp (99%) rename src/libs/database/impl/{ => objects}/MediaLibrary.cpp (96%) rename src/libs/database/impl/{ => objects}/PlayListFile.cpp (96%) rename src/libs/database/impl/{ => objects}/PlayQueue.cpp (90%) rename src/libs/database/impl/{ => objects}/RatedArtist.cpp (95%) rename src/libs/database/impl/{ => objects}/RatedRelease.cpp (95%) rename src/libs/database/impl/{ => objects}/RatedTrack.cpp (95%) rename src/libs/database/impl/{ => objects}/Release.cpp (99%) rename src/libs/database/impl/{ => objects}/ScanSettings.cpp (98%) rename src/libs/database/impl/{ => objects}/StarredArtist.cpp (95%) rename src/libs/database/impl/{ => objects}/StarredRelease.cpp (95%) rename src/libs/database/impl/{ => objects}/StarredTrack.cpp (96%) rename src/libs/database/impl/{ => objects}/Track.cpp (97%) rename src/libs/database/impl/{ => objects}/TrackArtistLink.cpp (98%) rename src/libs/database/impl/{ => objects}/TrackBookmark.cpp (95%) rename src/libs/database/impl/{ => objects}/TrackEmbeddedImage.cpp (98%) rename src/libs/database/impl/{ => objects}/TrackEmbeddedImageLink.cpp (94%) rename src/libs/database/impl/{ => objects}/TrackFeatures.cpp (96%) rename src/libs/database/impl/{ => objects}/TrackList.cpp (98%) rename src/libs/database/impl/{ => objects}/TrackLyrics.cpp (97%) rename src/libs/database/impl/{ => objects}/UIState.cpp (96%) rename src/libs/database/impl/{ => objects}/User.cpp (94%) rename src/libs/database/include/database/{ => objects}/Artist.hpp (95%) rename src/libs/database/include/database/{ => objects}/ArtistId.hpp (100%) rename src/libs/database/include/database/{ => objects}/ArtistInfo.hpp (97%) rename src/libs/database/include/database/{ => objects}/ArtistInfoId.hpp (100%) rename src/libs/database/include/database/{ => objects}/Artwork.hpp (94%) rename src/libs/database/include/database/{ => objects}/ArtworkId.hpp (100%) rename src/libs/database/include/database/{ => objects}/AuthToken.hpp (97%) rename src/libs/database/include/database/{ => objects}/AuthTokenId.hpp (100%) rename src/libs/database/include/database/{ => objects}/Cluster.hpp (98%) rename src/libs/database/include/database/{ => objects}/ClusterId.hpp (100%) rename src/libs/database/include/database/{ => objects}/CountryId.hpp (100%) rename src/libs/database/include/database/{ => objects}/Directory.hpp (97%) rename src/libs/database/include/database/{ => objects}/DirectoryId.hpp (100%) rename src/libs/database/include/database/{ => objects}/Filters.hpp (90%) rename src/libs/database/include/database/{ => objects}/Image.hpp (98%) rename src/libs/database/include/database/{ => objects}/ImageId.hpp (100%) rename src/libs/database/include/database/{ => objects}/LabelId.hpp (100%) rename src/libs/database/include/database/{ => objects}/Listen.hpp (96%) rename src/libs/database/include/database/{ => objects}/ListenId.hpp (100%) rename src/libs/database/include/database/{ => objects}/MediaLibrary.hpp (98%) rename src/libs/database/include/database/{ => objects}/MediaLibraryId.hpp (100%) rename src/libs/database/include/database/{ => objects}/PlayListFile.hpp (99%) rename src/libs/database/include/database/{ => objects}/PlayQueue.hpp (97%) rename src/libs/database/include/database/{ => objects}/RatedArtist.hpp (95%) rename src/libs/database/include/database/{ => objects}/RatedArtistId.hpp (100%) rename src/libs/database/include/database/{ => objects}/RatedRelease.hpp (95%) rename src/libs/database/include/database/{ => objects}/RatedReleaseId.hpp (100%) rename src/libs/database/include/database/{ => objects}/RatedTrack.hpp (95%) rename src/libs/database/include/database/{ => objects}/RatedTrackId.hpp (100%) rename src/libs/database/include/database/{ => objects}/Release.hpp (97%) rename src/libs/database/include/database/{ => objects}/ReleaseId.hpp (100%) rename src/libs/database/include/database/{ => objects}/ReleaseTypeId.hpp (100%) rename src/libs/database/include/database/{ => objects}/ScanSettings.hpp (100%) rename src/libs/database/include/database/{ => objects}/StarredArtist.hpp (95%) rename src/libs/database/include/database/{ => objects}/StarredArtistId.hpp (100%) rename src/libs/database/include/database/{ => objects}/StarredRelease.hpp (95%) rename src/libs/database/include/database/{ => objects}/StarredReleaseId.hpp (100%) rename src/libs/database/include/database/{ => objects}/StarredTrack.hpp (96%) rename src/libs/database/include/database/{ => objects}/StarredTrackId.hpp (100%) rename src/libs/database/include/database/{ => objects}/Track.hpp (97%) rename src/libs/database/include/database/{ => objects}/TrackArtistLink.hpp (97%) rename src/libs/database/include/database/{ => objects}/TrackBookmark.hpp (97%) rename src/libs/database/include/database/{ => objects}/TrackEmbeddedImage.hpp (95%) rename src/libs/database/include/database/{ => objects}/TrackEmbeddedImageId.hpp (100%) rename src/libs/database/include/database/{ => objects}/TrackEmbeddedImageLink.hpp (96%) rename src/libs/database/include/database/{ => objects}/TrackEmbeddedImageLinkId.hpp (100%) rename src/libs/database/include/database/{ => objects}/TrackFeatures.hpp (98%) rename src/libs/database/include/database/{ => objects}/TrackId.hpp (100%) rename src/libs/database/include/database/{ => objects}/TrackList.hpp (98%) rename src/libs/database/include/database/{ => objects}/TrackListId.hpp (100%) rename src/libs/database/include/database/{ => objects}/TrackLyrics.hpp (99%) rename src/libs/database/include/database/{ => objects}/UIState.hpp (95%) rename src/libs/database/include/database/{ => objects}/UIStateId.hpp (100%) rename src/libs/database/include/database/{ => objects}/User.hpp (99%) rename src/libs/database/include/database/{ => objects}/UserId.hpp (100%) diff --git a/src/libs/database/CMakeLists.txt b/src/libs/database/CMakeLists.txt index e282a328..8efc57ca 100644 --- a/src/libs/database/CMakeLists.txt +++ b/src/libs/database/CMakeLists.txt @@ -1,41 +1,41 @@ add_library(lmsdatabase STATIC - impl/Artist.cpp - impl/ArtistInfo.cpp - impl/Artwork.cpp - impl/AuthToken.cpp - impl/Cluster.cpp + impl/objects/Artist.cpp + impl/objects/ArtistInfo.cpp + impl/objects/Artwork.cpp + impl/objects/AuthToken.cpp + impl/objects/Cluster.cpp + impl/objects/Directory.cpp + impl/objects/Image.cpp + impl/objects/Listen.cpp + impl/objects/MediaLibrary.cpp + impl/objects/PlayListFile.cpp + impl/objects/PlayQueue.cpp + impl/objects/TrackArtistLink.cpp + impl/objects/TrackFeatures.cpp + impl/objects/TrackList.cpp + impl/objects/RatedArtist.cpp + impl/objects/RatedRelease.cpp + impl/objects/RatedTrack.cpp + impl/objects/Release.cpp + impl/objects/ScanSettings.cpp + impl/objects/StarredArtist.cpp + impl/objects/StarredRelease.cpp + impl/objects/StarredTrack.cpp + impl/objects/Track.cpp + impl/objects/TrackBookmark.cpp + impl/objects/TrackEmbeddedImage.cpp + impl/objects/TrackEmbeddedImageLink.cpp + impl/objects/TrackLyrics.cpp + impl/objects/UIState.cpp + impl/objects/User.cpp impl/Db.cpp - impl/Directory.cpp impl/IdType.cpp - impl/Image.cpp - impl/Listen.cpp - impl/MediaLibrary.cpp impl/Migration.cpp impl/Object.cpp - impl/PlayListFile.cpp - impl/PlayQueue.cpp - impl/TrackArtistLink.cpp - impl/TrackFeatures.cpp - impl/TrackList.cpp - impl/RatedArtist.cpp - impl/RatedRelease.cpp - impl/RatedTrack.cpp - impl/Release.cpp - impl/ScanSettings.cpp impl/Session.cpp - impl/StarredArtist.cpp - impl/StarredRelease.cpp - impl/StarredTrack.cpp impl/SqlQuery.cpp - impl/Track.cpp - impl/TrackBookmark.cpp - impl/TrackEmbeddedImage.cpp - impl/TrackEmbeddedImageLink.cpp - impl/TrackLyrics.cpp impl/Transaction.cpp impl/Types.cpp - impl/UIState.cpp - impl/User.cpp impl/Utils.cpp ) @@ -48,6 +48,7 @@ target_include_directories(lmsdatabase INTERFACE ) target_include_directories(lmsdatabase PRIVATE + impl include ) diff --git a/src/libs/database/impl/Db.cpp b/src/libs/database/impl/Db.cpp index 91787a7e..df00596e 100644 --- a/src/libs/database/impl/Db.cpp +++ b/src/libs/database/impl/Db.cpp @@ -27,7 +27,7 @@ #include "core/ILogger.hpp" #include "core/Service.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "Db.hpp" diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index 194d1500..62922926 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -24,9 +24,9 @@ #include "core/Exception.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/User.hpp" #include "Db.hpp" #include "Utils.hpp" diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 64f4e19f..d480c8da 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -21,35 +21,35 @@ #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" -#include "database/Artist.hpp" -#include "database/ArtistInfo.hpp" -#include "database/Artwork.hpp" -#include "database/AuthToken.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" -#include "database/Image.hpp" -#include "database/Listen.hpp" -#include "database/MediaLibrary.hpp" -#include "database/PlayListFile.hpp" -#include "database/PlayQueue.hpp" -#include "database/RatedArtist.hpp" -#include "database/RatedRelease.hpp" -#include "database/RatedTrack.hpp" -#include "database/Release.hpp" -#include "database/ScanSettings.hpp" -#include "database/StarredArtist.hpp" -#include "database/StarredRelease.hpp" -#include "database/StarredTrack.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackBookmark.hpp" -#include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageLink.hpp" -#include "database/TrackFeatures.hpp" -#include "database/TrackList.hpp" -#include "database/TrackLyrics.hpp" -#include "database/UIState.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/AuthToken.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/Listen.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/PlayListFile.hpp" +#include "database/objects/PlayQueue.hpp" +#include "database/objects/RatedArtist.hpp" +#include "database/objects/RatedRelease.hpp" +#include "database/objects/RatedTrack.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/StarredArtist.hpp" +#include "database/objects/StarredRelease.hpp" +#include "database/objects/StarredTrack.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackBookmark.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackFeatures.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/TrackLyrics.hpp" +#include "database/objects/UIState.hpp" +#include "database/objects/User.hpp" #include "Db.hpp" #include "Migration.hpp" diff --git a/src/libs/database/impl/Artist.cpp b/src/libs/database/impl/objects/Artist.cpp similarity index 98% rename from src/libs/database/impl/Artist.cpp rename to src/libs/database/impl/objects/Artist.cpp index 04e44676..0ecda221 100644 --- a/src/libs/database/impl/Artist.cpp +++ b/src/libs/database/impl/objects/Artist.cpp @@ -16,18 +16,18 @@ * You should have received a copy of the GNU General Public License * along with LMS. If not, see . */ -#include "database/Artist.hpp" +#include "database/objects/Artist.hpp" #include #include "core/ILogger.hpp" -#include "database/Artwork.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "SqlQuery.hpp" #include "Utils.hpp" diff --git a/src/libs/database/impl/ArtistInfo.cpp b/src/libs/database/impl/objects/ArtistInfo.cpp similarity index 97% rename from src/libs/database/impl/ArtistInfo.cpp rename to src/libs/database/impl/objects/ArtistInfo.cpp index a534d307..2edd646f 100644 --- a/src/libs/database/impl/ArtistInfo.cpp +++ b/src/libs/database/impl/objects/ArtistInfo.cpp @@ -17,14 +17,14 @@ * along with LMS. If not, see . */ -#include "database/ArtistInfo.hpp" +#include "database/objects/ArtistInfo.hpp" #include -#include "database/Artist.hpp" -#include "database/ArtistInfoId.hpp" -#include "database/Directory.hpp" #include "database/Session.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfoId.hpp" +#include "database/objects/Directory.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/Artwork.cpp b/src/libs/database/impl/objects/Artwork.cpp similarity index 97% rename from src/libs/database/impl/Artwork.cpp rename to src/libs/database/impl/objects/Artwork.cpp index 4dd62d4d..444b8070 100644 --- a/src/libs/database/impl/Artwork.cpp +++ b/src/libs/database/impl/objects/Artwork.cpp @@ -17,13 +17,12 @@ * along with LMS. If not, see . */ -#include "database/Artwork.hpp" - +#include "database/objects/Artwork.hpp" #include -#include "database/Image.hpp" #include "database/Session.hpp" -#include "database/TrackEmbeddedImage.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/AuthToken.cpp b/src/libs/database/impl/objects/AuthToken.cpp similarity index 97% rename from src/libs/database/impl/AuthToken.cpp rename to src/libs/database/impl/objects/AuthToken.cpp index 8622975f..63ad027d 100644 --- a/src/libs/database/impl/AuthToken.cpp +++ b/src/libs/database/impl/objects/AuthToken.cpp @@ -17,12 +17,12 @@ * along with LMS. If not, see . */ -#include "database/AuthToken.hpp" +#include "database/objects/AuthToken.hpp" #include #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/Cluster.cpp b/src/libs/database/impl/objects/Cluster.cpp similarity index 96% rename from src/libs/database/impl/Cluster.cpp rename to src/libs/database/impl/objects/Cluster.cpp index 589b2f15..7816cb68 100644 --- a/src/libs/database/impl/Cluster.cpp +++ b/src/libs/database/impl/objects/Cluster.cpp @@ -17,16 +17,16 @@ * along with LMS. If not, see . */ -#include "database/Cluster.hpp" +#include "database/objects/Cluster.hpp" -#include "database/Artist.hpp" -#include "database/Artwork.hpp" -#include "database/Directory.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/Track.hpp" #include "SqlQuery.hpp" #include "Utils.hpp" diff --git a/src/libs/database/impl/Directory.cpp b/src/libs/database/impl/objects/Directory.cpp similarity index 99% rename from src/libs/database/impl/Directory.cpp rename to src/libs/database/impl/objects/Directory.cpp index da595498..9d180fd9 100644 --- a/src/libs/database/impl/Directory.cpp +++ b/src/libs/database/impl/objects/Directory.cpp @@ -17,11 +17,11 @@ * along with LMS. If not, see . */ -#include "database/Directory.hpp" +#include "database/objects/Directory.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" #include "database/Types.hpp" +#include "database/objects/MediaLibrary.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/Image.cpp b/src/libs/database/impl/objects/Image.cpp similarity index 97% rename from src/libs/database/impl/Image.cpp rename to src/libs/database/impl/objects/Image.cpp index 4b5bbd5a..2010547d 100644 --- a/src/libs/database/impl/Image.cpp +++ b/src/libs/database/impl/objects/Image.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include "database/Image.hpp" +#include "database/objects/Image.hpp" #include -#include "database/Artist.hpp" -#include "database/Directory.hpp" #include "database/Session.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Directory.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/Listen.cpp b/src/libs/database/impl/objects/Listen.cpp similarity index 99% rename from src/libs/database/impl/Listen.cpp rename to src/libs/database/impl/objects/Listen.cpp index 73e58490..ffd4294b 100644 --- a/src/libs/database/impl/Listen.cpp +++ b/src/libs/database/impl/objects/Listen.cpp @@ -17,10 +17,10 @@ * along with LMS. If not, see . */ -#include "database/Listen.hpp" +#include "database/objects/Listen.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "SqlQuery.hpp" #include "Utils.hpp" diff --git a/src/libs/database/impl/MediaLibrary.cpp b/src/libs/database/impl/objects/MediaLibrary.cpp similarity index 96% rename from src/libs/database/impl/MediaLibrary.cpp rename to src/libs/database/impl/objects/MediaLibrary.cpp index cbbadaae..1b6ea7cb 100644 --- a/src/libs/database/impl/MediaLibrary.cpp +++ b/src/libs/database/impl/objects/MediaLibrary.cpp @@ -17,11 +17,11 @@ * along with LMS. If not, see . */ -#include "database/MediaLibrary.hpp" +#include "database/objects/MediaLibrary.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/Track.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/PlayListFile.cpp b/src/libs/database/impl/objects/PlayListFile.cpp similarity index 96% rename from src/libs/database/impl/PlayListFile.cpp rename to src/libs/database/impl/objects/PlayListFile.cpp index 1f408f4c..61f388f3 100644 --- a/src/libs/database/impl/PlayListFile.cpp +++ b/src/libs/database/impl/objects/PlayListFile.cpp @@ -17,16 +17,16 @@ * along with LMS. If not, see . */ -#include "database/PlayListFile.hpp" +#include "database/objects/PlayListFile.hpp" #include #include "core/ILogger.hpp" -#include "database/Directory.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" -#include "database/TrackList.hpp" -#include "database/User.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/PlayQueue.cpp b/src/libs/database/impl/objects/PlayQueue.cpp similarity index 90% rename from src/libs/database/impl/PlayQueue.cpp rename to src/libs/database/impl/objects/PlayQueue.cpp index d5941f20..22fa1fd0 100644 --- a/src/libs/database/impl/PlayQueue.cpp +++ b/src/libs/database/impl/objects/PlayQueue.cpp @@ -17,17 +17,17 @@ * along with LMS. If not, see . */ -#include "database/PlayQueue.hpp" +#include "database/objects/PlayQueue.hpp" #include -#include "database/Artwork.hpp" -#include "database/Directory.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/RatedArtist.cpp b/src/libs/database/impl/objects/RatedArtist.cpp similarity index 95% rename from src/libs/database/impl/RatedArtist.cpp rename to src/libs/database/impl/objects/RatedArtist.cpp index 3e480f1f..7952b530 100644 --- a/src/libs/database/impl/RatedArtist.cpp +++ b/src/libs/database/impl/objects/RatedArtist.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include "database/RatedArtist.hpp" +#include "database/objects/RatedArtist.hpp" #include -#include "database/Artist.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/RatedRelease.cpp b/src/libs/database/impl/objects/RatedRelease.cpp similarity index 95% rename from src/libs/database/impl/RatedRelease.cpp rename to src/libs/database/impl/objects/RatedRelease.cpp index b7de0d78..f5562327 100644 --- a/src/libs/database/impl/RatedRelease.cpp +++ b/src/libs/database/impl/objects/RatedRelease.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include "database/RatedRelease.hpp" +#include "database/objects/RatedRelease.hpp" #include -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/RatedTrack.cpp b/src/libs/database/impl/objects/RatedTrack.cpp similarity index 95% rename from src/libs/database/impl/RatedTrack.cpp rename to src/libs/database/impl/objects/RatedTrack.cpp index 0c0ec110..146b1d88 100644 --- a/src/libs/database/impl/RatedTrack.cpp +++ b/src/libs/database/impl/objects/RatedTrack.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include "database/RatedTrack.hpp" +#include "database/objects/RatedTrack.hpp" #include #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/Release.cpp b/src/libs/database/impl/objects/Release.cpp similarity index 99% rename from src/libs/database/impl/Release.cpp rename to src/libs/database/impl/objects/Release.cpp index 9b740d21..bb5d82b8 100644 --- a/src/libs/database/impl/Release.cpp +++ b/src/libs/database/impl/objects/Release.cpp @@ -17,19 +17,19 @@ * along with LMS. If not, see . */ -#include "database/Release.hpp" +#include "database/objects/Release.hpp" #include #include "core/PartialDateTime.hpp" -#include "database/Artist.hpp" -#include "database/Artwork.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "SqlQuery.hpp" #include "Utils.hpp" diff --git a/src/libs/database/impl/ScanSettings.cpp b/src/libs/database/impl/objects/ScanSettings.cpp similarity index 98% rename from src/libs/database/impl/ScanSettings.cpp rename to src/libs/database/impl/objects/ScanSettings.cpp index f38ee204..961661b8 100644 --- a/src/libs/database/impl/ScanSettings.cpp +++ b/src/libs/database/impl/objects/ScanSettings.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include "database/ScanSettings.hpp" +#include "database/objects/ScanSettings.hpp" #include #include "core/String.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" +#include "database/objects/MediaLibrary.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/StarredArtist.cpp b/src/libs/database/impl/objects/StarredArtist.cpp similarity index 95% rename from src/libs/database/impl/StarredArtist.cpp rename to src/libs/database/impl/objects/StarredArtist.cpp index e19071c1..ec68c229 100644 --- a/src/libs/database/impl/StarredArtist.cpp +++ b/src/libs/database/impl/objects/StarredArtist.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include "database/StarredArtist.hpp" +#include "database/objects/StarredArtist.hpp" #include -#include "database/Artist.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/StarredRelease.cpp b/src/libs/database/impl/objects/StarredRelease.cpp similarity index 95% rename from src/libs/database/impl/StarredRelease.cpp rename to src/libs/database/impl/objects/StarredRelease.cpp index 1b5fded8..8ace864e 100644 --- a/src/libs/database/impl/StarredRelease.cpp +++ b/src/libs/database/impl/objects/StarredRelease.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include "database/StarredRelease.hpp" +#include "database/objects/StarredRelease.hpp" #include -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/StarredTrack.cpp b/src/libs/database/impl/objects/StarredTrack.cpp similarity index 96% rename from src/libs/database/impl/StarredTrack.cpp rename to src/libs/database/impl/objects/StarredTrack.cpp index 842b276d..4fc4829e 100644 --- a/src/libs/database/impl/StarredTrack.cpp +++ b/src/libs/database/impl/objects/StarredTrack.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include "database/StarredTrack.hpp" +#include "database/objects/StarredTrack.hpp" #include #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/objects/Track.cpp similarity index 97% rename from src/libs/database/impl/Track.cpp rename to src/libs/database/impl/objects/Track.cpp index 394689fe..7dd20df1 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/objects/Track.cpp @@ -17,24 +17,24 @@ * along with LMS. If not, see . */ -#include "database/Track.hpp" +#include "database/objects/Track.hpp" #include #include "core/ILogger.hpp" -#include "database/Artist.hpp" -#include "database/Artwork.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageLink.hpp" -#include "database/TrackFeatures.hpp" -#include "database/TrackLyrics.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackFeatures.hpp" +#include "database/objects/TrackLyrics.hpp" +#include "database/objects/User.hpp" #include "SqlQuery.hpp" #include "Utils.hpp" diff --git a/src/libs/database/impl/TrackArtistLink.cpp b/src/libs/database/impl/objects/TrackArtistLink.cpp similarity index 98% rename from src/libs/database/impl/TrackArtistLink.cpp rename to src/libs/database/impl/objects/TrackArtistLink.cpp index ea92ef36..e2d15cac 100644 --- a/src/libs/database/impl/TrackArtistLink.cpp +++ b/src/libs/database/impl/objects/TrackArtistLink.cpp @@ -17,11 +17,11 @@ * along with LMS. If not, see . */ -#include "database/TrackArtistLink.hpp" +#include "database/objects/TrackArtistLink.hpp" -#include "database/Artist.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Track.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/TrackBookmark.cpp b/src/libs/database/impl/objects/TrackBookmark.cpp similarity index 95% rename from src/libs/database/impl/TrackBookmark.cpp rename to src/libs/database/impl/objects/TrackBookmark.cpp index f0d0bc22..f24b3755 100644 --- a/src/libs/database/impl/TrackBookmark.cpp +++ b/src/libs/database/impl/objects/TrackBookmark.cpp @@ -17,11 +17,11 @@ * along with LMS. If not, see . */ -#include "database/TrackBookmark.hpp" +#include "database/objects/TrackBookmark.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/TrackEmbeddedImage.cpp b/src/libs/database/impl/objects/TrackEmbeddedImage.cpp similarity index 98% rename from src/libs/database/impl/TrackEmbeddedImage.cpp rename to src/libs/database/impl/objects/TrackEmbeddedImage.cpp index 55509420..c3d2bb05 100644 --- a/src/libs/database/impl/TrackEmbeddedImage.cpp +++ b/src/libs/database/impl/objects/TrackEmbeddedImage.cpp @@ -17,12 +17,12 @@ * along with LMS. If not, see . */ -#include "database/Directory.hpp" +#include "database/objects/Directory.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackEmbeddedImage.hpp" #include "database/Types.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/TrackEmbeddedImageLink.cpp b/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp similarity index 94% rename from src/libs/database/impl/TrackEmbeddedImageLink.cpp rename to src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp index 300d2ed3..9b074777 100644 --- a/src/libs/database/impl/TrackEmbeddedImageLink.cpp +++ b/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp @@ -17,12 +17,12 @@ * along with LMS. If not, see . */ -#include "database/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackEmbeddedImage.hpp" #include "database/Types.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/TrackFeatures.cpp b/src/libs/database/impl/objects/TrackFeatures.cpp similarity index 96% rename from src/libs/database/impl/TrackFeatures.cpp rename to src/libs/database/impl/objects/TrackFeatures.cpp index cfb088ea..c2557560 100644 --- a/src/libs/database/impl/TrackFeatures.cpp +++ b/src/libs/database/impl/objects/TrackFeatures.cpp @@ -17,15 +17,15 @@ * along with LMS. If not, see . */ -#include "database/TrackFeatures.hpp" +#include "database/objects/TrackFeatures.hpp" #include #include #include "core/ILogger.hpp" -#include "database/Directory.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Track.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/TrackList.cpp b/src/libs/database/impl/objects/TrackList.cpp similarity index 98% rename from src/libs/database/impl/TrackList.cpp rename to src/libs/database/impl/objects/TrackList.cpp index 1b32030f..0ef495dc 100644 --- a/src/libs/database/impl/TrackList.cpp +++ b/src/libs/database/impl/objects/TrackList.cpp @@ -16,15 +16,15 @@ * You should have received a copy of the GNU General Public License * along with LMS. If not, see . */ -#include "database/TrackList.hpp" +#include "database/objects/TrackList.hpp" #include -#include "database/Cluster.hpp" -#include "database/PlayListFile.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/PlayListFile.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "SqlQuery.hpp" #include "Utils.hpp" diff --git a/src/libs/database/impl/TrackLyrics.cpp b/src/libs/database/impl/objects/TrackLyrics.cpp similarity index 97% rename from src/libs/database/impl/TrackLyrics.cpp rename to src/libs/database/impl/objects/TrackLyrics.cpp index 2f71e8fd..3285e676 100644 --- a/src/libs/database/impl/TrackLyrics.cpp +++ b/src/libs/database/impl/objects/TrackLyrics.cpp @@ -17,16 +17,16 @@ * along with LMS. If not, see . */ -#include "database/TrackLyrics.hpp" +#include "database/objects/TrackLyrics.hpp" #include #include -#include "database/Artist.hpp" -#include "database/Directory.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/UIState.cpp b/src/libs/database/impl/objects/UIState.cpp similarity index 96% rename from src/libs/database/impl/UIState.cpp rename to src/libs/database/impl/objects/UIState.cpp index 22a11d75..4d495534 100644 --- a/src/libs/database/impl/UIState.cpp +++ b/src/libs/database/impl/objects/UIState.cpp @@ -17,10 +17,10 @@ * along with LMS. If not, see . */ -#include "database/UIState.hpp" +#include "database/objects/UIState.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" diff --git a/src/libs/database/impl/User.cpp b/src/libs/database/impl/objects/User.cpp similarity index 94% rename from src/libs/database/impl/User.cpp rename to src/libs/database/impl/objects/User.cpp index fcbb6e71..bd1932ec 100644 --- a/src/libs/database/impl/User.cpp +++ b/src/libs/database/impl/objects/User.cpp @@ -17,15 +17,15 @@ * along with LMS. If not, see . */ -#include "database/User.hpp" +#include "database/objects/User.hpp" #include -#include "database/Artist.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/UIState.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/UIState.hpp" #include "Utils.hpp" #include "traits/EnumSetTraits.hpp" diff --git a/src/libs/database/include/database/Artist.hpp b/src/libs/database/include/database/objects/Artist.hpp similarity index 95% rename from src/libs/database/include/database/Artist.hpp rename to src/libs/database/include/database/objects/Artist.hpp index 051b7025..762e6f4a 100644 --- a/src/libs/database/include/database/Artist.hpp +++ b/src/libs/database/include/database/objects/Artist.hpp @@ -30,17 +30,17 @@ #include "core/EnumSet.hpp" #include "core/UUID.hpp" -#include "database/ArtistId.hpp" -#include "database/ArtworkId.hpp" -#include "database/ClusterId.hpp" -#include "database/Filters.hpp" #include "database/IdRange.hpp" -#include "database/MediaLibraryId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/ClusterId.hpp" +#include "database/objects/Filters.hpp" +#include "database/objects/MediaLibraryId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/ArtistId.hpp b/src/libs/database/include/database/objects/ArtistId.hpp similarity index 100% rename from src/libs/database/include/database/ArtistId.hpp rename to src/libs/database/include/database/objects/ArtistId.hpp diff --git a/src/libs/database/include/database/ArtistInfo.hpp b/src/libs/database/include/database/objects/ArtistInfo.hpp similarity index 97% rename from src/libs/database/include/database/ArtistInfo.hpp rename to src/libs/database/include/database/objects/ArtistInfo.hpp index 7f6b95a6..bf371220 100644 --- a/src/libs/database/include/database/ArtistInfo.hpp +++ b/src/libs/database/include/database/objects/ArtistInfo.hpp @@ -27,11 +27,11 @@ #include #include -#include "database/ArtistId.hpp" -#include "database/ArtistInfoId.hpp" -#include "database/DirectoryId.hpp" #include "database/Object.hpp" #include "database/Types.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ArtistInfoId.hpp" +#include "database/objects/DirectoryId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/ArtistInfoId.hpp b/src/libs/database/include/database/objects/ArtistInfoId.hpp similarity index 100% rename from src/libs/database/include/database/ArtistInfoId.hpp rename to src/libs/database/include/database/objects/ArtistInfoId.hpp diff --git a/src/libs/database/include/database/Artwork.hpp b/src/libs/database/include/database/objects/Artwork.hpp similarity index 94% rename from src/libs/database/include/database/Artwork.hpp rename to src/libs/database/include/database/objects/Artwork.hpp index 4873e45b..44e08075 100644 --- a/src/libs/database/include/database/Artwork.hpp +++ b/src/libs/database/include/database/objects/Artwork.hpp @@ -24,10 +24,10 @@ #include #include -#include "database/ArtworkId.hpp" -#include "database/ImageId.hpp" #include "database/Object.hpp" -#include "database/TrackEmbeddedImageId.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/ImageId.hpp" +#include "database/objects/TrackEmbeddedImageId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/ArtworkId.hpp b/src/libs/database/include/database/objects/ArtworkId.hpp similarity index 100% rename from src/libs/database/include/database/ArtworkId.hpp rename to src/libs/database/include/database/objects/ArtworkId.hpp diff --git a/src/libs/database/include/database/AuthToken.hpp b/src/libs/database/include/database/objects/AuthToken.hpp similarity index 97% rename from src/libs/database/include/database/AuthToken.hpp rename to src/libs/database/include/database/objects/AuthToken.hpp index 720716aa..08a067ec 100644 --- a/src/libs/database/include/database/AuthToken.hpp +++ b/src/libs/database/include/database/objects/AuthToken.hpp @@ -25,10 +25,10 @@ #include #include -#include "database/AuthTokenId.hpp" #include "database/Object.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/AuthTokenId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/AuthTokenId.hpp b/src/libs/database/include/database/objects/AuthTokenId.hpp similarity index 100% rename from src/libs/database/include/database/AuthTokenId.hpp rename to src/libs/database/include/database/objects/AuthTokenId.hpp diff --git a/src/libs/database/include/database/Cluster.hpp b/src/libs/database/include/database/objects/Cluster.hpp similarity index 98% rename from src/libs/database/include/database/Cluster.hpp rename to src/libs/database/include/database/objects/Cluster.hpp index 471e1c8e..7c7c37cd 100644 --- a/src/libs/database/include/database/Cluster.hpp +++ b/src/libs/database/include/database/objects/Cluster.hpp @@ -28,11 +28,11 @@ #include #include -#include "database/ClusterId.hpp" #include "database/Object.hpp" -#include "database/Release.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" +#include "database/objects/ClusterId.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/TrackId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/ClusterId.hpp b/src/libs/database/include/database/objects/ClusterId.hpp similarity index 100% rename from src/libs/database/include/database/ClusterId.hpp rename to src/libs/database/include/database/objects/ClusterId.hpp diff --git a/src/libs/database/include/database/CountryId.hpp b/src/libs/database/include/database/objects/CountryId.hpp similarity index 100% rename from src/libs/database/include/database/CountryId.hpp rename to src/libs/database/include/database/objects/CountryId.hpp diff --git a/src/libs/database/include/database/Directory.hpp b/src/libs/database/include/database/objects/Directory.hpp similarity index 97% rename from src/libs/database/include/database/Directory.hpp rename to src/libs/database/include/database/objects/Directory.hpp index 45f17743..7a1eda7b 100644 --- a/src/libs/database/include/database/Directory.hpp +++ b/src/libs/database/include/database/objects/Directory.hpp @@ -28,12 +28,12 @@ #include #include "core/EnumSet.hpp" -#include "database/ArtistId.hpp" -#include "database/DirectoryId.hpp" -#include "database/MediaLibraryId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" #include "database/Types.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/DirectoryId.hpp" +#include "database/objects/MediaLibraryId.hpp" +#include "database/objects/ReleaseId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/DirectoryId.hpp b/src/libs/database/include/database/objects/DirectoryId.hpp similarity index 100% rename from src/libs/database/include/database/DirectoryId.hpp rename to src/libs/database/include/database/objects/DirectoryId.hpp diff --git a/src/libs/database/include/database/Filters.hpp b/src/libs/database/include/database/objects/Filters.hpp similarity index 90% rename from src/libs/database/include/database/Filters.hpp rename to src/libs/database/include/database/objects/Filters.hpp index d287021c..1d95a09f 100644 --- a/src/libs/database/include/database/Filters.hpp +++ b/src/libs/database/include/database/objects/Filters.hpp @@ -22,10 +22,10 @@ #include #include -#include "database/ClusterId.hpp" -#include "database/LabelId.hpp" -#include "database/MediaLibraryId.hpp" -#include "database/ReleaseTypeId.hpp" +#include "database/objects/ClusterId.hpp" +#include "database/objects/LabelId.hpp" +#include "database/objects/MediaLibraryId.hpp" +#include "database/objects/ReleaseTypeId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/Image.hpp b/src/libs/database/include/database/objects/Image.hpp similarity index 98% rename from src/libs/database/include/database/Image.hpp rename to src/libs/database/include/database/objects/Image.hpp index a8eeb195..79985fee 100644 --- a/src/libs/database/include/database/Image.hpp +++ b/src/libs/database/include/database/objects/Image.hpp @@ -25,10 +25,10 @@ #include #include -#include "database/DirectoryId.hpp" -#include "database/ImageId.hpp" #include "database/Object.hpp" #include "database/Types.hpp" +#include "database/objects/DirectoryId.hpp" +#include "database/objects/ImageId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/ImageId.hpp b/src/libs/database/include/database/objects/ImageId.hpp similarity index 100% rename from src/libs/database/include/database/ImageId.hpp rename to src/libs/database/include/database/objects/ImageId.hpp diff --git a/src/libs/database/include/database/LabelId.hpp b/src/libs/database/include/database/objects/LabelId.hpp similarity index 100% rename from src/libs/database/include/database/LabelId.hpp rename to src/libs/database/include/database/objects/LabelId.hpp diff --git a/src/libs/database/include/database/Listen.hpp b/src/libs/database/include/database/objects/Listen.hpp similarity index 96% rename from src/libs/database/include/database/Listen.hpp rename to src/libs/database/include/database/objects/Listen.hpp index dcbb32c7..a028da5e 100644 --- a/src/libs/database/include/database/Listen.hpp +++ b/src/libs/database/include/database/objects/Listen.hpp @@ -24,14 +24,14 @@ #include #include -#include "database/ArtistId.hpp" -#include "database/Filters.hpp" -#include "database/ListenId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/Filters.hpp" +#include "database/objects/ListenId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/ListenId.hpp b/src/libs/database/include/database/objects/ListenId.hpp similarity index 100% rename from src/libs/database/include/database/ListenId.hpp rename to src/libs/database/include/database/objects/ListenId.hpp diff --git a/src/libs/database/include/database/MediaLibrary.hpp b/src/libs/database/include/database/objects/MediaLibrary.hpp similarity index 98% rename from src/libs/database/include/database/MediaLibrary.hpp rename to src/libs/database/include/database/objects/MediaLibrary.hpp index d26b0336..c52881ef 100644 --- a/src/libs/database/include/database/MediaLibrary.hpp +++ b/src/libs/database/include/database/objects/MediaLibrary.hpp @@ -26,8 +26,8 @@ #include -#include "database/MediaLibraryId.hpp" #include "database/Object.hpp" +#include "database/objects/MediaLibraryId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/MediaLibraryId.hpp b/src/libs/database/include/database/objects/MediaLibraryId.hpp similarity index 100% rename from src/libs/database/include/database/MediaLibraryId.hpp rename to src/libs/database/include/database/objects/MediaLibraryId.hpp diff --git a/src/libs/database/include/database/PlayListFile.hpp b/src/libs/database/include/database/objects/PlayListFile.hpp similarity index 99% rename from src/libs/database/include/database/PlayListFile.hpp rename to src/libs/database/include/database/objects/PlayListFile.hpp index bc53f7ce..bfcc6811 100644 --- a/src/libs/database/include/database/PlayListFile.hpp +++ b/src/libs/database/include/database/objects/PlayListFile.hpp @@ -27,9 +27,9 @@ #include #include -#include "database/DirectoryId.hpp" #include "database/IdRange.hpp" #include "database/Object.hpp" +#include "database/objects/DirectoryId.hpp" LMS_DECLARE_IDTYPE(PlayListFileId) diff --git a/src/libs/database/include/database/PlayQueue.hpp b/src/libs/database/include/database/objects/PlayQueue.hpp similarity index 97% rename from src/libs/database/include/database/PlayQueue.hpp rename to src/libs/database/include/database/objects/PlayQueue.hpp index a3dcbaee..68e39d4e 100644 --- a/src/libs/database/include/database/PlayQueue.hpp +++ b/src/libs/database/include/database/objects/PlayQueue.hpp @@ -28,9 +28,9 @@ #include #include "database/Object.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/UserId.hpp" LMS_DECLARE_IDTYPE(PlayQueueId) diff --git a/src/libs/database/include/database/RatedArtist.hpp b/src/libs/database/include/database/objects/RatedArtist.hpp similarity index 95% rename from src/libs/database/include/database/RatedArtist.hpp rename to src/libs/database/include/database/objects/RatedArtist.hpp index 7e846b67..ac21bc6a 100644 --- a/src/libs/database/include/database/RatedArtist.hpp +++ b/src/libs/database/include/database/objects/RatedArtist.hpp @@ -22,11 +22,11 @@ #include #include -#include "database/ArtistId.hpp" #include "database/Object.hpp" -#include "database/RatedArtistId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/RatedArtistId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/RatedArtistId.hpp b/src/libs/database/include/database/objects/RatedArtistId.hpp similarity index 100% rename from src/libs/database/include/database/RatedArtistId.hpp rename to src/libs/database/include/database/objects/RatedArtistId.hpp diff --git a/src/libs/database/include/database/RatedRelease.hpp b/src/libs/database/include/database/objects/RatedRelease.hpp similarity index 95% rename from src/libs/database/include/database/RatedRelease.hpp rename to src/libs/database/include/database/objects/RatedRelease.hpp index 54a12e1c..374de014 100644 --- a/src/libs/database/include/database/RatedRelease.hpp +++ b/src/libs/database/include/database/objects/RatedRelease.hpp @@ -23,10 +23,10 @@ #include #include "database/Object.hpp" -#include "database/RatedReleaseId.hpp" -#include "database/ReleaseId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/RatedReleaseId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/RatedReleaseId.hpp b/src/libs/database/include/database/objects/RatedReleaseId.hpp similarity index 100% rename from src/libs/database/include/database/RatedReleaseId.hpp rename to src/libs/database/include/database/objects/RatedReleaseId.hpp diff --git a/src/libs/database/include/database/RatedTrack.hpp b/src/libs/database/include/database/objects/RatedTrack.hpp similarity index 95% rename from src/libs/database/include/database/RatedTrack.hpp rename to src/libs/database/include/database/objects/RatedTrack.hpp index bdc2a6c6..32d49b87 100644 --- a/src/libs/database/include/database/RatedTrack.hpp +++ b/src/libs/database/include/database/objects/RatedTrack.hpp @@ -23,10 +23,10 @@ #include #include "database/Object.hpp" -#include "database/RatedTrackId.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/RatedTrackId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/RatedTrackId.hpp b/src/libs/database/include/database/objects/RatedTrackId.hpp similarity index 100% rename from src/libs/database/include/database/RatedTrackId.hpp rename to src/libs/database/include/database/objects/RatedTrackId.hpp diff --git a/src/libs/database/include/database/Release.hpp b/src/libs/database/include/database/objects/Release.hpp similarity index 97% rename from src/libs/database/include/database/Release.hpp rename to src/libs/database/include/database/objects/Release.hpp index 44a10eae..9895b8c2 100644 --- a/src/libs/database/include/database/Release.hpp +++ b/src/libs/database/include/database/objects/Release.hpp @@ -30,19 +30,19 @@ #include "core/EnumSet.hpp" #include "core/PartialDateTime.hpp" #include "core/UUID.hpp" -#include "database/ArtistId.hpp" -#include "database/ArtworkId.hpp" -#include "database/CountryId.hpp" -#include "database/DirectoryId.hpp" -#include "database/Filters.hpp" #include "database/IdRange.hpp" -#include "database/LabelId.hpp" -#include "database/MediaLibraryId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" -#include "database/ReleaseTypeId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/CountryId.hpp" +#include "database/objects/DirectoryId.hpp" +#include "database/objects/Filters.hpp" +#include "database/objects/LabelId.hpp" +#include "database/objects/MediaLibraryId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/ReleaseTypeId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/ReleaseId.hpp b/src/libs/database/include/database/objects/ReleaseId.hpp similarity index 100% rename from src/libs/database/include/database/ReleaseId.hpp rename to src/libs/database/include/database/objects/ReleaseId.hpp diff --git a/src/libs/database/include/database/ReleaseTypeId.hpp b/src/libs/database/include/database/objects/ReleaseTypeId.hpp similarity index 100% rename from src/libs/database/include/database/ReleaseTypeId.hpp rename to src/libs/database/include/database/objects/ReleaseTypeId.hpp diff --git a/src/libs/database/include/database/ScanSettings.hpp b/src/libs/database/include/database/objects/ScanSettings.hpp similarity index 100% rename from src/libs/database/include/database/ScanSettings.hpp rename to src/libs/database/include/database/objects/ScanSettings.hpp diff --git a/src/libs/database/include/database/StarredArtist.hpp b/src/libs/database/include/database/objects/StarredArtist.hpp similarity index 95% rename from src/libs/database/include/database/StarredArtist.hpp rename to src/libs/database/include/database/objects/StarredArtist.hpp index 0e05137e..bcc69e79 100644 --- a/src/libs/database/include/database/StarredArtist.hpp +++ b/src/libs/database/include/database/objects/StarredArtist.hpp @@ -22,11 +22,11 @@ #include #include -#include "database/ArtistId.hpp" #include "database/Object.hpp" -#include "database/StarredArtistId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/StarredArtistId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/StarredArtistId.hpp b/src/libs/database/include/database/objects/StarredArtistId.hpp similarity index 100% rename from src/libs/database/include/database/StarredArtistId.hpp rename to src/libs/database/include/database/objects/StarredArtistId.hpp diff --git a/src/libs/database/include/database/StarredRelease.hpp b/src/libs/database/include/database/objects/StarredRelease.hpp similarity index 95% rename from src/libs/database/include/database/StarredRelease.hpp rename to src/libs/database/include/database/objects/StarredRelease.hpp index 7894f990..4fc66cdf 100644 --- a/src/libs/database/include/database/StarredRelease.hpp +++ b/src/libs/database/include/database/objects/StarredRelease.hpp @@ -23,10 +23,10 @@ #include #include "database/Object.hpp" -#include "database/ReleaseId.hpp" -#include "database/StarredReleaseId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/StarredReleaseId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/StarredReleaseId.hpp b/src/libs/database/include/database/objects/StarredReleaseId.hpp similarity index 100% rename from src/libs/database/include/database/StarredReleaseId.hpp rename to src/libs/database/include/database/objects/StarredReleaseId.hpp diff --git a/src/libs/database/include/database/StarredTrack.hpp b/src/libs/database/include/database/objects/StarredTrack.hpp similarity index 96% rename from src/libs/database/include/database/StarredTrack.hpp rename to src/libs/database/include/database/objects/StarredTrack.hpp index 05d3490d..bcd127ee 100644 --- a/src/libs/database/include/database/StarredTrack.hpp +++ b/src/libs/database/include/database/objects/StarredTrack.hpp @@ -23,10 +23,10 @@ #include #include "database/Object.hpp" -#include "database/StarredTrackId.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/StarredTrackId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/StarredTrackId.hpp b/src/libs/database/include/database/objects/StarredTrackId.hpp similarity index 100% rename from src/libs/database/include/database/StarredTrackId.hpp rename to src/libs/database/include/database/objects/StarredTrackId.hpp diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/objects/Track.hpp similarity index 97% rename from src/libs/database/include/database/Track.hpp rename to src/libs/database/include/database/objects/Track.hpp index c6b62524..1d9e1013 100644 --- a/src/libs/database/include/database/Track.hpp +++ b/src/libs/database/include/database/objects/Track.hpp @@ -34,20 +34,20 @@ #include "core/EnumSet.hpp" #include "core/PartialDateTime.hpp" #include "core/UUID.hpp" -#include "database/ArtistId.hpp" -#include "database/ArtworkId.hpp" -#include "database/ClusterId.hpp" -#include "database/DirectoryId.hpp" -#include "database/Filters.hpp" #include "database/IdRange.hpp" -#include "database/MediaLibraryId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackEmbeddedImageId.hpp" -#include "database/TrackId.hpp" -#include "database/TrackListId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/ClusterId.hpp" +#include "database/objects/DirectoryId.hpp" +#include "database/objects/Filters.hpp" +#include "database/objects/MediaLibraryId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackEmbeddedImageId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/TrackListId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/TrackArtistLink.hpp b/src/libs/database/include/database/objects/TrackArtistLink.hpp similarity index 97% rename from src/libs/database/include/database/TrackArtistLink.hpp rename to src/libs/database/include/database/objects/TrackArtistLink.hpp index 47547f3b..6ad1801e 100644 --- a/src/libs/database/include/database/TrackArtistLink.hpp +++ b/src/libs/database/include/database/objects/TrackArtistLink.hpp @@ -26,12 +26,12 @@ #include #include "core/EnumSet.hpp" -#include "database/ArtistId.hpp" #include "database/IdType.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" LMS_DECLARE_IDTYPE(TrackArtistLinkId) diff --git a/src/libs/database/include/database/TrackBookmark.hpp b/src/libs/database/include/database/objects/TrackBookmark.hpp similarity index 97% rename from src/libs/database/include/database/TrackBookmark.hpp rename to src/libs/database/include/database/objects/TrackBookmark.hpp index 61a606a2..016f69be 100644 --- a/src/libs/database/include/database/TrackBookmark.hpp +++ b/src/libs/database/include/database/objects/TrackBookmark.hpp @@ -26,9 +26,9 @@ #include "database/IdType.hpp" #include "database/Object.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/UserId.hpp" LMS_DECLARE_IDTYPE(TrackBookmarkId) diff --git a/src/libs/database/include/database/TrackEmbeddedImage.hpp b/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp similarity index 95% rename from src/libs/database/include/database/TrackEmbeddedImage.hpp rename to src/libs/database/include/database/objects/TrackEmbeddedImage.hpp index 83261073..c4187ddc 100644 --- a/src/libs/database/include/database/TrackEmbeddedImage.hpp +++ b/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp @@ -26,13 +26,13 @@ #include #include "core/EnumSet.hpp" -#include "database/ArtistId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackEmbeddedImageId.hpp" -#include "database/TrackId.hpp" -#include "database/TrackListId.hpp" #include "database/Types.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackEmbeddedImageId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/TrackListId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/TrackEmbeddedImageId.hpp b/src/libs/database/include/database/objects/TrackEmbeddedImageId.hpp similarity index 100% rename from src/libs/database/include/database/TrackEmbeddedImageId.hpp rename to src/libs/database/include/database/objects/TrackEmbeddedImageId.hpp diff --git a/src/libs/database/include/database/TrackEmbeddedImageLink.hpp b/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp similarity index 96% rename from src/libs/database/include/database/TrackEmbeddedImageLink.hpp rename to src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp index 69335195..fe94213a 100644 --- a/src/libs/database/include/database/TrackEmbeddedImageLink.hpp +++ b/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp @@ -25,9 +25,9 @@ #include #include "database/Object.hpp" -#include "database/TrackEmbeddedImageId.hpp" -#include "database/TrackEmbeddedImageLinkId.hpp" #include "database/Types.hpp" +#include "database/objects/TrackEmbeddedImageId.hpp" +#include "database/objects/TrackEmbeddedImageLinkId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/TrackEmbeddedImageLinkId.hpp b/src/libs/database/include/database/objects/TrackEmbeddedImageLinkId.hpp similarity index 100% rename from src/libs/database/include/database/TrackEmbeddedImageLinkId.hpp rename to src/libs/database/include/database/objects/TrackEmbeddedImageLinkId.hpp diff --git a/src/libs/database/include/database/TrackFeatures.hpp b/src/libs/database/include/database/objects/TrackFeatures.hpp similarity index 98% rename from src/libs/database/include/database/TrackFeatures.hpp rename to src/libs/database/include/database/objects/TrackFeatures.hpp index 4ff8e1e9..6530a214 100644 --- a/src/libs/database/include/database/TrackFeatures.hpp +++ b/src/libs/database/include/database/objects/TrackFeatures.hpp @@ -29,8 +29,8 @@ #include "database/IdType.hpp" #include "database/Object.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" +#include "database/objects/TrackId.hpp" LMS_DECLARE_IDTYPE(TrackFeaturesId) diff --git a/src/libs/database/include/database/TrackId.hpp b/src/libs/database/include/database/objects/TrackId.hpp similarity index 100% rename from src/libs/database/include/database/TrackId.hpp rename to src/libs/database/include/database/objects/TrackId.hpp diff --git a/src/libs/database/include/database/TrackList.hpp b/src/libs/database/include/database/objects/TrackList.hpp similarity index 98% rename from src/libs/database/include/database/TrackList.hpp rename to src/libs/database/include/database/objects/TrackList.hpp index 57c10b7c..27fe17fe 100644 --- a/src/libs/database/include/database/TrackList.hpp +++ b/src/libs/database/include/database/objects/TrackList.hpp @@ -27,12 +27,12 @@ #include #include -#include "database/Filters.hpp" #include "database/Object.hpp" -#include "database/TrackId.hpp" -#include "database/TrackListId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/Filters.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/TrackListId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/TrackListId.hpp b/src/libs/database/include/database/objects/TrackListId.hpp similarity index 100% rename from src/libs/database/include/database/TrackListId.hpp rename to src/libs/database/include/database/objects/TrackListId.hpp diff --git a/src/libs/database/include/database/TrackLyrics.hpp b/src/libs/database/include/database/objects/TrackLyrics.hpp similarity index 99% rename from src/libs/database/include/database/TrackLyrics.hpp rename to src/libs/database/include/database/objects/TrackLyrics.hpp index d89c46d8..e8d7bbee 100644 --- a/src/libs/database/include/database/TrackLyrics.hpp +++ b/src/libs/database/include/database/objects/TrackLyrics.hpp @@ -29,8 +29,8 @@ #include "database/IdType.hpp" #include "database/Object.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" +#include "database/objects/TrackId.hpp" LMS_DECLARE_IDTYPE(TrackLyricsId) diff --git a/src/libs/database/include/database/UIState.hpp b/src/libs/database/include/database/objects/UIState.hpp similarity index 95% rename from src/libs/database/include/database/UIState.hpp rename to src/libs/database/include/database/objects/UIState.hpp index 06455269..fcd4320f 100644 --- a/src/libs/database/include/database/UIState.hpp +++ b/src/libs/database/include/database/objects/UIState.hpp @@ -24,8 +24,8 @@ #include "core/String.hpp" #include "database/Object.hpp" #include "database/Types.hpp" -#include "database/UIStateId.hpp" -#include "database/UserId.hpp" +#include "database/objects/UIStateId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/UIStateId.hpp b/src/libs/database/include/database/objects/UIStateId.hpp similarity index 100% rename from src/libs/database/include/database/UIStateId.hpp rename to src/libs/database/include/database/objects/UIStateId.hpp diff --git a/src/libs/database/include/database/User.hpp b/src/libs/database/include/database/objects/User.hpp similarity index 99% rename from src/libs/database/include/database/User.hpp rename to src/libs/database/include/database/objects/User.hpp index 4bf2c4fc..78ae5a75 100644 --- a/src/libs/database/include/database/User.hpp +++ b/src/libs/database/include/database/objects/User.hpp @@ -29,7 +29,7 @@ #include "core/UUID.hpp" #include "database/Object.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/database/include/database/UserId.hpp b/src/libs/database/include/database/objects/UserId.hpp similarity index 100% rename from src/libs/database/include/database/UserId.hpp rename to src/libs/database/include/database/objects/UserId.hpp diff --git a/src/libs/database/test/Artist.cpp b/src/libs/database/test/Artist.cpp index 5b52344a..69abbfd0 100644 --- a/src/libs/database/test/Artist.cpp +++ b/src/libs/database/test/Artist.cpp @@ -19,8 +19,8 @@ #include "Common.hpp" -#include "database/Artwork.hpp" -#include "database/Image.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Image.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/ArtistInfo.cpp b/src/libs/database/test/ArtistInfo.cpp index 3146e05f..706195ba 100644 --- a/src/libs/database/test/ArtistInfo.cpp +++ b/src/libs/database/test/ArtistInfo.cpp @@ -19,9 +19,9 @@ #include "Common.hpp" -#include "database/Artist.hpp" -#include "database/ArtistInfo.hpp" -#include "database/Directory.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/Directory.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/Artwork.cpp b/src/libs/database/test/Artwork.cpp index e0a2745e..88c020cd 100644 --- a/src/libs/database/test/Artwork.cpp +++ b/src/libs/database/test/Artwork.cpp @@ -17,10 +17,10 @@ #include "Common.hpp" -#include "database/Artwork.hpp" -#include "database/Image.hpp" -#include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageLink.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/AuthToken.cpp b/src/libs/database/test/AuthToken.cpp index 3cf6fc91..071fd358 100644 --- a/src/libs/database/test/AuthToken.cpp +++ b/src/libs/database/test/AuthToken.cpp @@ -19,7 +19,7 @@ #include "Common.hpp" -#include "database/AuthToken.hpp" +#include "database/objects/AuthToken.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/Common.cpp b/src/libs/database/test/Common.cpp index 7817b3dc..b9377ff4 100644 --- a/src/libs/database/test/Common.cpp +++ b/src/libs/database/test/Common.cpp @@ -19,9 +19,9 @@ #include "Common.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" #include "database/Types.hpp" +#include "database/objects/Release.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/Common.hpp b/src/libs/database/test/Common.hpp index 1c7d92fc..7a025976 100644 --- a/src/libs/database/test/Common.hpp +++ b/src/libs/database/test/Common.hpp @@ -24,21 +24,21 @@ #include -#include "database/Artist.hpp" -#include "database/Cluster.hpp" #include "database/IDb.hpp" -#include "database/Listen.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackBookmark.hpp" -#include "database/TrackFeatures.hpp" -#include "database/TrackList.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Listen.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackBookmark.hpp" +#include "database/objects/TrackFeatures.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/Directory.cpp b/src/libs/database/test/Directory.cpp index 546a0de0..5f365d81 100644 --- a/src/libs/database/test/Directory.cpp +++ b/src/libs/database/test/Directory.cpp @@ -19,7 +19,7 @@ #include "Common.hpp" -#include "database/Directory.hpp" +#include "database/objects/Directory.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/Image.cpp b/src/libs/database/test/Image.cpp index 1bed6697..a26340ad 100644 --- a/src/libs/database/test/Image.cpp +++ b/src/libs/database/test/Image.cpp @@ -19,8 +19,8 @@ #include "Common.hpp" -#include "database/Directory.hpp" -#include "database/Image.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Image.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/Listen.cpp b/src/libs/database/test/Listen.cpp index 1e6d8adc..4a79b015 100644 --- a/src/libs/database/test/Listen.cpp +++ b/src/libs/database/test/Listen.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/Listen.hpp" +#include "database/objects/Listen.hpp" #include "Common.hpp" diff --git a/src/libs/database/test/Migration.cpp b/src/libs/database/test/Migration.cpp index 84c78238..828889ab 100644 --- a/src/libs/database/test/Migration.cpp +++ b/src/libs/database/test/Migration.cpp @@ -20,26 +20,26 @@ #include "Common.hpp" #include "core/String.hpp" -#include "database/Artist.hpp" -#include "database/ArtistInfo.hpp" -#include "database/AuthToken.hpp" -#include "database/Directory.hpp" -#include "database/Image.hpp" -#include "database/PlayListFile.hpp" -#include "database/PlayQueue.hpp" -#include "database/RatedArtist.hpp" -#include "database/RatedRelease.hpp" -#include "database/RatedTrack.hpp" -#include "database/ScanSettings.hpp" -#include "database/StarredArtist.hpp" -#include "database/StarredRelease.hpp" -#include "database/StarredTrack.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageLink.hpp" -#include "database/TrackLyrics.hpp" -#include "database/UIState.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/AuthToken.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/PlayListFile.hpp" +#include "database/objects/PlayQueue.hpp" +#include "database/objects/RatedArtist.hpp" +#include "database/objects/RatedRelease.hpp" +#include "database/objects/RatedTrack.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/StarredArtist.hpp" +#include "database/objects/StarredRelease.hpp" +#include "database/objects/StarredTrack.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackLyrics.hpp" +#include "database/objects/UIState.hpp" +#include "database/objects/User.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/PlayListFile.cpp b/src/libs/database/test/PlayListFile.cpp index c508c79d..304c0523 100644 --- a/src/libs/database/test/PlayListFile.cpp +++ b/src/libs/database/test/PlayListFile.cpp @@ -19,8 +19,8 @@ #include "Common.hpp" -#include "database/PlayListFile.hpp" -#include "database/TrackList.hpp" +#include "database/objects/PlayListFile.hpp" +#include "database/objects/TrackList.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/RatedArtist.cpp b/src/libs/database/test/RatedArtist.cpp index 3cb44501..38ddacdc 100644 --- a/src/libs/database/test/RatedArtist.cpp +++ b/src/libs/database/test/RatedArtist.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/RatedArtist.hpp" +#include "database/objects/RatedArtist.hpp" #include "Common.hpp" diff --git a/src/libs/database/test/RatedRelease.cpp b/src/libs/database/test/RatedRelease.cpp index 7a309e92..ee4c66e0 100644 --- a/src/libs/database/test/RatedRelease.cpp +++ b/src/libs/database/test/RatedRelease.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/RatedRelease.hpp" +#include "database/objects/RatedRelease.hpp" #include "Common.hpp" diff --git a/src/libs/database/test/RatedTrack.cpp b/src/libs/database/test/RatedTrack.cpp index d939a6af..13ed38b5 100644 --- a/src/libs/database/test/RatedTrack.cpp +++ b/src/libs/database/test/RatedTrack.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/RatedTrack.hpp" +#include "database/objects/RatedTrack.hpp" #include "Common.hpp" diff --git a/src/libs/database/test/Release.cpp b/src/libs/database/test/Release.cpp index 4d134964..f232c6e7 100644 --- a/src/libs/database/test/Release.cpp +++ b/src/libs/database/test/Release.cpp @@ -20,8 +20,8 @@ #include "Common.hpp" #include "core/PartialDateTime.hpp" -#include "database/Artwork.hpp" -#include "database/Image.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Image.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/ScanSettings.cpp b/src/libs/database/test/ScanSettings.cpp index a6b28010..c619e4e6 100644 --- a/src/libs/database/test/ScanSettings.cpp +++ b/src/libs/database/test/ScanSettings.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/ScanSettings.hpp" +#include "database/objects/ScanSettings.hpp" #include diff --git a/src/libs/database/test/StarredArtist.cpp b/src/libs/database/test/StarredArtist.cpp index dac89056..f85af565 100644 --- a/src/libs/database/test/StarredArtist.cpp +++ b/src/libs/database/test/StarredArtist.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/StarredArtist.hpp" +#include "database/objects/StarredArtist.hpp" #include "Common.hpp" diff --git a/src/libs/database/test/StarredRelease.cpp b/src/libs/database/test/StarredRelease.cpp index 6fc161a4..d8e66a35 100644 --- a/src/libs/database/test/StarredRelease.cpp +++ b/src/libs/database/test/StarredRelease.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/StarredRelease.hpp" +#include "database/objects/StarredRelease.hpp" #include "Common.hpp" diff --git a/src/libs/database/test/StarredTrack.cpp b/src/libs/database/test/StarredTrack.cpp index 03e560c3..0c0b4632 100644 --- a/src/libs/database/test/StarredTrack.cpp +++ b/src/libs/database/test/StarredTrack.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "database/StarredTrack.hpp" +#include "database/objects/StarredTrack.hpp" #include "Common.hpp" diff --git a/src/libs/database/test/Track.cpp b/src/libs/database/test/Track.cpp index 5fb48041..9b83cf63 100644 --- a/src/libs/database/test/Track.cpp +++ b/src/libs/database/test/Track.cpp @@ -21,8 +21,8 @@ #include -#include "database/Artwork.hpp" -#include "database/Image.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Image.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/TrackArtistLink.cpp b/src/libs/database/test/TrackArtistLink.cpp index 51bcfba3..d8e512a2 100644 --- a/src/libs/database/test/TrackArtistLink.cpp +++ b/src/libs/database/test/TrackArtistLink.cpp @@ -20,7 +20,7 @@ #include "Common.hpp" #include "database/Types.hpp" -#include "database/TrackArtistLink.hpp" +#include "database/objects/TrackArtistLink.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/TrackBookmark.cpp b/src/libs/database/test/TrackBookmark.cpp index 2b30eb07..5e4d8208 100644 --- a/src/libs/database/test/TrackBookmark.cpp +++ b/src/libs/database/test/TrackBookmark.cpp @@ -19,7 +19,7 @@ #include "Common.hpp" -#include "database/TrackBookmark.hpp" +#include "database/objects/TrackBookmark.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/TrackEmbeddedImage.cpp b/src/libs/database/test/TrackEmbeddedImage.cpp index 0e1855c3..5b8123e9 100644 --- a/src/libs/database/test/TrackEmbeddedImage.cpp +++ b/src/libs/database/test/TrackEmbeddedImage.cpp @@ -19,10 +19,10 @@ #include -#include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageLink.hpp" -#include "database/TrackList.hpp" #include "database/Types.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackList.hpp" #include "Common.hpp" diff --git a/src/libs/database/test/TrackFeatures.cpp b/src/libs/database/test/TrackFeatures.cpp index cb799684..edf56025 100644 --- a/src/libs/database/test/TrackFeatures.cpp +++ b/src/libs/database/test/TrackFeatures.cpp @@ -19,7 +19,7 @@ #include "Common.hpp" -#include "database/TrackFeatures.hpp" +#include "database/objects/TrackFeatures.hpp" namespace lms::db::tests { diff --git a/src/libs/database/test/TrackLyrics.cpp b/src/libs/database/test/TrackLyrics.cpp index 79e91824..3ab59f3d 100644 --- a/src/libs/database/test/TrackLyrics.cpp +++ b/src/libs/database/test/TrackLyrics.cpp @@ -19,8 +19,8 @@ #include "Common.hpp" -#include "database/Track.hpp" -#include "database/TrackLyrics.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackLyrics.hpp" namespace lms::db::tests { diff --git a/src/libs/services/artwork/impl/ArtworkService.cpp b/src/libs/services/artwork/impl/ArtworkService.cpp index 23b697db..0480b756 100644 --- a/src/libs/services/artwork/impl/ArtworkService.cpp +++ b/src/libs/services/artwork/impl/ArtworkService.cpp @@ -22,17 +22,17 @@ #include "core/IConfig.hpp" #include "core/ILogger.hpp" #include "core/Utils.hpp" -#include "database/Artist.hpp" -#include "database/Artwork.hpp" #include "database/IDb.hpp" -#include "database/Image.hpp" -#include "database/ImageId.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageLink.hpp" -#include "database/TrackList.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/ImageId.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackList.hpp" #include "image/Exception.hpp" #include "image/IEncodedImage.hpp" #include "image/Image.hpp" diff --git a/src/libs/services/artwork/impl/ArtworkService.hpp b/src/libs/services/artwork/impl/ArtworkService.hpp index f08b8a6d..6eb0a691 100644 --- a/src/libs/services/artwork/impl/ArtworkService.hpp +++ b/src/libs/services/artwork/impl/ArtworkService.hpp @@ -22,8 +22,8 @@ #include #include -#include "database/ImageId.hpp" -#include "database/TrackEmbeddedImageId.hpp" +#include "database/objects/ImageId.hpp" +#include "database/objects/TrackEmbeddedImageId.hpp" #include "services/artwork/IArtworkService.hpp" #include "ImageCache.hpp" diff --git a/src/libs/services/artwork/impl/ImageCache.hpp b/src/libs/services/artwork/impl/ImageCache.hpp index 995e67f7..e4921362 100644 --- a/src/libs/services/artwork/impl/ImageCache.hpp +++ b/src/libs/services/artwork/impl/ImageCache.hpp @@ -26,7 +26,7 @@ #include #include -#include "database/ArtworkId.hpp" +#include "database/objects/ArtworkId.hpp" #include "image/IEncodedImage.hpp" namespace lms::artwork diff --git a/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp b/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp index 7577f640..d8fcc71f 100644 --- a/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp +++ b/src/libs/services/artwork/include/services/artwork/IArtworkService.hpp @@ -23,8 +23,8 @@ #include #include -#include "database/ArtworkId.hpp" -#include "database/TrackListId.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/TrackListId.hpp" #include "image/IEncodedImage.hpp" namespace lms::db diff --git a/src/libs/services/auth/impl/AuthServiceBase.cpp b/src/libs/services/auth/impl/AuthServiceBase.cpp index 9164716a..cb3b9e5b 100644 --- a/src/libs/services/auth/impl/AuthServiceBase.cpp +++ b/src/libs/services/auth/impl/AuthServiceBase.cpp @@ -22,7 +22,7 @@ #include "core/ILogger.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" namespace lms::auth { diff --git a/src/libs/services/auth/impl/AuthServiceBase.hpp b/src/libs/services/auth/impl/AuthServiceBase.hpp index 4b9956b1..c25aa28d 100644 --- a/src/libs/services/auth/impl/AuthServiceBase.hpp +++ b/src/libs/services/auth/impl/AuthServiceBase.hpp @@ -21,7 +21,7 @@ #include -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/services/auth/impl/AuthTokenService.cpp b/src/libs/services/auth/impl/AuthTokenService.cpp index 2e1fca8f..5fef93db 100644 --- a/src/libs/services/auth/impl/AuthTokenService.cpp +++ b/src/libs/services/auth/impl/AuthTokenService.cpp @@ -23,9 +23,9 @@ #include #include "core/ILogger.hpp" -#include "database/AuthToken.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/AuthToken.hpp" +#include "database/objects/User.hpp" #include "services/auth/Types.hpp" namespace lms::auth diff --git a/src/libs/services/auth/impl/internal/InternalPasswordService.cpp b/src/libs/services/auth/impl/internal/InternalPasswordService.cpp index 2b3e5bc0..8764b875 100644 --- a/src/libs/services/auth/impl/internal/InternalPasswordService.cpp +++ b/src/libs/services/auth/impl/internal/InternalPasswordService.cpp @@ -24,7 +24,7 @@ #include "core/IConfig.hpp" #include "core/ILogger.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "services/auth/Types.hpp" namespace lms::auth diff --git a/src/libs/services/auth/impl/internal/InternalPasswordService.hpp b/src/libs/services/auth/impl/internal/InternalPasswordService.hpp index 1c05e3d8..92fbfc53 100644 --- a/src/libs/services/auth/impl/internal/InternalPasswordService.hpp +++ b/src/libs/services/auth/impl/internal/InternalPasswordService.hpp @@ -22,7 +22,7 @@ #include #include -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "PasswordServiceBase.hpp" #include "services/auth/IPasswordService.hpp" diff --git a/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp b/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp index 22739642..300d4b32 100644 --- a/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp +++ b/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp @@ -28,7 +28,7 @@ #include #include "core/LiteralString.hpp" -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/services/auth/include/services/auth/IEnvService.hpp b/src/libs/services/auth/include/services/auth/IEnvService.hpp index 502d9f19..4a743bf4 100644 --- a/src/libs/services/auth/include/services/auth/IEnvService.hpp +++ b/src/libs/services/auth/include/services/auth/IEnvService.hpp @@ -22,7 +22,7 @@ #include #include -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/services/auth/include/services/auth/IPasswordService.hpp b/src/libs/services/auth/include/services/auth/IPasswordService.hpp index 1986883b..83260ca5 100644 --- a/src/libs/services/auth/include/services/auth/IPasswordService.hpp +++ b/src/libs/services/auth/include/services/auth/IPasswordService.hpp @@ -25,7 +25,7 @@ #include #include -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" #include "services/auth/Types.hpp" namespace lms::db diff --git a/src/libs/services/feedback/impl/FeedbackService.cpp b/src/libs/services/feedback/impl/FeedbackService.cpp index 69e80df9..c7e53313 100644 --- a/src/libs/services/feedback/impl/FeedbackService.cpp +++ b/src/libs/services/feedback/impl/FeedbackService.cpp @@ -21,18 +21,18 @@ #include "FeedbackService.impl.hpp" #include "core/ILogger.hpp" -#include "database/Artist.hpp" #include "database/IDb.hpp" -#include "database/RatedArtist.hpp" -#include "database/RatedRelease.hpp" -#include "database/RatedTrack.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/StarredArtist.hpp" -#include "database/StarredRelease.hpp" -#include "database/StarredTrack.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/RatedArtist.hpp" +#include "database/objects/RatedRelease.hpp" +#include "database/objects/RatedTrack.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/StarredArtist.hpp" +#include "database/objects/StarredRelease.hpp" +#include "database/objects/StarredTrack.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "internal/InternalBackend.hpp" #include "listenbrainz/ListenBrainzBackend.hpp" diff --git a/src/libs/services/feedback/impl/FeedbackService.impl.hpp b/src/libs/services/feedback/impl/FeedbackService.impl.hpp index 2db429ce..6f549648 100644 --- a/src/libs/services/feedback/impl/FeedbackService.impl.hpp +++ b/src/libs/services/feedback/impl/FeedbackService.impl.hpp @@ -21,7 +21,7 @@ #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" namespace lms::feedback { diff --git a/src/libs/services/feedback/impl/IFeedbackBackend.hpp b/src/libs/services/feedback/impl/IFeedbackBackend.hpp index cb377f1a..dea1b433 100644 --- a/src/libs/services/feedback/impl/IFeedbackBackend.hpp +++ b/src/libs/services/feedback/impl/IFeedbackBackend.hpp @@ -21,9 +21,9 @@ #include -#include "database/StarredArtistId.hpp" -#include "database/StarredReleaseId.hpp" -#include "database/StarredTrackId.hpp" +#include "database/objects/StarredArtistId.hpp" +#include "database/objects/StarredReleaseId.hpp" +#include "database/objects/StarredTrackId.hpp" namespace lms::feedback { diff --git a/src/libs/services/feedback/impl/internal/InternalBackend.cpp b/src/libs/services/feedback/impl/internal/InternalBackend.cpp index 847e24ac..0c90b540 100644 --- a/src/libs/services/feedback/impl/internal/InternalBackend.cpp +++ b/src/libs/services/feedback/impl/internal/InternalBackend.cpp @@ -21,9 +21,9 @@ #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/StarredArtist.hpp" -#include "database/StarredRelease.hpp" -#include "database/StarredTrack.hpp" +#include "database/objects/StarredArtist.hpp" +#include "database/objects/StarredRelease.hpp" +#include "database/objects/StarredTrack.hpp" namespace lms::feedback { diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp index 40123058..7b69456d 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp @@ -31,9 +31,9 @@ #include "core/http/IClient.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/StarredTrack.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/StarredTrack.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "Exception.hpp" #include "FeedbacksParser.hpp" diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp index ae9153ea..a1a39078 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp @@ -26,8 +26,8 @@ #include #include -#include "database/StarredTrackId.hpp" -#include "database/UserId.hpp" +#include "database/objects/StarredTrackId.hpp" +#include "database/objects/UserId.hpp" #include "FeedbackTypes.hpp" diff --git a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp index f3a45527..59a7fc71 100644 --- a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp @@ -24,9 +24,9 @@ #include "core/http/IClient.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/StarredArtist.hpp" -#include "database/StarredRelease.hpp" -#include "database/Track.hpp" +#include "database/objects/StarredArtist.hpp" +#include "database/objects/StarredRelease.hpp" +#include "database/objects/Track.hpp" #include "Utils.hpp" diff --git a/src/libs/services/feedback/impl/listenbrainz/Utils.cpp b/src/libs/services/feedback/impl/listenbrainz/Utils.cpp index e240c8c6..6f9932d4 100644 --- a/src/libs/services/feedback/impl/listenbrainz/Utils.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/Utils.cpp @@ -23,7 +23,7 @@ #include #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" namespace lms::feedback::listenBrainz::utils { diff --git a/src/libs/services/feedback/impl/listenbrainz/Utils.hpp b/src/libs/services/feedback/impl/listenbrainz/Utils.hpp index a55641ee..d2790cef 100644 --- a/src/libs/services/feedback/impl/listenbrainz/Utils.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/Utils.hpp @@ -21,7 +21,7 @@ #include "core/ILogger.hpp" #include "core/UUID.hpp" -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" #define LOG(sev, message) LMS_LOG(FEEDBACK, sev, "[listenbrainz] " << message) diff --git a/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp b/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp index 10fa960b..e1353b4a 100644 --- a/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp +++ b/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp @@ -25,12 +25,12 @@ #include #include -#include "database/ArtistId.hpp" -#include "database/Filters.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/Filters.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/UserId.hpp" namespace lms::db { diff --git a/src/libs/services/recommendation/impl/IEngine.hpp b/src/libs/services/recommendation/impl/IEngine.hpp index d4229a8f..a072fba4 100644 --- a/src/libs/services/recommendation/impl/IEngine.hpp +++ b/src/libs/services/recommendation/impl/IEngine.hpp @@ -22,8 +22,8 @@ #include #include "core/EnumSet.hpp" -#include "database/TrackListId.hpp" #include "database/Types.hpp" +#include "database/objects/TrackListId.hpp" #include "services/recommendation/Types.hpp" namespace lms::db diff --git a/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp b/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp index 1315bbd6..05a0f892 100644 --- a/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp +++ b/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp @@ -24,7 +24,7 @@ #include "core/ILogger.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Track.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "playlist-constraints/ConsecutiveArtists.hpp" diff --git a/src/libs/services/recommendation/impl/RecommendationService.cpp b/src/libs/services/recommendation/impl/RecommendationService.cpp index b5498f9f..e51ba11b 100644 --- a/src/libs/services/recommendation/impl/RecommendationService.cpp +++ b/src/libs/services/recommendation/impl/RecommendationService.cpp @@ -22,8 +22,8 @@ #include #include "database/IDb.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" +#include "database/objects/ScanSettings.hpp" #include "ClustersEngineCreator.hpp" #include "FeaturesEngineCreator.hpp" diff --git a/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp b/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp index 2a001500..e1100d0f 100644 --- a/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp +++ b/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp @@ -19,13 +19,13 @@ #include "ClustersEngine.hpp" -#include "database/Artist.hpp" -#include "database/Cluster.hpp" #include "database/IDb.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" namespace lms::recommendation { diff --git a/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp b/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp index 181f6c3f..cb3bf190 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp +++ b/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp @@ -23,14 +23,14 @@ #include "core/ILogger.hpp" #include "core/Random.hpp" -#include "database/Artist.hpp" #include "database/IDb.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackFeatures.hpp" -#include "database/TrackList.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackFeatures.hpp" +#include "database/objects/TrackList.hpp" #include "som/DataNormalizer.hpp" namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/features/FeaturesEngineCache.hpp b/src/libs/services/recommendation/impl/features/FeaturesEngineCache.hpp index 84ca8697..1b4794ae 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesEngineCache.hpp +++ b/src/libs/services/recommendation/impl/features/FeaturesEngineCache.hpp @@ -22,7 +22,7 @@ #include #include -#include "database/TrackId.hpp" +#include "database/objects/TrackId.hpp" #include "som/Network.hpp" namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp index 9aaaae0c..f5a27025 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp @@ -22,9 +22,9 @@ #include #include "database/IDb.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" namespace lms::recommendation::PlaylistGeneratorConstraint { diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp index 9d8a4760..9b0f2802 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp @@ -20,9 +20,9 @@ #include "ConsecutiveReleases.hpp" #include "database/IDb.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" namespace lms::recommendation::PlaylistGeneratorConstraint { diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp index 6055e21d..819d4ac1 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp @@ -21,7 +21,7 @@ #include "IConstraint.hpp" -#include "database/ReleaseId.hpp" +#include "database/objects/ReleaseId.hpp" namespace lms::db { diff --git a/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp b/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp index 3fd5168b..b36dd023 100644 --- a/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp +++ b/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp @@ -21,7 +21,7 @@ #include -#include "database/TrackListId.hpp" +#include "database/objects/TrackListId.hpp" #include "services/recommendation/Types.hpp" namespace lms::db diff --git a/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp b/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp index 92849eec..fabb9a0d 100644 --- a/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp +++ b/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp @@ -23,10 +23,10 @@ #include #include "core/EnumSet.hpp" -#include "database/ArtistId.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackListId.hpp" #include "database/Types.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackListId.hpp" #include "services/recommendation/Types.hpp" namespace lms::db diff --git a/src/libs/services/recommendation/include/services/recommendation/Types.hpp b/src/libs/services/recommendation/include/services/recommendation/Types.hpp index 53a7c9b8..5389640e 100644 --- a/src/libs/services/recommendation/include/services/recommendation/Types.hpp +++ b/src/libs/services/recommendation/include/services/recommendation/Types.hpp @@ -2,9 +2,9 @@ #include -#include "database/ArtistId.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" namespace lms::recommendation { diff --git a/src/libs/services/scanner/impl/MediaLibraryInfo.hpp b/src/libs/services/scanner/impl/MediaLibraryInfo.hpp index 5b62eb83..116aa748 100644 --- a/src/libs/services/scanner/impl/MediaLibraryInfo.hpp +++ b/src/libs/services/scanner/impl/MediaLibraryInfo.hpp @@ -21,7 +21,7 @@ #include -#include "database/MediaLibraryId.hpp" +#include "database/objects/MediaLibraryId.hpp" namespace lms::scanner { diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index cc770bd2..41137b52 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -27,9 +27,9 @@ #include "core/IJobScheduler.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" -#include "database/MediaLibrary.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/ScanSettings.hpp" #include "scanners/ArtistInfoFileScanner.hpp" #include "scanners/AudioFileScanner.hpp" diff --git a/src/libs/services/scanner/impl/ScannerSettings.hpp b/src/libs/services/scanner/impl/ScannerSettings.hpp index d915404b..0a450b3b 100644 --- a/src/libs/services/scanner/impl/ScannerSettings.hpp +++ b/src/libs/services/scanner/impl/ScannerSettings.hpp @@ -25,7 +25,7 @@ #include -#include "database/ScanSettings.hpp" +#include "database/objects/ScanSettings.hpp" #include "MediaLibraryInfo.hpp" diff --git a/src/libs/services/scanner/impl/helpers/ArtistHelpers.hpp b/src/libs/services/scanner/impl/helpers/ArtistHelpers.hpp index 83af1527..1c81320a 100644 --- a/src/libs/services/scanner/impl/helpers/ArtistHelpers.hpp +++ b/src/libs/services/scanner/impl/helpers/ArtistHelpers.hpp @@ -20,7 +20,7 @@ #pragma once #include "core/TaggedType.hpp" -#include "database/Artist.hpp" +#include "database/objects/Artist.hpp" namespace lms::metadata { diff --git a/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.cpp b/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.cpp index 7fade649..c6a984be 100644 --- a/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/ArtistInfoFileScanner.cpp @@ -24,11 +24,11 @@ #include "core/ILogger.hpp" #include "core/String.hpp" -#include "database/Artist.hpp" -#include "database/ArtistInfo.hpp" #include "database/IDb.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/MediaLibrary.hpp" #include "metadata/ArtistInfo.hpp" #include "metadata/Types.hpp" #include "services/scanner/ScanErrors.hpp" diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index 6c3d1221..e67cbc4b 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -24,21 +24,21 @@ #include "core/PartialDateTime.hpp" #include "core/Path.hpp" #include "core/XxHash3.hpp" -#include "database/Artist.hpp" -#include "database/Artwork.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" #include "database/IDb.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageLink.hpp" -#include "database/TrackFeatures.hpp" -#include "database/TrackLyrics.hpp" #include "database/Types.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackFeatures.hpp" +#include "database/objects/TrackLyrics.hpp" #include "image/Exception.hpp" #include "image/Image.hpp" #include "metadata/Exception.hpp" diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp index 5bd20f8a..5b8d7a0c 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp @@ -22,9 +22,9 @@ #include "core/IConfig.hpp" #include "core/Service.hpp" #include "database/IDb.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Track.hpp" #include "metadata/IAudioFileParser.hpp" #include "AudioFileScanOperation.hpp" diff --git a/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp b/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp index 8910f07d..b84e4672 100644 --- a/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/ImageFileScanner.cpp @@ -22,11 +22,12 @@ #include #include "core/ILogger.hpp" -#include "database/Artwork.hpp" + #include "database/IDb.hpp" -#include "database/Image.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/MediaLibrary.hpp" #include "image/Exception.hpp" #include "image/Image.hpp" #include "services/scanner/ScanErrors.hpp" diff --git a/src/libs/services/scanner/impl/scanners/LyricsFileScanner.cpp b/src/libs/services/scanner/impl/scanners/LyricsFileScanner.cpp index d077802b..de85094a 100644 --- a/src/libs/services/scanner/impl/scanners/LyricsFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/LyricsFileScanner.cpp @@ -26,9 +26,9 @@ #include "ScannerSettings.hpp" #include "core/ILogger.hpp" #include "database/IDb.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" -#include "database/TrackLyrics.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/TrackLyrics.hpp" #include "metadata/Lyrics.hpp" #include "services/scanner/ScanErrors.hpp" diff --git a/src/libs/services/scanner/impl/scanners/PlayListFileScanner.cpp b/src/libs/services/scanner/impl/scanners/PlayListFileScanner.cpp index 0be759d6..809ed1fa 100644 --- a/src/libs/services/scanner/impl/scanners/PlayListFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/PlayListFileScanner.cpp @@ -24,9 +24,9 @@ #include "core/ILogger.hpp" #include "database/IDb.hpp" -#include "database/MediaLibrary.hpp" -#include "database/PlayListFile.hpp" #include "database/Session.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/PlayListFile.hpp" #include "metadata/Exception.hpp" #include "metadata/PlayList.hpp" diff --git a/src/libs/services/scanner/impl/scanners/Utils.cpp b/src/libs/services/scanner/impl/scanners/Utils.cpp index 4469a3a1..fc187ce8 100644 --- a/src/libs/services/scanner/impl/scanners/Utils.cpp +++ b/src/libs/services/scanner/impl/scanners/Utils.cpp @@ -22,9 +22,9 @@ #include #include "core/Path.hpp" -#include "database/Directory.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" namespace lms::scanner::utils { diff --git a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp index 4513ea96..77d2bbdd 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp @@ -23,13 +23,13 @@ #include #include "core/ILogger.hpp" -#include "database/Artist.hpp" -#include "database/ArtistInfo.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackList.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackList.hpp" #include "metadata/Types.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index 9e3490d5..08b36aed 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -30,16 +30,16 @@ #include "core/ILogger.hpp" #include "core/Path.hpp" #include "core/String.hpp" -#include "database/Artist.hpp" -#include "database/ArtistInfo.hpp" -#include "database/Artwork.hpp" -#include "database/ArtworkId.hpp" -#include "database/Directory.hpp" #include "database/IDb.hpp" -#include "database/Image.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" #include "JobQueue.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp index 03dc6cbe..9fb01f3a 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp @@ -22,11 +22,11 @@ #include #include "core/ILogger.hpp" -#include "database/Directory.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackLyrics.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackLyrics.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp index f8f740b6..098f6bba 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp @@ -25,13 +25,13 @@ #include "core/IJob.hpp" #include "core/ILogger.hpp" -#include "database/Directory.hpp" #include "database/IDb.hpp" -#include "database/PlayListFile.hpp" -#include "database/ReleaseId.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/PlayListFile.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" #include "services/scanner/ScanErrors.hpp" #include "JobQueue.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index 3e15d1ad..17572122 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -28,14 +28,14 @@ #include "core/IJob.hpp" #include "core/ILogger.hpp" #include "core/Path.hpp" -#include "database/Artwork.hpp" -#include "database/Directory.hpp" #include "database/IDb.hpp" -#include "database/Image.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackEmbeddedImage.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" #include "JobQueue.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp index dd361328..6d4175f0 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp @@ -27,15 +27,15 @@ #include "core/IJobScheduler.hpp" #include "core/ILogger.hpp" #include "core/LiteralString.hpp" -#include "database/Artwork.hpp" -#include "database/Directory.hpp" #include "database/IDb.hpp" #include "database/IdRange.hpp" -#include "database/Image.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackEmbeddedImage.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" #include "JobQueue.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp index b78918f9..3b236cd7 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp @@ -22,7 +22,7 @@ #include "core/ILogger.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Track.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index c91c8b2c..d30dae79 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -23,13 +23,13 @@ #include "core/ILogger.hpp" #include "core/Path.hpp" -#include "database/ArtistInfo.hpp" #include "database/IDb.hpp" -#include "database/Image.hpp" -#include "database/PlayListFile.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackLyrics.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/PlayListFile.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackLyrics.hpp" #include "ScanContext.hpp" #include "ScannerSettings.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp index 60cb53b1..7d1dd110 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp @@ -19,9 +19,9 @@ #include "ScanStepComputeClusterStats.hpp" #include "core/ILogger.hpp" -#include "database/Cluster.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" +#include "database/objects/Cluster.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp index dba7c06c..abaac7a8 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp @@ -20,14 +20,14 @@ #include "ScanStepRemoveOrphanedDbEntries.hpp" #include "core/ILogger.hpp" -#include "database/Artist.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" #include "database/IDb.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackEmbeddedImage.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp b/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp index 14958504..22500381 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp @@ -19,10 +19,10 @@ #include "ScanStepUpdateLibraryFields.hpp" -#include "database/Directory.hpp" #include "database/IDb.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" #include "MediaLibraryInfo.hpp" #include "ScanContext.hpp" diff --git a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp index 7d1633df..3ed335a0 100644 --- a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp +++ b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp @@ -24,7 +24,7 @@ #include #include -#include "database/TrackId.hpp" +#include "database/objects/TrackId.hpp" #include "ScanErrors.hpp" diff --git a/src/libs/services/scrobbling/impl/ScrobblingService.cpp b/src/libs/services/scrobbling/impl/ScrobblingService.cpp index 162cf523..5e97a9a7 100644 --- a/src/libs/services/scrobbling/impl/ScrobblingService.cpp +++ b/src/libs/services/scrobbling/impl/ScrobblingService.cpp @@ -20,13 +20,13 @@ #include "ScrobblingService.hpp" #include "core/ILogger.hpp" -#include "database/Artist.hpp" #include "database/IDb.hpp" -#include "database/Listen.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Listen.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "internal/InternalBackend.hpp" #include "listenbrainz/ListenBrainzBackend.hpp" diff --git a/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp b/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp index 70ae072d..2fef72d0 100644 --- a/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp +++ b/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp @@ -20,10 +20,10 @@ #include "InternalBackend.hpp" #include "database/IDb.hpp" -#include "database/Listen.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Listen.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" namespace lms::scrobbling { diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp index 19adf19e..f241f01e 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp @@ -25,7 +25,7 @@ #include "core/http/IClient.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Track.hpp" #include "Utils.hpp" diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp index 2e9a81e3..9d78f95c 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp @@ -30,13 +30,13 @@ #include "core/IConfig.hpp" #include "core/Service.hpp" #include "core/http/IClient.hpp" -#include "database/Artist.hpp" #include "database/IDb.hpp" -#include "database/Listen.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Listen.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "services/scrobbling/Exception.hpp" #include "Utils.hpp" diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp index 2751272f..25523e3b 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp @@ -27,7 +27,7 @@ #include #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" #include "services/scrobbling/Listen.hpp" diff --git a/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp b/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp index 3c0d47bf..230f9df1 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp @@ -23,7 +23,7 @@ #include #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" namespace lms::scrobbling::listenBrainz::utils { diff --git a/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp b/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp index 0e3801c8..6bd75648 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp @@ -21,7 +21,7 @@ #include "core/ILogger.hpp" #include "core/UUID.hpp" -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" #define LOG(sev, message) LMS_LOG(SCROBBLING, sev, "[listenbrainz] " << message) diff --git a/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp b/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp index 35f3e8bc..3d0b2e09 100644 --- a/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp +++ b/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp @@ -26,11 +26,11 @@ #include #include -#include "database/ArtistId.hpp" -#include "database/Filters.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/Filters.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" #include "services/scrobbling/Listen.hpp" namespace lms::db diff --git a/src/libs/services/scrobbling/include/services/scrobbling/Listen.hpp b/src/libs/services/scrobbling/include/services/scrobbling/Listen.hpp index 7491bd04..f586f0f9 100644 --- a/src/libs/services/scrobbling/include/services/scrobbling/Listen.hpp +++ b/src/libs/services/scrobbling/include/services/scrobbling/Listen.hpp @@ -21,8 +21,8 @@ #include -#include "database/TrackId.hpp" -#include "database/UserId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/UserId.hpp" namespace lms::scrobbling { diff --git a/src/libs/services/transcoding/impl/TranscodingService.cpp b/src/libs/services/transcoding/impl/TranscodingService.cpp index 56fa18dc..5a14820c 100644 --- a/src/libs/services/transcoding/impl/TranscodingService.cpp +++ b/src/libs/services/transcoding/impl/TranscodingService.cpp @@ -23,7 +23,7 @@ #include "core/ILogger.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Track.hpp" #include "TranscodingResourceHandler.hpp" diff --git a/src/libs/services/transcoding/include/services/transcoding/ITranscodingService.hpp b/src/libs/services/transcoding/include/services/transcoding/ITranscodingService.hpp index e1b478d3..593a47e6 100644 --- a/src/libs/services/transcoding/include/services/transcoding/ITranscodingService.hpp +++ b/src/libs/services/transcoding/include/services/transcoding/ITranscodingService.hpp @@ -23,7 +23,7 @@ #include #include -#include "database/TrackId.hpp" +#include "database/objects/TrackId.hpp" namespace lms { diff --git a/src/libs/subsonic/impl/CoverArtId.cpp b/src/libs/subsonic/impl/CoverArtId.cpp index fc91c008..9f184a21 100644 --- a/src/libs/subsonic/impl/CoverArtId.cpp +++ b/src/libs/subsonic/impl/CoverArtId.cpp @@ -22,7 +22,7 @@ #include #include "core/String.hpp" -#include "database/ArtworkId.hpp" +#include "database/objects/ArtworkId.hpp" namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/CoverArtId.hpp b/src/libs/subsonic/impl/CoverArtId.hpp index 11a763e6..ec0c3ccb 100644 --- a/src/libs/subsonic/impl/CoverArtId.hpp +++ b/src/libs/subsonic/impl/CoverArtId.hpp @@ -22,7 +22,7 @@ #include #include "core/String.hpp" -#include "database/ArtworkId.hpp" +#include "database/objects/ArtworkId.hpp" namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/SubsonicId.hpp b/src/libs/subsonic/impl/SubsonicId.hpp index f0db1e48..7dac636c 100644 --- a/src/libs/subsonic/impl/SubsonicId.hpp +++ b/src/libs/subsonic/impl/SubsonicId.hpp @@ -20,12 +20,12 @@ #pragma once #include "core/String.hpp" -#include "database/ArtistId.hpp" -#include "database/DirectoryId.hpp" -#include "database/MediaLibraryId.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" -#include "database/TrackListId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/DirectoryId.hpp" +#include "database/objects/MediaLibraryId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/TrackListId.hpp" namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index 67718981..91871541 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -31,7 +31,7 @@ #include "core/String.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "services/auth/IAuthTokenService.hpp" #include "services/auth/IPasswordService.hpp" diff --git a/src/libs/subsonic/impl/SubsonicResource.hpp b/src/libs/subsonic/impl/SubsonicResource.hpp index 4433d1ab..b0d89217 100644 --- a/src/libs/subsonic/impl/SubsonicResource.hpp +++ b/src/libs/subsonic/impl/SubsonicResource.hpp @@ -25,7 +25,7 @@ #include #include -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" #include "RequestContext.hpp" diff --git a/src/libs/subsonic/impl/endpoints/AlbumSongLists.cpp b/src/libs/subsonic/impl/endpoints/AlbumSongLists.cpp index 179269b1..2c9871d7 100644 --- a/src/libs/subsonic/impl/endpoints/AlbumSongLists.cpp +++ b/src/libs/subsonic/impl/endpoints/AlbumSongLists.cpp @@ -22,13 +22,13 @@ #include #include "core/Service.hpp" -#include "database/Artist.hpp" -#include "database/Cluster.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/libs/subsonic/impl/endpoints/Bookmarks.cpp b/src/libs/subsonic/impl/endpoints/Bookmarks.cpp index fe75e9b1..7587bed7 100644 --- a/src/libs/subsonic/impl/endpoints/Bookmarks.cpp +++ b/src/libs/subsonic/impl/endpoints/Bookmarks.cpp @@ -19,11 +19,11 @@ #include "Bookmarks.hpp" -#include "database/PlayQueue.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackBookmark.hpp" -#include "database/User.hpp" +#include "database/objects/PlayQueue.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackBookmark.hpp" +#include "database/objects/User.hpp" #include "ParameterParsing.hpp" #include "SubsonicId.hpp" diff --git a/src/libs/subsonic/impl/endpoints/Browsing.cpp b/src/libs/subsonic/impl/endpoints/Browsing.cpp index d36a7053..9f783714 100644 --- a/src/libs/subsonic/impl/endpoints/Browsing.cpp +++ b/src/libs/subsonic/impl/endpoints/Browsing.cpp @@ -22,15 +22,15 @@ #include "core/ILogger.hpp" #include "core/Random.hpp" #include "core/Service.hpp" -#include "database/Artist.hpp" -#include "database/ArtistInfo.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/libs/subsonic/impl/endpoints/MediaAnnotation.cpp b/src/libs/subsonic/impl/endpoints/MediaAnnotation.cpp index 55749da6..3bd79e77 100644 --- a/src/libs/subsonic/impl/endpoints/MediaAnnotation.cpp +++ b/src/libs/subsonic/impl/endpoints/MediaAnnotation.cpp @@ -23,12 +23,12 @@ #include #include "core/Service.hpp" -#include "database/ArtistId.hpp" -#include "database/Release.hpp" -#include "database/ReleaseId.hpp" #include "database/Session.hpp" -#include "database/TrackId.hpp" -#include "database/User.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp b/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp index 805a0468..e589fa2a 100644 --- a/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp +++ b/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp @@ -27,10 +27,10 @@ #include "core/String.hpp" #include "core/Utils.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackEmbeddedImageId.hpp" -#include "database/TrackLyrics.hpp" -#include "database/User.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackEmbeddedImageId.hpp" +#include "database/objects/TrackLyrics.hpp" +#include "database/objects/User.hpp" #include "services/artwork/IArtworkService.hpp" #include "services/transcoding/ITranscodingService.hpp" diff --git a/src/libs/subsonic/impl/endpoints/Playlists.cpp b/src/libs/subsonic/impl/endpoints/Playlists.cpp index a3d2e4bb..cfa46fff 100644 --- a/src/libs/subsonic/impl/endpoints/Playlists.cpp +++ b/src/libs/subsonic/impl/endpoints/Playlists.cpp @@ -20,9 +20,9 @@ #include "Playlists.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" -#include "database/User.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" #include "ParameterParsing.hpp" #include "SubsonicId.hpp" diff --git a/src/libs/subsonic/impl/endpoints/Searching.cpp b/src/libs/subsonic/impl/endpoints/Searching.cpp index 9cc979cb..f38f1519 100644 --- a/src/libs/subsonic/impl/endpoints/Searching.cpp +++ b/src/libs/subsonic/impl/endpoints/Searching.cpp @@ -24,12 +24,12 @@ #include #include "core/Random.hpp" -#include "database/Artist.hpp" -#include "database/Directory.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "ParameterParsing.hpp" #include "SubsonicId.hpp" diff --git a/src/libs/subsonic/impl/endpoints/UserManagement.cpp b/src/libs/subsonic/impl/endpoints/UserManagement.cpp index 9f47adaf..541b2a46 100644 --- a/src/libs/subsonic/impl/endpoints/UserManagement.cpp +++ b/src/libs/subsonic/impl/endpoints/UserManagement.cpp @@ -2,7 +2,7 @@ #include "core/Service.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "services/auth/IPasswordService.hpp" #include "ParameterParsing.hpp" diff --git a/src/libs/subsonic/impl/responses/Album.cpp b/src/libs/subsonic/impl/responses/Album.cpp index 767e5fa3..07f71b96 100644 --- a/src/libs/subsonic/impl/responses/Album.cpp +++ b/src/libs/subsonic/impl/responses/Album.cpp @@ -22,14 +22,14 @@ #include "core/ITraceLogger.hpp" #include "core/Service.hpp" #include "core/String.hpp" -#include "database/Artist.hpp" -#include "database/Artwork.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" -#include "database/Release.hpp" -#include "database/Track.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/libs/subsonic/impl/responses/AlbumInfo.cpp b/src/libs/subsonic/impl/responses/AlbumInfo.cpp index 4d3a4e5a..0463609a 100644 --- a/src/libs/subsonic/impl/responses/AlbumInfo.cpp +++ b/src/libs/subsonic/impl/responses/AlbumInfo.cpp @@ -19,7 +19,7 @@ #include "AlbumInfo.hpp" -#include "database/Release.hpp" +#include "database/objects/Release.hpp" #include "RequestContext.hpp" diff --git a/src/libs/subsonic/impl/responses/Artist.cpp b/src/libs/subsonic/impl/responses/Artist.cpp index f47a76bf..53dbf7d3 100644 --- a/src/libs/subsonic/impl/responses/Artist.cpp +++ b/src/libs/subsonic/impl/responses/Artist.cpp @@ -22,11 +22,11 @@ #include "core/ITraceLogger.hpp" #include "core/Service.hpp" #include "core/String.hpp" -#include "database/Artist.hpp" -#include "database/Artwork.hpp" -#include "database/Release.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "CoverArtId.hpp" diff --git a/src/libs/subsonic/impl/responses/Bookmark.cpp b/src/libs/subsonic/impl/responses/Bookmark.cpp index 063f330c..07069412 100644 --- a/src/libs/subsonic/impl/responses/Bookmark.cpp +++ b/src/libs/subsonic/impl/responses/Bookmark.cpp @@ -19,8 +19,8 @@ #include "responses/Bookmark.hpp" -#include "database/TrackBookmark.hpp" -#include "database/User.hpp" +#include "database/objects/TrackBookmark.hpp" +#include "database/objects/User.hpp" namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/Contributor.cpp b/src/libs/subsonic/impl/responses/Contributor.cpp index 952fc662..430f5d5a 100644 --- a/src/libs/subsonic/impl/responses/Contributor.cpp +++ b/src/libs/subsonic/impl/responses/Contributor.cpp @@ -20,7 +20,7 @@ #include "responses/Contributor.hpp" #include "database/Object.hpp" -#include "database/TrackArtistLink.hpp" +#include "database/objects/TrackArtistLink.hpp" #include "SubsonicResponse.hpp" #include "responses/Artist.hpp" diff --git a/src/libs/subsonic/impl/responses/Genre.cpp b/src/libs/subsonic/impl/responses/Genre.cpp index 2ae28e9f..0b0504d4 100644 --- a/src/libs/subsonic/impl/responses/Genre.cpp +++ b/src/libs/subsonic/impl/responses/Genre.cpp @@ -19,7 +19,7 @@ #include "responses/Genre.hpp" -#include "database/Cluster.hpp" +#include "database/objects/Cluster.hpp" #include "RequestContext.hpp" diff --git a/src/libs/subsonic/impl/responses/ItemDate.cpp b/src/libs/subsonic/impl/responses/ItemDate.cpp index c5c92c99..98441b15 100644 --- a/src/libs/subsonic/impl/responses/ItemDate.cpp +++ b/src/libs/subsonic/impl/responses/ItemDate.cpp @@ -19,7 +19,7 @@ #include "responses/Genre.hpp" -#include "database/Cluster.hpp" +#include "database/objects/Cluster.hpp" namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/ItemGenre.cpp b/src/libs/subsonic/impl/responses/ItemGenre.cpp index db4dea6c..0850ffdb 100644 --- a/src/libs/subsonic/impl/responses/ItemGenre.cpp +++ b/src/libs/subsonic/impl/responses/ItemGenre.cpp @@ -19,7 +19,7 @@ #include "responses/ItemGenre.hpp" -#include "database/Cluster.hpp" +#include "database/objects/Cluster.hpp" namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/Lyrics.cpp b/src/libs/subsonic/impl/responses/Lyrics.cpp index 67b91454..2273d046 100644 --- a/src/libs/subsonic/impl/responses/Lyrics.cpp +++ b/src/libs/subsonic/impl/responses/Lyrics.cpp @@ -19,7 +19,7 @@ #include "responses/Lyrics.hpp" -#include "database/TrackLyrics.hpp" +#include "database/objects/TrackLyrics.hpp" #include "RequestContext.hpp" diff --git a/src/libs/subsonic/impl/responses/Playlist.cpp b/src/libs/subsonic/impl/responses/Playlist.cpp index d053c14a..e3a9befb 100644 --- a/src/libs/subsonic/impl/responses/Playlist.cpp +++ b/src/libs/subsonic/impl/responses/Playlist.cpp @@ -21,9 +21,9 @@ #include "core/Service.hpp" #include "core/String.hpp" -#include "database/Artwork.hpp" -#include "database/TrackList.hpp" -#include "database/User.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" #include "services/artwork/IArtworkService.hpp" #include "CoverArtId.hpp" diff --git a/src/libs/subsonic/impl/responses/RecordLabel.cpp b/src/libs/subsonic/impl/responses/RecordLabel.cpp index 749a3443..81f813cd 100644 --- a/src/libs/subsonic/impl/responses/RecordLabel.cpp +++ b/src/libs/subsonic/impl/responses/RecordLabel.cpp @@ -19,7 +19,7 @@ #include "responses/RecordLabel.hpp" -#include "database/Release.hpp" +#include "database/objects/Release.hpp" namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/ReplayGain.cpp b/src/libs/subsonic/impl/responses/ReplayGain.cpp index 5fd9d821..a2fd1dd9 100644 --- a/src/libs/subsonic/impl/responses/ReplayGain.cpp +++ b/src/libs/subsonic/impl/responses/ReplayGain.cpp @@ -19,7 +19,7 @@ #include "responses/ReplayGain.hpp" -#include "database/Track.hpp" +#include "database/objects/Track.hpp" namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/Song.cpp b/src/libs/subsonic/impl/responses/Song.cpp index 093cdc7a..5462bb9c 100644 --- a/src/libs/subsonic/impl/responses/Song.cpp +++ b/src/libs/subsonic/impl/responses/Song.cpp @@ -27,16 +27,16 @@ #include "core/MimeTypes.hpp" #include "core/Service.hpp" #include "core/String.hpp" -#include "database/Artist.hpp" -#include "database/Artwork.hpp" -#include "database/Cluster.hpp" -#include "database/Directory.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Artwork.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/libs/subsonic/impl/responses/User.cpp b/src/libs/subsonic/impl/responses/User.cpp index 885d2189..8859b2c1 100644 --- a/src/libs/subsonic/impl/responses/User.cpp +++ b/src/libs/subsonic/impl/responses/User.cpp @@ -19,8 +19,8 @@ #include "responses/User.hpp" -#include "database/MediaLibrary.hpp" -#include "database/User.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/User.hpp" #include "RequestContext.hpp" #include "SubsonicId.hpp" diff --git a/src/lms/ui/Auth.cpp b/src/lms/ui/Auth.cpp index 1ffac05b..20a2f297 100644 --- a/src/lms/ui/Auth.cpp +++ b/src/lms/ui/Auth.cpp @@ -30,7 +30,7 @@ #include "core/Service.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "services/auth/IAuthTokenService.hpp" #include "services/auth/IPasswordService.hpp" diff --git a/src/lms/ui/Auth.hpp b/src/lms/ui/Auth.hpp index 9763d7fe..a0496d78 100644 --- a/src/lms/ui/Auth.hpp +++ b/src/lms/ui/Auth.hpp @@ -21,7 +21,7 @@ #include -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" namespace lms::auth { diff --git a/src/lms/ui/LmsApplication.cpp b/src/lms/ui/LmsApplication.cpp index 437bed35..3acf03b2 100644 --- a/src/lms/ui/LmsApplication.cpp +++ b/src/lms/ui/LmsApplication.cpp @@ -29,13 +29,13 @@ #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" #include "core/Service.hpp" -#include "database/Artist.hpp" -#include "database/Cluster.hpp" #include "database/IDb.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/TrackList.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" #include "services/artwork/IArtworkService.hpp" #include "services/auth/IAuthTokenService.hpp" #include "services/auth/IEnvService.hpp" diff --git a/src/lms/ui/LmsApplication.hpp b/src/lms/ui/LmsApplication.hpp index 166716cf..f5a54586 100644 --- a/src/lms/ui/LmsApplication.hpp +++ b/src/lms/ui/LmsApplication.hpp @@ -27,7 +27,7 @@ #include "database/Object.hpp" #include "database/Types.hpp" -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" #include "services/scanner/ScannerEvents.hpp" #include "Auth.hpp" diff --git a/src/lms/ui/LmsApplicationManager.hpp b/src/lms/ui/LmsApplicationManager.hpp index 92c14189..dfe40a3d 100644 --- a/src/lms/ui/LmsApplicationManager.hpp +++ b/src/lms/ui/LmsApplicationManager.hpp @@ -25,7 +25,7 @@ #include -#include "database/UserId.hpp" +#include "database/objects/UserId.hpp" namespace lms::ui { diff --git a/src/lms/ui/MediaPlayer.cpp b/src/lms/ui/MediaPlayer.cpp index 58a29e14..7bddd090 100644 --- a/src/lms/ui/MediaPlayer.cpp +++ b/src/lms/ui/MediaPlayer.cpp @@ -27,13 +27,13 @@ #include "core/ILogger.hpp" #include "core/String.hpp" #include "core/Utils.hpp" -#include "database/Artist.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" #include "LmsApplication.hpp" #include "Utils.hpp" diff --git a/src/lms/ui/MediaPlayer.hpp b/src/lms/ui/MediaPlayer.hpp index 0bdc41e7..ea5472ac 100644 --- a/src/lms/ui/MediaPlayer.hpp +++ b/src/lms/ui/MediaPlayer.hpp @@ -27,8 +27,8 @@ #include #include -#include "database/TrackId.hpp" #include "database/Types.hpp" +#include "database/objects/TrackId.hpp" namespace lms::ui { diff --git a/src/lms/ui/PlayQueue.cpp b/src/lms/ui/PlayQueue.cpp index b7835fe1..3290581b 100644 --- a/src/lms/ui/PlayQueue.cpp +++ b/src/lms/ui/PlayQueue.cpp @@ -32,12 +32,12 @@ #include "core/ILogger.hpp" #include "core/Random.hpp" #include "core/Service.hpp" -#include "database/Artist.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IPlaylistGeneratorService.hpp" diff --git a/src/lms/ui/PlayQueue.hpp b/src/lms/ui/PlayQueue.hpp index a6debe27..01186781 100644 --- a/src/lms/ui/PlayQueue.hpp +++ b/src/lms/ui/PlayQueue.hpp @@ -27,8 +27,8 @@ #include #include "database/Object.hpp" -#include "database/TrackId.hpp" -#include "database/TrackListId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/TrackListId.hpp" #include "common/Template.hpp" diff --git a/src/lms/ui/SettingsView.cpp b/src/lms/ui/SettingsView.cpp index 6507d5aa..6849717b 100644 --- a/src/lms/ui/SettingsView.cpp +++ b/src/lms/ui/SettingsView.cpp @@ -34,7 +34,7 @@ #include "core/String.hpp" #include "database/Session.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "services/auth/IAuthTokenService.hpp" #include "services/auth/IPasswordService.hpp" diff --git a/src/lms/ui/State.cpp b/src/lms/ui/State.cpp index 46d0790a..52f6c7e1 100644 --- a/src/lms/ui/State.cpp +++ b/src/lms/ui/State.cpp @@ -20,8 +20,8 @@ #include "State.hpp" #include "database/Session.hpp" -#include "database/UIState.hpp" -#include "database/User.hpp" +#include "database/objects/UIState.hpp" +#include "database/objects/User.hpp" #include "LmsApplication.hpp" diff --git a/src/lms/ui/Utils.cpp b/src/lms/ui/Utils.cpp index ba11e50c..a8ce3a8d 100644 --- a/src/lms/ui/Utils.cpp +++ b/src/lms/ui/Utils.cpp @@ -25,14 +25,14 @@ #include #include -#include "database/Artist.hpp" -#include "database/Cluster.hpp" -#include "database/Image.hpp" -#include "database/Release.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" #include "LmsApplication.hpp" #include "ModalManager.hpp" diff --git a/src/lms/ui/Utils.hpp b/src/lms/ui/Utils.hpp index f2cdc20a..64dcd021 100644 --- a/src/lms/ui/Utils.hpp +++ b/src/lms/ui/Utils.hpp @@ -28,11 +28,11 @@ #include #include -#include "database/ArtistId.hpp" -#include "database/ClusterId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ClusterId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" #include "database/Types.hpp" #include "resource/ArtworkResource.hpp" diff --git a/src/lms/ui/admin/InitWizardView.cpp b/src/lms/ui/admin/InitWizardView.cpp index 3cec9844..0e2838ab 100644 --- a/src/lms/ui/admin/InitWizardView.cpp +++ b/src/lms/ui/admin/InitWizardView.cpp @@ -28,7 +28,7 @@ #include "core/ILogger.hpp" #include "core/Service.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "services/auth/IPasswordService.hpp" #include "LmsApplication.hpp" diff --git a/src/lms/ui/admin/MediaLibrariesView.cpp b/src/lms/ui/admin/MediaLibrariesView.cpp index 57731d91..344d0aa1 100644 --- a/src/lms/ui/admin/MediaLibrariesView.cpp +++ b/src/lms/ui/admin/MediaLibrariesView.cpp @@ -22,8 +22,8 @@ #include #include "core/Service.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" +#include "database/objects/MediaLibrary.hpp" #include "services/scanner/IScannerService.hpp" #include "LmsApplication.hpp" diff --git a/src/lms/ui/admin/MediaLibrariesView.hpp b/src/lms/ui/admin/MediaLibrariesView.hpp index 8ba277e7..f201c0cf 100644 --- a/src/lms/ui/admin/MediaLibrariesView.hpp +++ b/src/lms/ui/admin/MediaLibrariesView.hpp @@ -22,7 +22,7 @@ #include #include -#include "database/MediaLibraryId.hpp" +#include "database/objects/MediaLibraryId.hpp" namespace lms::ui { diff --git a/src/lms/ui/admin/MediaLibraryModal.cpp b/src/lms/ui/admin/MediaLibraryModal.cpp index fb9a20ba..b5b3ef3b 100644 --- a/src/lms/ui/admin/MediaLibraryModal.cpp +++ b/src/lms/ui/admin/MediaLibraryModal.cpp @@ -26,8 +26,8 @@ #include "core/Path.hpp" #include "core/String.hpp" -#include "database/MediaLibrary.hpp" #include "database/Session.hpp" +#include "database/objects/MediaLibrary.hpp" #include "LmsApplication.hpp" diff --git a/src/lms/ui/admin/MediaLibraryModal.hpp b/src/lms/ui/admin/MediaLibraryModal.hpp index 03f20689..137b5a5c 100644 --- a/src/lms/ui/admin/MediaLibraryModal.hpp +++ b/src/lms/ui/admin/MediaLibraryModal.hpp @@ -22,7 +22,7 @@ #include #include -#include "database/MediaLibraryId.hpp" +#include "database/objects/MediaLibraryId.hpp" namespace lms::ui { diff --git a/src/lms/ui/admin/ScanSettingsView.cpp b/src/lms/ui/admin/ScanSettingsView.cpp index 807d7c17..0ec0cacd 100644 --- a/src/lms/ui/admin/ScanSettingsView.cpp +++ b/src/lms/ui/admin/ScanSettingsView.cpp @@ -30,8 +30,8 @@ #include "core/Service.hpp" #include "core/String.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" +#include "database/objects/ScanSettings.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "services/scanner/IScannerService.hpp" diff --git a/src/lms/ui/admin/ScannerReportResource.cpp b/src/lms/ui/admin/ScannerReportResource.cpp index e430757f..5279d1a8 100644 --- a/src/lms/ui/admin/ScannerReportResource.cpp +++ b/src/lms/ui/admin/ScannerReportResource.cpp @@ -24,7 +24,7 @@ #include "core/String.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Track.hpp" #include "LmsApplication.hpp" #include "services/scanner/ScanErrors.hpp" diff --git a/src/lms/ui/admin/UserView.cpp b/src/lms/ui/admin/UserView.cpp index 2f6869d8..206c30ae 100644 --- a/src/lms/ui/admin/UserView.cpp +++ b/src/lms/ui/admin/UserView.cpp @@ -31,7 +31,7 @@ #include "core/Service.hpp" #include "core/String.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "services/auth/IAuthTokenService.hpp" #include "services/auth/IPasswordService.hpp" diff --git a/src/lms/ui/admin/UsersView.cpp b/src/lms/ui/admin/UsersView.cpp index 65d08173..39239e59 100644 --- a/src/lms/ui/admin/UsersView.cpp +++ b/src/lms/ui/admin/UsersView.cpp @@ -26,7 +26,7 @@ #include "core/ILogger.hpp" #include "core/Service.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/User.hpp" #include "services/auth/IPasswordService.hpp" #include "LmsApplication.hpp" diff --git a/src/lms/ui/common/LoginNameValidator.cpp b/src/lms/ui/common/LoginNameValidator.cpp index b1abc51e..c712f200 100644 --- a/src/lms/ui/common/LoginNameValidator.cpp +++ b/src/lms/ui/common/LoginNameValidator.cpp @@ -21,7 +21,7 @@ #include -#include "database/User.hpp" +#include "database/objects/User.hpp" namespace lms::ui { diff --git a/src/lms/ui/explore/ArtistCollector.cpp b/src/lms/ui/explore/ArtistCollector.cpp index e0d4907b..058dfe59 100644 --- a/src/lms/ui/explore/ArtistCollector.cpp +++ b/src/lms/ui/explore/ArtistCollector.cpp @@ -20,10 +20,10 @@ #include "ArtistCollector.hpp" #include "core/Service.hpp" -#include "database/Artist.hpp" #include "database/Session.hpp" -#include "database/TrackList.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/lms/ui/explore/ArtistCollector.hpp b/src/lms/ui/explore/ArtistCollector.hpp index 9e5967ac..7d09cdb1 100644 --- a/src/lms/ui/explore/ArtistCollector.hpp +++ b/src/lms/ui/explore/ArtistCollector.hpp @@ -22,8 +22,8 @@ #include #include "DatabaseCollectorBase.hpp" -#include "database/ArtistId.hpp" #include "database/Types.hpp" +#include "database/objects/ArtistId.hpp" namespace lms::db { diff --git a/src/lms/ui/explore/ArtistListHelpers.cpp b/src/lms/ui/explore/ArtistListHelpers.cpp index 0dadb5dc..3d81a9c8 100644 --- a/src/lms/ui/explore/ArtistListHelpers.cpp +++ b/src/lms/ui/explore/ArtistListHelpers.cpp @@ -20,7 +20,7 @@ #include -#include "database/Artist.hpp" +#include "database/objects/Artist.hpp" #include "Utils.hpp" diff --git a/src/lms/ui/explore/ArtistView.cpp b/src/lms/ui/explore/ArtistView.cpp index c2da9b5c..36a0b8f5 100644 --- a/src/lms/ui/explore/ArtistView.cpp +++ b/src/lms/ui/explore/ArtistView.cpp @@ -22,15 +22,15 @@ #include #include "core/String.hpp" -#include "database/Artist.hpp" -#include "database/ArtistInfo.hpp" -#include "database/ArtworkId.hpp" -#include "database/Cluster.hpp" -#include "database/Release.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IRecommendationService.hpp" diff --git a/src/lms/ui/explore/ArtistView.hpp b/src/lms/ui/explore/ArtistView.hpp index 4a613508..a05f3de3 100644 --- a/src/lms/ui/explore/ArtistView.hpp +++ b/src/lms/ui/explore/ArtistView.hpp @@ -21,10 +21,10 @@ #include -#include "database/ArtistId.hpp" -#include "database/ArtworkId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/ReleaseId.hpp" #include "ReleaseTypes.hpp" #include "common/Template.hpp" diff --git a/src/lms/ui/explore/ArtistsView.cpp b/src/lms/ui/explore/ArtistsView.cpp index 630d1f4f..24ef72a6 100644 --- a/src/lms/ui/explore/ArtistsView.cpp +++ b/src/lms/ui/explore/ArtistsView.cpp @@ -22,9 +22,9 @@ #include #include -#include "database/Artist.hpp" #include "database/Session.hpp" -#include "database/TrackArtistLink.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/TrackArtistLink.hpp" #include "ArtistListHelpers.hpp" #include "Filters.hpp" diff --git a/src/lms/ui/explore/Filters.cpp b/src/lms/ui/explore/Filters.cpp index 1f565c7e..e618e9e1 100644 --- a/src/lms/ui/explore/Filters.cpp +++ b/src/lms/ui/explore/Filters.cpp @@ -26,12 +26,12 @@ #include #include -#include "database/Cluster.hpp" -#include "database/LabelId.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" -#include "database/ReleaseTypeId.hpp" #include "database/Session.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/LabelId.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/ReleaseTypeId.hpp" #include "LmsApplication.hpp" #include "ModalManager.hpp" diff --git a/src/lms/ui/explore/Filters.hpp b/src/lms/ui/explore/Filters.hpp index 1407c847..c63b7398 100644 --- a/src/lms/ui/explore/Filters.hpp +++ b/src/lms/ui/explore/Filters.hpp @@ -23,7 +23,7 @@ #include #include -#include "database/Filters.hpp" +#include "database/objects/Filters.hpp" namespace lms::ui { diff --git a/src/lms/ui/explore/PlayQueueController.cpp b/src/lms/ui/explore/PlayQueueController.cpp index 2bfa0fe6..77bc8443 100644 --- a/src/lms/ui/explore/PlayQueueController.cpp +++ b/src/lms/ui/explore/PlayQueueController.cpp @@ -19,9 +19,9 @@ #include "explore/PlayQueueController.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" #include "LmsApplication.hpp" #include "PlayQueue.hpp" diff --git a/src/lms/ui/explore/PlayQueueController.hpp b/src/lms/ui/explore/PlayQueueController.hpp index 03771646..21b80255 100644 --- a/src/lms/ui/explore/PlayQueueController.hpp +++ b/src/lms/ui/explore/PlayQueueController.hpp @@ -21,10 +21,10 @@ #include -#include "database/ArtistId.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" -#include "database/TrackListId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/TrackListId.hpp" namespace lms::ui { diff --git a/src/lms/ui/explore/ReleaseCollector.cpp b/src/lms/ui/explore/ReleaseCollector.cpp index b4e25cc7..c404990c 100644 --- a/src/lms/ui/explore/ReleaseCollector.cpp +++ b/src/lms/ui/explore/ReleaseCollector.cpp @@ -20,9 +20,9 @@ #include "ReleaseCollector.hpp" #include "core/Service.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/User.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/lms/ui/explore/ReleaseCollector.hpp b/src/lms/ui/explore/ReleaseCollector.hpp index 4b002e95..cd434b54 100644 --- a/src/lms/ui/explore/ReleaseCollector.hpp +++ b/src/lms/ui/explore/ReleaseCollector.hpp @@ -23,8 +23,8 @@ #include "DatabaseCollectorBase.hpp" -#include "database/ReleaseId.hpp" #include "database/Types.hpp" +#include "database/objects/ReleaseId.hpp" namespace lms::db { diff --git a/src/lms/ui/explore/ReleaseHelpers.cpp b/src/lms/ui/explore/ReleaseHelpers.cpp index 45143712..6fe653d5 100644 --- a/src/lms/ui/explore/ReleaseHelpers.cpp +++ b/src/lms/ui/explore/ReleaseHelpers.cpp @@ -24,8 +24,8 @@ #include #include "core/EnumSet.hpp" -#include "database/Artist.hpp" -#include "database/Release.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Release.hpp" #include "Utils.hpp" diff --git a/src/lms/ui/explore/ReleaseView.cpp b/src/lms/ui/explore/ReleaseView.cpp index 8fcfa166..c9ae9de9 100644 --- a/src/lms/ui/explore/ReleaseView.cpp +++ b/src/lms/ui/explore/ReleaseView.cpp @@ -28,15 +28,15 @@ #include "av/IAudioFile.hpp" #include "core/String.hpp" -#include "database/Artist.hpp" -#include "database/Cluster.hpp" -#include "database/Release.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/lms/ui/explore/ReleaseView.hpp b/src/lms/ui/explore/ReleaseView.hpp index 2100998b..55c66ca2 100644 --- a/src/lms/ui/explore/ReleaseView.hpp +++ b/src/lms/ui/explore/ReleaseView.hpp @@ -19,9 +19,9 @@ #pragma once -#include "database/ArtworkId.hpp" #include "database/Object.hpp" -#include "database/ReleaseId.hpp" +#include "database/objects/ArtworkId.hpp" +#include "database/objects/ReleaseId.hpp" #include "common/Template.hpp" diff --git a/src/lms/ui/explore/ReleasesView.cpp b/src/lms/ui/explore/ReleasesView.cpp index 527df48f..769baafb 100644 --- a/src/lms/ui/explore/ReleasesView.cpp +++ b/src/lms/ui/explore/ReleasesView.cpp @@ -22,8 +22,8 @@ #include #include -#include "database/Release.hpp" #include "database/Session.hpp" +#include "database/objects/Release.hpp" #include "LmsApplication.hpp" #include "SortModeSelector.hpp" diff --git a/src/lms/ui/explore/TrackCollector.cpp b/src/lms/ui/explore/TrackCollector.cpp index 74baa2bf..5c7fac86 100644 --- a/src/lms/ui/explore/TrackCollector.cpp +++ b/src/lms/ui/explore/TrackCollector.cpp @@ -21,9 +21,9 @@ #include "core/Service.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" -#include "database/User.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/lms/ui/explore/TrackCollector.hpp b/src/lms/ui/explore/TrackCollector.hpp index 034d4cb6..b27ea867 100644 --- a/src/lms/ui/explore/TrackCollector.hpp +++ b/src/lms/ui/explore/TrackCollector.hpp @@ -21,7 +21,7 @@ #include -#include "database/TrackId.hpp" +#include "database/objects/TrackId.hpp" #include "DatabaseCollectorBase.hpp" diff --git a/src/lms/ui/explore/TrackListHelpers.cpp b/src/lms/ui/explore/TrackListHelpers.cpp index 5f320bff..1fea0698 100644 --- a/src/lms/ui/explore/TrackListHelpers.cpp +++ b/src/lms/ui/explore/TrackListHelpers.cpp @@ -25,14 +25,14 @@ #include "av/IAudioFile.hpp" #include "core/Service.hpp" -#include "database/Artist.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackLyrics.hpp" #include "database/Types.hpp" -#include "database/User.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackLyrics.hpp" +#include "database/objects/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" diff --git a/src/lms/ui/explore/TrackListHelpers.hpp b/src/lms/ui/explore/TrackListHelpers.hpp index 57f90b3c..3dbae791 100644 --- a/src/lms/ui/explore/TrackListHelpers.hpp +++ b/src/lms/ui/explore/TrackListHelpers.hpp @@ -27,10 +27,10 @@ #include #include "core/EnumSet.hpp" -#include "database/ArtistId.hpp" #include "database/Object.hpp" -#include "database/TrackId.hpp" #include "database/Types.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/TrackId.hpp" namespace lms::db { diff --git a/src/lms/ui/explore/TrackListView.cpp b/src/lms/ui/explore/TrackListView.cpp index 2fcb8fbe..61e9a62d 100644 --- a/src/lms/ui/explore/TrackListView.cpp +++ b/src/lms/ui/explore/TrackListView.cpp @@ -22,11 +22,11 @@ #include #include "core/String.hpp" -#include "database/Cluster.hpp" -#include "database/ScanSettings.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/ScanSettings.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" #include "LmsApplication.hpp" #include "LmsApplicationException.hpp" diff --git a/src/lms/ui/explore/TrackListView.hpp b/src/lms/ui/explore/TrackListView.hpp index 2e381f3d..8ead2f0f 100644 --- a/src/lms/ui/explore/TrackListView.hpp +++ b/src/lms/ui/explore/TrackListView.hpp @@ -19,7 +19,7 @@ #pragma once -#include "database/TrackListId.hpp" +#include "database/objects/TrackListId.hpp" #include "common/Template.hpp" diff --git a/src/lms/ui/explore/TrackListsView.cpp b/src/lms/ui/explore/TrackListsView.cpp index 4ed2bf22..7b2faca9 100644 --- a/src/lms/ui/explore/TrackListsView.cpp +++ b/src/lms/ui/explore/TrackListsView.cpp @@ -23,7 +23,7 @@ #include #include "database/Session.hpp" -#include "database/TrackList.hpp" +#include "database/objects/TrackList.hpp" #include "DropDownMenuSelector.hpp" #include "Filters.hpp" diff --git a/src/lms/ui/explore/TrackListsView.hpp b/src/lms/ui/explore/TrackListsView.hpp index 37cf3f40..03478d13 100644 --- a/src/lms/ui/explore/TrackListsView.hpp +++ b/src/lms/ui/explore/TrackListsView.hpp @@ -24,7 +24,7 @@ #include #include "database/Object.hpp" -#include "database/TrackListId.hpp" +#include "database/objects/TrackListId.hpp" #include "common/Template.hpp" diff --git a/src/lms/ui/explore/TracksView.cpp b/src/lms/ui/explore/TracksView.cpp index b83aef68..218ecb60 100644 --- a/src/lms/ui/explore/TracksView.cpp +++ b/src/lms/ui/explore/TracksView.cpp @@ -23,7 +23,7 @@ #include #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Track.hpp" #include "LmsApplication.hpp" #include "SortModeSelector.hpp" diff --git a/src/lms/ui/resource/ArtworkResource.hpp b/src/lms/ui/resource/ArtworkResource.hpp index 7b5d6a25..05d8266c 100644 --- a/src/lms/ui/resource/ArtworkResource.hpp +++ b/src/lms/ui/resource/ArtworkResource.hpp @@ -23,7 +23,7 @@ #include -#include "database/ArtworkId.hpp" +#include "database/objects/ArtworkId.hpp" namespace lms::ui { diff --git a/src/lms/ui/resource/AudioFileResource.cpp b/src/lms/ui/resource/AudioFileResource.cpp index 1a90142a..3225d8e1 100644 --- a/src/lms/ui/resource/AudioFileResource.cpp +++ b/src/lms/ui/resource/AudioFileResource.cpp @@ -26,7 +26,7 @@ #include "core/ITraceLogger.hpp" #include "core/String.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" +#include "database/objects/Track.hpp" #include "LmsApplication.hpp" diff --git a/src/lms/ui/resource/AudioFileResource.hpp b/src/lms/ui/resource/AudioFileResource.hpp index da00ae7d..f9ac913f 100644 --- a/src/lms/ui/resource/AudioFileResource.hpp +++ b/src/lms/ui/resource/AudioFileResource.hpp @@ -21,7 +21,7 @@ #include -#include "database/TrackId.hpp" +#include "database/objects/TrackId.hpp" namespace lms::ui { diff --git a/src/lms/ui/resource/AudioTranscodingResource.cpp b/src/lms/ui/resource/AudioTranscodingResource.cpp index 926985cc..0d67d7e3 100644 --- a/src/lms/ui/resource/AudioTranscodingResource.cpp +++ b/src/lms/ui/resource/AudioTranscodingResource.cpp @@ -28,8 +28,8 @@ #include "core/Service.hpp" #include "core/String.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/User.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/User.hpp" #include "services/transcoding/ITranscodingService.hpp" #include "LmsApplication.hpp" diff --git a/src/lms/ui/resource/AudioTranscodingResource.hpp b/src/lms/ui/resource/AudioTranscodingResource.hpp index 8002279f..362e1c9f 100644 --- a/src/lms/ui/resource/AudioTranscodingResource.hpp +++ b/src/lms/ui/resource/AudioTranscodingResource.hpp @@ -22,7 +22,7 @@ #include #include -#include "database/TrackId.hpp" +#include "database/objects/TrackId.hpp" namespace lms::db { diff --git a/src/lms/ui/resource/DownloadResource.cpp b/src/lms/ui/resource/DownloadResource.cpp index 3dec9d7f..0f2e8092 100644 --- a/src/lms/ui/resource/DownloadResource.cpp +++ b/src/lms/ui/resource/DownloadResource.cpp @@ -23,11 +23,11 @@ #include #include "core/ILogger.hpp" -#include "database/Artist.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackList.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackList.hpp" #include "LmsApplication.hpp" diff --git a/src/lms/ui/resource/DownloadResource.hpp b/src/lms/ui/resource/DownloadResource.hpp index b525b560..f8e91fac 100644 --- a/src/lms/ui/resource/DownloadResource.hpp +++ b/src/lms/ui/resource/DownloadResource.hpp @@ -23,10 +23,10 @@ #include #include "core/IZipper.hpp" -#include "database/ArtistId.hpp" -#include "database/ReleaseId.hpp" -#include "database/TrackId.hpp" -#include "database/TrackListId.hpp" +#include "database/objects/ArtistId.hpp" +#include "database/objects/ReleaseId.hpp" +#include "database/objects/TrackId.hpp" +#include "database/objects/TrackListId.hpp" namespace lms::ui { diff --git a/src/tools/db-generator/LmsDbGenerator.cpp b/src/tools/db-generator/LmsDbGenerator.cpp index f9aaf881..f6daa1b5 100644 --- a/src/tools/db-generator/LmsDbGenerator.cpp +++ b/src/tools/db-generator/LmsDbGenerator.cpp @@ -32,16 +32,16 @@ #include "core/Service.hpp" #include "core/StreamLogger.hpp" #include "core/SystemPaths.hpp" -#include "database/Artist.hpp" -#include "database/Cluster.hpp" #include "database/IDb.hpp" -#include "database/MediaLibrary.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" -#include "database/TrackArtistLink.hpp" -#include "database/TrackEmbeddedImage.hpp" -#include "database/TrackEmbeddedImageLink.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/MediaLibrary.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" namespace lms { diff --git a/src/tools/recommendation/LmsRecommendation.cpp b/src/tools/recommendation/LmsRecommendation.cpp index 067b3062..b5235951 100644 --- a/src/tools/recommendation/LmsRecommendation.cpp +++ b/src/tools/recommendation/LmsRecommendation.cpp @@ -27,13 +27,13 @@ #include "core/Service.hpp" #include "core/StreamLogger.hpp" #include "core/SystemPaths.hpp" -#include "database/Artist.hpp" -#include "database/Cluster.hpp" #include "database/IDb.hpp" -#include "database/Release.hpp" #include "database/Session.hpp" -#include "database/Track.hpp" #include "database/Types.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" #include "services/recommendation/IRecommendationService.hpp" namespace lms diff --git a/src/tools/similarity-parameters/LmsSimilarityParameters.cpp b/src/tools/similarity-parameters/LmsSimilarityParameters.cpp index ea0e2fa7..1f2d8a24 100644 --- a/src/tools/similarity-parameters/LmsSimilarityParameters.cpp +++ b/src/tools/similarity-parameters/LmsSimilarityParameters.cpp @@ -24,13 +24,13 @@ #include "core/Config.hpp" #include "core/Service.hpp" #include "core/StreamLogger.hpp" -#include "database/Artist.hpp" -#include "database/Cluster.hpp" #include "database/IDb.hpp" -#include "database/Release.hpp" #include "database/SessionPool.hpp" -#include "database/Track.hpp" -#include "database/TrackFeatures.hpp" +#include "database/objects/Artist.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Release.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackFeatures.hpp" #include "similarity/features/SimilarityFeaturesSearcher.hpp" #include "GeneticAlgorithm.hpp" From 59e85ee424b010e7818b0d3a1d8298343a7d03b2 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 11 Jul 2025 00:11:02 +0200 Subject: [PATCH 27/46] Added a query plan recorder for debugging purposes --- approot/admin-db.xml | 14 +++ approot/admin-debugtools.xml | 15 +++ approot/admin-tracing.xml | 3 +- approot/main.xml | 5 +- approot/messages.xml | 13 +- approot/messages_es.xml | 13 +- approot/messages_fr.xml | 13 +- approot/messages_it.xml | 13 +- approot/messages_pl.xml | 13 +- approot/messages_zh.xml | 6 + conf/lms.conf | 4 + src/libs/av/impl/AudioFile.cpp | 1 - src/libs/database/CMakeLists.txt | 1 + src/libs/database/impl/Db.cpp | 6 +- src/libs/database/impl/Db.hpp | 4 +- src/libs/database/impl/QueryPlanRecorder.cpp | 112 ++++++++++++++++++ src/libs/database/impl/QueryPlanRecorder.hpp | 48 ++++++++ src/libs/database/impl/Utils.hpp | 32 ++++- src/libs/database/impl/objects/Artwork.cpp | 1 + .../include/database/IQueryPlanRecorder.hpp | 39 ++++++ src/lms/CMakeLists.txt | 4 +- src/lms/main.cpp | 5 + src/lms/ui/LmsApplication.cpp | 23 ++-- src/lms/ui/admin/DebugToolsView.cpp | 36 ++++++ src/lms/ui/admin/DebugToolsView.hpp | 31 +++++ src/lms/ui/admin/debug/Database.cpp | 91 ++++++++++++++ .../{TracingView.hpp => debug/Database.hpp} | 4 +- .../{TracingView.cpp => debug/Tracing.cpp} | 9 +- src/lms/ui/admin/debug/Tracing.hpp | 31 +++++ 29 files changed, 546 insertions(+), 44 deletions(-) create mode 100644 approot/admin-db.xml create mode 100644 approot/admin-debugtools.xml create mode 100644 src/libs/database/impl/QueryPlanRecorder.cpp create mode 100644 src/libs/database/impl/QueryPlanRecorder.hpp create mode 100644 src/libs/database/include/database/IQueryPlanRecorder.hpp create mode 100644 src/lms/ui/admin/DebugToolsView.cpp create mode 100644 src/lms/ui/admin/DebugToolsView.hpp create mode 100644 src/lms/ui/admin/debug/Database.cpp rename src/lms/ui/admin/{TracingView.hpp => debug/Database.hpp} (92%) rename src/lms/ui/admin/{TracingView.cpp => debug/Tracing.cpp} (93%) create mode 100644 src/lms/ui/admin/debug/Tracing.hpp diff --git a/approot/admin-db.xml b/approot/admin-db.xml new file mode 100644 index 00000000..ca7246ac --- /dev/null +++ b/approot/admin-db.xml @@ -0,0 +1,14 @@ + + + + +
+
+
+ ${export-query-plans-btn class="btn btn-primary"} +
+
+
+
+ +
diff --git a/approot/admin-debugtools.xml b/approot/admin-debugtools.xml new file mode 100644 index 00000000..83025d9f --- /dev/null +++ b/approot/admin-debugtools.xml @@ -0,0 +1,15 @@ + + + + +
+ ${tr:Lms.Admin.DebugTools.Tracing.tracing} + ${tracing} +
+ ${tr:Lms.Admin.DebugTools.Db.db} + ${db} +
+ +
+ +
diff --git a/approot/admin-tracing.xml b/approot/admin-tracing.xml index eeb1ad43..5f5376a2 100644 --- a/approot/admin-tracing.xml +++ b/approot/admin-tracing.xml @@ -1,9 +1,8 @@ - +
- ${tr:Lms.Admin.Tracing.tracing}
${export-btn class="btn btn-primary"} diff --git a/approot/main.xml b/approot/main.xml index 0dea95e8..d9c0fcd4 100644 --- a/approot/main.xml +++ b/approot/main.xml @@ -44,7 +44,10 @@
  • ${scan-settings class="dropdown-item"}
  • ${scanner class="dropdown-item"}
  • ${users class="dropdown-item"}
  • -
  • ${tracing class="dropdown-item"}
  • + ${} + +
  • ${debug-tools class="dropdown-item"}
  • + ${
    } ${} diff --git a/approot/messages.xml b/approot/messages.xml index dd550f6e..070c40f2 100644 --- a/approot/messages.xml +++ b/approot/messages.xml @@ -52,10 +52,10 @@ User not found + Debug tools Libraries Scan settings Scanner - Tracing Users @@ -149,9 +149,16 @@ Step status Updating library fields: {1} entries + +Debug tools + + +Export query plans +Database + -Export traces -Tracing +Export traces +Tracing New user diff --git a/approot/messages_es.xml b/approot/messages_es.xml index 9d90a2f6..0bce3785 100644 --- a/approot/messages_es.xml +++ b/approot/messages_es.xml @@ -52,10 +52,10 @@ No existe el usuario + Herramientas de depuración Bibliotecas Opciones de escaneo Escanear - Traces Usuarios @@ -148,9 +148,16 @@ Estado de las etapas Actualizando campos de la biblioteca: {1} entradas + +Herramientas de depuración + + +Exportar planes de consulta +Base de datos + -Exportar las trazas -Trazas +Exportar las trazas +Trazas Añadir diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml index b7c94d7a..c8c654b0 100644 --- a/approot/messages_fr.xml +++ b/approot/messages_fr.xml @@ -52,10 +52,10 @@ L'utilisateur n'existe pas + Outils de débogage Bibliothèques Paramètres du scan Scanner - Traces Utilisateurs @@ -148,9 +148,16 @@ Statut de l'étape Mise à jour des champs des bibliothèques: {1} entrées + +Outils de débogage + + +Exporter les plans de requête +Base de données + -Exporter les traces -Traces +Exporter les traces +Traces Ajouter diff --git a/approot/messages_it.xml b/approot/messages_it.xml index 30894331..42a157a5 100644 --- a/approot/messages_it.xml +++ b/approot/messages_it.xml @@ -52,10 +52,10 @@ Utente non trovato + Strumenti di debug Librerie Impostazioni di scansione Scanner - Tracing Utenti @@ -148,9 +148,16 @@ Stato passo Aggiornamento dei campi della libreria: {1} voci + +Strumenti di debug + + +Esporta i piani di query +Database + -Esporta tracce -Tracing +Esporta tracce +Tracing Nuovo utente diff --git a/approot/messages_pl.xml b/approot/messages_pl.xml index 5bd2eed0..5adcdb87 100644 --- a/approot/messages_pl.xml +++ b/approot/messages_pl.xml @@ -53,10 +53,10 @@ Użytkownik nie odnaleziony + Narzędzia debugowania Biblioteki Ustawienia skanowania Skaner - Śledzenie Użytkownicy @@ -165,9 +165,16 @@ Obecny krok Aktualizowanie pól biblioteki: {1} wpisów + +Narzędzia debugowania + + +Eksportuj plany zapytań +Baza danych + -Eksportuj ślady -Śledzenie +Eksportuj ślady +Śledzenie Nowy użytkownik diff --git a/approot/messages_zh.xml b/approot/messages_zh.xml index ce6bbebb..6ca9201f 100644 --- a/approot/messages_zh.xml +++ b/approot/messages_zh.xml @@ -145,6 +145,12 @@ 当前步骤状态 + + + + + + diff --git a/conf/lms.conf b/conf/lms.conf index 0ae9ebea..4636f82e 100644 --- a/conf/lms.conf +++ b/conf/lms.conf @@ -17,7 +17,11 @@ log-min-severity = "info"; # Can be "none", "quick", or "full" db-integrity-check = "quick"; # Output db queries on stdout +# Use this only for debugging purpose, as this may impact performance db-show-queries = false; +# Record query plans for database queries. +# Use this only for debugging purposes, as this may impact performance +db-record-query-plans = false; # Listen port/addr of the web server listen-port = 5082; diff --git a/src/libs/av/impl/AudioFile.cpp b/src/libs/av/impl/AudioFile.cpp index 614c6cde..6c91c368 100644 --- a/src/libs/av/impl/AudioFile.cpp +++ b/src/libs/av/impl/AudioFile.cpp @@ -28,7 +28,6 @@ extern "C" } #include -#include #include #include "core/ILogger.hpp" diff --git a/src/libs/database/CMakeLists.txt b/src/libs/database/CMakeLists.txt index 8efc57ca..96af316e 100644 --- a/src/libs/database/CMakeLists.txt +++ b/src/libs/database/CMakeLists.txt @@ -32,6 +32,7 @@ add_library(lmsdatabase STATIC impl/IdType.cpp impl/Migration.cpp impl/Object.cpp + impl/QueryPlanRecorder.cpp impl/Session.cpp impl/SqlQuery.cpp impl/Transaction.cpp diff --git a/src/libs/database/impl/Db.cpp b/src/libs/database/impl/Db.cpp index df00596e..daa9fccd 100644 --- a/src/libs/database/impl/Db.cpp +++ b/src/libs/database/impl/Db.cpp @@ -206,7 +206,7 @@ namespace lms::db LMS_LOG(DB, INFO, "Performing quick database check..."); // Quick check is just a simple integrity check - bool quickCheckPassed{ checkDbIntegrity(*connection, IntegrityCheckType::Quick, [&](std::string_view error) { + const bool quickCheckPassed{ checkDbIntegrity(*connection, IntegrityCheckType::Quick, [&](std::string_view error) { LMS_LOG(DB, ERROR, "Quick check error: " << error); }) }; @@ -222,7 +222,7 @@ namespace lms::db LMS_LOG(DB, INFO, "Checking database integrity..."); - bool integrityCheckPassed{ checkDbIntegrity(*connection, IntegrityCheckType::Full, [&](std::string_view error) { + const bool integrityCheckPassed{ checkDbIntegrity(*connection, IntegrityCheckType::Full, [&](std::string_view error) { LMS_LOG(DB, ERROR, "Integrity check error: " << error); }) }; @@ -238,7 +238,7 @@ namespace lms::db LMS_LOG(DB, INFO, "Checking foreign key constraints..."); - bool foreignKeyConstraintsPassed{ checkDbForeignKeyConstraints(*connection, [&](std::string_view table, long long rowId, std::string_view referredTable) { + const bool foreignKeyConstraintsPassed{ checkDbForeignKeyConstraints(*connection, [&](std::string_view table, long long rowId, std::string_view referredTable) { LMS_LOG(DB, ERROR, "Foreign key constraint failed in table '" << table << "', rowid = " << rowId << ", referred table = '" << referredTable << "'"); }) }; diff --git a/src/libs/database/impl/Db.hpp b/src/libs/database/impl/Db.hpp index 98299b0e..4d39b4b9 100644 --- a/src/libs/database/impl/Db.hpp +++ b/src/libs/database/impl/Db.hpp @@ -36,8 +36,6 @@ namespace lms::db public: Db(const std::filesystem::path& dbPath, std::size_t connectionCount); - Session& getTLSSession() override; - void executeSql(const std::string& sql); private: @@ -46,6 +44,8 @@ namespace lms::db friend class Session; + Session& getTLSSession() override; + core::RecursiveSharedMutex& getMutex() { return _sharedMutex; } Wt::Dbo::SqlConnectionPool& getConnectionPool() { return *_connectionPool; } diff --git a/src/libs/database/impl/QueryPlanRecorder.cpp b/src/libs/database/impl/QueryPlanRecorder.cpp new file mode 100644 index 00000000..fef01d1c --- /dev/null +++ b/src/libs/database/impl/QueryPlanRecorder.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include "QueryPlanRecorder.hpp" + +#include +#include + +#include +#include + +#include "core/ILogger.hpp" + +namespace lms::db +{ + std::unique_ptr createQueryPlanRecorder() + { + return std::make_unique(); + } + + QueryPlanRecorder::QueryPlanRecorder() + { + LMS_LOG(DB, INFO, "Recording database query plans"); + } + + QueryPlanRecorder::~QueryPlanRecorder() = default; + + void QueryPlanRecorder::visitQueryPlans(const QueryPlanVisitor& visitor) const + { + const std::shared_lock lock{ _mutex }; + + for (const auto& [query, plan] : _queryPlans) + visitor(query, plan); + } + + void QueryPlanRecorder::recordQueryPlanIfNeeded(Wt::Dbo::Session& session, const std::string& query) + { + { + const std::shared_lock lock{ _mutex }; + + if (_queryPlans.contains(query)) + return; + } + + Wt::Dbo::Transaction transaction{ session }; + + Wt::Dbo::SqlConnection* connection{ transaction.connection() }; + auto statement{ connection->prepareStatement("EXPLAIN QUERY PLAN " + query) }; + statement->execute(); + + std::map entries{ { 0, "" } }; + std::map> relationships; + + std::string detail; + while (statement->nextRow()) + { + detail.clear(); + + int id{}; + int parent{}; + int unused{}; + + if (statement->getResult(0, &id) + && statement->getResult(1, &parent) + && statement->getResult(2, &unused) + && statement->getResult(3, &detail, static_cast(detail.capacity()))) + { + entries.emplace(id, detail); + relationships[parent].push_back(id); + } + } + + // format + std::string result; + std::function formatQuery = [&](int id, unsigned level) -> void { + for (std::size_t i{}; i < level; ++i) + result += '\t'; + + result += entries.at(id); + result += '\n'; + auto itChildren = relationships.find(id); + if (itChildren == relationships.end()) + return; + + for (int child : itChildren->second) + formatQuery(child, level + 1); + }; + + formatQuery(0, 0); + + { + const std::unique_lock lock{ _mutex }; + _queryPlans.try_emplace(query, std::move(result)); + } + } +} // namespace lms::db diff --git a/src/libs/database/impl/QueryPlanRecorder.hpp b/src/libs/database/impl/QueryPlanRecorder.hpp new file mode 100644 index 00000000..6025b7a1 --- /dev/null +++ b/src/libs/database/impl/QueryPlanRecorder.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 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 . + */ + +#pragma once + +#include +#include +#include + +#include + +#include "database/IQueryPlanRecorder.hpp" + +namespace lms::db +{ + class QueryPlanRecorder : public IQueryPlanRecorder + { + public: + QueryPlanRecorder(); + ~QueryPlanRecorder() override; + QueryPlanRecorder(const QueryPlanRecorder&) = delete; + QueryPlanRecorder& operator=(const QueryPlanRecorder&) = delete; + + void visitQueryPlans(const QueryPlanVisitor& visitor) const override; + + void recordQueryPlanIfNeeded(Wt::Dbo::Session& session, const std::string& query); + + private: + mutable std::shared_mutex _mutex; + std::map _queryPlans; + }; +} // namespace lms::db diff --git a/src/libs/database/impl/Utils.hpp b/src/libs/database/impl/Utils.hpp index 1fe3fc19..7cbd1f03 100644 --- a/src/libs/database/impl/Utils.hpp +++ b/src/libs/database/impl/Utils.hpp @@ -19,22 +19,39 @@ #pragma once -#include #include #include -#include +#include +#include +#include +#include #include #include "core/ITraceLogger.hpp" +#include "core/Service.hpp" #include "database/Types.hpp" +#include "QueryPlanRecorder.hpp" + namespace lms::db::utils { #define ESCAPE_CHAR_STR "\\" static inline constexpr char escapeChar{ '\\' }; std::string escapeLikeKeyword(std::string_view keywords); + Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime); + + namespace details + { + template + void recordQueryPlanIfNeeded(const Query& query) + { + if (IQueryPlanRecorder * recorder{ core::Service::get() }) + static_cast(recorder)->recordQueryPlanIfNeeded(query.session(), query.asString()); + } + } // namespace details + template void applyRange(Query& query, std::optional range) { @@ -82,13 +99,18 @@ namespace lms::db::utils template void forEachQueryResult(const Query& query, UnaryFunc&& func) { + details::recordQueryPlanIfNeeded(query); + LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ForEachQueryResult", "Query", query.asString()); + forEachResult(query.resultList(), std::forward(func)); } template std::vector fetchQueryResults(const Query& query) { + details::recordQueryPlanIfNeeded(query); + LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString()); auto collection{ query.resultList() }; @@ -98,6 +120,8 @@ namespace lms::db::utils template std::vector::type> fetchQueryResults(const Query& query) { + details::recordQueryPlanIfNeeded(query); + LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString()); auto collection{ query.resultList() }; @@ -107,6 +131,8 @@ namespace lms::db::utils template auto fetchQuerySingleResult(const Query& query) { + details::recordQueryPlanIfNeeded(query); + LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQuerySingleResult", "Query", query.asString()); return query.resultValue(); } @@ -183,6 +209,4 @@ namespace lms::db::utils call.run(); } } - - Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime); } // namespace lms::db::utils \ No newline at end of file diff --git a/src/libs/database/impl/objects/Artwork.cpp b/src/libs/database/impl/objects/Artwork.cpp index 444b8070..2c8a350e 100644 --- a/src/libs/database/impl/objects/Artwork.cpp +++ b/src/libs/database/impl/objects/Artwork.cpp @@ -18,6 +18,7 @@ */ #include "database/objects/Artwork.hpp" + #include #include "database/Session.hpp" diff --git a/src/libs/database/include/database/IQueryPlanRecorder.hpp b/src/libs/database/include/database/IQueryPlanRecorder.hpp new file mode 100644 index 00000000..298634c8 --- /dev/null +++ b/src/libs/database/include/database/IQueryPlanRecorder.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2025 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 . + */ + +#pragma once + +#include +#include + +namespace lms::db +{ + // Due to technical limitations, query plans are recorded globally across all databases. + // As a result, this class is implemented as a singleton rather than being owned per DB instance. + class IQueryPlanRecorder + { + public: + virtual ~IQueryPlanRecorder() = default; + + using QueryPlanVisitor = std::function; + virtual void visitQueryPlans(const QueryPlanVisitor& visitor) const = 0; + }; + + std::unique_ptr createQueryPlanRecorder(); +} // namespace lms::db diff --git a/src/lms/CMakeLists.txt b/src/lms/CMakeLists.txt index 9db7d25a..2adef2e1 100644 --- a/src/lms/CMakeLists.txt +++ b/src/lms/CMakeLists.txt @@ -14,10 +14,12 @@ add_executable(lms ui/State.cpp ui/Tooltip.cpp ui/Utils.cpp + ui/admin/debug/Database.cpp + ui/admin/debug/Tracing.cpp + ui/admin/DebugToolsView.cpp ui/admin/InitWizardView.cpp ui/admin/MediaLibrariesView.cpp ui/admin/MediaLibraryModal.cpp - ui/admin/TracingView.cpp ui/admin/ScannerController.cpp ui/admin/ScannerReportResource.cpp ui/admin/ScanSettingsView.cpp diff --git a/src/lms/main.cpp b/src/lms/main.cpp index 9110af3e..09befea6 100644 --- a/src/lms/main.cpp +++ b/src/lms/main.cpp @@ -33,6 +33,7 @@ #include "core/SystemPaths.hpp" #include "core/WtLogger.hpp" #include "database/IDb.hpp" +#include "database/IQueryPlanRecorder.hpp" #include "database/Session.hpp" #include "image/Image.hpp" #include "services/artwork/IArtworkService.hpp" @@ -315,6 +316,10 @@ namespace lms core::IOContextRunner ioContextRunner{ ioContext, getThreadCount(), "Misc" }; + core::Service queryPlanRecorder; + if (config->getBool("db-record-query-plans", false)) + queryPlanRecorder.assign(db::createQueryPlanRecorder()); + // Connection pool size must be twice the number of threads: we have at least 2 io pools with getThreadCount() each and they all may access the database auto database{ db::createDb(config->getPath("working-dir", "/var/lms") / "lms.db", getThreadCount() * 2) }; { diff --git a/src/lms/ui/LmsApplication.cpp b/src/lms/ui/LmsApplication.cpp index 3acf03b2..e6f6034e 100644 --- a/src/lms/ui/LmsApplication.cpp +++ b/src/lms/ui/LmsApplication.cpp @@ -30,6 +30,7 @@ #include "core/ITraceLogger.hpp" #include "core/Service.hpp" #include "database/IDb.hpp" +#include "database/IQueryPlanRecorder.hpp" #include "database/Session.hpp" #include "database/objects/Artist.hpp" #include "database/objects/Cluster.hpp" @@ -51,11 +52,11 @@ #include "NotificationContainer.hpp" #include "PlayQueue.hpp" #include "SettingsView.hpp" +#include "admin/DebugToolsView.hpp" #include "admin/InitWizardView.hpp" #include "admin/MediaLibrariesView.hpp" #include "admin/ScanSettingsView.hpp" #include "admin/ScannerController.hpp" -#include "admin/TracingView.hpp" #include "admin/UserView.hpp" #include "admin/UsersView.hpp" #include "common/Template.hpp" @@ -75,6 +76,8 @@ namespace lms::ui const std::string appRoot{ Wt::WApplication::appRoot() }; auto res{ std::make_shared() }; + res->use(appRoot + "admin-db"); + res->use(appRoot + "admin-debugtools"); res->use(appRoot + "admin-initwizard"); res->use(appRoot + "admin-medialibraries"); res->use(appRoot + "admin-medialibrary"); @@ -132,7 +135,7 @@ namespace lms::ui IdxAdminScanner, IdxAdminUsers, IdxAdminUser, - IdxAdminTracing, + IdxAdminDebugTools, }; void handlePathChange(Wt::WStackedWidget& stack, bool isAdmin) @@ -158,7 +161,7 @@ namespace lms::ui { "/admin/scanner", IdxAdminScanner, true, Wt::WString::tr("Lms.Admin.ScannerController.scanner") }, { "/admin/users", IdxAdminUsers, true, Wt::WString::tr("Lms.Admin.Users.users") }, { "/admin/user", IdxAdminUser, true, std::nullopt }, - { "/admin/tracing", IdxAdminTracing, true, Wt::WString::tr("Lms.Admin.Tracing.tracing") }, + { "/admin/debug-tools", IdxAdminDebugTools, true, Wt::WString::tr("Lms.Admin.DebugTools.debug-tools") }, }; LMS_LOG(UI, DEBUG, "Internal path changed to '" << wApp->internalPath() << "'"); @@ -461,11 +464,13 @@ namespace lms::ui navbar->bindNew("scan-settings", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/scan-settings" }, Wt::WString::tr("Lms.Admin.menu-scan-settings")); navbar->bindNew("scanner", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/scanner" }, Wt::WString::tr("Lms.Admin.menu-scanner")); navbar->bindNew("users", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/users" }, Wt::WString::tr("Lms.Admin.menu-users")); - // Hide the entry if the trace logger is not enabled - if (core::Service::get()) - navbar->bindNew("tracing", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/tracing" }, Wt::WString::tr("Lms.Admin.menu-tracing")); - else - navbar->bindEmpty("tracing"); + // Hide the entry if no debug service is enabled + if (core::Service::get() + || core::Service::get()) + { + navbar->setCondition("if-debug-tools", true); + navbar->bindNew("debug-tools", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/debug-tools" }, Wt::WString::tr("Lms.Admin.menu-debug-tools")); + } } // Contents @@ -486,7 +491,7 @@ namespace lms::ui mainStack->addNew(); mainStack->addNew(); mainStack->addNew(); - mainStack->addNew(); + mainStack->addNew(); } explore->getPlayQueueController().setMaxTrackCountToEnqueue(_playQueue->getCapacity()); diff --git a/src/lms/ui/admin/DebugToolsView.cpp b/src/lms/ui/admin/DebugToolsView.cpp new file mode 100644 index 00000000..570c97fa --- /dev/null +++ b/src/lms/ui/admin/DebugToolsView.cpp @@ -0,0 +1,36 @@ +/* + * 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 . + */ + +#include "DebugToolsView.hpp" + +#include "admin/debug/Database.hpp" +#include "debug/Database.hpp" +#include "debug/Tracing.hpp" + +namespace lms::ui +{ + DebugToolsView::DebugToolsView() + : Wt::WTemplate{ Wt::WString::tr("Lms.Admin.DebugTools.template") } + { + addFunction("tr", &Wt::WTemplate::Functions::tr); + + bindNew("tracing"); + bindNew("db"); + } +} // namespace lms::ui diff --git a/src/lms/ui/admin/DebugToolsView.hpp b/src/lms/ui/admin/DebugToolsView.hpp new file mode 100644 index 00000000..152f4fd5 --- /dev/null +++ b/src/lms/ui/admin/DebugToolsView.hpp @@ -0,0 +1,31 @@ +/* + * 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 . + */ + +#pragma once + +#include + +namespace lms::ui +{ + class DebugToolsView : public Wt::WTemplate + { + public: + DebugToolsView(); + }; +} // namespace lms::ui diff --git a/src/lms/ui/admin/debug/Database.cpp b/src/lms/ui/admin/debug/Database.cpp new file mode 100644 index 00000000..811afb58 --- /dev/null +++ b/src/lms/ui/admin/debug/Database.cpp @@ -0,0 +1,91 @@ +/* + * 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 . + */ + +#include "Database.hpp" + +#include +#include +#include +#include +#include + +#include "core/ITraceLogger.hpp" +#include "core/String.hpp" +#include "database/IQueryPlanRecorder.hpp" + +namespace lms::ui +{ + namespace + { + class QueryPlansReportResource : public Wt::WResource + { + public: + QueryPlansReportResource(const db::IQueryPlanRecorder& recorder) + : _recorder{ recorder } + { + } + + ~QueryPlansReportResource() + { + beingDeleted(); + } + QueryPlansReportResource(const QueryPlansReportResource&) = delete; + QueryPlansReportResource& operator=(const QueryPlansReportResource&) = delete; + + private: + void handleRequest(const Wt::Http::Request&, Wt::Http::Response& response) + { + response.setMimeType("application/text"); + + auto encodeHttpHeaderField = [](const std::string& fieldName, const std::string& fieldValue) { + // This implements RFC 5987 + return fieldName + "*=UTF-8''" + Wt::Utils::urlEncode(fieldValue); + }; + + const std::string cdp{ encodeHttpHeaderField("filename", "LMS_db_query_plans_" + core::stringUtils::toISO8601String(Wt::WDateTime::currentDateTime()) + ".txt") }; + response.addHeader("Content-Disposition", "attachment; " + cdp); + + _recorder.visitQueryPlans([&](std::string_view query, std::string_view plan) { + response.out() << query << '\n'; + response.out() << plan << "\n-------------------------\n"; + }); + } + + const db::IQueryPlanRecorder& _recorder; + }; + } // namespace + + Database::Database() + : Wt::WTemplate{ Wt::WString::tr("Lms.Admin.DebugTools.Db.template") } + { + addFunction("tr", &Wt::WTemplate::Functions::tr); + + Wt::WPushButton* dumpBtn{ bindNew("export-query-plans-btn", Wt::WString::tr("Lms.Admin.DebugTools.Db.export-query-plans")) }; + + if (const auto* recorder{ core::Service::get() }) + { + Wt::WLink link{ std::make_shared(*recorder) }; + link.setTarget(Wt::LinkTarget::NewWindow); + dumpBtn->setLink(link); + } + else + dumpBtn->setEnabled(false); + } + +} // namespace lms::ui diff --git a/src/lms/ui/admin/TracingView.hpp b/src/lms/ui/admin/debug/Database.hpp similarity index 92% rename from src/lms/ui/admin/TracingView.hpp rename to src/lms/ui/admin/debug/Database.hpp index 95318c9e..131bb017 100644 --- a/src/lms/ui/admin/TracingView.hpp +++ b/src/lms/ui/admin/debug/Database.hpp @@ -23,9 +23,9 @@ namespace lms::ui { - class TracingView : public Wt::WTemplate + class Database : public Wt::WTemplate { public: - TracingView(); + Database(); }; } // namespace lms::ui diff --git a/src/lms/ui/admin/TracingView.cpp b/src/lms/ui/admin/debug/Tracing.cpp similarity index 93% rename from src/lms/ui/admin/TracingView.cpp rename to src/lms/ui/admin/debug/Tracing.cpp index 948e32c6..26af6712 100644 --- a/src/lms/ui/admin/TracingView.cpp +++ b/src/lms/ui/admin/debug/Tracing.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "TracingView.hpp" +#include "Tracing.hpp" #include #include @@ -73,12 +73,12 @@ namespace lms::ui }; } // namespace - TracingView::TracingView() - : Wt::WTemplate{ Wt::WString::tr("Lms.Admin.Tracing.template") } + Tracing::Tracing() + : Wt::WTemplate{ Wt::WString::tr("Lms.Admin.DebugTools.Tracing.template") } { addFunction("tr", &Wt::WTemplate::Functions::tr); - Wt::WPushButton* dumpBtn{ bindNew("export-btn", Wt::WString::tr("Lms.Admin.Tracing.export-current-buffer")) }; + Wt::WPushButton* dumpBtn{ bindNew("export-btn", Wt::WString::tr("Lms.Admin.DebugTools.Tracing.export-current-buffer")) }; if (auto traceLogger{ core::Service::get() }) { @@ -89,4 +89,5 @@ namespace lms::ui else dumpBtn->setEnabled(false); } + } // namespace lms::ui diff --git a/src/lms/ui/admin/debug/Tracing.hpp b/src/lms/ui/admin/debug/Tracing.hpp new file mode 100644 index 00000000..60a2964d --- /dev/null +++ b/src/lms/ui/admin/debug/Tracing.hpp @@ -0,0 +1,31 @@ +/* + * 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 . + */ + +#pragma once + +#include + +namespace lms::ui +{ + class Tracing : public Wt::WTemplate + { + public: + Tracing(); + }; +} // namespace lms::ui From 6704762cc31b402ce024b9161cd1373bf034fffa Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 13 Jul 2025 00:06:10 +0200 Subject: [PATCH 28/46] Tentative fix for bad query perf with recent sqlite versions: limit 1 seems to be culprit --- src/libs/database/impl/Db.cpp | 88 ++++++++++++++++++- src/libs/database/impl/Db.hpp | 3 + src/libs/database/impl/Utils.hpp | 3 +- .../impl/objects/TrackEmbeddedImage.cpp | 2 +- .../steps/ScanStepAssociateReleaseImages.cpp | 14 +-- .../steps/ScanStepAssociateTrackImages.cpp | 21 +++-- 6 files changed, 116 insertions(+), 15 deletions(-) diff --git a/src/libs/database/impl/Db.cpp b/src/libs/database/impl/Db.cpp index daa9fccd..057974ab 100644 --- a/src/libs/database/impl/Db.cpp +++ b/src/libs/database/impl/Db.cpp @@ -114,7 +114,7 @@ namespace lms::db std::string table; std::string foreignTable; - // see https://www.sqlite.org/pragma.html#pragma_foreign_key_check for exepcted result + // see https://www.sqlite.org/pragma.html#pragma_foreign_key_check for expected result while (statement->nextRow()) { foreignKeyConstraintsPassed = false; @@ -132,6 +132,57 @@ namespace lms::db return foreignKeyConstraintsPassed; } + + std::optional getPageSize(Wt::Dbo::SqlConnection& connection) + { + auto statement = connection.prepareStatement("PRAGMA page_size"); + statement->execute(); + + std::optional res; + while (statement->nextRow()) + { + assert(!res); + int value{}; + if (statement->getResult(0, &value)) + res = value; + break; + } + + return res; + } + + std::optional getCacheSize(Wt::Dbo::SqlConnection& connection) + { + auto statement = connection.prepareStatement("PRAGMA cache_size"); + statement->execute(); + + std::optional res; + while (statement->nextRow()) + { + assert(!res); + int value{}; + if (statement->getResult(0, &value)) + res = value; + break; + } + + return res; + } + + void getCompileOptions(Wt::Dbo::SqlConnection& connection, std::function callback) + { + auto statement = connection.prepareStatement("PRAGMA compile_options"); + statement->execute(); + + std::string res; + while (statement->nextRow()) + { + res.clear(); + + if (statement->getResult(0, &res, static_cast(res.capacity()))) + callback(res); + } + } } // namespace std::unique_ptr createDb(const std::filesystem::path& dbPath, std::size_t connectionCount) @@ -157,6 +208,13 @@ namespace lms::db _connectionPool = std::move(connectionPool); + executeSql("PRAGMA temp_store=MEMORY"); + executeSql("PRAGMA cache_size=-8000"); + executeSql("PRAGMA automatic_index=0"); + + logPageSize(); + logCacheSize(); + logCompileOptions(); if (checkType == "quick") { performQuickCheck(); @@ -199,6 +257,34 @@ namespace lms::db return *tlsSession; } + void Db::logPageSize() + { + ScopedConnection connection{ *_connectionPool }; + const std::optional pageSize{ getPageSize(*connection) }; + + if (pageSize) + LMS_LOG(DB, INFO, "Page size set to " << *pageSize); + } + + void Db::logCacheSize() + { + ScopedConnection connection{ *_connectionPool }; + const std::optional cacheSize{ getCacheSize(*connection) }; + + if (cacheSize) + LMS_LOG(DB, INFO, "Cache size set to " << *cacheSize); + } + + void Db::logCompileOptions() + { + ScopedConnection connection{ *_connectionPool }; + + LMS_LOG(DB, INFO, "Sqlite3 compile options:"); + getCompileOptions(*connection, [](std::string_view compileOption) { + LMS_LOG(DB, INFO, compileOption); + }); + } + void Db::performQuickCheck() { ScopedConnection connection{ *_connectionPool }; diff --git a/src/libs/database/impl/Db.hpp b/src/libs/database/impl/Db.hpp index 4d39b4b9..63890021 100644 --- a/src/libs/database/impl/Db.hpp +++ b/src/libs/database/impl/Db.hpp @@ -49,6 +49,9 @@ namespace lms::db core::RecursiveSharedMutex& getMutex() { return _sharedMutex; } Wt::Dbo::SqlConnectionPool& getConnectionPool() { return *_connectionPool; } + void logPageSize(); + void logCacheSize(); + void logCompileOptions(); void performQuickCheck(); void performIntegrityCheck(); void performForeignKeyConstraintsCheck(); diff --git a/src/libs/database/impl/Utils.hpp b/src/libs/database/impl/Utils.hpp index 7cbd1f03..bb377756 100644 --- a/src/libs/database/impl/Utils.hpp +++ b/src/libs/database/impl/Utils.hpp @@ -58,7 +58,8 @@ namespace lms::db::utils if (range) { query.limit(static_cast(range->size)); - query.offset(static_cast(range->offset)); + if (range->offset != 0) + query.offset(static_cast(range->offset)); } } diff --git a/src/libs/database/impl/objects/TrackEmbeddedImage.cpp b/src/libs/database/impl/objects/TrackEmbeddedImage.cpp index c3d2bb05..aebb8580 100644 --- a/src/libs/database/impl/objects/TrackEmbeddedImage.cpp +++ b/src/libs/database/impl/objects/TrackEmbeddedImage.cpp @@ -91,7 +91,7 @@ namespace lms::db } if (params.imageType.has_value()) - query.where("+t_e_i_l.type = ?").bind(params.imageType.value()); // hack: type is a bad way to reduce the result space + query.where("t_e_i_l.type = ?").bind(params.imageType.value()); } switch (params.sortMethod) diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index 17572122..f5a589a8 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -142,9 +142,10 @@ namespace lms::scanner params.setRelease(release->getId()); params.setImageType(db::ImageType::FrontCover); params.setSortMethod(db::TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - - db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { artwork = db::Artwork::find(session, image->getId()); }); + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { + if (!artwork) + artwork = db::Artwork::find(session, image->getId()); + }); } if (artwork) @@ -156,9 +157,10 @@ namespace lms::scanner params.setRelease(release->getId()); params.setImageType(db::ImageType::Media); params.setSortMethod(db::TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - - db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { artwork = db::Artwork::find(session, image->getId()); }); + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { + if (!artwork) + artwork = db::Artwork::find(session, image->getId()); + }); } return artwork; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp index 6d4175f0..d7d7d456 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp @@ -65,8 +65,11 @@ namespace lms::scanner params.setTrack(track->getId()); params.setImageType(db::ImageType::FrontCover); params.setSortMethod(db::TrackEmbeddedImageSortMethod::SizeDesc); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); + + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { + if (!res) + res = db::Artwork::find(session, image->getId()); + }); } if (res) @@ -92,8 +95,11 @@ namespace lms::scanner params.setTrack(track->getId()); params.setImageType(db::ImageType::Media); params.setSortMethod(db::TrackEmbeddedImageSortMethod::SizeDesc); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); + + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { + if (!res) + res = db::Artwork::find(session, image->getId()); + }); } if (res) @@ -111,8 +117,11 @@ namespace lms::scanner params.setDiscNumber(discNumber); params.setImageType(db::ImageType::Media); params.setSortMethod(db::TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc); - params.setRange(db::Range{ .offset = 0, .size = 1 }); - db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { res = db::Artwork::find(session, image->getId()); }); + + db::TrackEmbeddedImage::find(session, params, [&](const db::TrackEmbeddedImage::pointer& image) { + if (!res) + res = db::Artwork::find(session, image->getId()); + }); } return res; From 5d2db5c02b0a2a77fc82ecf5f36d61b2a640f9af Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 13 Jul 2025 13:54:39 +0200 Subject: [PATCH 29/46] Reduced includes --- src/libs/database/impl/Migration.cpp | 1 - src/libs/database/impl/Session.cpp | 2 ++ src/libs/database/impl/objects/Artist.cpp | 5 +++++ src/libs/database/impl/objects/ArtistInfo.cpp | 3 +++ src/libs/database/impl/objects/Artwork.cpp | 3 +++ src/libs/database/impl/objects/AuthToken.cpp | 3 +++ src/libs/database/impl/objects/Cluster.cpp | 11 +++++++++-- src/libs/database/impl/objects/Directory.cpp | 4 ++++ src/libs/database/impl/objects/Image.cpp | 3 +++ src/libs/database/impl/objects/Listen.cpp | 6 ++++++ src/libs/database/impl/objects/MediaLibrary.cpp | 5 ++++- src/libs/database/impl/objects/PlayListFile.cpp | 4 ++++ src/libs/database/impl/objects/PlayQueue.cpp | 11 ++++++++++- src/libs/database/impl/objects/RatedArtist.cpp | 3 +++ src/libs/database/impl/objects/RatedRelease.cpp | 3 +++ src/libs/database/impl/objects/RatedTrack.cpp | 3 +++ src/libs/database/impl/objects/Release.cpp | 11 +++++++++++ src/libs/database/impl/objects/ScanSettings.cpp | 3 +++ src/libs/database/impl/objects/StarredArtist.cpp | 3 +++ src/libs/database/impl/objects/StarredRelease.cpp | 3 +++ src/libs/database/impl/objects/StarredTrack.cpp | 3 +++ src/libs/database/impl/objects/Track.cpp | 3 +++ src/libs/database/impl/objects/TrackArtistLink.cpp | 4 ++++ src/libs/database/impl/objects/TrackBookmark.cpp | 4 ++++ src/libs/database/impl/objects/TrackEmbeddedImage.cpp | 9 +++++++-- .../database/impl/objects/TrackEmbeddedImageLink.cpp | 6 ++++++ src/libs/database/impl/objects/TrackFeatures.cpp | 3 +++ src/libs/database/impl/objects/TrackList.cpp | 6 ++++++ src/libs/database/impl/objects/TrackLyrics.cpp | 4 +++- src/libs/database/impl/objects/UIState.cpp | 4 ++++ src/libs/database/impl/objects/User.cpp | 6 ++++++ src/libs/database/include/database/objects/Artist.hpp | 3 ++- .../database/include/database/objects/ArtistInfo.hpp | 2 +- .../database/include/database/objects/Artwork.hpp | 2 +- .../database/include/database/objects/AuthToken.hpp | 3 +-- .../database/include/database/objects/Cluster.hpp | 4 ++-- .../database/include/database/objects/Directory.hpp | 3 ++- src/libs/database/include/database/objects/Image.hpp | 3 ++- src/libs/database/include/database/objects/Listen.hpp | 2 +- .../include/database/objects/MediaLibrary.hpp | 2 +- .../include/database/objects/PlayListFile.hpp | 4 +++- .../database/include/database/objects/PlayQueue.hpp | 5 ++--- .../database/include/database/objects/RatedArtist.hpp | 4 +++- .../include/database/objects/RatedRelease.hpp | 4 +++- .../database/include/database/objects/RatedTrack.hpp | 4 +++- .../database/include/database/objects/Release.hpp | 3 ++- .../include/database/objects/ScanSettings.hpp | 2 +- .../include/database/objects/StarredArtist.hpp | 2 +- .../include/database/objects/StarredRelease.hpp | 2 +- .../include/database/objects/StarredTrack.hpp | 4 +++- src/libs/database/include/database/objects/Track.hpp | 4 ++-- .../include/database/objects/TrackArtistLink.hpp | 2 +- .../include/database/objects/TrackBookmark.hpp | 2 +- .../include/database/objects/TrackEmbeddedImage.hpp | 3 ++- .../database/objects/TrackEmbeddedImageLink.hpp | 2 +- .../include/database/objects/TrackFeatures.hpp | 2 +- .../database/include/database/objects/TrackList.hpp | 3 ++- .../database/include/database/objects/TrackLyrics.hpp | 3 ++- .../database/include/database/objects/UIState.hpp | 7 ++++--- src/libs/database/include/database/objects/User.hpp | 3 ++- .../impl/listenbrainz/FeedbacksSynchronizer.cpp | 1 + .../impl/listenbrainz/ListensSynchronizer.cpp | 1 + src/lms/ui/MediaPlayer.cpp | 1 + 63 files changed, 190 insertions(+), 44 deletions(-) diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index 62922926..4833d28d 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -26,7 +26,6 @@ #include "core/ITraceLogger.hpp" #include "database/Session.hpp" #include "database/objects/ScanSettings.hpp" -#include "database/objects/User.hpp" #include "Db.hpp" #include "Utils.hpp" diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index d480c8da..8d03aaef 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -19,6 +19,8 @@ #include "database/Session.hpp" +#include + #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" #include "database/objects/Artist.hpp" diff --git a/src/libs/database/impl/objects/Artist.cpp b/src/libs/database/impl/objects/Artist.cpp index 0ecda221..86d0b029 100644 --- a/src/libs/database/impl/objects/Artist.cpp +++ b/src/libs/database/impl/objects/Artist.cpp @@ -18,6 +18,7 @@ */ #include "database/objects/Artist.hpp" +#include #include #include "core/ILogger.hpp" @@ -26,13 +27,17 @@ #include "database/objects/Cluster.hpp" #include "database/objects/Directory.hpp" #include "database/objects/Release.hpp" +#include "database/objects/StarredArtist.hpp" #include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" #include "database/objects/User.hpp" #include "SqlQuery.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::Artist) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/ArtistInfo.cpp b/src/libs/database/impl/objects/ArtistInfo.cpp index 2edd646f..b7acd5d4 100644 --- a/src/libs/database/impl/objects/ArtistInfo.cpp +++ b/src/libs/database/impl/objects/ArtistInfo.cpp @@ -19,6 +19,7 @@ #include "database/objects/ArtistInfo.hpp" +#include #include #include "database/Session.hpp" @@ -30,6 +31,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/PathTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::ArtistInfo) + namespace lms::db { ArtistInfo::pointer ArtistInfo::create(Session& session) diff --git a/src/libs/database/impl/objects/Artwork.cpp b/src/libs/database/impl/objects/Artwork.cpp index 2c8a350e..e91b7d84 100644 --- a/src/libs/database/impl/objects/Artwork.cpp +++ b/src/libs/database/impl/objects/Artwork.cpp @@ -19,6 +19,7 @@ #include "database/objects/Artwork.hpp" +#include #include #include "database/Session.hpp" @@ -29,6 +30,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/PathTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::Artwork) + namespace lms::db { Artwork::Artwork(ObjectPtr trackEmbeddedImage) diff --git a/src/libs/database/impl/objects/AuthToken.cpp b/src/libs/database/impl/objects/AuthToken.cpp index 63ad027d..4f32c34b 100644 --- a/src/libs/database/impl/objects/AuthToken.cpp +++ b/src/libs/database/impl/objects/AuthToken.cpp @@ -19,6 +19,7 @@ #include "database/objects/AuthToken.hpp" +#include #include #include "database/Session.hpp" @@ -28,6 +29,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::AuthToken) + namespace lms::db { AuthToken::AuthToken(std::string_view domain, std::string_view value, const Wt::WDateTime& expiry, std::optional maxUseCount, ObjectPtr user) diff --git a/src/libs/database/impl/objects/Cluster.cpp b/src/libs/database/impl/objects/Cluster.cpp index 7816cb68..1ce9a7ee 100644 --- a/src/libs/database/impl/objects/Cluster.cpp +++ b/src/libs/database/impl/objects/Cluster.cpp @@ -19,20 +19,27 @@ #include "database/objects/Cluster.hpp" +#include + #include "database/Session.hpp" #include "database/objects/Artist.hpp" #include "database/objects/Artwork.hpp" #include "database/objects/Directory.hpp" #include "database/objects/MediaLibrary.hpp" #include "database/objects/Release.hpp" -#include "database/objects/ScanSettings.hpp" #include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackLyrics.hpp" -#include "SqlQuery.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::Cluster) +DBO_INSTANTIATE_TEMPLATES(lms::db::ClusterType) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/Directory.cpp b/src/libs/database/impl/objects/Directory.cpp index 9d180fd9..9e0a69f8 100644 --- a/src/libs/database/impl/objects/Directory.cpp +++ b/src/libs/database/impl/objects/Directory.cpp @@ -19,6 +19,8 @@ #include "database/objects/Directory.hpp" +#include + #include "database/Session.hpp" #include "database/Types.hpp" #include "database/objects/MediaLibrary.hpp" @@ -27,6 +29,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/PathTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::Directory) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/Image.cpp b/src/libs/database/impl/objects/Image.cpp index 2010547d..ec63a4fd 100644 --- a/src/libs/database/impl/objects/Image.cpp +++ b/src/libs/database/impl/objects/Image.cpp @@ -19,6 +19,7 @@ #include "database/objects/Image.hpp" +#include #include #include "database/Session.hpp" @@ -29,6 +30,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/PathTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::Image) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/Listen.cpp b/src/libs/database/impl/objects/Listen.cpp index ffd4294b..08874598 100644 --- a/src/libs/database/impl/objects/Listen.cpp +++ b/src/libs/database/impl/objects/Listen.cpp @@ -18,6 +18,10 @@ */ #include "database/objects/Listen.hpp" + +#include +#include + #include "database/Session.hpp" #include "database/objects/Track.hpp" #include "database/objects/User.hpp" @@ -26,6 +30,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::Listen) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/MediaLibrary.cpp b/src/libs/database/impl/objects/MediaLibrary.cpp index 1b6ea7cb..73c0a60d 100644 --- a/src/libs/database/impl/objects/MediaLibrary.cpp +++ b/src/libs/database/impl/objects/MediaLibrary.cpp @@ -19,8 +19,9 @@ #include "database/objects/MediaLibrary.hpp" +#include + #include "database/Session.hpp" -#include "database/objects/ScanSettings.hpp" #include "database/objects/Track.hpp" #include "Utils.hpp" @@ -28,6 +29,8 @@ #include "traits/PathTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::MediaLibrary) + namespace lms::db { MediaLibrary::MediaLibrary(std::string_view name, const std::filesystem::path& p) diff --git a/src/libs/database/impl/objects/PlayListFile.cpp b/src/libs/database/impl/objects/PlayListFile.cpp index 61f388f3..17bf4036 100644 --- a/src/libs/database/impl/objects/PlayListFile.cpp +++ b/src/libs/database/impl/objects/PlayListFile.cpp @@ -19,12 +19,14 @@ #include "database/objects/PlayListFile.hpp" +#include #include #include "core/ILogger.hpp" #include "database/Session.hpp" #include "database/objects/Directory.hpp" #include "database/objects/MediaLibrary.hpp" +#include "database/objects/Track.hpp" #include "database/objects/TrackList.hpp" #include "database/objects/User.hpp" @@ -33,6 +35,8 @@ #include "traits/PathTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::PlayListFile) + namespace lms::db { PlayListFile::PlayListFile(const std::filesystem::path& file) diff --git a/src/libs/database/impl/objects/PlayQueue.cpp b/src/libs/database/impl/objects/PlayQueue.cpp index 22fa1fd0..ddbe913c 100644 --- a/src/libs/database/impl/objects/PlayQueue.cpp +++ b/src/libs/database/impl/objects/PlayQueue.cpp @@ -19,20 +19,29 @@ #include "database/objects/PlayQueue.hpp" -#include +#include +#include #include "database/Session.hpp" +#include "database/objects/Artist.hpp" #include "database/objects/Artwork.hpp" +#include "database/objects/Cluster.hpp" #include "database/objects/Directory.hpp" #include "database/objects/MediaLibrary.hpp" #include "database/objects/Release.hpp" #include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackLyrics.hpp" #include "database/objects/User.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::PlayQueue) + namespace lms::db { PlayQueue::PlayQueue(const ObjectPtr& user, std::string_view name) diff --git a/src/libs/database/impl/objects/RatedArtist.cpp b/src/libs/database/impl/objects/RatedArtist.cpp index 7952b530..45bafda5 100644 --- a/src/libs/database/impl/objects/RatedArtist.cpp +++ b/src/libs/database/impl/objects/RatedArtist.cpp @@ -19,6 +19,7 @@ #include "database/objects/RatedArtist.hpp" +#include #include #include "database/Session.hpp" @@ -28,6 +29,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::RatedArtist) + namespace lms::db { RatedArtist::RatedArtist(ObjectPtr artist, ObjectPtr user) diff --git a/src/libs/database/impl/objects/RatedRelease.cpp b/src/libs/database/impl/objects/RatedRelease.cpp index f5562327..f0686052 100644 --- a/src/libs/database/impl/objects/RatedRelease.cpp +++ b/src/libs/database/impl/objects/RatedRelease.cpp @@ -19,6 +19,7 @@ #include "database/objects/RatedRelease.hpp" +#include #include #include "database/Session.hpp" @@ -28,6 +29,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::RatedRelease) + namespace lms::db { RatedRelease::RatedRelease(ObjectPtr release, ObjectPtr user) diff --git a/src/libs/database/impl/objects/RatedTrack.cpp b/src/libs/database/impl/objects/RatedTrack.cpp index 146b1d88..8a8a1d7d 100644 --- a/src/libs/database/impl/objects/RatedTrack.cpp +++ b/src/libs/database/impl/objects/RatedTrack.cpp @@ -19,6 +19,7 @@ #include "database/objects/RatedTrack.hpp" +#include #include #include "database/Session.hpp" @@ -28,6 +29,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::RatedTrack) + namespace lms::db { RatedTrack::RatedTrack(ObjectPtr track, ObjectPtr user) diff --git a/src/libs/database/impl/objects/Release.cpp b/src/libs/database/impl/objects/Release.cpp index bb5d82b8..2c56eb8f 100644 --- a/src/libs/database/impl/objects/Release.cpp +++ b/src/libs/database/impl/objects/Release.cpp @@ -19,6 +19,7 @@ #include "database/objects/Release.hpp" +#include #include #include "core/PartialDateTime.hpp" @@ -28,7 +29,12 @@ #include "database/objects/Artwork.hpp" #include "database/objects/Cluster.hpp" #include "database/objects/Directory.hpp" +#include "database/objects/MediaLibrary.hpp" #include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" +#include "database/objects/TrackLyrics.hpp" #include "database/objects/User.hpp" #include "SqlQuery.hpp" @@ -38,6 +44,11 @@ #include "traits/PartialDateTimeTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::Country) +DBO_INSTANTIATE_TEMPLATES(lms::db::Label) +DBO_INSTANTIATE_TEMPLATES(lms::db::Release) +DBO_INSTANTIATE_TEMPLATES(lms::db::ReleaseType) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/ScanSettings.cpp b/src/libs/database/impl/objects/ScanSettings.cpp index 961661b8..23907e24 100644 --- a/src/libs/database/impl/objects/ScanSettings.cpp +++ b/src/libs/database/impl/objects/ScanSettings.cpp @@ -19,6 +19,7 @@ #include "database/objects/ScanSettings.hpp" +#include #include #include "core/String.hpp" @@ -29,6 +30,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::ScanSettings) + namespace lms::db { ScanSettings::ScanSettings(std::string_view name) diff --git a/src/libs/database/impl/objects/StarredArtist.cpp b/src/libs/database/impl/objects/StarredArtist.cpp index ec68c229..94474f86 100644 --- a/src/libs/database/impl/objects/StarredArtist.cpp +++ b/src/libs/database/impl/objects/StarredArtist.cpp @@ -19,6 +19,7 @@ #include "database/objects/StarredArtist.hpp" +#include #include #include "database/Session.hpp" @@ -28,6 +29,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::StarredArtist) + namespace lms::db { StarredArtist::StarredArtist(ObjectPtr artist, ObjectPtr user, FeedbackBackend backend) diff --git a/src/libs/database/impl/objects/StarredRelease.cpp b/src/libs/database/impl/objects/StarredRelease.cpp index 8ace864e..54b3eadb 100644 --- a/src/libs/database/impl/objects/StarredRelease.cpp +++ b/src/libs/database/impl/objects/StarredRelease.cpp @@ -19,6 +19,7 @@ #include "database/objects/StarredRelease.hpp" +#include #include #include "database/Session.hpp" @@ -28,6 +29,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::StarredRelease) + namespace lms::db { StarredRelease::StarredRelease(ObjectPtr release, ObjectPtr user, FeedbackBackend backend) diff --git a/src/libs/database/impl/objects/StarredTrack.cpp b/src/libs/database/impl/objects/StarredTrack.cpp index 4fc4829e..74230219 100644 --- a/src/libs/database/impl/objects/StarredTrack.cpp +++ b/src/libs/database/impl/objects/StarredTrack.cpp @@ -19,6 +19,7 @@ #include "database/objects/StarredTrack.hpp" +#include #include #include "database/Session.hpp" @@ -28,6 +29,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::StarredTrack) + namespace lms::db { StarredTrack::StarredTrack(ObjectPtr track, ObjectPtr user, FeedbackBackend backend) diff --git a/src/libs/database/impl/objects/Track.cpp b/src/libs/database/impl/objects/Track.cpp index 7dd20df1..ab731be5 100644 --- a/src/libs/database/impl/objects/Track.cpp +++ b/src/libs/database/impl/objects/Track.cpp @@ -19,6 +19,7 @@ #include "database/objects/Track.hpp" +#include #include #include "core/ILogger.hpp" @@ -43,6 +44,8 @@ #include "traits/PathTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::Track) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/TrackArtistLink.cpp b/src/libs/database/impl/objects/TrackArtistLink.cpp index e2d15cac..d68d606e 100644 --- a/src/libs/database/impl/objects/TrackArtistLink.cpp +++ b/src/libs/database/impl/objects/TrackArtistLink.cpp @@ -19,6 +19,8 @@ #include "database/objects/TrackArtistLink.hpp" +#include + #include "database/Session.hpp" #include "database/objects/Artist.hpp" #include "database/objects/Track.hpp" @@ -26,6 +28,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::TrackArtistLink) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/TrackBookmark.cpp b/src/libs/database/impl/objects/TrackBookmark.cpp index f24b3755..aa358bd7 100644 --- a/src/libs/database/impl/objects/TrackBookmark.cpp +++ b/src/libs/database/impl/objects/TrackBookmark.cpp @@ -19,6 +19,8 @@ #include "database/objects/TrackBookmark.hpp" +#include + #include "database/Session.hpp" #include "database/objects/Track.hpp" #include "database/objects/User.hpp" @@ -26,6 +28,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::TrackBookmark) + namespace lms::db { TrackBookmark::TrackBookmark(ObjectPtr user, ObjectPtr track) diff --git a/src/libs/database/impl/objects/TrackEmbeddedImage.cpp b/src/libs/database/impl/objects/TrackEmbeddedImage.cpp index aebb8580..52e174f0 100644 --- a/src/libs/database/impl/objects/TrackEmbeddedImage.cpp +++ b/src/libs/database/impl/objects/TrackEmbeddedImage.cpp @@ -17,17 +17,22 @@ * along with LMS. If not, see . */ -#include "database/objects/Directory.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" + +#include #include "database/Session.hpp" #include "database/Types.hpp" #include "database/objects/Track.hpp" -#include "database/objects/TrackEmbeddedImage.hpp" + +#include "database/objects/TrackEmbeddedImageLink.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" #include "traits/ImageHashTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::TrackEmbeddedImage) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp b/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp index 9b074777..e39b2965 100644 --- a/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp +++ b/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp @@ -19,6 +19,9 @@ #include "database/objects/TrackEmbeddedImageLink.hpp" +#include +#include + #include "database/Session.hpp" #include "database/Types.hpp" #include "database/objects/Track.hpp" @@ -26,6 +29,9 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +#include "traits/ImageHashTypeTraits.hpp" + +DBO_INSTANTIATE_TEMPLATES(lms::db::TrackEmbeddedImageLink) namespace lms::db { diff --git a/src/libs/database/impl/objects/TrackFeatures.cpp b/src/libs/database/impl/objects/TrackFeatures.cpp index c2557560..46c9607a 100644 --- a/src/libs/database/impl/objects/TrackFeatures.cpp +++ b/src/libs/database/impl/objects/TrackFeatures.cpp @@ -19,6 +19,7 @@ #include "database/objects/TrackFeatures.hpp" +#include #include #include @@ -30,6 +31,8 @@ #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::TrackFeatures) + namespace lms::db { diff --git a/src/libs/database/impl/objects/TrackList.cpp b/src/libs/database/impl/objects/TrackList.cpp index 0ef495dc..de77c518 100644 --- a/src/libs/database/impl/objects/TrackList.cpp +++ b/src/libs/database/impl/objects/TrackList.cpp @@ -20,6 +20,9 @@ #include +#include +#include + #include "database/Session.hpp" #include "database/objects/Cluster.hpp" #include "database/objects/PlayListFile.hpp" @@ -31,6 +34,9 @@ #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::TrackList) +DBO_INSTANTIATE_TEMPLATES(lms::db::TrackListEntry) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/TrackLyrics.cpp b/src/libs/database/impl/objects/TrackLyrics.cpp index 3285e676..e580efbe 100644 --- a/src/libs/database/impl/objects/TrackLyrics.cpp +++ b/src/libs/database/impl/objects/TrackLyrics.cpp @@ -19,7 +19,7 @@ #include "database/objects/TrackLyrics.hpp" -#include +#include #include #include "database/Session.hpp" @@ -32,6 +32,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/PathTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::TrackLyrics) + namespace lms::db { namespace diff --git a/src/libs/database/impl/objects/UIState.cpp b/src/libs/database/impl/objects/UIState.cpp index 4d495534..8b4b07cc 100644 --- a/src/libs/database/impl/objects/UIState.cpp +++ b/src/libs/database/impl/objects/UIState.cpp @@ -19,6 +19,8 @@ #include "database/objects/UIState.hpp" +#include + #include "database/Session.hpp" #include "database/objects/User.hpp" @@ -26,6 +28,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::UIState) + namespace lms::db { UIState::UIState(std::string_view item, ObjectPtr user) diff --git a/src/libs/database/impl/objects/User.cpp b/src/libs/database/impl/objects/User.cpp index bd1932ec..1bc03388 100644 --- a/src/libs/database/impl/objects/User.cpp +++ b/src/libs/database/impl/objects/User.cpp @@ -21,8 +21,12 @@ #include +#include +#include + #include "database/Session.hpp" #include "database/objects/Artist.hpp" +#include "database/objects/AuthToken.hpp" #include "database/objects/Release.hpp" #include "database/objects/Track.hpp" #include "database/objects/UIState.hpp" @@ -32,6 +36,8 @@ #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" +DBO_INSTANTIATE_TEMPLATES(lms::db::User) + namespace lms::db { User::User(std::string_view loginName) diff --git a/src/libs/database/include/database/objects/Artist.hpp b/src/libs/database/include/database/objects/Artist.hpp index 762e6f4a..b33e1705 100644 --- a/src/libs/database/include/database/objects/Artist.hpp +++ b/src/libs/database/include/database/objects/Artist.hpp @@ -25,7 +25,8 @@ #include #include -#include +#include +#include #include #include "core/EnumSet.hpp" diff --git a/src/libs/database/include/database/objects/ArtistInfo.hpp b/src/libs/database/include/database/objects/ArtistInfo.hpp index bf371220..28d5e4b8 100644 --- a/src/libs/database/include/database/objects/ArtistInfo.hpp +++ b/src/libs/database/include/database/objects/ArtistInfo.hpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/Artwork.hpp b/src/libs/database/include/database/objects/Artwork.hpp index 44e08075..50b7626a 100644 --- a/src/libs/database/include/database/objects/Artwork.hpp +++ b/src/libs/database/include/database/objects/Artwork.hpp @@ -21,7 +21,7 @@ #include -#include +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/AuthToken.hpp b/src/libs/database/include/database/objects/AuthToken.hpp index 08a067ec..755d468d 100644 --- a/src/libs/database/include/database/objects/AuthToken.hpp +++ b/src/libs/database/include/database/objects/AuthToken.hpp @@ -22,11 +22,10 @@ #include #include -#include +#include #include #include "database/Object.hpp" -#include "database/Types.hpp" #include "database/objects/AuthTokenId.hpp" #include "database/objects/UserId.hpp" diff --git a/src/libs/database/include/database/objects/Cluster.hpp b/src/libs/database/include/database/objects/Cluster.hpp index 7c7c37cd..f30e343d 100644 --- a/src/libs/database/include/database/objects/Cluster.hpp +++ b/src/libs/database/include/database/objects/Cluster.hpp @@ -22,10 +22,10 @@ #include #include #include -#include #include -#include +#include +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/Directory.hpp b/src/libs/database/include/database/objects/Directory.hpp index 7a1eda7b..58390b03 100644 --- a/src/libs/database/include/database/objects/Directory.hpp +++ b/src/libs/database/include/database/objects/Directory.hpp @@ -21,11 +21,12 @@ #include #include +#include #include #include #include -#include +#include #include "core/EnumSet.hpp" #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/Image.hpp b/src/libs/database/include/database/objects/Image.hpp index 79985fee..da4c48bf 100644 --- a/src/libs/database/include/database/objects/Image.hpp +++ b/src/libs/database/include/database/objects/Image.hpp @@ -21,8 +21,9 @@ #include #include +#include -#include +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/Listen.hpp b/src/libs/database/include/database/objects/Listen.hpp index a028da5e..b6882fa2 100644 --- a/src/libs/database/include/database/objects/Listen.hpp +++ b/src/libs/database/include/database/objects/Listen.hpp @@ -21,7 +21,7 @@ #include -#include +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/MediaLibrary.hpp b/src/libs/database/include/database/objects/MediaLibrary.hpp index c52881ef..484f4e5a 100644 --- a/src/libs/database/include/database/objects/MediaLibrary.hpp +++ b/src/libs/database/include/database/objects/MediaLibrary.hpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include "database/Object.hpp" #include "database/objects/MediaLibraryId.hpp" diff --git a/src/libs/database/include/database/objects/PlayListFile.hpp b/src/libs/database/include/database/objects/PlayListFile.hpp index bfcc6811..c6443d0e 100644 --- a/src/libs/database/include/database/objects/PlayListFile.hpp +++ b/src/libs/database/include/database/objects/PlayListFile.hpp @@ -24,7 +24,9 @@ #include #include -#include +#include +#include +#include #include #include "database/IdRange.hpp" diff --git a/src/libs/database/include/database/objects/PlayQueue.hpp b/src/libs/database/include/database/objects/PlayQueue.hpp index 68e39d4e..845db082 100644 --- a/src/libs/database/include/database/objects/PlayQueue.hpp +++ b/src/libs/database/include/database/objects/PlayQueue.hpp @@ -20,15 +20,14 @@ #pragma once #include -#include #include #include -#include +#include +#include #include #include "database/Object.hpp" -#include "database/Types.hpp" #include "database/objects/TrackId.hpp" #include "database/objects/UserId.hpp" diff --git a/src/libs/database/include/database/objects/RatedArtist.hpp b/src/libs/database/include/database/objects/RatedArtist.hpp index ac21bc6a..0a336d08 100644 --- a/src/libs/database/include/database/objects/RatedArtist.hpp +++ b/src/libs/database/include/database/objects/RatedArtist.hpp @@ -19,7 +19,9 @@ #pragma once -#include +#include + +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/RatedRelease.hpp b/src/libs/database/include/database/objects/RatedRelease.hpp index 374de014..4096f380 100644 --- a/src/libs/database/include/database/objects/RatedRelease.hpp +++ b/src/libs/database/include/database/objects/RatedRelease.hpp @@ -19,7 +19,9 @@ #pragma once -#include +#include + +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/RatedTrack.hpp b/src/libs/database/include/database/objects/RatedTrack.hpp index 32d49b87..de944e5b 100644 --- a/src/libs/database/include/database/objects/RatedTrack.hpp +++ b/src/libs/database/include/database/objects/RatedTrack.hpp @@ -19,7 +19,9 @@ #pragma once -#include +#include + +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/Release.hpp b/src/libs/database/include/database/objects/Release.hpp index 9895b8c2..1f8085c0 100644 --- a/src/libs/database/include/database/objects/Release.hpp +++ b/src/libs/database/include/database/objects/Release.hpp @@ -24,7 +24,8 @@ #include #include -#include +#include +#include #include #include "core/EnumSet.hpp" diff --git a/src/libs/database/include/database/objects/ScanSettings.hpp b/src/libs/database/include/database/objects/ScanSettings.hpp index 4da2ef94..83f3e7ac 100644 --- a/src/libs/database/include/database/objects/ScanSettings.hpp +++ b/src/libs/database/include/database/objects/ScanSettings.hpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include "database/IdType.hpp" diff --git a/src/libs/database/include/database/objects/StarredArtist.hpp b/src/libs/database/include/database/objects/StarredArtist.hpp index bcc69e79..3bca8939 100644 --- a/src/libs/database/include/database/objects/StarredArtist.hpp +++ b/src/libs/database/include/database/objects/StarredArtist.hpp @@ -19,7 +19,7 @@ #pragma once -#include +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/StarredRelease.hpp b/src/libs/database/include/database/objects/StarredRelease.hpp index 4fc66cdf..6f172d38 100644 --- a/src/libs/database/include/database/objects/StarredRelease.hpp +++ b/src/libs/database/include/database/objects/StarredRelease.hpp @@ -19,7 +19,7 @@ #pragma once -#include +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/StarredTrack.hpp b/src/libs/database/include/database/objects/StarredTrack.hpp index bcd127ee..352b1ba7 100644 --- a/src/libs/database/include/database/objects/StarredTrack.hpp +++ b/src/libs/database/include/database/objects/StarredTrack.hpp @@ -19,7 +19,9 @@ #pragma once -#include +#include + +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/Track.hpp b/src/libs/database/include/database/objects/Track.hpp index 1d9e1013..39c5b624 100644 --- a/src/libs/database/include/database/objects/Track.hpp +++ b/src/libs/database/include/database/objects/Track.hpp @@ -27,8 +27,8 @@ #include #include -#include -#include +#include +#include #include #include "core/EnumSet.hpp" diff --git a/src/libs/database/include/database/objects/TrackArtistLink.hpp b/src/libs/database/include/database/objects/TrackArtistLink.hpp index 6ad1801e..1f9e6117 100644 --- a/src/libs/database/include/database/objects/TrackArtistLink.hpp +++ b/src/libs/database/include/database/objects/TrackArtistLink.hpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include "core/EnumSet.hpp" #include "database/IdType.hpp" diff --git a/src/libs/database/include/database/objects/TrackBookmark.hpp b/src/libs/database/include/database/objects/TrackBookmark.hpp index 016f69be..833747e8 100644 --- a/src/libs/database/include/database/objects/TrackBookmark.hpp +++ b/src/libs/database/include/database/objects/TrackBookmark.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include "database/IdType.hpp" #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp b/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp index c4187ddc..c9ea94a3 100644 --- a/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp +++ b/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp @@ -23,7 +23,8 @@ #include #include -#include +#include +#include #include "core/EnumSet.hpp" #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp b/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp index fe94213a..ea670888 100644 --- a/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp +++ b/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include "database/Object.hpp" #include "database/Types.hpp" diff --git a/src/libs/database/include/database/objects/TrackFeatures.hpp b/src/libs/database/include/database/objects/TrackFeatures.hpp index 6530a214..bea09c34 100644 --- a/src/libs/database/include/database/objects/TrackFeatures.hpp +++ b/src/libs/database/include/database/objects/TrackFeatures.hpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include "database/IdType.hpp" #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/TrackList.hpp b/src/libs/database/include/database/objects/TrackList.hpp index 27fe17fe..37647203 100644 --- a/src/libs/database/include/database/objects/TrackList.hpp +++ b/src/libs/database/include/database/objects/TrackList.hpp @@ -24,7 +24,8 @@ #include #include -#include +#include +#include #include #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/TrackLyrics.hpp b/src/libs/database/include/database/objects/TrackLyrics.hpp index e8d7bbee..dd7c5c9c 100644 --- a/src/libs/database/include/database/objects/TrackLyrics.hpp +++ b/src/libs/database/include/database/objects/TrackLyrics.hpp @@ -22,10 +22,11 @@ #include #include #include +#include #include #include -#include +#include #include "database/IdType.hpp" #include "database/Object.hpp" diff --git a/src/libs/database/include/database/objects/UIState.hpp b/src/libs/database/include/database/objects/UIState.hpp index fcd4320f..458350e4 100644 --- a/src/libs/database/include/database/objects/UIState.hpp +++ b/src/libs/database/include/database/objects/UIState.hpp @@ -19,11 +19,12 @@ #pragma once -#include +#include +#include + +#include -#include "core/String.hpp" #include "database/Object.hpp" -#include "database/Types.hpp" #include "database/objects/UIStateId.hpp" #include "database/objects/UserId.hpp" diff --git a/src/libs/database/include/database/objects/User.hpp b/src/libs/database/include/database/objects/User.hpp index 78ae5a75..ba731886 100644 --- a/src/libs/database/include/database/objects/User.hpp +++ b/src/libs/database/include/database/objects/User.hpp @@ -22,7 +22,8 @@ #include #include -#include +#include +#include #include #include "core/EnumSet.hpp" diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp index 7b69456d..1a07b794 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp index 9d78f95c..192695fa 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/src/lms/ui/MediaPlayer.cpp b/src/lms/ui/MediaPlayer.cpp index 7bddd090..0bc6d444 100644 --- a/src/lms/ui/MediaPlayer.cpp +++ b/src/lms/ui/MediaPlayer.cpp @@ -20,6 +20,7 @@ #include "MediaPlayer.hpp" #include +#include #include #include #include From 5c8a18d86e43de8fcef6243e100d04afe1ff7300 Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 14 Jul 2025 15:14:20 +0200 Subject: [PATCH 30/46] Fixed fallback artworks not shown when removed from library (and scan not triggered yet) --- src/lms/ui/MediaPlayer.cpp | 8 +-- src/lms/ui/PlayQueue.cpp | 4 +- src/lms/ui/Utils.cpp | 22 ++------ src/lms/ui/Utils.hpp | 6 +-- src/lms/ui/explore/ArtistListHelpers.cpp | 4 +- src/lms/ui/explore/ArtistView.cpp | 6 +-- src/lms/ui/explore/ReleaseHelpers.cpp | 4 +- src/lms/ui/explore/ReleaseView.cpp | 10 ++-- src/lms/ui/explore/TrackListHelpers.cpp | 6 +-- src/lms/ui/resource/ArtworkResource.cpp | 65 +++++++++++++----------- src/lms/ui/resource/ArtworkResource.hpp | 12 +++-- 11 files changed, 72 insertions(+), 75 deletions(-) diff --git a/src/lms/ui/MediaPlayer.cpp b/src/lms/ui/MediaPlayer.cpp index 0bc6d444..f423ebf7 100644 --- a/src/lms/ui/MediaPlayer.cpp +++ b/src/lms/ui/MediaPlayer.cpp @@ -259,15 +259,17 @@ namespace lms::ui artworkId = track->getPreferredArtworkId(); if (artworkId.isValid()) { + // Potential issue: If the image is really not here, we fall back on a default svg image: the provided type does not match, so we don't put type here + // Another solution would be to test the image presence and put type accordingly oss << " artwork: [" - << " { src: \"" << LmsApp->getArtworkResource()->getArtworkUrl(artworkId, ArtworkResource::Size::Small) << "\", sizes: \"128x128\", type: \"image/jpeg\" }," - << " { src: \"" << LmsApp->getArtworkResource()->getArtworkUrl(artworkId, ArtworkResource::Size::Large) << "\", sizes: \"512x512\", type: \"image/jpeg\" }," + << " { src: \"" << LmsApp->getArtworkResource()->getArtworkUrl(artworkId, ArtworkResource::DefaultArtworkType::Track, ArtworkResource::Size::Small) << "\", sizes: \"128x128\" }," + << " { src: \"" << LmsApp->getArtworkResource()->getArtworkUrl(artworkId, ArtworkResource::DefaultArtworkType::Track, ArtworkResource::Size::Large) << "\", sizes: \"512x512\" }," << " ]"; } else { oss << " artwork: [" - << " { src: \"" << LmsApp->getArtworkResource()->getDefaultTrackArtworkUrl() << "\", type: \"image/svg+xml\" }," + << " { src: \"" << LmsApp->getArtworkResource()->getDefaultArtworkUrl(ArtworkResource::DefaultArtworkType::Track) << "\", type: \"image/svg+xml\" }," << " ]"; } oss << "};"; diff --git a/src/lms/ui/PlayQueue.cpp b/src/lms/ui/PlayQueue.cpp index 3290581b..f152b434 100644 --- a/src/lms/ui/PlayQueue.cpp +++ b/src/lms/ui/PlayQueue.cpp @@ -496,9 +496,9 @@ namespace lms::ui std::unique_ptr image; if (artworkId.isValid()) - image = utils::createArtworkImage(artworkId, ArtworkResource::Size::Small); + image = utils::createArtworkImage(artworkId, ArtworkResource::DefaultArtworkType::Track, ArtworkResource::Size::Small); else - image = utils::createDefaultTrackArtworkImage(); + image = utils::createDefaultArtworkImage(ArtworkResource::DefaultArtworkType::Track); image->addStyleClass("Lms-cover-track rounded"); // HACK diff --git a/src/lms/ui/Utils.cpp b/src/lms/ui/Utils.cpp index a8ce3a8d..ac813775 100644 --- a/src/lms/ui/Utils.cpp +++ b/src/lms/ui/Utils.cpp @@ -88,31 +88,17 @@ namespace lms::ui::utils LmsApp->getModalManager().show(std::move(rawImage)); } - std::unique_ptr createArtworkImage(db::ArtworkId artworkId, ArtworkResource::Size size) + std::unique_ptr createArtworkImage(db::ArtworkId artworkId, ArtworkResource::DefaultArtworkType type, ArtworkResource::Size size) { auto image{ createArtworkImage() }; - image->setImageLink(LmsApp->getArtworkResource()->getArtworkUrl(artworkId, size)); + image->setImageLink(LmsApp->getArtworkResource()->getArtworkUrl(artworkId, type, size)); return image; } - std::unique_ptr createDefaultArtistArtworkImage() + std::unique_ptr createDefaultArtworkImage(ArtworkResource::DefaultArtworkType type) { auto image{ createArtworkImage() }; - image->setImageLink(LmsApp->getArtworkResource()->getDefaultArtistArtworkUrl()); - return image; - } - - std::unique_ptr createDefaultReleaseArtworkImage() - { - auto image{ createArtworkImage() }; - image->setImageLink(LmsApp->getArtworkResource()->getDefaultReleaseArtworkUrl()); - return image; - } - - std::unique_ptr createDefaultTrackArtworkImage() - { - auto image{ createArtworkImage() }; - image->setImageLink(LmsApp->getArtworkResource()->getDefaultTrackArtworkUrl()); + image->setImageLink(LmsApp->getArtworkResource()->getDefaultArtworkUrl(type)); return image; } diff --git a/src/lms/ui/Utils.hpp b/src/lms/ui/Utils.hpp index 64dcd021..0c849fde 100644 --- a/src/lms/ui/Utils.hpp +++ b/src/lms/ui/Utils.hpp @@ -57,10 +57,8 @@ namespace lms::ui::utils void showArtworkModal(Wt::WLink image); - std::unique_ptr createArtworkImage(db::ArtworkId artworkId, ArtworkResource::Size size); - std::unique_ptr createDefaultArtistArtworkImage(); - std::unique_ptr createDefaultReleaseArtworkImage(); - std::unique_ptr createDefaultTrackArtworkImage(); + std::unique_ptr createArtworkImage(db::ArtworkId artworkId, ArtworkResource::DefaultArtworkType type, ArtworkResource::Size size); + std::unique_ptr createDefaultArtworkImage(ArtworkResource::DefaultArtworkType type); std::unique_ptr createFilter(const Wt::WString& name, const Wt::WString& tooltip, std::string_view colorStyleClass, bool canDelete = false); std::unique_ptr createFilterCluster(db::ClusterId clusterId, bool canDelete = false); diff --git a/src/lms/ui/explore/ArtistListHelpers.cpp b/src/lms/ui/explore/ArtistListHelpers.cpp index 3d81a9c8..300e6d58 100644 --- a/src/lms/ui/explore/ArtistListHelpers.cpp +++ b/src/lms/ui/explore/ArtistListHelpers.cpp @@ -35,9 +35,9 @@ namespace lms::ui::ArtistListHelpers std::unique_ptr image; if (artist->getPreferredArtworkId().isValid()) - image = utils::createArtworkImage(artist->getPreferredArtworkId(), ArtworkResource::Size::Large); + image = utils::createArtworkImage(artist->getPreferredArtworkId(), ArtworkResource::DefaultArtworkType::Artist, ArtworkResource::Size::Large); else - image = utils::createDefaultArtistArtworkImage(); + image = utils::createDefaultArtworkImage(ArtworkResource::DefaultArtworkType::Artist); image->addStyleClass("Lms-image-artist Lms-cover-anchor"); // hack anchor->setImage(std::move(image)); diff --git a/src/lms/ui/explore/ArtistView.cpp b/src/lms/ui/explore/ArtistView.cpp index 36a0b8f5..38a8c8bc 100644 --- a/src/lms/ui/explore/ArtistView.cpp +++ b/src/lms/ui/explore/ArtistView.cpp @@ -197,17 +197,17 @@ namespace lms::ui std::unique_ptr artworkImage; if (artworkId.isValid()) { - artworkImage = utils::createArtworkImage(artworkId, ArtworkResource::Size::Large); + artworkImage = utils::createArtworkImage(artworkId, ArtworkResource::DefaultArtworkType::Artist, ArtworkResource::Size::Large); artworkImage->addStyleClass("Lms-cursor-pointer"); // HACK } else - artworkImage = utils::createDefaultArtistArtworkImage(); + artworkImage = utils::createDefaultArtworkImage(ArtworkResource::DefaultArtworkType::Artist); auto* image{ bindWidget("artwork", std::move(artworkImage)) }; if (artworkId.isValid()) { image->clicked().connect([artworkId] { - utils::showArtworkModal(Wt::WLink{ LmsApp->getArtworkResource()->getArtworkUrl(artworkId) }); + utils::showArtworkModal(Wt::WLink{ LmsApp->getArtworkResource()->getArtworkUrl(artworkId, ArtworkResource::DefaultArtworkType::Artist) }); }); } } diff --git a/src/lms/ui/explore/ReleaseHelpers.cpp b/src/lms/ui/explore/ReleaseHelpers.cpp index 6fe653d5..f01ec00f 100644 --- a/src/lms/ui/explore/ReleaseHelpers.cpp +++ b/src/lms/ui/explore/ReleaseHelpers.cpp @@ -54,9 +54,9 @@ namespace lms::ui::releaseListHelpers std::unique_ptr image; if (release->getPreferredArtworkId().isValid()) - image = utils::createArtworkImage(release->getPreferredArtworkId(), ArtworkResource::Size::Large); + image = utils::createArtworkImage(release->getPreferredArtworkId(), ArtworkResource::DefaultArtworkType::Release, ArtworkResource::Size::Large); else - image = utils::createDefaultReleaseArtworkImage(); + image = utils::createDefaultArtworkImage(ArtworkResource::DefaultArtworkType::Release); image->addStyleClass("Lms-cover-release Lms-cover-anchor rounded"); // hack anchor->setImage(std::move(image)); diff --git a/src/lms/ui/explore/ReleaseView.cpp b/src/lms/ui/explore/ReleaseView.cpp index c9ae9de9..4b5697be 100644 --- a/src/lms/ui/explore/ReleaseView.cpp +++ b/src/lms/ui/explore/ReleaseView.cpp @@ -396,13 +396,13 @@ namespace lms::ui if (mediaArtworkId.isValid()) { - auto image{ utils::createArtworkImage(mediaArtworkId, ArtworkResource::Size::Small) }; + auto image{ utils::createArtworkImage(mediaArtworkId, ArtworkResource::DefaultArtworkType::Release, ArtworkResource::Size::Small) }; disc->setCondition("if-has-artwork", true); image->addStyleClass("Lms-cover-track rounded"); // HACK image->clicked().connect([=] { - utils::showArtworkModal(Wt::WLink{ LmsApp->getArtworkResource()->getArtworkUrl(mediaArtworkId) }); + utils::showArtworkModal(Wt::WLink{ LmsApp->getArtworkResource()->getArtworkUrl(mediaArtworkId, ArtworkResource::DefaultArtworkType::Release) }); }); disc->bindWidget("artwork", std::move(image)); } @@ -570,17 +570,17 @@ namespace lms::ui std::unique_ptr artworkImage; if (artworkId.isValid()) { - artworkImage = utils::createArtworkImage(artworkId, ArtworkResource::Size::Large); + artworkImage = utils::createArtworkImage(artworkId, ArtworkResource::DefaultArtworkType::Release, ArtworkResource::Size::Large); artworkImage->addStyleClass("Lms-cursor-pointer"); // HACK } else - artworkImage = utils::createDefaultReleaseArtworkImage(); + artworkImage = utils::createDefaultArtworkImage(ArtworkResource::DefaultArtworkType::Release); auto* image{ bindWidget("artwork", std::move(artworkImage)) }; if (artworkId.isValid()) { image->clicked().connect([artworkId] { - utils::showArtworkModal(Wt::WLink{ LmsApp->getArtworkResource()->getArtworkUrl(artworkId) }); + utils::showArtworkModal(Wt::WLink{ LmsApp->getArtworkResource()->getArtworkUrl(artworkId, ArtworkResource::DefaultArtworkType::Release) }); }); } } diff --git a/src/lms/ui/explore/TrackListHelpers.cpp b/src/lms/ui/explore/TrackListHelpers.cpp index 1fea0698..2cc0bc2f 100644 --- a/src/lms/ui/explore/TrackListHelpers.cpp +++ b/src/lms/ui/explore/TrackListHelpers.cpp @@ -230,11 +230,11 @@ namespace lms::ui::TrackListHelpers std::unique_ptr image; if (track->getPreferredMediaArtworkId().isValid()) - image = utils::createArtworkImage(track->getPreferredMediaArtworkId(), ArtworkResource::Size::Small); + image = utils::createArtworkImage(track->getPreferredMediaArtworkId(), ArtworkResource::DefaultArtworkType::Track, ArtworkResource::Size::Small); else if (track->getPreferredArtworkId().isValid()) - image = utils::createArtworkImage(track->getPreferredArtworkId(), ArtworkResource::Size::Small); + image = utils::createArtworkImage(track->getPreferredArtworkId(), ArtworkResource::DefaultArtworkType::Track, ArtworkResource::Size::Small); else - image = utils::createDefaultTrackArtworkImage(); + image = utils::createDefaultArtworkImage(ArtworkResource::DefaultArtworkType::Track); image->addStyleClass("Lms-cover-track rounded"); // hack if (track->getRelease()) diff --git a/src/lms/ui/resource/ArtworkResource.cpp b/src/lms/ui/resource/ArtworkResource.cpp index 20b341ed..cb7a5893 100644 --- a/src/lms/ui/resource/ArtworkResource.cpp +++ b/src/lms/ui/resource/ArtworkResource.cpp @@ -34,6 +34,26 @@ namespace lms::ui { + namespace + { + std::string_view getDefaultArtworkPart(ArtworkResource::DefaultArtworkType fallbackType) + { + std::string_view res; + switch (fallbackType) + { + case ArtworkResource::DefaultArtworkType::Release: + case ArtworkResource::DefaultArtworkType::Track: + res = "&fallback=defrelease"; + break; + + case ArtworkResource::DefaultArtworkType::Artist: + res = "&fallback=defartist"; + } + + return res; + } + } // namespace + ArtworkResource::ArtworkResource() { LmsApp->getScannerEvents().scanComplete.connect(this, [this](const scanner::ScanStats& stats) { @@ -47,28 +67,22 @@ namespace lms::ui beingDeleted(); } - std::string ArtworkResource::getArtworkUrl(db::ArtworkId artworkId, std::optional size) const + std::string ArtworkResource::getArtworkUrl(db::ArtworkId artworkId, DefaultArtworkType fallbackType, std::optional size) const { std::string res{ url() + "&artworkid=" + artworkId.toString() }; if (size) res += "&size=" + std::to_string(static_cast(*size)); + res += getDefaultArtworkPart(fallbackType); + return res; } - std::string ArtworkResource::getDefaultArtistArtworkUrl() const + std::string ArtworkResource::getDefaultArtworkUrl(DefaultArtworkType type) const { - return url() + "&type=defartist"; - } - - std::string ArtworkResource::getDefaultReleaseArtworkUrl() const - { - return url() + "&type=defrelease"; - } - - std::string ArtworkResource::getDefaultTrackArtworkUrl() const - { - return url() + "&type=defrelease"; + std::string res{ url() }; + res += getDefaultArtworkPart(type); + return res; } void ArtworkResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response) @@ -78,20 +92,13 @@ namespace lms::ui // Retrieve parameters const std::string* artworkIdStr = request.getParameter("artworkid"); const std::string* sizeStr = request.getParameter("size"); - const std::string* typeStr = request.getParameter("type"); + const std::string* fallbackStr = request.getParameter("fallback"); std::shared_ptr image; - if (artworkIdStr && typeStr) + if (!artworkIdStr && !fallbackStr) { - ARTWORK_RESOURCE_LOG(DEBUG, "both artwork ID and type provided, only one is allowed"); - response.setStatus(400); - return; - } - - if (!artworkIdStr && !typeStr) - { - ARTWORK_RESOURCE_LOG(DEBUG, "no artwork ID or type provided"); + ARTWORK_RESOURCE_LOG(DEBUG, "no artwork ID or fallback provided"); response.setStatus(400); return; } @@ -118,22 +125,22 @@ namespace lms::ui if (!image) ARTWORK_RESOURCE_LOG(DEBUG, "no image found for artwork ID: '" << *artworkIdStr << "'"); } - else + + if (!image && fallbackStr) { - assert(typeStr); - if (*typeStr == "defartist") + if (*fallbackStr == "defartist") image = core::Service::get()->getDefaultArtistArtwork(); - else if (*typeStr == "defrelease") + else if (*fallbackStr == "defrelease") image = core::Service::get()->getDefaultReleaseArtwork(); else { - ARTWORK_RESOURCE_LOG(DEBUG, "invalid type provided: '" << *typeStr << "'"); + ARTWORK_RESOURCE_LOG(DEBUG, "invalid type provided: '" << *fallbackStr << "'"); response.setStatus(400); return; } if (!image) - ARTWORK_RESOURCE_LOG(DEBUG, "no default image found for type: '" << *typeStr << "'"); + ARTWORK_RESOURCE_LOG(DEBUG, "no default image found for type: '" << *fallbackStr << "'"); } if (image) diff --git a/src/lms/ui/resource/ArtworkResource.hpp b/src/lms/ui/resource/ArtworkResource.hpp index 05d8266c..03d4b4f0 100644 --- a/src/lms/ui/resource/ArtworkResource.hpp +++ b/src/lms/ui/resource/ArtworkResource.hpp @@ -41,11 +41,15 @@ namespace lms::ui Large = 512, }; - std::string getArtworkUrl(db::ArtworkId artworkId, std::optional size = std::nullopt) const; + enum class DefaultArtworkType + { + Artist, + Release, + Track, + }; - std::string getDefaultArtistArtworkUrl() const; - std::string getDefaultReleaseArtworkUrl() const; - std::string getDefaultTrackArtworkUrl() const; + std::string getArtworkUrl(db::ArtworkId artworkId, DefaultArtworkType fallbackType, std::optional size = std::nullopt) const; + std::string getDefaultArtworkUrl(DefaultArtworkType type) const; private: void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response) override; From b4915f5b6faf4eb7f98b54a8a8706d227b33bd23 Mon Sep 17 00:00:00 2001 From: emeric Date: Thu, 17 Jul 2025 20:34:17 +0200 Subject: [PATCH 31/46] Removed duplicate trace --- .../services/scanner/impl/scanners/AudioFileScanOperation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index e67cbc4b..1944bc2d 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -476,7 +476,6 @@ namespace lms::scanner void AudioFileScanOperation::scan() { - LMS_SCOPED_TRACE_OVERVIEW("Scanner", "ScanAudioFile"); std::unique_ptr track; try From 4d4f83130aaeb540cd81b64e128e1cdfccbd36ae Mon Sep 17 00:00:00 2001 From: emeric Date: Thu, 17 Jul 2025 20:34:43 +0200 Subject: [PATCH 32/46] Removed offending index --- src/libs/database/impl/Migration.cpp | 9 ++++++++- src/libs/database/impl/Session.cpp | 7 ++++--- src/libs/database/include/database/Session.hpp | 2 ++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index 4833d28d..c6e1e1b6 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -34,7 +34,7 @@ namespace lms::db { namespace { - static constexpr Version LMS_DATABASE_VERSION{ 97 }; + static constexpr Version LMS_DATABASE_VERSION{ 98 }; } VersionInfo::VersionInfo() @@ -1417,6 +1417,12 @@ WHERE art.image_id IS NULL)"); dropIndexes(session); } + void migrateFromV97(Session& session) + { + // Removed not that useful indexes + dropIndexes(session); + } + bool doDbMigration(Session& session) { constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" }; @@ -1490,6 +1496,7 @@ WHERE art.image_id IS NULL)"); { 94, migrateFromV94 }, { 95, migrateFromV95 }, { 96, migrateFromV96 }, + { 97, migrateFromV97 }, }; bool migrationPerformed{}; diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 8d03aaef..fbb5194f 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -289,10 +289,9 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_artist_idx ON track_artist_link(artist_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_artist_mbid_matched_artist_idx ON track_artist_link(artist_mbid_matched, artist_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_artist_track_idx ON track_artist_link(artist_id, track_id)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_artist_type_idx ON track_artist_link(artist_id, type)"); + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_artist_type_track_idx ON track_artist_link(artist_id, type, track_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_track_artist_idx ON track_artist_link(track_id, artist_id)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_track_type_idx ON track_artist_link(track_id,type)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_type_track_artist_idx ON track_artist_link(type, track_id, artist_id)"); + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_artist_link_track_type_idx ON track_artist_link(track_id, type)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_features_track_idx ON track_features(track_id)"); @@ -384,6 +383,8 @@ namespace lms::db bool Session::areAllTablesEmpty() { + checkReadTransaction(); + const std::vector entryList{ utils::fetchQueryResults(_session.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")) }; return std::all_of(entryList.cbegin(), entryList.cend(), [this](const std::string& entry) { diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index c07f43c5..b1e3f5c7 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -47,6 +47,8 @@ namespace lms::db void execute(std::string_view statement); + void optimize(); // need to acquire a write transaction + // All these methods will acquire transactions void fullAnalyze(); // helper for retrieveEntriesToAnalyze + analyzeEntry void retrieveEntriesToAnalyze(std::vector& entryList); From 08ac5f0b10c510c6b9925966eab40b7ba598ecc1 Mon Sep 17 00:00:00 2001 From: emeric Date: Thu, 17 Jul 2025 20:52:06 +0200 Subject: [PATCH 33/46] Added a macro to log with a condition --- src/libs/core/include/core/ILogger.hpp | 7 +++++++ src/libs/database/impl/objects/Artist.cpp | 6 ++---- src/libs/database/impl/objects/PlayListFile.cpp | 3 +-- src/libs/database/impl/objects/Track.cpp | 9 +++------ 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/libs/core/include/core/ILogger.hpp b/src/libs/core/include/core/ILogger.hpp index 8c7ee446..336898e9 100644 --- a/src/libs/core/include/core/ILogger.hpp +++ b/src/libs/core/include/core/ILogger.hpp @@ -101,3 +101,10 @@ namespace lms::core::logging if (auto* logger_{ ::lms::core::Service<::lms::core::logging::ILogger>::get() }; logger_ && logger_->isSeverityActive(::lms::core::logging::Severity::severity)) \ ::lms::core::logging::Log{ *logger_, ::lms::core::logging::Module::module, ::lms::core::logging::Severity::severity }.getOstream() << message; \ } while (0) + +#define LMS_LOG_IF(module, severity, cond, message) \ + do \ + { \ + if (auto* logger_{ ::lms::core::Service<::lms::core::logging::ILogger>::get() }; logger_ && logger_->isSeverityActive(::lms::core::logging::Severity::severity) && cond) \ + ::lms::core::logging::Log{ *logger_, ::lms::core::logging::Module::module, ::lms::core::logging::Severity::severity }.getOstream() << message; \ + } while (0) diff --git a/src/libs/database/impl/objects/Artist.cpp b/src/libs/database/impl/objects/Artist.cpp index 86d0b029..368c87ab 100644 --- a/src/libs/database/impl/objects/Artist.cpp +++ b/src/libs/database/impl/objects/Artist.cpp @@ -445,16 +445,14 @@ AND NOT EXISTS ( void Artist::setName(std::string_view name) { _name.assign(name, 0, _maxNameLength); - if (name.size() > _maxNameLength) - LMS_LOG(DB, WARNING, "Artist name too long, truncated to '" << _name << "'"); + LMS_LOG_IF(DB, WARNING, name.size() > _maxNameLength, "Artist name too long, truncated to '" << _name << "'"); } void Artist::setSortName(std::string_view sortName) { _sortName.assign(sortName, 0, _maxNameLength); - if (sortName.size() > _maxNameLength) - LMS_LOG(DB, WARNING, "Artist sort name too long, truncated to '" << _sortName << "'"); + LMS_LOG_IF(DB, WARNING, sortName.size() > _maxNameLength, "Artist sort name too long, truncated to '" << _sortName << "'"); } void Artist::setPreferredArtwork(ObjectPtr artwork) diff --git a/src/libs/database/impl/objects/PlayListFile.cpp b/src/libs/database/impl/objects/PlayListFile.cpp index 17bf4036..e7b408d1 100644 --- a/src/libs/database/impl/objects/PlayListFile.cpp +++ b/src/libs/database/impl/objects/PlayListFile.cpp @@ -167,8 +167,7 @@ namespace lms::db void PlayListFile::setName(std::string_view name) { _name = std::string{ name, 0, _maxNameLength }; - if (name.size() > _maxNameLength) - LMS_LOG(DB, WARNING, "PlaylistFile name too long, truncated to '" << _name << "'"); + LMS_LOG_IF(DB, WARNING, name.size() > _maxNameLength, "PlaylistFile name too long, truncated to '" << _name << "'"); } void PlayListFile::setFiles(std::span files) diff --git a/src/libs/database/impl/objects/Track.cpp b/src/libs/database/impl/objects/Track.cpp index ab731be5..4925b3e3 100644 --- a/src/libs/database/impl/objects/Track.cpp +++ b/src/libs/database/impl/objects/Track.cpp @@ -511,22 +511,19 @@ namespace lms::db void Track::setName(std::string_view name) { _name = std::string{ name, 0, _maxNameLength }; - if (name.size() > _maxNameLength) - LMS_LOG(DB, WARNING, "Track name too long, truncated to '" << _name << "'"); + LMS_LOG_IF(DB, WARNING, name.size() > _maxNameLength, "Track name too long, truncated to '" << _name << "'"); } void Track::setCopyright(std::string_view copyright) { _copyright = std::string{ copyright, 0, _maxCopyrightLength }; - if (copyright.size() > _maxCopyrightLength) - LMS_LOG(DB, WARNING, "Track copyright too long, truncated to '" << _copyright << "'"); + LMS_LOG_IF(DB, WARNING, copyright.size() > _maxCopyrightLength, "Track copyright too long, truncated to '" << _copyright << "'"); } void Track::setCopyrightURL(std::string_view copyrightURL) { _copyrightURL = std::string{ copyrightURL, 0, _maxCopyrightURLLength }; - if (copyrightURL.size() > _maxCopyrightURLLength) - LMS_LOG(DB, WARNING, "Track copyright URL too long, truncated to '" << _copyrightURL << "'"); + LMS_LOG_IF(DB, WARNING, copyrightURL.size() > _maxCopyrightURLLength, "Track copyright URL too long, truncated to '" << _copyrightURL << "'"); } void Track::clearArtistLinks() From cba7f3c0ec0a4ec46c7126c5caeece203035e640 Mon Sep 17 00:00:00 2001 From: emeric Date: Thu, 17 Jul 2025 21:08:15 +0200 Subject: [PATCH 34/46] Fixed assert / infinite loop that may actually occur if artist name is too long (> 512chars), fixes #710 --- src/libs/database/impl/objects/Artist.cpp | 15 +++++++++------ .../database/impl/objects/TrackArtistLink.cpp | 7 +++++-- .../database/include/database/objects/Artist.hpp | 4 ++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/libs/database/impl/objects/Artist.cpp b/src/libs/database/impl/objects/Artist.cpp index 368c87ab..436f6735 100644 --- a/src/libs/database/impl/objects/Artist.cpp +++ b/src/libs/database/impl/objects/Artist.cpp @@ -35,6 +35,7 @@ #include "SqlQuery.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" +#include "traits/StringViewTraits.hpp" DBO_INSTANTIATE_TEMPLATES(lms::db::Artist) @@ -257,7 +258,10 @@ namespace lms::db { session.checkReadTransaction(); - return utils::fetchQueryResults(session.getDboSession()->query>("SELECT a FROM artist a").where("a.name = ?").bind(std::string{ name, 0, _maxNameLength }).orderBy("LENGTH(a.mbid) DESC")); // put mbid entries first + if (name.size() > maxNameLength) + name = name.substr(0, maxNameLength); + + return utils::fetchQueryResults(session.getDboSession()->query>("SELECT a FROM artist a").where("a.name = ?").bind(name).orderBy("LENGTH(a.mbid) DESC")); // put mbid entries first } Artist::pointer Artist::find(Session& session, const core::UUID& mbid) @@ -444,15 +448,14 @@ AND NOT EXISTS ( void Artist::setName(std::string_view name) { - _name.assign(name, 0, _maxNameLength); - LMS_LOG_IF(DB, WARNING, name.size() > _maxNameLength, "Artist name too long, truncated to '" << _name << "'"); + _name.assign(name, 0, maxNameLength); + LMS_LOG_IF(DB, WARNING, name.size() > maxNameLength, "Artist name too long, truncated to '" << _name << "'"); } void Artist::setSortName(std::string_view sortName) { - _sortName.assign(sortName, 0, _maxNameLength); - - LMS_LOG_IF(DB, WARNING, sortName.size() > _maxNameLength, "Artist sort name too long, truncated to '" << _sortName << "'"); + _sortName.assign(sortName, 0, maxNameLength); + LMS_LOG_IF(DB, WARNING, sortName.size() > maxNameLength, "Artist sort name too long, truncated to '" << _sortName << "'"); } void Artist::setPreferredArtwork(ObjectPtr artwork) diff --git a/src/libs/database/impl/objects/TrackArtistLink.cpp b/src/libs/database/impl/objects/TrackArtistLink.cpp index d68d606e..90a373ff 100644 --- a/src/libs/database/impl/objects/TrackArtistLink.cpp +++ b/src/libs/database/impl/objects/TrackArtistLink.cpp @@ -21,6 +21,7 @@ #include +#include "core/ILogger.hpp" #include "database/Session.hpp" #include "database/objects/Artist.hpp" #include "database/objects/Track.hpp" @@ -177,11 +178,13 @@ namespace lms::db void TrackArtistLink::setArtistName(std::string_view artistName) { - _artistName = artistName; + _artistName.assign(artistName, 0, Artist::maxNameLength); + LMS_LOG_IF(DB, WARNING, artistName.size() > Artist::maxNameLength, "Artist link name too long, truncated to '" << _artistName << "'"); } void TrackArtistLink::setArtistSortName(std::string_view artistSortName) { - _artistSortName = artistSortName; + _artistSortName.assign(artistSortName, 0, Artist::maxNameLength); + LMS_LOG_IF(DB, WARNING, artistSortName.size() > Artist::maxNameLength, "Artist link sort name too long, truncated to '" << _artistSortName << "'"); } } // namespace lms::db diff --git a/src/libs/database/include/database/objects/Artist.hpp b/src/libs/database/include/database/objects/Artist.hpp index b33e1705..6310e283 100644 --- a/src/libs/database/include/database/objects/Artist.hpp +++ b/src/libs/database/include/database/objects/Artist.hpp @@ -58,6 +58,8 @@ namespace lms::db class Artist final : public Object { public: + static constexpr std::size_t maxNameLength{ 512 }; + struct FindParameters { Filters filters; @@ -173,8 +175,6 @@ namespace lms::db } private: - static constexpr std::size_t _maxNameLength{ 512 }; - friend class Session; // Create Artist(const std::string& name, const std::optional& MBID = {}); From 288f764a6aca3ff292f13cd70d1c309c3ec73e3d Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 18 Jul 2025 13:55:15 +0200 Subject: [PATCH 35/46] Adjusted rule --- .clang-tidy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.clang-tidy b/.clang-tidy index fd3c5114..2e08e112 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -17,4 +17,6 @@ CheckOptions: value: '1' - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor value: '1' + - key: readability-function-cognitive-complexity.IgnoreMacros + value: '1' ... From aa23350f5637a9fe1881dadb10905edc4705006d Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 18 Jul 2025 13:55:39 +0200 Subject: [PATCH 36/46] Removed useless declaration --- src/libs/database/include/database/Session.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index b1e3f5c7..c07f43c5 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -47,8 +47,6 @@ namespace lms::db void execute(std::string_view statement); - void optimize(); // need to acquire a write transaction - // All these methods will acquire transactions void fullAnalyze(); // helper for retrieveEntriesToAnalyze + analyzeEntry void retrieveEntriesToAnalyze(std::vector& entryList); From f31d366731e2a1e52c075c5cc9169004a0bf4856 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 18 Jul 2025 18:39:50 +0200 Subject: [PATCH 37/46] Made the step 'check for removed files' faster when nothing was actually removed --- src/libs/services/scanner/CMakeLists.txt | 1 + .../services/scanner/impl/FileScanners.cpp | 81 ++++++ .../services/scanner/impl/FileScanners.hpp | 45 ++++ .../services/scanner/impl/ScannerService.cpp | 21 +- .../services/scanner/impl/ScannerService.hpp | 3 +- .../services/scanner/impl/steps/JobQueue.hpp | 4 +- .../steps/ScanStepAssociateArtistImages.cpp | 14 +- .../scanner/impl/steps/ScanStepBase.cpp | 46 +--- .../scanner/impl/steps/ScanStepBase.hpp | 14 +- .../steps/ScanStepCheckForRemovedFiles.cpp | 235 +++++++++++++----- .../scanner/impl/steps/ScanStepScanFiles.cpp | 15 +- .../scanner/impl/steps/ScanStepScanFiles.hpp | 2 +- 12 files changed, 329 insertions(+), 152 deletions(-) create mode 100644 src/libs/services/scanner/impl/FileScanners.cpp create mode 100644 src/libs/services/scanner/impl/FileScanners.hpp diff --git a/src/libs/services/scanner/CMakeLists.txt b/src/libs/services/scanner/CMakeLists.txt index 3aab7cc5..79122c0b 100644 --- a/src/libs/services/scanner/CMakeLists.txt +++ b/src/libs/services/scanner/CMakeLists.txt @@ -25,6 +25,7 @@ add_library(lmsscanner STATIC impl/steps/ScanStepRemoveOrphanedDbEntries.cpp impl/steps/ScanStepScanFiles.cpp impl/steps/ScanStepUpdateLibraryFields.cpp + impl/FileScanners.cpp impl/ScannerService.cpp impl/ScannerStats.cpp ) diff --git a/src/libs/services/scanner/impl/FileScanners.cpp b/src/libs/services/scanner/impl/FileScanners.cpp new file mode 100644 index 00000000..3a43e656 --- /dev/null +++ b/src/libs/services/scanner/impl/FileScanners.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2025 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 . + */ + +#include "FileScanners.hpp" + +#include + +#include "core/String.hpp" + +#include "scanners/IFileScanner.hpp" + +namespace lms::scanner +{ + void FileScanners::add(std::unique_ptr scanner) + { + for (const std::filesystem::path& file : scanner->getSupportedFiles()) + { + [[maybe_unused]] auto [it, inserted]{ _scannerByFile.emplace(file, scanner.get()) }; + assert(inserted); + } + + for (const std::filesystem::path& extension : scanner->getSupportedExtensions()) + { + [[maybe_unused]] auto [it, inserted]{ _scannerByExtension.emplace(extension, scanner.get()) }; + assert(inserted); + } + + _fileScanners.emplace_back(std::move(scanner)); + } + + void FileScanners::clear() + { + _fileScanners.clear(); + _scannerByFile.clear(); + _scannerByExtension.clear(); + } + + IFileScanner* FileScanners::select(const std::filesystem::path& filePath) const + { + { + const std::string fileName{ core::stringUtils::stringToLower(filePath.filename().string()) }; + + auto itScanner{ _scannerByFile.find(fileName) }; + if (itScanner != std::cend(_scannerByFile)) + return itScanner->second; + } + + { + const std::string extension{ core::stringUtils::stringToLower(filePath.extension().string()) }; + + auto itScanner{ _scannerByExtension.find(extension) }; + if (itScanner != std::cend(_scannerByExtension)) + return itScanner->second; + } + + return nullptr; + } + + void FileScanners::visit(const std::function& visitor) const + { + for (const auto& scanner : _fileScanners) + visitor(*scanner); + } + +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/FileScanners.hpp b/src/libs/services/scanner/impl/FileScanners.hpp new file mode 100644 index 00000000..8c7e6af2 --- /dev/null +++ b/src/libs/services/scanner/impl/FileScanners.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2025 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 . + */ + +#pragma once + +#include +#include +#include +#include + +namespace lms::scanner +{ + class IFileScanner; + + class FileScanners + { + public: + void add(std::unique_ptr scanner); + void clear(); + + IFileScanner* select(const std::filesystem::path& filePath) const; + void visit(const std::function& visitor) const; + + private: + std::unordered_map _scannerByFile; + std::unordered_map _scannerByExtension; + std::vector> _fileScanners; + }; +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index 41137b52..53d19a17 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -452,14 +452,19 @@ namespace lms::scanner } }; _fileScanners.clear(); - _fileScanners.emplace_back(std::make_unique(_db, _settings)); - _fileScanners.emplace_back(std::make_unique(_db, _settings)); - _fileScanners.emplace_back(std::make_unique(_db, _settings)); - _fileScanners.emplace_back(std::make_unique(_db, _settings)); - _fileScanners.emplace_back(std::make_unique(_db, _settings)); + _fileScanners.add(std::make_unique(_db, _settings)); + _fileScanners.add(std::make_unique(_db, _settings)); + _fileScanners.add(std::make_unique(_db, _settings)); + _fileScanners.add(std::make_unique(_db, _settings)); + _fileScanners.add(std::make_unique(_db, _settings)); - std::vector fileScanners; - std::transform(std::cbegin(_fileScanners), std::cend(_fileScanners), std::back_inserter(fileScanners), [](const std::unique_ptr& scanner) { return scanner.get(); }); + _fileScanners.visit([](const IFileScanner& scanner) { + for (const std::filesystem::path& file : scanner.getSupportedFiles()) + LMS_LOG(DBUPDATER, INFO, scanner.getName() << ": supporting file " << file); + + for (const std::filesystem::path& extension : scanner.getSupportedExtensions()) + LMS_LOG(DBUPDATER, INFO, scanner.getName() << ": supporting file extension " << extension); + }); ScanStepBase::InitParams params{ .jobScheduler = *_jobScheduler, @@ -468,7 +473,7 @@ namespace lms::scanner .progressCallback = progressFunc, .abortScan = _abortScan, .db = _db, - .fileScanners = fileScanners, + .fileScanners = _fileScanners, }; // Order is important: steps are sequential diff --git a/src/libs/services/scanner/impl/ScannerService.hpp b/src/libs/services/scanner/impl/ScannerService.hpp index 35599da9..2ac1481f 100644 --- a/src/libs/services/scanner/impl/ScannerService.hpp +++ b/src/libs/services/scanner/impl/ScannerService.hpp @@ -31,6 +31,7 @@ #include #include +#include "FileScanners.hpp" #include "ScannerSettings.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" @@ -88,7 +89,7 @@ namespace lms::scanner db::IDb& _db; std::unique_ptr _jobScheduler; - std::vector> _fileScanners; + FileScanners _fileScanners; std::vector> _scanSteps; std::mutex _controlMutex; diff --git a/src/libs/services/scanner/impl/steps/JobQueue.hpp b/src/libs/services/scanner/impl/steps/JobQueue.hpp index a7d16c9b..db68727f 100644 --- a/src/libs/services/scanner/impl/steps/JobQueue.hpp +++ b/src/libs/services/scanner/impl/steps/JobQueue.hpp @@ -37,7 +37,9 @@ namespace lms::scanner public: using ProcessFunction = std::function>)>; - JobQueue(core::IJobScheduler& scheduler, std::size_t maxQueueSize, ProcessFunction processJobsDoneFunc, std::size_t batchSize, float drainThreshold); + // processBatchSize -> how many jobs done to notify at once using processJobsDoneFunc + // drainThreshold: fraction of maxQueueSize at which completed jobs are processed + JobQueue(core::IJobScheduler& scheduler, std::size_t maxQueueSize, ProcessFunction processJobsDoneFunc, std::size_t processBatchSize, float drainThreshold); ~JobQueue(); JobQueue(const JobQueue&) = delete; JobQueue& operator=(const JobQueue&) = delete; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index 08b36aed..c3200419 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -363,14 +363,14 @@ namespace lms::scanner _progressCallback(context.currentStepStats); }; - JobQueue queue{ getJobScheduler(), 20, processJobsDone, 1, 0.85F }; + { + JobQueue queue{ getJobScheduler(), 20, processJobsDone, 1, 0.85F }; - db::ArtistId lastRetrievedArtistId{}; - db::IdRange artistIdRange; - while (fetchNextArtistIdRange(session, lastRetrievedArtistId, artistIdRange)) - queue.push(std::make_unique(_db, searchParams, artistIdRange)); - - queue.finish(); + db::ArtistId lastRetrievedArtistId{}; + db::IdRange artistIdRange; + while (fetchNextArtistIdRange(session, lastRetrievedArtistId, artistIdRange)) + queue.push(std::make_unique(_db, searchParams, artistIdRange)); + } // process all remaining associations updateArtistPreferredArtworks(session, artistArtworkAssociations, false); diff --git a/src/libs/services/scanner/impl/steps/ScanStepBase.cpp b/src/libs/services/scanner/impl/steps/ScanStepBase.cpp index bde21dde..ba1be78c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepBase.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepBase.cpp @@ -19,10 +19,7 @@ #include "ScanStepBase.hpp" -#include "core/String.hpp" - #include "ScanContext.hpp" -#include "scanners/IFileScanner.hpp" namespace lms::scanner { @@ -32,54 +29,13 @@ namespace lms::scanner , _abortScan{ initParams.abortScan } , _db{ initParams.db } , _jobScheduler{ initParams.jobScheduler } - , _fileScanners(std::cbegin(initParams.fileScanners), std::cend(initParams.fileScanners)) + , _fileScanners(initParams.fileScanners) , _lastScanSettings{ initParams.lastScanSettings } { - for (IFileScanner* scanner : _fileScanners) - { - for (const std::filesystem::path& file : scanner->getSupportedFiles()) - { - [[maybe_unused]] auto [it, inserted]{ _scannerByFile.emplace(file, scanner) }; - assert(inserted); - } - - for (const std::filesystem::path& extension : scanner->getSupportedExtensions()) - { - [[maybe_unused]] auto [it, inserted]{ _scannerByExtension.emplace(extension, scanner) }; - assert(inserted); - } - } } ScanStepBase::~ScanStepBase() = default; - IFileScanner* ScanStepBase::selectFileScanner(const std::filesystem::path& filePath) const - { - { - const std::string fileName{ core::stringUtils::stringToLower(filePath.filename().string()) }; - - auto itScanner{ _scannerByFile.find(fileName) }; - if (itScanner != std::cend(_scannerByFile)) - return itScanner->second; - } - - { - const std::string extension{ core::stringUtils::stringToLower(filePath.extension().string()) }; - - auto itScanner{ _scannerByExtension.find(extension) }; - if (itScanner != std::cend(_scannerByExtension)) - return itScanner->second; - } - - return nullptr; - } - - void ScanStepBase::visitFileScanners(const std::function& visitor) const - { - for (IFileScanner* scanner : _fileScanners) - visitor(scanner); - } - void ScanStepBase::addError(ScanContext& context, std::shared_ptr error) { error->accept(_scanErrorLogger); diff --git a/src/libs/services/scanner/impl/steps/ScanStepBase.hpp b/src/libs/services/scanner/impl/steps/ScanStepBase.hpp index a544274a..93b35343 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepBase.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepBase.hpp @@ -20,9 +20,6 @@ #pragma once #include -#include -#include -#include #include "IScanStep.hpp" #include "ScanErrorLogger.hpp" @@ -39,7 +36,7 @@ namespace lms::db namespace lms::scanner { - class IFileScanner; + class FileScanners; struct ScannerSettings; struct ScanStepStats; struct ScanContext; @@ -57,7 +54,7 @@ namespace lms::scanner ProgressCallback progressCallback; bool& abortScan; db::IDb& db; - std::span fileScanners; + const FileScanners& fileScanners; }; ScanStepBase(InitParams& initParams); ~ScanStepBase() override; @@ -67,8 +64,7 @@ namespace lms::scanner protected: core::IJobScheduler& getJobScheduler() { return _jobScheduler; }; const ScannerSettings* getLastScanSettings() const { return _lastScanSettings; } - IFileScanner* selectFileScanner(const std::filesystem::path& filePath) const; - void visitFileScanners(const std::function& visitor) const; + const FileScanners& getFileScanners() const { return _fileScanners; } void addError(ScanContext& context, std::shared_ptr error); @@ -86,9 +82,7 @@ namespace lms::scanner private: core::IJobScheduler& _jobScheduler; - std::unordered_map _scannerByFile; - std::unordered_map _scannerByExtension; - std::vector _fileScanners; + const FileScanners& _fileScanners; const ScannerSettings* _lastScanSettings{}; ScanErrorLogger _scanErrorLogger; diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index d30dae79..dd255c55 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -19,8 +19,12 @@ #include "ScanStepCheckForRemovedFiles.hpp" +#include +#include +#include #include +#include "core/IJob.hpp" #include "core/ILogger.hpp" #include "core/Path.hpp" #include "database/IDb.hpp" @@ -31,11 +35,153 @@ #include "database/objects/Track.hpp" #include "database/objects/TrackLyrics.hpp" +#include "FileScanners.hpp" +#include "JobQueue.hpp" #include "ScanContext.hpp" #include "ScannerSettings.hpp" +#include "services/scanner/ScannerStats.hpp" namespace lms::scanner { + namespace + { + template + struct FileToCheck + { + IdType objectId; + std::filesystem::path file; + }; + + template + class CheckForRemovedFilesJob : public core::IJob + { + public: + CheckForRemovedFilesJob(const ScannerSettings& settings, const FileScanners& scanners, std::span> filesToCheck) + : _settings{ settings } + , _scanners{ scanners } + , _filesToCheck{ std::cbegin(filesToCheck), std::cend(filesToCheck) } + { + } + + std::size_t getProcessedCount() const { return _processedCount; } + std::span getObjectsToRemove() const { return _objectsToRemove; } + + private: + core::LiteralString getName() const override { return "Check For Removed Files"; } + void run() override + { + for (const FileToCheck& fileToCheck : _filesToCheck) + { + if (!checkFile(fileToCheck.file)) + _objectsToRemove.push_back(fileToCheck.objectId); + } + + _processedCount += _filesToCheck.size(); + } + + bool checkFile(const std::filesystem::path& p) + { + std::error_code ec; + const std::filesystem::directory_entry fileEntry{ p, ec }; + if (ec) + { + // TODO store error? + LMS_LOG(DBUPDATER, ERROR, "Error while checking file " << p << ": " << ec.message()); + return false; + } + + // For each track, make sure the the file still exists + // and still belongs to a media directory + if (!fileEntry.exists() || !fileEntry.is_regular_file()) + { + LMS_LOG(DBUPDATER, DEBUG, "Removing " << p << ": missing"); + return false; + } + + if (std::none_of(std::cbegin(_settings.mediaLibraries), std::cend(_settings.mediaLibraries), + [&](const MediaLibraryInfo& libraryInfo) { + return core::pathUtils::isPathInRootPath(p, libraryInfo.rootDirectory, &excludeDirFileName); + })) + { + LMS_LOG(DBUPDATER, DEBUG, "Removing " << p << ": out of media directory"); + return false; + } + + if (!_scanners.select(p)) + { + LMS_LOG(DBUPDATER, DEBUG, "Removing " << p << ": file format no longer handled"); + return false; + } + + return true; + } + + const ScannerSettings& _settings; + const FileScanners& _scanners; + std::vector> _filesToCheck; + std::vector _objectsToRemove; + std::size_t _processedCount{}; + }; + + template + std::size_t removeObjects(db::Session& session, std::deque& objectIdsToRemove, bool forceFullBatch) + { + std::size_t removedObjectCount{}; + constexpr std::size_t writeBatchSize{ 50 }; + + std::vector ids; + while ((forceFullBatch && objectIdsToRemove.size() >= writeBatchSize) || !objectIdsToRemove.empty()) + { + for (std::size_t i{}; !objectIdsToRemove.empty() && i < writeBatchSize; ++i) + { + ids.push_back(objectIdsToRemove.front()); + objectIdsToRemove.pop_front(); + } + + { + auto transaction{ session.createWriteTransaction() }; + session.destroy(ids); + } + + removedObjectCount += ids.size(); + ids.clear(); + } + + return removedObjectCount; + } + + template + bool fetchNextFilesToCheck(db::Session& session, typename Object::IdType& lastCheckedId, std::vector>& filesToCheck) + { + constexpr std::size_t batchSize{ 200 }; + + filesToCheck.clear(); + filesToCheck.reserve(batchSize); + + auto transaction{ session.createReadTransaction() }; + + while (filesToCheck.size() < batchSize) + { + const typename Object::IdType previousLastCheckedId{ lastCheckedId }; + Object::findAbsoluteFilePath(session, lastCheckedId, batchSize, [&](Object::IdType objectId, const std::filesystem::path& filePath) { + // special case for track lyrics, only check external lyrics + if constexpr (std::is_same_v) + { + if (filePath.empty()) + return; + } + + filesToCheck.emplace_back(objectId, filePath); + }); + + if (previousLastCheckedId == lastCheckedId) + break; + } + + return !filesToCheck.empty(); + } + } // namespace + bool ScanStepCheckForRemovedFiles::needProcess([[maybe_unused]] const ScanContext& context) const { // always check for removed files @@ -67,91 +213,48 @@ namespace lms::scanner template void ScanStepCheckForRemovedFiles::checkForRemovedFiles(ScanContext& context) { - using namespace db; + using ObjectIdType = typename Object::IdType; if (_abortScan) return; - Session& session{ _db.getTLSSession() }; + db::Session& session{ _db.getTLSSession() }; - std::vector objectIdsToRemove; + std::deque objectIdsToRemove; - typename Object::IdType lastCheckedId; - bool endReached{}; - while (!endReached) - { + auto processJobsDone = [&](std::span> jobs) { if (_abortScan) - break; + return; - objectIdsToRemove.clear(); + for (const auto& job : jobs) { - constexpr std::size_t batchSize = 200; + const auto& checkJob{ static_cast&>(*job) }; + std::span objectsToRemove{ checkJob.getObjectsToRemove() }; - auto transaction{ session.createReadTransaction() }; + objectIdsToRemove.insert(std::end(objectIdsToRemove), std::cbegin(objectsToRemove), std::cend(objectsToRemove)); - endReached = true; - Object::findAbsoluteFilePath(session, lastCheckedId, batchSize, [&](Object::IdType objectId, const std::filesystem::path& filePath) { - endReached = false; - - // special case for track lyrics, only check external lyrics - if constexpr (std::is_same_v) - { - if (filePath.empty()) - return; - } - - if (!checkFile(filePath)) - objectIdsToRemove.push_back(objectId); - - context.currentStepStats.processedElems++; - }); + context.currentStepStats.processedElems += checkJob.getProcessedCount(); } if (!objectIdsToRemove.empty()) { - auto transaction{ session.createWriteTransaction() }; - - session.destroy(objectIdsToRemove); + removeObjects(session, objectIdsToRemove, true); context.stats.deletions += objectIdsToRemove.size(); } - _progressCallback(context.currentStepStats); + }; + + { + JobQueue queue{ getJobScheduler(), 50, processJobsDone, 1, 0.85F }; + + ObjectIdType lastCheckedId; + std::vector> filesToCheck; + while (fetchNextFilesToCheck(session, lastCheckedId, filesToCheck)) + queue.push(std::make_unique>(_settings, getFileScanners(), filesToCheck)); } + + // process all remaining objects + removeObjects(session, objectIdsToRemove, false); } - bool ScanStepCheckForRemovedFiles::checkFile(const std::filesystem::path& p) - { - try - { - // For each track, make sure the the file still exists - // and still belongs to a media directory - if (!std::filesystem::exists(p) || !std::filesystem::is_regular_file(p)) - { - LMS_LOG(DBUPDATER, DEBUG, "Removing " << p << ": missing"); - return false; - } - - if (std::none_of(std::cbegin(_settings.mediaLibraries), std::cend(_settings.mediaLibraries), - [&](const MediaLibraryInfo& libraryInfo) { - return core::pathUtils::isPathInRootPath(p, libraryInfo.rootDirectory, &excludeDirFileName); - })) - { - LMS_LOG(DBUPDATER, DEBUG, "Removing " << p << ": out of media directory"); - return false; - } - - if (!selectFileScanner(p)) - { - LMS_LOG(DBUPDATER, DEBUG, "Removing " << p << ": file format no longer handled"); - return false; - } - - return true; - } - catch (std::filesystem::filesystem_error& e) - { - LMS_LOG(DBUPDATER, ERROR, "Caught exception while checking file " << p << ": " << e.what()); - return false; - } - } } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index e0183444..29d9c576 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -31,6 +31,7 @@ #include "scanners/IFileScanOperation.hpp" #include "scanners/IFileScanner.hpp" +#include "FileScanners.hpp" #include "JobQueue.hpp" #include "ScanContext.hpp" @@ -68,18 +69,6 @@ namespace lms::scanner }; } // namespace - ScanStepScanFiles::ScanStepScanFiles(InitParams& initParams) - : ScanStepBase{ initParams } - { - visitFileScanners([](IFileScanner* scanner) { - for (const std::filesystem::path& file : scanner->getSupportedFiles()) - LMS_LOG(DBUPDATER, INFO, scanner->getName() << ": supporting file " << file); - - for (const std::filesystem::path& extension : scanner->getSupportedExtensions()) - LMS_LOG(DBUPDATER, INFO, scanner->getName() << ": supporting file extension " << extension); - }); - } - bool ScanStepScanFiles::needProcess([[maybe_unused]] const ScanContext& context) const { // Always need to scan files @@ -122,7 +111,7 @@ namespace lms::scanner addError(context, path, ec); context.stats.skips++; } - else if (IFileScanner * scanner{ selectFileScanner(path) }) + else if (IFileScanner * scanner{ getFileScanners().select(path) }) { FileToScan fileToScan; diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp index 1dfc315b..fe0b2ece 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp @@ -36,7 +36,7 @@ namespace lms::scanner class ScanStepScanFiles : public ScanStepBase { public: - ScanStepScanFiles(InitParams& initParams); + using ScanStepBase::ScanStepBase; private: ScanStep getStep() const override { return ScanStep::ScanFiles; } From f64a93b5b6ca3d33903da0c3bb47a71434f71d67 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 18 Jul 2025 18:44:43 +0200 Subject: [PATCH 38/46] Fixed deletion stats --- .../scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index dd255c55..718b3c8b 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -237,10 +237,8 @@ namespace lms::scanner } if (!objectIdsToRemove.empty()) - { - removeObjects(session, objectIdsToRemove, true); - context.stats.deletions += objectIdsToRemove.size(); - } + context.stats.deletions += removeObjects(session, objectIdsToRemove, true); + _progressCallback(context.currentStepStats); }; @@ -254,7 +252,7 @@ namespace lms::scanner } // process all remaining objects - removeObjects(session, objectIdsToRemove, false); + context.stats.deletions += removeObjects(session, objectIdsToRemove, false); } } // namespace lms::scanner From f51ceb933e5fccad968b19d7079e7c5a8eacbb1a Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 18 Jul 2025 19:29:08 +0200 Subject: [PATCH 39/46] Do not try to optimize when there are too few files, it seems to bring more drawbacks than benefits --- src/libs/database/impl/Session.cpp | 33 ++++------ .../database/include/database/Session.hpp | 4 +- src/libs/services/scanner/CMakeLists.txt | 1 + .../services/scanner/impl/ScannerService.cpp | 17 ++++- .../services/scanner/impl/ScannerService.hpp | 1 + .../impl/ScannerServiceTraceLogger.cpp | 63 +++++++++++++++++++ .../services/scanner/impl/ScannerStats.cpp | 4 +- .../steps/ScanStepAssociateArtistImages.cpp | 2 +- .../steps/ScanStepAssociateExternalLyrics.cpp | 2 +- .../steps/ScanStepAssociatePlayListTracks.cpp | 2 +- .../steps/ScanStepAssociateReleaseImages.cpp | 2 +- .../steps/ScanStepAssociateTrackImages.cpp | 2 +- .../steps/ScanStepCheckForRemovedFiles.cpp | 7 +-- .../steps/ScanStepComputeClusterStats.cpp | 5 +- .../scanner/impl/steps/ScanStepOptimize.cpp | 7 ++- .../include/services/scanner/ScannerStats.hpp | 4 +- src/lms/main.cpp | 6 -- src/lms/ui/LmsApplication.cpp | 2 +- src/lms/ui/admin/ScannerController.cpp | 2 +- src/lms/ui/resource/ArtworkResource.cpp | 2 +- 20 files changed, 116 insertions(+), 52 deletions(-) create mode 100644 src/libs/services/scanner/impl/ScannerServiceTraceLogger.cpp diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index fbb5194f..c946c947 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -346,26 +346,6 @@ namespace lms::db LMS_LOG(DB, INFO, "Vacuum complete!"); } - void Session::refreshTracingLoggerStats() - { - auto* traceLogger{ core::Service::get() }; - if (!traceLogger) - return; - - auto transaction{ createReadTransaction() }; - - traceLogger->setMetadata("db_artist_count", std::to_string(db::Artist::getCount(*this))); - traceLogger->setMetadata("db_cluster_count", std::to_string(db::Cluster::getCount(*this))); - traceLogger->setMetadata("db_cluster_type_count", std::to_string(db::ClusterType::getCount(*this))); - traceLogger->setMetadata("db_starred_artist_count", std::to_string(db::StarredArtist::getCount(*this))); - traceLogger->setMetadata("db_starred_release_count", std::to_string(db::StarredRelease::getCount(*this))); - traceLogger->setMetadata("db_starred_track_count", std::to_string(db::StarredTrack::getCount(*this))); - traceLogger->setMetadata("db_track_bookmark_count", std::to_string(db::TrackBookmark::getCount(*this))); - traceLogger->setMetadata("db_listen_count", std::to_string(db::Listen::getCount(*this))); - traceLogger->setMetadata("db_release_count", std::to_string(db::Release::getCount(*this))); - traceLogger->setMetadata("db_track_count", std::to_string(db::Track::getCount(*this))); - } - void Session::fullAnalyze() { LMS_SCOPED_TRACE_OVERVIEW("Database", "Analyze"); @@ -393,6 +373,19 @@ namespace lms::db }); } + std::size_t Session::getTotalFilesCount() + { + std::size_t res{}; + + res += db::Track::getCount(*this); + res += db::Image::getCount(*this); + res += db::TrackLyrics::getExternalLyricsCount(*this); + res += db::PlayListFile::getCount(*this); + res += db::ArtistInfo::getCount(*this); + + return res; + } + void Session::retrieveEntriesToAnalyze(std::vector& entryList) { auto transaction{ createReadTransaction() }; diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index c07f43c5..b7e45687 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -52,14 +52,14 @@ namespace lms::db void retrieveEntriesToAnalyze(std::vector& entryList); void analyzeEntry(const std::string& entry); - bool areAllTablesEmpty(); // need to acquire a read transaction + bool areAllTablesEmpty(); // need to acquire a read transaction + std::size_t getTotalFilesCount(); // need to acquire a read transaction void prepareTablesIfNeeded(); // need to run only once at startup bool migrateSchemaIfNeeded(); // returns true if migration was performed void createIndexesIfNeeded(); void vacuumIfNeeded(); void vacuum(); - void refreshTracingLoggerStats(); // returning a ptr here to ease further wrapping using operator-> Wt::Dbo::Session* getDboSession() { return &_session; } diff --git a/src/libs/services/scanner/CMakeLists.txt b/src/libs/services/scanner/CMakeLists.txt index 79122c0b..86cec564 100644 --- a/src/libs/services/scanner/CMakeLists.txt +++ b/src/libs/services/scanner/CMakeLists.txt @@ -27,6 +27,7 @@ add_library(lmsscanner STATIC impl/steps/ScanStepUpdateLibraryFields.cpp impl/FileScanners.cpp impl/ScannerService.cpp + impl/ScannerServiceTraceLogger.cpp impl/ScannerStats.cpp ) diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index 53d19a17..3cf55aa8 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -166,6 +166,20 @@ namespace lms::scanner LMS_LOG(DBUPDATER, INFO, "Using " << _jobScheduler->getThreadCount() << " thread(s) for jobs"); _jobScheduler->setShouldAbortCallback([this]() { return _abortScan; }); + std::size_t totalFilesCount{}; + { + auto& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; + totalFilesCount = session.getTotalFilesCount(); + } + + // Force optimize in case scanner aborted during a large import, but do this only if there are enough elements in the database + // Otherwise, indexes may be not used and queries may be slower and slower while adding more and more elements in the db + LMS_LOG(DBUPDATER, INFO, "Scanned file count = " << totalFilesCount); + if (totalFilesCount >= 1'000) + _db.getTLSSession().fullAnalyze(); + + refreshTracingLoggerStats(); refreshScanSettings(); start(); @@ -371,7 +385,8 @@ namespace lms::scanner _currentScanStepStats.reset(); // must be sync with _curState } - LMS_LOG(DBUPDATER, INFO, "Scan " << (_abortScan ? "aborted" : "complete") << ". Changes = " << stats.nbChanges() << " (added = " << stats.additions << ", removed = " << stats.deletions << ", updated = " << stats.updates << ", failures = " << stats.failures << "), Not changed = " << stats.skips << ", Scanned = " << stats.scans << " (errors = " << stats.errorsCount << "), features fetched = " << stats.featuresFetched << ", duplicates = " << stats.duplicates.size()); + refreshTracingLoggerStats(); + LMS_LOG(DBUPDATER, INFO, "Scan " << (_abortScan ? "aborted" : "complete") << ". Changes = " << stats.getChangesCount() << " (added = " << stats.additions << ", removed = " << stats.deletions << ", updated = " << stats.updates << ", failures = " << stats.failures << "), Not changed = " << stats.skips << ", Scanned = " << stats.scans << " (errors = " << stats.errorsCount << "), features fetched = " << stats.featuresFetched << ", duplicates = " << stats.duplicates.size()); if (!_abortScan) { diff --git a/src/libs/services/scanner/impl/ScannerService.hpp b/src/libs/services/scanner/impl/ScannerService.hpp index 2ac1481f..88779ae9 100644 --- a/src/libs/services/scanner/impl/ScannerService.hpp +++ b/src/libs/services/scanner/impl/ScannerService.hpp @@ -82,6 +82,7 @@ namespace lms::scanner // Helpers void refreshScanSettings(); + void refreshTracingLoggerStats(); void notifyInProgressIfNeeded(const ScanStepStats& stats); void notifyInProgress(const ScanStepStats& stats); diff --git a/src/libs/services/scanner/impl/ScannerServiceTraceLogger.cpp b/src/libs/services/scanner/impl/ScannerServiceTraceLogger.cpp new file mode 100644 index 00000000..1c25f484 --- /dev/null +++ b/src/libs/services/scanner/impl/ScannerServiceTraceLogger.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2013 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 . + */ + +#include "ScannerService.hpp" + +#include "database/objects/Artist.hpp" +#include "database/objects/ArtistInfo.hpp" +#include "database/objects/Cluster.hpp" +#include "database/objects/Image.hpp" +#include "database/objects/Listen.hpp" +#include "database/objects/StarredArtist.hpp" +#include "database/objects/StarredRelease.hpp" +#include "database/objects/StarredTrack.hpp" +#include "database/objects/Track.hpp" +#include "database/objects/TrackArtistLink.hpp" +#include "database/objects/TrackBookmark.hpp" +#include "database/objects/TrackEmbeddedImage.hpp" +#include "database/objects/TrackEmbeddedImageLink.hpp" + +namespace lms::scanner +{ + void ScannerService::refreshTracingLoggerStats() + { + auto* traceLogger{ core::Service::get() }; + if (!traceLogger) + return; + + auto& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; + + traceLogger->setMetadata("db_artist_count", std::to_string(db::Artist::getCount(session))); + traceLogger->setMetadata("db_artist_info_count", std::to_string(db::ArtistInfo::getCount(session))); + traceLogger->setMetadata("db_cluster_count", std::to_string(db::Cluster::getCount(session))); + traceLogger->setMetadata("db_cluster_type_count", std::to_string(db::ClusterType::getCount(session))); + traceLogger->setMetadata("db_image_count", std::to_string(db::Image::getCount(session))); + traceLogger->setMetadata("db_listen_count", std::to_string(db::Listen::getCount(session))); + traceLogger->setMetadata("db_release_count", std::to_string(db::Release::getCount(session))); + traceLogger->setMetadata("db_starred_artist_count", std::to_string(db::StarredArtist::getCount(session))); + traceLogger->setMetadata("db_starred_release_count", std::to_string(db::StarredRelease::getCount(session))); + traceLogger->setMetadata("db_starred_track_count", std::to_string(db::StarredTrack::getCount(session))); + traceLogger->setMetadata("db_track_bookmark_count", std::to_string(db::TrackBookmark::getCount(session))); + traceLogger->setMetadata("db_track_count", std::to_string(db::Track::getCount(session))); + traceLogger->setMetadata("db_track_artist_link_count", std::to_string(db::TrackArtistLink::getCount(session))); + traceLogger->setMetadata("db_track_embedded_image_count", std::to_string(db::TrackEmbeddedImage::getCount(session))); + traceLogger->setMetadata("db_track_embedded_image_link_count", std::to_string(db::TrackEmbeddedImageLink::getCount(session))); + } +} // namespace lms::scanner \ No newline at end of file diff --git a/src/libs/services/scanner/impl/ScannerStats.cpp b/src/libs/services/scanner/impl/ScannerStats.cpp index 37887424..74f15f14 100644 --- a/src/libs/services/scanner/impl/ScannerStats.cpp +++ b/src/libs/services/scanner/impl/ScannerStats.cpp @@ -21,12 +21,12 @@ namespace lms::scanner { - std::size_t ScanStats::nbFiles() const + std::size_t ScanStats::getTotalFileCount() const { return skips + additions + updates + failures; } - std::size_t ScanStats::nbChanges() const + std::size_t ScanStats::getChangesCount() const { return additions + deletions + updates; } diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index c3200419..c8209f9a 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -321,7 +321,7 @@ namespace lms::scanner bool ScanStepAssociateArtistImages::needProcess(const ScanContext& context) const { - if (context.stats.nbChanges() > 0) + if (context.stats.getChangesCount() > 0) return true; if (getLastScanSettings() && getLastScanSettings()->artistImageFallbackToRelease != _settings.artistImageFallbackToRelease) diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp index 9fb01f3a..e5038c31 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp @@ -145,7 +145,7 @@ namespace lms::scanner bool ScanStepAssociateExternalLyrics::needProcess(const ScanContext& context) const { - if (context.stats.nbChanges() > 0) + if (context.stats.getChangesCount() > 0) return true; return false; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp index 098f6bba..2e1a3cad 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp @@ -251,7 +251,7 @@ namespace lms::scanner bool ScanStepAssociatePlayListTracks::needProcess(const ScanContext& context) const { - if (context.stats.nbChanges() > 0) + if (context.stats.getChangesCount() > 0) return true; if (getLastScanSettings() && getLastScanSettings()->skipSingleReleasePlayLists != _settings.skipSingleReleasePlayLists) diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index f5a589a8..2488a139 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -266,7 +266,7 @@ namespace lms::scanner bool ScanStepAssociateReleaseImages::needProcess(const ScanContext& context) const { - return context.stats.nbChanges() > 0; + return context.stats.getChangesCount() > 0; } void ScanStepAssociateReleaseImages::process(ScanContext& context) diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp index d7d7d456..e7871c3b 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateTrackImages.cpp @@ -232,7 +232,7 @@ namespace lms::scanner bool ScanStepAssociateTrackImages::needProcess(const ScanContext& context) const { - return context.stats.nbChanges() > 0; + return context.stats.getChangesCount() > 0; } void ScanStepAssociateTrackImages::process(ScanContext& context) diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index 718b3c8b..0266249b 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -194,12 +194,7 @@ namespace lms::scanner { auto transaction{ session.createReadTransaction() }; - context.currentStepStats.totalElems = 0; - context.currentStepStats.totalElems += db::Track::getCount(session); - context.currentStepStats.totalElems += db::Image::getCount(session); - context.currentStepStats.totalElems += db::TrackLyrics::getExternalLyricsCount(session); - context.currentStepStats.totalElems += db::PlayListFile::getCount(session); - context.currentStepStats.totalElems += db::ArtistInfo::getCount(session); + context.currentStepStats.totalElems = session.getTotalFilesCount(); } LMS_LOG(DBUPDATER, DEBUG, context.currentStepStats.totalElems << " files to be checked..."); diff --git a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp index 7d1dd110..3089aa8a 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp @@ -29,10 +29,7 @@ namespace lms::scanner { bool ScanStepComputeClusterStats::needProcess(const ScanContext& context) const { - if (context.stats.nbChanges() > 0) - return true; - - return false; + return context.stats.getChangesCount() > 0; } void ScanStepComputeClusterStats::process(ScanContext& context) diff --git a/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp b/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp index 98acc7ea..dfc87d65 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp @@ -32,8 +32,13 @@ namespace lms::scanner if (context.scanOptions.forceOptimize) return true; - if (context.stats.nbChanges() > (context.stats.nbFiles() / 10)) + // Don't optimize if there are too few files: it may lead to some indexes not being used + // and will drastically slow down the scan process when adding more files later + if (context.stats.getChangesCount() > (context.stats.getTotalFileCount() / 5) + && context.stats.getTotalFileCount() >= 1'000) + { return true; + } return false; } diff --git a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp index 3ed335a0..1015cdbb 100644 --- a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp +++ b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp @@ -100,7 +100,7 @@ namespace lms::scanner std::size_t errorsCount{}; // maybe bigger than errors.size() if too many errors std::vector duplicates; - std::size_t nbFiles() const; - std::size_t nbChanges() const; + std::size_t getTotalFileCount() const; + std::size_t getChangesCount() const; }; } // namespace lms::scanner diff --git a/src/lms/main.cpp b/src/lms/main.cpp index 09befea6..2c1440d7 100644 --- a/src/lms/main.cpp +++ b/src/lms/main.cpp @@ -333,11 +333,6 @@ namespace lms session.vacuum(); else session.vacuumIfNeeded(); - - // force optimize in case scanner aborted during a large import: - // queries may be too slow to even be able to relaunch a scan using the web interface - session.fullAnalyze(); - database->getTLSSession().refreshTracingLoggerStats(); } ui::LmsApplicationManager appManager; @@ -385,7 +380,6 @@ namespace lms // Flush cover cache even if no changes: // covers may be external files that changed and we don't keep track of them for now (but we should) artworkService->flushCache(); - database->getTLSSession().refreshTracingLoggerStats(); }); core::Service feedbackService{ feedback::createFeedbackService(ioContext, *database) }; diff --git a/src/lms/ui/LmsApplication.cpp b/src/lms/ui/LmsApplication.cpp index e6f6034e..a1e3aa10 100644 --- a/src/lms/ui/LmsApplication.cpp +++ b/src/lms/ui/LmsApplication.cpp @@ -542,7 +542,7 @@ namespace lms::ui notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.Database.database"), Wt::WString::tr("Lms.Admin.Database.scan-complete") - .arg(static_cast(stats.nbFiles())) + .arg(static_cast(stats.getTotalFileCount())) .arg(static_cast(stats.additions)) .arg(static_cast(stats.updates)) .arg(static_cast(stats.deletions)) diff --git a/src/lms/ui/admin/ScannerController.cpp b/src/lms/ui/admin/ScannerController.cpp index 5931b8a9..fd45bb0b 100644 --- a/src/lms/ui/admin/ScannerController.cpp +++ b/src/lms/ui/admin/ScannerController.cpp @@ -115,7 +115,7 @@ namespace lms::ui if (status.lastCompleteScanStats) { _lastScanStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.last-scan-status") - .arg(status.lastCompleteScanStats->nbFiles()) + .arg(status.lastCompleteScanStats->getTotalFileCount()) .arg(durationToString(status.lastCompleteScanStats->startTime, status.lastCompleteScanStats->stopTime)) .arg(status.lastCompleteScanStats->stopTime.date().toString(Wt::WLocale::currentLocale().dateFormat())) .arg(status.lastCompleteScanStats->stopTime.time().toString(Wt::WLocale::currentLocale().timeFormat())) diff --git a/src/lms/ui/resource/ArtworkResource.cpp b/src/lms/ui/resource/ArtworkResource.cpp index cb7a5893..b160bf65 100644 --- a/src/lms/ui/resource/ArtworkResource.cpp +++ b/src/lms/ui/resource/ArtworkResource.cpp @@ -57,7 +57,7 @@ namespace lms::ui ArtworkResource::ArtworkResource() { LmsApp->getScannerEvents().scanComplete.connect(this, [this](const scanner::ScanStats& stats) { - if (stats.nbChanges()) + if (stats.getChangesCount()) setChanged(); }); } From 1236969516a9f2e04ee503edeb5cc52d79dfce0c Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 18 Jul 2025 23:59:23 +0200 Subject: [PATCH 40/46] Removed useless indexes --- src/libs/database/impl/Session.cpp | 6 ------ .../scanner/impl/scanners/AudioFileScanOperation.cpp | 2 +- src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp | 6 +++--- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index c946c947..b3394b14 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -258,24 +258,18 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_date_idx ON track(date)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_directory_release_idx ON track(directory_id, release_id);"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_added_idx ON track(file_added)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_added_desc_idx ON track(file_added DESC)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_last_write_idx ON track(file_last_write)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_last_write_desc_idx ON track(file_last_write DESC)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_media_library_idx ON track(media_library_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_media_library_release_idx ON track(media_library_id, release_id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_mbid_idx ON track(mbid)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_name_idx ON track(name)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_name_file_size_idx ON track(name, file_size)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_name_nocase_idx ON track(name COLLATE NOCASE)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_original_date_idx ON track(original_date)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_recording_mbid_idx ON track(recording_mbid)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_disc_idx ON track(release_id, disc_number)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_date_idx ON track(release_id, date)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_date_desc_idx ON track(release_id, date DESC)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_last_write_idx ON track(release_id, file_last_write)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_last_write_desc_idx ON track(release_id, file_last_write DESC)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_added_idx ON track(release_id, file_added)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_added_desc_idx ON track(release_id, file_added DESC)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS tracklist_id_idx ON tracklist(id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS tracklist_name_idx ON tracklist(name)"); diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index 1944bc2d..d0d30e44 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -384,6 +384,7 @@ namespace lms::scanner db::Track::FindParameters params; // Add as many fields as possible to limit errors params.setName(parsedTrack.title); + params.setFileSize(fileSize); if (parsedTrack.medium) { if (parsedTrack.medium->position) @@ -393,7 +394,6 @@ namespace lms::scanner } if (parsedTrack.position) params.setTrackNumber(*parsedTrack.position); - params.setFileSize(fileSize); bool error{}; db::Track::pointer res; diff --git a/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp b/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp index e589fa2a..8aa5c93a 100644 --- a/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp +++ b/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp @@ -207,9 +207,9 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createReadTransaction() }; db::Track::FindParameters params; - params.name = titleName; - params.artistName = artistName; - params.range = Range{ 0, 2 }; + params.setName(titleName); + params.setArtistName(artistName); + params.setRange(db::Range{ .offset = 0, .size = 2 }); // Choice: we return nothing if there are too many results const auto tracks{ db::Track::findIds(context.dbSession, params) }; From 97866d6143623dc875fb752d02ea5fc5f557f944 Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 19 Jul 2025 11:39:57 +0200 Subject: [PATCH 41/46] Moved scanner specific code from core --- src/libs/core/impl/Path.cpp | 57 ----------------- src/libs/core/include/core/Path.hpp | 11 ---- src/libs/metadata/impl/taglib/Utils.cpp | 11 ++-- .../scanner/impl/steps/ScanStepScanFiles.cpp | 63 ++++++++++++++++--- 4 files changed, 61 insertions(+), 81 deletions(-) diff --git a/src/libs/core/impl/Path.cpp b/src/libs/core/impl/Path.cpp index fc7c188a..ff7436a4 100644 --- a/src/libs/core/impl/Path.cpp +++ b/src/libs/core/impl/Path.cpp @@ -35,63 +35,6 @@ namespace lms::core::pathUtils return std::filesystem::create_directory(dir); } - bool exploreFilesRecursive(const std::filesystem::path& directory, ExploreFileCallback cb, const std::filesystem::path* excludeDirFileName) - { - std::error_code ec; - std::filesystem::directory_iterator itPath{ directory, std::filesystem::directory_options::follow_directory_symlink, ec }; - - if (ec) - { - cb(ec, directory, nullptr); - return true; // try to continue exploring anyway - } - - if (excludeDirFileName && !excludeDirFileName->empty()) - { - const std::filesystem::path excludePath{ directory / *excludeDirFileName }; - - if (std::filesystem::exists(excludePath, ec)) - { - // TODO: handle exclude another way + remove this log - LMS_LOG(DBUPDATER, DEBUG, "Found " << excludePath << ": skipping directory"); - return true; - } - } - - std::filesystem::directory_iterator itEnd; - while (itPath != itEnd) - { - bool continueExploring{ true }; - - if (ec) - { - continueExploring = cb(ec, *itPath, nullptr); - } - else - { - const std::filesystem::directory_entry& entry{ *itPath }; - - if (entry.is_regular_file()) - { - FileInfo fileInfo; - fileInfo.fileSize = entry.file_size(); - fileInfo.lastWriteTime = Wt::WDateTime{ std::chrono::file_clock::to_sys(entry.last_write_time()) }; - - continueExploring = cb(ec, *itPath, &fileInfo); - } - else if (entry.is_directory()) - continueExploring = exploreFilesRecursive(*itPath, cb, excludeDirFileName); - } - - if (!continueExploring) - return false; - - itPath.increment(ec); - } - - return true; - } - bool hasFileAnyExtension(const std::filesystem::path& file, std::span supportedExtensions) { const std::filesystem::path extension{ stringUtils::stringToLower(file.extension().c_str()) }; diff --git a/src/libs/core/include/core/Path.hpp b/src/libs/core/include/core/Path.hpp index ccc4c64b..2d8fece0 100644 --- a/src/libs/core/include/core/Path.hpp +++ b/src/libs/core/include/core/Path.hpp @@ -20,9 +20,7 @@ #pragma once #include -#include #include -#include #include @@ -32,15 +30,6 @@ namespace lms::core::pathUtils // Create it if needed bool ensureDirectory(const std::filesystem::path& dir); - struct FileInfo - { - Wt::WDateTime lastWriteTime; // Last write time of the file since Epoch - std::uint64_t fileSize{}; // Size of the file in bytes - }; - using ExploreFileCallback = std::function; - // returns false if aborted by user - bool exploreFilesRecursive(const std::filesystem::path& directory, ExploreFileCallback cb, const std::filesystem::path* excludeDirFileName = {}); - // Check if file's extension is one of provided extensions bool hasFileAnyExtension(const std::filesystem::path& file, std::span extensions); diff --git a/src/libs/metadata/impl/taglib/Utils.cpp b/src/libs/metadata/impl/taglib/Utils.cpp index 17e0f93a..4142c99c 100644 --- a/src/libs/metadata/impl/taglib/Utils.cpp +++ b/src/libs/metadata/impl/taglib/Utils.cpp @@ -154,10 +154,7 @@ namespace lms::metadata::taglib::utils #endif if (file && !file->isValid()) - { - LMS_LOG(METADATA, DEBUG, "File " << file << ": failed to parse by extension"); file.reset(); - } return file; } @@ -208,10 +205,7 @@ namespace lms::metadata::taglib::utils #endif if (file && !file->isValid()) - { - LMS_LOG(METADATA, DEBUG, "File " << file << ": failed to parse by content"); file.reset(); - } return file; } @@ -223,7 +217,12 @@ namespace lms::metadata::taglib::utils TagLib::FileStream fileStream{ createFileStream(p) }; std::unique_ptr file{ parseFileByExtension(&fileStream, p.extension(), readStyle, readAudioProperties.value()) }; if (!file) + { + LMS_LOG(METADATA, DEBUG, "File " << p << ": failed to parse by extension"); file = parseFileByContent(&fileStream, readStyle, readAudioProperties.value()); + if (!file) + LMS_LOG(METADATA, DEBUG, "File " << p << ": failed to parse by content"); + } return file; } diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index 29d9c576..bfafaef1 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -37,10 +37,59 @@ namespace lms::scanner { - using namespace db; - namespace { + using ExploreFileCallback = std::function; + bool exploreFilesRecursive(const std::filesystem::path& directory, ExploreFileCallback cb, const std::filesystem::path* excludeDirFileName) + { + std::error_code ec; + std::filesystem::directory_iterator itPath{ directory, std::filesystem::directory_options::follow_directory_symlink, ec }; + + if (ec) + { + cb(ec, directory, nullptr); + return true; // try to continue exploring anyway + } + + if (excludeDirFileName && !excludeDirFileName->empty()) + { + const std::filesystem::path excludePath{ directory / *excludeDirFileName }; + if (std::filesystem::exists(excludePath, ec)) + { + LMS_LOG(DBUPDATER, DEBUG, "Found " << excludePath << ": skipping directory"); + return true; + } + } + + std::filesystem::directory_iterator itEnd; + while (itPath != itEnd) + { + bool continueExploring{ true }; + + const std::filesystem::directory_entry& entry{ *itPath }; + const std::filesystem::path& path{ entry.path() }; + + if (ec) + { + continueExploring = cb(ec, path, nullptr); + } + else + { + if (entry.is_regular_file()) + continueExploring = cb(ec, path, &entry); + else if (entry.is_directory()) + continueExploring = exploreFilesRecursive(path, cb, excludeDirFileName); + } + + if (!continueExploring) + return false; + + itPath.increment(ec); + } + + return true; + } + class FileScanJob : public core::IJob { public: @@ -97,11 +146,11 @@ namespace lms::scanner std::vector> jobsDone; std::vector> scanOperations; - core::pathUtils::exploreFilesRecursive( - mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path, const core::pathUtils::FileInfo* fileInfo) { + exploreFilesRecursive( + mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path, const std::filesystem::directory_entry* fileEntry) { LMS_SCOPED_TRACE_DETAILED("Scanner", "OnExploreFile"); - assert((ec && !fileInfo) || (!ec && fileInfo)); + assert((ec && !fileEntry) || (!ec && fileEntry)); if (_abortScan) return false; // stop iterating @@ -117,8 +166,8 @@ namespace lms::scanner fileToScan.filePath = path; fileToScan.mediaLibrary = mediaLibrary; - fileToScan.lastWriteTime.setTime_t(fileInfo->lastWriteTime.toTime_t()); // sec resolution, as stored in the database - fileToScan.fileSize = fileInfo->fileSize; + fileToScan.lastWriteTime.setTime_t(Wt::WDateTime{ std::chrono::file_clock::to_sys(fileEntry->last_write_time()) }.toTime_t()); // sec resolution, as stored in the database + fileToScan.fileSize = fileEntry->file_size(); if (context.scanOptions.fullScan || scanner->needsScan(fileToScan)) { From 37c75f86773fdde95900baf45c4243bc777c5d7e Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 19 Jul 2025 17:10:15 +0200 Subject: [PATCH 42/46] Optimized the differential scan step by using threads to check files --- src/libs/database/impl/Session.cpp | 17 +- .../database/include/database/Session.hpp | 5 +- src/libs/database/include/database/Types.hpp | 11 + .../services/scanner/impl/ScannerService.cpp | 8 +- .../steps/ScanStepCheckForRemovedFiles.cpp | 2 +- .../scanner/impl/steps/ScanStepScanFiles.cpp | 199 ++++++++++++------ .../scanner/impl/steps/ScanStepScanFiles.hpp | 7 +- 7 files changed, 162 insertions(+), 87 deletions(-) diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index b3394b14..b01e7268 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -23,6 +23,7 @@ #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" + #include "database/objects/Artist.hpp" #include "database/objects/ArtistInfo.hpp" #include "database/objects/Artwork.hpp" @@ -367,17 +368,17 @@ namespace lms::db }); } - std::size_t Session::getTotalFilesCount() + FileStats Session::getFileStats() { - std::size_t res{}; + FileStats stats{}; - res += db::Track::getCount(*this); - res += db::Image::getCount(*this); - res += db::TrackLyrics::getExternalLyricsCount(*this); - res += db::PlayListFile::getCount(*this); - res += db::ArtistInfo::getCount(*this); + stats.trackCount = db::Track::getCount(*this); + stats.artistInfoCount = db::ArtistInfo::getCount(*this); + stats.imageCount = db::Image::getCount(*this); + stats.trackLyricsCount = db::TrackLyrics::getExternalLyricsCount(*this); + stats.playListCount = db::PlayListFile::getCount(*this); - return res; + return stats; } void Session::retrieveEntriesToAnalyze(std::vector& entryList) diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index b7e45687..90c0448c 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -27,6 +27,7 @@ #include #include "database/Transaction.hpp" +#include "database/Types.hpp" namespace lms::db { @@ -52,8 +53,8 @@ namespace lms::db void retrieveEntriesToAnalyze(std::vector& entryList); void analyzeEntry(const std::string& entry); - bool areAllTablesEmpty(); // need to acquire a read transaction - std::size_t getTotalFilesCount(); // need to acquire a read transaction + bool areAllTablesEmpty(); // need to acquire a read transaction + FileStats getFileStats(); // need to acquire a read transaction void prepareTablesIfNeeded(); // need to run only once at startup bool migrateSchemaIfNeeded(); // returns true if migration was performed diff --git a/src/libs/database/include/database/Types.hpp b/src/libs/database/include/database/Types.hpp index c2103044..9d4e4fc4 100644 --- a/src/libs/database/include/database/Types.hpp +++ b/src/libs/database/include/database/Types.hpp @@ -102,6 +102,17 @@ namespace lms::db } }; + struct FileStats + { + std::size_t trackCount; + std::size_t imageCount; + std::size_t trackLyricsCount; + std::size_t playListCount; + std::size_t artistInfoCount; + + std::size_t getTotalFileCount() const { return trackCount + imageCount + trackLyricsCount + playListCount + artistInfoCount; } + }; + struct YearRange { int begin{}; diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index 3cf55aa8..b944dafb 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -166,17 +166,17 @@ namespace lms::scanner LMS_LOG(DBUPDATER, INFO, "Using " << _jobScheduler->getThreadCount() << " thread(s) for jobs"); _jobScheduler->setShouldAbortCallback([this]() { return _abortScan; }); - std::size_t totalFilesCount{}; + std::size_t totalFileCount{}; { auto& session{ _db.getTLSSession() }; auto transaction{ session.createReadTransaction() }; - totalFilesCount = session.getTotalFilesCount(); + totalFileCount = session.getFileStats().getTotalFileCount(); } // Force optimize in case scanner aborted during a large import, but do this only if there are enough elements in the database // Otherwise, indexes may be not used and queries may be slower and slower while adding more and more elements in the db - LMS_LOG(DBUPDATER, INFO, "Scanned file count = " << totalFilesCount); - if (totalFilesCount >= 1'000) + LMS_LOG(DBUPDATER, INFO, "Scanned file count = " << totalFileCount); + if (totalFileCount >= 1'000) _db.getTLSSession().fullAnalyze(); refreshTracingLoggerStats(); diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index 0266249b..9a6bee1a 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -194,7 +194,7 @@ namespace lms::scanner { auto transaction{ session.createReadTransaction() }; - context.currentStepStats.totalElems = session.getTotalFilesCount(); + context.currentStepStats.totalElems = session.getFileStats().getTotalFileCount(); } LMS_LOG(DBUPDATER, DEBUG, context.currentStepStats.totalElems << " files to be checked..."); diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index bfafaef1..6f319ddf 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -19,12 +19,13 @@ #include "ScanStepScanFiles.hpp" +#include + #include "ScannerSettings.hpp" #include "core/IJob.hpp" #include "core/IJobScheduler.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" -#include "core/Path.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" #include "scanners/FileToScan.hpp" @@ -93,28 +94,60 @@ namespace lms::scanner class FileScanJob : public core::IJob { public: - FileScanJob(std::unique_ptr scanOperation) - : _scanOperation{ std::move(scanOperation) } + FileScanJob(const FileScanners& fileScanners, const MediaLibraryInfo& mediaLibrary, bool fullScan, std::span files) + : _fileScanners{ fileScanners } + , _mediaLibrary{ mediaLibrary } + , _fullScan{ fullScan } + , _files{ std::cbegin(files), std::cend(files) } { } - IFileScanOperation& getScanOperation() + std::size_t getFileCount() const { return _files.size(); }; + + std::span> getScanOperations() { - return *_scanOperation; + return _scanOperations; } private: core::LiteralString getName() const override { - return _scanOperation->getName(); + return "Scan Files"; } void run() override { - _scanOperation->scan(); + for (const auto& file : _files) + { + IFileScanner* scanner{ _fileScanners.select(file.path()) }; + if (!scanner) + continue; + + FileToScan fileToScan; + + fileToScan.filePath = file.path(); + fileToScan.mediaLibrary = _mediaLibrary; + fileToScan.lastWriteTime.setTime_t(Wt::WDateTime{ std::chrono::file_clock::to_sys(file.last_write_time()) }.toTime_t()); // sec resolution, as stored in the database + fileToScan.fileSize = file.file_size(); + + if (_fullScan || scanner->needsScan(fileToScan)) + { + auto scanOperation{ scanner->createScanOperation(std::move(fileToScan)) }; + + { + LMS_SCOPED_TRACE_DETAILED("Scanner", scanOperation->getName()); + scanOperation->scan(); + } + _scanOperations.push_back(std::move(scanOperation)); + } + } } - std::unique_ptr _scanOperation; + const FileScanners& _fileScanners; + const MediaLibraryInfo& _mediaLibrary; + const bool _fullScan; + std::vector _files; + std::vector> _scanOperations; }; } // namespace @@ -128,96 +161,124 @@ namespace lms::scanner { for (const MediaLibraryInfo& mediaLibrary : _settings.mediaLibraries) process(context, mediaLibrary); + + context.stats.totalFileCount = context.currentStepStats.processedElems; } void ScanStepScanFiles::process(ScanContext& context, const MediaLibraryInfo& mediaLibrary) { - const std::size_t scanQueueMaxScanRequestCount{ 50 * getJobScheduler().getThreadCount() }; - constexpr std::size_t processFileResultsBatchSize{ 10 }; + constexpr std::size_t filesPerScanJob{ 10 }; + constexpr std::size_t scanQueueMaxSize{ 50 }; + constexpr std::size_t processFileResultsBatchSize{ 1 }; constexpr float drainRatio{ 0.85 }; + std::deque> operations; + auto processDoneJobs = [&](std::span> jobsDone) { + for (const auto& jobDone : jobsDone) + { + auto& fileScanJob{ static_cast(*jobDone) }; + for (std::unique_ptr& scanOperation : fileScanJob.getScanOperations()) + operations.push_back(std::move(scanOperation)); + + context.currentStepStats.processedElems += fileScanJob.getFileCount(); + } + if (!_abortScan) - processFileScanResults(context, jobsDone); + processFileScanOperations(context, operations, true /* force batch */); + + _progressCallback(context.currentStepStats); }; - JobQueue queue{ getJobScheduler(), scanQueueMaxScanRequestCount, processDoneJobs, processFileResultsBatchSize, drainRatio }; + { + JobQueue queue{ getJobScheduler(), scanQueueMaxSize, processDoneJobs, processFileResultsBatchSize, drainRatio }; - std::vector> jobsDone; - std::vector> scanOperations; + std::vector filesToScan; - exploreFilesRecursive( - mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path, const std::filesystem::directory_entry* fileEntry) { - LMS_SCOPED_TRACE_DETAILED("Scanner", "OnExploreFile"); + exploreFilesRecursive( + mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path, const std::filesystem::directory_entry* fileEntry) { + LMS_SCOPED_TRACE_DETAILED("Scanner", "OnExploreFile"); - assert((ec && !fileEntry) || (!ec && fileEntry)); + assert((ec && !fileEntry) || (!ec && fileEntry)); - if (_abortScan) - return false; // stop iterating + if (_abortScan) + return false; // stop iterating - if (ec) - { - addError(context, path, ec); - context.stats.skips++; - } - else if (IFileScanner * scanner{ getFileScanners().select(path) }) - { - FileToScan fileToScan; - - fileToScan.filePath = path; - fileToScan.mediaLibrary = mediaLibrary; - fileToScan.lastWriteTime.setTime_t(Wt::WDateTime{ std::chrono::file_clock::to_sys(fileEntry->last_write_time()) }.toTime_t()); // sec resolution, as stored in the database - fileToScan.fileSize = fileEntry->file_size(); - - if (context.scanOptions.fullScan || scanner->needsScan(fileToScan)) + if (ec) { - auto scanOperation{ scanner->createScanOperation(std::move(fileToScan)) }; - queue.push(std::make_unique(std::move(scanOperation))); + addError(context, path, ec); + context.stats.skips++; + } + else + { + filesToScan.push_back(*fileEntry); + + if (filesToScan.size() >= filesPerScanJob) + { + queue.push(std::make_unique(getFileScanners(), mediaLibrary, context.scanOptions.fullScan, filesToScan)); + filesToScan.clear(); + } } - context.currentStepStats.processedElems++; - _progressCallback(context.currentStepStats); - } + return true; + }, + &excludeDirFileName); - return true; - }, - &excludeDirFileName); + if (!filesToScan.empty()) + queue.push(std::make_unique(getFileScanners(), mediaLibrary, context.scanOptions.fullScan, filesToScan)); - context.stats.totalFileCount = context.currentStepStats.totalElems; + _progressCallback(context.currentStepStats); + } + + // Process remaining objects + processFileScanOperations(context, operations, false /* force batch */); } - void ScanStepScanFiles::processFileScanResults(ScanContext& context, std::span> scanJobs) + std::size_t ScanStepScanFiles::processFileScanOperations(ScanContext& context, std::deque>& scanOperations, bool forceBatch) { + std::size_t count{}; + constexpr std::size_t writeBatchSize{ 10 }; + LMS_SCOPED_TRACE_OVERVIEW("Scanner", "ProcessScanResults"); - db::Session& dbSession{ _db.getTLSSession() }; - auto transaction{ dbSession.createWriteTransaction() }; - - for (auto& scanJob : scanJobs) + while ((forceBatch && scanOperations.size() >= writeBatchSize) || !scanOperations.empty()) { - IFileScanOperation& scanOperation{ static_cast(*scanJob).getScanOperation() }; + db::Session& dbSession{ _db.getTLSSession() }; + auto transaction{ dbSession.createWriteTransaction() }; - LMS_LOG(DBUPDATER, DEBUG, scanOperation.getName() << ": processing result for " << scanOperation.getFilePath()); - const IFileScanOperation::OperationResult res{ scanOperation.processResult() }; - switch (res) + for (std::size_t i{}; !scanOperations.empty() && i < writeBatchSize; ++i) { - case IFileScanOperation::OperationResult::Added: - context.stats.additions++; - break; - case IFileScanOperation::OperationResult::Removed: - context.stats.deletions++; - break; - case IFileScanOperation::OperationResult::Skipped: - context.stats.failures++; - break; - case IFileScanOperation::OperationResult::Updated: - context.stats.updates++; - break; + processFileScanOperation(context, *scanOperations.front()); + scanOperations.pop_front(); + count++; } - context.stats.scans++; - - for (const auto& error : scanOperation.getErrors()) - addError(context, error); } + + return count; + } + + void ScanStepScanFiles::processFileScanOperation(ScanContext& context, IFileScanOperation& scanOperation) + { + LMS_LOG(DBUPDATER, DEBUG, scanOperation.getName() << ": processing result for " << scanOperation.getFilePath()); + const IFileScanOperation::OperationResult res{ scanOperation.processResult() }; + switch (res) + { + case IFileScanOperation::OperationResult::Added: + context.stats.additions++; + break; + case IFileScanOperation::OperationResult::Removed: + context.stats.deletions++; + break; + case IFileScanOperation::OperationResult::Skipped: + context.stats.failures++; + break; + case IFileScanOperation::OperationResult::Updated: + context.stats.updates++; + break; + } + context.stats.scans++; + + for (const auto& error : scanOperation.getErrors()) + addError(context, error); } } // namespace lms::scanner \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp index fe0b2ece..0713454a 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp @@ -19,7 +19,7 @@ #pragma once -#include +#include #include "ScanStepBase.hpp" @@ -30,7 +30,7 @@ namespace lms::core namespace lms::scanner { - class IFileScanner; + class IFileScanOperation; struct MediaLibraryInfo; class ScanStepScanFiles : public ScanStepBase @@ -45,6 +45,7 @@ namespace lms::scanner void process(ScanContext& context) override; void process(ScanContext& context, const MediaLibraryInfo& mediaLibrary); - void processFileScanResults(ScanContext& context, std::span> scanJobs); + std::size_t processFileScanOperations(ScanContext& context, std::deque>& scanOperations, bool forceBatch); + void processFileScanOperation(ScanContext& context, IFileScanOperation& operation); }; } // namespace lms::scanner From b620dc8650ed4468cc3146ce97cd3d6cfe70f737 Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 19 Jul 2025 17:44:37 +0200 Subject: [PATCH 43/46] Fixed bad fallback on content detection for ogg files, fixes #715 --- src/libs/metadata/impl/taglib/Utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/metadata/impl/taglib/Utils.cpp b/src/libs/metadata/impl/taglib/Utils.cpp index 4142c99c..94dcc168 100644 --- a/src/libs/metadata/impl/taglib/Utils.cpp +++ b/src/libs/metadata/impl/taglib/Utils.cpp @@ -111,7 +111,7 @@ namespace lms::metadata::taglib::utils file = std::make_unique(stream, TagLib::ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); // VORBIS else if (ext == "OGG") - return std::make_unique(stream, readAudioProperties, audioPropertiesStyle); + file = std::make_unique(stream, readAudioProperties, audioPropertiesStyle); else if (ext == "OGA") { /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ From 34e619f8b2332326b9e0c420bde459e70ff3caac Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 19 Jul 2025 22:15:47 +0200 Subject: [PATCH 44/46] Added support for various potential musicbrainz custom tags like musicbrainz_composerid, fixes #709 --- src/libs/metadata/impl/AudioFileParser.cpp | 12 ++++++------ src/libs/metadata/impl/ITagReader.hpp | 8 ++++++++ .../metadata/impl/avformat/AvFormatTagReader.cpp | 8 ++++++++ src/libs/metadata/impl/taglib/TagLibTagReader.cpp | 8 ++++++++ 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/libs/metadata/impl/AudioFileParser.cpp b/src/libs/metadata/impl/AudioFileParser.cpp index 29cfa356..60f36eda 100644 --- a/src/libs/metadata/impl/AudioFileParser.cpp +++ b/src/libs/metadata/impl/AudioFileParser.cpp @@ -456,12 +456,12 @@ namespace lms::metadata track.artists = getArtists(tagReader, { TagType::Artists, TagType::Artist }, { TagType::ArtistSortOrder }, { TagType::MusicBrainzArtistID }, _params); track.artistDisplayName = computeArtistDisplayName(track.artists, getTagValueAs(tagReader, TagType::Artist), _params.artistTagDelimiters); - track.conductorArtists = getArtists(tagReader, { TagType::Conductors, TagType::Conductor }, { TagType::ConductorsSortOrder, TagType::ConductorSortOrder }, {}, _params); - track.composerArtists = getArtists(tagReader, { TagType::Composers, TagType::Composer }, { TagType::ComposersSortOrder, TagType::ComposerSortOrder }, {}, _params); - track.lyricistArtists = getArtists(tagReader, { TagType::Lyricists, TagType::Lyricist }, { TagType::LyricistsSortOrder, TagType::LyricistSortOrder }, {}, _params); - track.mixerArtists = getArtists(tagReader, { TagType::Mixers, TagType::Mixer }, { TagType::MixersSortOrder, TagType::MixerSortOrder }, {}, _params); - track.producerArtists = getArtists(tagReader, { TagType::Producers, TagType::Producer }, { TagType::ProducersSortOrder, TagType::ProducerSortOrder }, {}, _params); - track.remixerArtists = getArtists(tagReader, { TagType::Remixers, TagType::Remixer }, { TagType::RemixersSortOrder, TagType::RemixerSortOrder }, {}, _params); + track.conductorArtists = getArtists(tagReader, { TagType::Conductors, TagType::Conductor }, { TagType::ConductorsSortOrder, TagType::ConductorSortOrder }, { TagType::MusicBrainzConductorID }, _params); + track.composerArtists = getArtists(tagReader, { TagType::Composers, TagType::Composer }, { TagType::ComposersSortOrder, TagType::ComposerSortOrder }, { TagType::MusicBrainzComposerID }, _params); + track.lyricistArtists = getArtists(tagReader, { TagType::Lyricists, TagType::Lyricist }, { TagType::LyricistsSortOrder, TagType::LyricistSortOrder }, { TagType::MusicBrainzLyricistID }, _params); + track.mixerArtists = getArtists(tagReader, { TagType::Mixers, TagType::Mixer }, { TagType::MixersSortOrder, TagType::MixerSortOrder }, { TagType::MusicBrainzMixerID }, _params); + track.producerArtists = getArtists(tagReader, { TagType::Producers, TagType::Producer }, { TagType::ProducersSortOrder, TagType::ProducerSortOrder }, { TagType::MusicBrainzProducerID }, _params); + track.remixerArtists = getArtists(tagReader, { TagType::Remixers, TagType::Remixer }, { TagType::RemixersSortOrder, TagType::RemixerSortOrder }, { TagType::MusicBrainzRemixerID }, _params); track.performerArtists = getPerformerArtists(tagReader); // artistDelimiters not supported // If a file has originalDate but no originalYear, set it diff --git a/src/libs/metadata/impl/ITagReader.hpp b/src/libs/metadata/impl/ITagReader.hpp index 0b4bc8db..cc35d28c 100644 --- a/src/libs/metadata/impl/ITagReader.hpp +++ b/src/libs/metadata/impl/ITagReader.hpp @@ -89,14 +89,22 @@ namespace lms::metadata Movement, MovementCount, MovementNumber, + MusicBrainzArrangerID, // non standard MusicBrainzArtistID, + MusicBrainzComposerID, // non standard + MusicBrainzConductorID, // non standard + MusicBrainzDirectorID, // non standard MusicBrainzDiscID, + MusicBrainzLyricistID, // non standard MusicBrainzOriginalArtistID, MusicBrainzOriginalReleaseID, + MusicBrainzMixerID, // non standard + MusicBrainzProducerID, // non standard MusicBrainzRecordingID, MusicBrainzReleaseArtistID, MusicBrainzReleaseGroupID, MusicBrainzReleaseID, + MusicBrainzRemixerID, // non standard MusicBrainzTrackID, MusicBrainzWorkID, MusicIPFingerprint, diff --git a/src/libs/metadata/impl/avformat/AvFormatTagReader.cpp b/src/libs/metadata/impl/avformat/AvFormatTagReader.cpp index 1ac145a0..30134f3e 100644 --- a/src/libs/metadata/impl/avformat/AvFormatTagReader.cpp +++ b/src/libs/metadata/impl/avformat/AvFormatTagReader.cpp @@ -89,13 +89,21 @@ namespace lms::metadata::avformat { TagType::MovementCount, { "MOVEMENTCOUNT" } }, { TagType::MovementNumber, { "MOVEMENTNUMBER" } }, { TagType::MusicBrainzArtistID, { "MUSICBRAINZ_ARTISTID", "MUSICBRAINZ ARTIST ID", "MUSICBRAINZ/ARTIST ID" } }, + { TagType::MusicBrainzArrangerID, { "MUSICBRAINZ_ARRANGERID", "MUSICBRAINZ ARRANGER ID", "MUSICBRAINZ/ARRANGER ID" } }, + { TagType::MusicBrainzComposerID, { "MUSICBRAINZ_COMPOSERID", "MUSICBRAINZ COMPOSER ID", "MUSICBRAINZ/COMPOSER ID" } }, + { TagType::MusicBrainzConductorID, { "MUSICBRAINZ_CONDUCTORID", "MUSICBRAINZ CONDUCTOR ID", "MUSICBRAINZ/CONDUCTOR ID" } }, + { TagType::MusicBrainzDirectorID, { "MUSICBRAINZ_DIRECTORID", "MUSICBRAINZ DIRECTOR ID", "MUSICBRAINZ/DIRECTOR ID" } }, { TagType::MusicBrainzDiscID, { "MUSICBRAINZ_DISCID", "MUSICBRAINZ DISC ID", "MUSICBRAINZ/DISC ID" } }, + { TagType::MusicBrainzLyricistID, { "MUSICBRAINZ_LYRICISTID", "MUSICBRAINZ LYRICIST ID", "MUSICBRAINZ/LYRICIST ID" } }, { TagType::MusicBrainzOriginalArtistID, { "MUSICBRAINZ_ORIGINALARTISTID", "MUSICBRAINZ ORIGINAL ARTIST ID", "MUSICBRAINZ/ORIGINAL ARTIST ID" } }, { TagType::MusicBrainzOriginalReleaseID, { "MUSICBRAINZ_ORIGINALRELEASEID", "MUSICBRAINZ ORIGINAL RELEASE ID", "MUSICBRAINZ/ORIGINAL RELEASE ID" } }, + { TagType::MusicBrainzMixerID, { "MUSICBRAINZ_MIXERID", "MUSICBRAINZ MIXER ID", "MUSICBRAINZ/MIXER ID" } }, + { TagType::MusicBrainzProducerID, { "MUSICBRAINZ_PRODUCERID", "MUSICBRAINZ PRODUCER ID", "MUSICBRAINZ/PRODUCER ID" } }, { TagType::MusicBrainzRecordingID, { "MUSICBRAINZ_TRACKID", "MUSICBRAINZ TRACK ID", "MUSICBRAINZ/TRACK ID" } }, { TagType::MusicBrainzReleaseArtistID, { "MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ/ALBUM ARTIST ID" } }, { TagType::MusicBrainzReleaseGroupID, { "MUSICBRAINZ_RELEASEGROUPID", "MUSICBRAINZ RELEASE GROUP ID", "MUSICBRAINZ/RELEASE GROUP ID" } }, { TagType::MusicBrainzReleaseID, { "MUSICBRAINZ_ALBUMID", "MUSICBRAINZ ALBUM ID", "MUSICBRAINZ/ALBUM ID" } }, + { TagType::MusicBrainzRemixerID, { "MUSICBRAINZ_REMIXERID", "MUSICBRAINZ REMIXER ID", "MUSICBRAINZ/REMIXER ID" } }, { TagType::MusicBrainzTrackID, { "MUSICBRAINZ_RELEASETRACKID", "MUSICBRAINZ RELEASE TRACK ID", "MUSICBRAINZ/RELEASE TRACK ID" } }, { TagType::MusicBrainzWorkID, { "MUSICBRAINZ_WORKID", "MUSICBRAINZ WORK ID", "MUSICBRAINZ/WORK ID" } }, { TagType::OriginalArtist, { "ORIGINALARTIST" } }, diff --git a/src/libs/metadata/impl/taglib/TagLibTagReader.cpp b/src/libs/metadata/impl/taglib/TagLibTagReader.cpp index a7ae70e0..44a0d7ab 100644 --- a/src/libs/metadata/impl/taglib/TagLibTagReader.cpp +++ b/src/libs/metadata/impl/taglib/TagLibTagReader.cpp @@ -124,13 +124,21 @@ namespace lms::metadata::taglib { TagType::MovementCount, { "MOVEMENTCOUNT" } }, { TagType::MovementNumber, { "MOVEMENTNUMBER" } }, { TagType::MusicBrainzArtistID, { "MUSICBRAINZ_ARTISTID", "MUSICBRAINZ ARTIST ID", "MUSICBRAINZ/ARTIST ID" } }, + { TagType::MusicBrainzArrangerID, { "MUSICBRAINZ_ARRANGERID", "MUSICBRAINZ ARRANGER ID", "MUSICBRAINZ/ARRANGER ID" } }, + { TagType::MusicBrainzComposerID, { "MUSICBRAINZ_COMPOSERID", "MUSICBRAINZ COMPOSER ID", "MUSICBRAINZ/COMPOSER ID" } }, + { TagType::MusicBrainzConductorID, { "MUSICBRAINZ_CONDUCTORID", "MUSICBRAINZ CONDUCTOR ID", "MUSICBRAINZ/CONDUCTOR ID" } }, + { TagType::MusicBrainzDirectorID, { "MUSICBRAINZ_DIRECTORID", "MUSICBRAINZ DIRECTOR ID", "MUSICBRAINZ/DIRECTOR ID" } }, { TagType::MusicBrainzDiscID, { "MUSICBRAINZ_DISCID", "MUSICBRAINZ DISC ID", "MUSICBRAINZ/DISC ID" } }, + { TagType::MusicBrainzLyricistID, { "MUSICBRAINZ_LYRICISTID", "MUSICBRAINZ LYRICIST ID", "MUSICBRAINZ/LYRICIST ID" } }, { TagType::MusicBrainzOriginalArtistID, { "MUSICBRAINZ_ORIGINALARTISTID", "MUSICBRAINZ ORIGINAL ARTIST ID", "MUSICBRAINZ/ORIGINAL ARTIST ID" } }, { TagType::MusicBrainzOriginalReleaseID, { "MUSICBRAINZ_ORIGINALRELEASEID", "MUSICBRAINZ ORIGINAL RELEASE ID", "MUSICBRAINZ/ORIGINAL RELEASE ID" } }, + { TagType::MusicBrainzMixerID, { "MUSICBRAINZ_MIXERID", "MUSICBRAINZ MIXER ID", "MUSICBRAINZ/MIXER ID" } }, + { TagType::MusicBrainzProducerID, { "MUSICBRAINZ_PRODUCERID", "MUSICBRAINZ PRODUCER ID", "MUSICBRAINZ/PRODUCER ID" } }, { TagType::MusicBrainzRecordingID, { "MUSICBRAINZ_TRACKID", "MUSICBRAINZ TRACK ID", "MUSICBRAINZ/TRACK ID" } }, { TagType::MusicBrainzReleaseArtistID, { "MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ/ALBUM ARTIST ID" } }, { TagType::MusicBrainzReleaseGroupID, { "MUSICBRAINZ_RELEASEGROUPID", "MUSICBRAINZ RELEASE GROUP ID", "MUSICBRAINZ/RELEASE GROUP ID" } }, { TagType::MusicBrainzReleaseID, { "MUSICBRAINZ_ALBUMID", "MUSICBRAINZ ALBUM ID", "MUSICBRAINZ/ALBUM ID" } }, + { TagType::MusicBrainzRemixerID, { "MUSICBRAINZ_REMIXERID", "MUSICBRAINZ REMIXER ID", "MUSICBRAINZ/REMIXER ID" } }, { TagType::MusicBrainzTrackID, { "MUSICBRAINZ_RELEASETRACKID", "MUSICBRAINZ RELEASE TRACK ID", "MUSICBRAINZ/RELEASE TRACK ID" } }, { TagType::MusicBrainzWorkID, { "MUSICBRAINZ_WORKID", "MUSICBRAINZ WORK ID", "MUSICBRAINZ/WORK ID" } }, { TagType::OriginalArtist, { "ORIGINALARTIST" } }, From 6cf59b3294b259c08716f6932ec87b0bca3d8e9d Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 19 Jul 2025 22:24:40 +0200 Subject: [PATCH 45/46] Fixed clang format --- src/libs/metadata/impl/ITagReader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/metadata/impl/ITagReader.hpp b/src/libs/metadata/impl/ITagReader.hpp index cc35d28c..0cf72856 100644 --- a/src/libs/metadata/impl/ITagReader.hpp +++ b/src/libs/metadata/impl/ITagReader.hpp @@ -98,7 +98,7 @@ namespace lms::metadata MusicBrainzLyricistID, // non standard MusicBrainzOriginalArtistID, MusicBrainzOriginalReleaseID, - MusicBrainzMixerID, // non standard + MusicBrainzMixerID, // non standard MusicBrainzProducerID, // non standard MusicBrainzRecordingID, MusicBrainzReleaseArtistID, From 79872e28871c49cc61bfd1477ae092bf0a81c5aa Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 19 Jul 2025 22:57:05 +0200 Subject: [PATCH 46/46] Fixed stats --- src/libs/services/scanner/impl/ScannerService.cpp | 6 ++++++ .../scanner/impl/steps/ScanStepScanFiles.cpp | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index b944dafb..b5b8a84b 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -388,6 +388,12 @@ namespace lms::scanner refreshTracingLoggerStats(); LMS_LOG(DBUPDATER, INFO, "Scan " << (_abortScan ? "aborted" : "complete") << ". Changes = " << stats.getChangesCount() << " (added = " << stats.additions << ", removed = " << stats.deletions << ", updated = " << stats.updates << ", failures = " << stats.failures << "), Not changed = " << stats.skips << ", Scanned = " << stats.scans << " (errors = " << stats.errorsCount << "), features fetched = " << stats.featuresFetched << ", duplicates = " << stats.duplicates.size()); + { + auto transaction{ _db.getTLSSession().createReadTransaction() }; + const db::FileStats stats{ _db.getTLSSession().getFileStats() }; + LMS_LOG(DBUPDATER, INFO, stats.getTotalFileCount() << " total files: " << stats.artistInfoCount << " artist info, " << stats.imageCount << " images, " << stats.playListCount << " playlists, " << stats.trackCount << " tracks, " << stats.trackLyricsCount << " lyrics"); + } + if (!_abortScan) { stats.stopTime = Wt::WDateTime::currentDateTime(); diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index 6f319ddf..85af7f8c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -98,11 +98,14 @@ namespace lms::scanner : _fileScanners{ fileScanners } , _mediaLibrary{ mediaLibrary } , _fullScan{ fullScan } + , _processCount{} + , _skipCount{} , _files{ std::cbegin(files), std::cend(files) } { } - std::size_t getFileCount() const { return _files.size(); }; + std::size_t getFileCount() const { return _processCount; }; + std::size_t getSkipCount() const { return _skipCount; } std::span> getScanOperations() { @@ -140,12 +143,18 @@ namespace lms::scanner } _scanOperations.push_back(std::move(scanOperation)); } + else + _skipCount++; + + _processCount++; } } const FileScanners& _fileScanners; const MediaLibraryInfo& _mediaLibrary; const bool _fullScan; + std::size_t _processCount; + std::size_t _skipCount; std::vector _files; std::vector> _scanOperations; }; @@ -182,6 +191,7 @@ namespace lms::scanner operations.push_back(std::move(scanOperation)); context.currentStepStats.processedElems += fileScanJob.getFileCount(); + context.stats.skips += fileScanJob.getSkipCount(); } if (!_abortScan)