Deduplicate embedded images, ref #628
This commit is contained in:
@@ -25,6 +25,8 @@ add_library(lmsdatabase STATIC
|
||||
impl/SqlQuery.cpp
|
||||
impl/Track.cpp
|
||||
impl/TrackBookmark.cpp
|
||||
impl/TrackEmbeddedImage.cpp
|
||||
impl/TrackEmbeddedImageLink.cpp
|
||||
impl/TrackLyrics.cpp
|
||||
impl/Types.cpp
|
||||
impl/UIState.cpp
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "PathTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/PathTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
#include "database/Release.hpp"
|
||||
#include "database/Session.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "PathTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/PathTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "PathTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/PathTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static constexpr Version LMS_DATABASE_VERSION{ 83 };
|
||||
static constexpr Version LMS_DATABASE_VERSION{ 84 };
|
||||
}
|
||||
|
||||
VersionInfo::VersionInfo()
|
||||
@@ -1101,11 +1101,42 @@ FROM tracklist)");
|
||||
|
||||
void migrateFromV82(Session& session)
|
||||
{
|
||||
// new setting to display inline artist relationships in the release view
|
||||
// New setting to display inline artist relationships in the release view
|
||||
utils::executeCommand(*session.getDboSession(), "ALTER TABLE user ADD COLUMN ui_enable_inline_artist_relationships BOOLEAN NOT NULL DEFAULT(false)");
|
||||
utils::executeCommand(*session.getDboSession(), "ALTER TABLE user ADD COLUMN ui_inline_artist_relationships BIGINT NOT NULL DEFAULT(68)"); // Composer + Performer
|
||||
}
|
||||
|
||||
void migrateFromV83(Session& session)
|
||||
{
|
||||
// New embedded track image handling
|
||||
utils::executeCommand(*session.getDboSession(), "ALTER TABLE track DROP COLUMN has_cover");
|
||||
utils::executeCommand(*session.getDboSession(), R"(CREATE TABLE IF NOT EXISTS "track_embedded_image" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"hash" text not null,
|
||||
"size" integer not null,
|
||||
"width" integer not null,
|
||||
"height" integer not null,
|
||||
"mime_type" text not null
|
||||
))");
|
||||
|
||||
utils::executeCommand(*session.getDboSession(), R"(CREATE TABLE IF NOT EXISTS "track_embedded_image_link" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"index" integer not null,
|
||||
"is_preferred" boolean not null,
|
||||
"type" integer not null,
|
||||
"description" text not null,
|
||||
"track_id" bigint,
|
||||
"track_embedded_image_id" bigint,
|
||||
constraint "fk_track_embedded_image_link_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred,
|
||||
constraint "fk_track_embedded_image_link_track_embedded_image" foreign key ("track_embedded_image_id") references "track_embedded_image" ("id") on delete cascade deferrable initially deferred
|
||||
))");
|
||||
|
||||
// Just increment the scan version of the settings to make the next scan rescan everything
|
||||
utils::executeCommand(*session.getDboSession(), "UPDATE scan_settings SET scan_version = scan_version + 1");
|
||||
}
|
||||
|
||||
bool doDbMigration(Session& session)
|
||||
{
|
||||
constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" };
|
||||
@@ -1165,6 +1196,7 @@ FROM tracklist)");
|
||||
{ 80, migrateFromV80 },
|
||||
{ 81, migrateFromV81 },
|
||||
{ 82, migrateFromV82 },
|
||||
{ 83, migrateFromV83 },
|
||||
};
|
||||
|
||||
bool migrationPerformed{};
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
#include "database/TrackList.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "PathTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/PathTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "EnumSetTraits.hpp"
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "PartialDateTimeTraits.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/EnumSetTraits.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/PartialDateTimeTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
#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"
|
||||
@@ -50,11 +52,12 @@
|
||||
#include "database/UIState.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "EnumSetTraits.hpp"
|
||||
#include "Migration.hpp"
|
||||
#include "PartialDateTimeTraits.hpp"
|
||||
#include "PathTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/EnumSetTraits.hpp"
|
||||
#include "traits/ImageHashTypeTraits.hpp"
|
||||
#include "traits/PartialDateTimeTraits.hpp"
|
||||
#include "traits/PathTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
@@ -122,6 +125,8 @@ namespace lms::db
|
||||
_session.mapClass<Track>("track");
|
||||
_session.mapClass<TrackBookmark>("track_bookmark");
|
||||
_session.mapClass<TrackArtistLink>("track_artist_link");
|
||||
_session.mapClass<TrackEmbeddedImage>("track_embedded_image");
|
||||
_session.mapClass<TrackEmbeddedImageLink>("track_embedded_image_link");
|
||||
_session.mapClass<TrackFeatures>("track_features");
|
||||
_session.mapClass<TrackList>("tracklist");
|
||||
_session.mapClass<TrackListEntry>("tracklist_entry");
|
||||
@@ -209,6 +214,13 @@ namespace lms::db
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS directory_media_library_idx ON directory(media_library_id)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS directory_name_idx ON directory(name COLLATE NOCASE)");
|
||||
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_id_idx ON track_embedded_image(id)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_embedded_image_hash_idx ON track_embedded_image(hash)");
|
||||
|
||||
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_is_preferred_track_id_track_embedded_image_id_idx ON track_embedded_image_link(is_preferred, 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)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS image_path_idx ON image(absolute_file_path)");
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -29,16 +29,18 @@
|
||||
#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 "IdTypeTraits.hpp"
|
||||
#include "PartialDateTimeTraits.hpp"
|
||||
#include "PathTraits.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/PartialDateTimeTraits.hpp"
|
||||
#include "traits/PathTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
@@ -177,12 +179,15 @@ namespace lms::db
|
||||
if (params.directory.isValid())
|
||||
query.where("t.directory_id = ?").bind(params.directory);
|
||||
|
||||
if (params.hasEmbeddedImage.has_value())
|
||||
query.where("t.has_cover = ?").bind(params.hasEmbeddedImage.value());
|
||||
|
||||
if (params.fileSize.has_value())
|
||||
query.where("t.file_size = ?").bind(static_cast<long long>(params.fileSize.value()));
|
||||
|
||||
if (params.embeddedImageId.isValid())
|
||||
{
|
||||
query.join("track_embedded_image_link t_e_i_l ON t_e_i_l.track_id = t.id");
|
||||
query.where("t_e_i_l.track_embedded_image_id = ?").bind(params.embeddedImageId);
|
||||
}
|
||||
|
||||
switch (params.sortMethod)
|
||||
{
|
||||
case TrackSortMethod::None:
|
||||
@@ -469,6 +474,16 @@ namespace lms::db
|
||||
_trackLyrics.insert(getDboPtr(lyrics));
|
||||
}
|
||||
|
||||
void Track::clearEmbeddedImageLinks()
|
||||
{
|
||||
_embeddedImageLinks.clear();
|
||||
}
|
||||
|
||||
void Track::addEmbeddedImageLink(const ObjectPtr<TrackEmbeddedImageLink>& image)
|
||||
{
|
||||
_embeddedImageLinks.insert(getDboPtr(image));
|
||||
}
|
||||
|
||||
std::optional<int> Track::getYear() const
|
||||
{
|
||||
return _date.getYear();
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "database/Directory.hpp"
|
||||
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/TrackEmbeddedImage.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/ImageHashTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
Wt::Dbo::Query<Wt::Dbo::ptr<TrackEmbeddedImage>> createQuery(Session& session, const TrackEmbeddedImage::FindParameters& params)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<TrackEmbeddedImage>>("SELECT t_e_i FROM track_embedded_image t_e_i") };
|
||||
|
||||
if (params.isPreferred
|
||||
|| params.track.isValid()
|
||||
|| params.release.isValid()
|
||||
|| params.trackList.isValid()
|
||||
|| params.sortMethod == TrackEmbeddedImageSortMethod::FrontCoverAndSize)
|
||||
{
|
||||
query.join("track_embedded_image_link t_e_i_l ON t_e_i_l.track_embedded_image_id = t_e_i.id");
|
||||
|
||||
if (params.isPreferred)
|
||||
query.where("t_e_i_l.is_preferred = ?").bind(params.isPreferred.value());
|
||||
|
||||
if (params.track.isValid())
|
||||
query.where("t_e_i_l.track_id = ?").bind(params.track);
|
||||
|
||||
if (params.release.isValid())
|
||||
{
|
||||
query.join("track t ON t_e_i_l.track_id = t.id");
|
||||
query.where("t.release_id = ?").bind(params.release);
|
||||
}
|
||||
|
||||
if (params.trackList.isValid())
|
||||
{
|
||||
query.join("tracklist_entry t_l_e ON t_l_e.track_id = t_e_i_l.track_id");
|
||||
query.where("t_l_e.tracklist_id = ?").bind(params.trackList);
|
||||
}
|
||||
}
|
||||
|
||||
switch (params.sortMethod)
|
||||
{
|
||||
case TrackEmbeddedImageSortMethod::None:
|
||||
break;
|
||||
case TrackEmbeddedImageSortMethod::FrontCoverAndSize:
|
||||
query.orderBy("CASE WHEN t_e_i_l.type = ? THEN 0 ELSE 1 END, t_e_i.size").bind(ImageType::FrontCover);
|
||||
break;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TrackEmbeddedImage::pointer TrackEmbeddedImage::create(Session& session)
|
||||
{
|
||||
return session.getDboSession()->add(std::unique_ptr<TrackEmbeddedImage>{ new TrackEmbeddedImage{} });
|
||||
}
|
||||
|
||||
std::size_t TrackEmbeddedImage::getCount(Session& session)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) FROM track_embedded_image"));
|
||||
}
|
||||
|
||||
TrackEmbeddedImage::pointer TrackEmbeddedImage::find(Session& session, TrackEmbeddedImageId id)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackEmbeddedImage>().where("id = ?").bind(id));
|
||||
}
|
||||
|
||||
void TrackEmbeddedImage::find(Session& session, const FindParameters& params, const std::function<void(const pointer&)>& func)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery(session, params) };
|
||||
utils::forEachQueryRangeResult(query, params.range, func);
|
||||
}
|
||||
|
||||
TrackEmbeddedImage::pointer TrackEmbeddedImage::find(Session& session, std::size_t size, ImageHashType hash)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ session.getDboSession()->find<TrackEmbeddedImage>().where("size = ?").bind(static_cast<int>(size)).where("hash = ?").bind(hash) };
|
||||
return utils::fetchQuerySingleResult(query);
|
||||
}
|
||||
|
||||
RangeResults<TrackEmbeddedImageId> TrackEmbeddedImage::findOrphanIds(Session& session, std::optional<Range> range)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ session.getDboSession()->query<TrackEmbeddedImageId>("SELECT t_e_i.id FROM track_embedded_image t_e_i LEFT JOIN track_embedded_image_link t_e_i_l ON t_e_i.id = t_e_i_l.track_embedded_image_id WHERE t_e_i_l.track_embedded_image_id IS NULL") };
|
||||
return utils::execRangeQuery<TrackEmbeddedImageId>(query, range);
|
||||
}
|
||||
|
||||
} // namespace lms::db
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "database/TrackEmbeddedImageLink.hpp"
|
||||
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/TrackEmbeddedImage.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
TrackEmbeddedImageLink::TrackEmbeddedImageLink(ObjectPtr<Track> track, ObjectPtr<TrackEmbeddedImage> image)
|
||||
: _track{ getDboPtr(track) }
|
||||
, _image{ getDboPtr(image) }
|
||||
{
|
||||
}
|
||||
|
||||
TrackEmbeddedImageLink::pointer TrackEmbeddedImageLink::create(Session& session, ObjectPtr<Track> track, ObjectPtr<TrackEmbeddedImage> image)
|
||||
{
|
||||
return session.getDboSession()->add(std::unique_ptr<TrackEmbeddedImageLink>{ new TrackEmbeddedImageLink{ track, image } });
|
||||
}
|
||||
|
||||
std::size_t TrackEmbeddedImageLink::getCount(Session& session)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) FROM track_embedded_image_link"));
|
||||
}
|
||||
|
||||
TrackEmbeddedImageLink::pointer TrackEmbeddedImageLink::find(Session& session, TrackEmbeddedImageLinkId id)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackEmbeddedImageLink>().where("id = ?").bind(id));
|
||||
}
|
||||
|
||||
ObjectPtr<Track> TrackEmbeddedImageLink::getTrack() const
|
||||
{
|
||||
return _track;
|
||||
}
|
||||
|
||||
ObjectPtr<TrackEmbeddedImage> TrackEmbeddedImageLink::getImage() const
|
||||
{
|
||||
return _image;
|
||||
}
|
||||
} // namespace lms::db
|
||||
@@ -27,8 +27,8 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "PathTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/PathTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -19,13 +19,12 @@
|
||||
|
||||
#include "database/UIState.hpp"
|
||||
|
||||
#include "core/ILogger.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/UIState.hpp"
|
||||
|
||||
#include "EnumSetTraits.hpp"
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "traits/EnumSetTraits.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
#include "traits/StringViewTraits.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Wt/Dbo/StdSqlTraits.h>
|
||||
|
||||
#include "core/String.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
namespace Wt::Dbo
|
||||
{
|
||||
template<>
|
||||
struct sql_value_traits<lms::db::ImageHashType>
|
||||
{
|
||||
static const bool specialized = true;
|
||||
// Uses an underlying string to encode this big value
|
||||
|
||||
static std::string type(SqlConnection* conn, int size)
|
||||
{
|
||||
return sql_value_traits<std::string, void>::type(conn, size);
|
||||
}
|
||||
|
||||
static void bind(const lms::db::ImageHashType& v, SqlStatement* statement, int column, int size)
|
||||
{
|
||||
std::string valueAsStr{ std::to_string(v.value()) };
|
||||
sql_value_traits<std::string>::bind(valueAsStr, statement, column, size);
|
||||
}
|
||||
|
||||
static bool read(lms::db::ImageHashType& v, SqlStatement* statement, int column, int size)
|
||||
{
|
||||
std::string valueAsStr;
|
||||
if (sql_value_traits<std::string>::read(valueAsStr, statement, column, size))
|
||||
{
|
||||
if (const auto parsedValue{ lms::core::stringUtils::readAs<lms::db::ImageHashType::underlying_type>(valueAsStr) })
|
||||
{
|
||||
v = lms::db::ImageHashType{ *parsedValue };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
v = lms::db::ImageHashType{};
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // namespace Wt::Dbo
|
||||
@@ -41,6 +41,7 @@
|
||||
#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"
|
||||
@@ -52,6 +53,7 @@ namespace lms::db
|
||||
class Cluster;
|
||||
class ClusterType;
|
||||
class Directory;
|
||||
class TrackEmbeddedImageLink;
|
||||
class MediaLibrary;
|
||||
class Release;
|
||||
class Session;
|
||||
@@ -85,8 +87,8 @@ namespace lms::db
|
||||
std::optional<int> trackNumber; // matching this track number
|
||||
std::optional<int> discNumber; // matching this disc number
|
||||
DirectoryId directory; // if set, tracks in this directory
|
||||
std::optional<bool> hasEmbeddedImage; // if set, tracks that have or not embedded images
|
||||
std::optional<std::size_t> fileSize; // if set, tracks that match this file size
|
||||
TrackEmbeddedImageId embeddedImageId; // if set, tracks that have this embedded image
|
||||
|
||||
FindParameters& setFilters(const Filters& _filters)
|
||||
{
|
||||
@@ -182,16 +184,16 @@ namespace lms::db
|
||||
directory = _directory;
|
||||
return *this;
|
||||
}
|
||||
FindParameters& setHasEmbeddedImage(std::optional<bool> _hasEmbeddedImage)
|
||||
{
|
||||
hasEmbeddedImage = _hasEmbeddedImage;
|
||||
return *this;
|
||||
}
|
||||
FindParameters& setFileSize(std::optional<std::size_t> _fileSize)
|
||||
{
|
||||
fileSize = _fileSize;
|
||||
return *this;
|
||||
}
|
||||
FindParameters& setEmbeddedImage(TrackEmbeddedImageId _embeddedImageId)
|
||||
{
|
||||
embeddedImageId = _embeddedImageId;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
Track() = default;
|
||||
@@ -232,7 +234,6 @@ namespace lms::db
|
||||
void setSampleRate(std::size_t channelCount) { _sampleRate = channelCount; }
|
||||
void setDate(const core::PartialDateTime& date) { _date = date; }
|
||||
void setOriginalDate(const core::PartialDateTime& date) { _originalDate = date; }
|
||||
void setHasCover(bool hasCover) { _hasCover = hasCover; }
|
||||
void setTrackMBID(const std::optional<core::UUID>& MBID) { _trackMBID = MBID ? MBID->getAsString() : ""; }
|
||||
void setRecordingMBID(const std::optional<core::UUID>& MBID) { _recordingMBID = MBID ? MBID->getAsString() : ""; }
|
||||
void setCopyright(std::string_view copyright);
|
||||
@@ -249,6 +250,8 @@ namespace lms::db
|
||||
void clearLyrics();
|
||||
void clearEmbeddedLyrics();
|
||||
void addLyrics(const ObjectPtr<TrackLyrics>& lyrics);
|
||||
void clearEmbeddedImageLinks();
|
||||
void addEmbeddedImageLink(const ObjectPtr<TrackEmbeddedImageLink>& link);
|
||||
void setMediaLibrary(ObjectPtr<MediaLibrary> mediaLibrary) { _mediaLibrary = getDboPtr(mediaLibrary); }
|
||||
void setDirectory(ObjectPtr<Directory> directory) { _directory = getDboPtr(directory); }
|
||||
|
||||
@@ -273,7 +276,6 @@ namespace lms::db
|
||||
std::optional<int> getOriginalYear() const;
|
||||
const Wt::WDateTime& getLastWriteTime() const { return _fileLastWrite; }
|
||||
const Wt::WDateTime& getAddedTime() const { return _fileAdded; }
|
||||
bool hasCover() const { return _hasCover; }
|
||||
bool hasLyrics() const;
|
||||
std::optional<core::UUID> getTrackMBID() const { return core::UUID::fromString(_trackMBID); }
|
||||
std::optional<core::UUID> getRecordingMBID() const { return core::UUID::fromString(_recordingMBID); }
|
||||
@@ -321,7 +323,6 @@ namespace lms::db
|
||||
Wt::Dbo::field(a, _fileSize, "file_size");
|
||||
Wt::Dbo::field(a, _fileLastWrite, "file_last_write");
|
||||
Wt::Dbo::field(a, _fileAdded, "file_added");
|
||||
Wt::Dbo::field(a, _hasCover, "has_cover");
|
||||
Wt::Dbo::field(a, _trackMBID, "mbid");
|
||||
Wt::Dbo::field(a, _recordingMBID, "recording_mbid");
|
||||
Wt::Dbo::field(a, _copyright, "copyright");
|
||||
@@ -338,6 +339,7 @@ namespace lms::db
|
||||
Wt::Dbo::hasMany(a, _trackArtistLinks, Wt::Dbo::ManyToOne, "track");
|
||||
Wt::Dbo::hasMany(a, _clusters, Wt::Dbo::ManyToMany, "track_cluster", "", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::hasMany(a, _trackLyrics, Wt::Dbo::ManyToOne, "track");
|
||||
Wt::Dbo::hasMany(a, _embeddedImageLinks, Wt::Dbo::ManyToOne, "track");
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -368,7 +370,6 @@ namespace lms::db
|
||||
long long _fileSize{};
|
||||
Wt::WDateTime _fileLastWrite;
|
||||
Wt::WDateTime _fileAdded;
|
||||
bool _hasCover{};
|
||||
std::string _trackMBID;
|
||||
std::string _recordingMBID;
|
||||
std::string _copyright;
|
||||
@@ -384,6 +385,7 @@ namespace lms::db
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackLyrics>> _trackLyrics;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackEmbeddedImageLink>> _embeddedImageLinks;
|
||||
};
|
||||
|
||||
namespace Debug
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
#include "database/Object.hpp"
|
||||
#include "database/ReleaseId.hpp"
|
||||
#include "database/TrackEmbeddedImageId.hpp"
|
||||
#include "database/TrackId.hpp"
|
||||
#include "database/TrackListId.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
class TrackEmbeddedImageLink;
|
||||
class Session;
|
||||
class Track;
|
||||
|
||||
class TrackEmbeddedImage final : public Object<TrackEmbeddedImage, TrackEmbeddedImageId>
|
||||
{
|
||||
public:
|
||||
TrackEmbeddedImage() = default;
|
||||
|
||||
struct FindParameters
|
||||
{
|
||||
std::optional<Range> range;
|
||||
TrackId track;
|
||||
ReleaseId release;
|
||||
TrackListId trackList;
|
||||
std::optional<bool> isPreferred;
|
||||
TrackEmbeddedImageSortMethod sortMethod{ TrackEmbeddedImageSortMethod::None };
|
||||
|
||||
FindParameters& setRange(std::optional<Range> _range)
|
||||
{
|
||||
range = _range;
|
||||
return *this;
|
||||
}
|
||||
FindParameters& setTrack(TrackId _track)
|
||||
{
|
||||
track = _track;
|
||||
return *this;
|
||||
}
|
||||
FindParameters& setRelease(ReleaseId _release)
|
||||
{
|
||||
release = _release;
|
||||
return *this;
|
||||
}
|
||||
FindParameters& setTrackList(TrackListId _trackList)
|
||||
{
|
||||
trackList = _trackList;
|
||||
return *this;
|
||||
}
|
||||
FindParameters& setIsPreferred(std::optional<bool> _isPreferred)
|
||||
{
|
||||
isPreferred = _isPreferred;
|
||||
return *this;
|
||||
}
|
||||
FindParameters& setSortMethod(TrackEmbeddedImageSortMethod _sortMethod)
|
||||
{
|
||||
sortMethod = _sortMethod;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// find
|
||||
static std::size_t getCount(Session& session);
|
||||
static pointer find(Session& session, TrackEmbeddedImageId id);
|
||||
static void find(Session& session, const FindParameters& params, const std::function<void(const pointer&)>& func);
|
||||
static pointer find(Session& session, std::size_t size, ImageHashType hash);
|
||||
static RangeResults<TrackEmbeddedImageId> findOrphanIds(Session& session, std::optional<Range> range);
|
||||
|
||||
// getters
|
||||
ImageHashType getHash() const { return _hash; }
|
||||
std::size_t getSize() const { return _size; }
|
||||
std::size_t getWidth() const { return _width; }
|
||||
std::size_t getHeight() const { return _height; }
|
||||
std::string_view getMimeType() const { return _mimeType; }
|
||||
|
||||
// setters
|
||||
void setHash(ImageHashType hash) { _hash = hash; }
|
||||
void setSize(std::size_t size) { _size = static_cast<int>(size); }
|
||||
void setWidth(std::size_t width) { _width = static_cast<int>(width); }
|
||||
void setHeight(std::size_t height) { _height = static_cast<int>(height); }
|
||||
void setMimeType(std::string_view mimeType) { _mimeType = mimeType; }
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _hash, "hash");
|
||||
Wt::Dbo::field(a, _size, "size");
|
||||
Wt::Dbo::field(a, _width, "width");
|
||||
Wt::Dbo::field(a, _height, "height");
|
||||
Wt::Dbo::field(a, _mimeType, "mime_type");
|
||||
|
||||
Wt::Dbo::hasMany(a, _links, Wt::Dbo::ManyToOne, "track_embedded_image");
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Session;
|
||||
|
||||
static pointer create(Session& session);
|
||||
|
||||
ImageHashType _hash;
|
||||
int _size{};
|
||||
int _width{};
|
||||
int _height{};
|
||||
std::string _mimeType;
|
||||
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackEmbeddedImageLink>> _links;
|
||||
};
|
||||
} // namespace lms::db
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(TrackEmbeddedImageId)
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
#include "database/Object.hpp"
|
||||
#include "database/TrackEmbeddedImageLinkId.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
class TrackEmbeddedImage;
|
||||
class Session;
|
||||
class Track;
|
||||
|
||||
class TrackEmbeddedImageLink final : public Object<TrackEmbeddedImageLink, TrackEmbeddedImageLinkId>
|
||||
{
|
||||
public:
|
||||
TrackEmbeddedImageLink() = default;
|
||||
|
||||
using HashType = std::uint64_t;
|
||||
|
||||
// find
|
||||
static std::size_t getCount(Session& session);
|
||||
static pointer find(Session& session, TrackEmbeddedImageLinkId id);
|
||||
|
||||
// getters
|
||||
ObjectPtr<Track> getTrack() const;
|
||||
ObjectPtr<TrackEmbeddedImage> getImage() const;
|
||||
std::size_t getIndex() const { return _index; }
|
||||
bool isPreferred() const { return _isPreferred; }
|
||||
ImageType getType() const { return _type; }
|
||||
std::string_view getDescription() const { return _description; }
|
||||
|
||||
// setters
|
||||
void setIndex(std::size_t index) { _index = static_cast<int>(index); }
|
||||
void setIsPreferred(bool isPreferred) { _isPreferred = isPreferred; }
|
||||
void setType(ImageType type) { _type = type; }
|
||||
void setDescription(std::string_view description) { _description = description; }
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _index, "index");
|
||||
Wt::Dbo::field(a, _isPreferred, "is_preferred");
|
||||
Wt::Dbo::field(a, _type, "type");
|
||||
Wt::Dbo::field(a, _description, "description");
|
||||
|
||||
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::belongsTo(a, _image, "track_embedded_image", Wt::Dbo::OnDeleteCascade);
|
||||
}
|
||||
|
||||
private:
|
||||
TrackEmbeddedImageLink(ObjectPtr<Track> track, ObjectPtr<TrackEmbeddedImage> image);
|
||||
|
||||
friend class Session;
|
||||
static pointer create(Session& session, ObjectPtr<Track> track, ObjectPtr<TrackEmbeddedImage> image);
|
||||
|
||||
int _index{}; // index within the track
|
||||
bool _isPreferred{};
|
||||
ImageType _type{ ImageType::Unknown };
|
||||
std::string _description;
|
||||
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
Wt::Dbo::ptr<TrackEmbeddedImage> _image;
|
||||
};
|
||||
} // namespace lms::db
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(TrackEmbeddedImageLinkId)
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <Wt/WDate.h>
|
||||
|
||||
#include "core/Exception.hpp"
|
||||
#include "core/TaggedType.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
@@ -136,6 +137,8 @@ namespace lms::db
|
||||
Name,
|
||||
};
|
||||
|
||||
using ImageHashType = core::TaggedType<class ImageHash, std::uint64_t>;
|
||||
|
||||
enum class LabelSortMethod
|
||||
{
|
||||
None,
|
||||
@@ -165,6 +168,12 @@ namespace lms::db
|
||||
Name,
|
||||
};
|
||||
|
||||
enum class TrackEmbeddedImageSortMethod
|
||||
{
|
||||
None,
|
||||
FrontCoverAndSize,
|
||||
};
|
||||
|
||||
enum class TrackListSortMethod
|
||||
{
|
||||
None,
|
||||
@@ -194,6 +203,32 @@ namespace lms::db
|
||||
EmbeddedFirst,
|
||||
};
|
||||
|
||||
enum class ImageType
|
||||
{
|
||||
Unknown = 0,
|
||||
Other = 1,
|
||||
FileIcon = 2,
|
||||
OtherFileIcon = 3,
|
||||
FrontCover = 4,
|
||||
BackCover = 5,
|
||||
LeafletPage = 6,
|
||||
Media = 7,
|
||||
LeadArtist = 8,
|
||||
Artist = 9,
|
||||
Conductor = 10,
|
||||
Band = 11,
|
||||
Composer = 12,
|
||||
Lyricist = 13,
|
||||
RecordingLocation = 14,
|
||||
DuringRecording = 15,
|
||||
DuringPerformance = 16,
|
||||
MovieScreenCapture = 17,
|
||||
ColouredFish = 18,
|
||||
Illustration = 19,
|
||||
BandLogo = 20,
|
||||
PublisherLogo = 21
|
||||
};
|
||||
|
||||
enum class TrackArtistLinkType
|
||||
{
|
||||
Artist = 0, // regular track artist
|
||||
|
||||
@@ -19,6 +19,7 @@ add_executable(test-database
|
||||
StarredTrack.cpp
|
||||
Track.cpp
|
||||
TrackBookmark.cpp
|
||||
TrackEmbeddedImage.cpp
|
||||
TrackFeatures.cpp
|
||||
TrackList.cpp
|
||||
TrackLyrics.cpp
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "database/StarredArtist.hpp"
|
||||
#include "database/StarredRelease.hpp"
|
||||
#include "database/StarredTrack.hpp"
|
||||
#include "database/TrackEmbeddedImage.hpp"
|
||||
#include "database/TrackEmbeddedImageLink.hpp"
|
||||
#include "database/TrackLyrics.hpp"
|
||||
#include "database/UIState.hpp"
|
||||
#include "database/User.hpp"
|
||||
@@ -344,6 +346,8 @@ VALUES
|
||||
EXPECT_FALSE(Cluster::find(session, ClusterId{}));
|
||||
EXPECT_FALSE(ClusterType::find(session, ClusterTypeId{}));
|
||||
EXPECT_FALSE(Directory::find(session, DirectoryId{}));
|
||||
EXPECT_FALSE(TrackEmbeddedImage::find(session, TrackEmbeddedImageId{}));
|
||||
EXPECT_FALSE(TrackEmbeddedImageLink::find(session, TrackEmbeddedImageLinkId{}));
|
||||
EXPECT_FALSE(Image::find(session, ImageId{}));
|
||||
EXPECT_FALSE(Label::find(session, LabelId{}));
|
||||
EXPECT_FALSE(Listen::find(session, ListenId{}));
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "database/TrackEmbeddedImage.hpp"
|
||||
#include "database/TrackEmbeddedImageLink.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
namespace lms::db::tests
|
||||
{
|
||||
using ScopedTrackEmbeddedImage = ScopedEntity<db::TrackEmbeddedImage>;
|
||||
using ScopedTrackEmbeddedImageLink = ScopedEntity<db::TrackEmbeddedImageLink>;
|
||||
|
||||
TEST_F(DatabaseFixture, TrackEmbeddedImage)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackEmbeddedImage::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedTrackEmbeddedImage image{ session };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackEmbeddedImage::getCount(session), 1);
|
||||
|
||||
const TrackEmbeddedImage::pointer img{ TrackEmbeddedImage::find(session, image.getId()) };
|
||||
ASSERT_NE(img, TrackEmbeddedImage::pointer{});
|
||||
EXPECT_EQ(img->getHash(), db::ImageHashType{});
|
||||
EXPECT_EQ(img->getSize(), 0);
|
||||
EXPECT_EQ(img->getWidth(), 0);
|
||||
EXPECT_EQ(img->getHeight(), 0);
|
||||
EXPECT_EQ(img->getMimeType(), "");
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackEmbeddedImage::pointer img{ TrackEmbeddedImage::find(session, image.getId()) };
|
||||
ASSERT_NE(img, TrackEmbeddedImage::pointer{});
|
||||
img.modify()->setHash(db::ImageHashType{ std::numeric_limits<std::uint64_t>::max() });
|
||||
img.modify()->setSize(1024 * 1024);
|
||||
img.modify()->setWidth(640);
|
||||
img.modify()->setHeight(480);
|
||||
img.modify()->setMimeType("image/jpeg");
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const TrackEmbeddedImage::pointer img{ TrackEmbeddedImage::find(session, image.getId()) };
|
||||
ASSERT_NE(img, TrackEmbeddedImage::pointer{});
|
||||
EXPECT_EQ(img->getHash(), db::ImageHashType{ std::numeric_limits<std::uint64_t>::max() });
|
||||
EXPECT_EQ(img->getSize(), 1024 * 1024);
|
||||
EXPECT_EQ(img->getWidth(), 640);
|
||||
EXPECT_EQ(img->getHeight(), 480);
|
||||
EXPECT_EQ(img->getMimeType(), "image/jpeg");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackEmbeddedImage_findByHash)
|
||||
{
|
||||
ScopedTrackEmbeddedImage image{ session };
|
||||
constexpr std::size_t size{ 1024 };
|
||||
constexpr db::ImageHashType hash{ 42 };
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackEmbeddedImage::pointer img{ TrackEmbeddedImage::find(session, image.getId()) };
|
||||
ASSERT_NE(img, TrackEmbeddedImage::pointer{});
|
||||
img.modify()->setHash(hash);
|
||||
img.modify()->setSize(size);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const TrackEmbeddedImage::pointer img{ TrackEmbeddedImage::find(session, size, hash) };
|
||||
ASSERT_NE(img, TrackEmbeddedImage::pointer{});
|
||||
EXPECT_EQ(image.getId(), img->getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const TrackEmbeddedImage::pointer img{ TrackEmbeddedImage::find(session, size + 1, hash) };
|
||||
EXPECT_EQ(img, TrackEmbeddedImage::pointer{});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackEmbeddedImage_findByParams)
|
||||
{
|
||||
ScopedTrackEmbeddedImage image{ session };
|
||||
ScopedTrack track{ session };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedTrackEmbeddedImageLink link{ session, track.lockAndGet(), image.lockAndGet() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
TrackEmbeddedImage::FindParameters params;
|
||||
params.setIsPreferred(true);
|
||||
|
||||
bool visited{};
|
||||
TrackEmbeddedImage::find(session, params, [&](const auto&) { visited = true; });
|
||||
EXPECT_FALSE(visited);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
link.get().modify()->setIsPreferred(true);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
TrackEmbeddedImage::FindParameters params;
|
||||
params.setIsPreferred(true);
|
||||
|
||||
bool visited{};
|
||||
TrackEmbeddedImage::find(session, params, [&](const auto&) { visited = true; });
|
||||
EXPECT_TRUE(visited);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
TrackEmbeddedImage::FindParameters params;
|
||||
params.setIsPreferred(true);
|
||||
params.setRelease(release.getId());
|
||||
|
||||
bool visited{};
|
||||
TrackEmbeddedImage::find(session, params, [&](const auto&) { visited = true; });
|
||||
EXPECT_FALSE(visited);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
TrackEmbeddedImage::FindParameters params;
|
||||
params.setIsPreferred(true);
|
||||
params.setRelease(release.getId());
|
||||
params.setSortMethod(TrackEmbeddedImageSortMethod::FrontCoverAndSize);
|
||||
|
||||
bool visited{};
|
||||
TrackEmbeddedImage::find(session, params, [&](const auto&) { visited = true; });
|
||||
EXPECT_TRUE(visited);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
TrackEmbeddedImage::FindParameters params;
|
||||
params.setIsPreferred(true);
|
||||
params.setTrack(track.getId());
|
||||
params.setSortMethod(TrackEmbeddedImageSortMethod::FrontCoverAndSize);
|
||||
|
||||
bool visited{};
|
||||
TrackEmbeddedImage::find(session, params, [&](const auto&) { visited = true; });
|
||||
EXPECT_TRUE(visited);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_findByEmbeddedImage)
|
||||
{
|
||||
ScopedTrackEmbeddedImage image{ session };
|
||||
ScopedTrack track{ session };
|
||||
ScopedTrackEmbeddedImageLink link{ session, track.lockAndGet(), image.lockAndGet() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
Track::FindParameters params;
|
||||
params.setEmbeddedImage(image->getId());
|
||||
|
||||
bool visited{};
|
||||
Track::find(session, params, [&](const auto&) { visited = true; });
|
||||
EXPECT_TRUE(visited);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackEmbeddedImage_findOrphans)
|
||||
{
|
||||
ScopedTrackEmbeddedImage image{ session };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto orphans{ TrackEmbeddedImage::findOrphanIds(session, std::nullopt) };
|
||||
ASSERT_EQ(orphans.results.size(), 1);
|
||||
EXPECT_EQ(orphans.results[0], image.getId());
|
||||
}
|
||||
|
||||
{
|
||||
ScopedTrack track{ session };
|
||||
ScopedTrackEmbeddedImageLink link{ session, track.lockAndGet(), image.lockAndGet() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto orphans{ TrackEmbeddedImage::findOrphanIds(session, std::nullopt) };
|
||||
ASSERT_EQ(orphans.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto orphans{ TrackEmbeddedImage::findOrphanIds(session, std::nullopt) };
|
||||
ASSERT_EQ(orphans.results.size(), 1);
|
||||
EXPECT_EQ(orphans.results[0], image.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackEmbeddedImageLink)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackEmbeddedImage::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedTrack track{ session };
|
||||
ScopedTrackEmbeddedImage image{ session };
|
||||
ScopedTrackEmbeddedImageLink imageLink{ session, track.lockAndGet(), image.lockAndGet() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackEmbeddedImageLink::getCount(session), 1);
|
||||
|
||||
const TrackEmbeddedImageLink::pointer link{ TrackEmbeddedImageLink::find(session, imageLink.getId()) };
|
||||
ASSERT_NE(link, TrackEmbeddedImageLink::pointer{});
|
||||
EXPECT_EQ(link->getIndex(), 0);
|
||||
EXPECT_EQ(link->getType(), ImageType::Unknown);
|
||||
EXPECT_EQ(link->getDescription(), "");
|
||||
EXPECT_EQ(link->getTrack(), track.get());
|
||||
EXPECT_EQ(link->getImage(), image.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackEmbeddedImageLink::pointer link{ TrackEmbeddedImageLink::find(session, imageLink.getId()) };
|
||||
ASSERT_NE(link, TrackEmbeddedImage::pointer{});
|
||||
link.modify()->setIndex(2);
|
||||
link.modify()->setType(ImageType::FrontCover);
|
||||
link.modify()->setDescription("MyDesc");
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const TrackEmbeddedImageLink::pointer img{ TrackEmbeddedImageLink::find(session, imageLink.getId()) };
|
||||
ASSERT_NE(img, TrackEmbeddedImage::pointer{});
|
||||
EXPECT_EQ(img->getIndex(), 2);
|
||||
EXPECT_EQ(img->getType(), ImageType::FrontCover);
|
||||
EXPECT_EQ(img->getDescription(), "MyDesc");
|
||||
}
|
||||
}
|
||||
} // namespace lms::db::tests
|
||||
Reference in New Issue
Block a user