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 TIDALSERVICE_H 21 #define TIDALSERVICE_H 22 23 #include "config.h" 24 25 #include <memory> 26 27 #include <QtGlobal> 28 #include <QObject> 29 #include <QPair> 30 #include <QSet> 31 #include <QList> 32 #include <QMap> 33 #include <QVariant> 34 #include <QByteArray> 35 #include <QString> 36 #include <QStringList> 37 #include <QUrl> 38 #include <QDateTime> 39 #include <QSslError> 40 41 #include "core/song.h" 42 #include "internet/internetservice.h" 43 #include "internet/internetsearchview.h" 44 #include "settings/tidalsettingspage.h" 45 46 class QSortFilterProxyModel; 47 class QNetworkReply; 48 class QTimer; 49 50 class Application; 51 class NetworkAccessManager; 52 class TidalUrlHandler; 53 class TidalRequest; 54 class TidalFavoriteRequest; 55 class TidalStreamURLRequest; 56 class CollectionBackend; 57 class CollectionModel; 58 59 class TidalService : public InternetService { 60 Q_OBJECT 61 62 public: 63 explicit TidalService(Application *app, QObject *parent); 64 ~TidalService() override; 65 66 static const Song::Source kSource; 67 static const char *kApiUrl; 68 static const char *kResourcesUrl; 69 70 void Exit() override; 71 void ReloadSettings() override; 72 73 void Logout(); 74 int Search(const QString &text, InternetSearchView::SearchType type) override; 75 void CancelSearch() override; 76 max_login_attempts()77 int max_login_attempts() { return kLoginAttempts; } 78 app()79 Application *app() { return app_; } 80 oauth()81 bool oauth() override { return oauth_; } client_id()82 QString client_id() { return client_id_; } api_token()83 QString api_token() { return api_token_; } user_id()84 quint64 user_id() { return user_id_; } country_code()85 QString country_code() { return country_code_; } username()86 QString username() { return username_; } password()87 QString password() { return password_; } quality()88 QString quality() { return quality_; } artistssearchlimit()89 int artistssearchlimit() { return artistssearchlimit_; } albumssearchlimit()90 int albumssearchlimit() { return albumssearchlimit_; } songssearchlimit()91 int songssearchlimit() { return songssearchlimit_; } fetchalbums()92 bool fetchalbums() { return fetchalbums_; } coversize()93 QString coversize() { return coversize_; } download_album_covers()94 bool download_album_covers() { return download_album_covers_; } stream_url_method()95 TidalSettingsPage::StreamUrlMethod stream_url_method() { return stream_url_method_; } album_explicit()96 bool album_explicit() { return album_explicit_; } 97 access_token()98 QString access_token() { return access_token_; } session_id()99 QString session_id() { return session_id_; } 100 authenticated()101 bool authenticated() override { return (!access_token_.isEmpty() || !session_id_.isEmpty()); } login_sent()102 bool login_sent() { return login_sent_; } login_attempts()103 bool login_attempts() { return login_attempts_; } 104 105 void GetStreamURL(const QUrl &url); 106 artists_collection_backend()107 CollectionBackend *artists_collection_backend() override { return artists_collection_backend_; } albums_collection_backend()108 CollectionBackend *albums_collection_backend() override { return albums_collection_backend_; } songs_collection_backend()109 CollectionBackend *songs_collection_backend() override { return songs_collection_backend_; } 110 artists_collection_model()111 CollectionModel *artists_collection_model() override { return artists_collection_model_; } albums_collection_model()112 CollectionModel *albums_collection_model() override { return albums_collection_model_; } songs_collection_model()113 CollectionModel *songs_collection_model() override { return songs_collection_model_; } 114 artists_collection_sort_model()115 QSortFilterProxyModel *artists_collection_sort_model() override { return artists_collection_sort_model_; } albums_collection_sort_model()116 QSortFilterProxyModel *albums_collection_sort_model() override { return albums_collection_sort_model_; } songs_collection_sort_model()117 QSortFilterProxyModel *songs_collection_sort_model() override { return songs_collection_sort_model_; } 118 119 public slots: 120 void ShowConfig() override; 121 void StartAuthorization(const QString &client_id); 122 void TryLogin(); 123 void SendLogin(); 124 void SendLoginWithCredentials(const QString &api_token, const QString &username, const QString &password); 125 void GetArtists() override; 126 void GetAlbums() override; 127 void GetSongs() override; 128 void ResetArtistsRequest() override; 129 void ResetAlbumsRequest() override; 130 void ResetSongsRequest() override; 131 void AuthorizationUrlReceived(const QUrl &url); 132 133 private slots: 134 void ExitReceived(); RequestNewAccessToken()135 void RequestNewAccessToken() { RequestAccessToken(); } 136 void HandleLoginSSLErrors(const QList<QSslError> &ssl_errors); 137 void AccessTokenRequestFinished(QNetworkReply *reply); 138 void HandleAuthReply(QNetworkReply *reply); 139 void ResetLoginAttempts(); 140 void StartSearch(); 141 void ArtistsResultsReceived(const int id, const SongMap &songs, const QString &error); 142 void AlbumsResultsReceived(const int id, const SongMap &songs, const QString &error); 143 void SongsResultsReceived(const int id, const SongMap &songs, const QString &error); 144 void SearchResultsReceived(const int id, const SongMap &songs, const QString &error); 145 void ArtistsUpdateStatusReceived(const int id, const QString &text); 146 void AlbumsUpdateStatusReceived(const int id, const QString &text); 147 void SongsUpdateStatusReceived(const int id, const QString &text); 148 void ArtistsProgressSetMaximumReceived(const int id, const int max); 149 void AlbumsProgressSetMaximumReceived(const int id, const int max); 150 void SongsProgressSetMaximumReceived(const int id, const int max); 151 void ArtistsUpdateProgressReceived(const int id, const int progress); 152 void AlbumsUpdateProgressReceived(const int id, const int progress); 153 void SongsUpdateProgressReceived(const int id, const int progress); 154 void HandleStreamURLFinished(const int id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error = QString()); 155 156 private: 157 typedef QPair<QString, QString> Param; 158 typedef QList<Param> ParamList; 159 160 void LoadSession(); 161 void RequestAccessToken(const QString &code = QString()); 162 void SendSearch(); 163 void LoginError(const QString &error = QString(), const QVariant &debug = QVariant()); 164 165 static const char *kOAuthUrl; 166 static const char *kOAuthAccessTokenUrl; 167 static const char *kOAuthRedirectUrl; 168 static const char *kAuthUrl; 169 170 static const int kLoginAttempts; 171 static const int kTimeResetLoginAttempts; 172 173 static const char *kArtistsSongsTable; 174 static const char *kAlbumsSongsTable; 175 static const char *kSongsTable; 176 177 static const char *kArtistsSongsFtsTable; 178 static const char *kAlbumsSongsFtsTable; 179 static const char *kSongsFtsTable; 180 181 Application *app_; 182 NetworkAccessManager *network_; 183 TidalUrlHandler *url_handler_; 184 185 CollectionBackend *artists_collection_backend_; 186 CollectionBackend *albums_collection_backend_; 187 CollectionBackend *songs_collection_backend_; 188 189 CollectionModel *artists_collection_model_; 190 CollectionModel *albums_collection_model_; 191 CollectionModel *songs_collection_model_; 192 193 QSortFilterProxyModel *artists_collection_sort_model_; 194 QSortFilterProxyModel *albums_collection_sort_model_; 195 QSortFilterProxyModel *songs_collection_sort_model_; 196 197 QTimer *timer_search_delay_; 198 QTimer *timer_login_attempt_; 199 QTimer *timer_refresh_login_; 200 201 std::shared_ptr<TidalRequest> artists_request_; 202 std::shared_ptr<TidalRequest> albums_request_; 203 std::shared_ptr<TidalRequest> songs_request_; 204 std::shared_ptr<TidalRequest> search_request_; 205 TidalFavoriteRequest *favorite_request_; 206 207 bool enabled_; 208 bool oauth_; 209 QString client_id_; 210 QString api_token_; 211 quint64 user_id_; 212 QString country_code_; 213 QString username_; 214 QString password_; 215 QString quality_; 216 int artistssearchlimit_; 217 int albumssearchlimit_; 218 int songssearchlimit_; 219 bool fetchalbums_; 220 QString coversize_; 221 bool download_album_covers_; 222 TidalSettingsPage::StreamUrlMethod stream_url_method_; 223 bool album_explicit_; 224 225 QString access_token_; 226 QString refresh_token_; 227 QString session_id_; 228 quint64 expires_in_; 229 quint64 login_time_; 230 231 int pending_search_id_; 232 int next_pending_search_id_; 233 QString pending_search_text_; 234 InternetSearchView::SearchType pending_search_type_; 235 236 int search_id_; 237 QString search_text_; 238 bool login_sent_; 239 int login_attempts_; 240 241 QString code_verifier_; 242 QString code_challenge_; 243 244 int next_stream_url_request_id_; 245 QMap<int, std::shared_ptr<TidalStreamURLRequest>> stream_url_requests_; 246 247 QStringList login_errors_; 248 249 QList<QObject*> wait_for_exit_; 250 QList<QNetworkReply*> replies_; 251 252 }; 253 254 #endif // TIDALSERVICE_H 255