summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/library/dao/trackdao.cpp24
-rw-r--r--src/library/library_prefs.cpp6
-rw-r--r--src/library/library_prefs.h6
-rw-r--r--src/library/trackcollectionmanager.cpp2
-rw-r--r--src/preferences/dialog/dlgpreflibrary.cpp22
-rw-r--r--src/preferences/dialog/dlgpreflibrary.h2
-rw-r--r--src/preferences/dialog/dlgpreflibrarydlg.ui14
-rw-r--r--src/sources/metadatasource.cpp27
-rw-r--r--src/sources/metadatasource.h4
-rw-r--r--src/sources/metadatasourcetaglib.cpp19
-rw-r--r--src/sources/soundsourceproxy.cpp92
-rw-r--r--src/sources/soundsourceproxy.h26
-rw-r--r--src/test/autodjprocessor_test.cpp7
-rw-r--r--src/test/coverartutils_test.cpp4
-rw-r--r--src/test/soundproxy_test.cpp22
-rw-r--r--src/test/trackupdate_test.cpp30
-rw-r--r--src/track/track.cpp21
-rw-r--r--src/track/track.h8
-rw-r--r--src/track/trackrecord.cpp52
-rw-r--r--src/track/trackrecord.h17
-rw-r--r--src/widget/wtrackmenu.cpp13
21 files changed, 296 insertions, 122 deletions
diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp
index f10914bfcc..de1b475388 100644
--- a/src/library/dao/trackdao.cpp
+++ b/src/library/dao/trackdao.cpp
@@ -19,6 +19,7 @@
#include "library/dao/libraryhashdao.h"
#include "library/dao/playlistdao.h"
#include "library/dao/trackschema.h"
+#include "library/library_prefs.h"
#include "library/queryutil.h"
#include "library/trackset/crate/cratestorage.h"
#include "moc_trackdao.cpp"
@@ -849,8 +850,10 @@ TrackPointer TrackDAO::addTracksAddFile(
// Initially (re-)import the metadata for the newly created track
// from the file.
- SoundSourceProxy(pTrack).updateTrackFromSource();
- if (!pTrack->isSourceSynchronized()) {
+ SoundSourceProxy(pTrack).updateTrackFromSource(
+ m_pConfig,
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once);
+ if (!pTrack->checkSourceSynchronized()) {
qWarning() << "TrackDAO::addTracksAddFile:"
<< "Failed to parse track metadata from file"
<< pTrack->getLocation();
@@ -1487,7 +1490,22 @@ TrackPointer TrackDAO::getTrackById(TrackId trackId) const {
// file. This import might have never been completed successfully
// before, so just check and try for every track that has been
// freshly loaded from the database.
- SoundSourceProxy(pTrack).updateTrackFromSource();
+ auto updateTrackFromSourceMode =
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once;
+ if (m_pConfig &&
+ m_pConfig->getValueString(
+ mixxx::library::prefs::kSyncTrackMetadataConfigKey)
+ .toInt() == 1) {
+ // An implicit re-import and update is performed if the
+ // user has enabled export of file tags in the preferences.
+ // Either they want to keep their file tags synchronized or
+ // not, no exceptions!
+ updateTrackFromSourceMode =
+ SoundSourceProxy::UpdateTrackFromSourceMode::Newer;
+ }
+ SoundSourceProxy(pTrack).updateTrackFromSource(
+ m_pConfig,
+ updateTrackFromSourceMode);
if (kLogger.debugEnabled() && pTrack->isDirty()) {
kLogger.debug()
<< "Updated track metadata from file tags:"
diff --git a/src/library/library_prefs.cpp b/src/library/library_prefs.cpp
index 020b930dcd..b3b1e3d731 100644
--- a/src/library/library_prefs.cpp
+++ b/src/library/library_prefs.cpp
@@ -28,12 +28,14 @@ const ConfigKey mixxx::library::prefs::kSearchDebouncingTimeoutMillisConfigKey =
mixxx::library::prefs::kConfigGroup,
QStringLiteral("SearchDebouncingTimeoutMillis")};
-const ConfigKey mixxx::library::prefs::kSyncTrackMetadataExportConfigKey =
+// The "Export" suffix in the key is kept for backward compatibility
+const ConfigKey mixxx::library::prefs::kSyncTrackMetadataConfigKey =
ConfigKey{
mixxx::library::prefs::kConfigGroup,
QStringLiteral("SyncTrackMetadataExport")};
-const ConfigKey mixxx::library::prefs::kSeratoMetadataExportConfigKey =
+// The naming is unchanged for backward compatibility
+const ConfigKey mixxx::library::prefs::kSyncSeratoMetadataConfigKey =
ConfigKey{
mixxx::library::prefs::kConfigGroup,
QStringLiteral("SeratoMetadataExport")};
diff --git a/src/library/library_prefs.h b/src/library/library_prefs.h
index 32077ebc3b..cf3bf3b6cb 100644
--- a/src/library/library_prefs.h
+++ b/src/library/library_prefs.h
@@ -20,9 +20,11 @@ extern const ConfigKey kEditMetadataSelectedClickConfigKey;
const bool kEditMetadataSelectedClickDefault = false;
-extern const ConfigKey kSyncTrackMetadataExportConfigKey;
+extern const ConfigKey kSyncTrackMetadataConfigKey;
-extern const ConfigKey kSeratoMetadataExportConfigKey;
+extern const ConfigKey kSyncSeratoMetadataConfigKey;
+
+extern const ConfigKey kSyncSeratoMetadataConfigKey;
} // namespace prefs
diff --git a/src/library/trackcollectionmanager.cpp b/src/library/trackcollectionmanager.cpp
index 761c64ccee..d10e7762e5 100644
--- a/src/library/trackcollectionmanager.cpp
+++ b/src/library/trackcollectionmanager.cpp
@@ -285,7 +285,7 @@ void TrackCollectionManager::exportTrackMetadata(
(pTrack->isDirty() &&
m_pConfig &&
m_pConfig->getValueString(
- mixxx::library::prefs::kSyncTrackMetadataExportConfigKey)
+ mixxx::library::prefs::kSyncTrackMetadataConfigKey)
.toInt() == 1)) {
switch (mode) {
case TrackMetadataExportMode::Immediate:
diff --git a/src/preferences/dialog/dlgpreflibrary.cpp b/src/preferences/dialog/dlgpreflibrary.cpp
index 58d3076703..6f6b754f29 100644
--- a/src/preferences/dialog/dlgpreflibrary.cpp
+++ b/src/preferences/dialog/dlgpreflibrary.cpp
@@ -124,10 +124,10 @@ DlgPrefLibrary::DlgPrefLibrary(
QDesktopServices::openUrl(url);
});
- connect(checkBox_SyncTrackMetadataExport,
+ connect(checkBox_SyncTrackMetadata,
&QCheckBox::toggled,
this,
- &DlgPrefLibrary::slotSyncTrackMetadataExportToggled);
+ &DlgPrefLibrary::slotSyncTrackMetadataToggled);
// Initialize the controls after all slots have been connected
slotUpdate();
@@ -191,7 +191,7 @@ void DlgPrefLibrary::initializeDirList() {
void DlgPrefLibrary::slotResetToDefaults() {
checkBox_library_scan->setChecked(false);
- checkBox_SyncTrackMetadataExport->setChecked(false);
+ checkBox_SyncTrackMetadata->setChecked(false);
checkBox_SeratoMetadataExport->setChecked(false);
checkBox_use_relative_path->setChecked(false);
checkBox_show_rhythmbox->setChecked(true);
@@ -211,10 +211,10 @@ void DlgPrefLibrary::slotUpdate() {
initializeDirList();
checkBox_library_scan->setChecked(m_pConfig->getValue(
ConfigKey("[Library]","RescanOnStartup"), false));
- checkBox_SyncTrackMetadataExport->setChecked(
- m_pConfig->getValue(kSyncTrackMetadataExportConfigKey, false));
+ checkBox_SyncTrackMetadata->setChecked(
+ m_pConfig->getValue(kSyncTrackMetadataConfigKey, false));
checkBox_SeratoMetadataExport->setChecked(
- m_pConfig->getValue(kSeratoMetadataExportConfigKey, false));
+ m_pConfig->getValue(kSyncSeratoMetadataConfigKey, false));
checkBox_use_relative_path->setChecked(m_pConfig->getValue(
ConfigKey("[Library]","UseRelativePathOnExport"), false));
checkBox_show_rhythmbox->setChecked(m_pConfig->getValue(
@@ -379,10 +379,10 @@ void DlgPrefLibrary::slotApply() {
m_pConfig->set(ConfigKey("[Library]","RescanOnStartup"),
ConfigValue((int)checkBox_library_scan->isChecked()));
m_pConfig->set(
- kSyncTrackMetadataExportConfigKey,
- ConfigValue{checkBox_SyncTrackMetadataExport->isChecked()});
+ kSyncTrackMetadataConfigKey,
+ ConfigValue{checkBox_SyncTrackMetadata->isChecked()});
m_pConfig->set(
- kSeratoMetadataExportConfigKey,
+ kSyncSeratoMetadataConfigKey,
ConfigValue{checkBox_SeratoMetadataExport->isChecked()});
m_pConfig->set(ConfigKey("[Library]","UseRelativePathOnExport"),
ConfigValue((int)checkBox_use_relative_path->isChecked()));
@@ -467,8 +467,8 @@ void DlgPrefLibrary::slotSearchDebouncingTimeoutMillisChanged(int searchDebounci
WSearchLineEdit::setDebouncingTimeoutMillis(searchDebouncingTimeoutMillis);
}
-void DlgPrefLibrary::slotSyncTrackMetadataExportToggled() {
- if (isVisible() && checkBox_SyncTrackMetadataExport->isChecked()) {
+void DlgPrefLibrary::slotSyncTrackMetadataToggled() {
+ if (isVisible() && checkBox_SyncTrackMetadata->isChecked()) {
mixxx::DlgTrackMetadataExport::showMessageBoxOncePerSession();
}
}
diff --git a/src/preferences/dialog/dlgpreflibrary.h b/src/preferences/dialog/dlgpreflibrary.h
index 840a906461..ff4f2aa4fd 100644
--- a/src/preferences/dialog/dlgpreflibrary.h
+++ b/src/preferences/dialog/dlgpreflibrary.h
@@ -53,7 +53,7 @@ class DlgPrefLibrary : public DlgPreferencePage, public Ui::DlgPrefLibraryDlg {
private slots:
void slotRowHeightValueChanged(int);
void slotSelectFont();
- void slotSyncTrackMetadataExportToggled();
+ void slotSyncTrackMetadataToggled();
void slotSearchDebouncingTimeoutMillisChanged(int);
void slotSeratoMetadataExportClicked(bool);
diff --git a/src/preferences/dialog/dlgpreflibrarydlg.ui b/src/preferences/dialog/dlgpreflibrarydlg.ui
index d0da4273eb..233ec94fec 100644
--- a/src/preferences/dialog/dlgpreflibrarydlg.ui
+++ b/src/preferences/dialog/dlgpreflibrarydlg.ui
@@ -132,16 +132,22 @@
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" colspan="2">
- <widget class="QCheckBox" name="checkBox_SyncTrackMetadataExport">
+ <widget class="QCheckBox" name="checkBox_SyncTrackMetadata">
<property name="text">
- <string>Automatically write modified track metadata from the library into file tags</string>
+ <string>Synchronize library track metadata from/to file tags</string>
+ </property>
+ <property name="toolTip">
+ <string>Automatically write modified track metadata from the library into file tags and reimport metadata from updated file tags into the library</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_SeratoMetadataExport">
<property name="text">
- <string>Write Serato Metadata to files (experimental)</string>
+ <string>Synchronize Serato track metadata from/to file tags (experimental)</string>
+ </property>
+ <property name="toolTip">
+ <string>Keeps track color, beat grid, bpm lock, cue points, and loops synchronized with SERATO_MARKERS/MARKERS2 file tags.&lt;br/&gt;&lt;br/&gt;WARNING: Enabling this option also enables the reimport of Serato metadata after files have been modified outside of Mixxx. On reimport existing metadata in Mixxx is replaced with the metadata found in file tags. Custom metadata not included in file tags like loop colors is lost.</string>
</property>
</widget>
</item>
@@ -453,7 +459,7 @@
<tabstop>PushButtonAddDir</tabstop>
<tabstop>PushButtonRelocateDir</tabstop>
<tabstop>PushButtonRemoveDir</tabstop>
- <tabstop>checkBox_SyncTrackMetadataExport</tabstop>
+ <tabstop>checkBox_SyncTrackMetadata</tabstop>
<tabstop>checkBox_library_scan</tabstop>
<tabstop>checkBoxEditMetadataSelectedClicked</tabstop>
<tabstop>checkBox_use_relative_path</tabstop>
diff --git a/src/sources/metadatasource.cpp b/src/sources/metadatasource.cpp
new file mode 100644
index 0000000000..30c571ad5b
--- /dev/null
+++ b/src/sources/metadatasource.cpp
@@ -0,0 +1,27 @@
+#include "sources/metadatasource.h"
+
+#include "util/logger.h"
+
+namespace mixxx {
+
+namespace {
+
+const Logger kLogger("MetadataSource");
+
+} // anonymous namespace
+
+// static
+QDateTime MetadataSource::getFileSynchronizedAt(const QFileInfo& fileInfo) {
+ const QDateTime lastModifiedUtc = fileInfo.lastModified().toUTC();
+ // Ignore bogus values like 1970-01-01T00:00:00.000 UTC
+ // that are obviously incorrect and don't provide any
+ // information.
+ if (lastModifiedUtc.isValid() &&
+ // Only defined if valid
+ lastModifiedUtc.toMSecsSinceEpoch() == 0) {
+ return QDateTime{};
+ }
+ return lastModifiedUtc;
+}
+
+} // namespace mixxx
diff --git a/src/sources/metadatasource.h b/src/sources/metadatasource.h
index 2ee4c65e01..852e5c0501 100644
--- a/src/sources/metadatasource.h
+++ b/src/sources/metadatasource.h
@@ -1,8 +1,8 @@
#pragma once
#include <QDateTime>
+#include <QFileInfo>
#include <QImage>
-
#include <utility>
#include "track/trackmetadata.h"
@@ -20,6 +20,8 @@ class MetadataSource {
public:
virtual ~MetadataSource() = default;
+ static QDateTime getFileSynchronizedAt(const QFileInfo& fileInfo);
+
enum class ImportResult {
Succeeded,
Failed,
diff --git a/src/sources/metadatasourcetaglib.cpp b/src/sources/metadatasourcetaglib.cpp
index 37dfad843c..d9be95f71d 100644
--- a/src/sources/metadatasourcetaglib.cpp
+++ b/src/sources/metadatasourcetaglib.cpp
@@ -72,29 +72,18 @@ class AiffFile : public TagLib::RIFF::AIFF::File {
}
};
-inline QDateTime getSourceSynchronizedAt(const QFileInfo& fileInfo) {
- const QDateTime lastModifiedUtc = fileInfo.lastModified().toUTC();
- // Ignore bogus values like 1970-01-01T00:00:00.000 UTC
- // that are obviously incorrect and don't provide any
- // information.
- if (lastModifiedUtc.isValid() &&
- // Only defined if valid
- lastModifiedUtc.toMSecsSinceEpoch() == 0) {
- return QDateTime{};
- }
- return lastModifiedUtc;
-}
-
} // anonymous namespace
std::pair<MetadataSourceTagLib::ImportResult, QDateTime>
MetadataSourceTagLib::afterImport(ImportResult importResult) const {
- return std::make_pair(importResult, getSourceSynchronizedAt(QFileInfo(m_fileName)));
+ return std::make_pair(importResult,
+ MetadataSource::getFileSynchronizedAt(QFileInfo(m_fileName)));
}
std::pair<MetadataSourceTagLib::ExportResult, QDateTime>
MetadataSourceTagLib::afterExport(ExportResult exportResult) const {
- return std::make_pair(exportResult, getSourceSynchronizedAt(QFileInfo(m_fileName)));
+ return std::make_pair(exportResult,
+ MetadataSource::getFileSynchronizedAt(QFileInfo(m_fileName)));
}
std::pair<MetadataSource::ImportResult, QDateTime>
diff --git a/src/sources/soundsourceproxy.cpp b/src/sources/soundsourceproxy.cpp
index 6428f3732d..249984b7f3 100644
--- a/src/sources/soundsourceproxy.cpp
+++ b/src/sources/soundsourceproxy.cpp
@@ -4,6 +4,7 @@
#include <QRegularExpression>
#include <QStandardPaths>
+#include "library/library_prefs.h"
#include "sources/audiosourcetrackproxy.h"
#ifdef __MAD__
@@ -517,7 +518,35 @@ SoundSourceProxy::importTrackMetadataAndCoverImage(
pCoverImage);
}
+namespace {
+
+inline bool shouldUpdateTrackMetadataFromSource(
+ SoundSourceProxy::UpdateTrackFromSourceMode mode,
+ mixxx::TrackRecord::SourceSyncStatus sourceSyncStatus) {
+ return mode == SoundSourceProxy::UpdateTrackFromSourceMode::Always ||
+ (mode == SoundSourceProxy::UpdateTrackFromSourceMode::Newer &&
+ sourceSyncStatus == mixxx::TrackRecord::SourceSyncStatus::Outdated) ||
+ (mode == SoundSourceProxy::UpdateTrackFromSourceMode::Once &&
+ sourceSyncStatus == mixxx::TrackRecord::SourceSyncStatus::Void);
+}
+
+inline bool shouldImportSeratoTagsFromSource(
+ const UserSettingsPointer& pConfig,
+ mixxx::TrackRecord::SourceSyncStatus sourceSyncStatus) {
+ // Only reimport track metadata from Serato markers if export of
+ // Serato markers is enabled. This should ensure that track color,
+ // cue points, and loops do not get lost after they have been
+ // modified in Mixxx.
+ // A reimport of metadata happens if
+ // sourceSyncStatus == mixxx::TrackRecord::SourceSyncStatus::Outdated
+ return sourceSyncStatus != mixxx::TrackRecord::SourceSyncStatus::Outdated ||
+ pConfig->getValue<bool>(mixxx::library::prefs::kSyncSeratoMetadataConfigKey);
+}
+
+} // namespace
+
bool SoundSourceProxy::updateTrackFromSource(
+ const UserSettingsPointer& pConfig,
UpdateTrackFromSourceMode mode) {
DEBUG_ASSERT(m_pTrack);
@@ -540,9 +569,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 headerParsed = false;
+ mixxx::TrackRecord::SourceSyncStatus sourceSyncStatus;
mixxx::TrackMetadata trackMetadata =
- m_pTrack->getMetadata(&headerParsed);
+ m_pTrack->getMetadata(&sourceSyncStatus);
// Save for later to replace the unreliable and imprecise audio
// properties imported from file tags (see below).
@@ -555,17 +584,13 @@ bool SoundSourceProxy::updateTrackFromSource(
DEBUG_ASSERT(coverImg.isNull());
QImage* pCoverImg = nullptr; // pointer also serves as a flag
- // If the file tags have already been parsed at least once, the
- // existing track metadata should not be updated implicitly, i.e.
- // if the user did not explicitly choose to (re-)import metadata
- // explicitly from this file.
- bool mergeExtraMetadataFromSource = false;
- if (headerParsed && mode == UpdateTrackFromSourceMode::Once) {
- // No (re-)import needed or desired, only merge missing properties
- mergeExtraMetadataFromSource = true;
- } else {
- // Import the cover initially or when a reimport has been requested
+ const bool updateMetadataFromSource =
+ shouldUpdateTrackMetadataFromSource(mode, sourceSyncStatus);
+
+ // Decide if cover art needs to be re-imported
+ if (updateMetadataFromSource) {
const auto coverInfo = m_pTrack->getCoverInfo();
+ // Avoid replacing user selected cover art with guessed cover art!
if (coverInfo.source == CoverInfo::USER_SELECTED &&
coverInfo.type == CoverInfo::FILE) {
// Ignore embedded cover art
@@ -593,16 +618,26 @@ bool SoundSourceProxy::updateTrackFromSource(
<< "from file"
<< getUrl().toString();
// make sure that the trackMetadata was not messed up due to the failure
- trackMetadata = m_pTrack->getMetadata(&headerParsed);
+ mixxx::TrackRecord::SourceSyncStatus sourceSyncStatusNew;
+ trackMetadata = m_pTrack->getMetadata(&sourceSyncStatusNew);
+ if (sourceSyncStatus != sourceSyncStatusNew) {
+ // Do not continue after detecting an inconsistency due to
+ // race conditions while restoring the track metadata.
+ // This is almost impossible, but it may happen. The preceding
+ // warning message already identifies the track that is affected.
+ kLogger.critical() << "Aborting update of track metadata from source "
+ "due to unexpected inconsistencies during recovery";
+ return false;
+ }
}
// Partial import
- if (mergeExtraMetadataFromSource) {
- // No reimport of embedded cover image desired in this case
+ if (!updateMetadataFromSource) {
+ // No reimport of embedded cover image desired in this case.
+ // Only import and merge extra metadata that might be missing
+ // in the database.
DEBUG_ASSERT(!pCoverImg);
if (metadataImportedFromSource.first == mixxx::MetadataSource::ImportResult::Succeeded) {
- // Partial import of properties that are not (yet) stored
- // in the database
return m_pTrack->mergeExtraMetadataFromSource(trackMetadata);
} else {
// Nothing to do if no metadata has been imported
@@ -611,23 +646,26 @@ bool SoundSourceProxy::updateTrackFromSource(
}
// Full import
- 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
- // and preserve the existing data!
+ DEBUG_ASSERT(updateMetadataFromSource);
+ if (!shouldImportSeratoTagsFromSource(
+ pConfig,
+ sourceSyncStatus)) {
+ // Reset Serato tags to disable the (re-)import
+ trackMetadata.refTrackInfo().refSeratoTags() = {};
+ }
+ if (sourceSyncStatus == mixxx::TrackRecord::SourceSyncStatus::Void) {
+ DEBUG_ASSERT(pCoverImg);
if (kLogger.debugEnabled()) {
kLogger.debug()
- << "Updating track metadata"
- << (pCoverImg ? "and embedded cover art" : "")
- << "from file"
+ << "Initializing track metadata and embedded cover art from file"
<< getUrl().toString();
}
} else {
- DEBUG_ASSERT(pCoverImg);
if (kLogger.debugEnabled()) {
kLogger.debug()
- << "Initializing track metadata and embedded cover art from file"
+ << "Re-importing track metadata"
+ << (pCoverImg ? "and embedded cover art" : "")
+ << "from file"
<< getUrl().toString();
}
}
diff --git a/src/sources/soundsourceproxy.h b/src/sources/soundsourceproxy.h
index 679e30daa7..df52b0434c 100644
--- a/src/sources/soundsourceproxy.h
+++ b/src/sources/soundsourceproxy.h
@@ -105,18 +105,25 @@ class SoundSourceProxy {
/// Controls which (metadata/coverart) and how tags are (re-)imported from
/// audio files when creating a SoundSourceProxy.
+ ///
+ /// Cover art is only re-imported and updated if it has been guessed from
+ /// metadata to prevent overwriting a custom choice.
enum class UpdateTrackFromSourceMode {
// Import both track metadata and cover image once for new track objects.
// Otherwise the request is ignored and the track object is not modified.
Once,
- // (Re-)Import the track's metadata and cover art. Cover art is
- // only updated if it has been guessed from metadata to prevent
- // overwriting a custom choice.
- Again,
- // If omitted both metadata and cover image will be imported at most
- // once for each track object to avoid overwriting modified data in
- // the library.
- Default = Once,
+ /// (Re-)Import the track's metadata and cover art if the file's modification
+ /// time stamp is newer than the last synchronization time stamp.
+ ///
+ /// Source synchronization time stamps have been introduced by v2.4.0.
+ /// For existing files in the library this time stamp is undefined until
+ /// metadata is manually re-imported! In this case we cannot determine
+ /// if the file tags contain updated data and need to skip the implicit
+ /// re-import to prevent overwriting precious user data.
+ Newer,
+ // Unconditionally (re-)import the track's metadata and cover art, independent
+ // of when the file has last been modified and the synchronization time stamp.
+ Always,
};
/// Updates file type, metadata, and cover image of the track object
@@ -142,7 +149,8 @@ class SoundSourceProxy {
///
/// Returns true if the track has been modified and false otherwise.
bool updateTrackFromSource(
- UpdateTrackFromSourceMode mode = UpdateTrackFromSourceMode::Default);
+ const UserSettingsPointer& pConfig,
+ UpdateTrackFromSourceMode mode);
/// Opening the audio source through the proxy will update the
/// audio properties of the corresponding track object. Returns
diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp
index 145fa416c2..9ec3ae33d0 100644
--- a/src/test/autodjprocessor_test.cpp
+++ b/src/test/autodjprocessor_test.cpp
@@ -167,10 +167,13 @@ class AutoDJProcessorTest : public LibraryTest {
static TrackId nextTrackId(TrackId trackId) {
return TrackId(trackId.value() + 1);
}
- static TrackPointer newTestTrack(TrackId trackId) {
+
+ TrackPointer newTestTrack(TrackId trackId) const {
TrackPointer pTrack(
Track::newDummy(kTrackLocationTest, trackId));
- EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource());
+ EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource(
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once));
return pTrack;
}
diff --git a/src/test/coverartutils_test.cpp b/src/test/coverartutils_test.cpp
index 8bf8635dfe..0bec9234b9 100644
--- a/src/test/coverartutils_test.cpp
+++ b/src/test/coverartutils_test.cpp
@@ -114,7 +114,9 @@ TEST_F(CoverArtUtilTest, searchImage) {
// Looking for a track with embedded cover.
pTrack = Track::newTemporary(kTrackLocationTest);
- EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource());
+ EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource(
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once));
CoverInfo result = pTrack->getCoverInfoWithLocation();
EXPECT_EQ(result.type, CoverInfo::METADATA);
EXPECT_EQ(result.source, CoverInfo::GUESSED);
diff --git a/src/test/soundproxy_test.cpp b/src/test/soundproxy_test.cpp
index f2d6cc9ff3..98a496bd8a 100644
--- a/src/test/soundproxy_test.cpp
+++ b/src/test/soundproxy_test.cpp
@@ -213,7 +213,9 @@ TEST_F(SoundSourceProxyTest, openEmptyFile) {
TEST_F(SoundSourceProxyTest, readArtist) {
auto pTrack = Track::newTemporary(kTestDir, "artist.mp3");
SoundSourceProxy proxy(pTrack);
- EXPECT_TRUE(proxy.updateTrackFromSource());
+ EXPECT_TRUE(proxy.updateTrackFromSource(
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once));
EXPECT_EQ("Test Artist", pTrack->getArtist());
}
@@ -224,33 +226,41 @@ TEST_F(SoundSourceProxyTest, readNoTitle) {
auto pTrack1 = Track::newTemporary(
kTestDir, "empty.mp3");
SoundSourceProxy proxy1(pTrack1);
- EXPECT_TRUE(proxy1.updateTrackFromSource());
+ EXPECT_TRUE(proxy1.updateTrackFromSource(
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once));
EXPECT_EQ("empty", pTrack1->getTitle());
// Test a reload also works
pTrack1->setTitle("");
EXPECT_TRUE(proxy1.updateTrackFromSource(
- SoundSourceProxy::UpdateTrackFromSourceMode::Again));
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Always));
EXPECT_EQ("empty", pTrack1->getTitle());
// Test a file with other metadata but no title
auto pTrack2 = Track::newTemporary(
kTestDir, "cover-test-png.mp3");
SoundSourceProxy proxy2(pTrack2);
- EXPECT_TRUE(proxy2.updateTrackFromSource());
+ EXPECT_TRUE(proxy2.updateTrackFromSource(
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once));
EXPECT_EQ("cover-test-png", pTrack2->getTitle());
// Test a reload also works
pTrack2->setTitle("");
EXPECT_TRUE(proxy2.updateTrackFromSource(
- SoundSourceProxy::UpdateTrackFromSourceMode::Again));
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Always));
EXPECT_EQ("cover-test-png", pTrack2->getTitle());
// Test a file with a title
auto pTrack3 = Track::newTemporary(
kTestDir, "cover-test-jpg.mp3");
SoundSourceProxy proxy3(pTrack3);
- EXPECT_TRUE(proxy3.updateTrackFromSource());
+ EXPECT_TRUE(proxy3.updateTrackFromSource(
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once));
EXPECT_EQ("test22kMono", pTrack3->getTitle());
}
diff --git a/src/test/trackupdate_test.cpp b/src/test/trackupdate_test.cpp
index 3b4b0f4709..4cd0a44e30 100644
--- a/src/test/trackupdate_test.cpp
+++ b/src/test/trackupdate_test.cpp
@@ -27,10 +27,12 @@ class TrackUpdateTest : public MixxxTest, SoundSourceProviderRegistration {
return Track::newTemporary(kTestDir, "TOAL_TPE2.mp3");
}
- static TrackPointer newTestTrackParsed() {
+ TrackPointer newTestTrackParsed() const {
auto pTrack = newTestTrack();
- EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource());
- EXPECT_TRUE(pTrack->isSourceSynchronized());
+ EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource(
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Once));
+ EXPECT_TRUE(pTrack->checkSourceSynchronized());
EXPECT_TRUE(hasTrackMetadata(pTrack));
EXPECT_TRUE(hasCoverArt(pTrack));
pTrack->markClean();
@@ -38,7 +40,7 @@ class TrackUpdateTest : public MixxxTest, SoundSourceProviderRegistration {
return pTrack;
}
- static TrackPointer newTestTrackParsedModified() {
+ TrackPointer newTestTrackParsedModified() const {
auto pTrack = newTestTrackParsed();
pTrack->setArtist(pTrack->getArtist() + pTrack->getArtist());
auto coverInfo = pTrack->getCoverInfo();
@@ -60,13 +62,14 @@ TEST_F(TrackUpdateTest, parseModifiedCleanOnce) {
// Re-update from source should have no effect
ASSERT_FALSE(SoundSourceProxy(pTrack).updateTrackFromSource(
+ config(),
SoundSourceProxy::UpdateTrackFromSourceMode::Once));
const auto trackMetadataAfter = pTrack->getMetadata();
const auto coverInfoAfter = pTrack->getCoverInfo();
// Verify that the track has not been modified
- ASSERT_TRUE(pTrack->isSourceSynchronized());
+ ASSERT_TRUE(pTrack->checkSourceSynchronized());
ASSERT_FALSE(pTrack->isDirty());
ASSERT_EQ(trackMetadataBefore, trackMetadataAfter);
ASSERT_EQ(coverInfoBefore, coverInfoAfter);
@@ -80,13 +83,14 @@ TEST_F(TrackUpdateTest, parseModifiedCleanAgainSkipCover) {
const auto coverInfoBefore = pTrack->getCoverInfo();
EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource(
- SoundSourceProxy::UpdateTrackFromSourceMode::Again));
+ config(),
+ SoundSourceProxy::UpdateTrackFromSourceMode::Always));
const auto trackMetadataAfter = pTrack->getMetadata();
const auto coverInfoAfter = pTrack->getCoverInfo();
// Updated
- EXPECT_TRUE(pTrack->isSourceSynchronized());
+ E