From 2cd94984696abfc48932d1ec27635ec4f6d2f7df Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Thu, 18 Dec 2025 22:18:26 +0100 Subject: [PATCH] Add option to select ID3v2 version Fixes #1861 --- src/core/song.cpp | 12 ++++++ src/core/song.h | 6 +++ src/dialogs/edittagdialog.cpp | 45 ++++++++++++++++++++++- src/dialogs/edittagdialog.ui | 41 +++++++++++++++++++++ src/tagreader/tagid3v2version.h | 29 +++++++++++++++ src/tagreader/tagreaderbase.h | 3 +- src/tagreader/tagreaderclient.cpp | 10 +++-- src/tagreader/tagreaderclient.h | 5 ++- src/tagreader/tagreadergme.cpp | 4 +- src/tagreader/tagreadergme.h | 3 +- src/tagreader/tagreadertaglib.cpp | 43 +++++++++++++++++++++- src/tagreader/tagreadertaglib.h | 3 +- src/tagreader/tagreaderwritefilerequest.h | 2 + 13 files changed, 193 insertions(+), 13 deletions(-) create mode 100644 src/tagreader/tagid3v2version.h diff --git a/src/core/song.cpp b/src/core/song.cpp index 3b43f697e..ea2e93f87 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -353,6 +353,8 @@ struct Song::Private : public QSharedData { std::optional ebur128_integrated_loudness_lufs_; std::optional ebur128_loudness_range_lu_; + int id3v2_version_; // ID3v2 tag version (3 or 4), 0 if not applicable or unknown + bool init_from_file_; // Whether this song was loaded from a file using taglib. bool suspicious_tags_; // Whether our encoding guesser thinks these tags might be incorrectly encoded. @@ -400,6 +402,8 @@ Song::Private::Private(const Source source) rating_(-1), bpm_(-1), + id3v2_version_(0), + init_from_file_(false), suspicious_tags_(false) @@ -510,6 +514,8 @@ const QString &Song::musicbrainz_work_id() const { return d->musicbrainz_work_id std::optional Song::ebur128_integrated_loudness_lufs() const { return d->ebur128_integrated_loudness_lufs_; } std::optional Song::ebur128_loudness_range_lu() const { return d->ebur128_loudness_range_lu_; } +int Song::id3v2_version() const { return d->id3v2_version_; } + QString *Song::mutable_title() { return &d->title_; } QString *Song::mutable_album() { return &d->album_; } QString *Song::mutable_artist() { return &d->artist_; } @@ -624,6 +630,8 @@ void Song::set_musicbrainz_work_id(const QString &v) { d->musicbrainz_work_id_ = void Song::set_ebur128_integrated_loudness_lufs(const std::optional v) { d->ebur128_integrated_loudness_lufs_ = v; } void Song::set_ebur128_loudness_range_lu(const std::optional v) { d->ebur128_loudness_range_lu_ = v; } +void Song::set_id3v2_version(const int v) { d->id3v2_version_ = v; } + void Song::set_init_from_file(const bool v) { d->init_from_file_ = v; } void Song::set_stream_url(const QUrl &v) { d->stream_url_ = v; } @@ -833,6 +841,10 @@ bool Song::save_embedded_cover_supported(const FileType filetype) { } +bool Song::id3v2_tags_supported() const { + return d->filetype_ == FileType::MPEG || d->filetype_ == FileType::WAV || d->filetype_ == FileType::AIFF; +} + int Song::ColumnIndex(const QString &field) { return static_cast(kRowIdColumns.indexOf(field)); diff --git a/src/core/song.h b/src/core/song.h index 869cf3df6..9c06e54c7 100644 --- a/src/core/song.h +++ b/src/core/song.h @@ -234,6 +234,8 @@ class Song { std::optional ebur128_integrated_loudness_lufs() const; std::optional ebur128_loudness_range_lu() const; + int id3v2_version() const; + QString *mutable_title(); QString *mutable_album(); QString *mutable_artist(); @@ -349,6 +351,8 @@ class Song { void set_ebur128_integrated_loudness_lufs(const std::optional v); void set_ebur128_loudness_range_lu(const std::optional v); + void set_id3v2_version(const int v); + void set_init_from_file(const bool v); void set_stream_url(const QUrl &v); @@ -439,6 +443,8 @@ class Song { static bool save_embedded_cover_supported(const FileType filetype); bool save_embedded_cover_supported() const { return url().isLocalFile() && save_embedded_cover_supported(filetype()) && !has_cue(); }; + bool id3v2_tags_supported() const; + static int ColumnIndex(const QString &field); static QString JoinSpec(const QString &table); diff --git a/src/dialogs/edittagdialog.cpp b/src/dialogs/edittagdialog.cpp index 5a286fa1b..2a3e5fe92 100644 --- a/src/dialogs/edittagdialog.cpp +++ b/src/dialogs/edittagdialog.cpp @@ -81,6 +81,7 @@ #include "utilities/coverutils.h" #include "utilities/coveroptions.h" #include "tagreader/tagreaderclient.h" +#include "tagreader/tagid3v2version.h" #include "widgets/busyindicator.h" #include "widgets/lineedit.h" #include "collection/collectionbackend.h" @@ -107,6 +108,12 @@ using namespace Qt::Literals::StringLiterals; namespace { constexpr char kSettingsGroup[] = "EditTagDialog"; constexpr int kSmallImageSize = 128; + +// ID3v2 version constants +constexpr int kID3v2_Version_3 = 3; +constexpr int kID3v2_Version_4 = 4; +constexpr int kComboBoxIndex_ID3v2_3 = 0; +constexpr int kComboBoxIndex_ID3v2_4 = 1; } // namespace const char EditTagDialog::kTagsDifferentHintText[] = QT_TR_NOOP("(different across multiple songs)"); @@ -708,6 +715,9 @@ void EditTagDialog::SelectionChanged() { bool titlesort_enabled = false; bool artistsort_enabled = false; bool albumsort_enabled = false; + bool has_id3v2_support = false; + int id3v2_version = 0; + bool id3v2_version_different = false; for (const QModelIndex &idx : indexes) { if (data_.value(idx.row()).cover_action_ == UpdateCoverAction::None) { data_[idx.row()].cover_result_ = AlbumCoverImageResult(); @@ -769,6 +779,15 @@ void EditTagDialog::SelectionChanged() { if (song.albumsort_supported()) { albumsort_enabled = true; } + if (song.id3v2_tags_supported()) { + has_id3v2_support = true; + if (id3v2_version == 0) { + id3v2_version = song.id3v2_version(); + } + else if (id3v2_version != song.id3v2_version()) { + id3v2_version_different = true; + } + } } QString summary; @@ -840,6 +859,23 @@ void EditTagDialog::SelectionChanged() { ui_->artistsort->setEnabled(artistsort_enabled); ui_->albumsort->setEnabled(albumsort_enabled); + ui_->label_id3v2_version->setVisible(has_id3v2_support); + ui_->combobox_id3v2_version->setVisible(has_id3v2_support); + + if (has_id3v2_support) { + // Set default based on existing version(s) + if (id3v2_version_different || id3v2_version == 0) { + // Mixed versions or unknown - default to ID3v2.4 + ui_->combobox_id3v2_version->setCurrentIndex(kComboBoxIndex_ID3v2_4); + } + else if (id3v2_version == kID3v2_Version_3) { + ui_->combobox_id3v2_version->setCurrentIndex(kComboBoxIndex_ID3v2_3); + } + else { + ui_->combobox_id3v2_version->setCurrentIndex(kComboBoxIndex_ID3v2_4); + } + } + } void EditTagDialog::UpdateUI(const QModelIndexList &indexes) { @@ -1371,6 +1407,13 @@ void EditTagDialog::SaveData() { } save_tag_cover_data.cover_data = ref.cover_result_.image_data; } + + // Determine ID3v2 version based on user selection + TagID3v2Version tag_id3v2_version = TagID3v2Version::Default; + if (ref.current_.filetype() == Song::FileType::MPEG || ref.current_.filetype() == Song::FileType::WAV || ref.current_.filetype() == Song::FileType::AIFF) { + tag_id3v2_version = ui_->combobox_id3v2_version->currentIndex() == kComboBoxIndex_ID3v2_3 ? TagID3v2Version::V3 : TagID3v2Version::V4; + } + TagReaderClient::SaveOptions save_tags_options; if (save_tags) { save_tags_options |= TagReaderClient::SaveOption::Tags; @@ -1384,7 +1427,7 @@ void EditTagDialog::SaveData() { if (save_embedded_cover) { save_tags_options |= TagReaderClient::SaveOption::Cover; } - TagReaderReplyPtr reply = tagreader_client_->WriteFileAsync(ref.current_.url().toLocalFile(), ref.current_, save_tags_options, save_tag_cover_data); + TagReaderReplyPtr reply = tagreader_client_->WriteFileAsync(ref.current_.url().toLocalFile(), ref.current_, save_tags_options, save_tag_cover_data, tag_id3v2_version); SharedPtr connection = make_shared(); *connection = QObject::connect(&*reply, &TagReaderReply::Finished, this, [this, reply, ref, connection]() { SongSaveTagsComplete(reply, ref.current_.url().toLocalFile(), ref.current_, ref.cover_action_); diff --git a/src/dialogs/edittagdialog.ui b/src/dialogs/edittagdialog.ui index 0c0e0ea3d..0ac5b9b82 100644 --- a/src/dialogs/edittagdialog.ui +++ b/src/dialogs/edittagdialog.ui @@ -650,6 +650,47 @@ + + + + + + ID3v2 version: + + + + + + + true + + + + 2.3 + + + + + 2.4 + + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + diff --git a/src/tagreader/tagid3v2version.h b/src/tagreader/tagid3v2version.h new file mode 100644 index 000000000..513dd7e88 --- /dev/null +++ b/src/tagreader/tagid3v2version.h @@ -0,0 +1,29 @@ +/* + * Strawberry Music Player + * Copyright 2025, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGID3V2VERSION_H +#define TAGID3V2VERSION_H + +enum class TagID3v2Version { + Default = 0, // Use existing version or library default + V3 = 3, + V4 = 4 +}; + +#endif // TAGID3V2VERSION_H diff --git a/src/tagreader/tagreaderbase.h b/src/tagreader/tagreaderbase.h index 9b36e3ceb..77f35f3ad 100644 --- a/src/tagreader/tagreaderbase.h +++ b/src/tagreader/tagreaderbase.h @@ -32,6 +32,7 @@ #include "savetagsoptions.h" #include "savetagcoverdata.h" #include "albumcovertagdata.h" +#include "tagid3v2version.h" class TagReaderBase { public: @@ -45,7 +46,7 @@ class TagReaderBase { virtual TagReaderResult ReadStream(const QUrl &url, const QString &filename, const quint64 size, const quint64 mtime, const QString &token_type, const QString &access_token, Song *song) const = 0; #endif - virtual TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const = 0; + virtual TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data, const TagID3v2Version id3v2_version) const = 0; virtual TagReaderResult LoadEmbeddedCover(const QString &filename, QByteArray &data) const = 0; virtual TagReaderResult SaveEmbeddedCover(const QString &filename, const SaveTagCoverData &save_tag_cover_data) const = 0; diff --git a/src/tagreader/tagreaderclient.cpp b/src/tagreader/tagreaderclient.cpp index 981d6dbc4..b5dfa97d9 100644 --- a/src/tagreader/tagreaderclient.cpp +++ b/src/tagreader/tagreaderclient.cpp @@ -50,6 +50,7 @@ #include "tagreaderreadstreamreply.h" #include "tagreaderloadcoverdatareply.h" #include "tagreaderloadcoverimagereply.h" +#include "tagid3v2version.h" using std::dynamic_pointer_cast; using namespace Qt::Literals::StringLiterals; @@ -189,7 +190,7 @@ void TagReaderClient::ProcessRequest(TagReaderRequestPtr request) { } #endif // HAVE_STREAMTAGREADER else if (TagReaderWriteFileRequestPtr write_file_request = dynamic_pointer_cast(request)) { - result = WriteFileBlocking(write_file_request->filename, write_file_request->song, write_file_request->save_tags_options, write_file_request->save_tag_cover_data); + result = WriteFileBlocking(write_file_request->filename, write_file_request->song, write_file_request->save_tags_options, write_file_request->save_tag_cover_data, write_file_request->tag_id3v2_version); } else if (TagReaderLoadCoverDataRequestPtr load_cover_data_request = dynamic_pointer_cast(request)) { QByteArray cover_data; @@ -303,13 +304,13 @@ TagReaderReadStreamReplyPtr TagReaderClient::ReadStreamAsync(const QUrl &url, co } #endif // HAVE_STREAMTAGREADER -TagReaderResult TagReaderClient::WriteFileBlocking(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) { +TagReaderResult TagReaderClient::WriteFileBlocking(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data, const TagID3v2Version tag_id3v2_version) { - return tagreader_.WriteFile(filename, song, save_tags_options, save_tag_cover_data); + return tagreader_.WriteFile(filename, song, save_tags_options, save_tag_cover_data, tag_id3v2_version); } -TagReaderReplyPtr TagReaderClient::WriteFileAsync(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) { +TagReaderReplyPtr TagReaderClient::WriteFileAsync(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data, const TagID3v2Version tag_id3v2_version) { Q_ASSERT(QThread::currentThread() != thread()); @@ -321,6 +322,7 @@ TagReaderReplyPtr TagReaderClient::WriteFileAsync(const QString &filename, const request->song = song; request->save_tags_options = save_tags_options; request->save_tag_cover_data = save_tag_cover_data; + request->tag_id3v2_version = tag_id3v2_version; EnqueueRequest(request); diff --git a/src/tagreader/tagreaderclient.h b/src/tagreader/tagreaderclient.h index cc5557676..02b077f6a 100644 --- a/src/tagreader/tagreaderclient.h +++ b/src/tagreader/tagreaderclient.h @@ -43,6 +43,7 @@ #include "tagreaderloadcoverimagereply.h" #include "savetagsoptions.h" #include "savetagcoverdata.h" +#include "tagid3v2version.h" class QThread; class Song; @@ -72,8 +73,8 @@ class TagReaderClient : public QObject { [[nodiscard]] TagReaderReadStreamReplyPtr ReadStreamAsync(const QUrl &url, const QString &filename, const quint64 size, const quint64 mtime, const QString &token_type, const QString &access_token); #endif - TagReaderResult WriteFileBlocking(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options = SaveTagsOption::Tags, const SaveTagCoverData &save_tag_cover_data = SaveTagCoverData()); - [[nodiscard]] TagReaderReplyPtr WriteFileAsync(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options = SaveTagsOption::Tags, const SaveTagCoverData &save_tag_cover_data = SaveTagCoverData()); + TagReaderResult WriteFileBlocking(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options = SaveTagsOption::Tags, const SaveTagCoverData &save_tag_cover_data = SaveTagCoverData(), const TagID3v2Version tag_id3v2_version = TagID3v2Version::Default); + [[nodiscard]] TagReaderReplyPtr WriteFileAsync(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options = SaveTagsOption::Tags, const SaveTagCoverData &save_tag_cover_data = SaveTagCoverData(), const TagID3v2Version tag_id3v2_version = TagID3v2Version::Default); TagReaderResult LoadCoverDataBlocking(const QString &filename, QByteArray &data); TagReaderResult LoadCoverImageBlocking(const QString &filename, QImage &image); diff --git a/src/tagreader/tagreadergme.cpp b/src/tagreader/tagreadergme.cpp index 1c887fb9c..25ad75f1b 100644 --- a/src/tagreader/tagreadergme.cpp +++ b/src/tagreader/tagreadergme.cpp @@ -32,6 +32,7 @@ #include "core/logging.h" #include "tagreaderbase.h" #include "tagreadertaglib.h" +#include "tagid3v2version.h" using namespace Qt::Literals::StringLiterals; @@ -317,12 +318,13 @@ TagReaderResult TagReaderGME::ReadStream(const QUrl &url, const QString &filenam } #endif -TagReaderResult TagReaderGME::WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const { +TagReaderResult TagReaderGME::WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data, const TagID3v2Version id3v2_version) const { Q_UNUSED(filename); Q_UNUSED(song); Q_UNUSED(save_tags_options); Q_UNUSED(save_tag_cover_data); + Q_UNUSED(id3v2_version); return TagReaderResult::ErrorCode::Unsupported; diff --git a/src/tagreader/tagreadergme.h b/src/tagreader/tagreadergme.h index 13af9a4a6..64576d8d2 100644 --- a/src/tagreader/tagreadergme.h +++ b/src/tagreader/tagreadergme.h @@ -25,6 +25,7 @@ #include #include "tagreaderbase.h" +#include "tagid3v2version.h" namespace GME { bool IsSupportedFormat(const QFileInfo &fileinfo); @@ -107,7 +108,7 @@ class TagReaderGME : public TagReaderBase { TagReaderResult ReadStream(const QUrl &url, const QString &filename, const quint64 size, const quint64 mtime, const QString &token_type, const QString &access_token, Song *song) const override; #endif - TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const override; + TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data, const TagID3v2Version id3v2_version) const override; TagReaderResult LoadEmbeddedCover(const QString &filename, QByteArray &data) const override; TagReaderResult SaveEmbeddedCover(const QString &filename, const SaveTagCoverData &save_tag_cover_data) const override; diff --git a/src/tagreader/tagreadertaglib.cpp b/src/tagreader/tagreadertaglib.cpp index 63442c130..b3c09deb7 100644 --- a/src/tagreader/tagreadertaglib.cpp +++ b/src/tagreader/tagreadertaglib.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,7 @@ #include "constants/timeconstants.h" #include "albumcovertagdata.h" +#include "tagid3v2version.h" using std::make_unique; using namespace Qt::Literals::StringLiterals; @@ -149,6 +151,10 @@ constexpr char kID3v2_MusicBrainz_DiscId[] = "MusicBrainz Disc Id"; constexpr char kID3v2_MusicBrainz_ReleaseGroupId[] = "MusicBrainz Release Group Id"; constexpr char kID3v2_MusicBrainz_WorkId[] = "MusicBrainz Work Id"; +// ID3v2 version constants +constexpr int kID3v2_Version_3 = 3; +constexpr int kID3v2_Version_4 = 4; + constexpr char kVorbisComment_AlbumArtist1[] = "ALBUMARTIST"; constexpr char kVorbisComment_AlbumArtist2[] = "ALBUM ARTIST"; constexpr char kVorbisComment_AlbumArtistSort[] = "ALBUMARTISTSORT"; @@ -604,8 +610,14 @@ TagReaderResult TagReaderTagLib::ReadStream(const QUrl &url, void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QString *compilation, Song *song) const { + if (!tag) return; + TagLib::ID3v2::FrameListMap map = tag->frameListMap(); + if (tag->header()) { + song->set_id3v2_version(tag->header()->majorVersion()); + } + if (map.contains(kID3v2_Disc)) *disc = TagLibStringToQString(map[kID3v2_Disc].front()->toString()).trimmed(); if (map.contains(kID3v2_Composer)) song->set_composer(map[kID3v2_Composer].front()->toString()); if (map.contains(kID3v2_ComposerSort)) song->set_composersort(map[kID3v2_ComposerSort].front()->toString()); @@ -1042,7 +1054,7 @@ void TagReaderTagLib::ParseASFAttribute(const TagLib::ASF::AttributeListMap &att } -TagReaderResult TagReaderTagLib::WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const { +TagReaderResult TagReaderTagLib::WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data, const TagID3v2Version tag_id3v2_version) const { if (filename.isEmpty()) { return TagReaderResult::ErrorCode::FilenameMissing; @@ -1265,7 +1277,34 @@ TagReaderResult TagReaderTagLib::WriteFile(const QString &filename, const Song & } } - const bool success = fileref->save(); + // Determine ID3v2 version to use and convert to TagLib type + TagLib::ID3v2::Version taglib_id3v2_version = TagLib::ID3v2::v4; + if (tag_id3v2_version == TagID3v2Version::V3) { + taglib_id3v2_version = TagLib::ID3v2::v3; + } + else if (tag_id3v2_version == TagID3v2Version::V4) { + taglib_id3v2_version = TagLib::ID3v2::v4; + } + + bool success = false; + + // For MPEG files, use save with ID3v2 version parameter + if (TagLib::MPEG::File *file_mpeg = dynamic_cast(fileref->file())) { + success = file_mpeg->save(TagLib::MPEG::File::AllTags, TagLib::File::StripOthers, taglib_id3v2_version); + } + // For WAV files with ID3v2 tags + else if (TagLib::RIFF::WAV::File *file_wav = dynamic_cast(fileref->file())) { + success = file_wav->save(TagLib::RIFF::WAV::File::AllTags, TagLib::File::StripOthers, taglib_id3v2_version); + } + // For AIFF files with ID3v2 tags + else if (TagLib::RIFF::AIFF::File *file_aiff = dynamic_cast(fileref->file())) { + success = file_aiff->save(taglib_id3v2_version); + } + // For all other file types, use default save + else { + success = fileref->save(); + } + #ifdef Q_OS_LINUX if (success) { // Linux: inotify doesn't seem to notice the change to the file unless we change the timestamps as well. (this is what touch does) diff --git a/src/tagreader/tagreadertaglib.h b/src/tagreader/tagreadertaglib.h index 8c2596340..914184359 100644 --- a/src/tagreader/tagreadertaglib.h +++ b/src/tagreader/tagreadertaglib.h @@ -46,6 +46,7 @@ #include "tagreaderbase.h" #include "savetagcoverdata.h" +#include "tagid3v2version.h" #undef TStringToQString #undef QStringToTString @@ -72,7 +73,7 @@ class TagReaderTagLib : public TagReaderBase { TagReaderResult ReadStream(const QUrl &url, const QString &filename, const quint64 size, const quint64 mtime, const QString &token_type, const QString &access_token, Song *song) const override; #endif - TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const override; + TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data, const TagID3v2Version tag_id3v2_version) const override; TagReaderResult LoadEmbeddedCover(const QString &filename, QByteArray &data) const override; TagReaderResult SaveEmbeddedCover(const QString &filename, const SaveTagCoverData &save_tag_cover_data) const override; diff --git a/src/tagreader/tagreaderwritefilerequest.h b/src/tagreader/tagreaderwritefilerequest.h index 504313ed9..d6a417cb8 100644 --- a/src/tagreader/tagreaderwritefilerequest.h +++ b/src/tagreader/tagreaderwritefilerequest.h @@ -27,6 +27,7 @@ #include "tagreaderrequest.h" #include "savetagsoptions.h" #include "savetagcoverdata.h" +#include "tagid3v2version.h" using std::make_shared; @@ -39,6 +40,7 @@ class TagReaderWriteFileRequest : public TagReaderRequest { SaveTagsOptions save_tags_options; Song song; SaveTagCoverData save_tag_cover_data; + TagID3v2Version tag_id3v2_version; }; using TagReaderWriteFileRequestPtr = SharedPtr;