Add BPM, mood and initial key support
This commit is contained in:
@@ -132,6 +132,9 @@ const QStringList Song::kColumns = QStringList() << u"title"_s
|
||||
<< u"cue_path"_s
|
||||
|
||||
<< u"rating"_s
|
||||
<< u"bpm"_s
|
||||
<< u"mood"_s
|
||||
<< u"initial_key"_s
|
||||
|
||||
<< u"acoustid_id"_s
|
||||
<< u"acoustid_fingerprint"_s
|
||||
@@ -328,6 +331,9 @@ struct Song::Private : public QSharedData {
|
||||
QString cue_path_; // If the song has a CUE, this contains it's path.
|
||||
|
||||
float rating_; // Database rating, initial rating read from tag.
|
||||
float bpm_;
|
||||
QString mood_;
|
||||
QString initial_key_;
|
||||
|
||||
QString acoustid_id_;
|
||||
QString acoustid_fingerprint_;
|
||||
@@ -391,6 +397,7 @@ Song::Private::Private(const Source source)
|
||||
art_unset_(false),
|
||||
|
||||
rating_(-1),
|
||||
bpm_(-1),
|
||||
|
||||
init_from_file_(false),
|
||||
suspicious_tags_(false)
|
||||
@@ -481,6 +488,9 @@ bool Song::art_unset() const { return d->art_unset_; }
|
||||
const QString &Song::cue_path() const { return d->cue_path_; }
|
||||
|
||||
float Song::rating() const { return d->rating_; }
|
||||
float Song::bpm() const { return d->bpm_; }
|
||||
const QString &Song::mood() const { return d->mood_; }
|
||||
const QString &Song::initial_key() const { return d->initial_key_; }
|
||||
|
||||
const QString &Song::acoustid_id() const { return d->acoustid_id_; }
|
||||
const QString &Song::acoustid_fingerprint() const { return d->acoustid_fingerprint_; }
|
||||
@@ -592,6 +602,9 @@ void Song::set_art_unset(const bool v) { d->art_unset_ = v; }
|
||||
void Song::set_cue_path(const QString &v) { d->cue_path_ = v; }
|
||||
|
||||
void Song::set_rating(const float v) { d->rating_ = v; }
|
||||
void Song::set_bpm(const float v) { d->bpm_ = v; }
|
||||
void Song::set_mood(const QString &v) { d->mood_ = v; }
|
||||
void Song::set_initial_key(const QString &v) { d->initial_key_ = v; }
|
||||
|
||||
void Song::set_acoustid_id(const QString &v) { d->acoustid_id_ = v; }
|
||||
void Song::set_acoustid_fingerprint(const QString &v) { d->acoustid_fingerprint_ = v; }
|
||||
@@ -645,6 +658,8 @@ void Song::set_musicbrainz_track_id(const TagLib::String &v) { d->musicbrainz_tr
|
||||
void Song::set_musicbrainz_disc_id(const TagLib::String &v) { d->musicbrainz_disc_id_ = TagLibStringToQString(v).remove(u' ').replace(u';', u'/'); }
|
||||
void Song::set_musicbrainz_release_group_id(const TagLib::String &v) { d->musicbrainz_release_group_id_ = TagLibStringToQString(v).remove(u' ').replace(u';', u'/'); }
|
||||
void Song::set_musicbrainz_work_id(const TagLib::String &v) { d->musicbrainz_work_id_ = TagLibStringToQString(v).remove(u' ').replace(u';', u'/'); }
|
||||
void Song::set_mood(const TagLib::String &v) { d->mood_ = TagLibStringToQString(v); }
|
||||
void Song::set_initial_key(const TagLib::String &v) { d->initial_key_ = TagLibStringToQString(v); }
|
||||
|
||||
const QUrl &Song::effective_url() const { return !d->stream_url_.isEmpty() && d->stream_url_.isValid() ? d->stream_url_ : d->url_; }
|
||||
const QString &Song::effective_titlesort() const { return d->titlesort_.isEmpty() ? d->title_ : d->titlesort_; }
|
||||
@@ -977,6 +992,9 @@ bool Song::IsMetadataEqual(const Song &other) const {
|
||||
d->bitrate_ == other.d->bitrate_ &&
|
||||
d->samplerate_ == other.d->samplerate_ &&
|
||||
d->bitdepth_ == other.d->bitdepth_ &&
|
||||
d->bpm_ == other.d->bpm_ &&
|
||||
d->mood_ == other.d->mood_ &&
|
||||
d->initial_key_ == other.d->initial_key_ &&
|
||||
d->cue_path_ == other.d->cue_path_;
|
||||
}
|
||||
|
||||
@@ -1570,7 +1588,11 @@ void Song::InitFromQuery(const QSqlRecord &r, const bool reliable_metadata, cons
|
||||
d->art_unset_ = SqlHelper::ValueToBool(r, ColumnIndex(u"art_unset"_s) + col);
|
||||
|
||||
d->cue_path_ = SqlHelper::ValueToString(r, ColumnIndex(u"cue_path"_s) + col);
|
||||
|
||||
d->rating_ = SqlHelper::ValueToFloat(r, ColumnIndex(u"rating"_s) + col);
|
||||
d->bpm_ = SqlHelper::ValueToFloat(r, ColumnIndex(u"bpm"_s) + col);
|
||||
d->mood_ = SqlHelper::ValueToString(r, ColumnIndex(u"mood"_s) + col);
|
||||
d->initial_key_ = SqlHelper::ValueToString(r, ColumnIndex(u"initial_key"_s) + col);
|
||||
|
||||
d->acoustid_id_ = SqlHelper::ValueToString(r, ColumnIndex(u"acoustid_id"_s) + col);
|
||||
d->acoustid_fingerprint_ = SqlHelper::ValueToString(r, ColumnIndex(u"acoustid_fingerprint"_s) + col);
|
||||
@@ -1900,6 +1922,9 @@ void Song::BindToQuery(SqlQuery *query) const {
|
||||
query->BindValue(u":cue_path"_s, d->cue_path_);
|
||||
|
||||
query->BindFloatValue(u":rating"_s, d->rating_);
|
||||
query->BindFloatValue(u":bpm"_s, d->bpm_);
|
||||
query->BindStringValue(u":mood"_s, d->mood_);
|
||||
query->BindStringValue(u":initial_key"_s, d->initial_key_);
|
||||
|
||||
query->BindStringValue(u":acoustid_id"_s, d->acoustid_id_);
|
||||
query->BindStringValue(u":acoustid_fingerprint"_s, d->acoustid_fingerprint_);
|
||||
|
||||
@@ -213,6 +213,9 @@ class Song {
|
||||
const QString &cue_path() const;
|
||||
|
||||
float rating() const;
|
||||
float bpm() const;
|
||||
const QString &mood() const;
|
||||
const QString &initial_key() const;
|
||||
|
||||
const QString &acoustid_id() const;
|
||||
const QString &acoustid_fingerprint() const;
|
||||
@@ -325,6 +328,9 @@ class Song {
|
||||
void set_cue_path(const QString &v);
|
||||
|
||||
void set_rating(const float v);
|
||||
void set_bpm(const float v);
|
||||
void set_mood(const QString &v);
|
||||
void set_initial_key(const QString &v);
|
||||
|
||||
void set_acoustid_id(const QString &v);
|
||||
void set_acoustid_fingerprint(const QString &v);
|
||||
@@ -378,6 +384,8 @@ class Song {
|
||||
void set_musicbrainz_disc_id(const TagLib::String &v);
|
||||
void set_musicbrainz_release_group_id(const TagLib::String &v);
|
||||
void set_musicbrainz_work_id(const TagLib::String &v);
|
||||
void set_mood(const TagLib::String &v);
|
||||
void set_initial_key(const TagLib::String &v);
|
||||
|
||||
const QUrl &effective_url() const;
|
||||
const QString &effective_titlesort() const;
|
||||
|
||||
@@ -391,7 +391,11 @@ QVariant Playlist::data(const QModelIndex &idx, const int role) const {
|
||||
|
||||
case Column::HasCUE: return song.has_cue();
|
||||
|
||||
case Column::Mood:
|
||||
case Column::BPM: return song.bpm();
|
||||
case Column::Mood: return song.mood();
|
||||
case Column::InitialKey: return song.initial_key();
|
||||
|
||||
case Column::Moodbar:
|
||||
case Column::ColumnCount:
|
||||
break;
|
||||
|
||||
@@ -445,7 +449,7 @@ QVariant Playlist::data(const QModelIndex &idx, const int role) const {
|
||||
|
||||
#ifdef HAVE_MOODBAR
|
||||
void Playlist::MoodbarUpdated(const QModelIndex &idx) {
|
||||
Q_EMIT dataChanged(idx.sibling(idx.row(), static_cast<int>(Column::Mood)), idx.sibling(idx.row(), static_cast<int>(Column::Mood)));
|
||||
Q_EMIT dataChanged(idx.sibling(idx.row(), static_cast<int>(Column::Moodbar)), idx.sibling(idx.row(), static_cast<int>(Column::Moodbar)));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1412,7 +1416,11 @@ bool Playlist::CompareItems(const Column column, const Qt::SortOrder order, Play
|
||||
case Column::EBUR128IntegratedLoudness: return CompareVal(ma.ebur128_integrated_loudness_lufs(), mb.ebur128_integrated_loudness_lufs());
|
||||
case Column::EBUR128LoudnessRange: return CompareVal(ma.ebur128_loudness_range_lu(), mb.ebur128_loudness_range_lu());
|
||||
|
||||
case Column::Mood:
|
||||
case Column::BPM: return CompareVal(ma.bpm(), mb.bpm());
|
||||
case Column::Mood: return CompareStr(ma.mood(), mb.mood());
|
||||
case Column::InitialKey: return CompareStr(ma.initial_key(), mb.initial_key());
|
||||
|
||||
case Column::Moodbar:
|
||||
case Column::ColumnCount:
|
||||
break;
|
||||
}
|
||||
@@ -1460,13 +1468,17 @@ QString Playlist::column_name(const Column column) {
|
||||
|
||||
case Column::Comment: return tr("Comment");
|
||||
case Column::Source: return tr("Source");
|
||||
case Column::Mood: return tr("Mood");
|
||||
case Column::Moodbar: return tr("Moodbar");
|
||||
case Column::Rating: return tr("Rating");
|
||||
case Column::HasCUE: return tr("CUE");
|
||||
|
||||
case Column::EBUR128IntegratedLoudness: return tr("Integrated Loudness");
|
||||
case Column::EBUR128LoudnessRange: return tr("Loudness Range");
|
||||
|
||||
case Column::BPM: return tr("BPM");
|
||||
case Column::Mood: return tr("Mood");
|
||||
case Column::InitialKey: return tr("Initial key");
|
||||
|
||||
case Column::ColumnCount:
|
||||
break;
|
||||
}
|
||||
@@ -2266,6 +2278,15 @@ Playlist::Columns Playlist::ChangedColumns(const Song &metadata1, const Song &me
|
||||
if (metadata1.ebur128_loudness_range_lu() != metadata2.ebur128_loudness_range_lu()) {
|
||||
columns << Column::EBUR128LoudnessRange;
|
||||
}
|
||||
if (metadata1.bpm() != metadata2.bpm()) {
|
||||
columns << Column::BPM;
|
||||
}
|
||||
if (metadata1.mood() != metadata2.mood()) {
|
||||
columns << Column::Mood;
|
||||
}
|
||||
if (metadata1.initial_key() != metadata2.initial_key()) {
|
||||
columns << Column::InitialKey;
|
||||
}
|
||||
|
||||
return columns;
|
||||
|
||||
|
||||
@@ -133,11 +133,14 @@ class Playlist : public QAbstractListModel {
|
||||
Comment,
|
||||
Grouping,
|
||||
Source,
|
||||
Mood,
|
||||
Moodbar,
|
||||
Rating,
|
||||
HasCUE,
|
||||
EBUR128IntegratedLoudness,
|
||||
EBUR128LoudnessRange,
|
||||
BPM,
|
||||
Mood,
|
||||
InitialKey,
|
||||
ColumnCount
|
||||
};
|
||||
using Columns = QList<Column>;
|
||||
|
||||
@@ -246,7 +246,7 @@ void PlaylistView::SetItemDelegates() {
|
||||
setItemDelegateForColumn(static_cast<int>(Playlist::Column::Source), new SongSourceDelegate(this));
|
||||
|
||||
#ifdef HAVE_MOODBAR
|
||||
setItemDelegateForColumn(static_cast<int>(Playlist::Column::Mood), new MoodbarItemDelegate(moodbar_loader_, this, this));
|
||||
setItemDelegateForColumn(static_cast<int>(Playlist::Column::Moodbar), new MoodbarItemDelegate(moodbar_loader_, this, this));
|
||||
#endif
|
||||
|
||||
rating_delegate_ = new RatingItemDelegate(this);
|
||||
@@ -254,6 +254,7 @@ void PlaylistView::SetItemDelegates() {
|
||||
|
||||
setItemDelegateForColumn(static_cast<int>(Playlist::Column::EBUR128IntegratedLoudness), new Ebur128LoudnessLUFSItemDelegate(this));
|
||||
setItemDelegateForColumn(static_cast<int>(Playlist::Column::EBUR128LoudnessRange), new Ebur128LoudnessRangeLUItemDelegate(this));
|
||||
|
||||
}
|
||||
|
||||
void PlaylistView::setModel(QAbstractItemModel *m) {
|
||||
@@ -390,11 +391,14 @@ void PlaylistView::RestoreHeaderState() {
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::LastPlayed));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::Comment));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::Grouping));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::Mood));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::Moodbar));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::Rating));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::HasCUE));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::EBUR128IntegratedLoudness));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::EBUR128LoudnessRange));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::BPM));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::Mood));
|
||||
header_->HideSection(static_cast<int>(Playlist::Column::InitialKey));
|
||||
|
||||
header_->ShowSection(static_cast<int>(Playlist::Column::Track));
|
||||
header_->ShowSection(static_cast<int>(Playlist::Column::Title));
|
||||
@@ -1390,6 +1394,7 @@ ColumnAlignmentMap PlaylistView::DefaultColumnAlignment() {
|
||||
ret[static_cast<int>(Playlist::Column::Filesize)] =
|
||||
ret[static_cast<int>(Playlist::Column::PlayCount)] =
|
||||
ret[static_cast<int>(Playlist::Column::SkipCount)] =
|
||||
ret[static_cast<int>(Playlist::Column::BPM)] =
|
||||
(Qt::AlignRight | Qt::AlignVCenter);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -214,6 +214,7 @@ SmartPlaylistSearchTerm::Type SmartPlaylistSearchTerm::TypeOf(const Field field)
|
||||
case Field::Samplerate:
|
||||
case Field::Bitdepth:
|
||||
case Field::Bitrate:
|
||||
case Field::BPM:
|
||||
return Type::Number;
|
||||
|
||||
case Field::LastPlayed:
|
||||
@@ -365,9 +366,16 @@ QString SmartPlaylistSearchTerm::FieldColumnName(const Field field) {
|
||||
return u"performersort"_s;
|
||||
case Field::TitleSort:
|
||||
return u"titlesort"_s;
|
||||
case Field::BPM:
|
||||
return u"bpm"_s;
|
||||
case Field::Mood:
|
||||
return u"mood"_s;
|
||||
case Field::InitialKey:
|
||||
return u"initial_key"_s;
|
||||
case Field::FieldCount:
|
||||
Q_ASSERT(0);
|
||||
}
|
||||
|
||||
return QString();
|
||||
|
||||
}
|
||||
@@ -439,6 +447,12 @@ QString SmartPlaylistSearchTerm::FieldName(const Field field) {
|
||||
return Playlist::column_name(Playlist::Column::PerformerSort);
|
||||
case Field::TitleSort:
|
||||
return Playlist::column_name(Playlist::Column::TitleSort);
|
||||
case Field::BPM:
|
||||
return Playlist::column_name(Playlist::Column::BPM);
|
||||
case Field::Mood:
|
||||
return Playlist::column_name(Playlist::Column::Mood);
|
||||
case Field::InitialKey:
|
||||
return Playlist::column_name(Playlist::Column::InitialKey);
|
||||
case Field::FieldCount:
|
||||
Q_ASSERT(0);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ class SmartPlaylistSearchTerm {
|
||||
ComposerSort,
|
||||
PerformerSort,
|
||||
TitleSort,
|
||||
BPM,
|
||||
Mood,
|
||||
InitialKey,
|
||||
FieldCount
|
||||
};
|
||||
|
||||
|
||||
@@ -133,6 +133,9 @@ constexpr char kID3v2_FMPS_Rating[] = "FMPS_Rating";
|
||||
constexpr char kID3v2_Unique_File_Identifier[] = "UFID";
|
||||
constexpr char kID3v2_UserDefinedTextInformationFrame[] = "TXXX";
|
||||
constexpr char kID3v2_Popularimeter[] = "POPM";
|
||||
constexpr char kID3v2_BPM[] = "TBPM";
|
||||
constexpr char kID3v2_Mood[] = "TMOO";
|
||||
constexpr char kID3v2_Initial_Key[] = "TKEY";
|
||||
constexpr char kID3v2_AcoustId[] = "Acoustid Id";
|
||||
constexpr char kID3v2_AcoustId_Fingerprint[] = "Acoustid Fingerprint";
|
||||
constexpr char kID3v2_MusicBrainz_AlbumArtistId[] = "MusicBrainz Album Artist Id";
|
||||
@@ -168,6 +171,9 @@ constexpr char kVorbisComment_FMPS_Playcount[] = "FMPS_PLAYCOUNT";
|
||||
constexpr char kVorbisComment_FMPS_Rating[] = "FMPS_RATING";
|
||||
constexpr char kVorbisComment_Lyrics[] = "LYRICS";
|
||||
constexpr char kVorbisComment_UnsyncedLyrics[] = "UNSYNCEDLYRICS";
|
||||
constexpr char kVorbisComment_BPM[] = "BPM";
|
||||
constexpr char kVorbisComment_Mood[] = "MOOD";
|
||||
constexpr char kVorbisComment_Initial_Key[] = "INITIALKEY";
|
||||
constexpr char kVorbisComment_AcoustId[] = "ACOUSTID_ID";
|
||||
constexpr char kVorbisComment_AcoustId_Fingerprint[] = "ACOUSTID_FINGERPRINT";
|
||||
constexpr char kVorbisComment_MusicBrainz_AlbumArtistId[] = "MUSICBRAINZ_ALBUMARTISTID";
|
||||
@@ -191,6 +197,7 @@ constexpr char kMP4_CoverArt[] = "covr";
|
||||
constexpr char kMP4_OriginalYear[] = "----:com.apple.iTunes:ORIGINAL YEAR";
|
||||
constexpr char kMP4_FMPS_Playcount[] = "----:com.apple.iTunes:FMPS_Playcount";
|
||||
constexpr char kMP4_FMPS_Rating[] = "----:com.apple.iTunes:FMPS_Rating";
|
||||
constexpr char kMP4_BPM[] = "tmpo";
|
||||
constexpr char kMP4_AcoustId[] = "----:com.apple.iTunes:Acoustid Id";
|
||||
constexpr char kMP4_AcoustId_Fingerprint[] = "----:com.apple.iTunes:Acoustid Fingerprint";
|
||||
constexpr char kMP4_MusicBrainz_AlbumArtistId[] = "----:com.apple.iTunes:MusicBrainz Album Artist Id";
|
||||
@@ -214,6 +221,7 @@ constexpr char kAPE_CoverArt[] = "COVER ART (FRONT)";
|
||||
constexpr char kAPE_FMPS_Playcount[] = "FMPS_PLAYCOUNT";
|
||||
constexpr char kAPE_FMPS_Rating[] = "FMPS_RATING";
|
||||
constexpr char kAPE_Lyrics[] = "LYRICS";
|
||||
constexpr char kAPE_BPM[] = "BPM";
|
||||
constexpr char kAPE_AcoustId[] = "ACOUSTID_ID";
|
||||
constexpr char kAPE_AcoustId_Fingerprint[] = "ACOUSTID_FINGERPRINT";
|
||||
constexpr char kAPE_MusicBrainz_AlbumArtistId[] = "MUSICBRAINZ_ALBUMARTISTID";
|
||||
@@ -633,6 +641,10 @@ void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QSt
|
||||
|
||||
if (map.contains(kID3v2_CoverArt) && song->url().isLocalFile()) song->set_art_embedded(true);
|
||||
|
||||
if (map.contains(kID3v2_BPM)) song->set_bpm(TagLibStringToQString(map[kID3v2_BPM].front()->toString()).trimmed().toFloat());
|
||||
if (map.contains(kID3v2_Mood)) song->set_mood(map[kID3v2_Mood].front()->toString());
|
||||
if (map.contains(kID3v2_Initial_Key)) song->set_initial_key(map[kID3v2_Initial_Key].front()->toString());
|
||||
|
||||
if (TagLib::ID3v2::UserTextIdentificationFrame *frame_fmps_playcount = TagLib::ID3v2::UserTextIdentificationFrame::find(tag, kID3v2_FMPS_Playcount)) {
|
||||
TagLib::StringList frame_field_list = frame_fmps_playcount->fieldList();
|
||||
if (frame_field_list.size() > 1) {
|
||||
@@ -753,6 +765,10 @@ void TagReaderTagLib::ParseVorbisComments(const TagLib::Ogg::FieldListMap &map,
|
||||
if (map.contains(kVorbisComment_Lyrics)) song->set_lyrics(map[kVorbisComment_Lyrics].front());
|
||||
else if (map.contains(kVorbisComment_UnsyncedLyrics)) song->set_lyrics(map[kVorbisComment_UnsyncedLyrics].front());
|
||||
|
||||
if (map.contains(kVorbisComment_BPM)) song->set_bpm(TagLibStringToQString(map[kVorbisComment_BPM].front()).toFloat());
|
||||
if (map.contains(kVorbisComment_Mood)) song->set_mood(map[kVorbisComment_Mood].front());
|
||||
if (map.contains(kVorbisComment_Initial_Key)) song->set_initial_key(map[kVorbisComment_Initial_Key].front());
|
||||
|
||||
if (map.contains(kVorbisComment_AcoustId)) song->set_acoustid_id(map[kVorbisComment_AcoustId].front());
|
||||
if (map.contains(kVorbisComment_AcoustId_Fingerprint)) song->set_acoustid_fingerprint(map[kVorbisComment_AcoustId_Fingerprint].front());
|
||||
|
||||
@@ -818,6 +834,10 @@ void TagReaderTagLib::ParseAPETags(const TagLib::APE::ItemListMap &map, QString
|
||||
}
|
||||
}
|
||||
|
||||
if (map.contains(kAPE_BPM)) {
|
||||
song->set_bpm(TagLibStringToQString(map[kAPE_BPM].toString()).toFloat());
|
||||
}
|
||||
|
||||
if (map.contains(kAPE_AcoustId)) song->set_acoustid_id(map[kAPE_AcoustId].toString());
|
||||
if (map.contains(kAPE_AcoustId_Fingerprint)) song->set_acoustid_fingerprint(map[kAPE_AcoustId_Fingerprint].toString());
|
||||
|
||||
@@ -895,6 +915,16 @@ void TagReaderTagLib::ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString
|
||||
|
||||
song->set_comment(tag->comment());
|
||||
|
||||
if (tag->item(kMP4_BPM).isValid()) {
|
||||
const TagLib::MP4::Item item = tag->item(kMP4_BPM);
|
||||
if (item.isValid()) {
|
||||
const float bpm = TagLibStringToQString(item.toStringList().toString('\n')).toFloat();
|
||||
if (bpm > 0) {
|
||||
song->set_bpm(bpm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tag->contains(kMP4_AcoustId)) {
|
||||
song->set_acoustid_id(tag->item(kMP4_AcoustId).toStringList().toString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user