1 /* 2 * Strawberry Music Player 3 * Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net> 4 * 5 * Strawberry is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * Strawberry is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with Strawberry. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #ifndef TIDALREQUEST_H 21 #define TIDALREQUEST_H 22 23 #include "config.h" 24 25 #include <QtGlobal> 26 #include <QObject> 27 #include <QPair> 28 #include <QSet> 29 #include <QList> 30 #include <QHash> 31 #include <QMap> 32 #include <QMultiMap> 33 #include <QQueue> 34 #include <QVariant> 35 #include <QString> 36 #include <QStringList> 37 #include <QUrl> 38 #include <QJsonObject> 39 40 #include "core/song.h" 41 #include "tidalbaserequest.h" 42 43 class QNetworkReply; 44 class Application; 45 class NetworkAccessManager; 46 class TidalService; 47 class TidalUrlHandler; 48 49 class TidalRequest : public TidalBaseRequest { 50 Q_OBJECT 51 52 public: 53 explicit TidalRequest(TidalService *service, TidalUrlHandler *url_handler, Application *app, NetworkAccessManager *network, QueryType type, QObject *parent); 54 ~TidalRequest() override; 55 56 void ReloadSettings(); 57 58 void Process(); set_need_login()59 void set_need_login() override { need_login_ = true; } 60 void Search(const int query_id, const QString &search_text); 61 62 private: 63 struct Request { RequestRequest64 Request() : offset(0), limit(0), album_explicit(false) {} 65 QString artist_id; 66 QString album_id; 67 QString song_id; 68 int offset; 69 int limit; 70 QString album_artist; 71 QString album; 72 bool album_explicit; 73 }; 74 struct AlbumCoverRequest { 75 QString artist_id; 76 QString album_id; 77 QUrl url; 78 QString filename; 79 }; 80 81 signals: 82 void LoginSuccess(); 83 void LoginFailure(QString failure_reason); 84 void Results(int id, SongMap songs, QString error); 85 void UpdateStatus(int id, QString text); 86 void ProgressSetMaximum(int id, int max); 87 void UpdateProgress(int id, int max); 88 void StreamURLFinished(QUrl original_url, QUrl url, Song::FileType, QString error = QString()); 89 90 private slots: 91 void ArtistsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); 92 93 void AlbumsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); 94 void AlbumsReceived(QNetworkReply *reply, const QString &artist_id_requested, const int limit_requested, const int offset_requested, const bool auto_login); 95 96 void SongsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested); 97 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); 98 99 void ArtistAlbumsReplyReceived(QNetworkReply *reply, const QString &artist_id, const int offset_requested); 100 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); 101 void AlbumCoverReceived(QNetworkReply *reply, const QString &album_id, const QUrl &url, const QString &filename); 102 103 public slots: 104 void LoginComplete(const bool success, const QString &error = QString()); 105 106 private: IsQuery()107 bool IsQuery() { return (type_ == QueryType_Artists || type_ == QueryType_Albums || type_ == QueryType_Songs); } IsSearch()108 bool IsSearch() { return (type_ == QueryType_SearchArtists || type_ == QueryType_SearchAlbums || type_ == QueryType_SearchSongs); } 109 110 void GetArtists(); 111 void GetAlbums(); 112 void GetSongs(); 113 114 void ArtistsSearch(); 115 void AlbumsSearch(); 116 void SongsSearch(); 117 118 void AddArtistsRequest(const int offset = 0, const int limit = 0); 119 void AddArtistsSearchRequest(const int offset = 0); 120 void FlushArtistsRequests(); 121 void AddAlbumsRequest(const int offset = 0, const int limit = 0); 122 void AddAlbumsSearchRequest(const int offset = 0); 123 void FlushAlbumsRequests(); 124 void AddSongsRequest(const int offset = 0, const int limit = 0); 125 void AddSongsSearchRequest(const int offset = 0); 126 void FlushSongsRequests(); 127 128 void ArtistsFinishCheck(const int limit = 0, const int offset = 0, const int artists_received = 0); 129 void AlbumsFinishCheck(const QString &artist_id, const int limit = 0, const int offset = 0, const int albums_total = 0, const int albums_received = 0); 130 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); 131 132 void AddArtistAlbumsRequest(const QString &artist_id, const int offset = 0); 133 void FlushArtistAlbumsRequests(); 134 135 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); 136 void FlushAlbumSongsRequests(); 137 138 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); 139 140 void GetAlbumCovers(); 141 void AddAlbumCoverRequest(const Song &song); 142 void FlushAlbumCoverRequests(); 143 void AlbumCoverFinishCheck(); 144 145 void FinishCheck(); 146 static void Warn(const QString &error, const QVariant &debug = QVariant()); 147 void Error(const QString &error, const QVariant &debug = QVariant()) override; 148 149 static const char *kResourcesUrl; 150 static const int kMaxConcurrentArtistsRequests; 151 static const int kMaxConcurrentAlbumsRequests; 152 static const int kMaxConcurrentSongsRequests; 153 static const int kMaxConcurrentArtistAlbumsRequests; 154 static const int kMaxConcurrentAlbumSongsRequests; 155 static const int kMaxConcurrentAlbumCoverRequests; 156 157 TidalService *service_; 158 TidalUrlHandler *url_handler_; 159 Application *app_; 160 NetworkAccessManager *network_; 161 162 QueryType type_; 163 bool fetchalbums_; 164 QString coversize_; 165 166 int query_id_; 167 QString search_text_; 168 169 bool finished_; 170 171 QQueue<Request> artists_requests_queue_; 172 QQueue<Request> albums_requests_queue_; 173 QQueue<Request> songs_requests_queue_; 174 175 QQueue<Request> artist_albums_requests_queue_; 176 QQueue<Request> album_songs_requests_queue_; 177 QQueue<AlbumCoverRequest> album_cover_requests_queue_; 178 179 QList<QString> artist_albums_requests_pending_; 180 QHash<QString, Request> album_songs_requests_pending_; 181 QMultiMap<QString, QString> album_covers_requests_sent_; 182 183 int artists_requests_active_; 184 int artists_total_; 185 int artists_received_; 186 187 int albums_requests_active_; 188 int songs_requests_active_; 189 190 int artist_albums_requests_active_; 191 int artist_albums_requested_; 192 int artist_albums_received_; 193 194 int album_songs_requests_active_; 195 int album_songs_requested_; 196 int album_songs_received_; 197 198 int album_covers_requests_active_; 199 int album_covers_requested_; 200 int album_covers_received_; 201 202 SongMap songs_; 203 QStringList errors_; 204 bool need_login_; 205 bool no_results_; 206 QList<QNetworkReply*> replies_; 207 QList<QNetworkReply*> album_cover_replies_; 208 209 }; 210 211 #endif // TIDALREQUEST_H 212