diff --git a/src/library/browse/browsethread.cpp b/src/library/browse/browsethread.cpp index 164a8654294..ebc395f9988 100644 --- a/src/library/browse/browsethread.cpp +++ b/src/library/browse/browsethread.cpp @@ -162,10 +162,13 @@ void BrowseThread::populateModel() { thisPath.token()); { mixxx::TrackMetadata trackMetadata; + // Both resetMissingTagMetadata = false/true have the same effect + constexpr auto resetMissingTagMetadata = false; SoundSourceProxy::importTrackMetadataAndCoverImageFromFile( fileAccess, &trackMetadata, - nullptr); + nullptr, + resetMissingTagMetadata); item = new QStandardItem(fileAccess.info().fileName()); item->setToolTip(item->text()); diff --git a/src/library/coverartutils.cpp b/src/library/coverartutils.cpp index 09764ae6c60..d8bf50fa9fb 100644 --- a/src/library/coverartutils.cpp +++ b/src/library/coverartutils.cpp @@ -46,10 +46,13 @@ QString CoverArtUtils::supportedCoverArtExtensionsRegex() { QImage CoverArtUtils::extractEmbeddedCover( mixxx::FileAccess trackFileAccess) { QImage image; + // Both resetMissingTagMetadata = false/true have the same effect + constexpr auto resetMissingTagMetadata = false; SoundSourceProxy::importTrackMetadataAndCoverImageFromFile( std::move(trackFileAccess), nullptr, - &image); + &image, + resetMissingTagMetadata); return image; } diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 25ae64df69b..f08ee25d151 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -9,6 +9,7 @@ #include "library/coverartcache.h" #include "library/coverartutils.h" #include "library/dlgtagfetcher.h" +#include "library/library_prefs.h" #include "library/trackmodel.h" #include "moc_dlgtrackinfo.cpp" #include "preferences/colorpalettesettings.h" @@ -36,10 +37,12 @@ const mixxx::Duration kMaxInterval = mixxx::Duration::fromMillis( } // namespace DlgTrackInfo::DlgTrackInfo( + UserSettingsPointer pUserSettings, const TrackModel* trackModel) // No parent because otherwise it inherits the style parent's // style which can make it unreadable. Bug #673411 : QDialog(nullptr), + m_pUserSettings(std::move(pUserSettings)), m_pTrackModel(trackModel), m_tapFilter(this, kFilterLength, kMaxInterval), m_pWCoverArtLabel(make_parented(this)), @@ -663,10 +666,12 @@ void DlgTrackInfo::slotImportMetadataFromFile() { mixxx::TrackRecord trackRecord = m_pLoadedTrack->getRecord(); mixxx::TrackMetadata trackMetadata = trackRecord.getMetadata(); QImage coverImage; + const auto resetMissingTagMetadata = m_pUserSettings->getValue( + mixxx::library::prefs::kResetMissingTagMetadataOnImportConfigKey); const auto [importResult, sourceSynchronizedAt] = SoundSourceProxy(m_pLoadedTrack) .importTrackMetadataAndCoverImage( - &trackMetadata, &coverImage); + &trackMetadata, &coverImage, resetMissingTagMetadata); if (importResult != mixxx::MetadataSource::ImportResult::Succeeded) { return; } diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index 9930ac9f0a9..0998cc62dbb 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -6,6 +6,7 @@ #include "library/coverart.h" #include "library/ui_dlgtrackinfo.h" +#include "preferences/usersettings.h" #include "track/beats.h" #include "track/keys.h" #include "track/track_decl.h" @@ -27,6 +28,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { public: // TODO: Remove dependency on TrackModel explicit DlgTrackInfo( + UserSettingsPointer pUserSettings, const TrackModel* trackModel = nullptr); ~DlgTrackInfo() override = default; @@ -100,6 +102,8 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { void updateTrackMetadataFields(); void updateSpinBpmFromBeats(); + const UserSettingsPointer m_pUserSettings; + const TrackModel* const m_pTrackModel; TrackPointer m_pLoadedTrack; diff --git a/src/library/library_prefs.cpp b/src/library/library_prefs.cpp index 38b6a4d17e1..40d8db69bc2 100644 --- a/src/library/library_prefs.cpp +++ b/src/library/library_prefs.cpp @@ -54,6 +54,11 @@ const ConfigKey mixxx::library::prefs::kSyncTrackMetadataConfigKey = mixxx::library::prefs::kConfigGroup, QStringLiteral("SyncTrackMetadataExport")}; +const ConfigKey mixxx::library::prefs::kResetMissingTagMetadataOnImportConfigKey = + ConfigKey{ + mixxx::library::prefs::kConfigGroup, + QStringLiteral("ResetMissingTagMetadataOnImport")}; + // The naming is unchanged for backward compatibility const ConfigKey mixxx::library::prefs::kSyncSeratoMetadataConfigKey = ConfigKey{ diff --git a/src/library/library_prefs.h b/src/library/library_prefs.h index d79c7c74a42..cf7cbfa6c1f 100644 --- a/src/library/library_prefs.h +++ b/src/library/library_prefs.h @@ -34,7 +34,7 @@ const bool kEditMetadataSelectedClickDefault = false; extern const ConfigKey kSyncTrackMetadataConfigKey; -extern const ConfigKey kSyncSeratoMetadataConfigKey; +extern const ConfigKey kResetMissingTagMetadataOnImportConfigKey; extern const ConfigKey kSyncSeratoMetadataConfigKey; diff --git a/src/sources/metadatasource.h b/src/sources/metadatasource.h index 900a6b07ffe..8f76e55af42 100644 --- a/src/sources/metadatasource.h +++ b/src/sources/metadatasource.h @@ -31,14 +31,20 @@ class MetadataSource { Unavailable, }; - // Read both track metadata and cover art at once, because this - // is the most common use case. Both pointers are output parameters - // and might be passed a nullptr if their result is not needed. - // If no metadata is available for a track then the source should - // return Unavailable as this default implementation does. + /// Read both track metadata and cover art at once, because this + /// is the most common use case. Both pointers are output parameters + /// and might be passed a nullptr if their result is not needed. + /// If no metadata is available for a track then the source should + /// return Unavailable as this default implementation does. + /// The flag resetMissingTagMetadata controls if existing metadata + /// should be discarded if the corresponding file tags are missing. virtual std::pair importTrackMetadataAndCoverImage( - TrackMetadata* /*pTrackMetadata*/, - QImage* /*pCoverImage*/) const { + TrackMetadata* pTrackMetadata, + QImage* pCoverImage, + bool resetMissingTagMetadata) const { + Q_UNUSED(pTrackMetadata) + Q_UNUSED(pCoverImage) + Q_UNUSED(resetMissingTagMetadata) return std::make_pair(ImportResult::Unavailable, QDateTime()); } diff --git a/src/sources/metadatasourcetaglib.cpp b/src/sources/metadatasourcetaglib.cpp index bf096ca3e27..bd572347242 100644 --- a/src/sources/metadatasourcetaglib.cpp +++ b/src/sources/metadatasourcetaglib.cpp @@ -105,7 +105,8 @@ MetadataSourceTagLib::afterExport(ExportResult exportResult) const { std::pair MetadataSourceTagLib::importTrackMetadataAndCoverImage( TrackMetadata* pTrackMetadata, - QImage* pCoverImage) const { + QImage* pCoverImage, + bool resetMissingTagMetadata) const { VERIFY_OR_DEBUG_ASSERT(pTrackMetadata || pCoverImage) { kLogger.warning() << "Nothing to import" @@ -136,13 +137,14 @@ MetadataSourceTagLib::importTrackMetadataAndCoverImage( if (taglib::hasID3v2Tag(file)) { const TagLib::ID3v2::Tag* pTag = file.ID3v2Tag(); DEBUG_ASSERT(pTag); - taglib::id3v2::importTrackMetadataFromTag(pTrackMetadata, *pTag); + taglib::id3v2::importTrackMetadataFromTag( + pTrackMetadata, *pTag, resetMissingTagMetadata); taglib::id3v2::importCoverImageFromTag(pCoverImage, *pTag); return afterImport(ImportResult::Succeeded); } else if (taglib::hasAPETag(file)) { const TagLib::APE::Tag* pTag = file.APETag(); DEBUG_ASSERT(pTag); - taglib::ape::importTrackMetadataFromTag(pTrackMetadata, *pTag); + taglib::ape::importTrackMetadataFromTag(pTrackMetadata, *pTag, resetMissingTagMetadata); taglib::ape::importCoverImageFromTag(pCoverImage, *pTag); return afterImport(ImportResult::Succeeded); } else if (taglib::hasID3v1Tag(file)) { @@ -166,7 +168,7 @@ MetadataSourceTagLib::importTrackMetadataAndCoverImage( if (taglib::hasMP4Tag(file)) { const TagLib::MP4::Tag* pTag = file.tag(); DEBUG_ASSERT(pTag); - taglib::mp4::importTrackMetadataFromTag(pTrackMetadata, *pTag); + taglib::mp4::importTrackMetadataFromTag(pTrackMetadata, *pTag, resetMissingTagMetadata); taglib::mp4::importCoverImageFromTag(pCoverImage, *pTag); return afterImport(ImportResult::Succeeded); } @@ -183,13 +185,17 @@ MetadataSourceTagLib::importTrackMetadataAndCoverImage( if (taglib::hasXiphComment(file)) { TagLib::Ogg::XiphComment* pTag = file.xiphComment(); DEBUG_ASSERT(pTag); - taglib::xiph::importTrackMetadataFromTag(pTrackMetadata, *pTag, taglib::FileType::FLAC); + taglib::xiph::importTrackMetadataFromTag(pTrackMetadata, + *pTag, + taglib::FileType::FLAC, + resetMissingTagMetadata); coverImageImported = taglib::xiph::importCoverImageFromTag(pCoverImage, *pTag); importSucceeded = true; } else if (taglib::hasID3v2Tag(file)) { const TagLib::ID3v2::Tag* pTag = file.ID3v2Tag(); DEBUG_ASSERT(pTag); - taglib::id3v2::importTrackMetadataFromTag(pTrackMetadata, *pTag); + taglib::id3v2::importTrackMetadataFromTag( + pTrackMetadata, *pTag, resetMissingTagMetadata); coverImageImported = taglib::id3v2::importCoverImageFromTag(pCoverImage, *pTag); importSucceeded = true; } @@ -216,7 +222,10 @@ MetadataSourceTagLib::importTrackMetadataAndCoverImage( } TagLib::Ogg::XiphComment* pTag = file.tag(); if (pTag) { - taglib::xiph::importTrackMetadataFromTag(pTrackMetadata, *pTag, taglib::FileType::OGG); + taglib::xiph::importTrackMetadataFromTag(pTrackMetadata, + *pTag, + taglib::FileType::OGG, + resetMissingTagMetadata); taglib::xiph::importCoverImageFromTag(pCoverImage, *pTag); return afterImport(ImportResult::Succeeded); } @@ -229,7 +238,10 @@ MetadataSourceTagLib::importTrackMetadataAndCoverImage( } TagLib::Ogg::XiphComment* pTag = file.tag(); if (pTag) { - taglib::xiph::importTrackMetadataFromTag(pTrackMetadata, *pTag, taglib::FileType::OPUS); + taglib::xiph::importTrackMetadataFromTag(pTrackMetadata, + *pTag, + taglib::FileType::OPUS, + resetMissingTagMetadata); taglib::xiph::importCoverImageFromTag(pCoverImage, *pTag); return afterImport(ImportResult::Succeeded); } @@ -243,7 +255,7 @@ MetadataSourceTagLib::importTrackMetadataAndCoverImage( if (taglib::hasAPETag(file)) { const TagLib::APE::Tag* pTag = file.APETag(); DEBUG_ASSERT(pTag); - taglib::ape::importTrackMetadataFromTag(pTrackMetadata, *pTag); + taglib::ape::importTrackMetadataFromTag(pTrackMetadata, *pTag, resetMissingTagMetadata); taglib::ape::importCoverImageFromTag(pCoverImage, *pTag); return afterImport(ImportResult::Succeeded); } @@ -257,7 +269,8 @@ MetadataSourceTagLib::importTrackMetadataAndCoverImage( if (taglib::hasID3v2Tag(file)) { const TagLib::ID3v2::Tag* pTag = file.ID3v2Tag(); DEBUG_ASSERT(pTag); - taglib::id3v2::importTrackMetadataFromTag(pTrackMetadata, *pTag); + taglib::id3v2::importTrackMetadataFromTag( + pTrackMetadata, *pTag, resetMissingTagMetadata); taglib::id3v2::importCoverImageFromTag(pCoverImage, *pTag); return afterImport(ImportResult::Succeeded); } else if (file.hasInfoTag()) { @@ -276,7 +289,8 @@ MetadataSourceTagLib::importTrackMetadataAndCoverImage( if (taglib::hasID3v2Tag(file)) { const TagLib::ID3v2::Tag* pTag = file.tag(); DEBUG_ASSERT(pTag); - taglib::id3v2::importTrackMetadataFromTag(pTrackMetadata, *pTag); + taglib::id3v2::importTrackMetadataFromTag( + pTrackMetadata, *pTag, resetMissingTagMetadata); taglib::id3v2::importCoverImageFromTag(pCoverImage, *pTag); return afterImport(ImportResult::Succeeded); } else if (file.importTrackMetadataFromTextChunks(pTrackMetadata)) { diff --git a/src/sources/metadatasourcetaglib.h b/src/sources/metadatasourcetaglib.h index ee7b92aaa3c..22a1a6a37ca 100644 --- a/src/sources/metadatasourcetaglib.h +++ b/src/sources/metadatasourcetaglib.h @@ -23,7 +23,8 @@ class MetadataSourceTagLib : public MetadataSource { std::pair importTrackMetadataAndCoverImage( TrackMetadata* pTrackMetadata, - QImage* pCoverArt) const override; + QImage* pCoverArt, + bool resetMissingTagMetadata) const override; std::pair exportTrackMetadata( const TrackMetadata& trackMetadata) const override; diff --git a/src/sources/soundsourcemodplug.cpp b/src/sources/soundsourcemodplug.cpp index ac76b480d34..92229a146c1 100644 --- a/src/sources/soundsourcemodplug.cpp +++ b/src/sources/soundsourcemodplug.cpp @@ -82,7 +82,8 @@ SoundSourceModPlug::~SoundSourceModPlug() { std::pair SoundSourceModPlug::importTrackMetadataAndCoverImage( TrackMetadata* pTrackMetadata, - QImage* pCoverArt) const { + QImage* pCoverArt, + bool resetMissingTagMetadata) const { if (pTrackMetadata != nullptr) { QFile modFile(getLocalFileName()); modFile.open(QIODevice::ReadOnly); @@ -111,7 +112,8 @@ SoundSourceModPlug::importTrackMetadataAndCoverImage( // The modplug library currently does not support reading cover-art from // modplug files -- kain88 (Oct 2014) - return MetadataSourceTagLib::importTrackMetadataAndCoverImage(nullptr, pCoverArt); + return MetadataSourceTagLib::importTrackMetadataAndCoverImage( + nullptr, pCoverArt, resetMissingTagMetadata); } SoundSource::OpenResult SoundSourceModPlug::tryOpen( diff --git a/src/sources/soundsourcemodplug.h b/src/sources/soundsourcemodplug.h index 02ea7810a7b..61071e26a03 100644 --- a/src/sources/soundsourcemodplug.h +++ b/src/sources/soundsourcemodplug.h @@ -28,7 +28,8 @@ class SoundSourceModPlug final : public SoundSource { std::pair importTrackMetadataAndCoverImage( TrackMetadata* pTrackMetadata, - QImage* pCoverArt) const override; + QImage* pCoverArt, + bool resetMissingTagMetadata) const override; void close() override; diff --git a/src/sources/soundsourceproxy.cpp b/src/sources/soundsourceproxy.cpp index 58c4933b615..460da5d43d5 100644 --- a/src/sources/soundsourceproxy.cpp +++ b/src/sources/soundsourceproxy.cpp @@ -545,7 +545,8 @@ std::pair SoundSourceProxy::importTrackMetadataAndCoverImageFromFile( mixxx::FileAccess trackFileAccess, mixxx::TrackMetadata* pTrackMetadata, - QImage* pCoverImage) { + QImage* pCoverImage, + bool resetMissingTagMetadata) { if (!trackFileAccess.info().checkFileExists()) { // Silently ignore missing files to avoid spaming the log: // https://bugs.launchpad.net/mixxx/+bug/1875237 @@ -567,13 +568,15 @@ SoundSourceProxy::importTrackMetadataAndCoverImageFromFile( } return SoundSourceProxy(pTrack).importTrackMetadataAndCoverImage( pTrackMetadata, - pCoverImage); + pCoverImage, + resetMissingTagMetadata); } std::pair SoundSourceProxy::importTrackMetadataAndCoverImage( mixxx::TrackMetadata* pTrackMetadata, - QImage* pCoverImage) const { + QImage* pCoverImage, + bool resetMissingTagMetadata) const { if (!m_pSoundSource) { // The file doesn't seem to be readable or the file format // is not supported. @@ -581,7 +584,8 @@ SoundSourceProxy::importTrackMetadataAndCoverImage( } return m_pSoundSource->importTrackMetadataAndCoverImage( pTrackMetadata, - pCoverImage); + pCoverImage, + resetMissingTagMetadata); } namespace { @@ -688,7 +692,8 @@ SoundSourceProxy::UpdateTrackFromSourceResult SoundSourceProxy::updateTrackFromS auto [metadataImportResult, sourceSynchronizedAt] = importTrackMetadataAndCoverImage( &trackMetadata, - pCoverImg); + pCoverImg, + syncParams.resetMissingTagMetadataOnImport); VERIFY_OR_DEBUG_ASSERT(!sourceSynchronizedAt.isValid() || sourceSynchronizedAt.timeSpec() == Qt::UTC) { qWarning() << "Converting source synchronization time to UTC:" << sourceSynchronizedAt; diff --git a/src/sources/soundsourceproxy.h b/src/sources/soundsourceproxy.h index 834198a8742..fc6c83ba0c2 100644 --- a/src/sources/soundsourceproxy.h +++ b/src/sources/soundsourceproxy.h @@ -102,7 +102,8 @@ class SoundSourceProxy { importTrackMetadataAndCoverImageFromFile( mixxx::FileAccess trackFileAccess, mixxx::TrackMetadata* pTrackMetadata, - QImage* pCoverImage); + QImage* pCoverImage, + bool resetMissingTagMetadata); /// Import both track metadata and/or the cover image of the /// captured track object from the corresponding file. @@ -117,7 +118,8 @@ class SoundSourceProxy { std::pair importTrackMetadataAndCoverImage( mixxx::TrackMetadata* pTrackMetadata, - QImage* pCoverImage) const; + QImage* pCoverImage, + bool resetMissingTagMetadata) const; /// Controls which (metadata/coverart) and how tags are (re-)imported from /// audio files when creating a SoundSourceProxy. diff --git a/src/test/coverartcache_test.cpp b/src/test/coverartcache_test.cpp index 88cebe0f84b..52d75b32771 100644 --- a/src/test/coverartcache_test.cpp +++ b/src/test/coverartcache_test.cpp @@ -13,10 +13,13 @@ class CoverArtCacheTest : public LibraryTest, public CoverArtCache { protected: void loadCoverFromMetadata(const QString& trackLocation) { QImage img; + // Both resetMissingTagMetadata = false/true have the same effect + constexpr auto resetMissingTagMetadata = false; SoundSourceProxy::importTrackMetadataAndCoverImageFromFile( mixxx::FileAccess(mixxx::FileInfo(trackLocation)), nullptr, - &img); + &img, + resetMissingTagMetadata); ASSERT_FALSE(img.isNull()); CoverInfo info; diff --git a/src/test/metadatatest.cpp b/src/test/metadatatest.cpp index 0b8f082b592..71ea50ff9ef 100644 --- a/src/test/metadatatest.cpp +++ b/src/test/metadatatest.cpp @@ -46,7 +46,10 @@ class MetadataTest : public testing::Test { pFrame.release(); mixxx::TrackMetadata trackMetadata; - mixxx::taglib::id3v2::importTrackMetadataFromTag(&trackMetadata, tag); + // Both resetMissingTagMetadata = false/true have the same effect + constexpr auto resetMissingTagMetadata = false; + mixxx::taglib::id3v2::importTrackMetadataFromTag( + &trackMetadata, tag, resetMissingTagMetadata); EXPECT_DOUBLE_EQ(expectedValue, trackMetadata.getTrackInfo().getBpm().value()); } @@ -128,7 +131,10 @@ TEST_F(MetadataTest, ID3v2Year) { mixxx::taglib::id3v2::exportTrackMetadataIntoTag(&tag, trackMetadata); } mixxx::TrackMetadata trackMetadata; - mixxx::taglib::id3v2::importTrackMetadataFromTag(&trackMetadata, tag); + // Both resetMissingTagMetadata = false/true have the same effect + constexpr auto resetMissingTagMetadata = false; + mixxx::taglib::id3v2::importTrackMetadataFromTag( + &trackMetadata, tag, resetMissingTagMetadata); if (4 > majorVersion) { // ID3v2.3.0: parsed + formatted const QString actualYear(trackMetadata.getTrackInfo().getYear()); diff --git a/src/test/soundproxy_test.cpp b/src/test/soundproxy_test.cpp index c5b87fee971..e67d1061dd5 100644 --- a/src/test/soundproxy_test.cpp +++ b/src/test/soundproxy_test.cpp @@ -290,8 +290,12 @@ TEST_F(SoundSourceProxyTest, TOAL_TPE2) { getTestDir().filePath(QStringLiteral("id3-test-data/TOAL_TPE2.mp3"))); SoundSourceProxy proxy(pTrack); mixxx::TrackMetadata trackMetadata; + // Both resetMissingTagMetadata = false/true have the same effect + constexpr auto resetMissingTagMetadata = false; EXPECT_EQ(mixxx::MetadataSource::ImportResult::Succeeded, - proxy.importTrackMetadataAndCoverImage(&trackMetadata, nullptr).first); + proxy.importTrackMetadataAndCoverImage( + &trackMetadata, nullptr, resetMissingTagMetadata) + .first); EXPECT_EQ("TITLE2", trackMetadata.getTrackInfo().getArtist()); EXPECT_EQ("ARTIST", trackMetadata.getAlbumInfo().getTitle()); EXPECT_EQ("TITLE", trackMetadata.getAlbumInfo().getArtist()); diff --git a/src/test/synctrackmetadatatest.cpp b/src/test/synctrackmetadatatest.cpp index 463a287b23b..ae3880f1d0f 100644 --- a/src/test/synctrackmetadatatest.cpp +++ b/src/test/synctrackmetadatatest.cpp @@ -291,9 +291,12 @@ class SyncTrackMetadataTest : public LibraryTest { // Reimport metadata from the file mixxx::TrackMetadata importedTrackMetadata; + // TODO: Test both use cases, i.e. also with resetMissingTagMetadata = true. + // Currently this option is disabled and not configurable in the UI. + constexpr auto resetMissingTagMetadata = false; auto [importResult, sourceSynchronizedAt] = SoundSourceProxy(pTrack).importTrackMetadataAndCoverImage( - &importedTrackMetadata, nullptr); + &importedTrackMetadata, nullptr, resetMissingTagMetadata); EXPECT_EQ(expectedImportResult, importResult); if (syncTrackMetadata) { diff --git a/src/track/taglib/trackmetadata_ape.cpp b/src/track/taglib/trackmetadata_ape.cpp index c77885ce6cc..84937c4bfea 100644 --- a/src/track/taglib/trackmetadata_ape.cpp +++ b/src/track/taglib/trackmetadata_ape.cpp @@ -79,7 +79,10 @@ bool importCoverImageFromTag(QImage* pCoverArt, const TagLib::APE::Tag& tag) { return false; } -void importTrackMetadataFromTag(TrackMetadata* pTrackMetadata, const TagLib::APE::Tag& tag) { +void importTrackMetadataFromTag( + TrackMetadata* pTrackMetadata, + const TagLib::APE::Tag& tag, + bool resetMissingTagMetadata) { if (!pTrackMetadata) { return; // nothing to do } @@ -97,19 +100,22 @@ void importTrackMetadataFromTag(TrackMetadata* pTrackMetadata, const TagLib::APE QString albumArtist; if (readItem(tag, "Album Artist", &albumArtist) || readItem(tag, "ALBUM ARTIST", &albumArtist) || - readItem(tag, "ALBUMARTIST", &albumArtist)) { + readItem(tag, "ALBUMARTIST", &albumArtist) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setArtist(albumArtist); } QString composer; if (readItem(tag, "Composer", &composer) || - readItem(tag, "COMPOSER", &composer)) { + readItem(tag, "COMPOSER", &composer) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setComposer(composer); } QString grouping; if (readItem(tag, "Grouping", &grouping) || - readItem(tag, "GROUPING", &grouping)) { + readItem(tag, "GROUPING", &grouping) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setGrouping(grouping); } @@ -119,7 +125,8 @@ void importTrackMetadataFromTag(TrackMetadata* pTrackMetadata, const TagLib::APE // https://picard.musicbrainz.org/docs/mappings QString year; if (readItem(tag, "Year", &year) || - readItem(tag, "YEAR", &year)) { + readItem(tag, "YEAR", &year) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setYear(year); } @@ -133,6 +140,9 @@ void importTrackMetadataFromTag(TrackMetadata* pTrackMetadata, const TagLib::APE &trackTotal); pTrackMetadata->refTrackInfo().setTrackNumber(trackNumber); pTrackMetadata->refTrackInfo().setTrackTotal(trackTotal); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setTrackNumber(QString{}); + pTrackMetadata->refTrackInfo().setTrackTotal(QString{}); } #if defined(__EXTRA_METADATA__) @@ -146,120 +156,135 @@ void importTrackMetadataFromTag(TrackMetadata* pTrackMetadata, const TagLib::APE &discTotal); pTrackMetadata->refTrackInfo().setDiscNumber(discNumber); pTrackMetadata->refTrackInfo().setDiscTotal(discTotal); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setDiscNumber(QString{}); + pTrackMetadata->refTrackInfo().setDiscTotal(QString{}); } #endif // __EXTRA_METADATA__ QString bpm; - if (readItem(tag, "BPM", &bpm)) { - parseBpm(pTrackMetadata, bpm); + if (readItem(tag, "BPM", &bpm) || resetMissingTagMetadata) { + parseBpm(pTrackMetadata, bpm, resetMissingTagMetadata); } QString trackGain; - if (readItem(tag, "REPLAYGAIN_TRACK_GAIN", &trackGain)) { - parseTrackGain(pTrackMetadata, trackGain); + if (readItem(tag, "REPLAYGAIN_TRACK_GAIN", &trackGain) || resetMissingTagMetadata) { + parseTrackGain(pTrackMetadata, trackGain, resetMissingTagMetadata); } QString trackPeak; - if (readItem(tag, "REPLAYGAIN_TRACK_PEAK", &trackPeak)) { - parseTrackPeak(pTrackMetadata, trackPeak); + if (readItem(tag, "REPLAYGAIN_TRACK_PEAK", &trackPeak) || resetMissingTagMetadata) { + parseTrackPeak(pTrackMetadata, trackPeak, resetMissingTagMetadata); } #if defined(__EXTRA_METADATA__) QString albumGain; - if (readItem(tag, "REPLAYGAIN_ALBUM_GAIN", &albumGain)) { - parseTrackGain(pTrackMetadata, albumGain); + if (readItem(tag, "REPLAYGAIN_ALBUM_GAIN", &albumGain) || resetMissingTagMetadata) { + parseTrackGain(pTrackMetadata, albumGain, resetMissingTagMetadata); } QString albumPeak; - if (readItem(tag, "REPLAYGAIN_ALBUM_PEAK", &albumPeak)) { - parseAlbumPeak(pTrackMetadata, albumPeak); + if (readItem(tag, "REPLAYGAIN_ALBUM_PEAK", &albumPeak) || resetMissingTagMetadata) { + parseAlbumPeak(pTrackMetadata, albumPeak, resetMissingTagMetadata); } QString trackArtistId; - if (readItem(tag, "MUSICBRAINZ_ARTISTID", &trackArtistId)) { + if (readItem(tag, "MUSICBRAINZ_ARTISTID", &trackArtistId) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzArtistId(QUuid(trackArtistId)); } QString trackRecordingId; - if (readItem(tag, "MUSICBRAINZ_TRACKID", &trackRecordingId)) { + if (readItem(tag, "MUSICBRAINZ_TRACKID", &trackRecordingId) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzRecordingId(QUuid(trackRecordingId)); } QString trackReleaseId; - if (readItem(tag, "MUSICBRAINZ_RELEASETRACKID", &trackReleaseId)) { + if (readItem(tag, "MUSICBRAINZ_RELEASETRACKID", &trackReleaseId) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzReleaseId(QUuid(trackReleaseId)); } QString trackWorkId; - if (readItem(tag, "MUSICBRAINZ_WORKID", &trackWorkId)) { + if (readItem(tag, "MUSICBRAINZ_WORKID", &trackWorkId) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzWorkId(QUuid(trackWorkId)); } QString albumArtistId; - if (readItem(tag, "MUSICBRAINZ_ALBUMARTISTID", &albumArtistId)) { + if (readItem(tag, "MUSICBRAINZ_ALBUMARTISTID", &albumArtistId) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzArtistId(QUuid(albumArtistId)); } QString albumReleaseId; - if (readItem(tag, "MUSICBRAINZ_ALBUMID", &albumReleaseId)) { + if (readItem(tag, "MUSICBRAINZ_ALBUMID", &albumReleaseId) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzReleaseId(QUuid(albumReleaseId)); } QString albumReleaseGroupId; - if (readItem(tag, "MUSICBRAINZ_RELEASEGROUPID", &albumReleaseGroupId)) { + if (readItem(tag, "MUSICBRAINZ_RELEASEGROUPID", &albumReleaseGroupId) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzReleaseGroupId(QUuid(albumReleaseGroupId)); } QString conductor; if (readItem(tag, "Conductor", &conductor) || - readItem(tag, "CONDUCTOR", &conductor)) { + readItem(tag, "CONDUCTOR", &conductor) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setConductor(conductor); } QString isrc; - if (readItem(tag, "ISRC", &isrc)) { + if (readItem(tag, "ISRC", &isrc) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setISRC(isrc); } QString language; if (readItem(tag, "Language", &language) || - readItem(tag, "LANGUAGE", &language)) { + readItem(tag, "LANGUAGE", &language) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setLanguage(language); } QString lyricist; if (readItem(tag, "Lyricist", &lyricist) || - readItem(tag, "LYRICIST", &lyricist)) { + readItem(tag, "LYRICIST", &lyricist) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setLyricist(lyricist); } QString mood; if (readItem(tag, "Mood", &mood) || - readItem(tag, "MOOD", &mood)) { + readItem(tag, "MOOD", &mood) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMood(mood); } QString remixer; if (readItem(tag, "MixArtist", &remixer) || readItem(tag, "MIXARTIST", &remixer) || - readItem(tag, "REMIXER", &remixer)) { + readItem(tag, "REMIXER", &remixer) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setRemixer(remixer); } QString copyright; if (readItem(tag, "Copyright", ©right) || - readItem(tag, "COPYRIGHT", ©right)) { + readItem(tag, "COPYRIGHT", ©right) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setCopyright(copyright); } QString license; if (readItem(tag, "License", &license) || - readItem(tag, "LICENSE", &license)) { + readItem(tag, "LICENSE", &license) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setLicense(license); } QString recordLabel; if (readItem(tag, "Label", &recordLabel) || - readItem(tag, "LABEL", &recordLabel)) { + readItem(tag, "LABEL", &recordLabel) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setRecordLabel(recordLabel); } QString subtitle; if (readItem(tag, "Subtitle", &subtitle) || - readItem(tag, "SUBTITLE", &subtitle)) { + readItem(tag, "SUBTITLE", &subtitle) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setSubtitle(subtitle); } QString encoder; if (readItem(tag, "EncodedBy", &encoder) || - readItem(tag, "ENCODEDBY", &encoder)) { + readItem(tag, "ENCODEDBY", &encoder) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setEncoder(encoder); } QString encoderSettings; if (readItem(tag, "EncoderSettings", &encoderSettings) || - readItem(tag, "ENCODERSETTINGS", &encoderSettings)) { + readItem(tag, "ENCODERSETTINGS", &encoderSettings) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setEncoderSettings(encoderSettings); } #endif // __EXTRA_METADATA__ diff --git a/src/track/taglib/trackmetadata_ape.h b/src/track/taglib/trackmetadata_ape.h index b1caa9d6df5..6f1db1d1e8c 100644 --- a/src/track/taglib/trackmetadata_ape.h +++ b/src/track/taglib/trackmetadata_ape.h @@ -12,7 +12,8 @@ namespace ape { void importTrackMetadataFromTag( TrackMetadata* pTrackMetadata, - const TagLib::APE::Tag& tag); + const TagLib::APE::Tag& tag, + bool resetMissingTagMetadata); bool importCoverImageFromTag( QImage* pCoverArt, diff --git a/src/track/taglib/trackmetadata_common.cpp b/src/track/taglib/trackmetadata_common.cpp index defb7247d68..d3f504201e0 100644 --- a/src/track/taglib/trackmetadata_common.cpp +++ b/src/track/taglib/trackmetadata_common.cpp @@ -14,13 +14,16 @@ namespace { Logger kLogger("TagLib"); bool parseReplayGainGain( - ReplayGain* pReplayGain, - const QString& dbGain) { - DEBUG_ASSERT(pReplayGain); - - bool isRatioValid = false; - double ratio = ReplayGain::ratioFromString(dbGain, &isRatioValid); - if (isRatioValid) { + gsl::not_null pReplayGain, + const QString& dbGain, + bool resetIfEmpty) { + if (resetIfEmpty && dbGain.trimmed().isEmpty()) { + pReplayGain->resetRatio(); + return true; + } + bool isValid = false; + double ratio = ReplayGain::ratioFromString(dbGain, &isValid); + if (isValid) { // Some applications (e.g. Rapid Evolution 3) write a replay gain // of 0 dB even if the replay gain is undefined. To be safe we // ignore this special value and instead prefer to recalculate @@ -32,20 +35,23 @@ bool parseReplayGainGain( } pReplayGain->setRatio(ratio); } - return isRatioValid; + return isValid; } bool parseReplayGainPeak( - ReplayGain* pReplayGain, - const QString& strPeak) { - DEBUG_ASSERT(pReplayGain); - - bool isPeakValid = false; - const CSAMPLE peak = ReplayGain::peakFromString(strPeak, &isPeakValid); - if (isPeakValid) { + gsl::not_null pReplayGain, + const QString& strPeak, + bool resetIfEmpty) { + if (resetIfEmpty && strPeak.trimmed().isEmpty()) { + pReplayGain->resetPeak(); + return true; + } + bool isValid = false; + const CSAMPLE peak = ReplayGain::peakFromString(strPeak, &isValid); + if (isValid) { pReplayGain->setPeak(peak); } - return isPeakValid; + return isValid; } } // anonymous namespace @@ -85,8 +91,13 @@ TagLib::String firstNonEmptyStringListItem( bool parseBpm( TrackMetadata* pTrackMetadata, - const QString& sBpm) { + const QString& sBpm, + bool resetIfEmpty) { DEBUG_ASSERT(pTrackMetadata); + if (resetIfEmpty && sBpm.trimmed().isEmpty()) { + pTrackMetadata->refTrackInfo().setBpm(Bpm{}); + return true; + } bool isBpmValid = false; const double bpmValue = Bpm::valueFromString(sBpm, &isBpmValid); if (isBpmValid) { @@ -96,56 +107,40 @@ bool parseBpm( } bool parseTrackGain( - TrackMetadata* pTrackMetadata, - const QString& dbGain) { - DEBUG_ASSERT(pTrackMetadata); - - ReplayGain replayGain(pTrackMetadata->getTrackInfo().getReplayGain()); - bool isRatioValid = parseReplayGainGain(&replayGain, dbGain); - if (isRatioValid) { - pTrackMetadata->refTrackInfo().setReplayGain(replayGain); - } - return isRatioValid; + gsl::not_null pTrackMetadata, + const QString& dbGain, + bool resetIfEmpty) { + return parseReplayGainGain(pTrackMetadata->refTrackInfo().ptrReplayGain(), + dbGain, + resetIfEmpty); } bool parseTrackPeak( - TrackMetadata* pTrackMetadata, - const QString& strPeak) { - DEBUG_ASSERT(pTrackMetadata); - - ReplayGain replayGain(pTrackMetadata->getTrackInfo().getReplayGain()); - bool isPeakValid = parseReplayGainPeak(&replayGain, strPeak); - if (isPeakValid) { - pTrackMetadata->refTrackInfo().setReplayGain(replayGain); - } - return isPeakValid; + gsl::not_null pTrackMetadata, + const QString& strPeak, + bool resetIfEmpty) { + return parseReplayGainPeak(pTrackMetadata->refTrackInfo().ptrReplayGain(), + strPeak, + resetIfEmpty); } #if defined(__EXTRA_METADATA__) bool parseAlbumGain( - TrackMetadata* pTrackMetadata, - const QString& dbGain) { - DEBUG_ASSERT(pTrackMetadata); - - ReplayGain replayGain(pTrackMetadata->getAlbumInfo().getReplayGain()); - bool isRatioValid = parseReplayGainGain(&replayGain, dbGain); - if (isRatioValid) { - pTrackMetadata->refAlbumInfo().setReplayGain(replayGain); - } - return isRatioValid; + gsl::not_null pTrackMetadata, + const QString& dbGain, + bool resetIfEmpty) { + return parseReplayGainGain(pTrackMetadata->refAlbumInfo().ptrReplayGain(), + dbGain, + resetIfEmpty); } bool parseAlbumPeak( - TrackMetadata* pTrackMetadata, - const QString& strPeak) { - DEBUG_ASSERT(pTrackMetadata); - - ReplayGain replayGain(pTrackMetadata->getAlbumInfo().getReplayGain()); - bool isPeakValid = parseReplayGainPeak(&replayGain, strPeak); - if (isPeakValid) { - pTrackMetadata->refAlbumInfo().setReplayGain(replayGain); - } - return isPeakValid; + gsl::not_null pTrackMetadata, + const QString& strPeak, + bool resetIfEmpty) { + return parseReplayGainPeak(pTrackMetadata->refAlbumInfo().ptrReplayGain(), + strPeak, + resetIfEmpty); } #endif // __EXTRA_METADATA__ diff --git a/src/track/taglib/trackmetadata_common.h b/src/track/taglib/trackmetadata_common.h index fcda5473296..12366988fc6 100644 --- a/src/track/taglib/trackmetadata_common.h +++ b/src/track/taglib/trackmetadata_common.h @@ -7,6 +7,7 @@ #include #include #include +#include #if defined(__EXTRA_METADATA__) #include "util/quuid.h" @@ -71,7 +72,8 @@ inline QString formatBpm( bool parseBpm( TrackMetadata* pTrackMetadata, - const QString& sBpm); + const QString& sBpm, + bool resetIfEmpty); inline QString formatReplayGainGain( const ReplayGain& replayGain) { @@ -90,8 +92,9 @@ inline QString formatTrackGain( } bool parseTrackGain( - TrackMetadata* pTrackMetadata, - const QString& dbGain); + gsl::not_null pTrackMetadata, + const QString& dbGain, + bool resetIfEmpty); inline QString formatTrackPeak( const TrackMetadata& trackMetadata) { @@ -100,8 +103,9 @@ inline QString formatTrackPeak( } bool parseTrackPeak( - TrackMetadata* pTrackMetadata, - const QString& strPeak); + gsl::not_null pTrackMetadata, + const QString& strPeak, + bool resetIfEmpty); #if defined(__EXTRA_METADATA__) inline QString formatAlbumGain( @@ -110,8 +114,9 @@ inline QString formatAlbumGain( } bool parseAlbumGain( - TrackMetadata* pTrackMetadata, - const QString& dbGain); + gsl::not_null pTrackMetadata, + const QString& dbGain, + bool resetIfEmpty); inline QString formatAlbumPeak( const TrackMetadata& trackMetadata) { @@ -119,8 +124,9 @@ inline QString formatAlbumPeak( } bool parseAlbumPeak( - TrackMetadata* pTrackMetadata, - const QString& strPeak); + gsl::not_null pTrackMetadata, + const QString& strPeak, + bool resetIfEmpty); #endif // __EXTRA_METADATA__ bool parseSeratoBeatGrid( diff --git a/src/track/taglib/trackmetadata_id3v2.cpp b/src/track/taglib/trackmetadata_id3v2.cpp index 6471662cc64..c837376a5e7 100644 --- a/src/track/taglib/trackmetadata_id3v2.cpp +++ b/src/track/taglib/trackmetadata_id3v2.cpp @@ -669,7 +669,8 @@ bool importCoverImageFromTag( void importTrackMetadataFromTag( TrackMetadata* pTrackMetadata, - const TagLib::ID3v2::Tag& tag) { + const TagLib::ID3v2::Tag& tag, + bool resetMissingTagMetadata) { if (!pTrackMetadata) { return; // nothing to do } @@ -711,13 +712,13 @@ void importTrackMetadataFromTag( readFirstUserTextIdentificationFrame( tag, QStringLiteral("COMMENT")); - if (!comment.isNull()) { + if (!comment.isNull() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setComment(comment); } } const TagLib::ID3v2::FrameList albumArtistFrames(tag.frameListMap()["TPE2"]); - if (!albumArtistFrames.isEmpty()) { + if (!albumArtistFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setArtist( firstNonEmptyFrameToQString(albumArtistFrames)); } @@ -733,7 +734,7 @@ void importTrackMetadataFromTag( } const TagLib::ID3v2::FrameList composerFrames(tag.frameListMap()["TCOM"]); - if (!composerFrames.isEmpty()) { + if (!composerFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setComposer( firstNonEmptyFrameToQString(composerFrames)); } @@ -751,16 +752,16 @@ void importTrackMetadataFromTag( // if it ends up in the wrong track properties. // The code must be consistent with the corresponding write function! // FIXME: Revisit this decision before enabling the code. - if (!appleGroupingFrames.isEmpty()) { + if (!appleGroupingFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setGrouping( firstNonEmptyFrameToQString(appleGroupingFrames)); } - if (!traditionalGroupingFrames.isEmpty()) { + if (!traditionalGroupingFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setWork( firstNonEmptyFrameToQString(traditionalGroupingFrames)); } const TagLib::ID3v2::FrameList movementFrames = tag.frameListMap()["MVNM"]; - if (!movementFrames.isEmpty()) { + if (!movementFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMovement( firstNonEmptyFrameToQString(movementFrames)); } @@ -774,7 +775,7 @@ void importTrackMetadataFromTag( const QString traditionalGrouping = firstNonEmptyFrameToQString(traditionalGroupingFrames); if (appleGroupingFrames.isEmpty()) { // Fallback - if (!traditionalGroupingFrames.isEmpty()) { + if (!traditionalGroupingFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setGrouping(traditionalGrouping); } } else { @@ -817,7 +818,7 @@ void importTrackMetadataFromTag( } } } - if (!year.isEmpty()) { + if (!year.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setYear(year); } } @@ -832,6 +833,9 @@ void importTrackMetadataFromTag( &trackTotal); pTrackMetadata->refTrackInfo().setTrackNumber(trackNumber); pTrackMetadata->refTrackInfo().setTrackTotal(trackTotal); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setTrackNumber(QString{}); + pTrackMetadata->refTrackInfo().setTrackTotal(QString{}); } #if defined(__EXTRA_METADATA__) @@ -845,13 +849,17 @@ void importTrackMetadataFromTag( &discTotal); pTrackMetadata->refTrackInfo().setDiscNumber(discNumber); pTrackMetadata->refTrackInfo().setDiscTotal(discTotal); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setDiscNumber(QString{}); + pTrackMetadata->refTrackInfo().setDiscTotal(QString{}); } #endif // __EXTRA_METADATA__ const TagLib::ID3v2::FrameList bpmFrames(tag.frameListMap()["TBPM"]); - if (!bpmFrames.isEmpty()) { + if (!bpmFrames.isEmpty() || resetMissingTagMetadata) { parseBpm(pTrackMetadata, - firstNonEmptyFrameToQString(bpmFrames)); + firstNonEmptyFrameToQString(bpmFrames), + resetMissingTagMetadata); if (pTrackMetadata->getTrackInfo().getBpm().isValid()) { double bpmValue = pTrackMetadata->getTrackInfo().getBpm().value(); // Some software use (or used) to write decimated values without comma, @@ -896,7 +904,7 @@ void importTrackMetadataFromTag( } const TagLib::ID3v2::FrameList keyFrames(tag.frameListMap()["TKEY"]); - if (!keyFrames.isEmpty()) { + if (!keyFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setKey( firstNonEmptyFrameToQString(keyFrames)); } @@ -905,15 +913,15 @@ void importTrackMetadataFromTag( readFirstUserTextIdentificationFrame( tag, QStringLiteral("REPLAYGAIN_TRACK_GAIN")); - if (!trackGain.isEmpty()) { - parseTrackGain(pTrackMetadata, trackGain); + if (!trackGain.isEmpty() || resetMissingTagMetadata) { + parseTrackGain(pTrackMetadata, trackGain, resetMissingTagMetadata); } QString trackPeak = readFirstUserTextIdentificationFrame( tag, QStringLiteral("REPLAYGAIN_TRACK_PEAK")); - if (!trackPeak.isEmpty()) { - parseTrackPeak(pTrackMetadata, trackPeak); + if (!trackPeak.isEmpty() || resetMissingTagMetadata) { + parseTrackPeak(pTrackMetadata, trackPeak, resetMissingTagMetadata); } #if defined(__EXTRA_METADATA__) @@ -921,126 +929,126 @@ void importTrackMetadataFromTag( readFirstUserTextIdentificationFrame( tag, QStringLiteral("REPLAYGAIN_ALBUM_GAIN")); - if (!albumGain.isEmpty()) { - parseAlbumGain(pTrackMetadata, albumGain); + if (!albumGain.isEmpty() || resetMissingTagMetadata) { + parseAlbumGain(pTrackMetadata, albumGain, resetMissingTagMetadata); } QString albumPeak = readFirstUserTextIdentificationFrame( tag, QStringLiteral("REPLAYGAIN_ALBUM_PEAK")); - if (!albumPeak.isEmpty()) { - parseAlbumPeak(pTrackMetadata, albumPeak); + if (!albumPeak.isEmpty() || resetMissingTagMetadata) { + parseAlbumPeak(pTrackMetadata, albumPeak, resetMissingTagMetadata); } QString trackArtistId = readFirstUserTextIdentificationFrame( tag, QStringLiteral("MusicBrainz Artist Id")); - if (!trackArtistId.isNull()) { + if (!trackArtistId.isNull() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzArtistId(QUuid(trackArtistId)); } QByteArray trackRecordingId = readFirstUniqueFileIdentifierFrame( tag, kMusicBrainzOwner); - if (!trackRecordingId.isEmpty()) { + if (!trackRecordingId.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzRecordingId(QUuid(trackRecordingId)); } QString trackReleaseId = readFirstUserTextIdentificationFrame( tag, QStringLiteral("MusicBrainz Release Track Id")); - if (!trackReleaseId.isNull()) { + if (!trackReleaseId.isNull() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzReleaseId(QUuid(trackReleaseId)); } QString trackWorkId = readFirstUserTextIdentificationFrame( tag, QStringLiteral("MusicBrainz Work Id")); - if (!trackWorkId.isNull()) { + if (!trackWorkId.isNull() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzWorkId(QUuid(trackWorkId)); } QString albumArtistId = readFirstUserTextIdentificationFrame( tag, QStringLiteral("MusicBrainz Album Artist Id")); - if (!albumArtistId.isNull()) { + if (!albumArtistId.isNull() || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzArtistId(QUuid(albumArtistId)); } QString albumReleaseId = readFirstUserTextIdentificationFrame( tag, QStringLiteral("MusicBrainz Album Id")); - if (!albumReleaseId.isNull()) { + if (!albumReleaseId.isNull() || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzReleaseId(QUuid(albumReleaseId)); } QString albumReleaseGroupId = readFirstUserTextIdentificationFrame( tag, QStringLiteral("MusicBrainz Release Group Id")); - if (!albumReleaseGroupId.isNull()) { + if (!albumReleaseGroupId.isNull() || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzReleaseGroupId(QUuid(albumReleaseGroupId)); } const TagLib::ID3v2::FrameList conductorFrames(tag.frameListMap()["TPE3"]); - if (!conductorFrames.isEmpty()) { + if (!conductorFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setConductor( firstNonEmptyFrameToQString(conductorFrames)); } const TagLib::ID3v2::FrameList isrcFrames(tag.frameListMap()["TSRC"]); - if (!isrcFrames.isEmpty()) { + if (!isrcFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setISRC( firstNonEmptyFrameToQString(isrcFrames)); } const TagLib::ID3v2::FrameList languageFrames(tag.frameListMap()["TLAN"]); - if (!languageFrames.isEmpty()) { + if (!languageFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setLanguage( firstNonEmptyFrameToQString(languageFrames)); } const TagLib::ID3v2::FrameList lyricistFrames(tag.frameListMap()["TEXT"]); - if (!lyricistFrames.isEmpty()) { + if (!lyricistFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setLyricist( firstNonEmptyFrameToQString(lyricistFrames)); } if (tag.header()->majorVersion() >= 4) { const TagLib::ID3v2::FrameList moodFrames(tag.frameListMap()["TMOO"]); - if (!moodFrames.isEmpty()) { + if (!moodFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMood( firstNonEmptyFrameToQString(moodFrames)); } } const TagLib::ID3v2::FrameList copyrightFrames(tag.frameListMap()["TCOP"]); - if (!copyrightFrames.isEmpty()) { + if (!copyrightFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setCopyright( firstNonEmptyFrameToQString(copyrightFrames)); } const TagLib::ID3v2::FrameList licenseFrames(tag.frameListMap()["WCOP"]); - if (!licenseFrames.isEmpty()) { + if (!licenseFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setLicense( firstNonEmptyFrameToQString(licenseFrames)); } const TagLib::ID3v2::FrameList recordLabelFrames(tag.frameListMap()["TPUB"]); - if (!recordLabelFrames.isEmpty()) { + if (!recordLabelFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setRecordLabel( firstNonEmptyFrameToQString(recordLabelFrames)); } const TagLib::ID3v2::FrameList remixerFrames(tag.frameListMap()["TPE4"]); - if (!remixerFrames.isEmpty()) { + if (!remixerFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setRemixer( firstNonEmptyFrameToQString(remixerFrames)); } const TagLib::ID3v2::FrameList subtitleFrames(tag.frameListMap()["TIT3"]); - if (!subtitleFrames.isEmpty()) { + if (!subtitleFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setSubtitle( firstNonEmptyFrameToQString(subtitleFrames)); } const TagLib::ID3v2::FrameList encoderFrames(tag.frameListMap()["TENC"]); - if (!encoderFrames.isEmpty()) { + if (!encoderFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setEncoder( firstNonEmptyFrameToQString(encoderFrames)); } const TagLib::ID3v2::FrameList encoderSettingsFrames(tag.frameListMap()["TSSE"]); - if (!encoderSettingsFrames.isEmpty()) { + if (!encoderSettingsFrames.isEmpty() || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setEncoderSettings( firstNonEmptyFrameToQString(encoderSettingsFrames)); } diff --git a/src/track/taglib/trackmetadata_id3v2.h b/src/track/taglib/trackmetadata_id3v2.h index 08b675b26e5..ecf3e41c781 100644 --- a/src/track/taglib/trackmetadata_id3v2.h +++ b/src/track/taglib/trackmetadata_id3v2.h @@ -12,7 +12,8 @@ namespace id3v2 { void importTrackMetadataFromTag( TrackMetadata* pTrackMetadata, - const TagLib::ID3v2::Tag& tag); + const TagLib::ID3v2::Tag& tag, + bool resetMissingTagMetadata); bool importCoverImageFromTag( QImage* pCoverArt, diff --git a/src/track/taglib/trackmetadata_mp4.cpp b/src/track/taglib/trackmetadata_mp4.cpp index 4e5b6c111b4..0a69e4de676 100644 --- a/src/track/taglib/trackmetadata_mp4.cpp +++ b/src/track/taglib/trackmetadata_mp4.cpp @@ -122,7 +122,8 @@ bool importCoverImageFromTag( void importTrackMetadataFromTag( TrackMetadata* pTrackMetadata, - const TagLib::MP4::Tag& tag) { + const TagLib::MP4::Tag& tag, + bool resetMissingTagMetadata) { if (!pTrackMetadata) { return; // nothing to do } @@ -132,22 +133,22 @@ void importTrackMetadataFromTag( tag); QString albumArtist; - if (readAtom(tag, "aART", &albumArtist)) { + if (readAtom(tag, "aART", &albumArtist) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setArtist(albumArtist); } QString composer; - if (readAtom(tag, "\251wrt", &composer)) { + if (readAtom(tag, "\251wrt", &composer) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setComposer(composer); } QString grouping; - if (readAtom(tag, "\251grp", &grouping)) { + if (readAtom(tag, "\251grp", &grouping) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setGrouping(grouping); } QString year; - if (readAtom(tag, "\251day", &year)) { + if (readAtom(tag, "\251day", &year) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setYear(year); } @@ -161,6 +162,9 @@ void importTrackMetadataFromTag( trackNumbers.toStrings(&trackNumber, &trackTotal); pTrackMetadata->refTrackInfo().setTrackNumber(trackNumber); pTrackMetadata->refTrackInfo().setTrackTotal(trackTotal); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setTrackNumber(QString{}); + pTrackMetadata->refTrackInfo().setTrackTotal(QString{}); } #if defined(__EXTRA_METADATA__) @@ -174,6 +178,9 @@ void importTrackMetadataFromTag( discNumbers.toStrings(&discNumber, &discTotal); pTrackMetadata->refTrackInfo().setDiscNumber(discNumber); pTrackMetadata->refTrackInfo().setDiscTotal(discTotal); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setDiscNumber(QString{}); + pTrackMetadata->refTrackInfo().setDiscTotal(QString{}); } #endif // __EXTRA_METADATA__ @@ -184,120 +191,150 @@ void importTrackMetadataFromTag( // If this field contains a valid value the integer // BPM value that might have been read before is // overwritten. - parseBpm(pTrackMetadata, bpm); + parseBpm(pTrackMetadata, bpm, resetMissingTagMetadata); } else if (tag.contains("tmpo")) { // Read the BPM as an integer value. const TagLib::MP4::Item tmpoItem = tag.item("tmpo"); double bpmValue = tmpoItem.toInt(); if (Bpm::isValidValue(bpmValue)) { pTrackMetadata->refTrackInfo().setBpm(Bpm(bpmValue)); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setBpm(Bpm{}); } + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setBpm(Bpm{}); } QString key; - if (readAtom(tag, kAtomKeyInitialKey, &key) || // preferred (conforms to MixedInKey, Serato, Traktor) - readAtom(tag, kAtomKeyAlternativeKey, &key)) { // alternative (conforms to Rapid Evolution) + if (readAtom(tag, + kAtomKeyInitialKey, + &key) || // preferred (conforms to MixedInKey, Serato, Traktor) + readAtom(tag, + kAtomKeyAlternativeKey, + &key) || // alternative (conforms to Rapid Evolution) + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setKey(key); } QString trackGain; - if (readAtom(tag, kAtomKeyReplayGainTrackGain, &trackGain)) { - parseTrackGain(pTrackMetadata, trackGain); + if (readAtom(tag, kAtomKeyReplayGainTrackGain, &trackGain) || resetMissingTagMetadata) { + parseTrackGain(pTrackMetadata, trackGain, resetMissingTagMetadata); } QString trackPeak; - if (readAtom(tag, kAtomKeyReplayGainTrackPeak, &trackPeak)) { - parseTrackPeak(pTrackMetadata, trackPeak); + if (readAtom(tag, kAtomKeyReplayGainTrackPeak, &trackPeak) || resetMissingTagMetadata) { + parseTrackPeak(pTrackMetadata, trackPeak, resetMissingTagMetadata); } #if defined(__EXTRA_METADATA__) QString albumGain; - if (readAtom(tag, kAtomKeyReplayGainAlbumGain, &albumGain)) { - parseAlbumGain(pTrackMetadata, albumGain); + if (readAtom(tag, kAtomKeyReplayGainAlbumGain, &albumGain) || resetMissingTagMetadata) { + parseAlbumGain(pTrackMetadata, albumGain, resetMissingTagMetadata); } QString albumPeak; - if (readAtom(tag, kAtomKeyReplayGainAlbumPeak, &albumPeak)) { - parseAlbumPeak(pTrackMetadata, albumPeak); + if (readAtom(tag, kAtomKeyReplayGainAlbumPeak, &albumPeak) || resetMissingTagMetadata) { + parseAlbumPeak(pTrackMetadata, albumPeak, resetMissingTagMetadata); } QString trackArtistId; - if (readAtom(tag, "----:com.apple.iTunes:MusicBrainz Artist Id", &trackArtistId)) { + if (readAtom(tag, + "----:com.apple.iTunes:MusicBrainz Artist Id", + &trackArtistId) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzArtistId(QUuid(trackArtistId)); } QString trackRecordingId; - if (readAtom(tag, "----:com.apple.iTunes:MusicBrainz Track Id", &trackRecordingId)) { + if (readAtom(tag, + "----:com.apple.iTunes:MusicBrainz Track Id", + &trackRecordingId) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzRecordingId(QUuid(trackRecordingId)); } QString trackReleaseId; - if (readAtom(tag, "----:com.apple.iTunes:MusicBrainz Release Track Id", &trackReleaseId)) { + if (readAtom(tag, + "----:com.apple.iTunes:MusicBrainz Release Track Id", + &trackReleaseId) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzReleaseId(QUuid(trackReleaseId)); } QString trackWorkId; - if (readAtom(tag, "----:com.apple.iTunes:MusicBrainz Work Id", &trackWorkId)) { + if (readAtom(tag, + "----:com.apple.iTunes:MusicBrainz Work Id", + &trackWorkId) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzWorkId(QUuid(trackWorkId)); } QString albumArtistId; - if (readAtom(tag, "----:com.apple.iTunes:MusicBrainz Album Artist Id", &albumArtistId)) { + if (readAtom(tag, + "----:com.apple.iTunes:MusicBrainz Album Artist Id", + &albumArtistId) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzArtistId(QUuid(albumArtistId)); } QString albumReleaseId; - if (readAtom(tag, "----:com.apple.iTunes:MusicBrainz Album Id", &albumReleaseId)) { + if (readAtom(tag, + "----:com.apple.iTunes:MusicBrainz Album Id", + &albumReleaseId) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzReleaseId(QUuid(albumReleaseId)); } QString albumReleaseGroupId; - if (readAtom(tag, "----:com.apple.iTunes:MusicBrainz Release Group Id", &albumReleaseGroupId)) { + if (readAtom(tag, + "----:com.apple.iTunes:MusicBrainz Release Group Id", + &albumReleaseGroupId) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzReleaseGroupId(QUuid(albumReleaseGroupId)); } QString conductor; - if (readAtom(tag, "----:com.apple.iTunes:CONDUCTOR", &conductor)) { + if (readAtom(tag, "----:com.apple.iTunes:CONDUCTOR", &conductor) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setConductor(conductor); } QString isrc; - if (readAtom(tag, "----:com.apple.iTunes:ISRC", &isrc)) { + if (readAtom(tag, "----:com.apple.iTunes:ISRC", &isrc) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setISRC(isrc); } QString language; - if (readAtom(tag, "----:com.apple.iTunes:LANGUAGE", &language)) { + if (readAtom(tag, "----:com.apple.iTunes:LANGUAGE", &language) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setLanguage(language); } QString lyricist; - if (readAtom(tag, "----:com.apple.iTunes:LYRICIST", &lyricist)) { + if (readAtom(tag, "----:com.apple.iTunes:LYRICIST", &lyricist) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setLyricist(lyricist); } QString mood; - if (readAtom(tag, "----:com.apple.iTunes:MOOD", &mood)) { + if (readAtom(tag, "----:com.apple.iTunes:MOOD", &mood) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMood(mood); } QString copyright; - if (readAtom(tag, "cprt", ©right)) { + if (readAtom(tag, "cprt", ©right) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setCopyright(copyright); } QString license; - if (readAtom(tag, "----:com.apple.iTunes:LICENSE", &license)) { + if (readAtom(tag, "----:com.apple.iTunes:LICENSE", &license) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setLicense(license); } QString recordLabel; - if (readAtom(tag, "----:com.apple.iTunes:LABEL", &recordLabel)) { + if (readAtom(tag, "----:com.apple.iTunes:LABEL", &recordLabel) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setRecordLabel(recordLabel); } QString remixer; - if (readAtom(tag, "----:com.apple.iTunes:REMIXER", &remixer)) { + if (readAtom(tag, "----:com.apple.iTunes:REMIXER", &remixer) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setRemixer(remixer); } QString subtitle; - if (readAtom(tag, "----:com.apple.iTunes:SUBTITLE", &subtitle)) { + if (readAtom(tag, "----:com.apple.iTunes:SUBTITLE", &subtitle) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setSubtitle(subtitle); } QString encoder; - if (readAtom(tag, "\251too", &encoder)) { + if (readAtom(tag, "\251too", &encoder) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setEncoder(encoder); } QString work; - if (readAtom(tag, "\251wrk", &work)) { + if (readAtom(tag, "\251wrk", &work) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setWork(work); } QString movement; - if (readAtom(tag, "\251mvn", &movement)) { + if (readAtom(tag, "\251mvn", &movement) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMovement(movement); } #endif // __EXTRA_METADATA__ diff --git a/src/track/taglib/trackmetadata_mp4.h b/src/track/taglib/trackmetadata_mp4.h index 5a0288b3a45..f05e930de8e 100644 --- a/src/track/taglib/trackmetadata_mp4.h +++ b/src/track/taglib/trackmetadata_mp4.h @@ -12,7 +12,8 @@ namespace mp4 { void importTrackMetadataFromTag( TrackMetadata* pTrackMetadata, - const TagLib::MP4::Tag& tag); + const TagLib::MP4::Tag& tag, + bool resetMissingTagMetadata); bool importCoverImageFromTag( QImage* pCoverArt, diff --git a/src/track/taglib/trackmetadata_xiph.cpp b/src/track/taglib/trackmetadata_xiph.cpp index 3bbdda5ec02..bbcc5e1fcb7 100644 --- a/src/track/taglib/trackmetadata_xiph.cpp +++ b/src/track/taglib/trackmetadata_xiph.cpp @@ -247,7 +247,8 @@ bool importCoverImageFromTag( void importTrackMetadataFromTag( TrackMetadata* pTrackMetadata, const TagLib::Ogg::XiphComment& tag, - FileType fileType) { + FileType fileType, + bool resetMissingTagMetadata) { if (!pTrackMetadata) { return; // nothing to do } @@ -270,28 +271,30 @@ void importTrackMetadataFromTag( // handling. It prefers "DESCRIPTION" for reading, but adds a "COMMENT" // field upon writing when no "DESCRIPTION" field exists. QString comment; - if (!readCommentField(tag, "COMMENT", &comment) || comment.isEmpty()) { - // Fallback to the the original "DESCRIPTION" field only if the - // "COMMENT" field is either missing or empty - readCommentField(tag, "DESCRIPTION", &comment); + if ((readCommentField(tag, "COMMENT", &comment) && !comment.isEmpty()) || + // Fallback to the the original "DESCRIPTION" field only if the + // "COMMENT" field is either missing or empty + (readCommentField(tag, "DESCRIPTION", &comment) && !comment.isEmpty()) || + resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setComment(comment); } - pTrackMetadata->refTrackInfo().setComment(comment); QString albumArtist; if (readCommentField(tag, "ALBUMARTIST", &albumArtist) || // recommended field readCommentField(tag, "ALBUM_ARTIST", &albumArtist) || // alternative field (with underscore character) readCommentField(tag, "ALBUM ARTIST", &albumArtist) || // alternative field (with space character) - readCommentField(tag, "ENSEMBLE", &albumArtist)) { // alternative field + readCommentField(tag, "ENSEMBLE", &albumArtist) || // alternative field + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setArtist(albumArtist); } QString composer; - if (readCommentField(tag, "COMPOSER", &composer)) { + if (readCommentField(tag, "COMPOSER", &composer) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setComposer(composer); } QString grouping; - if (readCommentField(tag, "GROUPING", &grouping)) { + if (readCommentField(tag, "GROUPING", &grouping) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setGrouping(grouping); } @@ -310,6 +313,9 @@ void importTrackMetadataFromTag( } pTrackMetadata->refTrackInfo().setTrackNumber(trackNumber); pTrackMetadata->refTrackInfo().setTrackTotal(trackTotal); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setTrackNumber(QString{}); + pTrackMetadata->refTrackInfo().setTrackTotal(QString{}); } #if defined(__EXTRA_METADATA__) @@ -328,6 +334,9 @@ void importTrackMetadataFromTag( } pTrackMetadata->refTrackInfo().setDiscNumber(discNumber); pTrackMetadata->refTrackInfo().setDiscTotal(discTotal); + } else if (resetMissingTagMetadata) { + pTrackMetadata->refTrackInfo().setDiscNumber(QString{}); + pTrackMetadata->refTrackInfo().setDiscTotal(QString{}); } #endif // __EXTRA_METADATA__ @@ -335,17 +344,17 @@ void importTrackMetadataFromTag( // be followed by a space character and arbitrary text. // http://age.hobba.nl/audio/mirroredpages/ogg-tagging.html QString date; - if (readCommentField(tag, "DATE", &date)) { + if (readCommentField(tag, "DATE", &date) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setYear(date); } // MusicBrainz recommends "BPM": https://picard.musicbrainz.org/docs/mappings // Mixxx (<= 2.0) favored "TEMPO": https://www.mixxx.org/wiki/doku.php/library_metadata_rewrite_using_taglib QString bpm; - if (!readCommentField(tag, "BPM", &bpm) || !parseBpm(pTrackMetadata, bpm)) { - if (readCommentField(tag, "TEMPO", &bpm)) { - parseBpm(pTrackMetadata, bpm); - } + if (readCommentField(tag, "BPM", &bpm) || + readCommentField(tag, "TEMPO", &bpm) || + resetMissingTagMetadata) { + parseBpm(pTrackMetadata, bpm, resetMissingTagMetadata); } // Reading key code information @@ -356,105 +365,111 @@ void importTrackMetadataFromTag( // or a "KEY" vorbis comment. QString key; if (readCommentField(tag, "INITIALKEY", &key) || // recommended field - readCommentField(tag, "KEY", &key)) { // alternative field + readCommentField(tag, "KEY", &key) || // alternative field + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setKey(key); } // Only read track gain (not album gain) QString trackGain; - if (readCommentField(tag, "REPLAYGAIN_TRACK_GAIN", &trackGain)) { - parseTrackGain(pTrackMetadata, trackGain); + if (readCommentField(tag, "REPLAYGAIN_TRACK_GAIN", &trackGain) || resetMissingTagMetadata) { + parseTrackGain(pTrackMetadata, trackGain, resetMissingTagMetadata); } QString trackPeak; - if (readCommentField(tag, "REPLAYGAIN_TRACK_PEAK", &trackPeak)) { - parseTrackPeak(pTrackMetadata, trackPeak); + if (readCommentField(tag, "REPLAYGAIN_TRACK_PEAK", &trackPeak) || resetMissingTagMetadata) { + parseTrackPeak(pTrackMetadata, trackPeak, resetMissingTagMetadata); } #if defined(__EXTRA_METADATA__) QString albumGain; - if (readCommentField(tag, "REPLAYGAIN_ALBUM_GAIN", &albumGain)) { - parseAlbumGain(pTrackMetadata, albumGain); + if (readCommentField(tag, "REPLAYGAIN_ALBUM_GAIN", &albumGain) || resetMissingTagMetadata) { + parseAlbumGain(pTrackMetadata, albumGain, resetMissingTagMetadata); } QString albumPeak; - if (readCommentField(tag, "REPLAYGAIN_ALBUM_PEAK", &albumPeak)) { - parseAlbumPeak(pTrackMetadata, albumPeak); + if (readCommentField(tag, "REPLAYGAIN_ALBUM_PEAK", &albumPeak) || resetMissingTagMetadata) { + parseAlbumPeak(pTrackMetadata, albumPeak, resetMissingTagMetadata); } QString trackArtistId; - if (readCommentField(tag, "MUSICBRAINZ_ARTISTID", &trackArtistId)) { + if (readCommentField(tag, "MUSICBRAINZ_ARTISTID", &trackArtistId) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzArtistId(QUuid(trackArtistId)); } QString trackRecordingId; - if (readCommentField(tag, "MUSICBRAINZ_TRACKID", &trackRecordingId)) { + if (readCommentField(tag, "MUSICBRAINZ_TRACKID", &trackRecordingId) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzRecordingId(QUuid(trackRecordingId)); } QString trackReleaseId; - if (readCommentField(tag, "MUSICBRAINZ_RELEASETRACKID", &trackReleaseId)) { + if (readCommentField(tag, "MUSICBRAINZ_RELEASETRACKID", &trackReleaseId) || + resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzReleaseId(QUuid(trackReleaseId)); } QString trackWorkId; - if (readCommentField(tag, "MUSICBRAINZ_WORKID", &trackWorkId)) { + if (readCommentField(tag, "MUSICBRAINZ_WORKID", &trackWorkId) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMusicBrainzWorkId(QUuid(trackWorkId)); } QString albumArtistId; - if (readCommentField(tag, "MUSICBRAINZ_ALBUMARTISTID", &albumArtistId)) { + if (readCommentField(tag, "MUSICBRAINZ_ALBUMARTISTID", &albumArtistId) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzArtistId(QUuid(albumArtistId)); } QString albumReleaseId; - if (readCommentField(tag, "MUSICBRAINZ_ALBUMID", &albumReleaseId)) { + if (readCommentField(tag, "MUSICBRAINZ_ALBUMID", &albumReleaseId) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzReleaseId(QUuid(albumReleaseId)); } QString albumReleaseGroupId; - if (readCommentField(tag, "MUSICBRAINZ_RELEASEGROUPID", &albumReleaseGroupId)) { + if (readCommentField( + tag, "MUSICBRAINZ_RELEASEGROUPID", &albumReleaseGroupId) || + resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setMusicBrainzReleaseGroupId(QUuid(albumReleaseGroupId)); } QString conductor; - if (readCommentField(tag, "CONDUCTOR", &conductor)) { + if (readCommentField(tag, "CONDUCTOR", &conductor) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setConductor(conductor); } QString isrc; - if (readCommentField(tag, "ISRC", &isrc)) { + if (readCommentField(tag, "ISRC", &isrc) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setISRC(isrc); } QString language; - if (readCommentField(tag, "LANGUAGE", &language)) { + if (readCommentField(tag, "LANGUAGE", &language) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setLanguage(language); } QString lyricist; - if (readCommentField(tag, "LYRICIST", &lyricist)) { + if (readCommentField(tag, "LYRICIST", &lyricist) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setLyricist(lyricist); } QString mood; - if (readCommentField(tag, "MOOD", &mood)) { + if (readCommentField(tag, "MOOD", &mood) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setMood(mood); } QString copyright; - if (readCommentField(tag, "COPYRIGHT", ©right)) { + if (readCommentField(tag, "COPYRIGHT", ©right) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setCopyright(copyright); } QString license; - if (readCommentField(tag, "LICENSE", &license)) { + if (readCommentField(tag, "LICENSE", &license) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setLicense(license); } QString recordLabel; - if (readCommentField(tag, "LABEL", &recordLabel)) { + if (readCommentField(tag, "LABEL", &recordLabel) || resetMissingTagMetadata) { pTrackMetadata->refAlbumInfo().setRecordLabel(recordLabel); } QString remixer; - if (readCommentField(tag, "REMIXER", &remixer)) { + if (readCommentField(tag, "REMIXER", &remixer) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setRemixer(remixer); } QString subtitle; - if (readCommentField(tag, "SUBTITLE", &subtitle)) { + if (readCommentField(tag, "SUBTITLE", &subtitle) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setSubtitle(subtitle); } QString encoder; - if (readCommentField(tag, "ENCODEDBY", &encoder)) { + if (readCommentField(tag, "ENCODEDBY", &encoder) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setEncoder(encoder); } QString encoderSettings; - if (readCommentField(tag, "ENCODERSETTINGS", &encoderSettings)) { + if (readCommentField(tag, "ENCODERSETTINGS", &encoderSettings) || resetMissingTagMetadata) { pTrackMetadata->refTrackInfo().setEncoderSettings(encoderSettings); } #endif // __EXTRA_METADATA__ diff --git a/src/track/taglib/trackmetadata_xiph.h b/src/track/taglib/trackmetadata_xiph.h index 1bf72c8e204..8d63552f338 100644 --- a/src/track/taglib/trackmetadata_xiph.h +++ b/src/track/taglib/trackmetadata_xiph.h @@ -20,7 +20,8 @@ QImage importCoverImageFromPictureList( void importTrackMetadataFromTag( TrackMetadata* pTrackMetadata, const TagLib::Ogg::XiphComment& tag, - FileType fileType); + FileType fileType, + bool resetMissingTagMetadata); bool exportTrackMetadataIntoTag( TagLib::Ogg::XiphComment* pTag, diff --git a/src/track/track.cpp b/src/track/track.cpp index d2964d82e8d..7fbc531a704 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -70,10 +70,12 @@ const QString Track::kArtistTitleSeparator = QStringLiteral(" - "); //static SyncTrackMetadataParams SyncTrackMetadataParams::readFromUserSettings( const UserSettings& userSettings) { - const auto syncSeratoMetadata = - userSettings.getValue(mixxx::library::prefs::kSyncSeratoMetadataConfigKey); return SyncTrackMetadataParams{ - syncSeratoMetadata, + .resetMissingTagMetadataOnImport = + userSettings.getValue( + mixxx::library::prefs::kResetMissingTagMetadataOnImportConfigKey), + .syncSeratoMetadata = userSettings.getValue( + mixxx::library::prefs::kSyncSeratoMetadataConfigKey), }; } @@ -1580,7 +1582,12 @@ ExportTrackMetadataResult Track::exportMetadata( // Otherwise floating-point values like the bpm value might become // inconsistent with the actual value stored by the beat grid! mixxx::TrackMetadata normalizedFromRecord; - if ((metadataSource.importTrackMetadataAndCoverImage(&importedFromFile, nullptr).first == + // Both resetMissingTagMetadata = false/true have the same effect + constexpr auto resetMissingTagMetadata = false; + if ((metadataSource.importTrackMetadataAndCoverImage(&importedFromFile, + nullptr, + resetMissingTagMetadata) + .first == mixxx::MetadataSource::ImportResult::Succeeded)) { // Prevent overwriting any file tags that are not yet stored in the // library database! This will in turn update the current metadata diff --git a/src/track/track_decl.h b/src/track/track_decl.h index f81aab24ccb..67074d8889d 100644 --- a/src/track/track_decl.h +++ b/src/track/track_decl.h @@ -15,6 +15,7 @@ typedef std::weak_ptr TrackWeakPointer; typedef QList TrackPointerList; struct SyncTrackMetadataParams { + bool resetMissingTagMetadataOnImport = false; bool syncSeratoMetadata = false; static SyncTrackMetadataParams readFromUserSettings( diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 0f2ed09204e..8cf8617d932 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -2027,6 +2027,7 @@ void WTrackMenu::slotShowDlgTrackInfo() { } // Create a fresh dialog on invocation m_pDlgTrackInfo = std::make_unique( + m_pConfig, m_pTrackModel); connect(m_pDlgTrackInfo.get(), &QDialog::finished,