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())