diff --git a/data/data.qrc b/data/data.qrc index 346b6bf6c..a944cff24 100644 --- a/data/data.qrc +++ b/data/data.qrc @@ -9,7 +9,6 @@ currenttrack_pause.png currenttrack_play.png globalsearch.css - grooveshark-valicert-ca.pem hypnotoad.gif icon_large_grey.png icon_large.png @@ -320,7 +319,6 @@ providers/dropbox.png providers/echonest.png providers/googledrive.png - providers/grooveshark.png providers/itunes.png providers/jamendo.png providers/jazzradio.png diff --git a/data/grooveshark-valicert-ca.pem b/data/grooveshark-valicert-ca.pem deleted file mode 100644 index 1cb1d7126..000000000 --- a/data/grooveshark-valicert-ca.pem +++ /dev/null @@ -1,43 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy -NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY -dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 -WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS -v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v -UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu -IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC -W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh -MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE -YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 -MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo -ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg -MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN -ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA -PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w -wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi -EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY -avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ -YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE -sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h -/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 -IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy -OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P -TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER -dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf -ReYNnyicsbkqWletNw+vHX/bvZ8= ------END CERTIFICATE----- diff --git a/data/providers/grooveshark.png b/data/providers/grooveshark.png deleted file mode 100644 index 98f9fa63c..000000000 Binary files a/data/providers/grooveshark.png and /dev/null differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc87333f6..d62f9a898 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -147,7 +147,6 @@ set(SOURCES globalsearch/globalsearchsettingspage.cpp globalsearch/globalsearchsortmodel.cpp globalsearch/globalsearchview.cpp - globalsearch/groovesharksearchprovider.cpp globalsearch/icecastsearchprovider.cpp globalsearch/librarysearchprovider.cpp globalsearch/savedradiosearchprovider.cpp @@ -167,10 +166,6 @@ set(SOURCES internet/digitally/digitallyimportedsettingspage.cpp internet/digitally/digitallyimportedurlhandler.cpp internet/core/geolocator.cpp - internet/grooveshark/groovesharkradio.cpp - internet/grooveshark/groovesharkservice.cpp - internet/grooveshark/groovesharksettingspage.cpp - internet/grooveshark/groovesharkurlhandler.cpp internet/icecast/icecastbackend.cpp internet/icecast/icecastfilterwidget.cpp internet/icecast/icecastmodel.cpp @@ -464,7 +459,6 @@ set(HEADERS globalsearch/globalsearchmodel.h globalsearch/globalsearchsettingspage.h globalsearch/globalsearchview.h - globalsearch/groovesharksearchprovider.h globalsearch/searchprovider.h globalsearch/simplesearchprovider.h globalsearch/soundcloudsearchprovider.h @@ -476,9 +470,6 @@ set(HEADERS internet/digitally/digitallyimportedservicebase.h internet/digitally/digitallyimportedsettingspage.h internet/core/geolocator.h - internet/grooveshark/groovesharkservice.h - internet/grooveshark/groovesharksettingspage.h - internet/grooveshark/groovesharkurlhandler.h internet/icecast/icecastbackend.h internet/icecast/icecastfilterwidget.h internet/icecast/icecastmodel.h @@ -694,7 +685,6 @@ set(UI globalsearch/suggestionwidget.ui internet/digitally/digitallyimportedsettingspage.ui - internet/grooveshark/groovesharksettingspage.ui internet/icecast/icecastfilterwidget.ui internet/core/internetshowsettingspage.ui internet/core/internetviewcontainer.ui diff --git a/src/engines/gstenginepipeline.cpp b/src/engines/gstenginepipeline.cpp index 7ca19408f..b81791713 100644 --- a/src/engines/gstenginepipeline.cpp +++ b/src/engines/gstenginepipeline.cpp @@ -890,19 +890,6 @@ void GstEnginePipeline::SourceSetupCallback(GstURIDecodeBin* bin, g_object_set(element, "device", instance->source_device().toLocal8Bit().constData(), nullptr); } - if (g_object_class_find_property(G_OBJECT_GET_CLASS(element), - "extra-headers") && - instance->url().host().contains("grooveshark")) { - // Grooveshark streaming servers will answer with a 400 error 'Bad request' - // if we don't specify 'Range' field in HTTP header. - // Maybe it could be useful in some other cases, but for now, I prefer to - // keep this grooveshark specific. - GstStructure* headers; - headers = gst_structure_new("extra-headers", "Range", G_TYPE_STRING, - "bytes=0-", nullptr); - g_object_set(element, "extra-headers", headers, nullptr); - gst_structure_free(headers); - } if (g_object_class_find_property(G_OBJECT_GET_CLASS(element), "extra-headers") && instance->url().host().contains("amazonaws.com")) { diff --git a/src/globalsearch/groovesharksearchprovider.cpp b/src/globalsearch/groovesharksearchprovider.cpp deleted file mode 100644 index aa96a1c7b..000000000 --- a/src/globalsearch/groovesharksearchprovider.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* 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 . -*/ - -#include "groovesharksearchprovider.h" - -#include - -#include "core/application.h" -#include "core/logging.h" -#include "covers/albumcoverloader.h" -#include "internet/grooveshark/groovesharkservice.h" - -GroovesharkSearchProvider::GroovesharkSearchProvider(Application* app, - QObject* parent) - : SearchProvider(app, parent), service_(nullptr) {} - -void GroovesharkSearchProvider::Init(GroovesharkService* service) { - service_ = service; - SearchProvider::Init( - "Grooveshark", "grooveshark", QIcon(":providers/grooveshark.png"), - WantsDelayedQueries | ArtIsProbablyRemote | CanShowConfig); - - connect(service_, SIGNAL(SimpleSearchResults(int, SongList)), - SLOT(SearchDone(int, SongList))); - connect(service_, SIGNAL(AlbumSearchResult(int, QList)), - SLOT(AlbumSearchResult(int, QList))); - connect(service_, SIGNAL(AlbumSongsLoaded(quint64, SongList)), - SLOT(AlbumSongsLoaded(quint64, SongList))); - - cover_loader_options_.desired_height_ = kArtHeight; - cover_loader_options_.pad_output_image_ = true; - cover_loader_options_.scale_output_image_ = true; - - connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)), - SLOT(AlbumArtLoaded(quint64, QImage))); -} - -void GroovesharkSearchProvider::SearchAsync(int id, const QString& query) { - const int service_id = service_->SimpleSearch(query); - pending_searches_[service_id] = PendingState(id, TokenizeQuery(query)); - ; - - const int album_id = service_->SearchAlbums(query); - pending_searches_[album_id] = PendingState(id, TokenizeQuery(query)); -} - -void GroovesharkSearchProvider::SearchDone(int id, const SongList& songs) { - // Map back to the original id. - const PendingState state = pending_searches_.take(id); - const int global_search_id = state.orig_id_; - - ResultList ret; - for (const Song& song : songs) { - Result result(this); - result.metadata_ = song; - - ret << result; - } - - emit ResultsAvailable(global_search_id, ret); - MaybeSearchFinished(global_search_id); -} - -void GroovesharkSearchProvider::AlbumSearchResult( - int id, const QList& albums_ids) { - // Map back to the original id. - const PendingState state = pending_searches_.take(id); - const int global_search_id = state.orig_id_; - if (albums_ids.isEmpty()) { - MaybeSearchFinished(global_search_id); - return; - } - for (const quint64 album_id : albums_ids) { - pending_searches_[album_id] = PendingState(global_search_id, QStringList()); - } -} - -void GroovesharkSearchProvider::MaybeSearchFinished(int id) { - if (pending_searches_.keys(PendingState(id, QStringList())).isEmpty()) { - emit SearchFinished(id); - } -} - -void GroovesharkSearchProvider::LoadArtAsync(int id, const Result& result) { - quint64 loader_id = app_->album_cover_loader()->LoadImageAsync( - cover_loader_options_, result.metadata_); - cover_loader_tasks_[loader_id] = id; -} - -void GroovesharkSearchProvider::AlbumArtLoaded(quint64 id, - const QImage& image) { - if (!cover_loader_tasks_.contains(id)) { - return; - } - int original_id = cover_loader_tasks_.take(id); - emit ArtLoaded(original_id, image); -} - -bool GroovesharkSearchProvider::IsLoggedIn() { - return (service_ && service_->IsLoggedIn()); -} - -void GroovesharkSearchProvider::ShowConfig() { service_->ShowConfig(); } - -void GroovesharkSearchProvider::AlbumSongsLoaded(quint64 id, - const SongList& songs) { - const PendingState state = pending_searches_.take(id); - const int global_search_id = state.orig_id_; - ResultList ret; - for (const Song& s : songs) { - Result result(this); - result.metadata_ = s; - ret << result; - } - - emit ResultsAvailable(global_search_id, ret); - MaybeSearchFinished(global_search_id); -} diff --git a/src/globalsearch/groovesharksearchprovider.h b/src/globalsearch/groovesharksearchprovider.h deleted file mode 100644 index c4aedd119..000000000 --- a/src/globalsearch/groovesharksearchprovider.h +++ /dev/null @@ -1,57 +0,0 @@ -/* 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 GROOVESHARKSEARCHPROVIDER_H -#define GROOVESHARKSEARCHPROVIDER_H - -#include "searchprovider.h" -#include "covers/albumcoverloaderoptions.h" -#include "internet/grooveshark/groovesharkservice.h" - -class AlbumCoverLoader; - -class GroovesharkSearchProvider : public SearchProvider { - Q_OBJECT - - public: - explicit GroovesharkSearchProvider(Application* app, QObject* parent = nullptr); - void Init(GroovesharkService* service); - - // SearchProvider - void SearchAsync(int id, const QString& query) override; - void LoadArtAsync(int id, const Result& result) override; - bool IsLoggedIn() override; - void ShowConfig() override; - InternetService* internet_service() override { return service_; } - - private slots: - void SearchDone(int id, const SongList& songs); - void AlbumSearchResult(int id, const QList& albums_ids); - void AlbumArtLoaded(quint64 id, const QImage& image); - void AlbumSongsLoaded(quint64 id, const SongList& songs); - - private: - void MaybeSearchFinished(int id); - - GroovesharkService* service_; - QMap pending_searches_; - - AlbumCoverLoaderOptions cover_loader_options_; - QMap cover_loader_tasks_; -}; - -#endif diff --git a/src/internet/core/internetmodel.cpp b/src/internet/core/internetmodel.cpp index 09754cd5e..707811d68 100644 --- a/src/internet/core/internetmodel.cpp +++ b/src/internet/core/internetmodel.cpp @@ -29,7 +29,6 @@ #include #include "internet/digitally/digitallyimportedservicebase.h" -#include "internet/grooveshark/groovesharkservice.h" #include "internet/icecast/icecastservice.h" #include "internet/core/internetmimedata.h" #include "internet/core/internetservice.h" @@ -90,7 +89,6 @@ InternetModel::InternetModel(Application* app, QObject* parent) AddService(new DigitallyImportedService(app, this)); AddService(new IcecastService(app, this)); AddService(new JamendoService(app, this)); - AddService(new GroovesharkService(app, this)); AddService(new JazzRadioService(app, this)); AddService(new MagnatuneService(app, this)); AddService(new PodcastService(app, this)); diff --git a/src/internet/grooveshark/groovesharkradio.cpp b/src/internet/grooveshark/groovesharkradio.cpp deleted file mode 100644 index df5326421..000000000 --- a/src/internet/grooveshark/groovesharkradio.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* This file is part of Clementine. - Copyright 2011, Arnaud Bienner - Copyright 2014, Krzysztof Sobiecki - Copyright 2014, John Maguire - - 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 . -*/ - -#include "groovesharkradio.h" - -#include "groovesharkservice.h" -#include "core/logging.h" -#include "internet/core/internetplaylistitem.h" - -GroovesharkRadio::GroovesharkRadio(GroovesharkService* service) - : service_(service), tag_id_(0), use_tag_(false), first_time_(true) {} - -GroovesharkRadio::GroovesharkRadio(GroovesharkService* service, int tag_id) - : service_(service), tag_id_(tag_id), use_tag_(true), first_time_(true) {} - -void GroovesharkRadio::Load(const QByteArray& data) {} - -QByteArray GroovesharkRadio::Save() const { return QByteArray(); } - -PlaylistItemList GroovesharkRadio::Generate() { - PlaylistItemList items; - if (first_time_) { - Song song; - if (use_tag_) { - song = service_->StartAutoplayTag(tag_id_, autoplay_state_); - } else { - song = service_->StartAutoplay(autoplay_state_); - } - // If the song url isn't valid, stop here - if (!song.is_valid()) { - return items; - } - PlaylistItemPtr playlist_item = - PlaylistItemPtr(new InternetPlaylistItem(service_, song)); - items << playlist_item; - first_time_ = false; - } - Song song = service_->GetAutoplaySong(autoplay_state_); - if (!song.is_valid()) { - return items; - } - PlaylistItemPtr playlist_item = - PlaylistItemPtr(new InternetPlaylistItem(service_, song)); - items << playlist_item; - return items; -} diff --git a/src/internet/grooveshark/groovesharkradio.h b/src/internet/grooveshark/groovesharkradio.h deleted file mode 100644 index b36d9e8b4..000000000 --- a/src/internet/grooveshark/groovesharkradio.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Clementine. - Copyright 2011, Arnaud Bienner - Copyright 2014, Krzysztof Sobiecki - Copyright 2014, John Maguire - - 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 INTERNET_GROOVESHARK_GROOVESHARKRADIO_H_ -#define INTERNET_GROOVESHARK_GROOVESHARKRADIO_H_ - -#include "smartplaylists/generator.h" - -class GroovesharkService; - -class GroovesharkRadio : public smart_playlists::Generator { - public: - // Start Grooveshark radio for a particular type of music - GroovesharkRadio(GroovesharkService* service, int tag_id); - // Start Grooveshark radio based on last artists and songs you listen to - explicit GroovesharkRadio(GroovesharkService* service); - - QString type() const { return "Grooveshark"; } - void Load(const QByteArray& data); - QByteArray Save() const; - PlaylistItemList Generate(); - PlaylistItemList GenerateMore(int count) { return Generate(); } - bool is_dynamic() const { return true; } - - private: - GroovesharkService* service_; - int tag_id_; - // Boolean to specify if we should use tag. If not, we will used autoplay - // without tag - bool use_tag_; - // For Generate: indicates if it's the first time we generate songs - bool first_time_; - QVariantMap autoplay_state_; -}; - -#endif // INTERNET_GROOVESHARK_GROOVESHARKRADIO_H_ diff --git a/src/internet/grooveshark/groovesharkservice.cpp b/src/internet/grooveshark/groovesharkservice.cpp deleted file mode 100644 index b97d4d3c1..000000000 --- a/src/internet/grooveshark/groovesharkservice.cpp +++ /dev/null @@ -1,1829 +0,0 @@ -/* This file is part of Clementine. - Copyright 2011-2014, Arnaud Bienner - Copyright 2011-2012, 2014, John Maguire - Copyright 2011, HYPNOTOAD - Copyright 2011-2012, David Sansome - Copyright 2014, Antonio Nicolás Pina - Copyright 2014, Krzysztof Sobiecki - - 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 . - */ - -#include "groovesharkservice.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "qtiocompressor.h" - -#include "internet/core/internetmodel.h" -#include "groovesharkradio.h" -#include "groovesharkurlhandler.h" -#include "internet/core/searchboxwidget.h" - -#include "core/application.h" -#include "core/closure.h" -#include "core/database.h" -#include "core/logging.h" -#include "core/mergedproxymodel.h" -#include "core/network.h" -#include "core/player.h" -#include "core/scopedtransaction.h" -#include "core/song.h" -#include "core/taskmanager.h" -#include "core/timeconstants.h" -#include "core/utilities.h" -#include "globalsearch/globalsearch.h" -#include "globalsearch/groovesharksearchprovider.h" -#include "playlist/playlist.h" -#include "playlist/playlistcontainer.h" -#include "playlist/playlistmanager.h" -#include "ui/iconloader.h" - -using smart_playlists::Generator; -using smart_playlists::GeneratorPtr; - -// The Grooveshark terms of service require that application keys are not -// accessible to third parties. Therefore this application key is obfuscated to -// prevent third parties from viewing it. -const char* GroovesharkService::kApiKey = "clementineplayer"; -const char* GroovesharkService::kApiSecret = - "OzLDTB5XqmhkkhxMUK0/Mp5PQgD5O27DTEJa/jtkwEw="; - -const char* GroovesharkService::kServiceName = "Grooveshark"; -const char* GroovesharkService::kSettingsGroup = "Grooveshark"; -const char* GroovesharkService::kUrl = "http://api.grooveshark.com/ws/3.0/"; -const char* GroovesharkService::kUrlCover = - "http://beta.grooveshark.com/static/amazonart/l"; -const char* GroovesharkService::kHomepage = "http://grooveshark.com/"; - -const int GroovesharkService::kSongSearchLimit = 100; -const int GroovesharkService::kSongSimpleSearchLimit = 10; -const int GroovesharkService::kAlbumSearchLimit = 10; - -const int GroovesharkService::kSearchDelayMsec = 400; - -typedef QPair Param; - -GroovesharkService::GroovesharkService(Application* app, InternetModel* parent) - : InternetService(kServiceName, app, parent, parent), - url_handler_(new GroovesharkUrlHandler(this, this)), - next_pending_search_id_(0), - next_pending_playlist_retrieve_id_(0), - root_(nullptr), - search_(nullptr), - popular_month_(nullptr), - popular_today_(nullptr), - stations_(nullptr), - grooveshark_radio_(nullptr), - favorites_(nullptr), - library_(nullptr), - playlists_parent_(nullptr), - subscribed_playlists_parent_(nullptr), - network_(new NetworkAccessManager(this)), - context_menu_(nullptr), - create_playlist_(nullptr), - delete_playlist_(nullptr), - rename_playlist_(nullptr), - remove_from_playlist_(nullptr), - remove_from_favorites_(nullptr), - remove_from_library_(nullptr), - get_url_to_share_song_(nullptr), - get_url_to_share_playlist_(nullptr), - search_box_(new SearchBoxWidget(this)), - search_delay_(new QTimer(this)), - last_search_reply_(nullptr), - api_key_(QByteArray::fromBase64(kApiSecret)), - login_state_(LoginState_OtherError), - task_popular_id_(0), - task_playlists_id_(0), - task_search_id_(0) { - app_->player()->RegisterUrlHandler(url_handler_); - - search_delay_->setInterval(kSearchDelayMsec); - search_delay_->setSingleShot(true); - connect(search_delay_, SIGNAL(timeout()), SLOT(DoSearch())); - - // Get already existing (authenticated) session id, if any - QSettings s; - s.beginGroup(GroovesharkService::kSettingsGroup); - session_id_ = s.value("sessionid").toString(); - username_ = s.value("username").toString(); - - GroovesharkSearchProvider* search_provider = - new GroovesharkSearchProvider(app_, this); - search_provider->Init(this); - app_->global_search()->AddProvider(search_provider); - - // Init secret: this code is ugly, but that's good as nobody is supposed to - // wonder what it does - QByteArray ba = - QByteArray::fromBase64(QCoreApplication::applicationName().toLatin1()); - int n = api_key_.length(), n2 = ba.length(); - for (int i = 0; i < n; i++) api_key_[i] = api_key_[i] ^ ba[i % n2]; - - connect(search_box_, SIGNAL(TextChanged(QString)), SLOT(Search(QString))); -} - -GroovesharkService::~GroovesharkService() {} - -QStandardItem* GroovesharkService::CreateRootItem() { - root_ = new QStandardItem(QIcon(":providers/grooveshark.png"), kServiceName); - root_->setData(true, InternetModel::Role_CanLazyLoad); - root_->setData(InternetModel::PlayBehaviour_DoubleClickAction, - InternetModel::Role_PlayBehaviour); - return root_; -} - -void GroovesharkService::LazyPopulate(QStandardItem* item) { - switch (item->data(InternetModel::Role_Type).toInt()) { - case InternetModel::Type_Service: { - EnsureConnected(); - break; - } - default: - break; - } -} - -void GroovesharkService::ShowConfig() { - app_->OpenSettingsDialogAtPage(SettingsDialog::Page_Grooveshark); -} - -QWidget* GroovesharkService::HeaderWidget() const { - if (IsLoggedIn()) return search_box_; - return nullptr; -} - -void GroovesharkService::Search(const QString& text, bool now) { - pending_search_ = text; - - // If there is no text (e.g. user cleared search box), we don't need to do a - // real query that will return nothing: we can clear the playlist now - if (text.isEmpty()) { - search_delay_->stop(); - ClearSearchResults(); - return; - } - - if (now) { - search_delay_->stop(); - DoSearch(); - } else { - search_delay_->start(); - } -} - -int GroovesharkService::SimpleSearch(const QString& query) { - QList parameters; - parameters << Param("query", query) << Param("country", "") - << Param("limit", QString::number(kSongSimpleSearchLimit)) - << Param("offset", ""); - - int id = next_pending_search_id_++; - QNetworkReply* reply = CreateRequest("getSongSearchResults", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(SimpleSearchFinished(QNetworkReply*, int)), reply, id); - return id; -} - -void GroovesharkService::SimpleSearchFinished(QNetworkReply* reply, int id) { - reply->deleteLater(); - - QVariantMap result = ExtractResult(reply); - SongList songs = ExtractSongs(result); - emit SimpleSearchResults(id, songs); -} - -int GroovesharkService::SearchAlbums(const QString& query) { - QList parameters; - parameters << Param("query", query) << Param("country", "") - << Param("limit", QString::number(kAlbumSearchLimit)); - - QNetworkReply* reply = CreateRequest("getAlbumSearchResults", parameters); - - const int id = next_pending_search_id_++; - - NewClosure(reply, SIGNAL(finished()), this, - SLOT(SearchAlbumsFinished(QNetworkReply*, int)), reply, id); - - return id; -} - -void GroovesharkService::SearchAlbumsFinished(QNetworkReply* reply, int id) { - reply->deleteLater(); - - QVariantMap result = ExtractResult(reply); - QVariantList albums = result["albums"].toList(); - - QList ret; - for (const QVariant& v : albums) { - quint64 album_id = v.toMap()["AlbumID"].toULongLong(); - GetAlbumSongs(album_id); - ret << album_id; - } - - emit AlbumSearchResult(id, ret); -} - -void GroovesharkService::GetAlbumSongs(quint64 album_id) { - QList parameters; - parameters << Param("albumID", album_id) << Param("country", ""); - QNetworkReply* reply = CreateRequest("getAlbumSongs", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(GetAlbumSongsFinished(QNetworkReply*, quint64)), reply, - album_id); -} - -void GroovesharkService::GetAlbumSongsFinished(QNetworkReply* reply, - quint64 album_id) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - SongList songs = ExtractSongs(result); - - emit AlbumSongsLoaded(album_id, songs); -} - -void GroovesharkService::DoSearch() { - if (!task_search_id_) { - task_search_id_ = - app_->task_manager()->StartTask(tr("Searching on Grooveshark")); - } - - ClearSearchResults(); - - QList parameters; - parameters << Param("query", pending_search_) << Param("country", "") - << Param("limit", QString::number(kSongSearchLimit)) - << Param("offset", ""); - last_search_reply_ = CreateRequest("getSongSearchResults", parameters); - NewClosure(last_search_reply_, SIGNAL(finished()), this, - SLOT(SearchSongsFinished(QNetworkReply*)), last_search_reply_); -} - -void GroovesharkService::SearchSongsFinished(QNetworkReply* reply) { - reply->deleteLater(); - - if (reply != last_search_reply_) return; - - QVariantMap result = ExtractResult(reply); - SongList songs = ExtractSongs(result); - app_->task_manager()->SetTaskFinished(task_search_id_); - task_search_id_ = 0; - - // Fill results list - if (!search_) return; - for (const Song& song : songs) { - QStandardItem* child = CreateSongItem(song); - search_->appendRow(child); - } - - QModelIndex index = model()->merged_model()->mapFromSource(search_->index()); - ScrollToIndex(index); -} - -void GroovesharkService::InitCountry() { - if (!country_.isEmpty()) return; - // Get country info - QNetworkReply* reply_country = CreateRequest("getCountry", QList()); - if (WaitForReply(reply_country)) { - country_ = ExtractResult(reply_country); - } - reply_country->deleteLater(); -} - -QUrl GroovesharkService::GetStreamingUrlFromSongId(const QString& song_id, - const QString& artist_id, - QString* server_id, - QString* stream_key, - qint64* length_nanosec) { - QList parameters; - - InitCountry(); - parameters << Param("songID", song_id) << Param("country", country_); - QNetworkReply* reply = CreateRequest("getSubscriberStreamKey", parameters); - - // Wait for the reply - bool reply_has_timeouted = !WaitForReply(reply); - reply->deleteLater(); - if (reply_has_timeouted) return QUrl(); - - QVariantMap result = ExtractResult(reply); - server_id->clear(); - server_id->append(result["StreamServerID"].toString()); - stream_key->clear(); - stream_key->append(result["StreamKey"].toString()); - *length_nanosec = result["uSecs"].toLongLong() * 1000; - // Keep in mind that user has request to listen to this song - last_songs_ids_.append(song_id.toInt()); - last_artists_ids_.append(artist_id.toInt()); - // If we have enough ids, remove the old ones - if (last_songs_ids_.size() > 100) last_songs_ids_.removeFirst(); - if (last_artists_ids_.size() > 100) last_artists_ids_.removeFirst(); - - return QUrl(result["url"].toString()); -} - -void GroovesharkService::Login(const QString& username, - const QString& password) { - // To login, we first need to create a session. Next, we will authenticate - // this session using the user's username and password (for now, we just keep - // them in mind) - username_ = username; - password_ = QCryptographicHash::hash(password.toLocal8Bit(), - QCryptographicHash::Md5).toHex(); - - QList parameters; - QNetworkReply* reply = CreateRequest("startSession", parameters, true); - - NewClosure(reply, SIGNAL(finished()), this, - SLOT(SessionCreated(QNetworkReply*)), reply); -} - -void GroovesharkService::SessionCreated(QNetworkReply* reply) { - reply->deleteLater(); - - if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != - 200) { - emit StreamError("Failed to create Grooveshark session: " + - reply->errorString()); - emit LoginFinished(false); - return; - } - - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Error) << "Grooveshark returned an error during session creation"; - } - session_id_ = result["sessionID"].toString(); - qLog(Debug) << "Session ID returned: " << session_id_; - - AuthenticateSession(); -} - -void GroovesharkService::AuthenticateSession() { - QList parameters; - parameters << Param("login", username_) << Param("password", password_); - - QNetworkReply* reply = CreateRequest("authenticate", parameters, true); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(Authenticated(QNetworkReply*)), reply); -} - -void GroovesharkService::Authenticated(QNetworkReply* reply) { - reply->deleteLater(); - - QVariantMap result = ExtractResult(reply); - // Check if the user has been authenticated correctly - QString error; - if (!result["success"].toBool() || result["UserID"].toInt() == 0) { - error = tr("Invalid username and/or password"); - login_state_ = LoginState_AuthFailed; - } else if (!result["IsAnywhere"].toBool() || !result["IsPremium"].toBool()) { - error = tr("User %1 doesn't have a Grooveshark Anywhere account") - .arg(username_); - login_state_ = LoginState_NoPremium; - } - if (!error.isEmpty()) { - QMessageBox::warning(nullptr, tr("Grooveshark login error"), error, - QMessageBox::Close); - ResetSessionId(); - emit LoginFinished(false); - return; - } - login_state_ = LoginState_LoggedIn; - user_id_ = result["UserID"].toString(); - emit LoginFinished(true); - EnsureItemsCreated(); -} - -void GroovesharkService::ClearSearchResults() { - if (search_) search_->removeRows(0, search_->rowCount()); -} - -void GroovesharkService::Logout() { - ResetSessionId(); - RemoveItems(); -} - -void GroovesharkService::RemoveItems() { - root_->removeRows(0, root_->rowCount()); - // 'search', 'favorites', 'popular', ... items were root's children, and have - // been deleted: we should update these now invalid pointers - search_ = nullptr; - popular_month_ = nullptr; - popular_today_ = nullptr; - library_ = nullptr; - favorites_ = nullptr; - subscribed_playlists_parent_ = nullptr; - stations_ = nullptr; - grooveshark_radio_ = nullptr; - playlists_parent_ = nullptr; - playlists_.clear(); - subscribed_playlists_parent_ = nullptr; - subscribed_playlists_.clear(); - // Cancel any pending requests and mark tasks as finished, in case they - // weren't - // finished yet. - pending_retrieve_playlists_.clear(); - app_->task_manager()->SetTaskFinished(task_playlists_id_); - app_->task_manager()->SetTaskFinished(task_popular_id_); - app_->task_manager()->SetTaskFinished(task_search_id_); -} - -void GroovesharkService::ResetSessionId() { - QSettings s; - s.beginGroup(GroovesharkService::kSettingsGroup); - - session_id_.clear(); - s.setValue("sessionid", session_id_); -} - -void GroovesharkService::ShowContextMenu(const QPoint& global_pos) { - EnsureMenuCreated(); - - // Check if we should display actions - bool display_delete_playlist_action = false, - display_remove_from_playlist_action = false, - display_remove_from_favorites_action = false, - display_remove_from_library_action = false, - display_share_song_url = false, display_share_playlist_url = false; - - QModelIndex index(model()->current_index()); - - if (index.data(InternetModel::Role_Type).toInt() == - InternetModel::Type_UserPlaylist && - index.data(Role_PlaylistType).toInt() == UserPlaylist) { - display_delete_playlist_action = true; - } - // We check parent's type (instead of index type) because we want to enable - // 'remove' actions for items which are inside a playlist - int parent_type = index.parent().data(InternetModel::Role_Type).toInt(); - if (parent_type == InternetModel::Type_UserPlaylist) { - int parent_playlist_type = index.parent().data(Role_PlaylistType).toInt(); - if (parent_playlist_type == UserFavorites) - display_remove_from_favorites_action = true; - else if (parent_playlist_type == UserLibrary) - display_remove_from_library_action = true; - else if (parent_playlist_type == UserPlaylist) - display_remove_from_playlist_action = true; - } - delete_playlist_->setVisible(display_delete_playlist_action); - // If we can delete this playlist, we can also rename it - rename_playlist_->setVisible(display_delete_playlist_action); - remove_from_playlist_->setVisible(display_remove_from_playlist_action); - remove_from_favorites_->setVisible(display_remove_from_favorites_action); - remove_from_library_->setVisible(display_remove_from_library_action); - - // Check if we can display actions to get URL for sharing songs/playlists: - // - share song - if (index.data(InternetModel::Role_Type).toInt() == - InternetModel::Type_Track) { - display_share_song_url = true; - current_song_id_ = - ExtractSongId(index.data(InternetModel::Role_Url).toUrl()); - } - get_url_to_share_song_->setVisible(display_share_song_url); - - // - share playlist - if (index.data(InternetModel::Role_Type).toInt() == - InternetModel::Type_UserPlaylist && - index.data(Role_UserPlaylistId).isValid()) { - display_share_playlist_url = true; - current_playlist_id_ = index.data(Role_UserPlaylistId).toInt(); - } else if (parent_type == InternetModel::Type_UserPlaylist && - index.parent().data(Role_UserPlaylistId).isValid()) { - display_share_playlist_url = true; - current_playlist_id_ = index.parent().data(Role_UserPlaylistId).toInt(); - } - get_url_to_share_playlist_->setVisible(display_share_playlist_url); - - context_menu_->popup(global_pos); -} - -void GroovesharkService::EnsureMenuCreated() { - if (!context_menu_) { - context_menu_ = new QMenu; - context_menu_->addActions(GetPlaylistActions()); - create_playlist_ = context_menu_->addAction( - IconLoader::Load("list-add"), tr("Create a new Grooveshark playlist"), - this, SLOT(CreateNewPlaylist())); - delete_playlist_ = context_menu_->addAction( - IconLoader::Load("edit-delete"), tr("Delete Grooveshark playlist"), - this, SLOT(DeleteCurrentPlaylist())); - rename_playlist_ = context_menu_->addAction( - IconLoader::Load("edit-rename"), tr("Rename Grooveshark playlist"), - this, SLOT(RenameCurrentPlaylist())); - context_menu_->addSeparator(); - remove_from_playlist_ = context_menu_->addAction( - IconLoader::Load("list-remove"), tr("Remove from playlist"), this, - SLOT(RemoveCurrentFromPlaylist())); - remove_from_favorites_ = context_menu_->addAction( - IconLoader::Load("list-remove"), tr("Remove from favorites"), this, - SLOT(RemoveCurrentFromFavorites())); - remove_from_library_ = context_menu_->addAction( - IconLoader::Load("list-remove"), tr("Remove from My Music"), this, - SLOT(RemoveCurrentFromLibrary())); - get_url_to_share_song_ = - context_menu_->addAction(tr("Get a URL to share this Grooveshark song"), - this, SLOT(GetCurrentSongUrlToShare())); - get_url_to_share_playlist_ = context_menu_->addAction( - tr("Get a URL to share this Grooveshark playlist"), this, - SLOT(GetCurrentPlaylistUrlToShare())); - context_menu_->addSeparator(); - context_menu_->addAction(IconLoader::Load("download"), - tr("Open %1 in browser").arg("grooveshark.com"), - this, SLOT(Homepage())); - context_menu_->addAction(IconLoader::Load("view-refresh"), tr("Refresh"), - this, SLOT(RefreshItems())); - context_menu_->addSeparator(); - context_menu_->addAction(IconLoader::Load("configure"), - tr("Configure Grooveshark..."), this, - SLOT(ShowConfig())); - } -} - -void GroovesharkService::Homepage() { - QDesktopServices::openUrl(QUrl(kHomepage)); -} - -void GroovesharkService::RefreshItems() { - RemoveItems(); - EnsureItemsCreated(); -} - -void GroovesharkService::EnsureItemsCreated() { - if (IsLoggedIn() && !search_) { - search_ = - new QStandardItem(IconLoader::Load("edit-find"), tr("Search results")); - search_->setToolTip( - tr("Start typing something on the search box above to " - "fill this search results list")); - search_->setData(InternetModel::PlayBehaviour_MultipleItems, - InternetModel::Role_PlayBehaviour); - root_->appendRow(search_); - - QStandardItem* popular = - new QStandardItem(QIcon(":/star-on.png"), tr("Popular songs")); - root_->appendRow(popular); - - popular_month_ = new QStandardItem(QIcon(":/star-on.png"), - tr("Popular songs of the Month")); - popular_month_->setData(InternetModel::Type_UserPlaylist, - InternetModel::Role_Type); - popular_month_->setData(true, InternetModel::Role_CanLazyLoad); - popular_month_->setData(InternetModel::PlayBehaviour_MultipleItems, - InternetModel::Role_PlayBehaviour); - popular->appendRow(popular_month_); - - popular_today_ = - new QStandardItem(QIcon(":/star-on.png"), tr("Popular songs today")); - popular_today_->setData(InternetModel::Type_UserPlaylist, - InternetModel::Role_Type); - popular_today_->setData(true, InternetModel::Role_CanLazyLoad); - popular_today_->setData(InternetModel::PlayBehaviour_MultipleItems, - InternetModel::Role_PlayBehaviour); - popular->appendRow(popular_today_); - - QStandardItem* radios_divider = - new QStandardItem(QIcon(":last.fm/icon_radio.png"), tr("Radios")); - root_->appendRow(radios_divider); - - stations_ = - new QStandardItem(QIcon(":last.fm/icon_radio.png"), tr("Stations")); - stations_->setData(InternetModel::Type_UserPlaylist, - InternetModel::Role_Type); - stations_->setData(true, InternetModel::Role_CanLazyLoad); - radios_divider->appendRow(stations_); - - grooveshark_radio_ = new QStandardItem(QIcon(":last.fm/icon_radio.png"), - tr("Grooveshark radio")); - grooveshark_radio_->setToolTip( - tr("Listen to Grooveshark songs based on what you've listened to " - "previously")); - grooveshark_radio_->setData(InternetModel::Type_SmartPlaylist, - InternetModel::Role_Type); - radios_divider->appendRow(grooveshark_radio_); - - library_ = - new QStandardItem(IconLoader::Load("folder-sound"), tr("My Music")); - library_->setData(InternetModel::Type_UserPlaylist, - InternetModel::Role_Type); - library_->setData(UserLibrary, Role_PlaylistType); - library_->setData(true, InternetModel::Role_CanLazyLoad); - library_->setData(true, InternetModel::Role_CanBeModified); - library_->setData(InternetModel::PlayBehaviour_MultipleItems, - InternetModel::Role_PlayBehaviour); - root_->appendRow(library_); - - favorites_ = - new QStandardItem(QIcon(":/last.fm/love.png"), tr("Favorites")); - favorites_->setData(InternetModel::Type_UserPlaylist, - InternetModel::Role_Type); - favorites_->setData(UserFavorites, Role_PlaylistType); - favorites_->setData(true, InternetModel::Role_CanLazyLoad); - favorites_->setData(true, InternetModel::Role_CanBeModified); - favorites_->setData(InternetModel::PlayBehaviour_MultipleItems, - InternetModel::Role_PlayBehaviour); - root_->appendRow(favorites_); - - playlists_parent_ = new QStandardItem(tr("Playlists")); - root_->appendRow(playlists_parent_); - - subscribed_playlists_parent_ = - new QStandardItem(tr("Subscribed playlists")); - root_->appendRow(subscribed_playlists_parent_); - - RetrieveUserFavorites(); - RetrieveUserLibrarySongs(); - RetrieveUserPlaylists(); - RetrieveSubscribedPlaylists(); - RetrieveAutoplayTags(); - RetrievePopularSongs(); - } -} - -void GroovesharkService::EnsureConnected() { - if (session_id_.isEmpty()) { - ShowConfig(); - } else { - EnsureItemsCreated(); - } -} - -QStandardItem* GroovesharkService::CreatePlaylistItem( - const QString& playlist_name, int playlist_id) { - QStandardItem* item = new QStandardItem(playlist_name); - item->setData(InternetModel::Type_UserPlaylist, InternetModel::Role_Type); - item->setData(UserPlaylist, Role_PlaylistType); - item->setData(true, InternetModel::Role_CanLazyLoad); - item->setData(true, InternetModel::Role_CanBeModified); - item->setData(InternetModel::PlayBehaviour_MultipleItems, - InternetModel::Role_PlayBehaviour); - item->setData(playlist_id, Role_UserPlaylistId); - return item; -} - -void GroovesharkService::RetrieveUserPlaylists() { - task_playlists_id_ = - app_->task_manager()->StartTask(tr("Retrieving Grooveshark playlists")); - QNetworkReply* reply = CreateRequest("getUserPlaylists", QList()); - - NewClosure(reply, SIGNAL(finished()), this, - SLOT(UserPlaylistsRetrieved(QNetworkReply*)), reply); -} - -void GroovesharkService::UserPlaylistsRetrieved(QNetworkReply* reply) { - reply->deleteLater(); - - QVariantMap result = ExtractResult(reply); - QList playlists = ExtractPlaylistInfo(result); - - for (const PlaylistInfo& playlist_info : playlists) { - int playlist_id = playlist_info.id_; - const QString& playlist_name = playlist_info.name_; - QStandardItem* playlist_item = - CreatePlaylistItem(playlist_name, playlist_id); - playlists_parent_->appendRow(playlist_item); - - // Keep in mind this playlist - playlists_.insert(playlist_id, - PlaylistInfo(playlist_id, playlist_name, playlist_item)); - - // Request playlist's songs - RefreshPlaylist(playlist_id); - } - - if (playlists.isEmpty()) { - app_->task_manager()->SetTaskFinished(task_playlists_id_); - } -} - -void GroovesharkService::PlaylistSongsRetrieved(QNetworkReply* reply, - int playlist_id, - int request_id) { - reply->deleteLater(); - - if (!pending_retrieve_playlists_.remove(request_id)) { - // This request has been canceled. Stop here - return; - } - PlaylistInfo* playlist_info = subscribed_playlists_.contains(playlist_id) - ? &subscribed_playlists_[playlist_id] - : &playlists_[playlist_id]; - playlist_info->item_->removeRows(0, playlist_info->item_->rowCount()); - - QVariantMap result = ExtractResult(reply); - SongList songs = ExtractSongs(result); - SortSongsAlphabeticallyIfNeeded(&songs); - - for (const Song& song : songs) { - QStandardItem* child = CreateSongItem(song); - child->setData(playlist_info->id_, Role_UserPlaylistId); - child->setData(true, InternetModel::Role_CanBeModified); - - playlist_info->item_->appendRow(child); - } - - // Keep in mind this playlist - playlist_info->songs_ids_ = ExtractSongsIds(result); - - if (pending_retrieve_playlists_.isEmpty()) { - app_->task_manager()->SetTaskFinished(task_playlists_id_); - } -} - -void GroovesharkService::RetrieveUserFavorites() { - int task_id = app_->task_manager()->StartTask( - tr("Retrieving Grooveshark favorites songs")); - QNetworkReply* reply = CreateRequest("getUserFavoriteSongs", QList()); - - NewClosure(reply, SIGNAL(finished()), this, - SLOT(UserFavoritesRetrieved(QNetworkReply*, int)), reply, task_id); -} - -void GroovesharkService::UserFavoritesRetrieved(QNetworkReply* reply, - int task_id) { - reply->deleteLater(); - app_->task_manager()->SetTaskFinished(task_id); - - if (!favorites_) { - // The use probably logged out before the response arrived. - return; - } - - favorites_->removeRows(0, favorites_->rowCount()); - - QVariantMap result = ExtractResult(reply); - SongList songs = ExtractSongs(result); - SortSongsAlphabeticallyIfNeeded(&songs); - - for (const Song& song : songs) { - QStandardItem* child = CreateSongItem(song); - child->setData(true, InternetModel::Role_CanBeModified); - - favorites_->appendRow(child); - } -} - -void GroovesharkService::RetrieveUserLibrarySongs() { - int task_id = app_->task_manager()->StartTask( - tr("Retrieving Grooveshark My Music songs")); - QNetworkReply* reply = CreateRequest("getUserLibrarySongs", QList()); - - NewClosure(reply, SIGNAL(finished()), this, - SLOT(UserLibrarySongsRetrieved(QNetworkReply*, int)), reply, - task_id); -} - -void GroovesharkService::UserLibrarySongsRetrieved(QNetworkReply* reply, - int task_id) { - reply->deleteLater(); - app_->task_manager()->SetTaskFinished(task_id); - - if (!library_) { - // The use probably logged out before the response arrived. - return; - } - - library_->removeRows(0, library_->rowCount()); - - QVariantMap result = ExtractResult(reply); - SongList songs = ExtractSongs(result); - SortSongsAlphabeticallyIfNeeded(&songs); - - for (const Song& song : songs) { - QStandardItem* child = CreateSongItem(song); - child->setData(true, InternetModel::Role_CanBeModified); - - library_->appendRow(child); - } -} - -void GroovesharkService::RetrievePopularSongs() { - task_popular_id_ = - app_->task_manager()->StartTask(tr("Getting Grooveshark popular songs")); - RetrievePopularSongsMonth(); - RetrievePopularSongsToday(); -} - -void GroovesharkService::RetrievePopularSongsMonth() { - QList parameters; - parameters << Param("limit", QString::number(kSongSearchLimit)); - QNetworkReply* reply = CreateRequest("getPopularSongsMonth", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(PopularSongsMonthRetrieved(QNetworkReply*)), reply); -} - -void GroovesharkService::PopularSongsMonthRetrieved(QNetworkReply* reply) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - SongList songs = ExtractSongs(result); - - app_->task_manager()->IncreaseTaskProgress(task_popular_id_, 50, 100); - if (app_->task_manager()->GetTaskProgress(task_popular_id_) >= 100) { - app_->task_manager()->SetTaskFinished(task_popular_id_); - } - - if (!popular_month_) return; - - for (const Song& song : songs) { - QStandardItem* child = CreateSongItem(song); - popular_month_->appendRow(child); - } -} - -void GroovesharkService::RetrievePopularSongsToday() { - QList parameters; - parameters << Param("limit", QString::number(kSongSearchLimit)); - QNetworkReply* reply = CreateRequest("getPopularSongsToday", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(PopularSongsTodayRetrieved(QNetworkReply*)), reply); -} - -void GroovesharkService::PopularSongsTodayRetrieved(QNetworkReply* reply) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - SongList songs = ExtractSongs(result); - - app_->task_manager()->IncreaseTaskProgress(task_popular_id_, 50, 100); - if (app_->task_manager()->GetTaskProgress(task_popular_id_) >= 100) { - app_->task_manager()->SetTaskFinished(task_popular_id_); - } - - if (!popular_today_) return; - - for (const Song& song : songs) { - QStandardItem* child = CreateSongItem(song); - popular_today_->appendRow(child); - } -} - -void GroovesharkService::RetrieveSubscribedPlaylists() { - QNetworkReply* reply = - CreateRequest("getUserPlaylistsSubscribed", QList()); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(SubscribedPlaylistsRetrieved(QNetworkReply*)), reply); -} - -void GroovesharkService::SubscribedPlaylistsRetrieved(QNetworkReply* reply) { - reply->deleteLater(); - - QVariantMap result = ExtractResult(reply); - QList playlists = ExtractPlaylistInfo(result); - - for (const PlaylistInfo& playlist_info : playlists) { - int playlist_id = playlist_info.id_; - const QString& playlist_name = playlist_info.name_; - - QStandardItem* playlist_item = - CreatePlaylistItem(playlist_name, playlist_id); - // Refine some playlist properties that should be different for subscribed - // playlists - playlist_item->setData(SubscribedPlaylist, Role_PlaylistType); - playlist_item->setData(false, InternetModel::Role_CanBeModified); - - subscribed_playlists_.insert( - playlist_id, PlaylistInfo(playlist_id, playlist_name, playlist_item)); - subscribed_playlists_parent_->appendRow(playlist_item); - - // Request playlist's songs - RefreshPlaylist(playlist_id); - } -} - -void GroovesharkService::RetrieveAutoplayTags() { - QNetworkReply* reply = CreateRequest("getAutoplayTags", QList()); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(AutoplayTagsRetrieved(QNetworkReply*)), reply); -} - -void GroovesharkService::AutoplayTagsRetrieved(QNetworkReply* reply) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - QVariantMap::const_iterator it; - if (!stations_) return; - for (it = result.constBegin(); it != result.constEnd(); ++it) { - int id = it.key().toInt(); - QString name = it.value().toString().toLower(); - // Names received aren't very nice: make them more user friendly to display - name.replace("_", " "); - name[0] = name[0].toUpper(); - - QStandardItem* item = - new QStandardItem(QIcon(":last.fm/icon_radio.png"), name); - item->setData(InternetModel::Type_SmartPlaylist, InternetModel::Role_Type); - item->setData(InternetModel::PlayBehaviour_SingleItem, - InternetModel::Role_PlayBehaviour); - item->setData(id, Role_UserPlaylistId); - - stations_->appendRow(item); - } -} - -Song GroovesharkService::StartAutoplayTag(int tag_id, - QVariantMap& autoplay_state) { - QList parameters; - parameters << Param("tagID", tag_id); - QNetworkReply* reply = CreateRequest("startAutoplayTag", parameters); - - bool reply_has_timeouted = !WaitForReply(reply); - reply->deleteLater(); - if (reply_has_timeouted) return Song(); - - QVariantMap result = ExtractResult(reply); - autoplay_state = result["autoplayState"].toMap(); - return ExtractSong(result["nextSong"].toMap()); -} - -Song GroovesharkService::StartAutoplay(QVariantMap& autoplay_state) { - QList parameters; - QVariantList artists_ids_qvariant; - for (int artist_id : last_artists_ids_) { - artists_ids_qvariant << QVariant(artist_id); - } - QVariantList songs_ids_qvariant; - for (int song_id : last_songs_ids_) { - songs_ids_qvariant << QVariant(song_id); - } - parameters << Param("artistIDs", artists_ids_qvariant) - << Param("songIDs", songs_ids_qvariant); - QNetworkReply* reply = CreateRequest("startAutoplay", parameters); - - bool reply_has_timeouted = !WaitForReply(reply); - reply->deleteLater(); - if (reply_has_timeouted) return Song(); - - QVariantMap result = ExtractResult(reply); - autoplay_state = result["autoplayState"].toMap(); - return ExtractSong(result["nextSong"].toMap()); -} - -Song GroovesharkService::GetAutoplaySong(QVariantMap& autoplay_state) { - QList parameters; - parameters << Param("autoplayState", autoplay_state); - QNetworkReply* reply = CreateRequest("getAutoplaySong", parameters); - - bool reply_has_timeouted = !WaitForReply(reply); - reply->deleteLater(); - if (reply_has_timeouted) return Song(); - - QVariantMap result = ExtractResult(reply); - autoplay_state = result["autoplayState"].toMap(); - return ExtractSong(result["nextSong"].toMap()); -} - -void GroovesharkService::MarkStreamKeyOver30Secs(const QString& stream_key, - const QString& server_id) { - QList parameters; - parameters << Param("streamKey", stream_key) - << Param("streamServerID", server_id); - - QNetworkReply* reply = CreateRequest("markStreamKeyOver30Secs", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(StreamMarked(QNetworkReply*)), reply); -} - -void GroovesharkService::StreamMarked(QNetworkReply* reply) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark markStreamKeyOver30Secs failed"; - } -} - -void GroovesharkService::MarkSongComplete(const QString& song_id, - const QString& stream_key, - const QString& server_id) { - QList parameters; - parameters << Param("songID", song_id) << Param("streamKey", stream_key) - << Param("streamServerID", server_id); - - QNetworkReply* reply = CreateRequest("markSongComplete", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(SongMarkedAsComplete(QNetworkReply*)), reply); -} - -void GroovesharkService::SongMarkedAsComplete(QNetworkReply* reply) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark markSongComplete failed"; - } -} - -void GroovesharkService::ItemDoubleClicked(QStandardItem* item) { - if (item == root_) { - EnsureConnected(); - } -} - -GeneratorPtr GroovesharkService::CreateGenerator(QStandardItem* item) { - GeneratorPtr ret; - if (!item || item->data(InternetModel::Role_Type).toInt() != - InternetModel::Type_SmartPlaylist) { - return ret; - } - - if (item == grooveshark_radio_) { - if (last_artists_ids_.isEmpty()) { - QMessageBox::warning(nullptr, tr("Error"), - tr("To start Grooveshark radio, you should first " - "listen to a few other Grooveshark songs")); - return ret; - } - ret = GeneratorPtr(new GroovesharkRadio(this)); - } else { - int tag_id = item->data(Role_UserPlaylistId).toInt(); - ret = GeneratorPtr(new GroovesharkRadio(this, tag_id)); - } - return ret; -} - -void GroovesharkService::DropMimeData(const QMimeData* data, - const QModelIndex& index) { - if (!data) { - return; - } - - // Get Grooveshark songs' ids, if any. - QList data_songs_ids = ExtractSongsIds(data->urls()); - if (data_songs_ids.isEmpty()) { - // There is none: probably means user didn't dropped Grooveshark songs - return; - } - - int type = index.data(InternetModel::Role_Type).toInt(); - int parent_type = index.parent().data(InternetModel::Role_Type).toInt(); - - if (type == InternetModel::Type_UserPlaylist || - parent_type == InternetModel::Type_UserPlaylist) { - int playlist_type = index.data(Role_PlaylistType).toInt(); - int parent_playlist_type = index.parent().data(Role_PlaylistType).toInt(); - // If dropped on Favorites list - if (playlist_type == UserFavorites || - parent_playlist_type == UserFavorites) { - for (int song_id : data_songs_ids) { - AddUserFavoriteSong(song_id); - } - } else if (playlist_type == UserLibrary || - parent_playlist_type == UserLibrary) { - // FIXME: Adding songs to user libray doesn't work atm, but the problem - // seems to be on Grooveshark server side, as it returns success=true - // when calling addUserLibrarySongs with a valid song id. - // So this code is deactivated for now to not mislead user - // AddUserLibrarySongs(data_songs_ids); - } else { // Dropped on a normal playlist - // Get the playlist - int playlist_id = index.data(Role_UserPlaylistId).toInt(); - if (!playlists_.contains(playlist_id)) { - return; - } - // Get the current playlist's songs - PlaylistInfo playlist = playlists_[playlist_id]; - QList songs_ids = playlist.songs_ids_; - songs_ids << data_songs_ids; - - SetPlaylistSongs(playlist_id, songs_ids); - } - } -} - -QList GroovesharkService::playlistitem_actions(const Song& song) { - // Clear previous actions - while (!playlistitem_actions_.isEmpty()) { - QAction* action = playlistitem_actions_.takeFirst(); - delete action->menu(); - delete action; - } - - // Create a 'add to favorites' action - QAction* add_to_favorites = new QAction( - QIcon(":/last.fm/love.png"), tr("Add to Grooveshark favorites"), this); - connect(add_to_favorites, SIGNAL(triggered()), - SLOT(AddCurrentSongToUserFavorites())); - playlistitem_actions_.append(add_to_favorites); - - // FIXME: as explained above, adding songs to library doesn't work currently - // QAction* add_to_library = new QAction(IconLoader::Load("folder-sound"), - // tr("Add to Grooveshark My Music"), - // this); - // connect(add_to_library, SIGNAL(triggered()), - // SLOT(AddCurrentSongToUserLibrary())); - // playlistitem_actions_.append(add_to_library); - - // Create a menu with 'add to playlist' actions for each Grooveshark playlist - QAction* add_to_playlists = new QAction( - IconLoader::Load("list-add"), tr("Add to Grooveshark playlists"), this); - QMenu* playlists_menu = new QMenu(); - for (const PlaylistInfo& playlist_info : playlists_.values()) { - QAction* add_to_playlist = new QAction(playlist_info.name_, this); - add_to_playlist->setData(playlist_info.id_); - playlists_menu->addAction(add_to_playlist); - } - connect(playlists_menu, SIGNAL(triggered(QAction*)), - SLOT(AddCurrentSongToPlaylist(QAction*))); - add_to_playlists->setMenu(playlists_menu); - playlistitem_actions_.append(add_to_playlists); - - QAction* share_song = - new QAction(tr("Get a URL to share this Grooveshark song"), this); - connect(share_song, SIGNAL(triggered()), SLOT(GetCurrentSongUrlToShare())); - playlistitem_actions_.append(share_song); - - // Keep in mind the current song id - current_song_id_ = ExtractSongId(song.url()); - - return playlistitem_actions_; -} - -void GroovesharkService::GetCurrentSongUrlToShare() { - GetSongUrlToShare(current_song_id_); -} - -void GroovesharkService::GetSongUrlToShare(int song_id) { - QList parameters; - parameters << Param("songID", song_id); - QNetworkReply* reply = CreateRequest("getSongURLFromSongID", parameters); - - NewClosure(reply, SIGNAL(finished()), this, - SLOT(SongUrlToShareReceived(QNetworkReply*)), reply); -} - -void GroovesharkService::SongUrlToShareReceived(QNetworkReply* reply) { - reply->deleteLater(); - - QVariantMap result = ExtractResult(reply); - if (!result["url"].isValid()) return; - QString url = result["url"].toString(); - ShowUrlBox(tr("Grooveshark song's URL"), url); -} - -void GroovesharkService::GetCurrentPlaylistUrlToShare() { - GetPlaylistUrlToShare(current_playlist_id_); -} - -void GroovesharkService::GetPlaylistUrlToShare(int playlist_id) { - QList parameters; - parameters << Param("playlistID", playlist_id); - QNetworkReply* reply = - CreateRequest("getPlaylistURLFromPlaylistID", parameters); - - NewClosure(reply, SIGNAL(finished()), this, - SLOT(PlaylistUrlToShareReceived(QNetworkReply*)), reply); -} - -void GroovesharkService::PlaylistUrlToShareReceived(QNetworkReply* reply) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - if (!result["url"].isValid()) return; - QString url = result["url"].toString(); - ShowUrlBox(tr("Grooveshark playlist's URL"), url); -} - -void GroovesharkService::AddCurrentSongToPlaylist(QAction* action) { - int playlist_id = action->data().toInt(); - if (!playlists_.contains(playlist_id)) { - return; - } - // Get the current playlist's songs - PlaylistInfo playlist = playlists_[playlist_id]; - QList songs_ids = playlist.songs_ids_; - songs_ids << current_song_id_; - - SetPlaylistSongs(playlist_id, songs_ids); -} - -void GroovesharkService::SetPlaylistSongs(int playlist_id, - const QList& songs_ids) { - // If we are still retrieving playlists songs, don't update playlist: don't - // take the risk to erase all (not yet retrieved) playlist's songs. - if (!pending_retrieve_playlists_.isEmpty()) return; - int task_id = - app_->task_manager()->StartTask(tr("Update Grooveshark playlist")); - - QList parameters; - - // Convert song ids to QVariant - QVariantList songs_ids_qvariant; - for (int song_id : songs_ids) { - songs_ids_qvariant << QVariant(song_id); - } - - parameters << Param("playlistID", playlist_id) - << Param("songIDs", songs_ids_qvariant); - - QNetworkReply* reply = CreateRequest("setPlaylistSongs", parameters); - - NewClosure(reply, SIGNAL(finished()), this, - SLOT(PlaylistSongsSet(QNetworkReply*, int, int)), reply, - playlist_id, task_id); -} - -void GroovesharkService::PlaylistSongsSet(QNetworkReply* reply, int playlist_id, - int task_id) { - reply->deleteLater(); - app_->task_manager()->SetTaskFinished(task_id); - - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark setPlaylistSongs failed"; - return; - } - - RefreshPlaylist(playlist_id); -} - -void GroovesharkService::RefreshPlaylist(int playlist_id) { - QList parameters; - parameters << Param("playlistID", playlist_id); - QNetworkReply* reply = CreateRequest("getPlaylistSongs", parameters); - int id = next_pending_playlist_retrieve_id_++; - NewClosure(reply, SIGNAL(finished()), this, - SLOT(PlaylistSongsRetrieved(QNetworkReply*, int, int)), reply, - playlist_id, id); - - pending_retrieve_playlists_.insert(id); -} - -void GroovesharkService::CreateNewPlaylist() { - QString name = - QInputDialog::getText(nullptr, tr("Create a new Grooveshark playlist"), - tr("Name"), QLineEdit::Normal); - if (name.isEmpty()) { - return; - } - - QList parameters; - parameters << Param("name", name) << Param("songIDs", QVariantList()); - QNetworkReply* reply = CreateRequest("createPlaylist", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(NewPlaylistCreated(QNetworkReply*, const QString&)), reply, - name); -} - -void GroovesharkService::NewPlaylistCreated(QNetworkReply* reply, - const QString& name) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool() || !result["playlistID"].isValid()) { - qLog(Warning) << "Grooveshark createPlaylist failed"; - return; - } - - int playlist_id = result["playlistID"].toInt(); - QStandardItem* new_playlist_item = CreatePlaylistItem(name, playlist_id); - PlaylistInfo playlist_info(playlist_id, name, new_playlist_item); - playlist_info.item_ = new_playlist_item; - playlists_parent_->appendRow(new_playlist_item); - playlists_.insert(playlist_id, playlist_info); -} - -void GroovesharkService::DeleteCurrentPlaylist() { - if (model()->current_index().data(InternetModel::Role_Type).toInt() != - InternetModel::Type_UserPlaylist) { - return; - } - - int playlist_id = model()->current_index().data(Role_UserPlaylistId).toInt(); - DeletePlaylist(playlist_id); -} - -void GroovesharkService::DeletePlaylist(int playlist_id) { - if (!playlists_.contains(playlist_id)) { - return; - } - - std::unique_ptr confirmation_dialog( - new QMessageBox(QMessageBox::Question, tr("Delete Grooveshark playlist"), - tr("Are you sure you want to delete this playlist?"), - QMessageBox::Yes | QMessageBox::Cancel)); - if (confirmation_dialog->exec() != QMessageBox::Yes) { - return; - } - - QList parameters; - parameters << Param("playlistID", playlist_id); - QNetworkReply* reply = CreateRequest("deletePlaylist", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(PlaylistDeleted(QNetworkReply*, int)), reply, playlist_id); -} - -void GroovesharkService::PlaylistDeleted(QNetworkReply* reply, - int playlist_id) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark deletePlaylist failed"; - return; - } - if (!playlists_.contains(playlist_id)) { - return; - } - PlaylistInfo playlist_info = playlists_.take(playlist_id); - playlists_parent_->removeRow(playlist_info.item_->row()); -} - -void GroovesharkService::RenameCurrentPlaylist() { - const QModelIndex& index(model()->current_index()); - - if (index.data(InternetModel::Role_Type).toInt() != - InternetModel::Type_UserPlaylist || - index.data(Role_PlaylistType).toInt() != UserPlaylist) { - return; - } - - const int playlist_id = index.data(Role_UserPlaylistId).toInt(); - RenamePlaylist(playlist_id); -} - -void GroovesharkService::RenamePlaylist(int playlist_id) { - if (!playlists_.contains(playlist_id)) { - return; - } - const QString& old_name = playlists_[playlist_id].name_; - QString new_name = - QInputDialog::getText(nullptr, tr("Rename \"%1\" playlist").arg(old_name), - tr("Name"), QLineEdit::Normal, old_name); - if (new_name.isEmpty()) { - return; - } - - QList parameters; - parameters << Param("playlistID", playlist_id) << Param("name", new_name); - QNetworkReply* reply = CreateRequest("renamePlaylist", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(PlaylistRenamed(QNetworkReply*, int, const QString&)), reply, - playlist_id, new_name); -} - -void GroovesharkService::PlaylistRenamed(QNetworkReply* reply, int playlist_id, - const QString& new_name) { - reply->deleteLater(); - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark renamePlaylist failed"; - return; - } - if (!playlists_.contains(playlist_id)) { - return; - } - PlaylistInfo& playlist_info = playlists_[playlist_id]; - playlist_info.name_ = new_name; - playlist_info.item_->setText(new_name); -} - -void GroovesharkService::AddUserFavoriteSong(int song_id) { - int task_id = app_->task_manager()->StartTask(tr("Adding song to favorites")); - QList parameters; - parameters << Param("songID", song_id); - QNetworkReply* reply = CreateRequest("addUserFavoriteSong", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(UserFavoriteSongAdded(QNetworkReply*, int)), reply, task_id); -} - -void GroovesharkService::UserFavoriteSongAdded(QNetworkReply* reply, - int task_id) { - reply->deleteLater(); - app_->task_manager()->SetTaskFinished(task_id); - - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark addUserFavoriteSong failed"; - return; - } - // Refresh user's favorites list - RetrieveUserFavorites(); -} - -void GroovesharkService::AddUserLibrarySongs(const QList& songs_ids) { - int task_id = app_->task_manager()->StartTask(tr("Adding song to My Music")); - QList parameters; - - // Convert songs ids to QVariant - QVariantList songs_ids_qvariant; - for (int song_id : songs_ids) { - songs_ids_qvariant << QVariant(song_id); - } - QVariantList albums_ids_qvariant; - QVariantList artists_ids_qvariant; - - parameters << Param("songIDs", songs_ids_qvariant); - // We do not support albums and artist parameters for now, but they are - // required - parameters << Param("albumIDs", albums_ids_qvariant); - parameters << Param("artistIDs", artists_ids_qvariant); - QNetworkReply* reply = CreateRequest("addUserLibrarySongs", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(UserLibrarySongAdded(QNetworkReply*, int)), reply, task_id); -} - -void GroovesharkService::UserLibrarySongAdded(QNetworkReply* reply, - int task_id) { - reply->deleteLater(); - app_->task_manager()->SetTaskFinished(task_id); - - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark addUserLibrarySongs failed"; - return; - } - // Refresh user's library list - RetrieveUserLibrarySongs(); -} - -void GroovesharkService::RemoveCurrentFromPlaylist() { - const QModelIndexList& indexes(model()->selected_indexes()); - QMap> playlists_songs_ids; - for (const QModelIndex& index : indexes) { - if (index.parent().data(InternetModel::Role_Type).toInt() != - InternetModel::Type_UserPlaylist) { - continue; - } - - int playlist_id = index.data(Role_UserPlaylistId).toInt(); - int song_id = ExtractSongId(index.data(InternetModel::Role_Url).toUrl()); - if (song_id) { - playlists_songs_ids[playlist_id] << song_id; - } - } - - for (QMap>::const_iterator it = - playlists_songs_ids.constBegin(); - it != playlists_songs_ids.constEnd(); ++it) { - RemoveFromPlaylist(it.key(), it.value()); - } -} - -void GroovesharkService::RemoveFromPlaylist( - int playlist_id, const QList& songs_ids_to_remove) { - if (!playlists_.contains(playlist_id)) { - return; - } - - QList songs_ids = playlists_[playlist_id].songs_ids_; - for (const int song_id : songs_ids_to_remove) { - songs_ids.removeOne(song_id); - } - - SetPlaylistSongs(playlist_id, songs_ids); -} - -void GroovesharkService::RemoveCurrentFromFavorites() { - const QModelIndexList& indexes(model()->selected_indexes()); - QList songs_ids; - for (const QModelIndex& index : indexes) { - if (index.parent().data(Role_PlaylistType).toInt() != UserFavorites) { - continue; - } - - int song_id = ExtractSongId(index.data(InternetModel::Role_Url).toUrl()); - if (song_id) { - songs_ids << song_id; - } - } - - RemoveFromFavorites(songs_ids); -} - -void GroovesharkService::RemoveFromFavorites( - const QList& songs_ids_to_remove) { - if (songs_ids_to_remove.isEmpty()) return; - - int task_id = - app_->task_manager()->StartTask(tr("Removing songs from favorites")); - QList parameters; - - // Convert song ids to QVariant - QVariantList songs_ids_qvariant; - for (const int song_id : songs_ids_to_remove) { - songs_ids_qvariant << QVariant(song_id); - } - - parameters << Param("songIDs", songs_ids_qvariant); - QNetworkReply* reply = CreateRequest("removeUserFavoriteSongs", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(SongsRemovedFromFavorites(QNetworkReply*, int)), reply, - task_id); -} - -void GroovesharkService::SongsRemovedFromFavorites(QNetworkReply* reply, - int task_id) { - app_->task_manager()->SetTaskFinished(task_id); - reply->deleteLater(); - - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark removeUserFavoriteSongs failed"; - return; - } - RetrieveUserFavorites(); -} - -void GroovesharkService::RemoveCurrentFromLibrary() { - const QModelIndexList& indexes(model()->selected_indexes()); - QList songs_ids; - - for (const QModelIndex& index : indexes) { - if (index.parent().data(Role_PlaylistType).toInt() != UserLibrary) { - continue; - } - - int song_id = ExtractSongId(index.data(InternetModel::Role_Url).toUrl()); - if (song_id) { - songs_ids << song_id; - } - } - - RemoveFromLibrary(songs_ids); -} - -void GroovesharkService::RemoveFromLibrary( - const QList& songs_ids_to_remove) { - if (songs_ids_to_remove.isEmpty()) return; - - int task_id = - app_->task_manager()->StartTask(tr("Removing songs from My Music")); - QList parameters; - - // Convert song ids to QVariant - QVariantList songs_ids_qvariant; - for (const int song_id : songs_ids_to_remove) { - songs_ids_qvariant << QVariant(song_id); - } - QVariantList albums_ids_qvariant; - QVariantList artists_ids_qvariant; - - parameters << Param("songIDs", songs_ids_qvariant); - // We do not support albums and artist parameters for now, but they are - // required - parameters << Param("albumIDs", albums_ids_qvariant); - parameters << Param("artistIDs", artists_ids_qvariant); - - QNetworkReply* reply = CreateRequest("removeUserLibrarySongs", parameters); - NewClosure(reply, SIGNAL(finished()), this, - SLOT(SongsRemovedFromLibrary(QNetworkReply*, int)), reply, - task_id); -} - -void GroovesharkService::SongsRemovedFromLibrary(QNetworkReply* reply, - int task_id) { - app_->task_manager()->SetTaskFinished(task_id); - reply->deleteLater(); - - QVariantMap result = ExtractResult(reply); - if (!result["success"].toBool()) { - qLog(Warning) << "Grooveshark removeUserLibrarySongs failed"; - return; - } - RetrieveUserLibrarySongs(); -} - -QNetworkReply* GroovesharkService::CreateRequest(const QString& method_name, - const QList& params, - bool use_https) { - QVariantMap request_params; - request_params.insert("method", method_name); - - QVariantMap header; - header.insert("wsKey", kApiKey); - if (session_id_.isEmpty()) { - if (method_name != "startSession") { - // It's normal to not have a session_id when calling startSession. - // Otherwise it's not, so print a warning message - qLog(Warning) << "Session ID is empty: will not be added to query"; - } - } else { - header.insert("sessionID", session_id_); - } - request_params.insert("header", header); - - QVariantMap parameters; - for (const Param& param : params) { - parameters.insert(param.first, param.second); - } - request_params.insert("parameters", parameters); - - QJson::Serializer serializer; - QByteArray post_params = serializer.serialize(request_params); - - QUrl url(kUrl); - if (use_https) { - url.setScheme("https"); - } - url.setQueryItems( - QList>() << QPair( - "sig", Utilities::HmacMd5(api_key_, post_params).toHex())); - QNetworkRequest req(url); - QNetworkReply* reply = network_->post(req, post_params); - - if (use_https) { - connect(reply, SIGNAL(sslErrors(QList)), - SLOT(RequestSslErrors(QList))); - } - - return reply; -} - -void GroovesharkService::RequestSslErrors(const QList& errors) { - QNetworkReply* reply = qobject_cast(sender()); - - for (const QSslError& error : errors) { - emit StreamError("SSL error occurred in Grooveshark request for " + - reply->url().toString() + ": " + error.errorString()); - } -} - -bool GroovesharkService::WaitForReply(QNetworkReply* reply) { - QEventLoop event_loop; - QTimer timeout_timer; - connect(&timeout_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); - connect(reply, SIGNAL(finished()), &event_loop, SLOT(quit())); - timeout_timer.start(10000); - event_loop.exec(); - if (!timeout_timer.isActive()) { - qLog(Error) << "Grooveshark request timeout"; - return false; - } - timeout_timer.stop(); - return true; -} - -QVariantMap GroovesharkService::ExtractResult(QNetworkReply* reply) { - QJson::Parser parser; - bool ok; - QVariantMap result = parser.parse(reply, &ok).toMap(); - if (!ok) { - qLog(Error) << "Error while parsing Grooveshark result"; - } - QVariantList errors = result["errors"].toList(); - QVariantList::iterator it; - for (it = errors.begin(); it != errors.end(); ++it) { - QVariantMap error = (*it).toMap(); - qLog(Error) << "Grooveshark error: (" << error["code"].toInt() << ") " - << error["message"].toString(); - switch (error["code"].toInt()) { - case 100: // User auth required - case 102: // User premium required - case 300: // Session required - // These errors can happen if session_id is obsolete (e.g. we haven't - // use - // it for more than two weeks): force the user to login again - Logout(); - break; - } - } - return result["result"].toMap(); -} - -namespace { -bool CompareSongs(const QVariant& song1, const QVariant& song2) { - QMap song1_map = song1.toMap(); - QMap song2_map = song2.toMap(); - int song1_sort = song1_map["Sort"].toInt(); - int song2_sort = song2_map["Sort"].toInt(); - if (song1_sort == song2_sort) { - // Favorite songs have a "TSFavorited" and (currently) no "Sort" field - return song1_map["TSFavorited"].toString() < - song2_map["TSFavorited"].toString(); - } - return song1_sort < song2_sort; -} -} // namespace - -SongList GroovesharkService::ExtractSongs(const QVariantMap& result) { - QVariantList result_songs = result["songs"].toList(); - qStableSort(result_songs.begin(), result_songs.end(), CompareSongs); - SongList songs; - for (int i = 0; i < result_songs.size(); ++i) { - QVariantMap result_song = result_songs[i].toMap(); - songs << ExtractSong(result_song); - } - return songs; -} - -Song GroovesharkService::ExtractSong(const QVariantMap& result_song) { - Song song; - if (!result_song.isEmpty()) { - int song_id = result_song["SongID"].toInt(); - QString song_name; - if (result_song.contains("SongName")) { - song_name = result_song["SongName"].toString(); - } else { - song_name = result_song["Name"].toString(); - } - int artist_id = result_song["ArtistID"].toInt(); - QString artist_name = result_song["ArtistName"].toString(); - int album_id = result_song["AlbumID"].toInt(); - QString album_name = result_song["AlbumName"].toString(); - qint64 duration = result_song["EstimateDuration"].toInt() * kNsecPerSec; - song.Init(song_name, artist_name, album_name, duration); - QVariant cover = result_song["CoverArtFilename"]; - if (cover.isValid()) { - song.set_art_automatic(QString(kUrlCover) + cover.toString()); - } - QVariant track_number = result_song["TrackNum"]; - if (track_number.isValid()) { - song.set_track(track_number.toInt()); - } - QVariant year = result_song["Year"]; - if (year.isValid()) { - song.set_year(year.toInt()); - } - // Special kind of URL: because we need to request a stream key for each - // play, we generate a fake URL for now, and we will create a real streaming - // URL when user will actually play the song (through url handler) - // URL is grooveshark://artist_id/album_id/song_id - song.set_url( - QUrl(QString("grooveshark://%1/%2/%3").arg(artist_id).arg(album_id).arg( - song_id))); - } - return song; -} - -QList GroovesharkService::ExtractSongsIds(const QVariantMap& result) { - QVariantList result_songs = result["songs"].toList(); - QList songs_ids; - for (int i = 0; i < result_songs.size(); ++i) { - QVariantMap result_song = result_songs[i].toMap(); - int song_id = result_song["SongID"].toInt(); - songs_ids << song_id; - } - return songs_ids; -} - -QList GroovesharkService::ExtractSongsIds(const QList& urls) { - QList songs_ids; - for (const QUrl& url : urls) { - int song_id = ExtractSongId(url); - if (song_id) { - songs_ids << song_id; - } - } - return songs_ids; -} - -int GroovesharkService::ExtractSongId(const QUrl& url) { - if (url.scheme() == "grooveshark") { - QStringList ids = url.toString().remove("grooveshark://").split("/"); - if (ids.size() == 3) - // Returns the third id: song id - return ids[2].toInt(); - } - return 0; -} - -QList GroovesharkService::ExtractPlaylistInfo( - const QVariantMap& result) { - QVariantList playlists_qvariant = result["playlists"].toList(); - - QList playlists; - - // Get playlists info - for (const QVariant& playlist_qvariant : playlists_qvariant) { - QVariantMap playlist = playlist_qvariant.toMap(); - int playlist_id = playlist["PlaylistID"].toInt(); - QString playlist_name = playlist["PlaylistName"].toString(); - - playlists << PlaylistInfo(playlist_id, playlist_name); - } - - // Sort playlists by name - qSort(playlists.begin(), playlists.end()); - - return playlists; -} - -void GroovesharkService::SortSongsAlphabeticallyIfNeeded(SongList* songs) const { - QSettings s; - s.beginGroup(GroovesharkService::kSettingsGroup); - const bool sort_songs_alphabetically = s.value("sort_alphabetically").toBool(); - if (sort_songs_alphabetically) { - Song::SortSongsListAlphabetically(songs); - } -} diff --git a/src/internet/grooveshark/groovesharkservice.h b/src/internet/grooveshark/groovesharkservice.h deleted file mode 100644 index 17c16c42f..000000000 --- a/src/internet/grooveshark/groovesharkservice.h +++ /dev/null @@ -1,338 +0,0 @@ -/* This file is part of Clementine. - Copyright 2011-2014, Arnaud Bienner - Copyright 2011-2012, 2014, John Maguire - Copyright 2012, David Sansome - Copyright 2014, Krzysztof Sobiecki - - 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 INTERNET_GROOVESHARK_GROOVESHARKSERVICE_H_ -#define INTERNET_GROOVESHARK_GROOVESHARKSERVICE_H_ - -#include "internet/core/internetmodel.h" -#include "internet/core/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(); - // Refresh all Grooveshark's items, and re-fill them - void RefreshItems(); - - 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, int request_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(); - - 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); - // 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(); - - // Sort songs alphabetically only if the "sort_alphabetically" option has been - // checked in the preferences settings. - void SortSongsAlphabeticallyIfNeeded(SongList* songs) const; - - GroovesharkUrlHandler* url_handler_; - - QString pending_search_; - - int next_pending_search_id_; - int next_pending_playlist_retrieve_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 // INTERNET_GROOVESHARK_GROOVESHARKSERVICE_H_ diff --git a/src/internet/grooveshark/groovesharksettingspage.cpp b/src/internet/grooveshark/groovesharksettingspage.cpp deleted file mode 100644 index 7c923e52a..000000000 --- a/src/internet/grooveshark/groovesharksettingspage.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* This file is part of Clementine. - Copyright 2011, 2014, Arnaud Bienner - Copyright 2011, David Sansome - Copyright 2014, Krzysztof Sobiecki - Copyright 2014, John Maguire - - 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 . -*/ - -#include "groovesharksettingspage.h" -#include "ui_groovesharksettingspage.h" - -#include -#include -#include -#include -#include - -#include "groovesharkservice.h" -#include "internet/core/internetmodel.h" -#include "core/logging.h" -#include "core/network.h" -#include "ui/iconloader.h" - -GroovesharkSettingsPage::GroovesharkSettingsPage(SettingsDialog* dialog) - : SettingsPage(dialog), - ui_(new Ui_GroovesharkSettingsPage), - service_(InternetModel::Service()), - validated_(false) { - ui_->setupUi(this); - - setWindowIcon(QIcon(":/providers/grooveshark.png")); - - connect(ui_->login, SIGNAL(clicked()), SLOT(Login())); - connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(Logout())); - connect(ui_->login_state, SIGNAL(LoginClicked()), SLOT(Login())); - - connect(service_, SIGNAL(LoginFinished(bool)), SLOT(LoginFinished(bool))); - - ui_->login_state->AddCredentialField(ui_->username); - ui_->login_state->AddCredentialField(ui_->password); - ui_->login_state->AddCredentialGroup(ui_->account_group); -} - -GroovesharkSettingsPage::~GroovesharkSettingsPage() { delete ui_; } - -void GroovesharkSettingsPage::Login() { - if (service_->IsLoggedIn()) { - return; - } - - ui_->login_state->SetLoggedIn(LoginStateWidget::LoginInProgress); - service_->Login(ui_->username->text(), ui_->password->text()); -} - -void GroovesharkSettingsPage::Load() { - QSettings s; - s.beginGroup(GroovesharkService::kSettingsGroup); - - original_username_ = s.value("username").toString(); - - ui_->username->setText(original_username_); - validated_ = false; - - UpdateLoginState(); - - ui_->sort_alphabetically->setChecked(s.value("sort_alphabetically").toBool()); -} - -void GroovesharkSettingsPage::Save() { - QSettings s; - s.beginGroup(GroovesharkService::kSettingsGroup); - - s.setValue("username", ui_->username->text()); - s.setValue("sessionid", service_->session_id()); - const bool old_sort_value = s.value("sort_alphabetically").toBool(); - const bool new_sort_value = ui_->sort_alphabetically->isChecked(); - if (old_sort_value != new_sort_value) { - s.setValue("sort_alphabetically", new_sort_value); - service_->RefreshItems(); - } -} - -void GroovesharkSettingsPage::LoginFinished(bool success) { - validated_ = success; - - Save(); - UpdateLoginState(); -} - -void GroovesharkSettingsPage::UpdateLoginState() { - const bool logged_in = service_->IsLoggedIn(); - - ui_->login_state->SetLoggedIn( - logged_in ? LoginStateWidget::LoggedIn : LoginStateWidget::LoggedOut, - ui_->username->text()); - ui_->login_state->SetAccountTypeVisible(!logged_in); - - switch (service_->login_state()) { - case GroovesharkService::LoginState_NoPremium: - ui_->login_state->SetAccountTypeText( - tr("You do not have a Grooveshark Anywhere account.")); - break; - - case GroovesharkService::LoginState_AuthFailed: - ui_->login_state->SetAccountTypeText( - tr("Your username or password was incorrect.")); - break; - - default: - ui_->login_state->SetAccountTypeText( - tr("A Grooveshark Anywhere account is required.")); - break; - } -} - -void GroovesharkSettingsPage::Logout() { - service_->Logout(); - UpdateLoginState(); -} diff --git a/src/internet/grooveshark/groovesharksettingspage.h b/src/internet/grooveshark/groovesharksettingspage.h deleted file mode 100644 index f465acd4e..000000000 --- a/src/internet/grooveshark/groovesharksettingspage.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This file is part of Clementine. - Copyright 2011, Arnaud Bienner - Copyright 2014, Krzysztof Sobiecki - Copyright 2014, John Maguire - - 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 INTERNET_GROOVESHARK_GROOVESHARKSETTINGSPAGE_H_ -#define INTERNET_GROOVESHARK_GROOVESHARKSETTINGSPAGE_H_ - -#include "ui/settingspage.h" - -class NetworkAccessManager; -class Ui_GroovesharkSettingsPage; -class GroovesharkService; - -class GroovesharkSettingsPage : public SettingsPage { - Q_OBJECT - - public: - explicit GroovesharkSettingsPage(SettingsDialog* dialog); - ~GroovesharkSettingsPage(); - - void Load(); - void Save(); - - private slots: - void Login(); - void LoginFinished(bool success); - void Logout(); - - private: - void UpdateLoginState(); - - private: - Ui_GroovesharkSettingsPage* ui_; - GroovesharkService* service_; - - bool validated_; - QString original_username_; - QString original_password_; -}; - -#endif // INTERNET_GROOVESHARK_GROOVESHARKSETTINGSPAGE_H_ diff --git a/src/internet/grooveshark/groovesharksettingspage.ui b/src/internet/grooveshark/groovesharksettingspage.ui deleted file mode 100644 index f79278f6e..000000000 --- a/src/internet/grooveshark/groovesharksettingspage.ui +++ /dev/null @@ -1,128 +0,0 @@ - - - GroovesharkSettingsPage - - - - 0 - 0 - 480 - 184 - - - - Grooveshark - - - By default, Grooveshark sorts songs on date added - - - - - - - - - Account details - - - - - - true - - - - 0 - - - - - Username - - - - - - - - - - Password - - - - - - - QLineEdit::Password - - - - - - - Login - - - - - - - - - - - - - Preferences - - - - - - - - true - - - Sort playlists songs alphabetically - - - false - - - - - - - - - - - - Qt::Vertical - - - - 20 - 30 - - - - - - - - - LoginStateWidget - QWidget -
widgets/loginstatewidget.h
- 1 -
-
- - - - -
diff --git a/src/internet/grooveshark/groovesharkurlhandler.cpp b/src/internet/grooveshark/groovesharkurlhandler.cpp deleted file mode 100644 index 9554892c8..000000000 --- a/src/internet/grooveshark/groovesharkurlhandler.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* This file is part of Clementine. - Copyright 2011, Arnaud Bienner - Copyright 2014, Krzysztof Sobiecki - Copyright 2014, John Maguire - - 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 . -*/ - -#include "groovesharkurlhandler.h" - -#include - -#include "groovesharkservice.h" -#include "core/logging.h" - -GroovesharkUrlHandler::GroovesharkUrlHandler(GroovesharkService* service, - QObject* parent) - : UrlHandler(parent), - service_(service), - timer_mark_stream_key_(new QTimer(this)) { - // We have to warn Grooveshark when user has listened for more than 30 - // seconds of a song, and when it ends. I guess this is used by Grooveshark - // for statistics and user history. - // To do this, we have TrackAboutToEnd method, and timer_mark_stream_key_ - // timer. - // It is not perfect, as we may call Grooveshark MarkStreamKeyOver30Secs even - // if user hasn't actually listen to 30 seconds (e.g. stream set to pause - // state) but this is not a big deal and it should be accurate enough anyway. - timer_mark_stream_key_->setInterval(30000); - timer_mark_stream_key_->setSingleShot(true); - connect(timer_mark_stream_key_, SIGNAL(timeout()), - SLOT(MarkStreamKeyOver30Secs())); -} - -UrlHandler::LoadResult GroovesharkUrlHandler::StartLoading(const QUrl& url) { - qint64 length_nanosec = 0; - QUrl streaming_url; - QStringList ids = url.toString().remove("grooveshark://").split("/"); - if (ids.size() < 3) { - qLog(Error) << "Invalid grooveshark URL: " << url.toString(); - qLog(Error) << "Should be grooveshark://artist_id/album_id/song_id"; - } else { - last_artist_id_ = ids[0]; - last_album_id_ = ids[1]; - last_song_id_ = ids[2]; - - streaming_url = service_->GetStreamingUrlFromSongId( - last_song_id_, last_artist_id_, &last_server_id_, &last_stream_key_, - &length_nanosec); - qLog(Debug) << "Grooveshark Streaming URL: " << streaming_url; - - timer_mark_stream_key_->start(); - } - - return LoadResult(url, LoadResult::TrackAvailable, streaming_url, - length_nanosec); -} - -void GroovesharkUrlHandler::TrackAboutToEnd() { - if (timer_mark_stream_key_->isActive()) { - timer_mark_stream_key_->stop(); - return; - } - service_->MarkSongComplete(last_song_id_, last_stream_key_, last_server_id_); -} - -void GroovesharkUrlHandler::TrackSkipped() { timer_mark_stream_key_->stop(); } - -void GroovesharkUrlHandler::MarkStreamKeyOver30Secs() { - service_->MarkStreamKeyOver30Secs(last_stream_key_, last_server_id_); -} diff --git a/src/internet/grooveshark/groovesharkurlhandler.h b/src/internet/grooveshark/groovesharkurlhandler.h deleted file mode 100644 index 883045ea4..000000000 --- a/src/internet/grooveshark/groovesharkurlhandler.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Clementine. - Copyright 2011, Arnaud Bienner - Copyright 2012, 2014, John Maguire - Copyright 2014, Krzysztof Sobiecki - - 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 INTERNET_GROOVESHARK_GROOVESHARKURLHANDLER_H_ -#define INTERNET_GROOVESHARK_GROOVESHARKURLHANDLER_H_ - -#include "core/urlhandler.h" - -class GroovesharkService; -class QTimer; - -class GroovesharkUrlHandler : public UrlHandler { - Q_OBJECT - public: - GroovesharkUrlHandler(GroovesharkService* service, QObject* parent); - - QString scheme() const { return "grooveshark"; } - QIcon icon() const { return QIcon(":providers/grooveshark.png"); } - LoadResult StartLoading(const QUrl& url); - void TrackAboutToEnd(); - void TrackSkipped(); - - private slots: - void MarkStreamKeyOver30Secs(); - - private: - GroovesharkService* service_; - QTimer* timer_mark_stream_key_; - QString last_artist_id_; - QString last_album_id_; - QString last_song_id_; - QString last_server_id_; - QString last_stream_key_; -}; - -#endif // INTERNET_GROOVESHARK_GROOVESHARKURLHANDLER_H_ diff --git a/src/main.cpp b/src/main.cpp index 24ad9dddd..2e6291299 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -398,15 +398,7 @@ int main(int argc, char* argv[]) { Q_INIT_RESOURCE(data); Q_INIT_RESOURCE(translations); - // Grooveshark uses GoDaddy to sign its SSL certificates, which are in turn - // signed by a ValiCert CA. This CA certificate isn't installed by default - // in Windows, it's only added by windows update, or manually browsing to a - // website with a certificate signed by ValiCert. Here we explicitly add - // that CA to the default list used by QSslSocket, so it always works in - // Clementine. - QSslSocket::addDefaultCaCertificates( - QSslCertificate::fromPath(":/grooveshark-valicert-ca.pem", QSsl::Pem)); - // Do the same for SoundCloud, whose certificate is missing on OS X. + // Add root CA cert for SoundCloud, whose certificate is missing on OS X. QSslSocket::addDefaultCaCertificates( QSslCertificate::fromPath(":/soundcloud-ca.pem", QSsl::Pem)); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 5cfb1bda8..2cb7e1b7b 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -36,7 +36,6 @@ #include "engines/gstengine.h" #include "globalsearch/globalsearchsettingspage.h" #include "internet/digitally/digitallyimportedsettingspage.h" -#include "internet/grooveshark/groovesharksettingspage.h" #include "internet/core/internetshowsettingspage.h" #include "internet/magnatune/magnatunesettingspage.h" #include "internet/soundcloud/soundcloudsettingspage.h" @@ -168,8 +167,6 @@ SettingsDialog::SettingsDialog(Application* app, BackgroundStreams* streams, AddPage(Page_Lastfm, new LastFMSettingsPage(this), providers); #endif - AddPage(Page_Grooveshark, new GroovesharkSettingsPage(this), providers); - #ifdef HAVE_GOOGLE_DRIVE AddPage(Page_GoogleDrive, new GoogleDriveSettingsPage(this), providers); #endif diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 607ecc0e8..14bb9765b 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -68,7 +68,6 @@ class SettingsDialog : public QDialog { Page_Notifications, Page_Library, Page_Lastfm, - Page_Grooveshark, Page_SoundCloud, Page_Spotify, Page_Magnatune,