From 534df42f9de6873a807b2fcc952fa25ef69441a3 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 24 Jan 2025 17:59:25 +0100 Subject: [PATCH] Distinguish initial scan to import last time write as added time, ref #601 --- src/libs/core/impl/PartialDateTime.cpp | 16 ++++++++++++++++ .../core/include/core/PartialDateTime.hpp | 6 ++++++ src/libs/database/impl/MediaLibrary.cpp | 7 +++++++ .../include/database/MediaLibrary.hpp | 1 + src/libs/database/test/Track.cpp | 16 ++++++++++++++-- .../scanner/impl/MediaLibraryInfo.hpp | 1 + .../services/scanner/impl/ScannerService.cpp | 7 ++++++- .../impl/scanners/AudioFileScanner.cpp | 19 +++++++------------ 8 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/libs/core/impl/PartialDateTime.cpp b/src/libs/core/impl/PartialDateTime.cpp index 24173de9..bfa849ad 100644 --- a/src/libs/core/impl/PartialDateTime.cpp +++ b/src/libs/core/impl/PartialDateTime.cpp @@ -22,6 +22,10 @@ #include #include +#include +#include +#include + namespace lms::core { PartialDateTime::PartialDateTime(int year) @@ -84,6 +88,18 @@ namespace lms::core return res; } + PartialDateTime PartialDateTime::fromWtDateTime(const Wt::WDateTime& dateTime) + { + return core::PartialDateTime{ + dateTime.date().year(), + static_cast(dateTime.date().month()), + static_cast(dateTime.date().day()), + static_cast(dateTime.time().hour()), + static_cast(dateTime.time().minute()), + static_cast(dateTime.time().second()) + }; + } + std::string PartialDateTime::toISO8601String() const { if (_precision == Precision::Invalid) diff --git a/src/libs/core/include/core/PartialDateTime.hpp b/src/libs/core/include/core/PartialDateTime.hpp index a16a44d8..37b05302 100644 --- a/src/libs/core/include/core/PartialDateTime.hpp +++ b/src/libs/core/include/core/PartialDateTime.hpp @@ -23,6 +23,11 @@ #include #include +namespace Wt +{ + class WDateTime; +} + namespace lms::core { class PartialDateTime @@ -35,6 +40,7 @@ namespace lms::core PartialDateTime(int year, unsigned month, unsigned day, unsigned hour, unsigned min, unsigned sec); static PartialDateTime fromString(std::string_view str); + static PartialDateTime fromWtDateTime(const Wt::WDateTime& dateTime); std::string toISO8601String() const; bool isValid() const { return _precision != Precision::Invalid; } diff --git a/src/libs/database/impl/MediaLibrary.cpp b/src/libs/database/impl/MediaLibrary.cpp index a01b291c..81033c7b 100644 --- a/src/libs/database/impl/MediaLibrary.cpp +++ b/src/libs/database/impl/MediaLibrary.cpp @@ -78,6 +78,13 @@ namespace lms::db }); } + bool MediaLibrary::isEmpty() const + { + assert(session()); + auto query{ session()->query("SELECT EXISTS (SELECT 1 FROM track WHERE media_library_id = ? LIMIT 1) AS is_media_library_empty").bind(getId()) }; + return !utils::fetchQuerySingleResult(query); + } + void MediaLibrary::setPath(const std::filesystem::path& p) { assert(p.is_absolute()); diff --git a/src/libs/database/include/database/MediaLibrary.hpp b/src/libs/database/include/database/MediaLibrary.hpp index 32426058..0649674e 100644 --- a/src/libs/database/include/database/MediaLibrary.hpp +++ b/src/libs/database/include/database/MediaLibrary.hpp @@ -50,6 +50,7 @@ namespace lms::db // getters std::string_view getName() const { return _name; } const std::filesystem::path& getPath() const { return _path; } + bool isEmpty() const; // setters void setName(std::string_view name) { _name = name; } diff --git a/src/libs/database/test/Track.cpp b/src/libs/database/test/Track.cpp index f5ab80fc..67be5338 100644 --- a/src/libs/database/test/Track.cpp +++ b/src/libs/database/test/Track.cpp @@ -151,19 +151,31 @@ namespace lms::db::tests ScopedMediaLibrary library{ session, "MyLibrary", "/root" }; ScopedMediaLibrary otherLibrary{ session, "OtherLibrary", "/otherRoot" }; + { + auto transaction{ session.createReadTransaction() }; + EXPECT_TRUE(library->isEmpty()); + EXPECT_TRUE(otherLibrary->isEmpty()); + } + { auto transaction{ session.createWriteTransaction() }; track.get().modify()->setMediaLibrary(library.get()); } { - auto transaction{ session.createWriteTransaction() }; + auto transaction{ session.createReadTransaction() }; + EXPECT_FALSE(library->isEmpty()); + EXPECT_TRUE(otherLibrary->isEmpty()); + } + + { + auto transaction{ session.createReadTransaction() }; const auto tracks{ Track::findIds(session, Track::FindParameters{}.setMediaLibrary(library->getId())) }; ASSERT_EQ(tracks.results.size(), 1); EXPECT_EQ(tracks.results.front(), track.getId()); } { - auto transaction{ session.createWriteTransaction() }; + auto transaction{ session.createReadTransaction() }; const auto tracks{ Track::findIds(session, Track::FindParameters{}.setMediaLibrary(otherLibrary->getId())) }; EXPECT_EQ(tracks.results.size(), 0); } diff --git a/src/libs/services/scanner/impl/MediaLibraryInfo.hpp b/src/libs/services/scanner/impl/MediaLibraryInfo.hpp index 5219a1e3..5b62eb83 100644 --- a/src/libs/services/scanner/impl/MediaLibraryInfo.hpp +++ b/src/libs/services/scanner/impl/MediaLibraryInfo.hpp @@ -29,6 +29,7 @@ namespace lms::scanner { db::MediaLibraryId id; std::filesystem::path rootDirectory; + bool firstScan{}; auto operator<=>(const MediaLibraryInfo& other) const = default; }; diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index fc4af817..6da34523 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -395,7 +395,12 @@ namespace lms::scanner newSettings.updatePeriod = scanSettings->getUpdatePeriod(); MediaLibrary::find(_db.getTLSSession(), [&](const MediaLibrary::pointer& mediaLibrary) { - newSettings.mediaLibraries.push_back(MediaLibraryInfo{ .id = mediaLibrary->getId(), .rootDirectory = mediaLibrary->getPath().lexically_normal() }); + MediaLibraryInfo info; + info.firstScan = mediaLibrary->isEmpty(); + info.id = mediaLibrary->getId(); + info.rootDirectory = mediaLibrary->getPath().lexically_normal(); + + newSettings.mediaLibraries.push_back(info); }); { diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp index ad226eee..5899e4d4 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp @@ -479,19 +479,14 @@ namespace lms::scanner if (!track) { track = dbSession.create(); - track.modify()->setAbsoluteFilePath(_file); - - const core::PartialDateTime addedTime{ - fileInfo->lastWriteTime.date().year(), - static_cast(fileInfo->lastWriteTime.date().month()), - static_cast(fileInfo->lastWriteTime.date().day()), - static_cast(fileInfo->lastWriteTime.time().hour()), - static_cast(fileInfo->lastWriteTime.time().minute()), - static_cast(fileInfo->lastWriteTime.time().second()) - }; - - track.modify()->setAddedTime(addedTime); // may be erased by encodingTime added = true; + + track.modify()->setAbsoluteFilePath(_file); + if (!_parsedTrack->encodingTime.isValid()) + { + const core::PartialDateTime addedTime{ core::PartialDateTime::fromWtDateTime(_mediaLibrary.firstScan ? fileInfo->lastWriteTime : Wt::WDateTime::currentDateTime()) }; + track.modify()->setAddedTime(addedTime); // may be erased by encodingTime + } } // Track related data