diff --git a/src/core/song.cpp b/src/core/song.cpp index b1ff7de9..6daeee10 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -150,7 +150,7 @@ const QString Song::kManuallyUnsetCover = "(unset)"; const QString Song::kEmbeddedCover = "(embedded)"; const QRegularExpression Song::kAlbumRemoveDisc(" ?-? ((\\(|\\[)?)(Disc|CD) ?([0-9]{1,2})((\\)|\\])?)$"); -const QRegularExpression Song::kAlbumRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$"); +const QRegularExpression Song::kAlbumRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|([0-9]{1,4}) *Remaster|Explicit) ?((\\)|\\])?)$"); const QRegularExpression Song::kTitleRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|Live|Remastered Version|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$"); const QString Song::kVariousArtists("various artists"); diff --git a/src/settings/tidalsettingspage.cpp b/src/settings/tidalsettingspage.cpp index 29138712..cdc0a750 100644 --- a/src/settings/tidalsettingspage.cpp +++ b/src/settings/tidalsettingspage.cpp @@ -111,6 +111,8 @@ void TidalSettingsPage::Load() { if (i == -1) i = ui_->streamurl->findData(StreamUrlMethod_StreamUrl); ui_->streamurl->setCurrentIndex(i); + ui_->checkbox_album_explicit->setChecked(s.value("album_explicit", false).toBool()); + s.endGroup(); OAuthClicked(ui_->oauth->isChecked()); @@ -143,6 +145,7 @@ void TidalSettingsPage::Save() { s.setValue("downloadalbumcovers", ui_->checkbox_download_album_covers->isChecked()); s.setValue("coversize", ui_->coversize->itemData(ui_->coversize->currentIndex())); s.setValue("streamurl", ui_->streamurl->itemData(ui_->streamurl->currentIndex())); + s.setValue("album_explicit", ui_->checkbox_album_explicit->isChecked()); s.endGroup(); service_->ReloadSettings(); diff --git a/src/settings/tidalsettingspage.ui b/src/settings/tidalsettingspage.ui index 7772d49d..51ff02ca 100644 --- a/src/settings/tidalsettingspage.ui +++ b/src/settings/tidalsettingspage.ui @@ -269,6 +269,13 @@ + + + + Append explicit to album title for explicit albums + + + diff --git a/src/tidal/tidalrequest.cpp b/src/tidal/tidalrequest.cpp index 39908005..4ece3b13 100644 --- a/src/tidal/tidalrequest.cpp +++ b/src/tidal/tidalrequest.cpp @@ -595,6 +595,7 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id QString album_id; QString album; + bool album_explicit = false; if (obj_item.contains("type")) { // This was a albums request or search if (!obj_item.contains("id") || !obj_item.contains("title")) { Error("Invalid Json reply, item is missing ID or title.", obj_item); @@ -607,6 +608,12 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id album_id = QString::number(obj_item["id"].toInt()); } album = obj_item["title"].toString(); + if (service_->album_explicit() && obj_item.contains("explicit")) { + album_explicit = obj_item["explicit"].toVariant().toBool(); + if (album_explicit && !album.isEmpty()) { + album.append(" (Explicit)"); + } + } } else if (obj_item.contains("album")) { // This was a tracks request or search QJsonValue value_album = obj_item["album"]; @@ -626,7 +633,12 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id album_id = QString::number(obj_album["id"].toInt()); } album = obj_album["title"].toString(); - + if (service_->album_explicit() && obj_album.contains("explicit")) { + album_explicit = obj_album["explicit"].toVariant().toBool(); + if (album_explicit && !album.isEmpty()) { + album.append(" (Explicit)"); + } + } } else { Error("Invalid Json reply, item missing type or album.", obj_item); @@ -673,6 +685,8 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id } request.album_id = album_id; request.album_artist = artist; + request.album = album; + request.album_explicit = album_explicit; album_songs_requests_pending_.insert(album_id, request); } @@ -717,7 +731,7 @@ void TidalRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, QHash ::iterator i; for (i = album_songs_requests_pending_.begin() ; i != album_songs_requests_pending_.end() ; ++i) { Request request = i.value(); - AddAlbumSongsRequest(request.artist_id, request.album_id, request.album_artist); + AddAlbumSongsRequest(request.artist_id, request.album_id, request.album_artist, request.album, request.album_explicit); } album_songs_requests_pending_.clear(); @@ -745,12 +759,14 @@ void TidalRequest::SongsReplyReceived(QNetworkReply *reply, const int limit_requ } -void TidalRequest::AddAlbumSongsRequest(const QString &artist_id, const QString &album_id, const QString &album_artist, const int offset) { +void TidalRequest::AddAlbumSongsRequest(const QString &artist_id, const QString &album_id, const QString &album_artist, const QString &album, const bool album_explicit, const int offset) { Request request; request.artist_id = artist_id; request.album_id = album_id; request.album_artist = album_artist; + request.album = album; + request.album_explicit = album_explicit; request.offset = offset; album_songs_requests_queue_.enqueue(request); ++album_songs_requested_; @@ -768,24 +784,24 @@ void TidalRequest::FlushAlbumSongsRequests() { if (request.offset > 0) parameters << Param("offset", QString::number(request.offset)); QNetworkReply *reply = CreateRequest(QString("albums/%1/tracks").arg(request.album_id), parameters); replies_ << reply; - QObject::connect(reply, &QNetworkReply::finished, [this, reply, request]() { AlbumSongsReplyReceived(reply, request.artist_id, request.album_id, request.offset, request.album_artist); }); + QObject::connect(reply, &QNetworkReply::finished, [this, reply, request]() { AlbumSongsReplyReceived(reply, request.artist_id, request.album_id, request.offset, request.album_artist, request.album, request.album_explicit); }); } } -void TidalRequest::AlbumSongsReplyReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int offset_requested, const QString &album_artist) { +void TidalRequest::AlbumSongsReplyReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int offset_requested, const QString &album_artist, const QString &album, const bool album_explicit) { --album_songs_requests_active_; ++album_songs_received_; if (offset_requested == 0) { emit UpdateProgress(query_id_, album_songs_received_); } - SongsReceived(reply, artist_id, album_id, 0, offset_requested, false, album_artist); + SongsReceived(reply, artist_id, album_id, 0, offset_requested, false, album_artist, album, album_explicit); } -void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int limit_requested, const int offset_requested, const bool auto_login, const QString &album_artist) { +void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int limit_requested, const int offset_requested, const bool auto_login, const QString &album_artist, const QString &album, const bool album_explicit) { if (!replies_.contains(reply)) return; replies_.removeAll(reply); @@ -797,13 +813,13 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, if (finished_) return; if (data.isEmpty()) { - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, 0, 0, album_artist); + SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, 0, 0, album_artist, album, album_explicit); return; } QJsonObject json_obj = ExtractJsonObj(data); if (json_obj.isEmpty()) { - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, 0, 0, album_artist); + SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, 0, 0, album_artist, album, album_explicit); return; } @@ -812,7 +828,7 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, !json_obj.contains("totalNumberOfItems") || !json_obj.contains("items")) { Error("Json object missing values.", json_obj); - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, 0, 0, album_artist); + SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, 0, 0, album_artist, album, album_explicit); return; } @@ -822,13 +838,13 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, if (offset != offset_requested) { Error(QString("Offset returned does not match offset requested! %1 != %2").arg(offset).arg(offset_requested)); - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist); + SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist, album, album_explicit); return; } QJsonValue json_value = ExtractItems(json_obj); if (!json_value.isArray()) { - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist); + SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist, album, album_explicit); return; } @@ -837,7 +853,7 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, if ((type_ == QueryType_Songs || type_ == QueryType_SearchSongs) && offset_requested == 0) { no_results_ = true; } - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist); + SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist, album, album_explicit); return; } @@ -864,7 +880,7 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, ++songs_received; Song song(Song::Source_Tidal); - ParseSong(song, obj_item, artist_id, album_id, album_artist); + ParseSong(song, obj_item, artist_id, album_id, album_artist, album, album_explicit); if (!song.is_valid()) continue; if (song.disc() >= 2) multidisc = true; if (song.is_compilation()) compilation = true; @@ -879,11 +895,11 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, songs_ << song; } - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, songs_received, album_artist); + SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, songs_received, album_artist, album, album_explicit); } -void TidalRequest::SongsFinishCheck(const QString &artist_id, const QString &album_id, const int limit, const int offset, const int songs_total, const int songs_received, const QString &album_artist) { +void TidalRequest::SongsFinishCheck(const QString &artist_id, const QString &album_id, const int limit, const int offset, const int songs_total, const int songs_received, const QString &album_artist, const QString &album, const bool album_explicit) { if (finished_) return; @@ -905,7 +921,7 @@ void TidalRequest::SongsFinishCheck(const QString &artist_id, const QString &alb case QueryType_SearchArtists: case QueryType_Albums: case QueryType_SearchAlbums: - AddAlbumSongsRequest(artist_id, album_id, album_artist, offset_next); + AddAlbumSongsRequest(artist_id, album_id, album_artist, album, album_explicit, offset_next); break; default: break; @@ -935,7 +951,7 @@ void TidalRequest::SongsFinishCheck(const QString &artist_id, const QString &alb } -QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const QString &artist_id_requested, const QString &album_id_requested, const QString &album_artist) { +QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const QString &artist_id_requested, const QString &album_id_requested, const QString &album_artist, const QString&, const bool album_explicit) { Q_UNUSED(artist_id_requested); @@ -1018,6 +1034,7 @@ QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Q return QString(); } QString album = obj_album["title"].toString(); + if (album_explicit) album.append(" (Explicit)"); QString cover = obj_album["cover"].toString(); if (!allow_streaming) { @@ -1283,4 +1300,3 @@ void TidalRequest::Warn(const QString &error, const QVariant &debug) { if (debug.isValid()) qLog(Debug) << debug; } - diff --git a/src/tidal/tidalrequest.h b/src/tidal/tidalrequest.h index 560fc432..2274d1fb 100644 --- a/src/tidal/tidalrequest.h +++ b/src/tidal/tidalrequest.h @@ -50,7 +50,6 @@ class TidalRequest : public TidalBaseRequest { Q_OBJECT public: - explicit TidalRequest(TidalService *service, TidalUrlHandler *url_handler, Application *app, NetworkAccessManager *network, QueryType type, QObject *parent); ~TidalRequest() override; @@ -60,6 +59,25 @@ class TidalRequest : public TidalBaseRequest { void NeedLogin() override { need_login_ = true; } void Search(const int query_id, const QString &search_text); + private: + struct Request { + Request() : offset(0), limit(0), album_explicit(false) {} + QString artist_id; + QString album_id; + QString song_id; + int offset; + int limit; + QString album_artist; + QString album; + bool album_explicit; + }; + struct AlbumCoverRequest { + QString artist_id; + QString album_id; + QUrl url; + QString filename; + }; + signals: void Login(); void Login(QString username, QString password, QString token); @@ -78,32 +96,16 @@ class TidalRequest : public TidalBaseRequest { void AlbumsReceived(QNetworkReply *reply, const QString &artist_id_requested, const int limit_requested, const int offset_requested, const bool auto_login); void SongsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); - void SongsReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int limit_requested, const int offset_requested, const bool auto_login = false, const QString &album_artist = QString()); + void SongsReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int limit_requested, const int offset_requested, const bool auto_login = false, const QString &album_artist = QString(), const QString &album = QString(), const bool album_explicit = false); void ArtistAlbumsReplyReceived(QNetworkReply *reply, const QString &artist_id, const int offset_requested); - void AlbumSongsReplyReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int offset_requested, const QString &album_artist); + void AlbumSongsReplyReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int offset_requested, const QString &album_artist, const QString &album, const bool album_explicit); void AlbumCoverReceived(QNetworkReply *reply, const QString &album_id, const QUrl &url, const QString &filename); public slots: void LoginComplete(const bool success, QString error = QString()); private: - struct Request { - Request() : offset(0), limit(0) {} - QString artist_id; - QString album_id; - QString song_id; - int offset; - int limit; - QString album_artist; - }; - struct AlbumCoverRequest { - QString artist_id; - QString album_id; - QUrl url; - QString filename; - }; - bool IsQuery() { return (type_ == QueryType_Artists || type_ == QueryType_Albums || type_ == QueryType_Songs); } bool IsSearch() { return (type_ == QueryType_SearchArtists || type_ == QueryType_SearchAlbums || type_ == QueryType_SearchSongs); } @@ -127,15 +129,15 @@ class TidalRequest : public TidalBaseRequest { void ArtistsFinishCheck(const int limit = 0, const int offset = 0, const int artists_received = 0); void AlbumsFinishCheck(const QString &artist_id, const int limit = 0, const int offset = 0, const int albums_total = 0, const int albums_received = 0); - void SongsFinishCheck(const QString &artist_id, const QString &album_id, const int limit, const int offset, const int songs_total, const int songs_received, const QString &album_artist); + void SongsFinishCheck(const QString &artist_id, const QString &album_id, const int limit, const int offset, const int songs_total, const int songs_received, const QString &album_artist, const QString &album, const bool album_explicit); void AddArtistAlbumsRequest(const QString &artist_id, const int offset = 0); void FlushArtistAlbumsRequests(); - void AddAlbumSongsRequest(const QString &artist_id, const QString &album_id, const QString &album_artist, const int offset = 0); + void AddAlbumSongsRequest(const QString &artist_id, const QString &album_id, const QString &album_artist, const QString &album, const bool album_explicit, const int offset = 0); void FlushAlbumSongsRequests(); - QString ParseSong(Song &song, const QJsonObject &json_obj, const QString &artist_id_requested = QString(), const QString &album_id_requested = QString(), const QString &album_artist = QString()); + QString ParseSong(Song &song, const QJsonObject &json_obj, const QString &artist_id_requested = QString(), const QString &album_id_requested = QString(), const QString &album_artist = QString(), const QString &album_album = QString(), const bool album_explicit = false); void GetAlbumCovers(); void AddAlbumCoverRequest(Song &song); diff --git a/src/tidal/tidalservice.cpp b/src/tidal/tidalservice.cpp index 954e5081..0256c65c 100644 --- a/src/tidal/tidalservice.cpp +++ b/src/tidal/tidalservice.cpp @@ -104,6 +104,7 @@ TidalService::TidalService(Application *app, QObject *parent) songssearchlimit_(1), fetchalbums_(true), download_album_covers_(true), + album_explicit_(false), expires_in_(0), login_time_(0), pending_search_id_(0), @@ -282,6 +283,7 @@ void TidalService::ReloadSettings() { coversize_ = s.value("coversize", "640x640").toString(); download_album_covers_ = s.value("downloadalbumcovers", true).toBool(); stream_url_method_ = static_cast(s.value("streamurl").toInt()); + album_explicit_ = s.value("album_explicit").toBool(); s.endGroup(); diff --git a/src/tidal/tidalservice.h b/src/tidal/tidalservice.h index 9752a59b..bb534fb3 100644 --- a/src/tidal/tidalservice.h +++ b/src/tidal/tidalservice.h @@ -90,6 +90,7 @@ class TidalService : public InternetService { QString coversize() { return coversize_; } bool download_album_covers() { return download_album_covers_; } TidalSettingsPage::StreamUrlMethod stream_url_method() { return stream_url_method_; } + bool album_explicit() { return album_explicit_; } QString access_token() { return access_token_; } QString session_id() { return session_id_; } @@ -224,6 +225,7 @@ class TidalService : public InternetService { QString coversize_; bool download_album_covers_; TidalSettingsPage::StreamUrlMethod stream_url_method_; + bool album_explicit_; QString access_token_; QString refresh_token_;