1 /* This file is part of Clementine. 2 Copyright 2011-2013, Alan Briolat <alan.briolat@gmail.com> 3 Copyright 2013, Ross Wolfson <ross.wolfson@gmail.com> 4 Copyright 2013, David Sansome <me@davidsansome.com> 5 Copyright 2013-2014, John Maguire <john.maguire@gmail.com> 6 Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com> 7 8 Clementine is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 3 of the License, or 11 (at your option) any later version. 12 13 Clementine is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with Clementine. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #ifndef INTERNET_SUBSONIC_SUBSONICSERVICE_H_ 23 #define INTERNET_SUBSONIC_SUBSONICSERVICE_H_ 24 25 #include <QQueue> 26 27 #include "internet/core/internetmodel.h" 28 #include "internet/core/internetservice.h" 29 #include "internet/subsonic/subsonicdynamicplaylist.h" 30 31 class QNetworkAccessManager; 32 class QNetworkReply; 33 class QSortFilterProxyModel; 34 class QXmlStreamReader; 35 36 class SubsonicUrlHandler; 37 class SubsonicLibraryScanner; 38 39 class SubsonicService : public InternetService { 40 Q_OBJECT 41 Q_ENUMS(LoginState) 42 Q_ENUMS(ApiError) 43 44 public: 45 SubsonicService(Application* app, InternetModel* parent); 46 ~SubsonicService(); 47 48 enum LoginState { 49 LoginState_Loggedin, 50 LoginState_BadServer, 51 LoginState_OutdatedClient, 52 LoginState_OutdatedServer, 53 LoginState_BadCredentials, 54 LoginState_Unlicensed, 55 LoginState_OtherError, 56 LoginState_Unknown, 57 LoginState_ConnectionRefused, 58 LoginState_HostNotFound, 59 LoginState_Timeout, 60 LoginState_SslError, 61 LoginState_IncompleteCredentials, 62 LoginState_RedirectLimitExceeded, 63 LoginState_RedirectNoUrl, 64 }; 65 66 enum ApiError { 67 ApiError_Generic = 0, 68 ApiError_ParameterMissing = 10, 69 ApiError_OutdatedClient = 20, 70 ApiError_OutdatedServer = 30, 71 ApiError_BadCredentials = 40, 72 ApiError_Unauthorized = 50, 73 ApiError_Unlicensed = 60, 74 ApiError_NotFound = 70, 75 }; 76 77 enum Type { 78 Type_Artist = InternetModel::TypeCount, 79 Type_Album, 80 Type_Track, 81 }; 82 83 enum Role { 84 Role_Id = InternetModel::RoleCount, 85 }; 86 87 typedef QMap<QString, QString> RequestOptions; 88 89 bool IsConfigured() const; 90 bool IsAmpache() const; 91 92 QStandardItem* CreateRootItem(); 93 void LazyPopulate(QStandardItem* item); 94 void ShowContextMenu(const QPoint& global_pos); 95 QWidget* HeaderWidget() const; 96 void ReloadSettings(); 97 98 void Login(); 99 void Login(const QString& server, const QString& username, 100 const QString& password, const bool& usesslv3, 101 const bool& verifycert); 102 login_state()103 LoginState login_state() const { return login_state_; } 104 105 // Subsonic API methods 106 void Ping(); 107 108 QUrl BuildRequestUrl(const QString& view) const; 109 // Scrubs the part of the path that we re-add in BuildRequestUrl(). 110 static QUrl ScrubUrl(const QUrl& url); 111 // Convenience function to reduce QNetworkRequest/QSslConfiguration 112 // boilerplate. 113 QNetworkReply* Send(const QUrl& url); 114 115 friend PlaylistItemList SubsonicDynamicPlaylist::GenerateMore(int); 116 117 static const char* kServiceName; 118 static const char* kSettingsGroup; 119 static const char* kApiVersion; 120 static const char* kApiClientName; 121 122 static const char* kSongsTable; 123 static const char* kFtsTable; 124 125 static const int kMaxRedirects; 126 static const int kCoverArtSize; 127 128 129 signals: 130 void LoginStateChanged(SubsonicService::LoginState newstate); 131 132 private: 133 void EnsureMenuCreated(); 134 // Update configured and working server state 135 void UpdateServer(const QString& server); 136 137 QNetworkAccessManager* network_; 138 SubsonicUrlHandler* url_handler_; 139 140 SubsonicLibraryScanner* scanner_; 141 int load_database_task_id_; 142 143 QMenu* context_menu_; 144 QStandardItem* root_; 145 146 LibraryBackend* library_backend_; 147 LibraryModel* library_model_; 148 LibraryFilterWidget* library_filter_; 149 QSortFilterProxyModel* library_sort_model_; 150 int total_song_count_; 151 152 // Configuration 153 // The server that shows up in the GUI (use UpdateServer() to update) 154 QString configured_server_; 155 QString username_; 156 QString password_; 157 bool usesslv3_; 158 bool verifycert_; 159 160 LoginState login_state_; 161 QString working_server_; // The actual server, possibly post-redirect 162 int redirect_count_; 163 bool is_ampache_; 164 165 private slots: 166 void UpdateTotalSongCount(int count); 167 void ReloadDatabase(); 168 void ReloadDatabaseFinished(); 169 void OnLoginStateChanged(SubsonicService::LoginState newstate); 170 void OnPingFinished(QNetworkReply* reply); 171 172 void ShowConfig(); 173 }; 174 175 class SubsonicLibraryScanner : public QObject { 176 Q_OBJECT 177 178 public: 179 explicit SubsonicLibraryScanner(SubsonicService* service, 180 QObject* parent = nullptr); 181 ~SubsonicLibraryScanner(); 182 183 void Scan(); GetSongs()184 const SongList& GetSongs() const { return songs_; } 185 186 static const int kAlbumChunkSize; 187 static const int kConcurrentRequests; 188 static const int kCoverArtSize; 189 190 signals: 191 void ScanFinished(); 192 193 private slots: 194 // Step 1: use getAlbumList2 type=alphabeticalByName to list all albums 195 void OnGetAlbumListFinished(QNetworkReply* reply, int offset); 196 // Step 2: use getAlbum id=? to list all songs for each album 197 void OnGetAlbumFinished(QNetworkReply* reply); 198 199 private: 200 void GetAlbumList(int offset); 201 void GetAlbum(const QString& id); 202 void ParsingError(const QString& message); 203 204 SubsonicService* service_; 205 bool scanning_; 206 QQueue<QString> album_queue_; 207 QSet<QNetworkReply*> pending_requests_; 208 SongList songs_; 209 }; 210 211 #endif // INTERNET_SUBSONIC_SUBSONICSERVICE_H_ 212