diff --git a/res/schema.xml b/res/schema.xml
index c4a70b26a00..6c086ee9799 100644
--- a/res/schema.xml
+++ b/res/schema.xml
@@ -557,4 +557,13 @@ reapplying those migrations.
GROUP BY PlaylistTracks.track_id);
+
+
+ Add source_synchronized_ms column to library table
+
+
+
+ ALTER TABLE library ADD COLUMN source_synchronized_ms INTEGER DEFAULT NULL;
+
+
diff --git a/src/database/mixxxdb.cpp b/src/database/mixxxdb.cpp
index 9e707bf260a..f2b38a425b8 100644
--- a/src/database/mixxxdb.cpp
+++ b/src/database/mixxxdb.cpp
@@ -12,7 +12,7 @@
const QString MixxxDb::kDefaultSchemaFile(":/schema.xml");
//static
-const int MixxxDb::kRequiredSchemaVersion = 36;
+const int MixxxDb::kRequiredSchemaVersion = 37;
namespace {
diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp
index 747725ff068..43e89462ba9 100644
--- a/src/library/dao/trackdao.cpp
+++ b/src/library/dao/trackdao.cpp
@@ -396,6 +396,7 @@ void TrackDAO::addTracksPrepare() {
"played,"
"mixxx_deleted,"
"header_parsed,"
+ "source_synchronized_ms,"
"channels,"
"samplerate,"
"bitrate,"
@@ -443,6 +444,7 @@ void TrackDAO::addTracksPrepare() {
":played,"
":mixxx_deleted,"
":header_parsed,"
+ ":source_synchronized_ms,"
":channels,"
":samplerate,"
":bitrate,"
@@ -549,7 +551,17 @@ void bindTrackLibraryValues(
trackMetadata.getStreamInfo().getDuration().toDoubleSeconds());
pTrackLibraryQuery->bindValue(":header_parsed",
- track.getMetadataSynchronized() ? 1 : 0);
+ track.isSourceSynchronized() ? 1 : 0);
+ const QDateTime sourceSynchronizedAt =
+ track.getSourceSynchronizedAt();
+ if (sourceSynchronizedAt.isValid()) {
+ DEBUG_ASSERT(sourceSynchronizedAt.timeSpec() == Qt::UTC);
+ pTrackLibraryQuery->bindValue(":source_synchronized_ms",
+ sourceSynchronizedAt.toMSecsSinceEpoch());
+ } else {
+ pTrackLibraryQuery->bindValue(":source_synchronized_ms",
+ QVariant());
+ }
const PlayCounter& playCounter = track.getPlayCounter();
pTrackLibraryQuery->bindValue(":timesplayed", playCounter.getTimesPlayed());
@@ -828,7 +840,7 @@ TrackPointer TrackDAO::addTracksAddFile(
// Initially (re-)import the metadata for the newly created track
// from the file.
SoundSourceProxy(pTrack).updateTrackFromSource();
- if (!pTrack->isMetadataSynchronized()) {
+ if (!pTrack->isSourceSynchronized()) {
qWarning() << "TrackDAO::addTracksAddFile:"
<< "Failed to parse track metadata from file"
<< pTrack->getLocation();
@@ -1189,9 +1201,20 @@ bool setTrackFiletype(const QSqlRecord& record, const int column,
return false;
}
-bool setTrackMetadataSynchronized(const QSqlRecord& record, const int column,
- TrackPointer pTrack) {
- pTrack->setMetadataSynchronized(record.value(column).toBool());
+bool setTrackHeaderParsed(const QSqlRecord& record, const int column, TrackPointer pTrack) {
+ pTrack->setHeaderParsedFromTrackDAO(record.value(column).toBool());
+ return false;
+}
+
+bool setTrackSourceSynchronizedAt(const QSqlRecord& record, const int column, TrackPointer pTrack) {
+ QDateTime sourceSynchronizedAt;
+ const QVariant value = record.value(column);
+ if (value.isValid() && value.canConvert()) {
+ const quint64 msecsSinceEpoch = qvariant_cast(value);
+ sourceSynchronizedAt.setTimeSpec(Qt::UTC);
+ sourceSynchronizedAt.setMSecsSinceEpoch(msecsSinceEpoch);
+ }
+ pTrack->setSourceSynchronizedAt(sourceSynchronizedAt);
return false;
}
@@ -1332,7 +1355,8 @@ TrackPointer TrackDAO::getTrackById(TrackId trackId) const {
{"last_played_at", setTrackLastPlayedAt},
{"played", setTrackPlayed},
{"datetime_added", setTrackDateAdded},
- {"header_parsed", setTrackMetadataSynchronized},
+ {"header_parsed", setTrackHeaderParsed},
+ {"source_synchronized_ms", setTrackSourceSynchronizedAt},
// Audio properties are set together at once. Do not change the
// ordering of these columns or put other columns in between them!
@@ -1600,6 +1624,7 @@ bool TrackDAO::updateTrack(Track* pTrack) const {
"last_played_at=:last_played_at,"
"played=:played,"
"header_parsed=:header_parsed,"
+ "source_synchronized_ms=:source_synchronized_ms,"
"channels=:channels,"
"bitrate=:bitrate,"
"samplerate=:samplerate,"
diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp
index a5810d1b172..a4f8ce93722 100644
--- a/src/library/dlgtrackinfo.cpp
+++ b/src/library/dlgtrackinfo.cpp
@@ -674,7 +674,7 @@ void DlgTrackInfo::slotImportMetadataFromFile() {
mixxx::TrackRecord trackRecord = m_pLoadedTrack->getRecord();
mixxx::TrackMetadata trackMetadata = trackRecord.getMetadata();
QImage coverImage;
- const auto [importResult, metadataSynchronized] =
+ const auto [importResult, sourceSynchronizedAt] =
SoundSourceProxy(m_pLoadedTrack)
.importTrackMetadataAndCoverImage(
&trackMetadata, &coverImage);
@@ -688,7 +688,7 @@ void DlgTrackInfo::slotImportMetadataFromFile() {
coverImage);
trackRecord.replaceMetadataFromSource(
std::move(trackMetadata),
- metadataSynchronized);
+ sourceSynchronizedAt);
trackRecord.setCoverInfo(
std::move(guessedCoverInfo));
replaceTrackRecord(
diff --git a/src/sources/metadatasourcetaglib.cpp b/src/sources/metadatasourcetaglib.cpp
index 607e9881cfd..85e09f49a15 100644
--- a/src/sources/metadatasourcetaglib.cpp
+++ b/src/sources/metadatasourcetaglib.cpp
@@ -75,20 +75,20 @@ class AiffFile : public TagLib::RIFF::AIFF::File {
}
};
-inline QDateTime getMetadataSynchronized(const QFileInfo& fileInfo) {
- return fileInfo.lastModified();
+inline QDateTime getSourceSynchronizedAt(const QFileInfo& fileInfo) {
+ return fileInfo.lastModified().toUTC();
}
} // anonymous namespace
std::pair
MetadataSourceTagLib::afterImport(ImportResult importResult) const {
- return std::make_pair(importResult, getMetadataSynchronized(QFileInfo(m_fileName)));
+ return std::make_pair(importResult, getSourceSynchronizedAt(QFileInfo(m_fileName)));
}
std::pair
MetadataSourceTagLib::afterExport(ExportResult exportResult) const {
- return std::make_pair(exportResult, getMetadataSynchronized(QFileInfo(m_fileName)));
+ return std::make_pair(exportResult, getSourceSynchronizedAt(QFileInfo(m_fileName)));
}
std::pair
diff --git a/src/sources/soundsourceproxy.cpp b/src/sources/soundsourceproxy.cpp
index 69d94ea1982..cc773234016 100644
--- a/src/sources/soundsourceproxy.cpp
+++ b/src/sources/soundsourceproxy.cpp
@@ -539,9 +539,9 @@ bool SoundSourceProxy::updateTrackFromSource(
// values if the corresponding file tags are missing. Depending
// on the file type some kind of tags might even not be supported
// at all and this information would get lost entirely otherwise!
- bool metadataSynchronized = false;
+ bool headerParsed = false;
mixxx::TrackMetadata trackMetadata =
- m_pTrack->getMetadata(&metadataSynchronized);
+ m_pTrack->getMetadata(&headerParsed);
// Save for later to replace the unreliable and imprecise audio
// properties imported from file tags (see below).
@@ -559,7 +559,7 @@ bool SoundSourceProxy::updateTrackFromSource(
// if the user did not explicitly choose to (re-)import metadata
// explicitly from this file.
bool mergeExtraMetadataFromSource = false;
- if (metadataSynchronized && mode == UpdateTrackFromSourceMode::Once) {
+ if (headerParsed && mode == UpdateTrackFromSourceMode::Once) {
// No (re-)import needed or desired, only merge missing properties
mergeExtraMetadataFromSource = true;
} else {
@@ -592,7 +592,7 @@ bool SoundSourceProxy::updateTrackFromSource(
<< "from file"
<< getUrl().toString();
// make sure that the trackMetadata was not messed up due to the failure
- trackMetadata = m_pTrack->getMetadata(&metadataSynchronized);
+ trackMetadata = m_pTrack->getMetadata(&headerParsed);
}
// Partial import
@@ -610,7 +610,7 @@ bool SoundSourceProxy::updateTrackFromSource(
}
// Full import
- if (metadataSynchronized) {
+ if (headerParsed) {
// Metadata has been synchronized successfully at least
// once in the past. Only overwrite this information if
// new data has actually been imported, otherwise abort
diff --git a/src/test/trackupdate_test.cpp b/src/test/trackupdate_test.cpp
index d413c922210..3b4b0f4709d 100644
--- a/src/test/trackupdate_test.cpp
+++ b/src/test/trackupdate_test.cpp
@@ -30,7 +30,7 @@ class TrackUpdateTest : public MixxxTest, SoundSourceProviderRegistration {
static TrackPointer newTestTrackParsed() {
auto pTrack = newTestTrack();
EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource());
- EXPECT_TRUE(pTrack->isMetadataSynchronized());
+ EXPECT_TRUE(pTrack->isSourceSynchronized());
EXPECT_TRUE(hasTrackMetadata(pTrack));
EXPECT_TRUE(hasCoverArt(pTrack));
pTrack->markClean();
@@ -66,7 +66,7 @@ TEST_F(TrackUpdateTest, parseModifiedCleanOnce) {
const auto coverInfoAfter = pTrack->getCoverInfo();
// Verify that the track has not been modified
- ASSERT_TRUE(pTrack->isMetadataSynchronized());
+ ASSERT_TRUE(pTrack->isSourceSynchronized());
ASSERT_FALSE(pTrack->isDirty());
ASSERT_EQ(trackMetadataBefore, trackMetadataAfter);
ASSERT_EQ(coverInfoBefore, coverInfoAfter);
@@ -86,7 +86,7 @@ TEST_F(TrackUpdateTest, parseModifiedCleanAgainSkipCover) {
const auto coverInfoAfter = pTrack->getCoverInfo();
// Updated
- EXPECT_TRUE(pTrack->isMetadataSynchronized());
+ EXPECT_TRUE(pTrack->isSourceSynchronized());
EXPECT_TRUE(pTrack->isDirty());
EXPECT_NE(trackMetadataBefore, trackMetadataAfter);
EXPECT_EQ(coverInfoBefore, coverInfoAfter);
@@ -110,7 +110,7 @@ TEST_F(TrackUpdateTest, parseModifiedCleanAgainUpdateCover) {
const auto coverInfoAfter = pTrack->getCoverInfo();
// Updated
- EXPECT_TRUE(pTrack->isMetadataSynchronized());
+ EXPECT_TRUE(pTrack->isSourceSynchronized());
EXPECT_TRUE(pTrack->isDirty());
EXPECT_NE(trackMetadataBefore, trackMetadataAfter);
EXPECT_NE(coverInfoBefore, coverInfoAfter);
@@ -129,7 +129,7 @@ TEST_F(TrackUpdateTest, parseModifiedDirtyAgain) {
const auto coverInfoAfter = pTrack->getCoverInfo();
// Updated
- EXPECT_TRUE(pTrack->isMetadataSynchronized());
+ EXPECT_TRUE(pTrack->isSourceSynchronized());
EXPECT_TRUE(pTrack->isDirty());
EXPECT_NE(trackMetadataBefore, trackMetadataAfter);
EXPECT_EQ(coverInfoBefore, coverInfoAfter);
diff --git a/src/track/track.cpp b/src/track/track.cpp
index 3c630bff404..753c98ae0af 100644
--- a/src/track/track.cpp
+++ b/src/track/track.cpp
@@ -135,7 +135,7 @@ void Track::relocate(
void Track::replaceMetadataFromSource(
mixxx::TrackMetadata importedMetadata,
- const QDateTime& metadataSynchronized) {
+ const QDateTime& sourceSynchronizedAt) {
// Information stored in Serato tags is imported separately after
// importing the metadata (see below). The Serato tags BLOB itself
// is updated together with the metadata.
@@ -164,7 +164,7 @@ void Track::replaceMetadataFromSource(
m_record.getMetadata().getTrackInfo().getReplayGain();
bool modified = m_record.replaceMetadataFromSource(
std::move(importedMetadata),
- metadataSynchronized);
+ sourceSynchronizedAt);
const auto newReplayGain =
m_record.getMetadata().getTrackInfo().getReplayGain();
@@ -245,10 +245,10 @@ bool Track::mergeExtraMetadataFromSource(
}
mixxx::TrackMetadata Track::getMetadata(
- bool* pMetadataSynchronized) const {
+ bool* pSourceSynchronized) const {
const QMutexLocker locked(&m_qMutex);
- if (pMetadataSynchronized) {
- *pMetadataSynchronized = m_record.getMetadataSynchronized();
+ if (pSourceSynchronized) {
+ *pSourceSynchronized = m_record.isSourceSynchronized();
}
return m_record.getMetadata();
}
@@ -461,16 +461,23 @@ void Track::emitChangedSignalsForAllMetadata() {
emit keyChanged();
}
-void Track::setMetadataSynchronized(bool metadataSynchronized) {
+bool Track::isSourceSynchronized() const {
QMutexLocker lock(&m_qMutex);
- if (compareAndSet(m_record.ptrMetadataSynchronized(), metadataSynchronized)) {
+ return m_record.isSourceSynchronized();
+}
+
+void Track::setSourceSynchronizedAt(const QDateTime& sourceSynchronizedAt) {
+ DEBUG_ASSERT(!sourceSynchronizedAt.isValid() ||
+ sourceSynchronizedAt.timeSpec() == Qt::UTC);
+ QMutexLocker lock(&m_qMutex);
+ if (compareAndSet(m_record.ptrSourceSynchronizedAt(), sourceSynchronizedAt)) {
markDirtyAndUnlock(&lock);
}
}
-bool Track::isMetadataSynchronized() const {
+QDateTime Track::getSourceSynchronizedAt() const {
QMutexLocker lock(&m_qMutex);
- return m_record.getMetadataSynchronized();
+ return m_record.getSourceSynchronizedAt();
}
QString Track::getInfo() const {
@@ -1430,12 +1437,11 @@ ExportTrackMetadataResult Track::exportMetadata(
// be called after all references to the object have been dropped.
// But it doesn't hurt much, so let's play it safe ;)
QMutexLocker lock(&m_qMutex);
- // TODO(XXX): m_record.getMetadataSynchronized() currently is a
- // boolean flag, but it should become a time stamp in the future.
- // We could take this time stamp and the file's last modification
- // time stamp into account and might decide to skip importing
- // the metadata again.
- if (!m_bMarkedForMetadataExport && !m_record.getMetadataSynchronized()) {
+ // TODO(XXX): Use sourceSynchronizedAt to decide if metadata
+ // should be (re-)imported before exporting it. The file might
+ // have been updated by external applications. Overwriting
+ // this modified metadata might not be intended.
+ if (!m_bMarkedForMetadataExport && !m_record.isSourceSynchronized()) {
// If the metadata has never been imported from file tags it
// must be exported explicitly once. This ensures that we don't
// overwrite existing file tags with completely different
@@ -1577,10 +1583,7 @@ ExportTrackMetadataResult Track::exportMetadata(
// This information (flag or time stamp) is stored in the database.
// The database update will follow immediately after returning from
// this operation!
- // TODO(XXX): Replace bool with QDateTime
- DEBUG_ASSERT(!trackMetadataExported.second.isNull());
- //pTrack->setMetadataSynchronized(trackMetadataExported.second);
- m_record.setMetadataSynchronized(!trackMetadataExported.second.isNull());
+ m_record.updateSourceSynchronizedAt(trackMetadataExported.second);
if (kLogger.debugEnabled()) {
kLogger.debug()
<< "Exported track metadata:"
diff --git a/src/track/track.h b/src/track/track.h
index 10a66c5533a..7352d89045b 100644
--- a/src/track/track.h
+++ b/src/track/track.h
@@ -72,6 +72,7 @@ class Track : public QObject {
STORED false NOTIFY durationChanged)
Q_PROPERTY(QString info READ getInfo STORED false NOTIFY infoChanged)
Q_PROPERTY(QString titleInfo READ getTitleInfo STORED false NOTIFY infoChanged)
+ Q_PROPERTY(QDateTime sourceSynchronizedAt READ getSourceSynchronizedAt STORED false)
mixxx::FileAccess getFileAccess() const {
// Copying QFileInfo is thread-safe due to implicit sharing,
@@ -148,9 +149,18 @@ class Track : public QObject {
mixxx::ReplayGain getReplayGain() const;
// Indicates if the metadata has been parsed from file tags.
- bool isMetadataSynchronized() const;
- // Only used by a free function in TrackDAO!
- void setMetadataSynchronized(bool metadataSynchronized);
+ bool isSourceSynchronized() const;
+
+ void setHeaderParsedFromTrackDAO(bool headerParsed) {
+ // Always operating on a newly created, exclusive instance! No need
+ // to lock the mutex.
+ DEBUG_ASSERT(!m_record.m_headerParsed);
+ m_record.m_headerParsed = headerParsed;
+ }
+
+ // The date/time of the last import or export of metadata
+ void setSourceSynchronizedAt(const QDateTime& sourceSynchronizedAt);
+ QDateTime getSourceSynchronizedAt() const;
void setDateAdded(const QDateTime& dateAdded);
QDateTime getDateAdded() const;
@@ -336,10 +346,10 @@ class Track : public QObject {
/// with file tags, either by importing or exporting the metadata.
void replaceMetadataFromSource(
mixxx::TrackMetadata importedMetadata,
- const QDateTime& metadataSynchronized);
+ const QDateTime& sourceSynchronizedAt);
mixxx::TrackMetadata getMetadata(
- bool* pMetadataSynchronized = nullptr) const;
+ bool* pHeaderParsed = nullptr) const;
mixxx::TrackRecord getRecord(
bool* pDirty = nullptr) const;
diff --git a/src/track/trackrecord.cpp b/src/track/trackrecord.cpp
index 39a6d077245..6d09d3724a6 100644
--- a/src/track/trackrecord.cpp
+++ b/src/track/trackrecord.cpp
@@ -15,9 +15,9 @@ const Logger kLogger("TrackRecord");
TrackRecord::TrackRecord(TrackId id)
: m_id(std::move(id)),
- m_metadataSynchronized(false),
m_rating(0),
- m_bpmLocked(false) {
+ m_bpmLocked(false),
+ m_headerParsed(false) {
}
void TrackRecord::setKeys(const Keys& keys) {
@@ -107,9 +107,47 @@ bool copyIfNotEmpty(
} // anonymous namespace
+bool TrackRecord::updateSourceSynchronizedAt(
+ const QDateTime& sourceSynchronizedAt) {
+ VERIFY_OR_DEBUG_ASSERT(sourceSynchronizedAt.isValid()) {
+ // Cannot be reset after it has been set at least once.
+ // This is required to prevent unintended and repeated
+ // reimporting of metadata from file tags.
+ return false;
+ }
+ if (getSourceSynchronizedAt() == sourceSynchronizedAt) {
+ return false; // unchanged
+ }
+ setSourceSynchronizedAt(sourceSynchronizedAt);
+ m_headerParsed = sourceSynchronizedAt.isValid();
+ DEBUG_ASSERT(isSourceSynchronized());
+ return true;
+}
+
+bool TrackRecord::isSourceSynchronized() const {
+ // This method cannot be used to update m_headerParsed
+ // after modifying m_sourceSynchronizedAt during a short
+ // moment of inconsistency. Otherwise the debug assertion
+ // triggers!
+ DEBUG_ASSERT(m_headerParsed ||
+ !getSourceSynchronizedAt().isValid());
+ if (getSourceSynchronizedAt().isValid()) {
+ return true;
+ }
+ // Legacy fallback: The property sourceSynchronizedAt has been
+ // added later. Files that have been added before that time
+ // and that have never been re-imported will only have that
+ // legacy flag set while sourceSynchronizedAt is still invalid.
+ return m_headerParsed;
+}
+
bool TrackRecord::replaceMetadataFromSource(
TrackMetadata&& importedMetadata,
- const QDateTime& metadataSynchronized) {
+ const QDateTime& sourceSynchronizedAt) {
+ VERIFY_OR_DEBUG_ASSERT(sourceSynchronizedAt.isValid()) {
+ return false;
+ }
+ DEBUG_ASSERT(sourceSynchronizedAt.timeSpec() == Qt::UTC);
if (m_streamInfoFromSource) {
// Preserve precise stream info if available, i.e. discard the
// audio properties that are also stored as track metadata.
@@ -120,16 +158,7 @@ bool TrackRecord::replaceMetadataFromSource(
setMetadata(std::move(importedMetadata));
modified = true;
}
- // Only set the metadata synchronized flag (column `header_parsed`
- // in the database) from false to true, but never reset it back to
- // false. Otherwise file tags would be re-imported and overwrite
- // the metadata stored in the database, e.g. after retrieving metadata
- // from MusicBrainz!
- // TODO: In the future this flag should become a time stamp
- // to detect updates of files and then decide based on time
- // stamps if file tags need to be re-imported.
- if (!getMetadataSynchronized() && !metadataSynchronized.isNull()) {
- setMetadataSynchronized(true);
+ if (updateSourceSynchronizedAt(sourceSynchronizedAt)) {
modified = true;
}
return modified;
@@ -278,7 +307,7 @@ bool operator==(const TrackRecord& lhs, const TrackRecord& rhs) {
return lhs.getMetadata() == rhs.getMetadata() &&
lhs.getCoverInfo() == rhs.getCoverInfo() &&
lhs.getId() == rhs.getId() &&
- lhs.getMetadataSynchronized() == rhs.getMetadataSynchronized() &&
+ lhs.getSourceSynchronizedAt() == rhs.getSourceSynchronizedAt() &&
lhs.getDateAdded() == rhs.getDateAdded() &&
lhs.getFileType() == rhs.getFileType() &&
lhs.getUrl() == rhs.getUrl() &&
@@ -287,7 +316,8 @@ bool operator==(const TrackRecord& lhs, const TrackRecord& rhs) {
lhs.getCuePoint() == rhs.getCuePoint() &&
lhs.getBpmLocked() == rhs.getBpmLocked() &&
lhs.getKeys() == rhs.getKeys() &&
- lhs.getRating() == rhs.getRating();
+ lhs.getRating() == rhs.getRating() &&
+ lhs.m_headerParsed == rhs.m_headerParsed;
}
} // namespace mixxx
diff --git a/src/track/trackrecord.h b/src/track/trackrecord.h
index 354a41ef02b..9f4b6abdfa0 100644
--- a/src/track/trackrecord.h
+++ b/src/track/trackrecord.h
@@ -1,15 +1,13 @@
#pragma once
+#include "library/coverart.h"
#include "proto/keys.pb.h"
-
-#include "track/trackid.h"
#include "track/cue.h"
#include "track/keys.h"
#include "track/keyutils.h"
-#include "track/trackmetadata.h"
#include "track/playcounter.h"
-
-#include "library/coverart.h"
+#include "track/trackid.h"
+#include "track/trackmetadata.h"
#include "util/color/rgbcolor.h"
@@ -39,19 +37,13 @@ class TrackRecord final {
// has been inserted or is loaded from the library DB.
MIXXX_DECL_PROPERTY(TrackId, id, Id)
- // TODO(uklotz): Change data type from bool to QDateTime
- //
// Both import and export of metadata can be tracked by a single time
// stamp, the direction doesn't matter. The value should be set to the
// modification time stamp provided by the metadata source. This would
// enable us to update the metadata of all tracks in the database after
// the external metadata has been modified, i.e. if the corresponding
// files have been modified.
- //
- // Requires a database update! We could reuse the 'header_parsed' column.
- // During migration the boolean value will be substituted with either a
- // default time stamp 1970-01-01 00:00:00.000 or NULL respectively.
- MIXXX_DECL_PROPERTY(bool /*QDateTime*/, metadataSynchronized, MetadataSynchronized)
+ MIXXX_DECL_PROPERTY(QDateTime, sourceSynchronizedAt, SourceSynchronizedAt)
MIXXX_DECL_PROPERTY(CoverInfoRelative, coverInfo, CoverInfo)
@@ -117,9 +109,11 @@ class TrackRecord final {
const QString& keyText,
track::io::key::Source keySource);
+ bool isSourceSynchronized() const;
bool replaceMetadataFromSource(
TrackMetadata&& importedMetadata,
- const QDateTime& metadataSynchronized);
+ const QDateTime& sourceSynchronizedAt);
+
// Merge the current metadata with new and additional properties
// imported from the file. Since these properties are not (yet)
// stored in the library or have been added later all existing
@@ -148,7 +142,13 @@ class TrackRecord final {
return m_streamInfoFromSource;
}
-private:
+ private:
+ // TODO: Remove this dependency
+ friend class ::Track;
+
+ bool updateSourceSynchronizedAt(
+ const QDateTime& sourceSynchronizedAt);
+
Keys m_keys;
// TODO: Use TrackMetadata as single source of truth and do not
@@ -173,6 +173,8 @@ class TrackRecord final {
// Stale metadata should be re-imported depending on the other flags.
std::optional m_streamInfoFromSource;
+ bool m_headerParsed; // deprecated, replaced by sourceSynchronizedAt
+
/// Equality comparison
///
/// Exception: The member m_streamInfoFromSource must not be considered