Scanner: parallelized processing within artwork association steps

This commit is contained in:
emeric
2025-07-04 23:05:35 +02:00
parent 427f777c44
commit 204a4a8857
23 changed files with 982 additions and 458 deletions
+31
View File
@@ -237,6 +237,17 @@ namespace lms::db
});
}
void Artist::find(Session& session, const IdRange<ArtistId>& idRange, const std::function<void(const Artist::pointer&)>& func)
{
assert(idRange.isValid());
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Artist>>("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::pointer> Artist::find(Session& session, std::string_view name)
{
session.checkReadTransaction();
@@ -280,6 +291,16 @@ namespace lms::db
utils::forEachQueryRangeResult(query, params.range, func);
}
IdRange<ArtistId> Artist::findNextRange(Session& session, ArtistId lastRetrievedId, std::size_t count)
{
auto query{ session.getDboSession()->query<std::tuple<ArtistId, ArtistId>>("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<int>(count));
auto res{ utils::fetchQuerySingleResult(query) };
return IdRange<ArtistId>{ .first = std::get<0>(res), .last = std::get<1>(res) };
}
RangeResults<ArtistId> Artist::findOrphanIds(Session& session, std::optional<Range> range)
{
session.checkReadTransaction();
@@ -304,6 +325,16 @@ AND NOT EXISTS (
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("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<core::UUID> Artist::getMBID() const
{
return core::UUID::fromString(_mbid);
+18 -1
View File
@@ -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{};
+31
View File
@@ -504,6 +504,27 @@ namespace lms::db
});
}
void Release::find(Session& session, const IdRange<ReleaseId>& idRange, const std::function<void(const Release::pointer&)>& func)
{
assert(idRange.isValid());
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Release>>("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<ReleaseId> Release::findNextRange(Session& session, ReleaseId lastRetrievedId, std::size_t count)
{
auto query{ session.getDboSession()->query<std::tuple<ReleaseId, ReleaseId>>("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<int>(count));
auto res{ utils::fetchQuerySingleResult(query) };
return IdRange<ReleaseId>{ .first = std::get<0>(res), .last = std::get<1>(res) };
}
RangeResults<Release::pointer> Release::find(Session& session, const FindParameters& params)
{
session.checkReadTransaction();
@@ -528,6 +549,16 @@ namespace lms::db
return utils::execRangeQuery<ReleaseId>(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();
+21
View File
@@ -292,6 +292,27 @@ namespace lms::db
});
}
void Track::find(Session& session, const IdRange<TrackId>& idRange, const std::function<void(const Track::pointer&)>& func)
{
assert(idRange.isValid());
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Track>>("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<TrackId> Track::findNextRange(Session& session, TrackId lastRetrievedId, std::size_t count)
{
auto query{ session.getDboSession()->query<std::tuple<TrackId, TrackId>>("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<int>(count));
auto res{ utils::fetchQuerySingleResult(query) };
return IdRange<TrackId>{ .first = std::get<0>(res), .last = std::get<1>(res) };
}
bool Track::exists(Session& session, TrackId id)
{
session.checkReadTransaction();