Associate user provided images with playlists (using EXTIMG or same named file), fixes #833

This commit is contained in:
emeric
2026-06-02 12:48:54 +02:00
parent 531c5ca24d
commit 64e183da38
22 changed files with 340 additions and 7 deletions
+8 -1
View File
@@ -35,7 +35,7 @@ namespace lms::db
{
namespace
{
static constexpr Version LMS_DATABASE_VERSION{ 104 };
static constexpr Version LMS_DATABASE_VERSION{ 105 };
}
VersionInfo::VersionInfo()
@@ -1723,6 +1723,12 @@ FROM track)");
utils::executeCommand(*session.getDboSession(), "ALTER TABLE scan_settings ADD COLUMN musicnn_model_identifier TEXT NOT NULL DEFAULT ''");
}
void migrateFromV104(Session& session)
{
utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE "playlist_file" ADD COLUMN "preferred_artwork_id" bigint)");
utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE "playlist_file" ADD COLUMN "cover_image_file" text NOT NULL DEFAULT '')");
}
bool doDbMigration(Session& session)
{
constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" };
@@ -1803,6 +1809,7 @@ FROM track)");
{ 101, migrateFromV101 },
{ 102, migrateFromV102 },
{ 103, migrateFromV103 },
{ 104, migrateFromV104 },
};
bool migrationPerformed{};
@@ -24,6 +24,7 @@
#include "core/ILogger.hpp"
#include "database/Session.hpp"
#include "database/objects/Artwork.hpp"
#include "database/objects/Directory.hpp"
#include "database/objects/MediaLibrary.hpp"
#include "database/objects/Track.hpp"
@@ -181,4 +182,19 @@ namespace lms::db
root["files"] = std::move(fileArray);
_entries = Wt::Json::serialize(root);
}
void PlayListFile::setCoverImageFile(const std::filesystem::path& file)
{
_coverImageFile = file;
}
void PlayListFile::updatePreferredArtwork(Session& session, PlayListFileId id, ArtworkId artworkId)
{
session.checkWriteTransaction();
if (artworkId.isValid())
utils::executeCommand(*session.getDboSession(), "UPDATE playlist_file SET preferred_artwork_id = ? WHERE id = ?", artworkId, id);
else
utils::executeCommand(*session.getDboSession(), "UPDATE playlist_file SET preferred_artwork_id = NULL WHERE id = ?", id);
}
} // namespace lms::db
@@ -31,12 +31,14 @@
#include "database/IdRange.hpp"
#include "database/Object.hpp"
#include "database/objects/ArtworkId.hpp"
#include "database/objects/DirectoryId.hpp"
LMS_DECLARE_IDTYPE(PlayListFileId)
namespace lms::db
{
class Artwork;
class Session;
class Directory;
class MediaLibrary;
@@ -61,6 +63,8 @@ namespace lms::db
const Wt::WDateTime& getLastWriteTime() const { return _fileLastWrite; }
std::size_t getFileSize() const { return _fileSize; }
std::string_view getName() const { return _name; }
const std::filesystem::path& getCoverImageFile() const { return _coverImageFile; }
ArtworkId getPreferredArtworkId() const { return _preferredArtwork.id(); }
std::vector<std::filesystem::path> getFiles() const;
ObjectPtr<TrackList> getTrackList() const;
ObjectPtr<Directory> getDirectory() const;
@@ -70,12 +74,15 @@ namespace lms::db
void setAbsoluteFilePath(const std::filesystem::path& filePath);
void setLastWriteTime(Wt::WDateTime time) { _fileLastWrite = time; }
void setFileSize(std::size_t fileSize) { _fileSize = fileSize; }
void setCoverImageFile(const std::filesystem::path& file);
void setMediaLibrary(ObjectPtr<MediaLibrary> mediaLibrary) { _mediaLibrary = getDboPtr(mediaLibrary); }
void setDirectory(ObjectPtr<Directory> directory);
void setTrackList(ObjectPtr<TrackList> trackList);
void setName(std::string_view name);
void setFiles(std::span<const std::filesystem::path> files);
static void updatePreferredArtwork(Session& session, PlayListFileId id, ArtworkId artworkId);
template<class Action>
void persist(Action& a)
{
@@ -85,9 +92,11 @@ namespace lms::db
Wt::Dbo::field(a, _fileLastWrite, "file_last_write");
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::field(a, _entries, "entries");
Wt::Dbo::field(a, _coverImageFile, "cover_image_file");
Wt::Dbo::belongsTo(a, _mediaLibrary, "media_library", Wt::Dbo::OnDeleteSetNull); // don't delete playlist on media library removal, we want to wait for the next scan to have a chance to migrate files
Wt::Dbo::belongsTo(a, _directory, "directory", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::belongsTo(a, _preferredArtwork, "preferred_artwork", Wt::Dbo::OnDeleteSetNull);
Wt::Dbo::hasOne(a, _trackList, "playlist_file");
}
@@ -106,9 +115,11 @@ namespace lms::db
std::string _name;
std::string _entries; // A json encoded list of files
std::filesystem::path _coverImageFile;
Wt::Dbo::ptr<MediaLibrary> _mediaLibrary;
Wt::Dbo::ptr<Directory> _directory;
Wt::Dbo::ptr<Artwork> _preferredArtwork;
Wt::Dbo::weak_ptr<TrackList> _trackList;
};
} // namespace lms::db
@@ -125,6 +125,7 @@ namespace lms::db
TrackListType getType() const { return _type; }
ObjectPtr<User> getUser() const { return _user; }
UserId getUserId() const { return _user.id(); }
ObjectPtr<PlayListFile> getPlayListFile() const { return _playListFile; }
Wt::WDateTime getLastModifiedDateTime() const { return _lastModifiedDateTime; }
Wt::WDateTime getCreationDateTime() const { return _creationDateTime; }