Get genre metadata for Tidal, Qobuz and Spotify
Extract genre information when fetching favorites and search results. Genre is now populated in the collection and playlists for tracks from these streaming services.
This commit is contained in:
committed by
Jonas Kvinge
parent
610b458196
commit
ea629aedd1
@@ -695,6 +695,16 @@ void QobuzRequest::AlbumsReceived(QNetworkReply *reply, const Artist &artist_req
|
|||||||
}
|
}
|
||||||
album.album = obj_item["title"_L1].toString();
|
album.album = obj_item["title"_L1].toString();
|
||||||
|
|
||||||
|
if (obj_item.contains("genre"_L1)) {
|
||||||
|
QJsonValue value_genre = obj_item["genre"_L1];
|
||||||
|
if (value_genre.isObject()) {
|
||||||
|
QJsonObject obj_genre = value_genre.toObject();
|
||||||
|
if (obj_genre.contains("name"_L1)) {
|
||||||
|
album.genre = obj_genre["name"_L1].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (album_songs_requests_pending_.contains(album.album_id)) continue;
|
if (album_songs_requests_pending_.contains(album.album_id)) continue;
|
||||||
|
|
||||||
QJsonValue value_artist = obj_item["artist"_L1];
|
QJsonValue value_artist = obj_item["artist"_L1];
|
||||||
@@ -921,6 +931,17 @@ void QobuzRequest::SongsReceived(QNetworkReply *reply, const Artist &artist_requ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract genre from album/get response if not already set
|
||||||
|
if (album.genre.isEmpty() && json_object.contains("genre"_L1)) {
|
||||||
|
QJsonValue value_genre = json_object["genre"_L1];
|
||||||
|
if (value_genre.isObject()) {
|
||||||
|
QJsonObject obj_genre = value_genre.toObject();
|
||||||
|
if (obj_genre.contains("name"_L1)) {
|
||||||
|
album.genre = obj_genre["name"_L1].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QJsonValue value_tracks = json_object["tracks"_L1];
|
QJsonValue value_tracks = json_object["tracks"_L1];
|
||||||
if (!value_tracks.isObject()) {
|
if (!value_tracks.isObject()) {
|
||||||
Error(u"Json tracks is not an object."_s, json_object);
|
Error(u"Json tracks is not an object."_s, json_object);
|
||||||
@@ -1053,6 +1074,7 @@ void QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Arti
|
|||||||
// bool streamable = json_obj["streamable"].toBool();
|
// bool streamable = json_obj["streamable"].toBool();
|
||||||
QString composer;
|
QString composer;
|
||||||
QString performer;
|
QString performer;
|
||||||
|
QString genre;
|
||||||
|
|
||||||
if (json_obj.contains("media_number"_L1)) {
|
if (json_obj.contains("media_number"_L1)) {
|
||||||
disc = json_obj["media_number"_L1].toInt();
|
disc = json_obj["media_number"_L1].toInt();
|
||||||
@@ -1118,6 +1140,21 @@ void QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Arti
|
|||||||
song_album.cover_url.setUrl(album_image);
|
song_album.cover_url.setUrl(album_image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj_album.contains("genre"_L1)) {
|
||||||
|
QJsonValue value_genre = obj_album["genre"_L1];
|
||||||
|
if (value_genre.isObject()) {
|
||||||
|
QJsonObject obj_genre = value_genre.toObject();
|
||||||
|
if (obj_genre.contains("name"_L1)) {
|
||||||
|
genre = obj_genre["name"_L1].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to genre from the Album struct if not found in the track's album object
|
||||||
|
if (genre.isEmpty() && !album.genre.isEmpty()) {
|
||||||
|
genre = album.genre;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json_obj.contains("composer"_L1)) {
|
if (json_obj.contains("composer"_L1)) {
|
||||||
@@ -1180,6 +1217,7 @@ void QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Arti
|
|||||||
song.set_performer(performer);
|
song.set_performer(performer);
|
||||||
song.set_composer(composer);
|
song.set_composer(composer);
|
||||||
song.set_comment(copyright);
|
song.set_comment(copyright);
|
||||||
|
song.set_genre(genre);
|
||||||
song.set_directory_id(0);
|
song.set_directory_id(0);
|
||||||
song.set_filetype(Song::FileType::Stream);
|
song.set_filetype(Song::FileType::Stream);
|
||||||
song.set_filesize(0);
|
song.set_filesize(0);
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ class QobuzRequest : public QobuzBaseRequest {
|
|||||||
QString album;
|
QString album;
|
||||||
QUrl cover_url;
|
QUrl cover_url;
|
||||||
bool album_explicit;
|
bool album_explicit;
|
||||||
|
QString genre;
|
||||||
};
|
};
|
||||||
struct Request {
|
struct Request {
|
||||||
Request() : offset(0), limit(0) {}
|
Request() : offset(0), limit(0) {}
|
||||||
|
|||||||
@@ -496,11 +496,20 @@ void SpotifyRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_
|
|||||||
const QString artist_id = object_item["id"_L1].toString();
|
const QString artist_id = object_item["id"_L1].toString();
|
||||||
const QString artist = object_item["name"_L1].toString();
|
const QString artist = object_item["name"_L1].toString();
|
||||||
|
|
||||||
|
QString genre;
|
||||||
|
if (object_item.contains("genres"_L1) && object_item["genres"_L1].isArray()) {
|
||||||
|
const QJsonArray array_genres = object_item["genres"_L1].toArray();
|
||||||
|
if (!array_genres.isEmpty()) {
|
||||||
|
genre = array_genres.first().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (artist_albums_requests_pending_.contains(artist_id)) continue;
|
if (artist_albums_requests_pending_.contains(artist_id)) continue;
|
||||||
|
|
||||||
ArtistAlbumsRequest request;
|
ArtistAlbumsRequest request;
|
||||||
request.artist.artist_id = artist_id;
|
request.artist.artist_id = artist_id;
|
||||||
request.artist.artist = artist;
|
request.artist.artist = artist;
|
||||||
|
request.artist.genre = genre;
|
||||||
artist_albums_requests_pending_.insert(artist_id, request);
|
artist_albums_requests_pending_.insert(artist_id, request);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -715,6 +724,12 @@ void SpotifyRequest::AlbumsReceived(QNetworkReply *reply, const Artist &artist_a
|
|||||||
if (artist.artist_id.isEmpty() || artist.artist_id == artist_artist.artist_id) {
|
if (artist.artist_id.isEmpty() || artist.artist_id == artist_artist.artist_id) {
|
||||||
artist.artist_id = obj_artist["id"_L1].toString();
|
artist.artist_id = obj_artist["id"_L1].toString();
|
||||||
artist.artist = obj_artist["name"_L1].toString();
|
artist.artist = obj_artist["name"_L1].toString();
|
||||||
|
if (obj_artist.contains("genres"_L1) && obj_artist["genres"_L1].isArray()) {
|
||||||
|
const QJsonArray array_genres = obj_artist["genres"_L1].toArray();
|
||||||
|
if (!array_genres.isEmpty()) {
|
||||||
|
album.genre = array_genres.first().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (artist.artist_id == artist_artist.artist_id) {
|
if (artist.artist_id == artist_artist.artist_id) {
|
||||||
artist_matches = true;
|
artist_matches = true;
|
||||||
break;
|
break;
|
||||||
@@ -730,6 +745,11 @@ void SpotifyRequest::AlbumsReceived(QNetworkReply *reply, const Artist &artist_a
|
|||||||
artist = artist_artist;
|
artist = artist_artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fall back to artist's genre if no genre found in album's artist data
|
||||||
|
if (album.genre.isEmpty() && !artist_artist.genre.isEmpty()) {
|
||||||
|
album.genre = artist_artist.genre;
|
||||||
|
}
|
||||||
|
|
||||||
if (object_item.contains("images"_L1) && object_item["images"_L1].isArray()) {
|
if (object_item.contains("images"_L1) && object_item["images"_L1].isArray()) {
|
||||||
const QJsonArray array_images = object_item["images"_L1].toArray();
|
const QJsonArray array_images = object_item["images"_L1].toArray();
|
||||||
for (const QJsonValue &value : array_images) {
|
for (const QJsonValue &value : array_images) {
|
||||||
@@ -1050,6 +1070,7 @@ void SpotifyRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Ar
|
|||||||
|
|
||||||
QString artist_id;
|
QString artist_id;
|
||||||
QString artist_title;
|
QString artist_title;
|
||||||
|
QString genre;
|
||||||
if (json_obj.contains("artists"_L1) && json_obj["artists"_L1].isArray()) {
|
if (json_obj.contains("artists"_L1) && json_obj["artists"_L1].isArray()) {
|
||||||
const QJsonArray array_artists = json_obj["artists"_L1].toArray();
|
const QJsonArray array_artists = json_obj["artists"_L1].toArray();
|
||||||
for (const QJsonValue &value_artist : array_artists) {
|
for (const QJsonValue &value_artist : array_artists) {
|
||||||
@@ -1060,6 +1081,12 @@ void SpotifyRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Ar
|
|||||||
}
|
}
|
||||||
artist_id = obj_artist["id"_L1].toString();
|
artist_id = obj_artist["id"_L1].toString();
|
||||||
artist_title = obj_artist["name"_L1].toString();
|
artist_title = obj_artist["name"_L1].toString();
|
||||||
|
if (obj_artist.contains("genres"_L1) && obj_artist["genres"_L1].isArray()) {
|
||||||
|
const QJsonArray array_genres = obj_artist["genres"_L1].toArray();
|
||||||
|
if (!array_genres.isEmpty()) {
|
||||||
|
genre = array_genres.first().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1102,6 +1129,16 @@ void SpotifyRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Ar
|
|||||||
cover_url = album.cover_url;
|
cover_url = album.cover_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fall back to genre from the Album struct if not found in the track's artist
|
||||||
|
if (genre.isEmpty() && !album.genre.isEmpty()) {
|
||||||
|
genre = album.genre;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to genre from the Artist struct if still not found
|
||||||
|
if (genre.isEmpty() && !album_artist.genre.isEmpty()) {
|
||||||
|
genre = album_artist.genre;
|
||||||
|
}
|
||||||
|
|
||||||
QString song_id = json_obj["id"_L1].toString();
|
QString song_id = json_obj["id"_L1].toString();
|
||||||
QString title = json_obj["name"_L1].toString();
|
QString title = json_obj["name"_L1].toString();
|
||||||
QString uri = json_obj["uri"_L1].toString();
|
QString uri = json_obj["uri"_L1].toString();
|
||||||
@@ -1130,6 +1167,7 @@ void SpotifyRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Ar
|
|||||||
song.set_url(url);
|
song.set_url(url);
|
||||||
song.set_length_nanosec(duration);
|
song.set_length_nanosec(duration);
|
||||||
song.set_art_automatic(cover_url);
|
song.set_art_automatic(cover_url);
|
||||||
|
song.set_genre(genre);
|
||||||
song.set_directory_id(0);
|
song.set_directory_id(0);
|
||||||
song.set_filetype(Song::FileType::Stream);
|
song.set_filetype(Song::FileType::Stream);
|
||||||
song.set_filesize(0);
|
song.set_filesize(0);
|
||||||
|
|||||||
@@ -57,11 +57,13 @@ class SpotifyRequest : public SpotifyBaseRequest {
|
|||||||
struct Artist {
|
struct Artist {
|
||||||
QString artist_id;
|
QString artist_id;
|
||||||
QString artist;
|
QString artist;
|
||||||
|
QString genre;
|
||||||
};
|
};
|
||||||
struct Album {
|
struct Album {
|
||||||
QString album_id;
|
QString album_id;
|
||||||
QString album;
|
QString album;
|
||||||
QUrl cover_url;
|
QUrl cover_url;
|
||||||
|
QString genre;
|
||||||
};
|
};
|
||||||
struct Request {
|
struct Request {
|
||||||
Request() : offset(0), limit(0) {}
|
Request() : offset(0), limit(0) {}
|
||||||
|
|||||||
@@ -1000,6 +1000,11 @@ void TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Arti
|
|||||||
const bool stream_ready = json_obj["streamReady"_L1].toBool();
|
const bool stream_ready = json_obj["streamReady"_L1].toBool();
|
||||||
const QString copyright = json_obj["copyright"_L1].toString();
|
const QString copyright = json_obj["copyright"_L1].toString();
|
||||||
|
|
||||||
|
QString genre;
|
||||||
|
if (json_obj.contains("genre"_L1)) {
|
||||||
|
genre = json_obj["genre"_L1].toString();
|
||||||
|
}
|
||||||
|
|
||||||
if (!value_artist.isObject()) {
|
if (!value_artist.isObject()) {
|
||||||
Error(u"Invalid Json reply, track artist is not a object."_s, value_artist);
|
Error(u"Invalid Json reply, track artist is not a object."_s, value_artist);
|
||||||
return;
|
return;
|
||||||
@@ -1095,6 +1100,7 @@ void TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Arti
|
|||||||
song.set_art_automatic(cover_url);
|
song.set_art_automatic(cover_url);
|
||||||
}
|
}
|
||||||
song.set_comment(copyright);
|
song.set_comment(copyright);
|
||||||
|
song.set_genre(genre);
|
||||||
song.set_directory_id(0);
|
song.set_directory_id(0);
|
||||||
song.set_filetype(Song::FileType::Stream);
|
song.set_filetype(Song::FileType::Stream);
|
||||||
song.set_filesize(0);
|
song.set_filesize(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user