diff --git a/src/libs/database/impl/Release.cpp b/src/libs/database/impl/Release.cpp index 9cfb04e9..b27dd380 100644 --- a/src/libs/database/impl/Release.cpp +++ b/src/libs/database/impl/Release.cpp @@ -708,7 +708,14 @@ namespace lms::db { assert(session()); - return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t").where("t.release_id = ?").bind(getId())); + return utils::fetchQuerySingleResult(session()->query("SELECT MAX(file_last_write) FROM track t").where("t.release_id = ?").bind(getId())); + } + + core::PartialDateTime Release::getAddedTime() const + { + assert(session()); + + return utils::fetchQuerySingleResult(session()->query("SELECT MAX(file_added) FROM track t").where("t.release_id = ?").bind(getId())); } std::vector> Release::getClusterGroups(const std::vector& clusterTypeIds, std::size_t size) const diff --git a/src/libs/database/include/database/Release.hpp b/src/libs/database/include/database/Release.hpp index 699c0236..d07d300c 100644 --- a/src/libs/database/include/database/Release.hpp +++ b/src/libs/database/include/database/Release.hpp @@ -244,6 +244,7 @@ namespace lms::db std::size_t getDiscCount() const; // may not be total disc (if incomplete for example) std::vector getDiscs() const; std::chrono::milliseconds getDuration() const; + core::PartialDateTime getAddedTime() const; Wt::WDateTime getLastWritten() const; std::string_view getArtistDisplayName() const { return _artistDisplayName; } bool isCompilation() const { return _isCompilation; } diff --git a/src/libs/database/test/Release.cpp b/src/libs/database/test/Release.cpp index 21416541..dce0a8d8 100644 --- a/src/libs/database/test/Release.cpp +++ b/src/libs/database/test/Release.cpp @@ -1201,4 +1201,66 @@ namespace lms::db::tests EXPECT_EQ(releases.results[3], releaseC.getId()); } } + + TEST_F(DatabaseFixture, Release_LastWritten) + { + ScopedRelease release{ session, "relA" }; + + ScopedTrack track1{ session }; + ScopedTrack track2{ session }; + + { + auto transaction{ session.createReadTransaction() }; + + Wt::WDateTime lastWritten{ release.get()->getLastWritten() }; + EXPECT_FALSE(lastWritten.isValid()); + } + + { + auto transaction{ session.createWriteTransaction() }; + track1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 } }); + track2.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 }, Wt::WTime{ 15, 36, 24 } }); + track1.get().modify()->setRelease(release.get()); + track2.get().modify()->setRelease(release.get()); + } + + { + auto transaction{ session.createReadTransaction() }; + + Wt::WDateTime lastWritten{ release.get()->getLastWritten() }; + ASSERT_TRUE(lastWritten.isValid()); + EXPECT_EQ(lastWritten, track2.get()->getLastWriteTime()); + } + } + + TEST_F(DatabaseFixture, Release_AddedTime) + { + ScopedRelease release{ session, "relA" }; + + ScopedTrack track1{ session }; + ScopedTrack track2{ session }; + + { + auto transaction{ session.createReadTransaction() }; + + core::PartialDateTime 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()->setRelease(release.get()); + track2.get().modify()->setRelease(release.get()); + } + + { + auto transaction{ session.createReadTransaction() }; + + core::PartialDateTime addedTime{ release.get()->getAddedTime() }; + ASSERT_TRUE(addedTime.isValid()); + EXPECT_EQ(addedTime, track2.get()->getAddedTime()); + } + } } // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Album.cpp b/src/libs/subsonic/impl/responses/Album.cpp index 051ff869..6b019879 100644 --- a/src/libs/subsonic/impl/responses/Album.cpp +++ b/src/libs/subsonic/impl/responses/Album.cpp @@ -85,7 +85,7 @@ namespace lms::api::subsonic albumNode.setAttribute("isDir", true); } - albumNode.setAttribute("created", core::stringUtils::toISO8601String(release->getLastWritten())); + albumNode.setAttribute("created", release->getAddedTime().toISO8601String()); if (const auto image{ release->getImage() }) { const CoverArtId coverArtId{ image->getId(), image->getLastWriteTime().toTime_t() }; diff --git a/src/libs/subsonic/impl/responses/Song.cpp b/src/libs/subsonic/impl/responses/Song.cpp index bdc8b3a6..6149589f 100644 --- a/src/libs/subsonic/impl/responses/Song.cpp +++ b/src/libs/subsonic/impl/responses/Song.cpp @@ -145,7 +145,7 @@ namespace lms::api::subsonic trackResponse.setAttribute("duration", std::chrono::duration_cast(track->getDuration()).count()); trackResponse.setAttribute("bitRate", (track->getBitrate() / 1000)); trackResponse.setAttribute("type", "music"); - trackResponse.setAttribute("created", core::stringUtils::toISO8601String(track->getLastWritten())); + trackResponse.setAttribute("created", track->getAddedTime().toISO8601String()); trackResponse.setAttribute("contentType", av::getMimeType(track->getAbsoluteFilePath().extension())); if (const auto rating{ core::Service::get()->getRating(context.user->getId(), track->getId()) }) trackResponse.setAttribute("userRating", *rating);