diff -rauN clementine-1.0.1/3rdparty/SPMediaKeyTap/SPMediaKeyTap.m clementine-libre-1.0.1/3rdparty/SPMediaKeyTap/SPMediaKeyTap.m --- clementine-1.0.1/3rdparty/SPMediaKeyTap/SPMediaKeyTap.m 2011-12-02 19:24:43.000000000 -0200 +++ clementine-libre-1.0.1/3rdparty/SPMediaKeyTap/SPMediaKeyTap.m 2012-05-28 17:19:14.612750904 -0300 @@ -98,7 +98,6 @@ { return [NSArray arrayWithObjects: [[NSBundle mainBundle] bundleIdentifier], // your app - @"com.spotify.client", @"com.apple.iTunes", @"com.apple.QuickTimePlayerX", @"com.apple.quicktimeplayer", diff -rauN clementine-1.0.1/Changelog clementine-libre-1.0.1/Changelog --- clementine-1.0.1/Changelog 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/Changelog 2012-05-28 13:50:10.422664725 -0300 @@ -1,3 +1,7 @@ +Version 1.0.1 (libre version): + Major features: + * Disabled and removed Spotify. + Version 1.0.1: Bugfixes: * Use Chromaprinter and Acoustid instead of Echoprint and MusicDNS. diff -rauN clementine-1.0.1/cmake/SpotifyVersion.cmake /dev/null --- clementine-1.0.1/cmake/SpotifyVersion.cmake 2011-12-02 19:24:43.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,3 +0,0 @@ -# Increment this whenever the user needs to download a new blob -# Remember to upload and sign the new version of the blob. -set(SPOTIFY_BLOB_VERSION 11) diff -rauN clementine-1.0.1/CMakeLists.txt clementine-libre-1.0.1/CMakeLists.txt --- clementine-1.0.1/CMakeLists.txt 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/CMakeLists.txt 2012-05-28 17:32:48.690568781 -0300 @@ -6,7 +6,6 @@ include(cmake/Version.cmake) include(cmake/Deb.cmake) include(cmake/Rpm.cmake) -include(cmake/SpotifyVersion.cmake) include(cmake/OptionalSource.cmake) if (UNIX AND NOT APPLE) @@ -66,7 +65,6 @@ pkg_check_modules(USBMUXD libusbmuxd) pkg_check_modules(LIBMTP libmtp>=1.0) pkg_check_modules(INDICATEQT indicate-qt) -pkg_check_modules(SPOTIFY libspotify>=10.1.16) pkg_check_modules(CDIO libcdio) pkg_check_modules(QCA qca2) pkg_check_modules(CHROMAPRINT libchromaprint) @@ -90,13 +88,6 @@ set(HAVE_SPARKLE ON) endif (ENABLE_SPARKLE AND SPARKLE) - find_library(SPOTIFY libspotify) - if (SPOTIFY) - set (SPOTIFY_FOUND ON) - set (SPOTIFY_INCLUDE_DIRS ${SPOTIFY}) - set (SPOTIFY_LIBRARIES ${SPOTIFY}) - endif (SPOTIFY) - add_subdirectory(3rdparty/SPMediaKeyTap) set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap) set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap) @@ -191,8 +182,8 @@ option(ENABLE_LIBLASTFM "Use liblastfm for fetching song info, scrobbling and radio streams" ON) option(ENABLE_REMOTE "Enable support for using remote controls with Clementine" OFF) option(ENABLE_BREAKPAD "Enable crash reporting" OFF) -option(ENABLE_SPOTIFY_BLOB "Build the spotify non-GPL binary" ON) -option(ENABLE_SPOTIFY "Enable spotify support" ON) +option(ENABLE_SPOTIFY_BLOB "Build the spotify non-GPL binary" OFF) +option(ENABLE_SPOTIFY "Enable spotify support" OFF) option(ENABLE_PLASMARUNNER "Enable plasma krunner global search" OFF) if(WIN32) @@ -235,24 +226,6 @@ set(HAVE_BREAKPAD ON) endif(ENABLE_BREAKPAD) -if(ENABLE_SPOTIFY AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE) - set(HAVE_SPOTIFY ON) -endif(ENABLE_SPOTIFY AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE) - -if(ENABLE_SPOTIFY_BLOB AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE AND SPOTIFY_FOUND) - set(HAVE_SPOTIFY_BLOB ON) -endif(ENABLE_SPOTIFY_BLOB AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE AND SPOTIFY_FOUND) - -if((NOT HAVE_SPOTIFY_BLOB) AND (NOT QCA_FOUND)) - # If we're not bundling the spotify blob then we must ensure QCA is available - # so we can verify the blob we download at runtime. - unset(HAVE_SPOTIFY) -endif((NOT HAVE_SPOTIFY_BLOB) AND (NOT QCA_FOUND)) - -if(QCA_FOUND AND HAVE_SPOTIFY) - set(HAVE_QCA ON) -endif(QCA_FOUND AND HAVE_SPOTIFY) - if(ENABLE_VISUALISATIONS) # When/if upstream accepts our patches then these options can be used to link @@ -391,14 +364,6 @@ add_subdirectory(3rdparty/google-breakpad) endif(HAVE_BREAKPAD) -if(HAVE_SPOTIFY) - add_subdirectory(spotifyblob/common) -endif(HAVE_SPOTIFY) - -if(HAVE_SPOTIFY_BLOB) - add_subdirectory(spotifyblob/blob) -endif(HAVE_SPOTIFY_BLOB) - # This goes after everything else because KDE fucks everything else up with its # cmake includes. find_package(KDE4 4.3.60) @@ -430,8 +395,6 @@ summary_add("Devices: GIO backend" HAVE_GIO) summary_add("Gnome sound menu integration" HAVE_LIBINDICATE) summary_add("Last.fm support" HAVE_LIBLASTFM) -summary_add("Spotify support: core code" HAVE_SPOTIFY) -summary_add("Spotify support: non-GPL binary helper" HAVE_SPOTIFY_BLOB) summary_add("Visualisations" ENABLE_VISUALISATIONS) summary_add("Wiimote support" HAVE_WIIMOTEDEV) summary_add("(KDE) Plasma global search" HAVE_PLASMARUNNER) diff -rauN clementine-1.0.1/data/data.qrc clementine-libre-1.0.1/data/data.qrc --- clementine-1.0.1/data/data.qrc 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/data/data.qrc 2012-05-28 17:50:22.768352061 -0300 @@ -49,9 +49,6 @@ providers/magnatune.png schema/schema-8.sql schema/schema-9.sql - icons/22x22/spotify.png - icons/32x32/spotify.png - icons/48x48/spotify.png icons/22x22/application-exit.png icons/22x22/applications-internet.png icons/22x22/configure.png @@ -320,7 +317,6 @@ icons/32x32/edit-find.png icons/48x48/edit-find.png schema/schema-33.sql - spotify-core-logo-128x128.png icons/22x22/dialog-warning.png icons/22x22/dialog-ok-apply.png schema/schema-34.sql @@ -331,7 +327,6 @@ providers/grooveshark.png allthethings.png globalsearch.css - clementine-spotify-public.pem icons/22x22/user-away.png icons/32x32/search.png schema/schema-35.sql diff -rauN clementine-1.0.1/data/icons/svg/spotify.svg /dev/null --- clementine-1.0.1/data/icons/svg/spotify.svg 2011-12-02 19:24:43.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,285 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - diff -rauN clementine-1.0.1/data/schema/schema-30.sql clementine-libre-1.0.1/data/schema/schema-30.sql --- clementine-1.0.1/data/schema/schema-30.sql 2011-12-02 19:24:43.000000000 -0200 +++ clementine-libre-1.0.1/data/schema/schema-30.sql 2012-05-28 17:55:40.840489308 -0300 @@ -1,45 +1 @@ -CREATE TABLE spotify_search_songs ( - title TEXT, - album TEXT, - artist TEXT, - albumartist TEXT, - composer TEXT, - track INTEGER, - disc INTEGER, - bpm REAL, - year INTEGER, - genre TEXT, - comment TEXT, - compilation INTEGER, - - length INTEGER, - bitrate INTEGER, - samplerate INTEGER, - - directory INTEGER NOT NULL, - filename TEXT NOT NULL, - mtime INTEGER NOT NULL, - ctime INTEGER NOT NULL, - filesize INTEGER NOT NULL, - sampler INTEGER NOT NULL DEFAULT 0, - art_automatic TEXT, - art_manual TEXT, - filetype INTEGER NOT NULL DEFAULT 0, - playcount INTEGER NOT NULL DEFAULT 0, - lastplayed INTEGER, - rating INTEGER, - forced_compilation_on INTEGER NOT NULL DEFAULT 0, - forced_compilation_off INTEGER NOT NULL DEFAULT 0, - effective_compilation NOT NULL DEFAULT 0, - skipcount INTEGER NOT NULL DEFAULT 0, - score INTEGER NOT NULL DEFAULT 0, - beginning INTEGER NOT NULL DEFAULT 0, - cue_path TEXT -); - -CREATE VIRTUAL TABLE spotify_search_songs_fts USING fts3 ( - ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsgenre, ftscomment, - tokenize=unicode -); - UPDATE schema_version SET version=30; diff -rauN clementine-1.0.1/dist/macdeploy.py clementine-libre-1.0.1/dist/macdeploy.py --- clementine-1.0.1/dist/macdeploy.py 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/dist/macdeploy.py 2012-05-28 17:58:29.937662793 -0300 @@ -367,11 +367,6 @@ FixPlugin(FindGstreamerPlugin('gst-plugin-scanner'), '.') -try: - FixPlugin('clementine-spotifyblob', '.') -except: - print 'Failed to find spotify blob' - for plugin in QT_PLUGINS: FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin)) diff -rauN clementine-1.0.1/dist/windows/clementine.nsi clementine-libre-1.0.1/dist/windows/clementine.nsi --- clementine-1.0.1/dist/windows/clementine.nsi 2012-01-22 10:43:46.000000000 -0200 +++ clementine-libre-1.0.1/dist/windows/clementine.nsi 2012-05-28 18:06:56.812551755 -0300 @@ -95,7 +95,6 @@ Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll" ; 1.0 prerelease - Delete "$INSTDIR\spotify.dll" ; 1.0 Delete "$INSTDIR\libofa.dll" @@ -109,7 +108,6 @@ File "avformat-52.dll" File "avutil-50.dll" File "clementine.exe" - File "clementine-spotifyblob.exe" File "clementine.ico" File "glew32.dll" File "intl.dll" @@ -163,7 +161,6 @@ File "libqjson.dll" File "libsoup-2.4-1.dll" File "libspeex-1.dll" - File "libspotify.dll" File "libtag.dll" File "libtasn1-3.dll" File "libusbmuxd.dll" @@ -949,7 +946,6 @@ Delete "$INSTDIR\avutil-50.dll" Delete "$INSTDIR\clementine.ico" Delete "$INSTDIR\clementine.exe" - Delete "$INSTDIR\clementine-spotifyblob.exe" Delete "$INSTDIR\glew32.dll" Delete "$INSTDIR\intl.dll" Delete "$INSTDIR\libcdio-12.dll" @@ -1002,7 +998,6 @@ Delete "$INSTDIR\libqjson.dll" Delete "$INSTDIR\libsoup-2.4-1.dll" Delete "$INSTDIR\libspeex-1.dll" - Delete "$INSTDIR\libspotify.dll" Delete "$INSTDIR\libtag.dll" Delete "$INSTDIR\libtasn1-3.dll" Delete "$INSTDIR\libusbmuxd.dll" diff -rauN clementine-1.0.1/dist/windows/clementine.nsi.in clementine-libre-1.0.1/dist/windows/clementine.nsi.in --- clementine-1.0.1/dist/windows/clementine.nsi.in 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/dist/windows/clementine.nsi.in 2012-05-28 18:09:14.664818947 -0300 @@ -95,7 +95,6 @@ Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll" ; 1.0 prerelease - Delete "$INSTDIR\spotify.dll" ; 1.0 Delete "$INSTDIR\libofa.dll" @@ -109,7 +108,6 @@ File "avformat-52.dll" File "avutil-50.dll" File "clementine.exe" - File "clementine-spotifyblob.exe" File "clementine.ico" File "glew32.dll" File "intl.dll" @@ -163,7 +161,6 @@ File "libqjson.dll" File "libsoup-2.4-1.dll" File "libspeex-1.dll" - File "libspotify.dll" File "libtag.dll" File "libtasn1-3.dll" File "libusbmuxd.dll" @@ -949,7 +946,6 @@ Delete "$INSTDIR\avutil-50.dll" Delete "$INSTDIR\clementine.ico" Delete "$INSTDIR\clementine.exe" - Delete "$INSTDIR\clementine-spotifyblob.exe" Delete "$INSTDIR\glew32.dll" Delete "$INSTDIR\intl.dll" Delete "$INSTDIR\libcdio-12.dll" @@ -1002,7 +998,6 @@ Delete "$INSTDIR\libqjson.dll" Delete "$INSTDIR\libsoup-2.4-1.dll" Delete "$INSTDIR\libspeex-1.dll" - Delete "$INSTDIR\libspotify.dll" Delete "$INSTDIR\libtag.dll" Delete "$INSTDIR\libtasn1-3.dll" Delete "$INSTDIR\libusbmuxd.dll" diff -rauN clementine-1.0.1/src/CMakeLists.txt clementine-libre-1.0.1/src/CMakeLists.txt --- clementine-1.0.1/src/CMakeLists.txt 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/src/CMakeLists.txt 2012-05-30 02:50:15.725755468 -0300 @@ -552,7 +552,6 @@ internet/internetviewcontainer.ui internet/magnatunedownloaddialog.ui internet/magnatunesettingspage.ui - internet/spotifysettingspage.ui library/groupbydialog.ui library/libraryfilterwidget.ui @@ -690,23 +689,6 @@ internet/lastfmstationdialog.ui ) -# Spotify -optional_source(HAVE_SPOTIFY - SOURCES - globalsearch/spotifysearchprovider.cpp - internet/spotifyblobdownloader.cpp - internet/spotifysearchplaylisttype.cpp - internet/spotifyserver.cpp - internet/spotifyservice.cpp - internet/spotifysettingspage.cpp - HEADERS - globalsearch/spotifysearchprovider.h - internet/spotifyblobdownloader.h - internet/spotifyserver.h - internet/spotifyservice.h - internet/spotifysettingspage.h -) - optional_source(HAVE_QCA INCLUDE_DIRECTORIES ${QCA_INCLUDE_DIRS}) # Platform specific - OS X @@ -1037,14 +1019,6 @@ endif (LINUX) endif(HAVE_BREAKPAD) -if(HAVE_SPOTIFY) - target_link_libraries(clementine_lib - clementine-spotifyblob-messages - ${QCA_LIBRARIES} - ) - link_directories(${QCA_LIBRARY_DIRS}) -endif(HAVE_SPOTIFY) - if (APPLE) target_link_libraries(clementine_lib ${GROWL} @@ -1118,11 +1092,6 @@ clementine_lib ) -# macdeploy.py relies on the blob being built first. -if(HAVE_SPOTIFY_BLOB) - add_dependencies(clementine clementine-spotifyblob) -endif(HAVE_SPOTIFY_BLOB) - set_target_properties(clementine PROPERTIES MACOSX_BUNDLE_INFO_PLIST "../dist/Info.plist" ) diff -rauN clementine-1.0.1/src/config.h.in clementine-libre-1.0.1/src/config.h.in --- clementine-1.0.1/src/config.h.in 2011-12-02 19:24:43.000000000 -0200 +++ clementine-libre-1.0.1/src/config.h.in 2012-05-28 18:17:13.027993639 -0300 @@ -35,7 +35,6 @@ #cmakedefine HAVE_QCA #cmakedefine HAVE_REMOTE #cmakedefine HAVE_SPARKLE -#cmakedefine HAVE_SPOTIFY #cmakedefine HAVE_STATIC_SQLITE #cmakedefine HAVE_WIIMOTEDEV #cmakedefine LEOPARD diff -rauN clementine-1.0.1/src/core/utilities.cpp clementine-libre-1.0.1/src/core/utilities.cpp --- clementine-1.0.1/src/core/utilities.cpp 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/src/core/utilities.cpp 2012-05-28 18:25:43.252728803 -0300 @@ -277,9 +277,6 @@ return QDir::homePath(); #endif - case Path_LocalSpotifyBlob: - return GetConfigPath(Path_Root) + "/spotifyblob"; - default: qFatal("%s", Q_FUNC_INFO); return QString::null; diff -rauN clementine-1.0.1/src/core/utilities.h clementine-libre-1.0.1/src/core/utilities.h --- clementine-1.0.1/src/core/utilities.h 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/src/core/utilities.h 2012-05-28 18:27:31.686659381 -0300 @@ -88,7 +88,6 @@ Path_NetworkCache, Path_GstreamerRegistry, Path_DefaultMusicLibrary, - Path_LocalSpotifyBlob, }; QString GetConfigPath(ConfigPath config); diff -rauN clementine-1.0.1/src/covers/albumcoverloader.cpp clementine-libre-1.0.1/src/covers/albumcoverloader.cpp --- clementine-1.0.1/src/covers/albumcoverloader.cpp 2011-12-02 19:24:44.000000000 -0200 +++ clementine-libre-1.0.1/src/covers/albumcoverloader.cpp 2012-05-28 18:34:26.543457483 -0300 @@ -28,10 +28,6 @@ #include #include -#ifdef HAVE_SPOTIFY -# include "internet/spotifyservice.h" -#endif - AlbumCoverLoader::AlbumCoverLoader(QObject* parent) : QObject(parent), @@ -40,8 +36,7 @@ scale_(true), padding_(true), next_id_(0), - network_(new NetworkAccessManager(this)), - connected_spotify_(false) + network_(new NetworkAccessManager(this)) { } @@ -148,46 +143,12 @@ remote_tasks_.insert(reply, task); return TryLoadResult(true, false, QImage()); - } else if (filename.toLower().startsWith("spotify://image/")) { - // HACK: we should add generic image URL handlers - #ifdef HAVE_SPOTIFY - SpotifyService* spotify = InternetModel::Service(); - - if (!connected_spotify_) { - connect(spotify, SIGNAL(ImageLoaded(QString,QImage)), - SLOT(SpotifyImageLoaded(QString,QImage))); - connected_spotify_ = true; - } - - QString id = QUrl(filename).path(); - if (id.startsWith('/')) { - id.remove(0, 1); - } - remote_spotify_tasks_.insert(id, task); - - // Need to schedule this in the spotify service's thread - QMetaObject::invokeMethod(spotify, "LoadImage", Qt::QueuedConnection, - Q_ARG(QString, id)); - return TryLoadResult(true, false, QImage()); - #else - return TryLoadResult(false, false, QImage()); - #endif } QImage image(filename); return TryLoadResult(false, !image.isNull(), image.isNull() ? default_ : image); } -void AlbumCoverLoader::SpotifyImageLoaded(const QString& id, const QImage& image) { - if (!remote_spotify_tasks_.contains(id)) - return; - - Task task = remote_spotify_tasks_.take(id); - QImage scaled = ScaleAndPad(image); - emit ImageLoaded(task.id, scaled); - emit ImageLoaded(task.id, scaled, image); -} - void AlbumCoverLoader::RemoteFetchFinished() { QNetworkReply* reply = qobject_cast(sender()); if (!reply) diff -rauN clementine-1.0.1/src/covers/albumcoverloader.h clementine-libre-1.0.1/src/covers/albumcoverloader.h --- clementine-1.0.1/src/covers/albumcoverloader.h 2011-12-02 19:24:44.000000000 -0200 +++ clementine-libre-1.0.1/src/covers/albumcoverloader.h 2012-05-28 18:38:03.228006474 -0300 @@ -65,7 +65,6 @@ protected slots: void ProcessTasks(); void RemoteFetchFinished(); - void SpotifyImageLoaded(const QString& url, const QImage& image); protected: enum State { @@ -108,13 +107,10 @@ QMutex mutex_; QQueue tasks_; QMap remote_tasks_; - QMap remote_spotify_tasks_; quint64 next_id_; NetworkAccessManager* network_; - bool connected_spotify_; - static const int kMaxRedirects = 3; }; diff -rauN clementine-1.0.1/src/engines/gstenginepipeline.cpp clementine-libre-1.0.1/src/engines/gstenginepipeline.cpp --- clementine-1.0.1/src/engines/gstenginepipeline.cpp 2011-12-02 19:24:44.000000000 -0200 +++ clementine-libre-1.0.1/src/engines/gstenginepipeline.cpp 2012-05-28 18:51:35.779395089 -0300 @@ -26,11 +26,6 @@ #include "core/utilities.h" #include "internet/internetmodel.h" -#ifdef HAVE_SPOTIFY -# include "internet/spotifyserver.h" -# include "internet/spotifyservice.h" -#endif - #include const int GstEnginePipeline::kGstStateTimeoutNanosecs = 10000000; @@ -131,36 +126,6 @@ bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) { GstElement* new_bin = NULL; - if (url.scheme() == "spotify") { - #ifdef HAVE_SPOTIFY - new_bin = gst_bin_new("spotify_bin"); - - // Create elements - GstElement* src = engine_->CreateElement("tcpserversrc", new_bin); - GstElement* gdp = engine_->CreateElement("gdpdepay", new_bin); - if (!src || !gdp) - return false; - - // Pick a port number - const int port = Utilities::PickUnusedPort(); - g_object_set(G_OBJECT(src), "host", "127.0.0.1", NULL); - g_object_set(G_OBJECT(src), "port", port, NULL); - - // Link the elements - gst_element_link(src, gdp); - - // Add a ghost pad - GstPad* pad = gst_element_get_static_pad(gdp, "src"); - gst_element_add_pad(GST_ELEMENT(new_bin), gst_ghost_pad_new("src", pad)); - gst_object_unref(GST_OBJECT(pad)); - - // Tell spotify to start sending data to us. - InternetModel::Service()->server()->StartPlaybackLater(url.toString(), port); - #else // HAVE_SPOTIFY - qLog(Error) << "Tried to play a spotify:// url, but spotify support is not compiled in"; - return false; - #endif - } else { new_bin = engine_->CreateElement("uridecodebin"); g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(), NULL); g_object_set(G_OBJECT(new_bin), "buffer-duration", buffer_duration_nanosec_, NULL); @@ -169,7 +134,6 @@ g_signal_connect(G_OBJECT(new_bin), "drained", G_CALLBACK(SourceDrainedCallback), this); g_signal_connect(G_OBJECT(new_bin), "pad-added", G_CALLBACK(NewPadCallback), this); g_signal_connect(G_OBJECT(new_bin), "notify::source", G_CALLBACK(SourceSetupCallback), this); - } return ReplaceDecodeBin(new_bin); } diff -rauN clementine-1.0.1/src/globalsearch/spotifysearchprovider.cpp /dev/null --- clementine-1.0.1/src/globalsearch/spotifysearchprovider.cpp 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,208 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 "spotifysearchprovider.h" -#include "core/logging.h" -#include "internet/internetmodel.h" -#include "internet/spotifyserver.h" -#include "internet/spotifyservice.h" -#include "playlist/songmimedata.h" -#include "spotifyblob/common/spotifymessagehandler.h" - -SpotifySearchProvider::SpotifySearchProvider(QObject* parent) - : SearchProvider(parent), - server_(NULL), - service_(NULL) -{ - Init("Spotify", "spotify", QIcon(":icons/32x32/spotify.png"), - WantsDelayedQueries | WantsSerialisedArtQueries | ArtIsProbablyRemote | - CanShowConfig); -} - -SpotifyServer* SpotifySearchProvider::server() { - if (server_) - return server_; - - if (!service_) - service_ = InternetModel::Service(); - - if (service_->login_state() != SpotifyService::LoginState_LoggedIn) - return NULL; - - server_ = service_->server(); - connect(server_, SIGNAL(SearchResults(spotify_pb::SearchResponse)), - SLOT(SearchFinishedSlot(spotify_pb::SearchResponse))); - connect(server_, SIGNAL(ImageLoaded(QString,QImage)), - SLOT(ArtLoadedSlot(QString,QImage))); - connect(server_, SIGNAL(AlbumBrowseResults(spotify_pb::BrowseAlbumResponse)), - SLOT(AlbumBrowseResponse(spotify_pb::BrowseAlbumResponse))); - connect(server_, SIGNAL(destroyed()), SLOT(ServerDestroyed())); - - return server_; -} - -void SpotifySearchProvider::ServerDestroyed() { - server_ = NULL; -} - -void SpotifySearchProvider::SearchAsync(int id, const QString& query) { - SpotifyServer* s = server(); - if (!s) { - emit SearchFinished(id); - return; - } - - PendingState state; - state.orig_id_ = id; - state.tokens_ = TokenizeQuery(query); - - const QString query_string = state.tokens_.join(" "); - s->Search(query_string, 5, 5); - queries_[query_string] = state; -} - -void SpotifySearchProvider::SearchFinishedSlot(const spotify_pb::SearchResponse& response) { - QString query_string = QString::fromUtf8(response.request().query().c_str()); - QMap::iterator it = queries_.find(query_string); - if (it == queries_.end()) - return; - - PendingState state = it.value(); - queries_.erase(it); - - ResultList ret; - for (int i=0; i < response.result_size() ; ++i) { - const spotify_pb::Track& track = response.result(i); - - Result result(this); - result.type_ = globalsearch::Type_Track; - SpotifyService::SongFromProtobuf(track, &result.metadata_); - result.match_quality_ = MatchQuality(state.tokens_, result.metadata_.title()); - - ret << result; - } - - for (int i=0 ; iLoadImage(image_id); -} - -void SpotifySearchProvider::ArtLoadedSlot(const QString& id, const QImage& image) { - QMap::iterator it = pending_art_.find(id); - if (it == pending_art_.end()) - return; - - const int orig_id = it.value(); - pending_art_.erase(it); - - emit ArtLoaded(orig_id, ScaleAndPad(image)); -} - -void SpotifySearchProvider::LoadTracksAsync(int id, const Result& result) { - switch (result.type_) { - case globalsearch::Type_Track: { - SongMimeData* mime_data = new SongMimeData; - mime_data->songs = SongList() << result.metadata_; - emit TracksLoaded(id, mime_data); - break; - } - - case globalsearch::Type_Album: { - SpotifyServer* s = server(); - if (!s) { - emit TracksLoaded(id, NULL); - return; - } - - QString uri = result.metadata_.url().toString(); - - pending_tracks_[uri] = id; - s->AlbumBrowse(uri); - break; - } - - default: - break; - } -} - -void SpotifySearchProvider::AlbumBrowseResponse(const spotify_pb::BrowseAlbumResponse& response) { - QString uri = QStringFromStdString(response.uri()); - QMap::iterator it = pending_tracks_.find(uri); - if (it == pending_tracks_.end()) - return; - - const int orig_id = it.value(); - pending_tracks_.erase(it); - - SongMimeData* mime_data = new SongMimeData; - - for (int i=0 ; isongs << song; - } - - emit TracksLoaded(orig_id, mime_data); -} - -bool SpotifySearchProvider::IsLoggedIn() { - if (server()) { - return service_->IsLoggedIn(); - } - return false; -} - -void SpotifySearchProvider::ShowConfig() { - if (service_) { - return service_->ShowConfig(); - } -} diff -rauN clementine-1.0.1/src/globalsearch/spotifysearchprovider.h /dev/null --- clementine-1.0.1/src/globalsearch/spotifysearchprovider.h 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,60 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 SPOTIFYSEARCHPROVIDER_H -#define SPOTIFYSEARCHPROVIDER_H - -#include "searchprovider.h" -#include "spotifyblob/common/spotifymessages.pb.h" - -class SpotifyServer; -class SpotifyService; - - -class SpotifySearchProvider : public SearchProvider { - Q_OBJECT - -public: - SpotifySearchProvider(QObject* parent = 0); - - void SearchAsync(int id, const QString& query); - void LoadArtAsync(int id, const Result& result); - void LoadTracksAsync(int id, const Result& result); - - bool IsLoggedIn(); - void ShowConfig(); - -private slots: - void ServerDestroyed(); - void SearchFinishedSlot(const spotify_pb::SearchResponse& response); - void ArtLoadedSlot(const QString& id, const QImage& image); - - void AlbumBrowseResponse(const spotify_pb::BrowseAlbumResponse& response); - -private: - SpotifyServer* server(); - -private: - SpotifyServer* server_; - SpotifyService* service_; - - QMap queries_; - QMap pending_art_; - QMap pending_tracks_; -}; - -#endif // SPOTIFYSEARCHPROVIDER_H diff -rauN clementine-1.0.1/src/internet/internetmodel.cpp clementine-libre-1.0.1/src/internet/internetmodel.cpp --- clementine-1.0.1/src/internet/internetmodel.cpp 2011-12-02 19:24:44.000000000 -0200 +++ clementine-libre-1.0.1/src/internet/internetmodel.cpp 2012-05-28 18:56:58.934758916 -0300 @@ -32,9 +32,6 @@ #ifdef HAVE_LIBLASTFM #include "lastfmservice.h" #endif -#ifdef HAVE_SPOTIFY - #include "spotifyservice.h" -#endif #include #include @@ -75,9 +72,6 @@ AddService(new SavedRadio(this)); AddService(new SkyFmService(this)); AddService(new SomaFMService(this)); -#ifdef HAVE_SPOTIFY - AddService(new SpotifyService(this)); -#endif } void InternetModel::AddService(InternetService *service) { diff -rauN clementine-1.0.1/src/internet/spotifyblobdownloader.cpp /dev/null --- clementine-1.0.1/src/internet/spotifyblobdownloader.cpp 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,222 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 "config.h" -#include "spotifyblobdownloader.h" -#include "spotifyservice.h" -#include "core/logging.h" -#include "core/network.h" -#include "core/utilities.h" - -#include -#include -#include -#include - -#ifdef HAVE_QCA - #include -#endif // HAVE_QCA - -const char* SpotifyBlobDownloader::kSignatureSuffix = ".sha1"; - - -SpotifyBlobDownloader::SpotifyBlobDownloader( - const QString& version, const QString& path, QObject* parent) - : QObject(parent), - version_(version), - path_(path), - network_(new NetworkAccessManager(this)), - progress_(new QProgressDialog(tr("Downloading Spotify plugin"), tr("Cancel"), 0, 0)) -{ - progress_->setWindowTitle(QCoreApplication::applicationName()); - connect(progress_, SIGNAL(canceled()), SLOT(Cancel())); -} - -SpotifyBlobDownloader::~SpotifyBlobDownloader() { - qDeleteAll(replies_); - replies_.clear(); - - delete progress_; -} - -bool SpotifyBlobDownloader::Prompt() { - QMessageBox::StandardButton ret = QMessageBox::question(NULL, - tr("Spotify plugin not installed"), - tr("An additional plugin is required to use Spotify in Clementine. Would you like to download and install it now?"), - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - return ret == QMessageBox::Yes; -} - -void SpotifyBlobDownloader::Start() { - qDeleteAll(replies_); - replies_.clear(); - - const QStringList filenames = QStringList() - << "blob" - << "blob" + QString(kSignatureSuffix) - << "libspotify.so.10.1.16" - << "libspotify.so.10.1.16" + QString(kSignatureSuffix); - - foreach (const QString& filename, filenames) { - const QUrl url(SpotifyService::kBlobDownloadUrl + version_ + "/" + filename); - qLog(Info) << "Downloading" << url; - - QNetworkReply* reply = network_->get(QNetworkRequest(url)); - connect(reply, SIGNAL(finished()), SLOT(ReplyFinished())); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(ReplyProgress())); - - replies_ << reply; - } - - progress_->show(); -} - -void SpotifyBlobDownloader::ReplyFinished() { - QNetworkReply* reply = qobject_cast(sender()); - if (reply->error() != QNetworkReply::NoError) { - // Handle network errors - ShowError(reply->errorString()); - return; - } - - // Is everything finished? - foreach (QNetworkReply* reply, replies_) { - if (!reply->isFinished()) { - return; - } - } - - // Read files into memory first. - QMap file_data; - QStringList signature_filenames; - - foreach (QNetworkReply* reply, replies_) { - const QString filename = reply->url().path().section('/', -1, -1); - - if (filename.endsWith(kSignatureSuffix)) { - signature_filenames << filename; - } - - file_data[filename] = reply->readAll(); - } - -#ifdef HAVE_QCA - // Load the public key - QCA::ConvertResult conversion_result; - QCA::PublicKey key = QCA::PublicKey::fromPEMFile(":/clementine-spotify-public.pem", - &conversion_result); - if (QCA::ConvertGood != conversion_result) { - ShowError("Failed to load Spotify public key"); - return; - } - - // Verify signatures - foreach (const QString& signature_filename, signature_filenames) { - QString actual_filename = signature_filename; - actual_filename.remove(kSignatureSuffix); - - qLog(Debug) << "Verifying" << actual_filename << "against" << signature_filename; - - if (!key.verifyMessage(file_data[actual_filename], - file_data[signature_filename], - QCA::EMSA3_SHA1)) { - ShowError("Invalid signature: " + actual_filename); - return; - } - } -#endif // HAVE_QCA - - // Make the destination directory and write the files into it - QDir().mkpath(path_); - - foreach (const QString& filename, file_data.keys()) { - const QString dest_path = path_ + "/" + filename; - - if (filename.endsWith(kSignatureSuffix)) - continue; - - qLog(Info) << "Writing" << dest_path; - - QFile file(dest_path); - if (!file.open(QIODevice::WriteOnly)) { - ShowError("Failed to open " + dest_path + " for writing"); - return; - } - - file.write(file_data[filename]); - file.close(); - file.setPermissions(QFile::Permissions(0x7755)); - -#ifdef Q_OS_UNIX - const int so_pos = filename.lastIndexOf(".so."); - if (so_pos != -1) { - QString link_path = path_ + "/" + filename.left(so_pos + 3); - QStringList version_parts = filename.mid(so_pos + 4).split('.'); - - while (!version_parts.isEmpty()) { - qLog(Debug) << "Linking" << dest_path << "to" << link_path; - int ret = symlink(dest_path.toLocal8Bit().constData(), - link_path.toLocal8Bit().constData()); - - if (ret != 0) { - qLog(Warning) << "Creating symlink failed with return code" << ret; - } - - link_path += "." + version_parts.takeFirst(); - } - } -#endif // Q_OS_UNIX - } - - EmitFinished(); -} - -void SpotifyBlobDownloader::ReplyProgress() { - int progress = 0; - int total = 0; - - foreach (QNetworkReply* reply, replies_) { - progress += reply->bytesAvailable(); - total += reply->rawHeader("Content-Length").toInt(); - } - - progress_->setMaximum(total); - progress_->setValue(progress); -} - -void SpotifyBlobDownloader::Cancel() { - deleteLater(); -} - -void SpotifyBlobDownloader::ShowError(const QString& message) { - // Stop any remaining replies before showing the dialog so they don't - // carry on in the background - foreach (QNetworkReply* reply, replies_) { - disconnect(reply, 0, this, 0); - reply->abort(); - } - - qLog(Warning) << message; - QMessageBox::warning(NULL, tr("Error downloading Spotify plugin"), message, - QMessageBox::Close); - deleteLater(); -} - -void SpotifyBlobDownloader::EmitFinished() { - emit Finished(); - deleteLater(); -} diff -rauN clementine-1.0.1/src/internet/spotifyblobdownloader.h /dev/null --- clementine-1.0.1/src/internet/spotifyblobdownloader.h 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,63 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 SPOTIFYBLOBDOWNLOADER_H -#define SPOTIFYBLOBDOWNLOADER_H - -#include - -class QNetworkAccessManager; -class QNetworkReply; -class QProgressDialog; - -class SpotifyBlobDownloader : public QObject { - Q_OBJECT - -public: - SpotifyBlobDownloader(const QString& version, const QString& path, - QObject* parent = 0); - ~SpotifyBlobDownloader(); - - static const char* kSignatureSuffix; - - static bool Prompt(); - - void Start(); - -signals: - void Finished(); - -private slots: - void ReplyFinished(); - void ReplyProgress(); - void Cancel(); - -private: - void ShowError(const QString& message); - void EmitFinished(); - -private: - QString version_; - QString path_; - - QNetworkAccessManager* network_; - QList replies_; - - QProgressDialog* progress_; -}; - -#endif // SPOTIFYBLOBDOWNLOADER_H diff -rauN clementine-1.0.1/src/internet/spotifysearchplaylisttype.cpp /dev/null --- clementine-1.0.1/src/internet/spotifysearchplaylisttype.cpp 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,49 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 "spotifysearchplaylisttype.h" -#include "spotifyservice.h" - -const char* SpotifySearchPlaylistType::kName = "spotify-search"; - -SpotifySearchPlaylistType::SpotifySearchPlaylistType(SpotifyService* service) - : service_(service) { -} - -QIcon SpotifySearchPlaylistType::icon(Playlist* playlist) const { - return QIcon(":icons/32x32/spotify.png"); -} - -QString SpotifySearchPlaylistType::search_hint_text(Playlist* playlist) const { - return QObject::tr("Search Spotify"); -} - -QString SpotifySearchPlaylistType::empty_playlist_text(Playlist* playlist) const { - return QObject::tr("Start typing in the search box above to find music on %1.").arg("Spotify"); -} - -bool SpotifySearchPlaylistType::has_special_search_behaviour(Playlist* playlist) const { - return true; -} - -void SpotifySearchPlaylistType::Search(const QString& text, Playlist* playlist) { - service_->Search(text, playlist); -} - -void SpotifySearchPlaylistType::DidYouMeanClicked(const QString& text, Playlist* playlist) { - service_->Search(text, playlist, true); -} diff -rauN clementine-1.0.1/src/internet/spotifysearchplaylisttype.h /dev/null --- clementine-1.0.1/src/internet/spotifysearchplaylisttype.h 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,44 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 SPOTIFYSEARCHPLAYLISTTYPE_H -#define SPOTIFYSEARCHPLAYLISTTYPE_H - -#include "playlist/specialplaylisttype.h" - -class SpotifyService; - -class SpotifySearchPlaylistType : public SpecialPlaylistType { -public: - SpotifySearchPlaylistType(SpotifyService* service); - - static const char* kName; - virtual QString name() const { return kName; } - - virtual QIcon icon(Playlist* playlist) const; - virtual QString search_hint_text(Playlist* playlist) const; - virtual QString empty_playlist_text(Playlist* playlist) const; - - virtual bool has_special_search_behaviour(Playlist* playlist) const; - virtual void Search(const QString& text, Playlist* playlist); - virtual void DidYouMeanClicked(const QString& text, Playlist* playlist); - -private: - SpotifyService* service_; -}; - -#endif // SPOTIFYSEARCHPLAYLISTTYPE_H diff -rauN clementine-1.0.1/src/internet/spotifyserver.cpp /dev/null --- clementine-1.0.1/src/internet/spotifyserver.cpp 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,261 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 "spotifyserver.h" -#include "core/closure.h" -#include "core/logging.h" - -#include "spotifyblob/common/spotifymessages.pb.h" -#include "spotifyblob/common/spotifymessagehandler.h" - -#include -#include -#include - -SpotifyServer::SpotifyServer(QObject* parent) - : QObject(parent), - server_(new QTcpServer(this)), - protocol_socket_(NULL), - handler_(NULL), - logged_in_(false) -{ - connect(server_, SIGNAL(newConnection()), SLOT(NewConnection())); -} - -void SpotifyServer::Init() { - if (!server_->listen(QHostAddress::LocalHost)) { - qLog(Error) << "Couldn't open server socket" << server_->errorString(); - } -} - -int SpotifyServer::server_port() const { - return server_->serverPort(); -} - -void SpotifyServer::NewConnection() { - delete protocol_socket_; - delete handler_; - - protocol_socket_ = server_->nextPendingConnection(); - handler_ = new SpotifyMessageHandler(protocol_socket_, this); - connect(handler_, SIGNAL(MessageArrived(spotify_pb::SpotifyMessage)), - SLOT(HandleMessage(spotify_pb::SpotifyMessage))); - - qLog(Info) << "Connection from port" << protocol_socket_->peerPort(); - - // Send any login messages that were queued before the client connected - foreach (const spotify_pb::SpotifyMessage& message, queued_login_messages_) { - SendMessage(message); - } - queued_login_messages_.clear(); -} - -void SpotifyServer::SendMessage(const spotify_pb::SpotifyMessage& message) { - const bool is_login_message = message.has_login_request(); - - QList* queue = - is_login_message ? &queued_login_messages_ : &queued_messages_; - - if (!protocol_socket_ || (!is_login_message && !logged_in_)) { - queue->append(message); - } else { - handler_->SendMessage(message); - } -} - -void SpotifyServer::Login(const QString& username, const QString& password, - spotify_pb::Bitrate bitrate, bool volume_normalisation) { - spotify_pb::SpotifyMessage message; - - spotify_pb::LoginRequest* request = message.mutable_login_request(); - request->set_username(DataCommaSizeFromQString(username)); - if (!password.isEmpty()) { - request->set_password(DataCommaSizeFromQString(password)); - } - request->mutable_playback_settings()->set_bitrate(bitrate); - request->mutable_playback_settings()->set_volume_normalisation(volume_normalisation); - - SendMessage(message); -} - -void SpotifyServer::SetPlaybackSettings(spotify_pb::Bitrate bitrate, bool volume_normalisation) { - spotify_pb::SpotifyMessage message; - - spotify_pb::PlaybackSettings* request = message.mutable_set_playback_settings_request(); - request->set_bitrate(bitrate); - request->set_volume_normalisation(volume_normalisation); - - SendMessage(message); -} - -void SpotifyServer::HandleMessage(const spotify_pb::SpotifyMessage& message) { - if (message.has_login_response()) { - const spotify_pb::LoginResponse& response = message.login_response(); - logged_in_ = response.success(); - - if (response.success()) { - // Send any messages that were queued before the client logged in - foreach (const spotify_pb::SpotifyMessage& message, queued_messages_) { - SendMessage(message); - } - queued_messages_.clear(); - } - - emit LoginCompleted(response.success(), QStringFromStdString(response.error()), - response.error_code()); - } else if (message.has_playlists_updated()) { - emit PlaylistsUpdated(message.playlists_updated()); - } else if (message.has_load_playlist_response()) { - const spotify_pb::LoadPlaylistResponse& response = message.load_playlist_response(); - - switch (response.request().type()) { - case spotify_pb::Inbox: - emit InboxLoaded(response); - break; - - case spotify_pb::Starred: - emit StarredLoaded(response); - break; - - case spotify_pb::UserPlaylist: - emit UserPlaylistLoaded(response); - break; - } - } else if (message.has_playback_error()) { - emit PlaybackError(QStringFromStdString(message.playback_error().error())); - } else if (message.has_search_response()) { - emit SearchResults(message.search_response()); - } else if (message.has_image_response()) { - const spotify_pb::ImageResponse& response = message.image_response(); - const QString id = QStringFromStdString(response.id()); - - if (response.has_data()) { - emit ImageLoaded(id, QImage::fromData(QByteArray( - response.data().data(), response.data().size()))); - } else { - emit ImageLoaded(id, QImage()); - } - } else if (message.has_sync_playlist_progress()) { - emit SyncPlaylistProgress(message.sync_playlist_progress()); - } else if (message.has_browse_album_response()) { - emit AlbumBrowseResults(message.browse_album_response()); - } -} - -void SpotifyServer::LoadPlaylist(spotify_pb::PlaylistType type, int index) { - spotify_pb::SpotifyMessage message; - spotify_pb::LoadPlaylistRequest* req = message.mutable_load_playlist_request(); - - req->set_type(type); - if (index != -1) { - req->set_user_playlist_index(index); - } - - SendMessage(message); -} - -void SpotifyServer::SyncPlaylist( - spotify_pb::PlaylistType type, int index, bool offline) { - spotify_pb::SpotifyMessage message; - spotify_pb::SyncPlaylistRequest* req = message.mutable_sync_playlist_request(); - req->mutable_request()->set_type(type); - if (index != -1) { - req->mutable_request()->set_user_playlist_index(index); - } - req->set_offline_sync(offline); - - SendMessage(message); -} - -void SpotifyServer::SyncInbox() { - SyncPlaylist(spotify_pb::Inbox, -1, true); -} - -void SpotifyServer::SyncStarred() { - SyncPlaylist(spotify_pb::Starred, -1, true); -} - -void SpotifyServer::SyncUserPlaylist(int index) { - Q_ASSERT(index >= 0); - SyncPlaylist(spotify_pb::UserPlaylist, index, true); -} - -void SpotifyServer::LoadInbox() { - LoadPlaylist(spotify_pb::Inbox); -} - -void SpotifyServer::LoadStarred() { - LoadPlaylist(spotify_pb::Starred); -} - -void SpotifyServer::LoadUserPlaylist(int index) { - Q_ASSERT(index >= 0); - LoadPlaylist(spotify_pb::UserPlaylist, index); -} - -void SpotifyServer::StartPlaybackLater(const QString& uri, quint16 port) { - QTimer* timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater())); - - timer->start(100); // lol - NewClosure(timer, SIGNAL(timeout()), - this, SLOT(StartPlayback(QString,quint16)), - uri, port); -} - -void SpotifyServer::StartPlayback(const QString& uri, quint16 port) { - spotify_pb::SpotifyMessage message; - spotify_pb::PlaybackRequest* req = message.mutable_playback_request(); - - req->set_track_uri(DataCommaSizeFromQString(uri)); - req->set_media_port(port); - SendMessage(message); -} - -void SpotifyServer::Seek(qint64 offset_bytes) { - spotify_pb::SpotifyMessage message; - spotify_pb::SeekRequest* req = message.mutable_seek_request(); - - req->set_offset_bytes(offset_bytes); - SendMessage(message); -} - -void SpotifyServer::Search(const QString& text, int limit, int limit_album) { - spotify_pb::SpotifyMessage message; - spotify_pb::SearchRequest* req = message.mutable_search_request(); - - req->set_query(DataCommaSizeFromQString(text)); - req->set_limit(limit); - req->set_limit_album(limit_album); - SendMessage(message); -} - -void SpotifyServer::LoadImage(const QString& id) { - spotify_pb::SpotifyMessage message; - spotify_pb::ImageRequest* req = message.mutable_image_request(); - - req->set_id(DataCommaSizeFromQString(id)); - SendMessage(message); -} - -void SpotifyServer::AlbumBrowse(const QString& uri) { - spotify_pb::SpotifyMessage message; - spotify_pb::BrowseAlbumRequest* req = message.mutable_browse_album_request(); - - req->set_uri(DataCommaSizeFromQString(uri)); - SendMessage(message); -} diff -rauN clementine-1.0.1/src/internet/spotifyserver.h /dev/null --- clementine-1.0.1/src/internet/spotifyserver.h 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,91 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 SPOTIFYSERVER_H -#define SPOTIFYSERVER_H - -#include "spotifyblob/common/spotifymessages.pb.h" - -#include -#include - -class SpotifyMessageHandler; - -class QTcpServer; -class QTcpSocket; - -class SpotifyServer : public QObject { - Q_OBJECT - -public: - SpotifyServer(QObject* parent = 0); - - void Init(); - void Login(const QString& username, const QString& password, - spotify_pb::Bitrate bitrate, bool volume_normalisation); - - void LoadStarred(); - void SyncStarred(); - void LoadInbox(); - void SyncInbox(); - void LoadUserPlaylist(int index); - void SyncUserPlaylist(int index); - void StartPlaybackLater(const QString& uri, quint16 port); - void Search(const QString& text, int limit, int limit_album = 0); - void LoadImage(const QString& id); - void AlbumBrowse(const QString& uri); - void SetPlaybackSettings(spotify_pb::Bitrate bitrate, bool volume_normalisation); - - int server_port() const; - -public slots: - void StartPlayback(const QString& uri, quint16 port); - void Seek(qint64 offset_bytes); - -signals: - void LoginCompleted(bool success, const QString& error, - spotify_pb::LoginResponse_Error error_code); - void PlaylistsUpdated(const spotify_pb::Playlists& playlists); - - void StarredLoaded(const spotify_pb::LoadPlaylistResponse& response); - void InboxLoaded(const spotify_pb::LoadPlaylistResponse& response); - void UserPlaylistLoaded(const spotify_pb::LoadPlaylistResponse& response); - void PlaybackError(const QString& message); - void SearchResults(const spotify_pb::SearchResponse& response); - void ImageLoaded(const QString& id, const QImage& image); - void SyncPlaylistProgress(const spotify_pb::SyncPlaylistProgress& progress); - void AlbumBrowseResults(const spotify_pb::BrowseAlbumResponse& response); - -private slots: - void NewConnection(); - void HandleMessage(const spotify_pb::SpotifyMessage& message); - -private: - void LoadPlaylist(spotify_pb::PlaylistType type, int index = -1); - void SyncPlaylist(spotify_pb::PlaylistType type, int index, bool offline); - void SendMessage(const spotify_pb::SpotifyMessage& message); - - QTcpServer* server_; - QTcpSocket* protocol_socket_; - SpotifyMessageHandler* handler_; - bool logged_in_; - - QList queued_login_messages_; - QList queued_messages_; -}; - -#endif // SPOTIFYSERVER_H diff -rauN clementine-1.0.1/src/internet/spotifyservice.cpp /dev/null --- clementine-1.0.1/src/internet/spotifyservice.cpp 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,669 +0,0 @@ -#include "config.h" -#include "internetmodel.h" -#include "spotifyblobdownloader.h" -#include "spotifyserver.h" -#include "spotifyservice.h" -#include "spotifysearchplaylisttype.h" -#include "core/database.h" -#include "core/logging.h" -#include "core/player.h" -#include "core/taskmanager.h" -#include "core/timeconstants.h" -#include "core/utilities.h" -#include "globalsearch/globalsearch.h" -#include "globalsearch/spotifysearchprovider.h" -#include "playlist/playlist.h" -#include "playlist/playlistcontainer.h" -#include "playlist/playlistmanager.h" -#include "spotifyblob/common/blobversion.h" -#include "spotifyblob/common/spotifymessagehandler.h" -#include "widgets/didyoumean.h" -#include "ui/iconloader.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -Q_DECLARE_METATYPE(QStandardItem*); - -const char* SpotifyService::kServiceName = "Spotify"; -const char* SpotifyService::kSettingsGroup = "Spotify"; -const char* SpotifyService::kBlobDownloadUrl = "http://spotify.clementine-player.org/"; -const int SpotifyService::kSearchDelayMsec = 400; - -SpotifyService::SpotifyService(InternetModel* parent) - : InternetService(kServiceName, parent, parent), - server_(NULL), - blob_process_(NULL), - root_(NULL), - search_(NULL), - starred_(NULL), - inbox_(NULL), - login_task_id_(0), - pending_search_playlist_(NULL), - context_menu_(NULL), - search_delay_(new QTimer(this)), - login_state_(LoginState_OtherError), - bitrate_(spotify_pb::Bitrate320k), - volume_normalisation_(false) -{ - // Build the search path for the binary blob. - // Look for one distributed alongside clementine first, then check in the - // user's home directory for any that have been downloaded. -#ifdef Q_OS_MAC - system_blob_path_ = QCoreApplication::applicationDirPath() + - "/../PlugIns/clementine-spotifyblob"; -#else - system_blob_path_ = QCoreApplication::applicationDirPath() + - "/clementine-spotifyblob" CMAKE_EXECUTABLE_SUFFIX; -#endif - - local_blob_version_ = QString("version%1-%2bit").arg(SPOTIFY_BLOB_VERSION).arg(sizeof(void*) * 8); - local_blob_path_ = Utilities::GetConfigPath(Utilities::Path_LocalSpotifyBlob) + - "/" + local_blob_version_ + "/blob"; - - qLog(Debug) << "Spotify system blob path:" << system_blob_path_; - qLog(Debug) << "Spotify local blob path:" << local_blob_path_; - - model()->player()->playlists()->RegisterSpecialPlaylistType( - new SpotifySearchPlaylistType(this)); - - model()->global_search()->AddProvider(new SpotifySearchProvider(this)); - - search_delay_->setInterval(kSearchDelayMsec); - search_delay_->setSingleShot(true); - connect(search_delay_, SIGNAL(timeout()), SLOT(DoSearch())); -} - -SpotifyService::~SpotifyService() { - if (blob_process_ && blob_process_->state() == QProcess::Running) { - qLog(Info) << "Terminating blob process..."; - blob_process_->terminate(); - blob_process_->waitForFinished(1000); - } -} - -QStandardItem* SpotifyService::CreateRootItem() { - root_ = new QStandardItem(QIcon(":icons/22x22/spotify.png"), kServiceName); - root_->setData(true, InternetModel::Role_CanLazyLoad); - return root_; -} - -void SpotifyService::LazyPopulate(QStandardItem* item) { - switch (item->data(InternetModel::Role_Type).toInt()) { - case InternetModel::Type_Service: - EnsureServerCreated(); - break; - - case Type_SearchResults: - break; - - case Type_InboxPlaylist: - EnsureServerCreated(); - server_->LoadInbox(); - break; - - case Type_StarredPlaylist: - EnsureServerCreated(); - server_->LoadStarred(); - break; - - case InternetModel::Type_UserPlaylist: - EnsureServerCreated(); - server_->LoadUserPlaylist(item->data(Role_UserPlaylistIndex).toInt()); - break; - - default: - break; - } - - return; -} - -QModelIndex SpotifyService::GetCurrentIndex() { - return QModelIndex(); -} - -void SpotifyService::Login(const QString& username, const QString& password) { - Logout(); - EnsureServerCreated(username, password); -} - -void SpotifyService::LoginCompleted(bool success, const QString& error, - spotify_pb::LoginResponse_Error error_code) { - if (login_task_id_) { - model()->task_manager()->SetTaskFinished(login_task_id_); - login_task_id_ = 0; - } - - if (!success) { - bool show_error_dialog = true; - QString error_copy(error); - - switch (error_code) { - case spotify_pb::LoginResponse_Error_BadUsernameOrPassword: - login_state_ = LoginState_BadCredentials; - break; - - case spotify_pb::LoginResponse_Error_UserBanned: - login_state_ = LoginState_Banned; - break; - - case spotify_pb::LoginResponse_Error_UserNeedsPremium: - login_state_ = LoginState_NoPremium; - break; - - case spotify_pb::LoginResponse_Error_ReloginFailed: - if (login_state_ == LoginState_LoggedIn) { - // This is the first time the relogin has failed - show a message this - // time only. - error_copy = tr("You have been logged out of Spotify, please re-enter your password in the Settings dialog."); - } else { - show_error_dialog = false; - } - - login_state_ = LoginState_ReloginFailed; - break; - - default: - login_state_ = LoginState_OtherError; - break; - } - - if (show_error_dialog) { - QMessageBox::warning(NULL, tr("Spotify login error"), error_copy, QMessageBox::Close); - } - } else { - login_state_ = LoginState_LoggedIn; - } - - QSettings s; - s.beginGroup(kSettingsGroup); - s.setValue("login_state", login_state_); - - emit LoginFinished(success); -} - -void SpotifyService::BlobProcessError(QProcess::ProcessError error) { - qLog(Error) << "Spotify blob process failed:" << error; - blob_process_->deleteLater(); - blob_process_ = NULL; - - if (login_task_id_) { - model()->task_manager()->SetTaskFinished(login_task_id_); - } -} - -void SpotifyService::ReloadSettings() { - QSettings s; - s.beginGroup(kSettingsGroup); - - login_state_ = LoginState(s.value("login_state", LoginState_OtherError).toInt()); - bitrate_ = static_cast( - s.value("bitrate", spotify_pb::Bitrate320k).toInt()); - volume_normalisation_ = s.value("volume_normalisation", false).toBool(); - - if (server_ && blob_process_) { - server_->SetPlaybackSettings(bitrate_, volume_normalisation_); - } -} - -void SpotifyService::EnsureServerCreated(const QString& username, - const QString& password) { - if (server_ && blob_process_) { - return; - } - - delete server_; - server_ = new SpotifyServer(this); - - connect(server_, SIGNAL(LoginCompleted(bool,QString,spotify_pb::LoginResponse_Error)), - SLOT(LoginCompleted(bool,QString,spotify_pb::LoginResponse_Error))); - connect(server_, SIGNAL(PlaylistsUpdated(spotify_pb::Playlists)), - SLOT(PlaylistsUpdated(spotify_pb::Playlists))); - connect(server_, SIGNAL(InboxLoaded(spotify_pb::LoadPlaylistResponse)), - SLOT(InboxLoaded(spotify_pb::LoadPlaylistResponse))); - connect(server_, SIGNAL(StarredLoaded(spotify_pb::LoadPlaylistResponse)), - SLOT(StarredLoaded(spotify_pb::LoadPlaylistResponse))); - connect(server_, SIGNAL(UserPlaylistLoaded(spotify_pb::LoadPlaylistResponse)), - SLOT(UserPlaylistLoaded(spotify_pb::LoadPlaylistResponse))); - connect(server_, SIGNAL(PlaybackError(QString)), - SIGNAL(StreamError(QString))); - connect(server_, SIGNAL(SearchResults(spotify_pb::SearchResponse)), - SLOT(SearchResults(spotify_pb::SearchResponse))); - connect(server_, SIGNAL(ImageLoaded(QString,QImage)), - SIGNAL(ImageLoaded(QString,QImage))); - connect(server_, SIGNAL(SyncPlaylistProgress(spotify_pb::SyncPlaylistProgress)), - SLOT(SyncPlaylistProgress(spotify_pb::SyncPlaylistProgress))); - - server_->Init(); - - login_task_id_ = model()->task_manager()->StartTask(tr("Connecting to Spotify")); - - QString login_username = username; - QString login_password = password; - - if (username.isEmpty()) { - QSettings s; - s.beginGroup(kSettingsGroup); - - login_username = s.value("username").toString(); - login_password = QString(); - } - - server_->Login(login_username, login_password, bitrate_, volume_normalisation_); - - StartBlobProcess(); -} - -void SpotifyService::StartBlobProcess() { - // Try to find an executable to run - QString blob_path; - QProcessEnvironment env(QProcessEnvironment::systemEnvironment()); - - // Look in the system search path first - if (QFile::exists(system_blob_path_)) { - blob_path = system_blob_path_; - } - - // Next look in the local path - if (blob_path.isEmpty()) { - if (QFile::exists(local_blob_path_)) { - blob_path = local_blob_path_; - env.insert("LD_LIBRARY_PATH", QFileInfo(local_blob_path_).path()); - } - } - - if (blob_path.isEmpty()) { - // If the blob still wasn't found then we'll prompt the user to download one - if (login_task_id_) { - model()->task_manager()->SetTaskFinished(login_task_id_); - } - - #ifdef Q_OS_LINUX - if (SpotifyBlobDownloader::Prompt()) { - InstallBlob(); - } - #endif - - return; - } - - delete blob_process_; - blob_process_ = new QProcess(this); - blob_process_->setProcessChannelMode(QProcess::ForwardedChannels); - blob_process_->setProcessEnvironment(env); - - connect(blob_process_, - SIGNAL(error(QProcess::ProcessError)), - SLOT(BlobProcessError(QProcess::ProcessError))); - - qLog(Info) << "Starting" << blob_path; - blob_process_->start( - blob_path, QStringList() << QString::number(server_->server_port())); -} - -bool SpotifyService::IsBlobInstalled() const { - return QFile::exists(system_blob_path_) || - QFile::exists(local_blob_path_); -} - -void SpotifyService::InstallBlob() { - // The downloader deletes itself when it finishes - SpotifyBlobDownloader* downloader = new SpotifyBlobDownloader( - local_blob_version_, QFileInfo(local_blob_path_).path(), this); - connect(downloader, SIGNAL(Finished()), SLOT(BlobDownloadFinished())); - connect(downloader, SIGNAL(Finished()), SIGNAL(BlobStateChanged())); - downloader->Start(); -} - -void SpotifyService::BlobDownloadFinished() { - EnsureServerCreated(); -} - -void SpotifyService::PlaylistsUpdated(const spotify_pb::Playlists& response) { - if (login_task_id_) { - model()->task_manager()->SetTaskFinished(login_task_id_); - login_task_id_ = 0; - } - - // Create starred and inbox playlists if they're not here already - if (!search_) { - search_ = new QStandardItem(IconLoader::Load("edit-find"), - tr("Search Spotify (opens a new tab)")); - search_->setData(Type_SearchResults, InternetModel::Role_Type); - search_->setData(InternetModel::PlayBehaviour_DoubleClickAction, - InternetModel::Role_PlayBehaviour); - - starred_ = new QStandardItem(QIcon(":/star-on.png"), tr("Starred")); - starred_->setData(Type_StarredPlaylist, InternetModel::Role_Type); - starred_->setData(true, InternetModel::Role_CanLazyLoad); - - inbox_ = new QStandardItem(IconLoader::Load("mail-message"), tr("Inbox")); - inbox_->setData(Type_InboxPlaylist, InternetModel::Role_Type); - inbox_->setData(true, InternetModel::Role_CanLazyLoad); - - root_->appendRow(search_); - root_->appendRow(starred_); - root_->appendRow(inbox_); - } - - // Don't do anything if the playlists haven't changed since last time. - if (!DoPlaylistsDiffer(response)) { - qLog(Debug) << "Playlists haven't changed - not updating"; - return; - } - - // Remove and recreate the other playlists - foreach (QStandardItem* item, playlists_) { - item->parent()->removeRow(item->row()); - } - playlists_.clear(); - - for (int i=0 ; isetData(InternetModel::Type_UserPlaylist, InternetModel::Role_Type); - item->setData(true, InternetModel::Role_CanLazyLoad); - item->setData(msg.index(), Role_UserPlaylistIndex); - item->setData(InternetModel::PlayBehaviour_SingleItem, InternetModel::Role_PlayBehaviour); - - root_->appendRow(item); - playlists_ << item; - - // Preload the playlist items so that drag & drop works immediately. - LazyPopulate(item); - } -} - -bool SpotifyService::DoPlaylistsDiffer(const spotify_pb::Playlists& response) const { - if (playlists_.count() != response.playlist_size()) { - return true; - } - - for (int i=0 ; itext()) { - return true; - } - } - - return false; -} - -void SpotifyService::InboxLoaded(const spotify_pb::LoadPlaylistResponse& response) { - FillPlaylist(inbox_, response); -} - -void SpotifyService::StarredLoaded(const spotify_pb::LoadPlaylistResponse& response) { - FillPlaylist(starred_, response); -} - -QStandardItem* SpotifyService::PlaylistBySpotifyIndex(int index) const { - foreach (QStandardItem* item, playlists_) { - if (item->data(Role_UserPlaylistIndex).toInt() == index) { - return item; - } - } - return NULL; -} - -void SpotifyService::UserPlaylistLoaded(const spotify_pb::LoadPlaylistResponse& response) { - // Find a playlist with this index - QStandardItem* item = PlaylistBySpotifyIndex(response.request().user_playlist_index()); - if (item) { - FillPlaylist(item, response); - } -} - -void SpotifyService::FillPlaylist(QStandardItem* item, const spotify_pb::LoadPlaylistResponse& response) { - qLog(Debug) << "Filling playlist:" << item->text(); - if (item->hasChildren()) - item->removeRows(0, item->rowCount()); - - for (int i=0 ; isetData(Type_Track, InternetModel::Role_Type); - child->setData(QVariant::fromValue(song), InternetModel::Role_SongMetadata); - child->setData(InternetModel::PlayBehaviour_SingleItem, InternetModel::Role_PlayBehaviour); - child->setData(song.url(), InternetModel::Role_Url); - - item->appendRow(child); - } -} - -void SpotifyService::SongFromProtobuf(const spotify_pb::Track& track, Song* song) { - song->set_rating(track.starred() ? 1.0 : 0.0); - song->set_title(QStringFromStdString(track.title())); - song->set_album(QStringFromStdString(track.album())); - song->set_length_nanosec(track.duration_msec() * kNsecPerMsec); - song->set_score(track.popularity()); - song->set_disc(track.disc()); - song->set_track(track.track()); - song->set_year(track.year()); - song->set_url(QUrl(QStringFromStdString(track.uri()))); - song->set_art_automatic("spotify://image/" + QStringFromStdString(track.album_art_id())); - - QStringList artists; - for (int i=0 ; iset_artist(artists.join(", ")); - - song->set_filetype(Song::Type_Stream); - song->set_valid(true); - song->set_directory_id(0); - song->set_mtime(0); - song->set_ctime(0); - song->set_filesize(0); -} - -PlaylistItem::Options SpotifyService::playlistitem_options() const { - return PlaylistItem::PauseDisabled | PlaylistItem::SeekDisabled; -} - -void SpotifyService::EnsureMenuCreated() { - if (context_menu_) - return; - - context_menu_ = new QMenu; - - context_menu_->addActions(GetPlaylistActions()); - context_menu_->addSeparator(); - context_menu_->addAction(IconLoader::Load("edit-find"), tr("Search Spotify (opens a new tab)..."), this, SLOT(OpenSearchTab())); - context_menu_->addSeparator(); - context_menu_->addAction(IconLoader::Load("configure"), tr("Configure Spotify..."), this, SLOT(ShowConfig())); - - playlist_context_menu_ = new QMenu; - playlist_sync_action_ = playlist_context_menu_->addAction( - IconLoader::Load("view-refresh"), - tr("Make playlist available offline"), - this, - SLOT(SyncPlaylist())); -} - -void SpotifyService::SyncPlaylist() { - QStandardItem* item = playlist_sync_action_->data().value(); - Q_ASSERT(item); - - switch (item->data(InternetModel::Role_Type).toInt()) { - case InternetModel::Type_UserPlaylist: { - int index = item->data(Role_UserPlaylistIndex).toInt(); - server_->SyncUserPlaylist(index); - playlist_sync_ids_[index] = - model()->task_manager()->StartTask(tr("Syncing Spotify playlist")); - break; - } - case Type_InboxPlaylist: - server_->SyncInbox(); - inbox_sync_id_ = model()->task_manager()->StartTask(tr("Syncing Spotify inbox")); - break; - case Type_StarredPlaylist: - server_->SyncStarred(); - starred_sync_id_ = model()->task_manager()->StartTask(tr("Syncing Spotify starred tracks")); - break; - default: - break; - } -} - -void SpotifyService::Search(const QString& text, Playlist* playlist, bool now) { - EnsureServerCreated(); - - pending_search_ = text; - pending_search_playlist_ = playlist; - - if (now) { - search_delay_->stop(); - DoSearch(); - } else { - search_delay_->start(); - } -} - -void SpotifyService::DoSearch() { - if (!pending_search_.isEmpty()) { - server_->Search(pending_search_, 200); - } -} - -void SpotifyService::SearchResults(const spotify_pb::SearchResponse& response) { - if (QStringFromStdString(response.request().query()) != pending_search_) { - qLog(Debug) << "Old search result for" - << QStringFromStdString(response.request().query()) - << "expecting" << pending_search_; - return; - } - pending_search_.clear(); - - SongList songs; - for (int i=0 ; iClear(); - pending_search_playlist_->InsertSongs(songs); - - const QString did_you_mean = QStringFromStdString(response.did_you_mean()); - if (!did_you_mean.isEmpty()) { - model()->player()->playlists()->playlist_container()->did_you_mean()->Show(did_you_mean); - } -} - -SpotifyServer* SpotifyService::server() const { - SpotifyService* nonconst_this = const_cast(this); - - if (QThread::currentThread() != thread()) { - metaObject()->invokeMethod(nonconst_this, "EnsureServerCreated", - Qt::BlockingQueuedConnection); - } else { - nonconst_this->EnsureServerCreated(); - } - - return server_; -} - -void SpotifyService::ShowContextMenu(const QModelIndex& index, const QPoint& global_pos) { - EnsureMenuCreated(); - QStandardItem* item = model()->itemFromIndex(index); - if (item) { - int type = item->data(InternetModel::Role_Type).toInt(); - if (type == Type_InboxPlaylist || - type == Type_StarredPlaylist || - type == InternetModel::Type_UserPlaylist) { - playlist_sync_action_->setData(qVariantFromValue(item)); - playlist_context_menu_->popup(global_pos); - return; - } - } - - context_menu_->popup(global_pos); -} - -void SpotifyService::OpenSearchTab() { - model()->player()->playlists()->New(tr("Search Spotify"), SongList(), - SpotifySearchPlaylistType::kName); -} - -void SpotifyService::ItemDoubleClicked(QStandardItem* item) { - if (item == search_) { - OpenSearchTab(); - } -} - -void SpotifyService::LoadImage(const QString& id) { - EnsureServerCreated(); - server_->LoadImage(id); -} - -void SpotifyService::SyncPlaylistProgress( - const spotify_pb::SyncPlaylistProgress& progress) { - qLog(Debug) << "Sync progress:" << progress.sync_progress(); - int task_id = -1; - switch (progress.request().type()) { - case spotify_pb::Inbox: - task_id = inbox_sync_id_; - break; - case spotify_pb::Starred: - task_id = starred_sync_id_; - break; - case spotify_pb::UserPlaylist: { - QMap::const_iterator it = playlist_sync_ids_.constFind( - progress.request().user_playlist_index()); - if (it != playlist_sync_ids_.constEnd()) { - task_id = it.value(); - } - break; - } - default: - break; - } - if (task_id == -1) { - qLog(Warning) << "Received sync progress for unknown playlist"; - return; - } - model()->task_manager()->SetTaskProgress(task_id, progress.sync_progress(), 100); - if (progress.sync_progress() == 100) { - model()->task_manager()->SetTaskFinished(task_id); - if (progress.request().type() == spotify_pb::UserPlaylist) { - playlist_sync_ids_.remove(task_id); - } - } -} - -void SpotifyService::ShowConfig() { - emit OpenSettingsAtPage(SettingsDialog::Page_Spotify); -} - -void SpotifyService::Logout() { - delete server_; - delete blob_process_; - server_ = NULL; - blob_process_ = NULL; - - login_state_ = LoginState_OtherError; - - QSettings s; - s.beginGroup(kSettingsGroup); - s.setValue("login_state", login_state_); -} diff -rauN clementine-1.0.1/src/internet/spotifyservice.h /dev/null --- clementine-1.0.1/src/internet/spotifyservice.h 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,147 +0,0 @@ -#ifndef SPOTIFYSERVICE_H -#define SPOTIFYSERVICE_H - -#include "internetmodel.h" -#include "internetservice.h" -#include "spotifyblob/common/spotifymessages.pb.h" - -#include -#include - -#include - -class Playlist; -class SpotifyServer; - -class QMenu; - -class SpotifyService : public InternetService { - Q_OBJECT - -public: - SpotifyService(InternetModel* parent); - ~SpotifyService(); - - enum Type { - Type_SearchResults = InternetModel::TypeCount, - Type_StarredPlaylist, - Type_InboxPlaylist, - Type_Track, - }; - - enum Role { - Role_UserPlaylistIndex = InternetModel::RoleCount, - }; - - // Values are persisted - don't change. - enum LoginState { - LoginState_LoggedIn = 1, - LoginState_Banned = 2, - LoginState_BadCredentials = 3, - LoginState_NoPremium = 4, - LoginState_OtherError = 5, - LoginState_ReloginFailed = 6 - }; - - static const char* kServiceName; - static const char* kSettingsGroup; - static const char* kBlobDownloadUrl; - static const int kSearchDelayMsec; - - void ReloadSettings(); - - QStandardItem* CreateRootItem(); - void LazyPopulate(QStandardItem* parent); - void ShowContextMenu(const QModelIndex& index, const QPoint& global_pos); - void ItemDoubleClicked(QStandardItem* item); - PlaylistItem::Options playlistitem_options() const; - - void Logout(); - void Login(const QString& username, const QString& password); - void Search(const QString& text, Playlist* playlist, bool now = false); - Q_INVOKABLE void LoadImage(const QString& id); - - SpotifyServer* server() const; - - bool IsBlobInstalled() const; - void InstallBlob(); - - // Persisted in the settings and updated on each Login(). - LoginState login_state() const { return login_state_; } - bool IsLoggedIn() const { return login_state_ == LoginState_LoggedIn; } - - static void SongFromProtobuf(const spotify_pb::Track& track, Song* song); - -signals: - void BlobStateChanged(); - void LoginFinished(bool success); - void ImageLoaded(const QString& id, const QImage& image); - -public slots: - void ShowConfig(); - -protected: - virtual QModelIndex GetCurrentIndex(); - -private: - void StartBlobProcess(); - void FillPlaylist(QStandardItem* item, const spotify_pb::LoadPlaylistResponse& response); - void EnsureMenuCreated(); - - QStandardItem* PlaylistBySpotifyIndex(int index) const; - bool DoPlaylistsDiffer(const spotify_pb::Playlists& response) const; - -private slots: - void EnsureServerCreated(const QString& username = QString(), - const QString& password = QString()); - void BlobProcessError(QProcess::ProcessError error); - void LoginCompleted(bool success, const QString& error, - spotify_pb::LoginResponse_Error error_code); - void PlaylistsUpdated(const spotify_pb::Playlists& response); - void InboxLoaded(const spotify_pb::LoadPlaylistResponse& response); - void StarredLoaded(const spotify_pb::LoadPlaylistResponse& response); - void UserPlaylistLoaded(const spotify_pb::LoadPlaylistResponse& response); - void SearchResults(const spotify_pb::SearchResponse& response); - void SyncPlaylistProgress(const spotify_pb::SyncPlaylistProgress& progress); - - void OpenSearchTab(); - void DoSearch(); - - void SyncPlaylist(); - void BlobDownloadFinished(); - -private: - SpotifyServer* server_; - - QString system_blob_path_; - QString local_blob_version_; - QString local_blob_path_; - QProcess* blob_process_; - - QStandardItem* root_; - QStandardItem* search_; - QStandardItem* starred_; - QStandardItem* inbox_; - QList playlists_; - - int login_task_id_; - QString pending_search_; - Playlist* pending_search_playlist_; - - QMenu* context_menu_; - QMenu* playlist_context_menu_; - QAction* playlist_sync_action_; - QModelIndex context_item_; - - QTimer* search_delay_; - - int inbox_sync_id_; - int starred_sync_id_; - QMap playlist_sync_ids_; - - LoginState login_state_; - spotify_pb::Bitrate bitrate_; - bool volume_normalisation_; -}; - -#endif diff -rauN clementine-1.0.1/src/internet/spotifysettingspage.cpp /dev/null --- clementine-1.0.1/src/internet/spotifysettingspage.cpp 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,172 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 "spotifysettingspage.h" - -#include "spotifyservice.h" -#include "internetmodel.h" -#include "ui_spotifysettingspage.h" -#include "core/network.h" -#include "spotifyblob/common/spotifymessages.pb.h" -#include "ui/iconloader.h" - -#include -#include -#include -#include -#include - -SpotifySettingsPage::SpotifySettingsPage(SettingsDialog* dialog) - : SettingsPage(dialog), - network_(new NetworkAccessManager(this)), - ui_(new Ui_SpotifySettingsPage), - service_(InternetModel::Service()), - validated_(false) -{ - ui_->setupUi(this); - - setWindowIcon(QIcon(":/icons/48x48/spotify.png")); - - QFont bold_font(font()); - bold_font.setBold(true); - ui_->blob_status->setFont(bold_font); - - connect(ui_->download_blob, SIGNAL(clicked()), SLOT(DownloadBlob())); - 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))); - connect(service_, SIGNAL(BlobStateChanged()), SLOT(BlobStateChanged())); - - ui_->login_state->AddCredentialField(ui_->username); - ui_->login_state->AddCredentialField(ui_->password); - ui_->login_state->AddCredentialGroup(ui_->account_group); - - ui_->bitrate->addItem("96 " + tr("kbps"), spotify_pb::Bitrate96k); - ui_->bitrate->addItem("160 " + tr("kbps"), spotify_pb::Bitrate160k); - ui_->bitrate->addItem("320 " + tr("kbps"), spotify_pb::Bitrate320k); - - BlobStateChanged(); -} - -SpotifySettingsPage::~SpotifySettingsPage() { - delete ui_; -} - -void SpotifySettingsPage::BlobStateChanged() { - const bool installed = service_->IsBlobInstalled(); - - ui_->account_group->setEnabled(installed); - ui_->blob_status->setText(installed ? tr("Installed") : tr("Not installed")); - -#ifdef Q_OS_LINUX - ui_->download_blob->setEnabled(!installed); -#else - ui_->download_blob->setEnabled(false); -#endif -} - -void SpotifySettingsPage::DownloadBlob() { - service_->InstallBlob(); -} - -void SpotifySettingsPage::Login() { - if (!service_->IsBlobInstalled()) { - return; - } - - if (ui_->username->text() == original_username_ && - ui_->password->text() == original_password_ && - service_->login_state() == SpotifyService::LoginState_LoggedIn) { - return; - } - - ui_->login_state->SetLoggedIn(LoginStateWidget::LoginInProgress); - service_->Login(ui_->username->text(), ui_->password->text()); -} - -void SpotifySettingsPage::Load() { - QSettings s; - s.beginGroup(SpotifyService::kSettingsGroup); - - original_username_ = s.value("username").toString(); - - ui_->username->setText(original_username_); - validated_ = false; - - ui_->bitrate->setCurrentIndex(ui_->bitrate->findData( - s.value("bitrate", spotify_pb::Bitrate320k).toInt())); - ui_->volume_normalisation->setChecked( - s.value("volume_normalisation", false).toBool()); - - UpdateLoginState(); -} - -void SpotifySettingsPage::Save() { - QSettings s; - s.beginGroup(SpotifyService::kSettingsGroup); - - s.setValue("username", ui_->username->text()); - s.setValue("password", ui_->password->text()); - - s.setValue("bitrate", ui_->bitrate->itemData(ui_->bitrate->currentIndex()).toInt()); - s.setValue("volume_normalisation", ui_->volume_normalisation->isChecked()); -} - -void SpotifySettingsPage::LoginFinished(bool success) { - validated_ = success; - - Save(); - UpdateLoginState(); -} - -void SpotifySettingsPage::UpdateLoginState() { - const bool logged_in = - service_->login_state() == SpotifyService::LoginState_LoggedIn; - - ui_->login_state->SetLoggedIn(logged_in ? LoginStateWidget::LoggedIn - : LoginStateWidget::LoggedOut, - ui_->username->text()); - ui_->login_state->SetAccountTypeVisible(!logged_in); - - switch (service_->login_state()) { - case SpotifyService::LoginState_NoPremium: - ui_->login_state->SetAccountTypeText(tr("You do not have a Spotify Premium account.")); - break; - - case SpotifyService::LoginState_Banned: - case SpotifyService::LoginState_BadCredentials: - ui_->login_state->SetAccountTypeText(tr("Your username or password was incorrect.")); - break; - - case SpotifyService::LoginState_ReloginFailed: - ui_->login_state->SetAccountTypeText(tr("You have been logged out of Spotify, please re-enter your password.")); - break; - - default: - ui_->login_state->SetAccountTypeText(tr("A Spotify Premium account is required.")); - break; - } -} - -void SpotifySettingsPage::Logout() { - service_->Logout(); - UpdateLoginState(); - - ui_->username->clear(); -} diff -rauN clementine-1.0.1/src/internet/spotifysettingspage.h /dev/null --- clementine-1.0.1/src/internet/spotifysettingspage.h 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,59 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, 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 SPOTIFYSETTINGSPAGE_H -#define SPOTIFYSETTINGSPAGE_H - -#include "ui/settingspage.h" - -class NetworkAccessManager; -class Ui_SpotifySettingsPage; -class SpotifyService; - -class SpotifySettingsPage : public SettingsPage { - Q_OBJECT - -public: - SpotifySettingsPage(SettingsDialog* dialog); - ~SpotifySettingsPage(); - - void Load(); - void Save(); - -public slots: - void BlobStateChanged(); - void DownloadBlob(); - -private slots: - void Login(); - void LoginFinished(bool success); - void Logout(); - -private: - void UpdateLoginState(); - -private: - NetworkAccessManager* network_; - Ui_SpotifySettingsPage* ui_; - SpotifyService* service_; - - bool validated_; - QString original_username_; - QString original_password_; -}; - -#endif // SPOTIFYSETTINGSPAGE_H diff -rauN clementine-1.0.1/src/internet/spotifysettingspage.ui /dev/null --- clementine-1.0.1/src/internet/spotifysettingspage.ui 2011-12-02 19:24:44.000000000 -0200 +++ /dev/null 2012-05-28 12:50:04.796939473 -0300 @@ -1,214 +0,0 @@ - - - SpotifySettingsPage - - - - 0 - 0 - 545 - 458 - - - - Spotify - - - - - - - - - Account details - - - - - - true - - - - 0 - - - - - Username - - - - - - - - - - Password - - - - - - - QLineEdit::Password - - - - - - - Login - - - - - - - - - - - - - Spotify plugin - - - - - - For licensing reasons Spotify support is in a separate plugin. - - - - - - - - - Plugin status: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Download... - - - - - - - - - - - - Preferences - - - - - - Preferred bitrate - - - - - - - - - - Use volume normalisation - - - - - - - - - - Qt::Vertical - - - - 20 - 30 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 64 - 64 - - - - - 64 - 64 - - - - :/spotify-core-logo-128x128.png - - - true - - - - - - - - - - LoginStateWidget - QWidget -
widgets/loginstatewidget.h
- 1 -
-
- - - - -
diff -rauN clementine-1.0.1/src/ui/about.cpp clementine-libre-1.0.1/src/ui/about.cpp --- clementine-1.0.1/src/ui/about.cpp 2012-01-22 10:43:26.000000000 -0200 +++ clementine-libre-1.0.1/src/ui/about.cpp 2012-05-28 19:44:38.760244927 -0300 @@ -79,12 +79,6 @@ ret += QString("
Scott Smitelli"); ret += QString("
Allie Brosh

"); -#ifdef HAVE_SPOTIFY - ret += "

This product uses SPOTIFY(R) CORE but is not endorsed, certified " - "or otherwise approved in any way by Spotify. Spotify is the " - "registered trade mark of the Spotify Group.

"; -#endif // HAVE_SPOTIFY - return ret; } diff -rauN clementine-1.0.1/src/ui/settingsdialog.cpp clementine-libre-1.0.1/src/ui/settingsdialog.cpp --- clementine-1.0.1/src/ui/settingsdialog.cpp 2011-12-02 19:24:44.000000000 -0200 +++ clementine-libre-1.0.1/src/ui/settingsdialog.cpp 2012-05-28 19:46:49.506369764 -0300 @@ -55,10 +55,6 @@ # include "remote/remotesettingspage.h" #endif -#ifdef HAVE_SPOTIFY -# include "internet/spotifysettingspage.h" -#endif - #include #include #include @@ -140,10 +136,6 @@ AddPage(Page_Grooveshark, new GroovesharkSettingsPage(this), providers); -#ifdef HAVE_SPOTIFY - AddPage(Page_Spotify, new SpotifySettingsPage(this), providers); -#endif - AddPage(Page_Magnatune, new MagnatuneSettingsPage(this), providers); AddPage(Page_DigitallyImported, new DigitallyImportedSettingsPage(this), providers); AddPage(Page_BackgroundStreams, new BackgroundStreamsSettingsPage(this), providers); diff -rauN clementine-1.0.1/src/ui/settingsdialog.h clementine-libre-1.0.1/src/ui/settingsdialog.h --- clementine-1.0.1/src/ui/settingsdialog.h 2011-12-02 19:24:44.000000000 -0200 +++ clementine-libre-1.0.1/src/ui/settingsdialog.h 2012-05-28 19:48:55.399426104 -0300 @@ -65,7 +65,6 @@ Page_Library, Page_Lastfm, Page_Grooveshark, - Page_Spotify, Page_Magnatune, Page_DigitallyImported, Page_BackgroundStreams, --- clementine-1.0.1/src/core/logging.cpp 2011-12-02 19:24:43.000000000 -0200 +++ clementine-libre-1.0.1/src/core/logging.cpp 2012-05-30 03:09:25.554790760 -0300 @@ -14,10 +14,6 @@ limitations under the License. */ -// Note: this file is licensed under the Apache License instead of GPL because -// it is used by the Spotify blob which links against libspotify and is not GPL -// compatible. - #include #include --- clementine-1.0.1/src/core/logging.h 2011-12-02 19:24:43.000000000 -0200 +++ clementine-libre-1.0.1/src/core/logging.h 2012-05-30 03:09:44.390404481 -0300 @@ -14,10 +14,6 @@ limitations under the License. */ -// Note: this file is licensed under the Apache License instead of GPL because -// it is used by the Spotify blob which links against libspotify and is not GPL -// compatible. - #ifndef LOGGING_H #define LOGGING_H --- clementine-1.0.1/src/core/timeconstants.h 2011-12-02 19:24:44.000000000 -0200 +++ clementine-libre-1.0.1/src/core/timeconstants.h 2012-05-30 03:10:10.338953893 -0300 @@ -14,10 +14,6 @@ limitations under the License. */ -// Note: this file is licensed under the Apache License instead of GPL because -// it is used by the Spotify blob which links against libspotify and is not GPL -// compatible. - #ifndef TIMECONSTANTS_H #define TIMECONSTANTS_H