diff --git a/src/covermanager/qobuzcoverprovider.cpp b/src/covermanager/qobuzcoverprovider.cpp index e8e9e217..b0e67afc 100644 --- a/src/covermanager/qobuzcoverprovider.cpp +++ b/src/covermanager/qobuzcoverprovider.cpp @@ -46,7 +46,7 @@ #include "jsoncoverprovider.h" #include "qobuzcoverprovider.h" -const int QobuzCoverProvider::kLimit = 10; +constexpr int QobuzCoverProvider::kLimit = 10; QobuzCoverProvider::QobuzCoverProvider(Application *app, NetworkAccessManager *network, QObject *parent) : JsonCoverProvider("Qobuz", true, true, 2.0, true, true, app, network, parent), @@ -93,7 +93,7 @@ bool QobuzCoverProvider::StartSearch(const QString &artist, const QString &album url_query.addQueryItem(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second)); } - QUrl url(QobuzService::kApiUrl + QString("/") + resource); + QUrl url(QString(QobuzService::kApiUrl) + QString("/") + resource); url.setQuery(url_query); QNetworkRequest req(url); diff --git a/src/covermanager/tidalcoverprovider.cpp b/src/covermanager/tidalcoverprovider.cpp index 7bf7d707..7a0da725 100644 --- a/src/covermanager/tidalcoverprovider.cpp +++ b/src/covermanager/tidalcoverprovider.cpp @@ -44,7 +44,7 @@ #include "jsoncoverprovider.h" #include "tidalcoverprovider.h" -const int TidalCoverProvider::kLimit = 10; +constexpr int TidalCoverProvider::kLimit = 10; TidalCoverProvider::TidalCoverProvider(Application *app, NetworkAccessManager *network, QObject *parent) : JsonCoverProvider("Tidal", true, true, 2.5, true, true, app, network, parent), @@ -91,7 +91,7 @@ bool TidalCoverProvider::StartSearch(const QString &artist, const QString &album url_query.addQueryItem(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second)); } - QUrl url(TidalService::kApiUrl + QString("/") + resource); + QUrl url(QString(TidalService::kApiUrl) + QString("/") + resource); url.setQuery(url_query); QNetworkRequest req(url); req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); diff --git a/src/internet/internetservice.h b/src/internet/internetservice.h index 3003ba72..b7f140d3 100644 --- a/src/internet/internetservice.h +++ b/src/internet/internetservice.h @@ -54,9 +54,9 @@ class InternetService : public QObject { virtual bool has_initial_load_settings() const { return false; } virtual void InitialLoadSettings() {} virtual void ReloadSettings() {} - virtual QIcon Icon() { return Song::IconForSource(source_); } - virtual bool oauth() { return false; } - virtual bool authenticated() { return false; } + virtual QIcon Icon() const { return Song::IconForSource(source_); } + virtual bool oauth() const { return false; } + virtual bool authenticated() const { return false; } virtual int Search(const QString &query, InternetSearchView::SearchType type) { Q_UNUSED(query); Q_UNUSED(type); return 0; } virtual void CancelSearch() {} diff --git a/src/qobuz/qobuzbaserequest.cpp b/src/qobuz/qobuzbaserequest.cpp index 5c5c073f..0b376c46 100644 --- a/src/qobuz/qobuzbaserequest.cpp +++ b/src/qobuz/qobuzbaserequest.cpp @@ -60,7 +60,7 @@ QNetworkReply *QobuzBaseRequest::CreateRequest(const QString &ressource_name, co url_query.addQueryItem(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second)); } - QUrl url(QobuzService::kApiUrl + QString("/") + ressource_name); + QUrl url(QString(QobuzService::kApiUrl) + QString("/") + ressource_name); url.setQuery(url_query); QNetworkRequest req(url); req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); diff --git a/src/qobuz/qobuzrequest.cpp b/src/qobuz/qobuzrequest.cpp index 5e9e0276..b5f21cab 100644 --- a/src/qobuz/qobuzrequest.cpp +++ b/src/qobuz/qobuzrequest.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "core/logging.h" #include "core/networkaccessmanager.h" @@ -42,12 +43,13 @@ #include "qobuzbaserequest.h" #include "qobuzrequest.h" -const int QobuzRequest::kMaxConcurrentArtistsRequests = 3; -const int QobuzRequest::kMaxConcurrentAlbumsRequests = 3; -const int QobuzRequest::kMaxConcurrentSongsRequests = 3; -const int QobuzRequest::kMaxConcurrentArtistAlbumsRequests = 3; -const int QobuzRequest::kMaxConcurrentAlbumSongsRequests = 3; -const int QobuzRequest::kMaxConcurrentAlbumCoverRequests = 1; +constexpr int QobuzRequest::kMaxConcurrentArtistsRequests = 3; +constexpr int QobuzRequest::kMaxConcurrentAlbumsRequests = 3; +constexpr int QobuzRequest::kMaxConcurrentSongsRequests = 3; +constexpr int QobuzRequest::kMaxConcurrentArtistAlbumsRequests = 3; +constexpr int QobuzRequest::kMaxConcurrentAlbumSongsRequests = 3; +constexpr int QobuzRequest::kMaxConcurrentAlbumCoverRequests = 1; +constexpr int QobuzRequest::kFlushRequestsDelay = 200; QobuzRequest::QobuzRequest(QobuzService *service, QobuzUrlHandler *url_handler, Application *app, NetworkAccessManager *network, QueryType type, QObject *parent) : QobuzBaseRequest(service, network, parent), @@ -55,24 +57,45 @@ QobuzRequest::QobuzRequest(QobuzService *service, QobuzUrlHandler *url_handler, url_handler_(url_handler), app_(app), network_(network), + timer_flush_requests_(new QTimer(this)), type_(type), query_id_(-1), finished_(false), + artists_requests_total_(0), artists_requests_active_(0), + artists_requests_received_(0), artists_total_(0), artists_received_(0), + albums_requests_total_(0), albums_requests_active_(0), + albums_requests_received_(0), + albums_total_(0), + albums_received_(0), + songs_requests_total_(0), songs_requests_active_(0), + songs_requests_received_(0), + songs_total_(0), + songs_received_(0), + artist_albums_requests_total_(), artist_albums_requests_active_(0), - artist_albums_requested_(0), + artist_albums_requests_received_(0), + artist_albums_total_(0), artist_albums_received_(0), album_songs_requests_active_(0), - album_songs_requested_(0), + album_songs_requests_received_(0), + album_songs_requests_total_(0), + album_songs_total_(0), album_songs_received_(0), - album_covers_requests_active_(), - album_covers_requested_(0), - album_covers_received_(0), - no_results_(false) {} + album_covers_requests_total_(0), + album_covers_requests_active_(0), + album_covers_requests_received_(0), + no_results_(false) { + + timer_flush_requests_->setInterval(kFlushRequestsDelay); + timer_flush_requests_->setSingleShot(false); + QObject::connect(timer_flush_requests_, &QTimer::timeout, this, &QobuzRequest::FlushRequests); + +} QobuzRequest::~QobuzRequest() { @@ -120,6 +143,50 @@ void QobuzRequest::Process() { } +void QobuzRequest::StartRequests() { + + if (!timer_flush_requests_->isActive()) { + timer_flush_requests_->start(); + } + +} + +void QobuzRequest::FlushRequests() { + + if (!artists_requests_queue_.isEmpty()) { + FlushArtistsRequests(); + return; + } + + if (!albums_requests_queue_.isEmpty()) { + FlushAlbumsRequests(); + return; + } + + if (!artist_albums_requests_queue_.isEmpty()) { + FlushArtistAlbumsRequests(); + return; + } + + if (!album_songs_requests_queue_.isEmpty()) { + FlushAlbumSongsRequests(); + return; + } + + if (!songs_requests_queue_.isEmpty()) { + FlushSongsRequests(); + return; + } + + if (!album_cover_requests_queue_.isEmpty()) { + FlushAlbumCoverRequests(); + return; + } + + timer_flush_requests_->stop(); + +} + void QobuzRequest::Search(const int query_id, const QString &search_text) { query_id_ = query_id; search_text_ = search_text; @@ -127,7 +194,7 @@ void QobuzRequest::Search(const int query_id, const QString &search_text) { void QobuzRequest::GetArtists() { - emit UpdateStatus(query_id_, tr("Retrieving artists...")); + emit UpdateStatus(query_id_, tr("Receiving artists...")); emit UpdateProgress(query_id_, 0); AddArtistsRequest(); @@ -139,7 +206,10 @@ void QobuzRequest::AddArtistsRequest(const int offset, const int limit) { request.limit = limit; request.offset = offset; artists_requests_queue_.enqueue(request); - if (artists_requests_active_ < kMaxConcurrentArtistsRequests) FlushArtistsRequests(); + + ++artists_requests_total_; + + StartRequests(); } @@ -148,7 +218,6 @@ void QobuzRequest::FlushArtistsRequests() { while (!artists_requests_queue_.isEmpty() && artists_requests_active_ < kMaxConcurrentArtistsRequests) { Request request = artists_requests_queue_.dequeue(); - ++artists_requests_active_; ParamList params; if (type_ == QueryType_Artists) { @@ -169,13 +238,15 @@ void QobuzRequest::FlushArtistsRequests() { replies_ << reply; QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { ArtistsReplyReceived(reply, request.limit, request.offset); }); + ++artists_requests_active_; + } } void QobuzRequest::GetAlbums() { - emit UpdateStatus(query_id_, tr("Retrieving albums...")); + emit UpdateStatus(query_id_, tr("Receiving albums...")); emit UpdateProgress(query_id_, 0); AddAlbumsRequest(); @@ -187,7 +258,10 @@ void QobuzRequest::AddAlbumsRequest(const int offset, const int limit) { request.limit = limit; request.offset = offset; albums_requests_queue_.enqueue(request); - if (albums_requests_active_ < kMaxConcurrentAlbumsRequests) FlushAlbumsRequests(); + + ++albums_requests_total_; + + StartRequests(); } @@ -196,7 +270,6 @@ void QobuzRequest::FlushAlbumsRequests() { while (!albums_requests_queue_.isEmpty() && albums_requests_active_ < kMaxConcurrentAlbumsRequests) { Request request = albums_requests_queue_.dequeue(); - ++albums_requests_active_; ParamList params; if (type_ == QueryType_Albums) { @@ -217,13 +290,15 @@ void QobuzRequest::FlushAlbumsRequests() { replies_ << reply; QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumsReplyReceived(reply, request.limit, request.offset); }); + ++albums_requests_active_; + } } void QobuzRequest::GetSongs() { - emit UpdateStatus(query_id_, tr("Retrieving songs...")); + emit UpdateStatus(query_id_, tr("Receiving songs...")); emit UpdateProgress(query_id_, 0); AddSongsRequest(); @@ -235,7 +310,10 @@ void QobuzRequest::AddSongsRequest(const int offset, const int limit) { request.limit = limit; request.offset = offset; songs_requests_queue_.enqueue(request); - if (songs_requests_active_ < kMaxConcurrentSongsRequests) FlushSongsRequests(); + + ++songs_requests_total_; + + StartRequests(); } @@ -244,7 +322,6 @@ void QobuzRequest::FlushSongsRequests() { while (!songs_requests_queue_.isEmpty() && songs_requests_active_ < kMaxConcurrentSongsRequests) { Request request = songs_requests_queue_.dequeue(); - ++songs_requests_active_; ParamList params; if (type_ == QueryType_Songs) { @@ -265,6 +342,8 @@ void QobuzRequest::FlushSongsRequests() { replies_ << reply; QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { SongsReplyReceived(reply, request.limit, request.offset); }); + ++songs_requests_active_; + } } @@ -321,6 +400,7 @@ void QobuzRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_re QByteArray data = GetReplyData(reply); --artists_requests_active_; + ++artists_requests_received_; if (finished_) return; @@ -376,8 +456,7 @@ void QobuzRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_re } if (offset_requested == 0) { - emit ProgressSetMaximum(query_id_, artists_total_); - emit UpdateProgress(query_id_, artists_received_); + emit UpdateProgress(query_id_, GetProgress(artists_received_, artists_total_)); } QJsonValue value_items = ExtractItems(obj_artists); @@ -418,20 +497,25 @@ void QobuzRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_re continue; } - QString artist_id; + Artist artist; if (obj_item["id"].isString()) { - artist_id = obj_item["id"].toString(); + artist.artist_id = obj_item["id"].toString(); } else { - artist_id = QString::number(obj_item["id"].toInt()); + artist.artist_id = QString::number(obj_item["id"].toInt()); } - if (artist_albums_requests_pending_.contains(artist_id)) continue; - artist_albums_requests_pending_.append(artist_id); + artist.artist = obj_item["name"].toString(); + + if (artist_albums_requests_pending_.contains(artist.artist_id)) continue; + + ArtistAlbumsRequest request; + request.artist = artist; + artist_albums_requests_pending_.insert(artist.artist_id, request); } artists_received_ += artists_received; - if (offset_requested != 0) emit UpdateProgress(query_id_, artists_received_); + if (offset_requested != 0) emit UpdateProgress(query_id_, GetProgress(artists_received_, artists_total_)); ArtistsFinishCheck(limit_requested, offset, artists_received); @@ -449,21 +533,18 @@ void QobuzRequest::ArtistsFinishCheck(const int limit, const int offset, const i } } - if (!artists_requests_queue_.isEmpty() && artists_requests_active_ < kMaxConcurrentArtistsRequests) FlushArtistsRequests(); - if (artists_requests_queue_.isEmpty() && artists_requests_active_ <= 0) { // Artist query is finished, get all albums for all artists. // Get artist albums - for (const QString &artist_id : artist_albums_requests_pending_) { - AddArtistAlbumsRequest(artist_id); - ++artist_albums_requested_; + QList requests = artist_albums_requests_pending_.values(); + for (const ArtistAlbumsRequest &request : requests) { + AddArtistAlbumsRequest(request.artist); } artist_albums_requests_pending_.clear(); - if (artist_albums_requested_ > 0) { - if (artist_albums_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving albums for %1 artist...").arg(artist_albums_requested_)); - else emit UpdateStatus(query_id_, tr("Retrieving albums for %1 artists...").arg(artist_albums_requested_)); - emit ProgressSetMaximum(query_id_, artist_albums_requested_); + if (artist_albums_requests_total_ > 0) { + if (artist_albums_requests_total_ == 1) emit UpdateStatus(query_id_, tr("Receiving albums for %1 artist...").arg(artist_albums_requests_total_)); + else emit UpdateStatus(query_id_, tr("Receiving albums for %1 artists...").arg(artist_albums_requests_total_)); emit UpdateProgress(query_id_, 0); } @@ -474,18 +555,23 @@ void QobuzRequest::ArtistsFinishCheck(const int limit, const int offset, const i } void QobuzRequest::AlbumsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested) { + --albums_requests_active_; - AlbumsReceived(reply, QString(), limit_requested, offset_requested); - if (!albums_requests_queue_.isEmpty() && albums_requests_active_ < kMaxConcurrentAlbumsRequests) FlushAlbumsRequests(); + ++albums_requests_received_; + AlbumsReceived(reply, Artist(), limit_requested, offset_requested); + } -void QobuzRequest::AddArtistAlbumsRequest(const QString &artist_id, const int offset) { +void QobuzRequest::AddArtistAlbumsRequest(const Artist &artist, const int offset) { - Request request; - request.artist_id = artist_id; + ArtistAlbumsRequest request; + request.artist = artist; request.offset = offset; artist_albums_requests_queue_.enqueue(request); - if (artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) FlushArtistAlbumsRequests(); + + ++artist_albums_requests_total_; + + StartRequests(); } @@ -493,32 +579,32 @@ void QobuzRequest::FlushArtistAlbumsRequests() { while (!artist_albums_requests_queue_.isEmpty() && artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) { - Request request = artist_albums_requests_queue_.dequeue(); - ++artist_albums_requests_active_; + const ArtistAlbumsRequest request = artist_albums_requests_queue_.dequeue(); - ParamList params = ParamList() << Param("artist_id", request.artist_id) + ParamList params = ParamList() << Param("artist_id", request.artist.artist_id) << Param("extra", "albums"); if (request.offset > 0) params << Param("offset", QString::number(request.offset)); QNetworkReply *reply = CreateRequest(QString("artist/get"), params); - QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { ArtistAlbumsReplyReceived(reply, request.artist_id, request.offset); }); + QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { ArtistAlbumsReplyReceived(reply, request.artist, request.offset); }); replies_ << reply; + ++artist_albums_requests_active_; + } } -void QobuzRequest::ArtistAlbumsReplyReceived(QNetworkReply *reply, const QString &artist_id, const int offset_requested) { +void QobuzRequest::ArtistAlbumsReplyReceived(QNetworkReply *reply, const Artist &artist, const int offset_requested) { --artist_albums_requests_active_; - ++artist_albums_received_; - emit UpdateProgress(query_id_, artist_albums_received_); - AlbumsReceived(reply, artist_id, 0, offset_requested); - if (!artist_albums_requests_queue_.isEmpty() && artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) FlushArtistAlbumsRequests(); + ++artist_albums_requests_received_; + emit UpdateProgress(query_id_, GetProgress(artist_albums_requests_received_, artist_albums_requests_total_)); + AlbumsReceived(reply, artist, 0, offset_requested); } -void QobuzRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id_requested, const int limit_requested, const int offset_requested) { +void QobuzRequest::AlbumsReceived(QNetworkReply *reply, const Artist &artist_requested, const int limit_requested, const int offset_requested) { if (!replies_.contains(reply)) return; replies_.removeAll(reply); @@ -530,45 +616,43 @@ void QobuzRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id if (finished_) return; if (data.isEmpty()) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } QJsonObject json_obj = ExtractJsonObj(data); if (json_obj.isEmpty()) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } - QString album_artist_id = artist_id_requested; - if (json_obj.contains("id")) { + Artist artist = artist_requested; + + if (json_obj.contains("id") && json_obj.contains("name")) { if (json_obj["id"].isString()) { - album_artist_id = json_obj["id"].toString(); + artist.artist_id = json_obj["id"].toString(); } else { - album_artist_id = QString::number(json_obj["id"].toInt()); + artist.artist_id = QString::number(json_obj["id"].toInt()); } - } - QString album_artist; - if (json_obj.contains("name")) { - album_artist = json_obj["name"].toString(); + artist.artist = json_obj["name"].toString(); } - if (album_artist_id != artist_id_requested) { - AlbumsFinishCheck(artist_id_requested); - Error("Artist id returned does not match artist id requested.", json_obj); + if (artist.artist_id != artist_requested.artist_id) { + AlbumsFinishCheck(artist_requested); + Error("Artist ID returned does not match artist ID requested.", json_obj); return; } if (!json_obj.contains("albums")) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); Error("Json object is missing albums.", json_obj); return; } QJsonValue value_albums = json_obj["albums"]; if (!value_albums.isObject()) { Error("Json albums is not an object.", json_obj); - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } QJsonObject obj_albums = value_albums.toObject(); @@ -577,7 +661,7 @@ void QobuzRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id !obj_albums.contains("offset") || !obj_albums.contains("total") || !obj_albums.contains("items")) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); Error("Json albums object is missing values.", json_obj); return; } @@ -588,13 +672,13 @@ void QobuzRequest::AlbumsReceived(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)); - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } QJsonValue value_items = ExtractItems(obj_albums); if (!value_items.isArray()) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } QJsonArray array_items = value_items.toArray(); @@ -602,37 +686,36 @@ void QobuzRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id if ((type_ == QueryType_Albums || type_ == QueryType_SearchAlbums) && offset_requested == 0) { no_results_ = true; } - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } int albums_received = 0; - for (const QJsonValueRef value : array_items) { + for (const QJsonValueRef value_item : array_items) { ++albums_received; - if (!value.isObject()) { - Error("Invalid Json reply, item not a object."); + if (!value_item.isObject()) { + Error("Invalid Json reply, item in array is not a object."); continue; } - QJsonObject obj_item = value.toObject(); + QJsonObject obj_item = value_item.toObject(); if (!obj_item.contains("artist") || !obj_item.contains("title") || !obj_item.contains("id")) { Error("Invalid Json reply, item missing artist, title or id.", obj_item); continue; } - QString album_id; + Album album; if (obj_item["id"].isString()) { - album_id = obj_item["id"].toString(); + album.album_id = obj_item["id"].toString(); } else { - album_id = QString::number(obj_item["id"].toInt()); + album.album_id = QString::number(obj_item["id"].toInt()); } + album.album = obj_item["title"].toString(); - if (album_songs_requests_pending_.contains(album_id)) continue; - - QString album = obj_item["title"].toString(); + if (album_songs_requests_pending_.contains(album.album_id)) continue; QJsonValue value_artist = obj_item["artist"]; if (!value_artist.isObject()) { @@ -645,34 +728,37 @@ void QobuzRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id continue; } - QString artist_id; + Artist album_artist; if (obj_artist["id"].isString()) { - artist_id = obj_artist["id"].toString(); + album_artist.artist_id = obj_artist["id"].toString(); } else { - artist_id = QString::number(obj_artist["id"].toInt()); + album_artist.artist_id = QString::number(obj_artist["id"].toInt()); } + album_artist.artist = obj_artist["name"].toString(); - QString artist = obj_artist["name"].toString(); - if (!artist_id_requested.isEmpty() && artist_id != artist_id_requested) { - qLog(Debug) << "Skipping artist" << "artist" << artist << artist_id << "does not match album artist" << album_artist_id << album_artist; + if (!artist_requested.artist_id.isEmpty() && album_artist.artist_id != artist_requested.artist_id) { + qLog(Debug) << "Skipping artist" << album_artist.artist << album_artist.artist_id << "does not match album artist" << artist_requested.artist_id << artist_requested.artist; continue; } - Request request; - request.artist_id = artist_id; - request.album_id = album_id; - request.album_artist = artist; + AlbumSongsRequest request; + request.artist = album_artist; request.album = album; - album_songs_requests_pending_.insert(album_id, request); + album_songs_requests_pending_.insert(album.album_id, request); } - AlbumsFinishCheck(artist_id_requested, limit_requested, offset, albums_total, albums_received); + if (type_ == QueryType_Albums || type_ == QueryType_SearchAlbums) { + albums_received_ += albums_received; + emit UpdateProgress(query_id_, GetProgress(albums_received_, albums_total_)); + } + + AlbumsFinishCheck(artist_requested, limit_requested, offset, albums_total, albums_received); } -void QobuzRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, const int offset, const int albums_total, const int albums_received) { +void QobuzRequest::AlbumsFinishCheck(const Artist &artist, const int limit, const int offset, const int albums_total, const int albums_received) { if (finished_) return; @@ -688,7 +774,7 @@ void QobuzRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, break; case QueryType_Artists: case QueryType_SearchArtists: - AddArtistAlbumsRequest(artist_id, offset_next); + AddArtistAlbumsRequest(artist, offset_next); break; default: break; @@ -697,6 +783,8 @@ void QobuzRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, } if ( + artists_requests_queue_.isEmpty() && + artists_requests_active_ <= 0 && albums_requests_queue_.isEmpty() && albums_requests_active_ <= 0 && artist_albums_requests_queue_.isEmpty() && @@ -705,21 +793,20 @@ void QobuzRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, // Get songs for all the albums. - QHash::iterator it; - for (it = album_songs_requests_pending_.begin(); it != album_songs_requests_pending_.end(); ++it) { - Request request = it.value(); - AddAlbumSongsRequest(request.artist_id, request.album_id, request.album_artist, request.album); + for (QHash::iterator it = album_songs_requests_pending_.begin(); it != album_songs_requests_pending_.end(); ++it) { + const AlbumSongsRequest &request = it.value(); + AddAlbumSongsRequest(request.artist, request.album); } album_songs_requests_pending_.clear(); - if (album_songs_requested_ > 0) { - if (album_songs_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving songs for %1 album...").arg(album_songs_requested_)); - else emit UpdateStatus(query_id_, tr("Retrieving songs for %1 albums...").arg(album_songs_requested_)); - emit ProgressSetMaximum(query_id_, album_songs_requested_); + if (album_songs_requests_total_ > 0) { + if (album_songs_requests_total_ == 1) emit UpdateStatus(query_id_, tr("Receiving songs for %1 album...").arg(album_songs_requests_total_)); + else emit UpdateStatus(query_id_, tr("Receiving songs for %1 albums...").arg(album_songs_requests_total_)); emit UpdateProgress(query_id_, 0); } } + GetAlbumCoversCheck(); FinishCheck(); } @@ -727,21 +814,22 @@ void QobuzRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, void QobuzRequest::SongsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested) { --songs_requests_active_; - SongsReceived(reply, QString(), QString(), limit_requested, offset_requested); + ++songs_requests_received_; + SongsReceived(reply, Artist(), Album(), limit_requested, offset_requested); } -void QobuzRequest::AddAlbumSongsRequest(const QString &artist_id, const QString &album_id, const QString &album_artist, const QString &album, const int offset) { +void QobuzRequest::AddAlbumSongsRequest(const Artist &artist, const Album &album, const int offset) { - Request request; - request.artist_id = artist_id; - request.album_id = album_id; - request.album_artist = album_artist; + AlbumSongsRequest request; + request.artist = artist; request.album = album; request.offset = offset; album_songs_requests_queue_.enqueue(request); - ++album_songs_requested_; - if (album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) FlushAlbumSongsRequests(); + + ++album_songs_requests_total_; + + StartRequests(); } @@ -749,33 +837,35 @@ void QobuzRequest::FlushAlbumSongsRequests() { while (!album_songs_requests_queue_.isEmpty() && album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) { - Request request = album_songs_requests_queue_.dequeue(); - ++album_songs_requests_active_; - ParamList params = ParamList() << Param("album_id", request.album_id); + AlbumSongsRequest request = album_songs_requests_queue_.dequeue(); + ParamList params = ParamList() << Param("album_id", request.album.album_id); if (request.offset > 0) params << Param("offset", QString::number(request.offset)); QNetworkReply *reply = CreateRequest(QString("album/get"), params); replies_ << reply; - QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumSongsReplyReceived(reply, request.artist_id, request.album_id, request.offset, request.album_artist, request.album); }); + QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumSongsReplyReceived(reply, request.artist, request.album, request.offset); }); + + ++album_songs_requests_active_; } } -void QobuzRequest::AlbumSongsReplyReceived(QNetworkReply *reply, const QString &artist_id, const QString &album_id, const int offset_requested, const QString &album_artist, const QString &album) { +void QobuzRequest::AlbumSongsReplyReceived(QNetworkReply *reply, const Artist &artist, const Album &album, const int offset_requested) { --album_songs_requests_active_; - ++album_songs_received_; + ++album_songs_requests_received_; if (offset_requested == 0) { - emit UpdateProgress(query_id_, album_songs_received_); + emit UpdateProgress(query_id_, GetProgress(album_songs_requests_received_, album_songs_requests_total_)); } - SongsReceived(reply, artist_id, album_id, 0, offset_requested, album_artist, album); + SongsReceived(reply, artist, album, 0, offset_requested); } -void QobuzRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id_requested, const QString &album_id_requested, const int limit_requested, const int offset_requested, const QString &album_artist_requested, const QString &album_requested) { +void QobuzRequest::SongsReceived(QNetworkReply *reply, const Artist &artist_requested, const Album &album_requested, const int limit_requested, const int offset_requested) { if (!replies_.contains(reply)) return; replies_.removeAll(reply); + QObject::disconnect(reply, nullptr, this, nullptr); reply->deleteLater(); QByteArray data = GetReplyData(reply); @@ -783,86 +873,80 @@ void QobuzRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id_ if (finished_) return; if (data.isEmpty()) { - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist_requested, album_requested); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); return; } QJsonObject json_obj = ExtractJsonObj(data); if (json_obj.isEmpty()) { - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist_requested, album_requested); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); return; } if (!json_obj.contains("tracks")) { Error("Json object is missing tracks.", json_obj); - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist_requested, album_requested); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); return; } - QString artist_id = artist_id_requested; - QString album_artist = album_artist_requested; - QString album_id = album_id_requested; - QString album = album_requested; - QUrl cover_url; + Artist album_artist = artist_requested; + Album album = album_requested; - if (json_obj.contains("id")) { + if (json_obj.contains("id") && json_obj.contains("title")) { if (json_obj["id"].isString()) { - album_id = json_obj["id"].toString(); + album.album_id = json_obj["id"].toString(); } else { - album_id = QString::number(json_obj["id"].toInt()); + album.album_id = QString::number(json_obj["id"].toInt()); } - } - - if (json_obj.contains("title")) { - album = json_obj["title"].toString(); + album.album = json_obj["title"].toString(); } if (json_obj.contains("artist")) { QJsonValue value_artist = json_obj["artist"]; if (!value_artist.isObject()) { Error("Invalid Json reply, album artist is not a object.", value_artist); - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); return; } QJsonObject obj_artist = value_artist.toObject(); if (!obj_artist.contains("id") || !obj_artist.contains("name")) { Error("Invalid Json reply, album artist is missing id or name.", obj_artist); - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); return; } if (obj_artist["id"].isString()) { - artist_id = obj_artist["id"].toString(); + album_artist.artist_id = obj_artist["id"].toString(); } else { - artist_id = QString::number(obj_artist["id"].toInt()); + album_artist.artist_id = QString::number(obj_artist["id"].toInt()); } - album_artist = obj_artist["name"].toString(); + album_artist.artist = obj_artist["name"].toString(); } if (json_obj.contains("image")) { QJsonValue value_image = json_obj["image"]; if (!value_image.isObject()) { Error("Invalid Json reply, album image is not a object.", value_image); - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); return; } QJsonObject obj_image = value_image.toObject(); if (!obj_image.contains("large")) { Error("Invalid Json reply, album image is missing large.", obj_image); - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); return; } QString album_image = obj_image["large"].toString(); if (!album_image.isEmpty()) { - cover_url = QUrl(album_image); + album.cover_url = QUrl(album_image); } } QJsonValue value_tracks = json_obj["tracks"]; if (!value_tracks.isObject()) { Error("Json tracks is not an object.", json_obj); - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); return; } QJsonObject obj_tracks = value_tracks.toObject(); @@ -871,7 +955,7 @@ void QobuzRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id_ !obj_tracks.contains("offset") || !obj_tracks.contains("total") || !obj_tracks.contains("items")) { - SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album); + SongsFinishCheck(artist_requested, album_requested, limit_requested, offset_requested); Error("Json songs object is missing values.", json_obj); return; } @@ -882,13 +966,13 @@ void QobuzRequest::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, album); + SongsFinishCheck(album_artist, album, limit_requested, offset_requested, songs_total); return; } QJsonValue value_items = ExtractItems(obj_tracks); if (!value_items.isArray()) { - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist, album); + SongsFinishCheck(album_artist, album, limit_requested, offset_requested, songs_total); return; } @@ -897,7 +981,7 @@ void QobuzRequest::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, album); + SongsFinishCheck(album_artist, album, limit_requested, offset_requested, songs_total); return; } @@ -915,7 +999,7 @@ void QobuzRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id_ ++songs_received; Song song(Song::Source_Qobuz); - ParseSong(song, obj_item, artist_id, album_id, album_artist, album, cover_url); + ParseSong(song, obj_item, album_artist, album); if (!song.is_valid()) continue; if (song.disc() >= 2) multidisc = true; if (song.is_compilation()) compilation = true; @@ -928,11 +1012,16 @@ void QobuzRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id_ songs_.insert(song.song_id(), song); } - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, songs_received, album_artist, album); + if (type_ == QueryType_Songs || type_ == QueryType_SearchSongs) { + songs_received_ += songs_received; + emit UpdateProgress(query_id_, GetProgress(songs_received_, songs_total_)); + } + + SongsFinishCheck(album_artist, album, limit_requested, offset_requested, songs_total, songs_received); } -void QobuzRequest::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) { +void QobuzRequest::SongsFinishCheck(const Artist &artist, const Album &album, const int limit, const int offset, const int songs_total, const int songs_received) { if (finished_) return; @@ -950,7 +1039,7 @@ void QobuzRequest::SongsFinishCheck(const QString &artist_id, const QString &alb case QueryType_SearchArtists: case QueryType_Albums: case QueryType_SearchAlbums: - AddAlbumSongsRequest(artist_id, album_id, album_artist, album, offset_next); + AddAlbumSongsRequest(artist, album, offset_next); break; default: break; @@ -958,29 +1047,12 @@ void QobuzRequest::SongsFinishCheck(const QString &artist_id, const QString &alb } } - if (!songs_requests_queue_.isEmpty() && songs_requests_active_ < kMaxConcurrentSongsRequests) FlushSongsRequests(); - if (!album_songs_requests_queue_.isEmpty() && album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) FlushAlbumSongsRequests(); - - if ( - service_->download_album_covers() && - IsQuery() && - songs_requests_queue_.isEmpty() && - songs_requests_active_ <= 0 && - album_songs_requests_queue_.isEmpty() && - album_songs_requests_active_ <= 0 && - album_cover_requests_queue_.isEmpty() && - album_covers_received_ <= 0 && - album_covers_requests_sent_.isEmpty() && - album_songs_received_ >= album_songs_requested_ - ) { - GetAlbumCovers(); - } - + GetAlbumCoversCheck(); FinishCheck(); } -QString QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, QString artist_id, QString album_id, QString album_artist, QString album, QUrl cover_url) { +void QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Artist &album_artist, const Album &album) { if ( !json_obj.contains("id") || @@ -991,7 +1063,7 @@ QString QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, QString !json_obj.contains("streamable") ) { Error("Invalid Json reply, track is missing one or more values.", json_obj); - return QString(); + return; } QString song_id; @@ -1010,62 +1082,64 @@ QString QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, QString QString composer; QString performer; + Artist song_artist = album_artist; + Album song_album = album; if (json_obj.contains("album")) { QJsonValue value_album = json_obj["album"]; if (!value_album.isObject()) { Error("Invalid Json reply, album is not an object.", value_album); - return QString(); + return; } QJsonObject obj_album = value_album.toObject(); if (obj_album.contains("id")) { if (obj_album["id"].isString()) { - album_id = obj_album["id"].toString(); + song_album.album_id = obj_album["id"].toString(); } else { - album_id = QString::number(obj_album["id"].toInt()); + song_album.album_id = QString::number(obj_album["id"].toInt()); } } if (obj_album.contains("title")) { - album = obj_album["title"].toString(); + song_album.album = obj_album["title"].toString(); } if (obj_album.contains("artist")) { QJsonValue value_artist = obj_album["artist"]; if (!value_artist.isObject()) { Error("Invalid Json reply, album artist is not a object.", value_artist); - return QString(); + return; } QJsonObject obj_artist = value_artist.toObject(); if (!obj_artist.contains("id") || !obj_artist.contains("name")) { Error("Invalid Json reply, album artist is missing id or name.", obj_artist); - return QString(); + return; } if (obj_artist["id"].isString()) { - artist_id = obj_artist["id"].toString(); + song_artist.artist_id = obj_artist["id"].toString(); } else { - artist_id = QString::number(obj_artist["id"].toInt()); + song_artist.artist_id = QString::number(obj_artist["id"].toInt()); } - album_artist = obj_artist["name"].toString(); + song_artist.artist = obj_artist["name"].toString(); } if (obj_album.contains("image")) { QJsonValue value_image = obj_album["image"]; if (!value_image.isObject()) { Error("Invalid Json reply, album image is not a object.", value_image); - return QString(); + return; } QJsonObject obj_image = value_image.toObject(); if (!obj_image.contains("large")) { Error("Invalid Json reply, album image is missing large.", obj_image); - return QString(); + return; } QString album_image = obj_image["large"].toString(); if (!album_image.isEmpty()) { - cover_url = QUrl(album_image); + song_album.cover_url.setUrl(album_image); } } } @@ -1074,12 +1148,12 @@ QString QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, QString QJsonValue value_composer = json_obj["composer"]; if (!value_composer.isObject()) { Error("Invalid Json reply, track composer is not a object.", value_composer); - return QString(); + return; } QJsonObject obj_composer = value_composer.toObject(); if (!obj_composer.contains("id") || !obj_composer.contains("name")) { Error("Invalid Json reply, track composer is missing id or name.", obj_composer); - return QString(); + return; } composer = obj_composer["name"].toString(); } @@ -1088,12 +1162,12 @@ QString QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, QString QJsonValue value_performer = json_obj["performer"]; if (!value_performer.isObject()) { Error("Invalid Json reply, track performer is not a object.", value_performer); - return QString(); + return; } QJsonObject obj_performer = value_performer.toObject(); if (!obj_performer.contains("id") || !obj_performer.contains("name")) { Error("Invalid Json reply, track performer is missing id or name.", obj_performer); - return QString(); + return; } performer = obj_performer["name"].toString(); } @@ -1112,15 +1186,18 @@ QString QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, QString song.set_source(Song::Source_Qobuz); song.set_song_id(song_id); - song.set_album_id(album_id); - song.set_artist_id(artist_id); - song.set_album(album); - song.set_artist(album_artist); + song.set_album_id(song_album.album_id); + song.set_artist_id(song_artist.artist_id); + song.set_album(song_album.album); + song.set_artist(song_artist.artist); + if (!album_artist.artist.isEmpty() && album_artist.artist != song_artist.artist) { + song.set_albumartist(album_artist.artist); + } song.set_title(title); song.set_track(track); song.set_url(url); song.set_length_nanosec(duration); - song.set_art_automatic(cover_url); + song.set_art_automatic(song_album.cover_url); song.set_performer(performer); song.set_composer(composer); song.set_comment(copyright); @@ -1131,7 +1208,32 @@ QString QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, QString song.set_ctime(0); song.set_valid(true); - return song_id; +} + +void QobuzRequest::GetAlbumCoversCheck() { + + if ( + !finished_ && + service_->download_album_covers() && + IsQuery() && + artists_requests_queue_.isEmpty() && + albums_requests_queue_.isEmpty() && + songs_requests_queue_.isEmpty() && + artist_albums_requests_queue_.isEmpty() && + album_songs_requests_queue_.isEmpty() && + album_cover_requests_queue_.isEmpty() && + artist_albums_requests_pending_.isEmpty() && + album_songs_requests_pending_.isEmpty() && + album_covers_requests_sent_.isEmpty() && + artists_requests_active_ <= 0 && + albums_requests_active_ <= 0 && + songs_requests_active_ <= 0 && + artist_albums_requests_active_ <= 0 && + album_songs_requests_active_ <= 0 && + album_covers_requests_active_ <= 0 + ) { + GetAlbumCovers(); + } } @@ -1141,13 +1243,13 @@ void QobuzRequest::GetAlbumCovers() { for (const Song &song : songs) { AddAlbumCoverRequest(song); } - FlushAlbumCoverRequests(); - if (album_covers_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving album cover for %1 album...").arg(album_covers_requested_)); - else emit UpdateStatus(query_id_, tr("Retrieving album covers for %1 albums...").arg(album_covers_requested_)); - emit ProgressSetMaximum(query_id_, album_covers_requested_); + if (album_covers_requests_total_ == 1) emit UpdateStatus(query_id_, tr("Receiving album cover for %1 album...").arg(album_covers_requests_total_)); + else emit UpdateStatus(query_id_, tr("Receiving album covers for %1 albums...").arg(album_covers_requests_total_)); emit UpdateProgress(query_id_, 0); + StartRequests(); + } void QobuzRequest::AddAlbumCoverRequest(const Song &song) { @@ -1166,7 +1268,7 @@ void QobuzRequest::AddAlbumCoverRequest(const Song &song) { if (request.filename.isEmpty()) return; album_covers_requests_sent_.insert(cover_url, song.song_id()); - ++album_covers_requested_; + ++album_covers_requests_total_; album_cover_requests_queue_.enqueue(request); @@ -1177,7 +1279,6 @@ void QobuzRequest::FlushAlbumCoverRequests() { while (!album_cover_requests_queue_.isEmpty() && album_covers_requests_active_ < kMaxConcurrentAlbumCoverRequests) { AlbumCoverRequest request = album_cover_requests_queue_.dequeue(); - ++album_covers_requests_active_; QNetworkRequest req(request.url); req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); @@ -1185,6 +1286,8 @@ void QobuzRequest::FlushAlbumCoverRequests() { album_cover_replies_ << reply; QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumCoverReceived(reply, request.url, request.filename); }); + ++album_covers_requests_active_; + } } @@ -1193,6 +1296,7 @@ void QobuzRequest::AlbumCoverReceived(QNetworkReply *reply, const QUrl &cover_ur if (album_cover_replies_.contains(reply)) { album_cover_replies_.removeAll(reply); + QObject::disconnect(reply, nullptr, this, nullptr); reply->deleteLater(); } else { @@ -1201,11 +1305,11 @@ void QobuzRequest::AlbumCoverReceived(QNetworkReply *reply, const QUrl &cover_ur } --album_covers_requests_active_; - ++album_covers_received_; + ++album_covers_requests_received_; if (finished_) return; - emit UpdateProgress(query_id_, album_covers_received_); + emit UpdateProgress(query_id_, GetProgress(album_covers_requests_received_, album_covers_requests_total_)); if (!album_covers_requests_sent_.contains(cover_url)) { AlbumCoverFinishCheck(); @@ -1277,9 +1381,6 @@ void QobuzRequest::AlbumCoverReceived(QNetworkReply *reply, const QUrl &cover_ur void QobuzRequest::AlbumCoverFinishCheck() { - if (!album_cover_requests_queue_.isEmpty() && album_covers_requests_active_ < kMaxConcurrentAlbumCoverRequests) - FlushAlbumCoverRequests(); - FinishCheck(); } @@ -1288,8 +1389,8 @@ void QobuzRequest::FinishCheck() { if ( !finished_ && - albums_requests_queue_.isEmpty() && artists_requests_queue_.isEmpty() && + albums_requests_queue_.isEmpty() && songs_requests_queue_.isEmpty() && artist_albums_requests_queue_.isEmpty() && album_songs_requests_queue_.isEmpty() && @@ -1301,13 +1402,12 @@ void QobuzRequest::FinishCheck() { albums_requests_active_ <= 0 && songs_requests_active_ <= 0 && artist_albums_requests_active_ <= 0 && - artist_albums_received_ >= artist_albums_requested_ && album_songs_requests_active_ <= 0 && - album_songs_received_ >= album_songs_requested_ && - album_covers_requested_ <= album_covers_received_ && - album_covers_requests_active_ <= 0 && - album_covers_received_ >= album_covers_requested_ + album_covers_requests_active_ <= 0 ) { + if (timer_flush_requests_->isActive()) { + timer_flush_requests_->stop(); + } finished_ = true; if (no_results_ && songs_.isEmpty()) { if (IsSearch()) @@ -1325,6 +1425,12 @@ void QobuzRequest::FinishCheck() { } +int QobuzRequest::GetProgress(const int count, const int total) { + + return static_cast((static_cast(count) / static_cast(total)) * 100.0F); + +} + void QobuzRequest::Error(const QString &error, const QVariant &debug) { if (!error.isEmpty()) { diff --git a/src/qobuz/qobuzrequest.h b/src/qobuz/qobuzrequest.h index 6878ce0f..9b3b4ecc 100644 --- a/src/qobuz/qobuzrequest.h +++ b/src/qobuz/qobuzrequest.h @@ -41,6 +41,7 @@ #include "qobuzbaserequest.h" class QNetworkReply; +class QTimer; class Application; class NetworkAccessManager; class QobuzService; @@ -52,19 +53,55 @@ class QobuzRequest : public QobuzBaseRequest { public: explicit QobuzRequest(QobuzService *service, QobuzUrlHandler *url_handler, Application *app, NetworkAccessManager *network, QueryType type, QObject *parent = nullptr); - ~QobuzRequest(); + ~QobuzRequest() override; void ReloadSettings(); void Process(); void Search(const int query_id, const QString &search_text); + private: + struct Artist { + QString artist_id; + QString artist; + }; + struct Album { + Album() : album_explicit(false) {} + QString album_id; + QString album; + QUrl cover_url; + bool album_explicit; + }; + struct Request { + Request() : offset(0), limit(0) {} + int offset; + int limit; + }; + struct ArtistAlbumsRequest { + ArtistAlbumsRequest() : offset(0), limit(0) {} + Artist artist; + int offset; + int limit; + }; + struct AlbumSongsRequest { + AlbumSongsRequest() : offset(0), limit(0) {} + Artist artist; + Album album; + int offset; + int limit; + }; + struct AlbumCoverRequest { + QString artist_id; + QString album_id; + QUrl url; + QString filename; + }; + signals: void LoginSuccess(); void LoginFailure(QString failure_reason); void Results(int id, SongMap songs, QString error); void UpdateStatus(int id, QString text); - void ProgressSetMaximum(int id, int max); void UpdateProgress(int id, int max); void StreamURLFinished(QUrl original_url, QUrl url, Song::FileType, QString error = QString()); @@ -72,35 +109,23 @@ class QobuzRequest : public QobuzBaseRequest { void ArtistsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); void AlbumsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); - void AlbumsReceived(QNetworkReply *reply, const QString &artist_id_requested, const int limit_requested, const int offset_requested); + void AlbumsReceived(QNetworkReply *reply, const Artist &artist_requested, const int limit_requested, const int offset_requested); void SongsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); - void SongsReceived(QNetworkReply *reply, const QString &artist_id_requested, const QString &album_id_requested, const int limit_requested, const int offset_requested, const QString &album_artist_requested = QString(), const QString &album_requested = QString()); + void SongsReceived(QNetworkReply *reply, const Artist &artist_requested, const Album &album_requested, const int limit_requested, const int offset_requested); - 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, const QString &album); + void ArtistAlbumsReplyReceived(QNetworkReply *reply, const Artist &artist, const int offset_requested); + void AlbumSongsReplyReceived(QNetworkReply *reply, const Artist &artist, const Album &album, const int offset_requested); void AlbumCoverReceived(QNetworkReply *reply, const QUrl &cover_url, const QString &filename); private: - struct Request { - Request() : offset(0), limit(0) {} - QString artist_id; - QString album_id; - QString song_id; - int offset; - int limit; - QString album_artist; - QString album; - }; - struct AlbumCoverRequest { - 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); } + void StartRequests(); + void FlushRequests(); + void GetArtists(); void GetAlbums(); void GetSongs(); @@ -120,24 +145,27 @@ class QobuzRequest : public QobuzBaseRequest { void FlushSongsRequests(); 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, const QString &album); + void AlbumsFinishCheck(const Artist &artist, const int limit = 0, const int offset = 0, const int albums_total = 0, const int albums_received = 0); + void SongsFinishCheck(const Artist &artist, const Album &album, const int limit = 0, const int offset = 0, const int songs_total = 0, const int songs_received = 0); - void AddArtistAlbumsRequest(const QString &artist_id, const int offset = 0); + void AddArtistAlbumsRequest(const Artist &artist, const int offset = 0); void FlushArtistAlbumsRequests(); - void AddAlbumSongsRequest(const QString &artist_id, const QString &album_id, const QString &album_artist, const QString &album, const int offset = 0); + void AddAlbumSongsRequest(const Artist &artist, const Album &album, const int offset = 0); void FlushAlbumSongsRequests(); - QString ParseSong(Song &song, const QJsonObject &json_obj, QString artist_id, QString album_id, QString album_artist, QString album, QUrl cover_url); + void ParseSong(Song &song, const QJsonObject &json_obj, const Artist &album_artist, const Album &album); QString AlbumCoverFileName(const Song &song); + void GetAlbumCoversCheck(); void GetAlbumCovers(); void AddAlbumCoverRequest(const Song &song); void FlushAlbumCoverRequests(); void AlbumCoverFinishCheck(); + int GetProgress(const int count, const int total); + void FinishCheck(); static void Warn(const QString &error, const QVariant &debug = QVariant()); void Error(const QString &error, const QVariant &debug = QVariant()) override; @@ -148,13 +176,15 @@ class QobuzRequest : public QobuzBaseRequest { static const int kMaxConcurrentArtistAlbumsRequests; static const int kMaxConcurrentAlbumSongsRequests; static const int kMaxConcurrentAlbumCoverRequests; + static const int kFlushRequestsDelay; QobuzService *service_; QobuzUrlHandler *url_handler_; Application *app_; NetworkAccessManager *network_; + QTimer *timer_flush_requests_; - QueryType type_; + const QueryType type_; int query_id_; QString search_text_; @@ -164,32 +194,47 @@ class QobuzRequest : public QobuzBaseRequest { QQueue albums_requests_queue_; QQueue songs_requests_queue_; - QQueue artist_albums_requests_queue_; - QQueue album_songs_requests_queue_; + QQueue artist_albums_requests_queue_; + QQueue album_songs_requests_queue_; QQueue album_cover_requests_queue_; - QList artist_albums_requests_pending_; - QHash album_songs_requests_pending_; + QHash artist_albums_requests_pending_; + QHash album_songs_requests_pending_; QMultiMap album_covers_requests_sent_; + int artists_requests_total_; int artists_requests_active_; + int artists_requests_received_; int artists_total_; int artists_received_; + int albums_requests_total_; int albums_requests_active_; - int songs_requests_active_; + int albums_requests_received_; + int albums_total_; + int albums_received_; + int songs_requests_total_; + int songs_requests_active_; + int songs_requests_received_; + int songs_total_; + int songs_received_; + + int artist_albums_requests_total_; int artist_albums_requests_active_; - int artist_albums_requested_; + int artist_albums_requests_received_; + int artist_albums_total_; int artist_albums_received_; int album_songs_requests_active_; - int album_songs_requested_; + int album_songs_requests_received_; + int album_songs_requests_total_; + int album_songs_total_; int album_songs_received_; + int album_covers_requests_total_; int album_covers_requests_active_; - int album_covers_requested_; - int album_covers_received_; + int album_covers_requests_received_; SongMap songs_; QStringList errors_; diff --git a/src/qobuz/qobuzservice.cpp b/src/qobuz/qobuzservice.cpp index 6892c434..5df06101 100644 --- a/src/qobuz/qobuzservice.cpp +++ b/src/qobuz/qobuzservice.cpp @@ -57,19 +57,19 @@ #include "settings/settingsdialog.h" #include "settings/qobuzsettingspage.h" -const Song::Source QobuzService::kSource = Song::Source_Qobuz; -const char *QobuzService::kAuthUrl = "https://www.qobuz.com/api.json/0.2/user/login"; -const char *QobuzService::kApiUrl = "https://www.qobuz.com/api.json/0.2"; -const int QobuzService::kLoginAttempts = 2; -const int QobuzService::kTimeResetLoginAttempts = 60000; +constexpr Song::Source QobuzService::kSource = Song::Source_Qobuz; +constexpr char QobuzService::kAuthUrl[] = "https://www.qobuz.com/api.json/0.2/user/login"; +constexpr char QobuzService::kApiUrl[] = "https://www.qobuz.com/api.json/0.2"; +constexpr int QobuzService::kLoginAttempts = 2; +constexpr int QobuzService::kTimeResetLoginAttempts = 60000; -const char *QobuzService::kArtistsSongsTable = "qobuz_artists_songs"; -const char *QobuzService::kAlbumsSongsTable = "qobuz_albums_songs"; -const char *QobuzService::kSongsTable = "qobuz_songs"; +constexpr char QobuzService::kArtistsSongsTable[] = "qobuz_artists_songs"; +constexpr char QobuzService::kAlbumsSongsTable[] = "qobuz_albums_songs"; +constexpr char QobuzService::kSongsTable[] = "qobuz_songs"; -const char *QobuzService::kArtistsSongsFtsTable = "qobuz_artists_songs_fts"; -const char *QobuzService::kAlbumsSongsFtsTable = "qobuz_albums_songs_fts"; -const char *QobuzService::kSongsFtsTable = "qobuz_songs_fts"; +constexpr char QobuzService::kArtistsSongsFtsTable[] = "qobuz_artists_songs_fts"; +constexpr char QobuzService::kAlbumsSongsFtsTable[] = "qobuz_albums_songs_fts"; +constexpr char QobuzService::kSongsFtsTable[] = "qobuz_songs_fts"; QobuzService::QobuzService(Application *app, QObject *parent) : InternetService(Song::Source_Qobuz, "Qobuz", "qobuz", QobuzSettingsPage::kSettingsGroup, SettingsDialog::Page_Qobuz, app, parent), @@ -536,7 +536,6 @@ void QobuzService::GetArtists() { artists_request_.reset(new QobuzRequest(this, url_handler_, app_, network_, QobuzBaseRequest::QueryType_Artists), [](QobuzRequest *request) { request->deleteLater(); }); QObject::connect(artists_request_.get(), &QobuzRequest::Results, this, &QobuzService::ArtistsResultsReceived); QObject::connect(artists_request_.get(), &QobuzRequest::UpdateStatus, this, &QobuzService::ArtistsUpdateStatusReceived); - QObject::connect(artists_request_.get(), &QobuzRequest::ProgressSetMaximum, this, &QobuzService::ArtistsProgressSetMaximumReceived); QObject::connect(artists_request_.get(), &QobuzRequest::UpdateProgress, this, &QobuzService::ArtistsUpdateProgressReceived); artists_request_->Process(); @@ -556,11 +555,6 @@ void QobuzService::ArtistsUpdateStatusReceived(const int id, const QString &text emit ArtistsUpdateStatus(text); } -void QobuzService::ArtistsProgressSetMaximumReceived(const int id, const int max) { - Q_UNUSED(id); - emit ArtistsProgressSetMaximum(max); -} - void QobuzService::ArtistsUpdateProgressReceived(const int id, const int progress) { Q_UNUSED(id); emit ArtistsUpdateProgress(progress); @@ -592,7 +586,6 @@ void QobuzService::GetAlbums() { albums_request_.reset(new QobuzRequest(this, url_handler_, app_, network_, QobuzBaseRequest::QueryType_Albums), [](QobuzRequest *request) { request->deleteLater(); }); QObject::connect(albums_request_.get(), &QobuzRequest::Results, this, &QobuzService::AlbumsResultsReceived); QObject::connect(albums_request_.get(), &QobuzRequest::UpdateStatus, this, &QobuzService::AlbumsUpdateStatusReceived); - QObject::connect(albums_request_.get(), &QobuzRequest::ProgressSetMaximum, this, &QobuzService::AlbumsProgressSetMaximumReceived); QObject::connect(albums_request_.get(), &QobuzRequest::UpdateProgress, this, &QobuzService::AlbumsUpdateProgressReceived); albums_request_->Process(); @@ -612,11 +605,6 @@ void QobuzService::AlbumsUpdateStatusReceived(const int id, const QString &text) emit AlbumsUpdateStatus(text); } -void QobuzService::AlbumsProgressSetMaximumReceived(const int id, const int max) { - Q_UNUSED(id); - emit AlbumsProgressSetMaximum(max); -} - void QobuzService::AlbumsUpdateProgressReceived(const int id, const int progress) { Q_UNUSED(id); emit AlbumsUpdateProgress(progress); @@ -648,7 +636,6 @@ void QobuzService::GetSongs() { songs_request_.reset(new QobuzRequest(this, url_handler_, app_, network_, QobuzBaseRequest::QueryType_Songs), [](QobuzRequest *request) { request->deleteLater(); }); QObject::connect(songs_request_.get(), &QobuzRequest::Results, this, &QobuzService::SongsResultsReceived); QObject::connect(songs_request_.get(), &QobuzRequest::UpdateStatus, this, &QobuzService::SongsUpdateStatusReceived); - QObject::connect(songs_request_.get(), &QobuzRequest::ProgressSetMaximum, this, &QobuzService::SongsProgressSetMaximumReceived); QObject::connect(songs_request_.get(), &QobuzRequest::UpdateProgress, this, &QobuzService::SongsUpdateProgressReceived); songs_request_->Process(); @@ -668,11 +655,6 @@ void QobuzService::SongsUpdateStatusReceived(const int id, const QString &text) emit SongsUpdateStatus(text); } -void QobuzService::SongsProgressSetMaximumReceived(const int id, const int max) { - Q_UNUSED(id); - emit SongsProgressSetMaximum(max); -} - void QobuzService::SongsUpdateProgressReceived(const int id, const int progress) { Q_UNUSED(id); emit SongsUpdateProgress(progress); @@ -734,7 +716,6 @@ void QobuzService::SendSearch() { QObject::connect(search_request_.get(), &QobuzRequest::Results, this, &QobuzService::SearchResultsReceived); QObject::connect(search_request_.get(), &QobuzRequest::UpdateStatus, this, &QobuzService::SearchUpdateStatus); - QObject::connect(search_request_.get(), &QobuzRequest::ProgressSetMaximum, this, &QobuzService::SearchProgressSetMaximum); QObject::connect(search_request_.get(), &QobuzRequest::UpdateProgress, this, &QobuzService::SearchUpdateProgress); search_request_->Search(search_id_, search_text_); diff --git a/src/qobuz/qobuzservice.h b/src/qobuz/qobuzservice.h index 82287af2..b488be65 100644 --- a/src/qobuz/qobuzservice.h +++ b/src/qobuz/qobuzservice.h @@ -61,7 +61,7 @@ class QobuzService : public InternetService { ~QobuzService(); static const Song::Source kSource; - static const char *kApiUrl; + static const char kApiUrl[]; void Exit() override; void ReloadSettings() override; @@ -72,26 +72,26 @@ class QobuzService : public InternetService { int max_login_attempts() { return kLoginAttempts; } - Application *app() { return app_; } - QString app_id() { return app_id_; } - QString app_secret() { return app_secret_; } - QString username() { return username_; } - QString password() { return password_; } - int format() { return format_; } - int search_delay() { return search_delay_; } - int artistssearchlimit() { return artistssearchlimit_; } - int albumssearchlimit() { return albumssearchlimit_; } - int songssearchlimit() { return songssearchlimit_; } - bool download_album_covers() { return download_album_covers_; } + Application *app() const { return app_; } + QString app_id() const { return app_id_; } + QString app_secret() const { return app_secret_; } + QString username() const { return username_; } + QString password() const { return password_; } + int format() const { return format_; } + int search_delay() const { return search_delay_; } + int artistssearchlimit() const { return artistssearchlimit_; } + int albumssearchlimit() const { return albumssearchlimit_; } + int songssearchlimit() const { return songssearchlimit_; } + bool download_album_covers() const { return download_album_covers_; } - QString user_auth_token() { return user_auth_token_; } - qint64 user_id() { return user_id_; } - QString device_id() { return device_id_; } - qint64 credential_id() { return credential_id_; } + QString user_auth_token() const { return user_auth_token_; } + qint64 user_id() const { return user_id_; } + QString device_id() const { return device_id_; } + qint64 credential_id() const { return credential_id_; } - bool authenticated() override { return (!app_id_.isEmpty() && !app_secret_.isEmpty() && !user_auth_token_.isEmpty()); } - bool login_sent() { return login_sent_; } - bool login_attempts() { return login_attempts_; } + bool authenticated() const override { return (!app_id_.isEmpty() && !app_secret_.isEmpty() && !user_auth_token_.isEmpty()); } + bool login_sent() const { return login_sent_; } + bool login_attempts() const { return login_attempts_; } uint GetStreamURL(const QUrl &url, QString &error); @@ -132,9 +132,6 @@ class QobuzService : public InternetService { void ArtistsUpdateStatusReceived(const int id, const QString &text); void AlbumsUpdateStatusReceived(const int id, const QString &text); void SongsUpdateStatusReceived(const int id, const QString &text); - void ArtistsProgressSetMaximumReceived(const int id, const int max); - void AlbumsProgressSetMaximumReceived(const int id, const int max); - void SongsProgressSetMaximumReceived(const int id, const int max); void ArtistsUpdateProgressReceived(const int id, const int progress); void AlbumsUpdateProgressReceived(const int id, const int progress); void SongsUpdateProgressReceived(const int id, const int progress); @@ -149,18 +146,18 @@ class QobuzService : public InternetService { void SendSearch(); void LoginError(const QString &error = QString(), const QVariant &debug = QVariant()); - static const char *kAuthUrl; + static const char kAuthUrl[]; static const int kLoginAttempts; static const int kTimeResetLoginAttempts; - static const char *kArtistsSongsTable; - static const char *kAlbumsSongsTable; - static const char *kSongsTable; + static const char kArtistsSongsTable[]; + static const char kAlbumsSongsTable[]; + static const char kSongsTable[]; - static const char *kArtistsSongsFtsTable; - static const char *kAlbumsSongsFtsTable; - static const char *kSongsFtsTable; + static const char kArtistsSongsFtsTable[]; + static const char kAlbumsSongsFtsTable[]; + static const char kSongsFtsTable[]; Application *app_; NetworkAccessManager *network_; diff --git a/src/tidal/tidalbaserequest.cpp b/src/tidal/tidalbaserequest.cpp index 25efc185..8fe70eaf 100644 --- a/src/tidal/tidalbaserequest.cpp +++ b/src/tidal/tidalbaserequest.cpp @@ -54,7 +54,7 @@ QNetworkReply *TidalBaseRequest::CreateRequest(const QString &ressource_name, co url_query.addQueryItem(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second)); } - QUrl url(TidalService::kApiUrl + QString("/") + ressource_name); + QUrl url(QString(TidalService::kApiUrl) + QString("/") + ressource_name); url.setQuery(url_query); QNetworkRequest req(url); req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); diff --git a/src/tidal/tidalfavoriterequest.cpp b/src/tidal/tidalfavoriterequest.cpp index 56eb9670..3b84cb91 100644 --- a/src/tidal/tidalfavoriterequest.cpp +++ b/src/tidal/tidalfavoriterequest.cpp @@ -141,7 +141,7 @@ void TidalFavoriteRequest::AddFavoritesRequest(const FavoriteType type, const QS url_query.addQueryItem(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second)); } - QUrl url(TidalService::kApiUrl + QString("/") + "users/" + QString::number(service_->user_id()) + "/favorites/" + FavoriteText(type)); + QUrl url(QString(TidalService::kApiUrl) + QString("/") + "users/" + QString::number(service_->user_id()) + "/favorites/" + FavoriteText(type)); QNetworkRequest req(url); req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); @@ -250,7 +250,7 @@ void TidalFavoriteRequest::RemoveFavoritesRequest(const FavoriteType type, const url_query.addQueryItem(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second)); } - QUrl url(TidalService::kApiUrl + QString("/") + "users/" + QString::number(service_->user_id()) + "/favorites/" + FavoriteText(type) + QString("/") + id); + QUrl url(QString(TidalService::kApiUrl) + QString("/") + "users/" + QString::number(service_->user_id()) + "/favorites/" + FavoriteText(type) + QString("/") + id); url.setQuery(url_query); QNetworkRequest req(url); #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) diff --git a/src/tidal/tidalrequest.cpp b/src/tidal/tidalrequest.cpp index 83b81006..30f915d5 100644 --- a/src/tidal/tidalrequest.cpp +++ b/src/tidal/tidalrequest.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "core/logging.h" #include "core/networkaccessmanager.h" @@ -42,13 +43,14 @@ #include "tidalbaserequest.h" #include "tidalrequest.h" -const char *TidalRequest::kResourcesUrl = "https://resources.tidal.com"; -const int TidalRequest::kMaxConcurrentArtistsRequests = 3; -const int TidalRequest::kMaxConcurrentAlbumsRequests = 3; -const int TidalRequest::kMaxConcurrentSongsRequests = 3; -const int TidalRequest::kMaxConcurrentArtistAlbumsRequests = 3; -const int TidalRequest::kMaxConcurrentAlbumSongsRequests = 3; -const int TidalRequest::kMaxConcurrentAlbumCoverRequests = 1; +constexpr char TidalRequest::kResourcesUrl[] = "https://resources.tidal.com"; +constexpr int TidalRequest::kMaxConcurrentArtistsRequests = 3; +constexpr int TidalRequest::kMaxConcurrentAlbumsRequests = 3; +constexpr int TidalRequest::kMaxConcurrentSongsRequests = 3; +constexpr int TidalRequest::kMaxConcurrentArtistAlbumsRequests = 3; +constexpr int TidalRequest::kMaxConcurrentAlbumSongsRequests = 3; +constexpr int TidalRequest::kMaxConcurrentAlbumCoverRequests = 1; +constexpr int TidalRequest::kFlushRequestsDelay = 200; TidalRequest::TidalRequest(TidalService *service, TidalUrlHandler *url_handler, Application *app, NetworkAccessManager *network, QueryType type, QObject *parent) : TidalBaseRequest(service, network, parent), @@ -56,26 +58,47 @@ TidalRequest::TidalRequest(TidalService *service, TidalUrlHandler *url_handler, url_handler_(url_handler), app_(app), network_(network), + timer_flush_requests_(new QTimer(this)), type_(type), fetchalbums_(service->fetchalbums()), - coversize_(service_->coversize()), + coversize_(service->coversize()), query_id_(-1), finished_(false), + artists_requests_total_(0), artists_requests_active_(0), + artists_requests_received_(0), artists_total_(0), artists_received_(0), + albums_requests_total_(0), albums_requests_active_(0), + albums_requests_received_(0), + albums_total_(0), + albums_received_(0), + songs_requests_total_(0), songs_requests_active_(0), + songs_requests_received_(0), + songs_total_(0), + songs_received_(0), + artist_albums_requests_total_(), artist_albums_requests_active_(0), - artist_albums_requested_(0), + artist_albums_requests_received_(0), + artist_albums_total_(0), artist_albums_received_(0), album_songs_requests_active_(0), - album_songs_requested_(0), + album_songs_requests_received_(0), + album_songs_requests_total_(0), + album_songs_total_(0), album_songs_received_(0), - album_covers_requests_active_(), - album_covers_requested_(0), - album_covers_received_(0), - need_login_(false) {} + album_covers_requests_total_(0), + album_covers_requests_active_(0), + album_covers_requests_received_(0), + need_login_(false) { + + timer_flush_requests_->setInterval(kFlushRequestsDelay); + timer_flush_requests_->setSingleShot(false); + QObject::connect(timer_flush_requests_, &QTimer::timeout, this, &TidalRequest::FlushRequests); + +} TidalRequest::~TidalRequest() { @@ -144,6 +167,50 @@ void TidalRequest::Process() { } +void TidalRequest::StartRequests() { + + if (!timer_flush_requests_->isActive()) { + timer_flush_requests_->start(); + } + +} + +void TidalRequest::FlushRequests() { + + if (!artists_requests_queue_.isEmpty()) { + FlushArtistsRequests(); + return; + } + + if (!albums_requests_queue_.isEmpty()) { + FlushAlbumsRequests(); + return; + } + + if (!artist_albums_requests_queue_.isEmpty()) { + FlushArtistAlbumsRequests(); + return; + } + + if (!album_songs_requests_queue_.isEmpty()) { + FlushAlbumSongsRequests(); + return; + } + + if (!songs_requests_queue_.isEmpty()) { + FlushSongsRequests(); + return; + } + + if (!album_cover_requests_queue_.isEmpty()) { + FlushAlbumCoverRequests(); + return; + } + + timer_flush_requests_->stop(); + +} + void TidalRequest::Search(const int query_id, const QString &search_text) { query_id_ = query_id; search_text_ = search_text; @@ -151,7 +218,7 @@ void TidalRequest::Search(const int query_id, const QString &search_text) { void TidalRequest::GetArtists() { - emit UpdateStatus(query_id_, tr("Retrieving artists...")); + emit UpdateStatus(query_id_, tr("Receiving artists...")); emit UpdateProgress(query_id_, 0); AddArtistsRequest(); @@ -163,7 +230,10 @@ void TidalRequest::AddArtistsRequest(const int offset, const int limit) { request.limit = limit; request.offset = offset; artists_requests_queue_.enqueue(request); - if (artists_requests_active_ < kMaxConcurrentArtistsRequests) FlushArtistsRequests(); + + ++artists_requests_total_; + + StartRequests(); } @@ -172,13 +242,12 @@ void TidalRequest::FlushArtistsRequests() { while (!artists_requests_queue_.isEmpty() && artists_requests_active_ < kMaxConcurrentArtistsRequests) { Request request = artists_requests_queue_.dequeue(); - ++artists_requests_active_; ParamList parameters; if (type_ == QueryType_SearchArtists) parameters << Param("query", search_text_); if (request.limit > 0) parameters << Param("limit", QString::number(request.limit)); if (request.offset > 0) parameters << Param("offset", QString::number(request.offset)); - QNetworkReply *reply(nullptr); + QNetworkReply *reply = nullptr; if (type_ == QueryType_Artists) { reply = CreateRequest(QString("users/%1/favorites/artists").arg(service_->user_id()), parameters); } @@ -189,13 +258,15 @@ void TidalRequest::FlushArtistsRequests() { replies_ << reply; QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { ArtistsReplyReceived(reply, request.limit, request.offset); }); + ++artists_requests_active_; + } } void TidalRequest::GetAlbums() { - emit UpdateStatus(query_id_, tr("Retrieving albums...")); + emit UpdateStatus(query_id_, tr("Receiving albums...")); emit UpdateProgress(query_id_, 0); AddAlbumsRequest(); @@ -207,7 +278,10 @@ void TidalRequest::AddAlbumsRequest(const int offset, const int limit) { request.limit = limit; request.offset = offset; albums_requests_queue_.enqueue(request); - if (albums_requests_active_ < kMaxConcurrentAlbumsRequests) FlushAlbumsRequests(); + + ++albums_requests_total_; + + StartRequests(); } @@ -216,13 +290,12 @@ void TidalRequest::FlushAlbumsRequests() { while (!albums_requests_queue_.isEmpty() && albums_requests_active_ < kMaxConcurrentAlbumsRequests) { Request request = albums_requests_queue_.dequeue(); - ++albums_requests_active_; ParamList parameters; if (type_ == QueryType_SearchAlbums) parameters << Param("query", search_text_); if (request.limit > 0) parameters << Param("limit", QString::number(request.limit)); if (request.offset > 0) parameters << Param("offset", QString::number(request.offset)); - QNetworkReply *reply(nullptr); + QNetworkReply *reply = nullptr; if (type_ == QueryType_Albums) { reply = CreateRequest(QString("users/%1/favorites/albums").arg(service_->user_id()), parameters); } @@ -233,13 +306,15 @@ void TidalRequest::FlushAlbumsRequests() { replies_ << reply; QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumsReplyReceived(reply, request.limit, request.offset); }); + ++albums_requests_active_; + } } void TidalRequest::GetSongs() { - emit UpdateStatus(query_id_, tr("Retrieving songs...")); + emit UpdateStatus(query_id_, tr("Receiving songs...")); emit UpdateProgress(query_id_, 0); AddSongsRequest(); @@ -251,7 +326,10 @@ void TidalRequest::AddSongsRequest(const int offset, const int limit) { request.limit = limit; request.offset = offset; songs_requests_queue_.enqueue(request); - if (songs_requests_active_ < kMaxConcurrentSongsRequests) FlushSongsRequests(); + + ++songs_requests_total_; + + StartRequests(); } @@ -260,13 +338,12 @@ void TidalRequest::FlushSongsRequests() { while (!songs_requests_queue_.isEmpty() && songs_requests_active_ < kMaxConcurrentSongsRequests) { Request request = songs_requests_queue_.dequeue(); - ++songs_requests_active_; ParamList parameters; if (type_ == QueryType_SearchSongs) parameters << Param("query", search_text_); if (request.limit > 0) parameters << Param("limit", QString::number(request.limit)); if (request.offset > 0) parameters << Param("offset", QString::number(request.offset)); - QNetworkReply *reply(nullptr); + QNetworkReply *reply = nullptr; if (type_ == QueryType_Songs) { reply = CreateRequest(QString("users/%1/favorites/tracks").arg(service_->user_id()), parameters); } @@ -277,6 +354,8 @@ void TidalRequest::FlushSongsRequests() { replies_ << reply; QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { SongsReplyReceived(reply, request.limit, request.offset); }); + ++songs_requests_active_; + } } @@ -333,6 +412,7 @@ void TidalRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_re QByteArray data = GetReplyData(reply, (offset_requested == 0)); --artists_requests_active_; + ++artists_requests_received_; if (finished_) return; @@ -351,8 +431,8 @@ void TidalRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_re !json_obj.contains("offset") || !json_obj.contains("totalNumberOfItems") || !json_obj.contains("items")) { - ArtistsFinishCheck(); Error("Json object missing values.", json_obj); + ArtistsFinishCheck(); return; } //int limit = json_obj["limit"].toInt(); @@ -375,8 +455,7 @@ void TidalRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_re } if (offset_requested == 0) { - emit ProgressSetMaximum(query_id_, artists_total_); - emit UpdateProgress(query_id_, artists_received_); + emit UpdateProgress(query_id_, GetProgress(artists_received_, artists_total_)); } QJsonValue value_items = ExtractItems(json_obj); @@ -416,20 +495,25 @@ void TidalRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_re continue; } - QString artist_id; + Artist artist; if (obj_item["id"].isString()) { - artist_id = obj_item["id"].toString(); + artist.artist_id = obj_item["id"].toString(); } else { - artist_id = QString::number(obj_item["id"].toInt()); + artist.artist_id = QString::number(obj_item["id"].toInt()); } - if (artist_albums_requests_pending_.contains(artist_id)) continue; - artist_albums_requests_pending_.append(artist_id); + artist.artist = obj_item["name"].toString(); + + if (artist_albums_requests_pending_.contains(artist.artist_id)) continue; + + ArtistAlbumsRequest request; + request.artist = artist; + artist_albums_requests_pending_.insert(artist.artist_id, request); } artists_received_ += artists_received; - if (offset_requested != 0) emit UpdateProgress(query_id_, artists_received_); + if (offset_requested != 0) emit UpdateProgress(query_id_, GetProgress(artists_received_, artists_total_)); ArtistsFinishCheck(limit_requested, offset, artists_received); @@ -447,21 +531,18 @@ void TidalRequest::ArtistsFinishCheck(const int limit, const int offset, const i } } - if (!artists_requests_queue_.isEmpty() && artists_requests_active_ < kMaxConcurrentArtistsRequests) FlushArtistsRequests(); - if (artists_requests_queue_.isEmpty() && artists_requests_active_ <= 0) { // Artist query is finished, get all albums for all artists. // Get artist albums - for (const QString &artist_id : artist_albums_requests_pending_) { - AddArtistAlbumsRequest(artist_id); - ++artist_albums_requested_; + QList requests = artist_albums_requests_pending_.values(); + for (const ArtistAlbumsRequest &request : requests) { + AddArtistAlbumsRequest(request.artist); } artist_albums_requests_pending_.clear(); - if (artist_albums_requested_ > 0) { - if (artist_albums_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving albums for %1 artist...").arg(artist_albums_requested_)); - else emit UpdateStatus(query_id_, tr("Retrieving albums for %1 artists...").arg(artist_albums_requested_)); - emit ProgressSetMaximum(query_id_, artist_albums_requested_); + if (artist_albums_requests_total_ > 0) { + if (artist_albums_requests_total_ == 1) emit UpdateStatus(query_id_, tr("Receiving albums for %1 artist...").arg(artist_albums_requests_total_)); + else emit UpdateStatus(query_id_, tr("Receiving albums for %1 artists...").arg(artist_albums_requests_total_)); emit UpdateProgress(query_id_, 0); } @@ -472,18 +553,23 @@ void TidalRequest::ArtistsFinishCheck(const int limit, const int offset, const i } void TidalRequest::AlbumsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested) { + --albums_requests_active_; - AlbumsReceived(reply, QString(), limit_requested, offset_requested, (offset_requested == 0)); - if (!albums_requests_queue_.isEmpty() && albums_requests_active_ < kMaxConcurrentAlbumsRequests) FlushAlbumsRequests(); + ++albums_requests_received_; + AlbumsReceived(reply, Artist(), limit_requested, offset_requested, offset_requested == 0); + } -void TidalRequest::AddArtistAlbumsRequest(const QString &artist_id, const int offset) { +void TidalRequest::AddArtistAlbumsRequest(const Artist &artist, const int offset) { - Request request; - request.artist_id = artist_id; + ArtistAlbumsRequest request; + request.artist = artist; request.offset = offset; artist_albums_requests_queue_.enqueue(request); - if (artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) FlushArtistAlbumsRequests(); + + ++artist_albums_requests_total_; + + StartRequests(); } @@ -491,30 +577,30 @@ void TidalRequest::FlushArtistAlbumsRequests() { while (!artist_albums_requests_queue_.isEmpty() && artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) { - Request request = artist_albums_requests_queue_.dequeue(); - ++artist_albums_requests_active_; + const ArtistAlbumsRequest request = artist_albums_requests_queue_.dequeue(); ParamList parameters; if (request.offset > 0) parameters << Param("offset", QString::number(request.offset)); - QNetworkReply *reply = CreateRequest(QString("artists/%1/albums").arg(request.artist_id), parameters); - QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { ArtistAlbumsReplyReceived(reply, request.artist_id, request.offset); }); + QNetworkReply *reply = CreateRequest(QString("artists/%1/albums").arg(request.artist.artist_id), parameters); + QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { ArtistAlbumsReplyReceived(reply, request.artist, request.offset); }); replies_ << reply; + ++artist_albums_requests_active_; + } } -void TidalRequest::ArtistAlbumsReplyReceived(QNetworkReply *reply, const QString &artist_id, const int offset_requested) { +void TidalRequest::ArtistAlbumsReplyReceived(QNetworkReply *reply, const Artist &artist, const int offset_requested) { --artist_albums_requests_active_; - ++artist_albums_received_; - emit UpdateProgress(query_id_, artist_albums_received_); - AlbumsReceived(reply, artist_id, 0, offset_requested, false); - if (!artist_albums_requests_queue_.isEmpty() && artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) FlushArtistAlbumsRequests(); + ++artist_albums_requests_received_; + emit UpdateProgress(query_id_, GetProgress(artist_albums_requests_received_, artist_albums_requests_total_)); + AlbumsReceived(reply, artist, 0, offset_requested, false); } -void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id_requested, const int limit_requested, const int offset_requested, const bool auto_login) { +void TidalRequest::AlbumsReceived(QNetworkReply *reply, const Artist &artist_requested, const int limit_requested, const int offset_requested, const bool auto_login) { if (!replies_.contains(reply)) return; replies_.removeAll(reply); @@ -526,13 +612,13 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id if (finished_) return; if (data.isEmpty()) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } QJsonObject json_obj = ExtractJsonObj(data); if (json_obj.isEmpty()) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } @@ -541,7 +627,7 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id !json_obj.contains("totalNumberOfItems") || !json_obj.contains("items")) { Error("Json object missing values.", json_obj); - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } @@ -551,18 +637,18 @@ void TidalRequest::AlbumsReceived(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)); - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } QJsonValue value_items = ExtractItems(json_obj); if (!value_items.isArray()) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } QJsonArray array_items = value_items.toArray(); if (array_items.isEmpty()) { - AlbumsFinishCheck(artist_id_requested); + AlbumsFinishCheck(artist_requested); return; } @@ -586,25 +672,23 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id obj_item = json_item.toObject(); } - QString album_id; - QString album; - bool album_explicit = false; + Album album; if (obj_item.contains("type")) { // This was an 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); continue; } if (obj_item["id"].isString()) { - album_id = obj_item["id"].toString(); + album.album_id = obj_item["id"].toString(); } else { - album_id = QString::number(obj_item["id"].toInt()); + album.album_id = QString::number(obj_item["id"].toInt()); } - album = obj_item["title"].toString(); + album.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)"); + album.album_explicit = obj_item["explicit"].toVariant().toBool(); + if (album.album_explicit && !album.album.isEmpty()) { + album.album.append(" (Explicit)"); } } } @@ -620,16 +704,16 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id continue; } if (obj_album["id"].isString()) { - album_id = obj_album["id"].toString(); + album.album_id = obj_album["id"].toString(); } else { - album_id = QString::number(obj_album["id"].toInt()); + album.album_id = QString::number(obj_album["id"].toInt()); } - album = obj_album["title"].toString(); + album.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)"); + album.album_explicit = obj_album["explicit"].toVariant().toBool(); + if (album.album_explicit && !album.album.isEmpty()) { + album.album.append(" (Explicit)"); } } } @@ -638,7 +722,7 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id continue; } - if (album_songs_requests_pending_.contains(album_id)) continue; + if (album_songs_requests_pending_.contains(album.album_id)) continue; if (!obj_item.contains("artist") || !obj_item.contains("title") || !obj_item.contains("audioQuality")) { Error("Invalid Json reply, item missing artist, title or audioQuality.", obj_item); @@ -655,40 +739,37 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id continue; } - QString artist_id; + Artist album_artist; if (obj_artist["id"].isString()) { - artist_id = obj_artist["id"].toString(); + album_artist.artist_id = obj_artist["id"].toString(); } else { - artist_id = QString::number(obj_artist["id"].toInt()); + album_artist.artist_id = QString::number(obj_artist["id"].toInt()); } - QString artist = obj_artist["name"].toString(); + album_artist.artist = obj_artist["name"].toString(); //QString quality = obj_item["audioQuality"].toString(); //QString copyright = obj_item["copyright"].toString(); //qLog(Debug) << "Tidal:" << artist << album << quality << copyright; - Request request; - if (artist_id_requested.isEmpty()) { - request.artist_id = artist_id; - } - else { - request.artist_id = artist_id_requested; - } - request.album_id = album_id; - request.album_artist = artist; + AlbumSongsRequest request; + request.artist = album_artist; request.album = album; - request.album_explicit = album_explicit; - album_songs_requests_pending_.insert(album_id, request); + album_songs_requests_pending_.insert(album.album_id, request); } - AlbumsFinishCheck(artist_id_requested, limit_requested, offset, albums_total, albums_received); + if (type_ == QueryType_Albums || type_ == QueryType_SearchAlbums) { + albums_received_ += albums_received; + emit UpdateProgress(query_id_, GetProgress(albums_received_, albums_total_)); + } + + AlbumsFinishCheck(artist_requested, limit_requested, offset, albums_total, albums_received); } -void TidalRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, const int offset, const int albums_total, const int albums_received) { +void TidalRequest::AlbumsFinishCheck(const Artist &artist, const int limit, const int offset, const int albums_total, const int albums_received) { if (finished_) return; @@ -704,7 +785,7 @@ void TidalRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, break; case QueryType_Artists: case QueryType_SearchArtists: - AddArtistAlbumsRequest(artist_id, offset_next); + AddArtistAlbumsRequest(artist, offset_next); break; default: break; @@ -713,6 +794,8 @@ void TidalRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, } if ( + artists_requests_queue_.isEmpty() && + artists_requests_active_ <= 0 && albums_requests_queue_.isEmpty() && albums_requests_active_ <= 0 && artist_albums_requests_queue_.isEmpty() && @@ -721,20 +804,20 @@ void TidalRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, // Get songs for all the albums. - for (QHash ::iterator it = album_songs_requests_pending_.begin(); it != album_songs_requests_pending_.end(); ++it) { - Request request = it.value(); - AddAlbumSongsRequest(request.artist_id, request.album_id, request.album_artist, request.album, request.album_explicit); + for (QHash::iterator it = album_songs_requests_pending_.begin(); it != album_songs_requests_pending_.end(); ++it) { + const AlbumSongsRequest &request = it.value(); + AddAlbumSongsRequest(request.artist, request.album); } album_songs_requests_pending_.clear(); - if (album_songs_requested_ > 0) { - if (album_songs_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving songs for %1 album...").arg(album_songs_requested_)); - else emit UpdateStatus(query_id_, tr("Retrieving songs for %1 albums...").arg(album_songs_requested_)); - emit ProgressSetMaximum(query_id_, album_songs_requested_); + if (album_songs_requests_total_ > 0) { + if (album_songs_requests_total_ == 1) emit UpdateStatus(query_id_, tr("Receiving songs for %1 album...").arg(album_songs_requests_total_)); + else emit UpdateStatus(query_id_, tr("Receiving songs for %1 albums...").arg(album_songs_requests_total_)); emit UpdateProgress(query_id_, 0); } } + GetAlbumCoversCheck(); FinishCheck(); } @@ -742,27 +825,27 @@ void TidalRequest::AlbumsFinishCheck(const QString &artist_id, const int limit, void TidalRequest::SongsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested) { --songs_requests_active_; + ++songs_requests_received_; if (type_ == QueryType_SearchSongs && fetchalbums_) { - AlbumsReceived(reply, QString(), limit_requested, offset_requested, (offset_requested == 0)); + AlbumsReceived(reply, Artist(), limit_requested, offset_requested, offset_requested == 0); } else { - SongsReceived(reply, QString(), QString(), limit_requested, offset_requested, (offset_requested == 0)); + SongsReceived(reply, Artist(), Album(), limit_requested, offset_requested, offset_requested == 0); } } -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) { +void TidalRequest::AddAlbumSongsRequest(const Artist &artist, const Album &album, const int offset) { - Request request; - request.artist_id = artist_id; - request.album_id = album_id; - request.album_artist = album_artist; + AlbumSongsRequest request; + request.artist = artist; request.album = album; - request.album_explicit = album_explicit; request.offset = offset; album_songs_requests_queue_.enqueue(request); - ++album_songs_requested_; - if (album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) FlushAlbumSongsRequests(); + + ++album_songs_requests_total_; + + StartRequests(); } @@ -770,30 +853,31 @@ void TidalRequest::FlushAlbumSongsRequests() { while (!album_songs_requests_queue_.isEmpty() && album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) { - Request request = album_songs_requests_queue_.dequeue(); - ++album_songs_requests_active_; + AlbumSongsRequest request = album_songs_requests_queue_.dequeue(); ParamList parameters; if (request.offset > 0) parameters << Param("offset", QString::number(request.offset)); - QNetworkReply *reply = CreateRequest(QString("albums/%1/tracks").arg(request.album_id), parameters); + QNetworkReply *reply = CreateRequest(QString("albums/%1/tracks").arg(request.album.album_id), parameters); replies_ << reply; - QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumSongsReplyReceived(reply, request.artist_id, request.album_id, request.offset, request.album_artist, request.album, request.album_explicit); }); + QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumSongsReplyReceived(reply, request.artist, request.album, request.offset); }); + + ++album_songs_requests_active_; } } -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) { +void TidalRequest::AlbumSongsReplyReceived(QNetworkReply *reply, const Artist &artist, const Album &album, const int offset_requested) { --album_songs_requests_active_; - ++album_songs_received_; + ++album_songs_requests_received_; if (offset_requested == 0) { - emit UpdateProgress(query_id_, album_songs_received_); + emit UpdateProgress(query_id_, GetProgress(album_songs_requests_received_, album_songs_requests_total_)); } - SongsReceived(reply, artist_id, album_id, 0, offset_requested, false, album_artist, album, album_explicit); + SongsReceived(reply, artist, album, 0, offset_requested, false); } -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) { +void TidalRequest::SongsReceived(QNetworkReply *reply, const Artist &artist, const Album &album, const int limit_requested, const int offset_requested, const bool auto_login) { if (!replies_.contains(reply)) return; replies_.removeAll(reply); @@ -805,13 +889,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, album, album_explicit); + SongsFinishCheck(artist, album, limit_requested, offset_requested); return; } QJsonObject json_obj = ExtractJsonObj(data); if (json_obj.isEmpty()) { - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, 0, 0, album_artist, album, album_explicit); + SongsFinishCheck(artist, album, limit_requested, offset_requested); return; } @@ -820,7 +904,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, album, album_explicit); + SongsFinishCheck(artist, album, limit_requested, offset_requested); return; } @@ -830,19 +914,19 @@ 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, album, album_explicit); + SongsFinishCheck(artist, album, limit_requested, offset_requested, songs_total, 0); 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, album, album_explicit); + SongsFinishCheck(artist, album, limit_requested, offset_requested, songs_total, 0); return; } - QJsonArray json_items = json_value.toArray(); - if (json_items.isEmpty()) { - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist, album, album_explicit); + QJsonArray array_items = json_value.toArray(); + if (array_items.isEmpty()) { + SongsFinishCheck(artist, album, limit_requested, offset_requested, songs_total, 0); return; } @@ -850,7 +934,7 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, bool multidisc = false; SongList songs; int songs_received = 0; - for (const QJsonValueRef value_item : json_items) { + for (const QJsonValueRef value_item : array_items) { if (!value_item.isObject()) { Error("Invalid Json reply, track is not a object."); @@ -869,7 +953,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, album, album_explicit); + ParseSong(song, obj_item, artist, album); if (!song.is_valid()) continue; if (song.disc() >= 2) multidisc = true; if (song.is_compilation()) compilation = true; @@ -882,11 +966,16 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id, songs_.insert(song.song_id(), song); } - SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, songs_received, album_artist, album, album_explicit); + if (type_ == QueryType_Songs || type_ == QueryType_SearchSongs) { + songs_received_ += songs_received; + emit UpdateProgress(query_id_, GetProgress(songs_received_, songs_total_)); + } + + SongsFinishCheck(artist, album, limit_requested, offset_requested, songs_total, songs_received); } -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) { +void TidalRequest::SongsFinishCheck(const Artist &artist, const Album &album, const int limit, const int offset, const int songs_total, const int songs_received) { if (finished_) return; @@ -899,7 +988,7 @@ void TidalRequest::SongsFinishCheck(const QString &artist_id, const QString &alb break; case QueryType_SearchSongs: // If artist_id and album_id isn't zero it means that it's a songs search where we fetch all albums too. So fallthrough. - if (artist_id.isEmpty() && album_id.isEmpty()) { + if (artist.artist_id.isEmpty() && album.album_id.isEmpty()) { AddSongsSearchRequest(offset_next); break; } @@ -908,7 +997,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, album, album_explicit, offset_next); + AddAlbumSongsRequest(artist, album, offset_next); break; default: break; @@ -916,31 +1005,12 @@ void TidalRequest::SongsFinishCheck(const QString &artist_id, const QString &alb } } - if (!songs_requests_queue_.isEmpty() && songs_requests_active_ < kMaxConcurrentSongsRequests) FlushSongsRequests(); - if (!album_songs_requests_queue_.isEmpty() && album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) FlushAlbumSongsRequests(); - - if ( - service_->download_album_covers() && - IsQuery() && - songs_requests_queue_.isEmpty() && - songs_requests_active_ <= 0 && - album_songs_requests_queue_.isEmpty() && - album_songs_requests_active_ <= 0 && - album_cover_requests_queue_.isEmpty() && - album_covers_received_ <= 0 && - album_covers_requests_sent_.isEmpty() && - album_songs_received_ >= album_songs_requested_ - ) { - GetAlbumCovers(); - } - + GetAlbumCoversCheck(); FinishCheck(); } -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); +void TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Artist &album_artist, const Album &album) { if ( !json_obj.contains("album") || @@ -958,7 +1028,7 @@ QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Q !json_obj.contains("copyright") ) { Error("Invalid Json reply, track is missing one or more values.", json_obj); - return QString(); + return; } QJsonValue value_artist = json_obj["artist"]; @@ -984,12 +1054,12 @@ QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Q if (!value_artist.isObject()) { Error("Invalid Json reply, track artist is not a object.", value_artist); - return QString(); + return; } QJsonObject obj_artist = value_artist.toObject(); if (!obj_artist.contains("id") || !obj_artist.contains("name")) { Error("Invalid Json reply, track artist is missing id or name.", obj_artist); - return QString(); + return; } QString artist_id; if (obj_artist["id"].isString()) { @@ -1002,12 +1072,12 @@ QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Q if (!value_album.isObject()) { Error("Invalid Json reply, track album is not a object.", value_album); - return QString(); + return; } QJsonObject obj_album = value_album.toObject(); if (!obj_album.contains("id") || !obj_album.contains("title") || !obj_album.contains("cover")) { Error("Invalid Json reply, track album is missing id, title or cover.", obj_album); - return QString(); + return; } QString album_id; if (obj_album["id"].isString()) { @@ -1016,22 +1086,22 @@ QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Q else { album_id = QString::number(obj_album["id"].toInt()); } - if (!album_id_requested.isEmpty() && album_id_requested != album_id) { + if (!album.album_id.isEmpty() && album.album_id != album_id) { Error("Invalid Json reply, track album id is wrong.", obj_album); - return QString(); + return; } - QString album = obj_album["title"].toString(); - if (album_explicit) album.append(" (Explicit)"); + QString album_title = obj_album["title"].toString(); + if (album.album_explicit) album_title.append(" (Explicit)"); QString cover = obj_album["cover"].toString(); if (!allow_streaming) { - Warn(QString("Song %1 %2 %3 is not allowStreaming").arg(artist, album, title)); - return QString(); + Warn(QString("Song %1 %2 %3 is not allowStreaming").arg(artist, album_title, title)); + return; } if (!stream_ready) { - Warn(QString("Song %1 %2 %3 is not streamReady").arg(artist, album, title)); - return QString(); + Warn(QString("Song %1 %2 %3 is not streamReady").arg(artist, album_title, title)); + return; } QUrl url; @@ -1045,7 +1115,7 @@ QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Q } else { Error("Invalid duration for song.", json_duration); - return QString(); + return; } cover = cover.replace("-", "/"); @@ -1059,8 +1129,8 @@ QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Q song.set_song_id(song_id); song.set_album_id(album_id); song.set_artist_id(artist_id); - if (album_artist != artist) song.set_albumartist(album_artist); - song.set_album(album); + if (album_artist.artist != artist) song.set_albumartist(album_artist.artist); + song.set_album(album_title); song.set_artist(artist); song.set_title(title); song.set_track(track); @@ -1076,7 +1146,32 @@ QString TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Q song.set_ctime(0); song.set_valid(true); - return song_id; +} + +void TidalRequest::GetAlbumCoversCheck() { + + if ( + !finished_ && + service_->download_album_covers() && + IsQuery() && + artists_requests_queue_.isEmpty() && + albums_requests_queue_.isEmpty() && + songs_requests_queue_.isEmpty() && + artist_albums_requests_queue_.isEmpty() && + album_songs_requests_queue_.isEmpty() && + album_cover_requests_queue_.isEmpty() && + artist_albums_requests_pending_.isEmpty() && + album_songs_requests_pending_.isEmpty() && + album_covers_requests_sent_.isEmpty() && + artists_requests_active_ <= 0 && + albums_requests_active_ <= 0 && + songs_requests_active_ <= 0 && + artist_albums_requests_active_ <= 0 && + album_songs_requests_active_ <= 0 && + album_covers_requests_active_ <= 0 + ) { + GetAlbumCovers(); + } } @@ -1086,13 +1181,13 @@ void TidalRequest::GetAlbumCovers() { for (const Song &song : songs) { AddAlbumCoverRequest(song); } - FlushAlbumCoverRequests(); - if (album_covers_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving album cover for %1 album...").arg(album_covers_requested_)); - else emit UpdateStatus(query_id_, tr("Retrieving album covers for %1 albums...").arg(album_covers_requested_)); - emit ProgressSetMaximum(query_id_, album_covers_requested_); + if (album_covers_requests_total_ == 1) emit UpdateStatus(query_id_, tr("Receiving album cover for %1 album...").arg(album_covers_requests_total_)); + else emit UpdateStatus(query_id_, tr("Receiving album covers for %1 albums...").arg(album_covers_requests_total_)); emit UpdateProgress(query_id_, 0); + StartRequests(); + } void TidalRequest::AddAlbumCoverRequest(const Song &song) { @@ -1109,7 +1204,7 @@ void TidalRequest::AddAlbumCoverRequest(const Song &song) { if (request.filename.isEmpty()) return; album_covers_requests_sent_.insert(song.album_id(), song.song_id()); - ++album_covers_requested_; + ++album_covers_requests_total_; album_cover_requests_queue_.enqueue(request); @@ -1120,7 +1215,6 @@ void TidalRequest::FlushAlbumCoverRequests() { while (!album_cover_requests_queue_.isEmpty() && album_covers_requests_active_ < kMaxConcurrentAlbumCoverRequests) { AlbumCoverRequest request = album_cover_requests_queue_.dequeue(); - ++album_covers_requests_active_; QNetworkRequest req(request.url); req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); @@ -1128,6 +1222,8 @@ void TidalRequest::FlushAlbumCoverRequests() { album_cover_replies_ << reply; QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumCoverReceived(reply, request.album_id, request.url, request.filename); }); + ++album_covers_requests_active_; + } } @@ -1145,11 +1241,11 @@ void TidalRequest::AlbumCoverReceived(QNetworkReply *reply, const QString &album } --album_covers_requests_active_; - ++album_covers_received_; + ++album_covers_requests_received_; if (finished_) return; - emit UpdateProgress(query_id_, album_covers_received_); + emit UpdateProgress(query_id_, GetProgress(album_covers_requests_received_, album_covers_requests_total_)); if (!album_covers_requests_sent_.contains(album_id)) { AlbumCoverFinishCheck(); @@ -1221,9 +1317,6 @@ void TidalRequest::AlbumCoverReceived(QNetworkReply *reply, const QString &album void TidalRequest::AlbumCoverFinishCheck() { - if (!album_cover_requests_queue_.isEmpty() && album_covers_requests_active_ < kMaxConcurrentAlbumCoverRequests) - FlushAlbumCoverRequests(); - FinishCheck(); } @@ -1233,8 +1326,8 @@ void TidalRequest::FinishCheck() { if ( !finished_ && !need_login_ && - albums_requests_queue_.isEmpty() && artists_requests_queue_.isEmpty() && + albums_requests_queue_.isEmpty() && songs_requests_queue_.isEmpty() && artist_albums_requests_queue_.isEmpty() && album_songs_requests_queue_.isEmpty() && @@ -1246,13 +1339,12 @@ void TidalRequest::FinishCheck() { albums_requests_active_ <= 0 && songs_requests_active_ <= 0 && artist_albums_requests_active_ <= 0 && - artist_albums_received_ >= artist_albums_requested_ && album_songs_requests_active_ <= 0 && - album_songs_received_ >= album_songs_requested_ && - album_covers_requested_ <= album_covers_received_ && - album_covers_requests_active_ <= 0 && - album_covers_received_ >= album_covers_requested_ + album_covers_requests_active_ <= 0 ) { + if (timer_flush_requests_->isActive()) { + timer_flush_requests_->stop(); + } finished_ = true; if (songs_.isEmpty()) { if (errors_.isEmpty()) { @@ -1274,6 +1366,12 @@ void TidalRequest::FinishCheck() { } +int TidalRequest::GetProgress(const int count, const int total) { + + return static_cast((static_cast(count) / static_cast(total)) * 100.0F); + +} + void TidalRequest::Error(const QString &error, const QVariant &debug) { if (!error.isEmpty()) { diff --git a/src/tidal/tidalrequest.h b/src/tidal/tidalrequest.h index a75cbe54..c5f3a21e 100644 --- a/src/tidal/tidalrequest.h +++ b/src/tidal/tidalrequest.h @@ -41,6 +41,7 @@ #include "tidalbaserequest.h" class QNetworkReply; +class QTimer; class Application; class NetworkAccessManager; class TidalService; @@ -60,16 +61,34 @@ class TidalRequest : public TidalBaseRequest { void Search(const int query_id, const QString &search_text); private: - struct Request { - Request() : offset(0), limit(0), album_explicit(false) {} + struct Artist { QString artist_id; + QString artist; + }; + struct Album { + Album() : album_explicit(false) {} QString album_id; - QString song_id; + QString album; + QUrl cover_url; + bool album_explicit; + }; + struct Request { + Request() : offset(0), limit(0) {} + int offset; + int limit; + }; + struct ArtistAlbumsRequest { + ArtistAlbumsRequest() : offset(0), limit(0) {} + Artist artist; + int offset; + int limit; + }; + struct AlbumSongsRequest { + AlbumSongsRequest() : offset(0), limit(0) {} + Artist artist; + Album album; int offset; int limit; - QString album_artist; - QString album; - bool album_explicit; }; struct AlbumCoverRequest { QString artist_id; @@ -83,7 +102,6 @@ class TidalRequest : public TidalBaseRequest { void LoginFailure(QString failure_reason); void Results(int id, SongMap songs = SongMap(), QString error = QString()); void UpdateStatus(int id, QString text); - void ProgressSetMaximum(int id, int max); void UpdateProgress(int id, int max); void StreamURLFinished(QUrl original_url, QUrl url, Song::FileType, QString error = QString()); @@ -91,13 +109,13 @@ class TidalRequest : public TidalBaseRequest { void ArtistsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); void AlbumsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); - void AlbumsReceived(QNetworkReply *reply, const QString &artist_id_requested, const int limit_requested, const int offset_requested, const bool auto_login); + void AlbumsReceived(QNetworkReply *reply, const Artist &artist_artist, 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(), const QString &album = QString(), const bool album_explicit = false); + void SongsReceived(QNetworkReply *reply, const Artist &artist, const Album &album, const int limit_requested, const int offset_requested, const bool auto_login = 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, const QString &album, const bool album_explicit); + void ArtistAlbumsReplyReceived(QNetworkReply *reply, const Artist &artist, const int offset_requested); + void AlbumSongsReplyReceived(QNetworkReply *reply, const Artist &artist, const Album &album, const int offset_requested); void AlbumCoverReceived(QNetworkReply *reply, const QString &album_id, const QUrl &url, const QString &filename); public slots: @@ -107,6 +125,9 @@ class TidalRequest : public TidalBaseRequest { bool IsQuery() { return (type_ == QueryType_Artists || type_ == QueryType_Albums || type_ == QueryType_Songs); } bool IsSearch() { return (type_ == QueryType_SearchArtists || type_ == QueryType_SearchAlbums || type_ == QueryType_SearchSongs); } + void StartRequests(); + void FlushRequests(); + void GetArtists(); void GetAlbums(); void GetSongs(); @@ -126,42 +147,47 @@ class TidalRequest : public TidalBaseRequest { void FlushSongsRequests(); 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, const QString &album, const bool album_explicit); + void AlbumsFinishCheck(const Artist &artist, const int limit = 0, const int offset = 0, const int albums_total = 0, const int albums_received = 0); + void SongsFinishCheck(const Artist &artist, const Album &album, const int limit = 0, const int offset = 0, const int songs_total = 0, const int songs_received = 0); - void AddArtistAlbumsRequest(const QString &artist_id, const int offset = 0); + void AddArtistAlbumsRequest(const Artist &artist, const int offset = 0); void FlushArtistAlbumsRequests(); - 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 AddAlbumSongsRequest(const Artist &artist, const Album &album, 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(), const QString &album_album = QString(), const bool album_explicit = false); + void ParseSong(Song &song, const QJsonObject &json_obj, const Artist &album_artist, const Album &album); + void GetAlbumCoversCheck(); void GetAlbumCovers(); void AddAlbumCoverRequest(const Song &song); void FlushAlbumCoverRequests(); void AlbumCoverFinishCheck(); + int GetProgress(const int count, const int total); + void FinishCheck(); static void Warn(const QString &error, const QVariant &debug = QVariant()); void Error(const QString &error, const QVariant &debug = QVariant()) override; - static const char *kResourcesUrl; + static const char kResourcesUrl[]; static const int kMaxConcurrentArtistsRequests; static const int kMaxConcurrentAlbumsRequests; static const int kMaxConcurrentSongsRequests; static const int kMaxConcurrentArtistAlbumsRequests; static const int kMaxConcurrentAlbumSongsRequests; static const int kMaxConcurrentAlbumCoverRequests; + static const int kFlushRequestsDelay; TidalService *service_; TidalUrlHandler *url_handler_; Application *app_; NetworkAccessManager *network_; + QTimer *timer_flush_requests_; - QueryType type_; - bool fetchalbums_; - QString coversize_; + const QueryType type_; + const bool fetchalbums_; + const QString coversize_; int query_id_; QString search_text_; @@ -172,32 +198,47 @@ class TidalRequest : public TidalBaseRequest { QQueue albums_requests_queue_; QQueue songs_requests_queue_; - QQueue artist_albums_requests_queue_; - QQueue album_songs_requests_queue_; + QQueue artist_albums_requests_queue_; + QQueue album_songs_requests_queue_; QQueue album_cover_requests_queue_; - QList artist_albums_requests_pending_; - QHash album_songs_requests_pending_; + QHash artist_albums_requests_pending_; + QHash album_songs_requests_pending_; QMultiMap album_covers_requests_sent_; + int artists_requests_total_; int artists_requests_active_; + int artists_requests_received_; int artists_total_; int artists_received_; + int albums_requests_total_; int albums_requests_active_; - int songs_requests_active_; + int albums_requests_received_; + int albums_total_; + int albums_received_; + int songs_requests_total_; + int songs_requests_active_; + int songs_requests_received_; + int songs_total_; + int songs_received_; + + int artist_albums_requests_total_; int artist_albums_requests_active_; - int artist_albums_requested_; + int artist_albums_requests_received_; + int artist_albums_total_; int artist_albums_received_; int album_songs_requests_active_; - int album_songs_requested_; + int album_songs_requests_received_; + int album_songs_requests_total_; + int album_songs_total_; int album_songs_received_; + int album_covers_requests_total_; int album_covers_requests_active_; - int album_covers_requested_; - int album_covers_received_; + int album_covers_requests_received_; SongMap songs_; QStringList errors_; diff --git a/src/tidal/tidalservice.cpp b/src/tidal/tidalservice.cpp index 9ffedf5c..979bcd14 100644 --- a/src/tidal/tidalservice.cpp +++ b/src/tidal/tidalservice.cpp @@ -61,23 +61,23 @@ #include "settings/settingsdialog.h" #include "settings/tidalsettingspage.h" -const Song::Source TidalService::kSource = Song::Source_Tidal; -const char *TidalService::kOAuthUrl = "https://login.tidal.com/authorize"; -const char *TidalService::kOAuthAccessTokenUrl = "https://login.tidal.com/oauth2/token"; -const char *TidalService::kOAuthRedirectUrl = "tidal://login/auth"; -const char *TidalService::kAuthUrl = "https://api.tidalhifi.com/v1/login/username"; -const char *TidalService::kApiUrl = "https://api.tidalhifi.com/v1"; -const char *TidalService::kResourcesUrl = "https://resources.tidal.com"; -const int TidalService::kLoginAttempts = 2; -const int TidalService::kTimeResetLoginAttempts = 60000; +constexpr Song::Source TidalService::kSource = Song::Source_Tidal; +constexpr char TidalService::kOAuthUrl[] = "https://login.tidal.com/authorize"; +constexpr char TidalService::kOAuthAccessTokenUrl[] = "https://login.tidal.com/oauth2/token"; +constexpr char TidalService::kOAuthRedirectUrl[] = "tidal://login/auth"; +constexpr char TidalService::kAuthUrl[] = "https://api.tidalhifi.com/v1/login/username"; +constexpr char TidalService::kApiUrl[] = "https://api.tidalhifi.com/v1"; +constexpr char TidalService::kResourcesUrl[] = "https://resources.tidal.com"; +constexpr int TidalService::kLoginAttempts = 2; +constexpr int TidalService::kTimeResetLoginAttempts = 60000; -const char *TidalService::kArtistsSongsTable = "tidal_artists_songs"; -const char *TidalService::kAlbumsSongsTable = "tidal_albums_songs"; -const char *TidalService::kSongsTable = "tidal_songs"; +constexpr char TidalService::kArtistsSongsTable[] = "tidal_artists_songs"; +constexpr char TidalService::kAlbumsSongsTable[] = "tidal_albums_songs"; +constexpr char TidalService::kSongsTable[] = "tidal_songs"; -const char *TidalService::kArtistsSongsFtsTable = "tidal_artists_songs_fts"; -const char *TidalService::kAlbumsSongsFtsTable = "tidal_albums_songs_fts"; -const char *TidalService::kSongsFtsTable = "tidal_songs_fts"; +constexpr char TidalService::kArtistsSongsFtsTable[] = "tidal_artists_songs_fts"; +constexpr char TidalService::kAlbumsSongsFtsTable[] = "tidal_albums_songs_fts"; +constexpr char TidalService::kSongsFtsTable[] = "tidal_songs_fts"; using namespace std::chrono_literals; @@ -753,7 +753,6 @@ void TidalService::GetArtists() { QObject::connect(artists_request_.get(), &TidalRequest::RequestLogin, this, &TidalService::SendLogin); QObject::connect(artists_request_.get(), &TidalRequest::Results, this, &TidalService::ArtistsResultsReceived); QObject::connect(artists_request_.get(), &TidalRequest::UpdateStatus, this, &TidalService::ArtistsUpdateStatusReceived); - QObject::connect(artists_request_.get(), &TidalRequest::ProgressSetMaximum, this, &TidalService::ArtistsProgressSetMaximumReceived); QObject::connect(artists_request_.get(), &TidalRequest::UpdateProgress, this, &TidalService::ArtistsUpdateProgressReceived); QObject::connect(this, &TidalService::LoginComplete, artists_request_.get(), &TidalRequest::LoginComplete); @@ -774,11 +773,6 @@ void TidalService::ArtistsUpdateStatusReceived(const int id, const QString &text emit ArtistsUpdateStatus(text); } -void TidalService::ArtistsProgressSetMaximumReceived(const int id, const int max) { - Q_UNUSED(id); - emit ArtistsProgressSetMaximum(max); -} - void TidalService::ArtistsUpdateProgressReceived(const int id, const int progress) { Q_UNUSED(id); emit ArtistsUpdateProgress(progress); @@ -814,7 +808,6 @@ void TidalService::GetAlbums() { QObject::connect(albums_request_.get(), &TidalRequest::RequestLogin, this, &TidalService::SendLogin); QObject::connect(albums_request_.get(), &TidalRequest::Results, this, &TidalService::AlbumsResultsReceived); QObject::connect(albums_request_.get(), &TidalRequest::UpdateStatus, this, &TidalService::AlbumsUpdateStatusReceived); - QObject::connect(albums_request_.get(), &TidalRequest::ProgressSetMaximum, this, &TidalService::AlbumsProgressSetMaximumReceived); QObject::connect(albums_request_.get(), &TidalRequest::UpdateProgress, this, &TidalService::AlbumsUpdateProgressReceived); QObject::connect(this, &TidalService::LoginComplete, albums_request_.get(), &TidalRequest::LoginComplete); @@ -835,11 +828,6 @@ void TidalService::AlbumsUpdateStatusReceived(const int id, const QString &text) emit AlbumsUpdateStatus(text); } -void TidalService::AlbumsProgressSetMaximumReceived(const int id, const int max) { - Q_UNUSED(id); - emit AlbumsProgressSetMaximum(max); -} - void TidalService::AlbumsUpdateProgressReceived(const int id, const int progress) { Q_UNUSED(id); emit AlbumsUpdateProgress(progress); @@ -875,7 +863,6 @@ void TidalService::GetSongs() { QObject::connect(songs_request_.get(), &TidalRequest::RequestLogin, this, &TidalService::SendLogin); QObject::connect(songs_request_.get(), &TidalRequest::Results, this, &TidalService::SongsResultsReceived); QObject::connect(songs_request_.get(), &TidalRequest::UpdateStatus, this, &TidalService::SongsUpdateStatusReceived); - QObject::connect(songs_request_.get(), &TidalRequest::ProgressSetMaximum, this, &TidalService::SongsProgressSetMaximumReceived); QObject::connect(songs_request_.get(), &TidalRequest::UpdateProgress, this, &TidalService::SongsUpdateProgressReceived); QObject::connect(this, &TidalService::LoginComplete, songs_request_.get(), &TidalRequest::LoginComplete); @@ -896,11 +883,6 @@ void TidalService::SongsUpdateStatusReceived(const int id, const QString &text) emit SongsUpdateStatus(text); } -void TidalService::SongsProgressSetMaximumReceived(const int id, const int max) { - Q_UNUSED(id); - emit SongsProgressSetMaximum(max); -} - void TidalService::SongsUpdateProgressReceived(const int id, const int progress) { Q_UNUSED(id); emit SongsUpdateProgress(progress); @@ -973,7 +955,6 @@ void TidalService::SendSearch() { QObject::connect(search_request_.get(), &TidalRequest::RequestLogin, this, &TidalService::SendLogin); QObject::connect(search_request_.get(), &TidalRequest::Results, this, &TidalService::SearchResultsReceived); QObject::connect(search_request_.get(), &TidalRequest::UpdateStatus, this, &TidalService::SearchUpdateStatus); - QObject::connect(search_request_.get(), &TidalRequest::ProgressSetMaximum, this, &TidalService::SearchProgressSetMaximum); QObject::connect(search_request_.get(), &TidalRequest::UpdateProgress, this, &TidalService::SearchUpdateProgress); QObject::connect(this, &TidalService::LoginComplete, search_request_.get(), &TidalRequest::LoginComplete); diff --git a/src/tidal/tidalservice.h b/src/tidal/tidalservice.h index 04941e1f..2d4d4278 100644 --- a/src/tidal/tidalservice.h +++ b/src/tidal/tidalservice.h @@ -64,8 +64,8 @@ class TidalService : public InternetService { ~TidalService() override; static const Song::Source kSource; - static const char *kApiUrl; - static const char *kResourcesUrl; + static const char kApiUrl[]; + static const char kResourcesUrl[]; void Exit() override; void ReloadSettings() override; @@ -74,33 +74,33 @@ class TidalService : public InternetService { int Search(const QString &text, InternetSearchView::SearchType type) override; void CancelSearch() override; - int max_login_attempts() { return kLoginAttempts; } + int max_login_attempts() const { return kLoginAttempts; } - Application *app() { return app_; } + Application *app() const { return app_; } - bool oauth() override { return oauth_; } - QString client_id() { return client_id_; } - QString api_token() { return api_token_; } - quint64 user_id() { return user_id_; } - QString country_code() { return country_code_; } - QString username() { return username_; } - QString password() { return password_; } - QString quality() { return quality_; } - int artistssearchlimit() { return artistssearchlimit_; } - int albumssearchlimit() { return albumssearchlimit_; } - int songssearchlimit() { return songssearchlimit_; } - bool fetchalbums() { return fetchalbums_; } - 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_; } + bool oauth() const override { return oauth_; } + QString client_id() const { return client_id_; } + QString api_token() const { return api_token_; } + quint64 user_id() const { return user_id_; } + QString country_code() const { return country_code_; } + QString username() const { return username_; } + QString password() const { return password_; } + QString quality() const { return quality_; } + int artistssearchlimit() const { return artistssearchlimit_; } + int albumssearchlimit() const { return albumssearchlimit_; } + int songssearchlimit() const { return songssearchlimit_; } + bool fetchalbums() const { return fetchalbums_; } + QString coversize() const { return coversize_; } + bool download_album_covers() const { return download_album_covers_; } + TidalSettingsPage::StreamUrlMethod stream_url_method() const { return stream_url_method_; } + bool album_explicit() const { return album_explicit_; } - QString access_token() { return access_token_; } - QString session_id() { return session_id_; } + QString access_token() const { return access_token_; } + QString session_id() const { return session_id_; } - bool authenticated() override { return (!access_token_.isEmpty() || !session_id_.isEmpty()); } - bool login_sent() { return login_sent_; } - bool login_attempts() { return login_attempts_; } + bool authenticated() const override { return (!access_token_.isEmpty() || !session_id_.isEmpty()); } + bool login_sent() const { return login_sent_; } + bool login_attempts() const { return login_attempts_; } uint GetStreamURL(const QUrl &url, QString &error); @@ -145,9 +145,6 @@ class TidalService : public InternetService { void ArtistsUpdateStatusReceived(const int id, const QString &text); void AlbumsUpdateStatusReceived(const int id, const QString &text); void SongsUpdateStatusReceived(const int id, const QString &text); - void ArtistsProgressSetMaximumReceived(const int id, const int max); - void AlbumsProgressSetMaximumReceived(const int id, const int max); - void SongsProgressSetMaximumReceived(const int id, const int max); void ArtistsUpdateProgressReceived(const int id, const int progress); void AlbumsUpdateProgressReceived(const int id, const int progress); void SongsUpdateProgressReceived(const int id, const int progress); @@ -163,21 +160,21 @@ class TidalService : public InternetService { void SendSearch(); void LoginError(const QString &error = QString(), const QVariant &debug = QVariant()); - static const char *kOAuthUrl; - static const char *kOAuthAccessTokenUrl; - static const char *kOAuthRedirectUrl; - static const char *kAuthUrl; + static const char kOAuthUrl[]; + static const char kOAuthAccessTokenUrl[]; + static const char kOAuthRedirectUrl[]; + static const char kAuthUrl[]; static const int kLoginAttempts; static const int kTimeResetLoginAttempts; - static const char *kArtistsSongsTable; - static const char *kAlbumsSongsTable; - static const char *kSongsTable; + static const char kArtistsSongsTable[]; + static const char kAlbumsSongsTable[]; + static const char kSongsTable[]; - static const char *kArtistsSongsFtsTable; - static const char *kAlbumsSongsFtsTable; - static const char *kSongsFtsTable; + static const char kArtistsSongsFtsTable[]; + static const char kAlbumsSongsFtsTable[]; + static const char kSongsFtsTable[]; Application *app_; NetworkAccessManager *network_;