Switched the file added info back to a full date time, ref #601

This commit is contained in:
emeric
2025-01-26 15:08:31 +01:00
parent e553e840d3
commit 814eaf0a3e
12 changed files with 96 additions and 55 deletions
+14 -4
View File
@@ -466,14 +466,24 @@ namespace lms::core::stringUtils
std::string toISO8601String(const Wt::WDateTime& dateTime)
{
// assume UTC
return dateTime.toString("yyyy-MM-ddThh:mm:ss.zzz", false).toUTF8();
if (dateTime.isValid())
{
// assume UTC
return dateTime.toString("yyyy-MM-ddThh:mm:ss.zzz", false).toUTF8();
}
return "";
}
std::string toISO8601String(const Wt::WDate& date)
{
// assume UTC
return date.toString("yyyy-MM-dd").toUTF8();
if (date.isValid())
{
// assume UTC
return date.toString("yyyy-MM-dd").toUTF8();
}
return "";
}
Wt::WDateTime fromISO8601String(std::string_view dateTime)
+16 -11
View File
@@ -43,11 +43,26 @@ namespace lms::core
static PartialDateTime fromWtDateTime(const Wt::WDateTime& dateTime);
std::string toISO8601String() const;
bool isValid() const { return _precision != Precision::Invalid; }
constexpr bool isValid() const { return _precision != Precision::Invalid; }
enum class Precision : std::uint8_t
{
Invalid,
Year,
Month,
Day,
Hour,
Min,
Sec,
};
constexpr Precision getPrecision() const { return _precision; }
constexpr std::optional<int> getYear() const { return (_precision >= Precision::Year ? std::make_optional(_year) : std::nullopt); }
constexpr std::optional<int> getMonth() const { return (_precision >= Precision::Month ? std::make_optional(_month) : std::nullopt); }
constexpr std::optional<int> getDay() const { return (_precision >= Precision::Day ? std::make_optional(_day) : std::nullopt); }
constexpr std::optional<int> getHour() const { return (_precision >= Precision::Hour ? std::make_optional(_hour) : std::nullopt); }
constexpr std::optional<int> getMin() const { return (_precision >= Precision::Min ? std::make_optional(_min) : std::nullopt); }
constexpr std::optional<int> getSec() const { return (_precision >= Precision::Sec ? std::make_optional(_sec) : std::nullopt); }
constexpr auto operator<=>(const PartialDateTime& other) const = default;
@@ -60,16 +75,6 @@ namespace lms::core
std::uint8_t _hour{}; // 0 to 23
std::uint8_t _min{}; // 0 to 59
std::uint8_t _sec{}; // 0 to 59
enum class Precision : std::uint8_t
{
Invalid,
Year,
Month,
Day,
Hour,
Min,
Sec,
};
Precision _precision{ Precision::Invalid };
};
} // namespace lms::core
+23 -4
View File
@@ -301,14 +301,33 @@ namespace lms::core::stringUtils::tests
TEST(Stringutils, DateToString)
{
const Wt::WDate date{ 2020, 01, 03 };
EXPECT_EQ(toISO8601String(date), "2020-01-03");
{
const Wt::WDate date{ 2020, 01, 03 };
EXPECT_EQ(toISO8601String(date), "2020-01-03");
}
{
const Wt::WDate date;
EXPECT_EQ(toISO8601String(date), "");
}
}
TEST(Stringutils, DateTimeToString)
{
const Wt::WDateTime dateTime{ Wt::WDate{ 2020, 01, 03 }, Wt::WTime{ 9, 8, 11, 75 } };
EXPECT_EQ(toISO8601String(dateTime), "2020-01-03T09:08:11.075");
{
const Wt::WDateTime dateTime{ Wt::WDate{ 2020, 01, 03 }, Wt::WTime{ 9, 8, 11, 75 } };
EXPECT_EQ(toISO8601String(dateTime), "2020-01-03T09:08:11.075");
}
{
const Wt::WDateTime dateTime{ Wt::WDate{ 2020, 01, 03 } };
EXPECT_EQ(toISO8601String(dateTime), "2020-01-03T00:00:00.000");
}
{
const Wt::WDateTime dateTime;
EXPECT_EQ(toISO8601String(dateTime), "");
}
}
TEST(Stringutils, DateTimeFromString)
+3 -3
View File
@@ -704,18 +704,18 @@ namespace lms::db
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t").where("t.release_id = ?").bind(getId()));
}
Wt::WDateTime Release::getLastWritten() const
Wt::WDateTime Release::getLastWrittenTime() const
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<Wt::WDateTime>("SELECT MAX(file_last_write) FROM track t").where("t.release_id = ?").bind(getId()));
}
core::PartialDateTime Release::getAddedTime() const
Wt::WDateTime Release::getAddedTime() const
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<core::PartialDateTime>("SELECT MAX(file_added) FROM track t").where("t.release_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<Wt::WDateTime>("SELECT MAX(file_added) FROM track t").where("t.release_id = ?").bind(getId()));
}
std::vector<std::vector<Cluster::pointer>> Release::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const
@@ -244,8 +244,8 @@ namespace lms::db
std::size_t getDiscCount() const; // may not be total disc (if incomplete for example)
std::vector<DiscInfo> getDiscs() const;
std::chrono::milliseconds getDuration() const;
core::PartialDateTime getAddedTime() const;
Wt::WDateTime getLastWritten() const;
Wt::WDateTime getAddedTime() const;
Wt::WDateTime getLastWrittenTime() const;
std::string_view getArtistDisplayName() const { return _artistDisplayName; }
bool isCompilation() const { return _isCompilation; }
std::size_t getTrackCount() const;
+4 -4
View File
@@ -223,8 +223,8 @@ namespace lms::db
void setAbsoluteFilePath(const std::filesystem::path& filePath);
void setRelativeFilePath(const std::filesystem::path& filePath);
void setFileSize(std::size_t fileSize) { _fileSize = fileSize; }
void setLastWriteTime(Wt::WDateTime time) { _fileLastWrite = time; }
void setAddedTime(core::PartialDateTime time) { _fileAdded = time; }
void setLastWriteTime(const Wt::WDateTime& time) { _fileLastWrite = time; }
void setAddedTime(const Wt::WDateTime& time) { _fileAdded = time; }
void setBitrate(std::size_t bitrate) { _bitrate = bitrate; }
void setBitsPerSample(std::size_t bitsPerSample) { _bitsPerSample = bitsPerSample; }
void setDuration(std::chrono::milliseconds duration) { _duration = duration; }
@@ -272,7 +272,7 @@ namespace lms::db
const core::PartialDateTime& getOriginalDate() const { return _originalDate; }
std::optional<int> getOriginalYear() const;
const Wt::WDateTime& getLastWriteTime() const { return _fileLastWrite; }
const core::PartialDateTime& getAddedTime() const { return _fileAdded; }
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); }
@@ -367,7 +367,7 @@ namespace lms::db
std::filesystem::path _fileName;
long long _fileSize{};
Wt::WDateTime _fileLastWrite;
core::PartialDateTime _fileAdded;
Wt::WDateTime _fileAdded;
bool _hasCover{};
std::string _trackMBID;
std::string _recordingMBID;
+5 -5
View File
@@ -751,11 +751,11 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
trackA1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2 });
trackB1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 1 });
trackD1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2, 15, 36, 24 });
trackD1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 3 });
trackA2.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 4 });
trackA1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 } });
trackB1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 1 } });
trackD1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 }, Wt::WTime{ 15, 36, 24 } });
trackD1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 3 } });
trackA2.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 4 } });
TrackArtistLink::create(session, trackA1.get(), artistA.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, trackA2.get(), artistA.get(), TrackArtistLinkType::Producer);
+11 -11
View File
@@ -1138,11 +1138,11 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
trackA1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2 });
trackB1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 1 });
trackD1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2, 15, 36, 24 });
trackD1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 3 });
trackA2.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 4 });
trackA1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 } });
trackB1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 1 } });
trackD1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 }, Wt::WTime{ 15, 36, 24 } });
trackD1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 3 } });
trackA2.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 4 } });
trackA1.get().modify()->setRelease(releaseA.get());
trackA2.get().modify()->setRelease(releaseA.get());
@@ -1212,7 +1212,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
Wt::WDateTime lastWritten{ release.get()->getLastWritten() };
Wt::WDateTime lastWritten{ release.get()->getLastWrittenTime() };
EXPECT_FALSE(lastWritten.isValid());
}
@@ -1227,7 +1227,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
Wt::WDateTime lastWritten{ release.get()->getLastWritten() };
Wt::WDateTime lastWritten{ release.get()->getLastWrittenTime() };
ASSERT_TRUE(lastWritten.isValid());
EXPECT_EQ(lastWritten, track2.get()->getLastWriteTime());
}
@@ -1243,14 +1243,14 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
core::PartialDateTime addedTime{ release.get()->getAddedTime() };
const Wt::WDateTime addedTime{ release.get()->getAddedTime() };
EXPECT_FALSE(addedTime.isValid());
}
{
auto transaction{ session.createWriteTransaction() };
track1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2 });
track2.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2, 15, 36, 24 });
track1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 } });
track2.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 }, Wt::WTime{ 15, 36, 24 } });
track1.get().modify()->setRelease(release.get());
track2.get().modify()->setRelease(release.get());
}
@@ -1258,7 +1258,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
core::PartialDateTime addedTime{ release.get()->getAddedTime() };
const Wt::WDateTime addedTime{ release.get()->getAddedTime() };
ASSERT_TRUE(addedTime.isValid());
EXPECT_EQ(addedTime, track2.get()->getAddedTime());
}
+3 -3
View File
@@ -399,9 +399,9 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
track1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2 });
track2.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 1 });
track4.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2, 15, 36, 24 });
track1.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 } });
track2.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 1 } });
track4.get().modify()->setAddedTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 }, Wt::WTime{ 15, 36, 24 } });
}
{
@@ -482,11 +482,7 @@ namespace lms::scanner
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.modify()->setAddedTime(_mediaLibrary.firstScan ? fileInfo->lastWriteTime : Wt::WDateTime::currentDateTime()); // may be erased by encodingTime
}
// Track related data
@@ -504,7 +500,18 @@ namespace lms::scanner
track.modify()->setLastWriteTime(fileInfo->lastWriteTime);
if (_parsedTrack->encodingTime.isValid())
track.modify()->setAddedTime(_parsedTrack->encodingTime);
{
const core::PartialDateTime& encodingTime{ _parsedTrack->encodingTime };
Wt::WDate date;
Wt::WTime time;
if (encodingTime.getPrecision() >= core::PartialDateTime::Precision::Day)
date = Wt::WDate{ *encodingTime.getYear(), *encodingTime.getMonth(), *encodingTime.getDay() };
if (encodingTime.getPrecision() >= core::PartialDateTime::Precision::Sec)
time = Wt::WTime{ *encodingTime.getHour(), *encodingTime.getMin(), *encodingTime.getSec() };
if (date.isValid())
track.modify()->setAddedTime(Wt::WDateTime{ date, time });
}
db::MediaLibrary::pointer mediaLibrary{ db::MediaLibrary::find(dbSession, _mediaLibrary.id) }; // may be null if settings are updated in // => next scan will correct this
track.modify()->setMediaLibrary(mediaLibrary);
+1 -1
View File
@@ -85,7 +85,7 @@ namespace lms::api::subsonic
albumNode.setAttribute("isDir", true);
}
albumNode.setAttribute("created", release->getAddedTime().toISO8601String());
albumNode.setAttribute("created", core::stringUtils::toISO8601String(release->getAddedTime()));
if (const auto image{ release->getImage() })
{
const CoverArtId coverArtId{ image->getId(), image->getLastWriteTime().toTime_t() };
+1 -1
View File
@@ -145,7 +145,7 @@ namespace lms::api::subsonic
trackResponse.setAttribute("duration", std::chrono::duration_cast<std::chrono::seconds>(track->getDuration()).count());
trackResponse.setAttribute("bitRate", (track->getBitrate() / 1000));
trackResponse.setAttribute("type", "music");
trackResponse.setAttribute("created", track->getAddedTime().toISO8601String());
trackResponse.setAttribute("created", core::stringUtils::toISO8601String(track->getAddedTime()));
trackResponse.setAttribute("contentType", av::getMimeType(track->getAbsoluteFilePath().extension()));
if (const auto rating{ core::Service<feedback::IFeedbackService>::get()->getRating(context.user->getId(), track->getId()) })
trackResponse.setAttribute("userRating", *rating);