Switched the file added info back to a full date time, ref #601
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() };
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user