diff --git a/data/schema/device-schema.sql b/data/schema/device-schema.sql index a903cb6b..a998b1bd 100644 --- a/data/schema/device-schema.sql +++ b/data/schema/device-schema.sql @@ -69,6 +69,7 @@ CREATE TABLE device_%deviceid_songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, diff --git a/data/schema/schema-16.sql b/data/schema/schema-16.sql index fe9874d3..0965086b 100644 --- a/data/schema/schema-16.sql +++ b/data/schema/schema-16.sql @@ -1,3 +1,5 @@ +ALTER TABLE songs ADD COLUMN acoustid_id TEXT; + ALTER TABLE songs ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE songs ADD COLUMN musicbrainz_album_artist_id TEXT; @@ -20,6 +22,8 @@ ALTER TABLE songs ADD COLUMN musicbrainz_release_group_id TEXT; ALTER TABLE songs ADD COLUMN musicbrainz_work_id TEXT; +ALTER TABLE subsonic_songs ADD COLUMN acoustid_id TEXT; + ALTER TABLE subsonic_songs ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_album_artist_id TEXT; @@ -42,6 +46,8 @@ ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_release_group_id TEXT; ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_work_id TEXT; +ALTER TABLE tidal_artists_songs ADD COLUMN acoustid_id TEXT; + ALTER TABLE tidal_artists_songs ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_album_artist_id TEXT; @@ -64,6 +70,8 @@ ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_release_group_id TEXT; ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_work_id TEXT; +ALTER TABLE tidal_albums_songs ADD COLUMN acoustid_id TEXT; + ALTER TABLE tidal_albums_songs ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_album_artist_id TEXT; @@ -86,6 +94,8 @@ ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_release_group_id TEXT; ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_work_id TEXT; +ALTER TABLE tidal_songs ADD COLUMN acoustid_id TEXT; + ALTER TABLE tidal_songs ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE tidal_songs ADD COLUMN musicbrainz_album_artist_id TEXT; @@ -108,6 +118,8 @@ ALTER TABLE tidal_songs ADD COLUMN musicbrainz_release_group_id TEXT; ALTER TABLE tidal_songs ADD COLUMN musicbrainz_work_id TEXT; +ALTER TABLE qobuz_artists_songs ADD COLUMN acoustid_id TEXT; + ALTER TABLE qobuz_artists_songs ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_album_artist_id TEXT; @@ -130,6 +142,8 @@ ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_release_group_id TEXT; ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_work_id TEXT; +ALTER TABLE qobuz_albums_songs ADD COLUMN acoustid_id TEXT; + ALTER TABLE qobuz_albums_songs ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_album_artist_id TEXT; @@ -152,6 +166,8 @@ ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_release_group_id TEXT; ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_work_id TEXT; +ALTER TABLE qobuz_songs ADD COLUMN acoustid_id TEXT; + ALTER TABLE qobuz_songs ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_album_artist_id TEXT; @@ -174,6 +190,8 @@ ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_release_group_id TEXT; ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_work_id TEXT; +ALTER TABLE playlist_items ADD COLUMN acoustid_id TEXT; + ALTER TABLE playlist_items ADD COLUMN acoustid_fingerprint TEXT; ALTER TABLE playlist_items ADD COLUMN musicbrainz_album_artist_id TEXT; diff --git a/data/schema/schema.sql b/data/schema/schema.sql index de6612dd..4e0b445e 100644 --- a/data/schema/schema.sql +++ b/data/schema/schema.sql @@ -77,6 +77,7 @@ CREATE TABLE IF NOT EXISTS songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, @@ -152,6 +153,7 @@ CREATE TABLE IF NOT EXISTS subsonic_songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, @@ -227,6 +229,7 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, @@ -302,6 +305,7 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, @@ -377,6 +381,7 @@ CREATE TABLE IF NOT EXISTS tidal_songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, @@ -452,6 +457,7 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, @@ -527,6 +533,7 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, @@ -602,6 +609,7 @@ CREATE TABLE IF NOT EXISTS qobuz_songs ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, @@ -697,6 +705,7 @@ CREATE TABLE IF NOT EXISTS playlist_items ( rating INTEGER DEFAULT -1, + acoustid_id TEXT, acoustid_fingerprint TEXT, musicbrainz_album_artist_id TEXT, diff --git a/ext/libstrawberry-tagreader/tagreadermessages.proto b/ext/libstrawberry-tagreader/tagreadermessages.proto index e709fca0..7b5cf819 100644 --- a/ext/libstrawberry-tagreader/tagreadermessages.proto +++ b/ext/libstrawberry-tagreader/tagreadermessages.proto @@ -73,18 +73,19 @@ message SongMetadata { optional float rating = 32; - optional string acoustid_fingerprint = 33; + optional string acoustid_id = 33; + optional string acoustid_fingerprint = 34; - optional string musicbrainz_album_artist_id = 34; // MusicBrainz Release Artist ID (MUSICBRAINZ_ALBUMARTISTID) - optional string musicbrainz_artist_id = 35; // MusicBrainz Artist ID (MUSICBRAINZ_ARTISTID) - optional string musicbrainz_original_artist_id = 36; // MusicBrainz Original Artist ID (MUSICBRAINZ_ORIGINALARTISTID) - optional string musicbrainz_album_id = 37; // MusicBrainz Release ID (MUSICBRAINZ_ALBUMID) - optional string musicbrainz_original_album_id = 38; // MusicBrainz Original Release ID (MUSICBRAINZ_ORIGINALALBUMID) - optional string musicbrainz_recording_id = 39; // MusicBrainz Recording ID (MUSICBRAINZ_TRACKID) - optional string musicbrainz_track_id = 40; // MusicBrainz Track ID (MUSICBRAINZ_RELEASETRACKID) - optional string musicbrainz_disc_id = 41; // MusicBrainz Disc ID (MUSICBRAINZ_DISCID) - optional string musicbrainz_release_group_id = 42; // MusicBrainz Release Group ID (MUSICBRAINZ_RELEASEGROUPID) - optional string musicbrainz_work_id = 43; // MusicBrainz Work ID (MUSICBRAINZ_WORKID) + optional string musicbrainz_album_artist_id = 35; // MusicBrainz Release Artist ID (MUSICBRAINZ_ALBUMARTISTID) + optional string musicbrainz_artist_id = 36; // MusicBrainz Artist ID (MUSICBRAINZ_ARTISTID) + optional string musicbrainz_original_artist_id = 37; // MusicBrainz Original Artist ID (MUSICBRAINZ_ORIGINALARTISTID) + optional string musicbrainz_album_id = 38; // MusicBrainz Release ID (MUSICBRAINZ_ALBUMID) + optional string musicbrainz_original_album_id = 39; // MusicBrainz Original Release ID (MUSICBRAINZ_ORIGINALALBUMID) + optional string musicbrainz_recording_id = 40; // MusicBrainz Recording ID (MUSICBRAINZ_TRACKID) + optional string musicbrainz_track_id = 41; // MusicBrainz Track ID (MUSICBRAINZ_RELEASETRACKID) + optional string musicbrainz_disc_id = 42; // MusicBrainz Disc ID (MUSICBRAINZ_DISCID) + optional string musicbrainz_release_group_id = 43; // MusicBrainz Release Group ID (MUSICBRAINZ_RELEASEGROUPID) + optional string musicbrainz_work_id = 44; // MusicBrainz Work ID (MUSICBRAINZ_WORKID) optional bool suspicious_tags = 50; diff --git a/ext/libstrawberry-tagreader/tagreadertaglib.cpp b/ext/libstrawberry-tagreader/tagreadertaglib.cpp index 98d74e9f..7ff3921a 100644 --- a/ext/libstrawberry-tagreader/tagreadertaglib.cpp +++ b/ext/libstrawberry-tagreader/tagreadertaglib.cpp @@ -134,6 +134,7 @@ TagLib::String QStringToTaglibString(const QString &s) { namespace { +constexpr char kID3v2_AcoustID_ID[] = "TXXX:Acoustid Id"; constexpr char kID3v2_AcoustID_Fingerprint[] = "TXXX:Acoustid Fingerprint"; constexpr char kID3v2_MusicBrainz_AlbumArtistID[] = "TXXX:MusicBrainz Album Artist Id"; constexpr char kID3v2_MusicBrainz_ArtistID[] = "TXXX:MusicBrainz Artist Id"; @@ -149,6 +150,7 @@ constexpr char kID3v2_MusicBrainz_WorkID[] = "TXXX:MusicBrainz Work Id"; constexpr char kMP4_OriginalYear_ID[] = "----:com.apple.iTunes:ORIGINAL YEAR"; constexpr char kMP4_FMPS_Playcount_ID[] = "----:com.apple.iTunes:FMPS_Playcount"; constexpr char kMP4_FMPS_Rating_ID[] = "----:com.apple.iTunes:FMPS_Rating"; +constexpr char kMP4_AcoustID_ID[] = "----: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"; constexpr char kMP4_MusicBrainz_ArtistID[] = "----:com.apple.iTunes:MusicBrainz Artist Id"; @@ -163,6 +165,7 @@ constexpr char kMP4_MusicBrainz_WorkID[] = "----:com.apple.iTunes:MusicBrainz Wo constexpr char kASF_OriginalDate_ID[] = "WM/OriginalReleaseTime"; constexpr char kASF_OriginalYear_ID[] = "WM/OriginalReleaseYear"; +constexpr char kASF_AcoustID_ID[] = "Acoustid/Id"; constexpr char kASF_AcoustID_Fingerprint[] = "Acoustid/Fingerprint"; constexpr char kASF_MusicBrainz_AlbumArtistID[] = "MusicBrainz/Album Artist Id"; constexpr char kASF_MusicBrainz_ArtistID[] = "MusicBrainz/Artist Id"; @@ -394,6 +397,9 @@ bool TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta } } + if (map.contains(kID3v2_AcoustID_ID)) { + TStringToStdString(map[kID3v2_AcoustID_ID].front()->toString(), song->mutable_acoustid_id()); + } if (map.contains(kID3v2_AcoustID_Fingerprint)) { TStringToStdString(map[kID3v2_AcoustID_Fingerprint].front()->toString(), song->mutable_acoustid_fingerprint()); } @@ -496,6 +502,9 @@ bool TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta TStringToStdString(mp4_tag->comment(), song->mutable_comment()); + if (mp4_tag->contains(kMP4_AcoustID_ID)) { + TStringToStdString(mp4_tag->item(kMP4_AcoustID_ID).toStringList().toString(), song->mutable_acoustid_id()); + } if (mp4_tag->contains(kMP4_AcoustID_Fingerprint)) { TStringToStdString(mp4_tag->item(kMP4_AcoustID_Fingerprint).toStringList().toString(), song->mutable_acoustid_fingerprint()); } @@ -576,6 +585,9 @@ bool TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta } } + if (attributes_map.contains(kASF_AcoustID_ID)) { + TStringToStdString(attributes_map[kASF_AcoustID_ID].front().toString(), song->mutable_acoustid_id()); + } if (attributes_map.contains(kASF_AcoustID_Fingerprint)) { TStringToStdString(attributes_map[kASF_AcoustID_Fingerprint].front().toString(), song->mutable_acoustid_fingerprint()); } @@ -701,6 +713,7 @@ void TagReaderTagLib::ParseOggTag(const TagLib::Ogg::FieldListMap &map, QString if (map.contains("LYRICS")) TStringToStdString(map["LYRICS"].front(), song->mutable_lyrics()); else if (map.contains("UNSYNCEDLYRICS")) TStringToStdString(map["UNSYNCEDLYRICS"].front(), song->mutable_lyrics()); + if (map.contains("ACOUSTID_ID")) TStringToStdString(map["ACOUSTID_ID"].front(), song->mutable_acoustid_id()); if (map.contains("ACOUSTID_FINGERPRINT")) TStringToStdString(map["ACOUSTID_FINGERPRINT"].front(), song->mutable_acoustid_fingerprint()); if (map.contains("MUSICBRAINZ_ALBUMARTISTID")) TStringToStdString(map["MUSICBRAINZ_ALBUMARTISTID"].front(), song->mutable_musicbrainz_album_artist_id()); @@ -765,6 +778,7 @@ void TagReaderTagLib::ParseAPETag(const TagLib::APE::ItemListMap &map, QString * } } + if (map.contains("ACOUSTID_ID")) TStringToStdString(map["ACOUSTID_ID"].toString(), song->mutable_acoustid_id()); if (map.contains("ACOUSTID_FINGERPRINT")) TStringToStdString(map["ACOUSTID_FINGERPRINT"].toString(), song->mutable_acoustid_fingerprint()); if (map.contains("MUSICBRAINZ_ALBUMARTISTID")) TStringToStdString(map["MUSICBRAINZ_ALBUMARTISTID"].toString(), song->mutable_musicbrainz_album_artist_id()); diff --git a/src/core/song.cpp b/src/core/song.cpp index d2bd4c99..f8ffcb7a 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -119,6 +119,7 @@ const QStringList Song::kColumns = QStringList() << "title" << "rating" + << "acoustid_id" << "acoustid_fingerprint" << "musicbrainz_album_artist_id" @@ -233,6 +234,7 @@ struct Song::Private : public QSharedData { float rating_; // Database rating, initial rating read from tag. + QString acoustid_id_; QString acoustid_fingerprint_; QString musicbrainz_album_artist_id_; @@ -461,6 +463,7 @@ bool Song::has_cue() const { return !d->cue_path_.isEmpty(); } float Song::rating() const { return d->rating_; } +const QString &Song::acoustid_id() const { return d->acoustid_id_; } const QString &Song::acoustid_fingerprint() const { return d->acoustid_fingerprint_; } const QString &Song::musicbrainz_album_artist_id() const { return d->musicbrainz_album_artist_id_; } @@ -579,6 +582,7 @@ 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_acoustid_id(const QString &v) { d->acoustid_id_ = v; } void Song::set_acoustid_fingerprint(const QString &v) { d->acoustid_fingerprint_ = v; } void Song::set_musicbrainz_album_artist_id(const QString &v) { d->musicbrainz_album_artist_id_ = v; } @@ -993,6 +997,7 @@ void Song::InitFromProtobuf(const spb::tagreader::SongMetadata &pb) { if (!art_automatic.isEmpty()) set_art_automatic(QUrl::fromLocalFile(art_automatic)); } + d->acoustid_id_ = QString::fromUtf8(pb.acoustid_id().data(), pb.acoustid_id().size()); d->acoustid_fingerprint_ = QString::fromUtf8(pb.acoustid_fingerprint().data(), pb.acoustid_fingerprint().size()); d->musicbrainz_album_artist_id_ = QString::fromUtf8(pb.musicbrainz_album_artist_id().data(), pb.musicbrainz_album_artist_id().size()); @@ -1050,6 +1055,7 @@ void Song::ToProtobuf(spb::tagreader::SongMetadata *pb) const { pb->set_art_automatic(art_automatic.constData(), art_automatic.size()); pb->set_rating(d->rating_); + pb->set_acoustid_id(d->acoustid_id_.toStdString()); pb->set_acoustid_fingerprint(d->acoustid_fingerprint_.toStdString()); pb->set_musicbrainz_album_artist_id(d->musicbrainz_album_artist_id_.toStdString()); @@ -1133,6 +1139,7 @@ void Song::InitFromQuery(const SqlRow &q, const bool reliable_metadata) { d->cue_path_ = q.ValueToString("cue_path"); d->rating_ = q.ValueToFloat("rating"); + d->acoustid_id_ = q.ValueToString("acoustid_id"); d->acoustid_fingerprint_ = q.ValueToString("acoustid_fingerprint"); d->musicbrainz_album_artist_id_ = q.ValueToString("musicbrainz_album_artist_id"); @@ -1495,6 +1502,7 @@ void Song::BindToQuery(SqlQuery *query) const { query->BindFloatValue(":rating", d->rating_); + query->BindStringValue("acoustid_id", d->acoustid_id_); query->BindStringValue("acoustid_fingerprint", d->acoustid_fingerprint_); query->BindStringValue("musicbrainz_album_artist_id", d->musicbrainz_album_artist_id_); @@ -1648,9 +1656,9 @@ bool Song::IsFingerprintEqual(const Song &other) const { } -bool Song::IsAcoustidFingerprintEqual(const Song &other) const { +bool Song::IsAcoustIdEqual(const Song &other) const { - return d->acoustid_fingerprint_ == other.d->acoustid_fingerprint_; + return d->acoustid_id_ == other.d->acoustid_id_ && d->acoustid_fingerprint_ == other.d->acoustid_fingerprint_; } @@ -1680,7 +1688,7 @@ bool Song::IsAllMetadataEqual(const Song &other) const { return IsMetadataEqual(other) && IsPlayStatisticsEqual(other) && IsRatingEqual(other) && - IsAcoustidFingerprintEqual(other) && + IsAcoustIdEqual(other) && IsMusicBrainzEqual(other) && IsArtEqual(other); diff --git a/src/core/song.h b/src/core/song.h index 694b0fbf..e64ea67a 100644 --- a/src/core/song.h +++ b/src/core/song.h @@ -259,6 +259,7 @@ class Song { float rating() const; + const QString &acoustid_id() const; const QString &acoustid_fingerprint() const; const QString &musicbrainz_album_artist_id() const; @@ -399,6 +400,7 @@ class Song { void set_rating(const float v); + void set_acoustid_id(const QString &v); void set_acoustid_fingerprint(const QString &v); void set_musicbrainz_album_artist_id(const QString &v); @@ -419,7 +421,7 @@ class Song { bool IsPlayStatisticsEqual(const Song &other) const; bool IsRatingEqual(const Song &other) const; bool IsFingerprintEqual(const Song &other) const; - bool IsAcoustidFingerprintEqual(const Song &other) const; + bool IsAcoustIdEqual(const Song &other) const; bool IsMusicBrainzEqual(const Song &other) const; bool IsArtEqual(const Song &other) const; bool IsAllMetadataEqual(const Song &other) const;