Distinguish initial scan to import last time write as added time, ref #601

This commit is contained in:
emeric
2025-01-24 17:59:25 +01:00
parent cfa59cb32c
commit 534df42f9d
8 changed files with 58 additions and 15 deletions
+16
View File
@@ -22,6 +22,10 @@
#include <limits> #include <limits>
#include <sstream> #include <sstream>
#include <Wt/WDate.h>
#include <Wt/WDateTime.h>
#include <Wt/WTime.h>
namespace lms::core namespace lms::core
{ {
PartialDateTime::PartialDateTime(int year) PartialDateTime::PartialDateTime(int year)
@@ -84,6 +88,18 @@ namespace lms::core
return res; return res;
} }
PartialDateTime PartialDateTime::fromWtDateTime(const Wt::WDateTime& dateTime)
{
return core::PartialDateTime{
dateTime.date().year(),
static_cast<unsigned>(dateTime.date().month()),
static_cast<unsigned>(dateTime.date().day()),
static_cast<unsigned>(dateTime.time().hour()),
static_cast<unsigned>(dateTime.time().minute()),
static_cast<unsigned>(dateTime.time().second())
};
}
std::string PartialDateTime::toISO8601String() const std::string PartialDateTime::toISO8601String() const
{ {
if (_precision == Precision::Invalid) if (_precision == Precision::Invalid)
@@ -23,6 +23,11 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
namespace Wt
{
class WDateTime;
}
namespace lms::core namespace lms::core
{ {
class PartialDateTime class PartialDateTime
@@ -35,6 +40,7 @@ namespace lms::core
PartialDateTime(int year, unsigned month, unsigned day, unsigned hour, unsigned min, unsigned sec); PartialDateTime(int year, unsigned month, unsigned day, unsigned hour, unsigned min, unsigned sec);
static PartialDateTime fromString(std::string_view str); static PartialDateTime fromString(std::string_view str);
static PartialDateTime fromWtDateTime(const Wt::WDateTime& dateTime);
std::string toISO8601String() const; std::string toISO8601String() const;
bool isValid() const { return _precision != Precision::Invalid; } bool isValid() const { return _precision != Precision::Invalid; }
+7
View File
@@ -78,6 +78,13 @@ namespace lms::db
}); });
} }
bool MediaLibrary::isEmpty() const
{
assert(session());
auto query{ session()->query<bool>("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) void MediaLibrary::setPath(const std::filesystem::path& p)
{ {
assert(p.is_absolute()); assert(p.is_absolute());
@@ -50,6 +50,7 @@ namespace lms::db
// getters // getters
std::string_view getName() const { return _name; } std::string_view getName() const { return _name; }
const std::filesystem::path& getPath() const { return _path; } const std::filesystem::path& getPath() const { return _path; }
bool isEmpty() const;
// setters // setters
void setName(std::string_view name) { _name = name; } void setName(std::string_view name) { _name = name; }
+14 -2
View File
@@ -151,19 +151,31 @@ namespace lms::db::tests
ScopedMediaLibrary library{ session, "MyLibrary", "/root" }; ScopedMediaLibrary library{ session, "MyLibrary", "/root" };
ScopedMediaLibrary otherLibrary{ session, "OtherLibrary", "/otherRoot" }; ScopedMediaLibrary otherLibrary{ session, "OtherLibrary", "/otherRoot" };
{
auto transaction{ session.createReadTransaction() };
EXPECT_TRUE(library->isEmpty());
EXPECT_TRUE(otherLibrary->isEmpty());
}
{ {
auto transaction{ session.createWriteTransaction() }; auto transaction{ session.createWriteTransaction() };
track.get().modify()->setMediaLibrary(library.get()); 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())) }; const auto tracks{ Track::findIds(session, Track::FindParameters{}.setMediaLibrary(library->getId())) };
ASSERT_EQ(tracks.results.size(), 1); ASSERT_EQ(tracks.results.size(), 1);
EXPECT_EQ(tracks.results.front(), track.getId()); 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())) }; const auto tracks{ Track::findIds(session, Track::FindParameters{}.setMediaLibrary(otherLibrary->getId())) };
EXPECT_EQ(tracks.results.size(), 0); EXPECT_EQ(tracks.results.size(), 0);
} }
@@ -29,6 +29,7 @@ namespace lms::scanner
{ {
db::MediaLibraryId id; db::MediaLibraryId id;
std::filesystem::path rootDirectory; std::filesystem::path rootDirectory;
bool firstScan{};
auto operator<=>(const MediaLibraryInfo& other) const = default; auto operator<=>(const MediaLibraryInfo& other) const = default;
}; };
@@ -395,7 +395,12 @@ namespace lms::scanner
newSettings.updatePeriod = scanSettings->getUpdatePeriod(); newSettings.updatePeriod = scanSettings->getUpdatePeriod();
MediaLibrary::find(_db.getTLSSession(), [&](const MediaLibrary::pointer& mediaLibrary) { 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);
}); });
{ {
@@ -479,19 +479,14 @@ namespace lms::scanner
if (!track) if (!track)
{ {
track = dbSession.create<db::Track>(); track = dbSession.create<db::Track>();
track.modify()->setAbsoluteFilePath(_file);
const core::PartialDateTime addedTime{
fileInfo->lastWriteTime.date().year(),
static_cast<unsigned>(fileInfo->lastWriteTime.date().month()),
static_cast<unsigned>(fileInfo->lastWriteTime.date().day()),
static_cast<unsigned>(fileInfo->lastWriteTime.time().hour()),
static_cast<unsigned>(fileInfo->lastWriteTime.time().minute()),
static_cast<unsigned>(fileInfo->lastWriteTime.time().second())
};
track.modify()->setAddedTime(addedTime); // may be erased by encodingTime
added = true; 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 // Track related data