/* This file is part of Clementine. Copyright 2011, David Sansome Clementine is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Clementine is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Clementine. If not, see . */ #ifndef GROOVESHARKSERVICE_H #define GROOVESHARKSERVICE_H #include "internetmodel.h" #include "internetservice.h" #include class GroovesharkUrlHandler; class NetworkAccessManager; class Playlist; class SearchBoxWidget; class QMenu; class QNetworkReply; class QNetworkRequest; class QSortFilterProxyModel; class GroovesharkService : public InternetService { Q_OBJECT public: GroovesharkService(Application* app, InternetModel* parent); ~GroovesharkService(); enum Role { Role_UserPlaylistId = InternetModel::RoleCount, Role_PlaylistType }; enum PlaylistType { UserPlaylist = Qt::UserRole, // Favorites and Library list are like playlists, but we want to do special // treatments in some cases UserFavorites, UserLibrary, SubscribedPlaylist }; // Values are persisted - don't change. enum LoginState { LoginState_LoggedIn = 1, LoginState_AuthFailed = 2, LoginState_NoPremium = 3, LoginState_OtherError = 4 }; // Internet Service methods QStandardItem* CreateRootItem(); void LazyPopulate(QStandardItem* parent); void ItemDoubleClicked(QStandardItem* item); smart_playlists::GeneratorPtr CreateGenerator(QStandardItem* item); void DropMimeData(const QMimeData* data, const QModelIndex& index); QList playlistitem_actions(const Song& song); void ShowContextMenu(const QPoint& global_pos); QWidget* HeaderWidget() const; // User should be logged in to be able to generate streaming urls QUrl GetStreamingUrlFromSongId(const QString& song_id, const QString& artist_id, QString* server_id, QString* stream_key, qint64* length_nanosec); void Login(const QString& username, const QString& password); void Logout(); bool IsLoggedIn() const { return !session_id_.isEmpty(); } void RetrieveUserPlaylists(); void RetrieveUserFavorites(); void RetrieveUserLibrarySongs(); void RetrievePopularSongs(); void RetrievePopularSongsMonth(); void RetrievePopularSongsToday(); void RetrieveSubscribedPlaylists(); void RetrieveAutoplayTags(); void SetPlaylistSongs(int playlist_id, const QList& songs_ids); void RemoveFromPlaylist(int playlist_id, const QList& songs_ids_to_remove); // Refresh playlist_id playlist , or create it if it doesn't exist void RefreshPlaylist(int playlist_id); void DeletePlaylist(int playlist_id); void RenamePlaylist(int playlist_id); void AddUserFavoriteSong(int song_id); void RemoveFromFavorites(const QList& songs_ids_to_remove); void AddUserLibrarySongs(const QList& songs_ids); void RemoveFromLibrary(const QList& songs_ids_to_remove); void GetSongUrlToShare(int song_id); void GetPlaylistUrlToShare(int playlist_id); // Start autoplay for the given tag_id, fill the autoplay_state, returns a // first song to play Song StartAutoplayTag(int tag_id, QVariantMap& autoplay_state); Song StartAutoplay(QVariantMap& autoplay_state); // Get another autoplay song. autoplay_state is the autoplay_state received // from StartAutoplayTag Song GetAutoplaySong(QVariantMap& autoplay_state); void MarkStreamKeyOver30Secs(const QString& stream_key, const QString& server_id); void MarkSongComplete(const QString& song_id, const QString& stream_key, const QString& server_id); // Persisted in the settings and updated on each Login(). LoginState login_state() const { return login_state_; } const QString& session_id() { return session_id_; } int SimpleSearch(const QString& query); int SearchAlbums(const QString& query); void GetAlbumSongs(quint64 album_id); static const char* kServiceName; static const char* kSettingsGroup; signals: void LoginFinished(bool success); void SimpleSearchResults(int id, SongList songs); // AlbumSearchResult emits the search id and the Grooveshark ids of the // albums found. Albums' songs will be loaded asynchronously and // AlbumSongsLoaded will be emitted, containing the actual Albums' songs. void AlbumSearchResult(int id, QList albums_ids); void AlbumSongsLoaded(quint64 id, SongList songs); public slots: void Search(const QString& text, bool now = false); void ShowConfig(); protected: struct PlaylistInfo { PlaylistInfo() {} PlaylistInfo(int id, QString name, QStandardItem* item = nullptr) : id_(id), name_(name), item_(item) {} bool operator<(const PlaylistInfo other) const { return name_.localeAwareCompare(other.name_) < 0; } int id_; QString name_; QStandardItem* item_; QList songs_ids_; }; private slots: void SessionCreated(QNetworkReply* reply); void DoSearch(); void SearchSongsFinished(QNetworkReply* reply); void SimpleSearchFinished(QNetworkReply* reply, int id); void SearchAlbumsFinished(QNetworkReply* reply, int id); void GetAlbumSongsFinished(QNetworkReply* reply, quint64 album_id); void Authenticated(QNetworkReply* reply); void UserPlaylistsRetrieved(QNetworkReply* reply); void UserFavoritesRetrieved(QNetworkReply* reply, int task_id); void UserLibrarySongsRetrieved(QNetworkReply* reply, int task_id); void PopularSongsMonthRetrieved(QNetworkReply* reply); void PopularSongsTodayRetrieved(QNetworkReply* reply); void SubscribedPlaylistsRetrieved(QNetworkReply* reply); void AutoplayTagsRetrieved(QNetworkReply* reply); void PlaylistSongsRetrieved(QNetworkReply* reply, int playlist_id); void PlaylistSongsSet(QNetworkReply* reply, int playlist_id, int task_id); void CreateNewPlaylist(); void NewPlaylistCreated(QNetworkReply* reply, const QString& name); void DeleteCurrentPlaylist(); void RenameCurrentPlaylist(); void PlaylistDeleted(QNetworkReply* reply, int playlist_id); void PlaylistRenamed(QNetworkReply* reply, int playlist_id, const QString& new_name); void AddCurrentSongToUserFavorites() { AddUserFavoriteSong(current_song_id_); } void AddCurrentSongToUserLibrary() { AddUserLibrarySongs(QList() << current_song_id_); } void AddCurrentSongToPlaylist(QAction* action); void UserFavoriteSongAdded(QNetworkReply* reply, int task_id); void UserLibrarySongAdded(QNetworkReply* reply, int task_id); void GetCurrentSongUrlToShare(); void SongUrlToShareReceived(QNetworkReply* reply); void GetCurrentPlaylistUrlToShare(); void PlaylistUrlToShareReceived(QNetworkReply* reply); void RemoveCurrentFromPlaylist(); void RemoveCurrentFromFavorites(); void RemoveCurrentFromLibrary(); void SongsRemovedFromFavorites(QNetworkReply* reply, int task_id); void SongsRemovedFromLibrary(QNetworkReply* reply, int task_id); void StreamMarked(QNetworkReply* reply); void SongMarkedAsComplete(QNetworkReply* reply); void RequestSslErrors(const QList& errors); void Homepage(); // Refresh all Grooveshark's items, and re-fill them void RefreshItems(); private: void EnsureMenuCreated(); void EnsureItemsCreated(); void RemoveItems(); void EnsureConnected(); void ClearSearchResults(); // Create a playlist item, with data set as excepted. Doesn't fill the item // with songs rows. QStandardItem* CreatePlaylistItem(const QString& playlist_name, int playlist_id); void AuthenticateSession(); void InitCountry(); // Create a request for the given method, with the given params. // If need_authentication is true, add session_id to params. // Returns the reply object created QNetworkReply* CreateRequest(const QString& method_name, const QList >& params, bool use_https = false); // Convenient function which block until 'reply' replies, or timeout after 10 // seconds. Returns false if reply has timeouted bool WaitForReply(QNetworkReply* reply); void ShowUrlBox(const QString& title, const QString& url); // Convenient function for extracting result from reply QVariantMap ExtractResult(QNetworkReply* reply); // Convenient function for extracting songs from grooveshark result. result // should be the "result" field of most Grooveshark replies SongList ExtractSongs(const QVariantMap& result); // Convenient function for extracting song from grooveshark result. // result_song should be the song field ('song', 'nextSong', ...) of the // Grooveshark reply Song ExtractSong(const QVariantMap& result_song); // Convenient functions for extracting Grooveshark songs ids QList ExtractSongsIds(const QVariantMap& result); QList ExtractSongsIds(const QList& urls); int ExtractSongId( const QUrl& url); // Returns 0 if url is not a Grooveshark url // Convenient function for extracting basic playlist info (only 'id' and // 'name': QStandardItem still need to be created), and sort them by name QList ExtractPlaylistInfo(const QVariantMap& result); void ResetSessionId(); GroovesharkUrlHandler* url_handler_; QString pending_search_; int next_pending_search_id_; QSet pending_retrieve_playlists_; QMap playlists_; QMap subscribed_playlists_; QStandardItem* root_; QStandardItem* search_; QStandardItem* popular_month_; QStandardItem* popular_today_; QStandardItem* stations_; QStandardItem* grooveshark_radio_; QStandardItem* favorites_; // Grooveshark Library (corresponds to Grooveshark 'MyMusic' actually, but // called 'Library' in the API). // Nothing to do with Clementine's local library QStandardItem* library_; QStandardItem* playlists_parent_; QStandardItem* subscribed_playlists_parent_; NetworkAccessManager* network_; QMenu* context_menu_; // IDs kept when showing menu, to know what the user has clicked on, to be // able to perform actions on corresponding items int current_song_id_; int current_playlist_id_; QAction* create_playlist_; QAction* delete_playlist_; QAction* rename_playlist_; QAction* remove_from_playlist_; QAction* remove_from_favorites_; QAction* remove_from_library_; QAction* get_url_to_share_song_; QAction* get_url_to_share_playlist_; QList playlistitem_actions_; SearchBoxWidget* search_box_; QTimer* search_delay_; QNetworkReply* last_search_reply_; QString username_; QString password_; // In fact, password's md5 hash QString user_id_; QString session_id_; QMap country_; // The last artists and songs ids th users has listened to. Used for autoplay QList last_artists_ids_; QList last_songs_ids_; QByteArray api_key_; LoginState login_state_; // Tasks' ids: we need to keep them in mind to be able to update task status // on each step int task_popular_id_; int task_playlists_id_; int task_search_id_; static const char* kUrl; static const char* kUrlCover; static const char* kHomepage; static const int kSongSearchLimit; static const int kSongSimpleSearchLimit; static const int kAlbumSearchLimit; static const int kSearchDelayMsec; static const char* kApiKey; static const char* kApiSecret; }; #endif // GROOVESHARKSERVICE_H