From 56280db289798d45708db86efe7ec5313122e801 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 2 Oct 2011 12:18:48 -0400 Subject: [PATCH] Support new spotify server-side parsing, courtesy of Hugo. Thanks! --- src/libtomahawk/CMakeLists.txt | 2 + src/libtomahawk/dropjob.cpp | 74 +++++----- src/libtomahawk/dropjob.h | 3 +- src/libtomahawk/utils/itunesparser.cpp | 60 ++++++--- src/libtomahawk/utils/itunesparser.h | 4 + src/libtomahawk/utils/spotifyparser.cpp | 171 ++++++++++++------------ src/libtomahawk/utils/spotifyparser.h | 48 ++----- 7 files changed, 185 insertions(+), 177 deletions(-) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index bb21cf564..6d64c0d0b 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -194,6 +194,7 @@ set( libSources utils/shortenedlinkparser.cpp utils/stylehelper.cpp utils/qnr_iodevicestream.cpp + utils/dropjobnotifier.cpp widgets/checkdirtree.cpp widgets/querylabel.cpp @@ -413,6 +414,7 @@ set( libHeaders utils/rdioparser.h utils/shortenedlinkparser.h utils/qnr_iodevicestream.h + utils/dropjobnotifier.h widgets/checkdirtree.h widgets/querylabel.h diff --git a/src/libtomahawk/dropjob.cpp b/src/libtomahawk/dropjob.cpp index 80af236af..844c355dc 100644 --- a/src/libtomahawk/dropjob.cpp +++ b/src/libtomahawk/dropjob.cpp @@ -116,12 +116,16 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType { if ( url.contains( "itunes" ) && url.contains( "album" ) ) // YES itunes is fucked up and song links have album/ in the url. return true; + if ( url.contains( "spotify" ) && url.contains( "album" ) ) + return true; } if ( acceptedType.testFlag( Artist ) ) { if ( url.contains( "itunes" ) && url.contains( "artist" ) ) // YES itunes is fucked up and song links have album/ in the url. return true; + if ( url.contains( "spotify" ) && url.contains( "artist" ) ) + return true; } // We whitelist t.co and bit.ly (and j.mp) since they do some link checking. Often playable (e.g. spotify..) links hide behind them, @@ -374,41 +378,46 @@ DropJob::handleXspf( const QString& fileUrl ) if ( dropAction() == Default ) setDropAction( Create ); - // Doing like so on *nix, dont know really how files are - // passed on others. - // TODO look in to! -// QString newFile = fileUrl; -// newFile.replace("file://", ""); -// QFile xspfFile(newFile); -// XSPFLoader* l = new XSPFLoader( createNewPlaylist, this ); -// tDebug( LOGINFO ) << "Loading local xspf:" << newFile; -// l->load( xspfFile ); + QFile xspfFile( QUrl::fromUserInput( fileUrl ).toLocalFile() ); + + if ( xspfFile.exists() ) + { + XSPFLoader* l = new XSPFLoader( true, this ); + tDebug( LOGINFO ) << "Loading local xspf " << xspfFile.fileName(); + l->load( xspfFile ); + } + else + tLog( LOGINFO ) << "Error Loading local xspf " << xspfFile.fileName(); + + } void -DropJob::handleSpPlaylist( const QString& url ) +DropJob::handleSpotifyUrl( const QString& url ) { - qDebug() << "Got spotify playlist!!" << url; + qDebug() << "Got spotify browse uri!!" << url; - QString playlistUri = url; - if ( url.contains( "open.spotify.com/user" ) ) // convert to a URI + /// Lets allow parsing all spotify uris here, if parse server is not available + /// fallback to spotify metadata for tracks /hugo + QString browseUri = url; + if ( url.contains( "open.spotify.com/" ) ) // convert to a URI { - playlistUri.replace("http://open.spotify.com/", ""); - playlistUri.replace( "/", ":" ); - playlistUri = "spotify:" + playlistUri; + browseUri.replace( "http://open.spotify.com/", "" ); + browseUri.replace( "/", ":" ); + browseUri = "spotify:" + browseUri; } if ( dropAction() == Default ) setDropAction( Create ); - tDebug() << "Got a spotify playlist uri in dropjob!" << playlistUri; - SpotifyParser* spot = new SpotifyParser( playlistUri, dropAction() == Create, this ); + tDebug() << "Got a spotify browse uri in dropjob!" << browseUri; + SpotifyParser* spot = new SpotifyParser( browseUri, dropAction() == Create, this ); - //This currently supports draging and dropping a spotify playlist + /// This currently supports draging and dropping a spotify playlist and artist if ( dropAction() == Append ) { - tDebug() << Q_FUNC_INFO << "Asking for spotify playlist contents from" << playlistUri; + tDebug() << Q_FUNC_INFO << "Asking for spotify browse contents from" << browseUri; connect( spot, SIGNAL( tracks( QList ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) ); } @@ -420,8 +429,10 @@ DropJob::handleAllUrls( const QString& urls ) { if ( urls.contains( "xspf" ) ) handleXspf( urls ); - else if ( urls.contains( "spotify" ) && urls.contains( "playlist" ) && s_canParseSpotifyPlaylists ) - handleSpPlaylist( urls ); + else if ( urls.contains( "spotify" ) /// Handle all the spotify uris on internal server, if not avail. fallback to spotify + && ( urls.contains( "playlist" ) || urls.contains( "artist" ) || urls.contains( "album" ) || urls.contains( "track" ) ) + && s_canParseSpotifyPlaylists ) + handleSpotifyUrl( urls ); else handleTrackUrls ( urls ); } @@ -430,14 +441,7 @@ DropJob::handleAllUrls( const QString& urls ) void DropJob::handleTrackUrls( const QString& urls ) { - // TODO REMOVE HACK - if ( urls.contains( "open.spotify.com/user") || - urls.contains( "spotify:user" ) ) - { - Q_ASSERT( false ); -// handleSpPlaylist( urls, dropAction() ); - } - else if ( urls.contains( "itunes.apple.com") ) + if ( urls.contains( "itunes.apple.com") ) { QStringList tracks = urls.split( QRegExp( "\\s+" ), QString::SkipEmptyParts ); @@ -457,7 +461,7 @@ DropJob::handleTrackUrls( const QString& urls ) } else if ( urls.contains( "rdio.com" ) ) { - QStringList tracks = urls.split( "\n" ); + QStringList tracks = urls.split( QRegExp( "\\s+" ), QString::SkipEmptyParts ); tDebug() << "Got a list of rdio urls!" << tracks; RdioParser* rdio = new RdioParser( this ); @@ -466,11 +470,11 @@ DropJob::handleTrackUrls( const QString& urls ) rdio->parse( tracks ); } else if ( urls.contains( "bit.ly" ) || - urls.contains( "j.mp" ) || - urls.contains( "t.co" ) || - urls.contains( "rd.io" ) ) + urls.contains( "j.mp" ) || + urls.contains( "t.co" ) || + urls.contains( "rd.io" ) ) { - QStringList tracks = urls.split( "\n" ); + QStringList tracks = urls.split( QRegExp( "\\s+" ), QString::SkipEmptyParts ); tDebug() << "Got a list of shortened urls!" << tracks; ShortenedLinkParser* parser = new ShortenedLinkParser( tracks, this ); diff --git a/src/libtomahawk/dropjob.h b/src/libtomahawk/dropjob.h index 4bc81a2bd..1bca326af 100644 --- a/src/libtomahawk/dropjob.h +++ b/src/libtomahawk/dropjob.h @@ -90,8 +90,9 @@ public: void setGetWholeAlbums( bool getWholeAlbums ); void tracksFromMimeData( const QMimeData* data, bool allowDuplicates = false, bool onlyLocal = false, bool top10 = false ); void handleXspf( const QString& file ); - void handleSpPlaylist( const QString& url ); + void handleSpotifyUrl( const QString& url ); + static bool canParseSpotifyPlaylists() { return s_canParseSpotifyPlaylists; } static void setCanParseSpotifyPlaylists( bool parseable ) { s_canParseSpotifyPlaylists = parseable; } signals: /// QMimeData parsing results diff --git a/src/libtomahawk/utils/itunesparser.cpp b/src/libtomahawk/utils/itunesparser.cpp index 4ce127df6..1f5d9ebb1 100644 --- a/src/libtomahawk/utils/itunesparser.cpp +++ b/src/libtomahawk/utils/itunesparser.cpp @@ -23,6 +23,9 @@ #include "utils/tomahawkutils.h" #include "query.h" #include "sourcelist.h" +#include "jobview/JobStatusView.h" +#include "jobview/JobStatusModel.h" + #include #include @@ -31,6 +34,8 @@ using namespace Tomahawk; +QPixmap* ItunesParser::s_pixmap = 0; + ItunesParser::ItunesParser( const QStringList& urls, QObject* parent ) : QObject ( parent ) , m_single( false ) @@ -41,6 +46,9 @@ ItunesParser::ItunesParser( const QStringList& urls, QObject* parent ) lookupItunesUri( url ); } + + if ( !s_pixmap ) + s_pixmap = new QPixmap( ); } ItunesParser::ItunesParser( const QString& Url, QObject* parent ) @@ -48,6 +56,9 @@ ItunesParser::ItunesParser( const QString& Url, QObject* parent ) , m_single( true ) { lookupItunesUri( Url ); + + if ( !s_pixmap ) + s_pixmap = new QPixmap( RESPATH "images/itunes.png" ); } ItunesParser::~ItunesParser() @@ -58,7 +69,6 @@ ItunesParser::~ItunesParser() void ItunesParser::lookupItunesUri( const QString& link ) { - // Itunes uri parsing, using regex // (\d+)(?:\?i=*)(\d+) = AlbumId and trackId // (\d+)(?:\s*) = id @@ -68,37 +78,45 @@ ItunesParser::lookupItunesUri( const QString& link ) // Doing a parse on regex in 2 stages, // first, look if we have both album and track id - int pos = rxAlbumTrack.indexIn( link ); - if ( pos > -1 ) { - id = rxAlbumTrack.cap( 1 ); - trackId = rxAlbumTrack.cap( 2 ); - } - else - { - // Second, if we dont have trackId, check for just Id - int pos = rxId.indexIn( link ); - if ( pos > -1 ) - { - id = rxId.cap( 1 ); - } - else - return; + int pos = rxAlbumTrack.indexIn( link ); + if ( pos > -1 ) + { + id = rxAlbumTrack.cap( 1 ); + trackId = rxAlbumTrack.cap( 2 ); + } + else + { + // Second, if we dont have trackId, check for just Id + int pos = rxId.indexIn( link ); + if ( pos > -1 ) + { + id = rxId.cap( 1 ); + } + else + return; - } - - qDebug() << "Got Itunes link with id " << id << "and trackid" <get( QNetworkRequest( url ) ); connect( reply, SIGNAL( finished() ), this, SLOT( itunesResponseLookupFinished() ) ); + + DropJobNotifier* j = new DropJobNotifier( *s_pixmap, QString( "Itunes" ), type, reply ); + JobStatusView::instance()->model()->addJob( j ); + m_queries.insert( reply ); } diff --git a/src/libtomahawk/utils/itunesparser.h b/src/libtomahawk/utils/itunesparser.h index c779b47bf..1711f4796 100644 --- a/src/libtomahawk/utils/itunesparser.h +++ b/src/libtomahawk/utils/itunesparser.h @@ -24,6 +24,7 @@ #include "dllmacro.h" #include "typedefs.h" #include "query.h" +#include "dropjobnotifier.h" #include #include @@ -64,6 +65,9 @@ private: QSet< QNetworkReply* > m_queries; QString m_title, m_info, m_creator; Tomahawk::playlist_ptr m_playlist; + + DropJobNotifier* m_browseJob; + static QPixmap* s_pixmap; }; } diff --git a/src/libtomahawk/utils/spotifyparser.cpp b/src/libtomahawk/utils/spotifyparser.cpp index a1a6a05a0..86db98cd0 100644 --- a/src/libtomahawk/utils/spotifyparser.cpp +++ b/src/libtomahawk/utils/spotifyparser.cpp @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2011, Hugo Lindström * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +23,7 @@ #include "utils/tomahawkutils.h" #include "query.h" #include "sourcelist.h" +#include "dropjob.h" #include "jobview/JobStatusView.h" #include "jobview/JobStatusModel.h" @@ -29,62 +31,18 @@ #include #include +#include "dropjobnotifier.h" using namespace Tomahawk; QPixmap* SpotifyParser::s_pixmap = 0; -SpotifyJobNotifier::SpotifyJobNotifier( QNetworkReply* job ) - : JobStatusItem() - , m_type( "track" ) - , m_job( job ) -{ - connect( job, SIGNAL( finished() ), this, SLOT( setFinished()) ); -} - -SpotifyJobNotifier::SpotifyJobNotifier() - : JobStatusItem() - , m_type( "playlist" ) - , m_job( 0 ) -{ -} - - -SpotifyJobNotifier::~SpotifyJobNotifier() -{} - -QString -SpotifyJobNotifier::rightColumnText() const -{ - return QString(); -} - -QPixmap -SpotifyJobNotifier::icon() const -{ - return SpotifyParser::pixmap(); -} - - -QString -SpotifyJobNotifier::mainText() const -{ - return tr( "Parsing Spotify %1" ).arg( m_type ); -} - -void -SpotifyJobNotifier::setFinished() -{ - emit finished(); -} - - SpotifyParser::SpotifyParser( const QStringList& Urls, bool createNewPlaylist, QObject* parent ) : QObject ( parent ) , m_single( false ) , m_trackMode( true ) , m_createNewPlaylist( createNewPlaylist ) - , m_playlistJob( 0 ) + , m_browseJob( 0 ) { foreach ( const QString& url, Urls ) @@ -96,7 +54,7 @@ SpotifyParser::SpotifyParser( const QString& Url, bool createNewPlaylist, QObjec , m_single( true ) , m_trackMode( true ) , m_createNewPlaylist( createNewPlaylist ) - , m_playlistJob( 0 ) + , m_browseJob( 0 ) { lookupUrl( Url ); } @@ -114,32 +72,44 @@ SpotifyParser::lookupUrl( const QString& link ) m_trackMode = true; lookupTrack( link ); } - else if( link.contains( "playlist" ) ) + else if( link.contains( "playlist" ) || link.contains( "album" ) || link.contains( "artist" ) ) { - m_trackMode = false; - lookupPlaylist( link ); + if( !m_createNewPlaylist ) + m_trackMode = true; + else + m_trackMode = false; + + lookupSpotifyBrowse( link ); } else - return; // We only support tracks and playlists + return; // Not valid spotify item } void -SpotifyParser::lookupPlaylist( const QString& link ) +SpotifyParser::lookupSpotifyBrowse( const QString& link ) { - if ( !link.contains( "spotify:user:" ) ) // we only support playlist here - return; - - tLog() << "Parsing Spotify Playlist URI:" << link; - QUrl url = QUrl( QString( SPOTIFY_PLAYLIST_API_URL "/playlist/%1" ).arg( link ) ); + tLog() << "Parsing Spotify Browse URI:" << link; + QUrl url = QUrl( QString( SPOTIFY_PLAYLIST_API_URL "/browse/%1" ).arg( link ) ); tDebug() << "Looking up URL..." << url.toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); - connect( reply, SIGNAL( finished() ), this, SLOT( spotifyPlaylistLookupFinished() ) ); + connect( reply, SIGNAL( finished() ), this, SLOT( spotifyBrowseFinished() ) ); - m_playlistJob = new SpotifyJobNotifier(); - JobStatusView::instance()->model()->addJob( m_playlistJob ); + DropJob::DropType type; + + if ( link.contains( "spotify:user" ) ) + type = DropJob::Playlist; + if ( link.contains( "spotify:artist" ) ) + type = DropJob::Artist; + if ( link.contains( "spotify:album" ) ) + type = DropJob::Album; + if ( link.contains( "spotify:track" ) ) + type = DropJob::Track; + + m_browseJob = new DropJobNotifier( pixmap(), QString( "Spotify" ).arg( (int)type ), type, reply ); + JobStatusView::instance()->model()->addJob( m_browseJob ); m_queries.insert( reply ); } @@ -147,7 +117,6 @@ SpotifyParser::lookupPlaylist( const QString& link ) void SpotifyParser::lookupTrack( const QString& link ) { - tDebug() << "Got a QString " << link; if ( !link.contains( "track" )) // we only support track links atm return; @@ -162,12 +131,12 @@ SpotifyParser::lookupTrack( const QString& link ) } QUrl url = QUrl( QString( "http://ws.spotify.com/lookup/1/.json?uri=%1" ).arg( uri ) ); - tLog() << "Looking up spotify track information..." << url.toString(); + tDebug() << "Looking up URL..." << url.toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); connect( reply, SIGNAL( finished() ), this, SLOT( spotifyTrackLookupFinished() ) ); - SpotifyJobNotifier* j = new SpotifyJobNotifier( reply ); + DropJobNotifier* j = new DropJobNotifier( pixmap(), QString( "Spotify" ), DropJob::Track, reply ); JobStatusView::instance()->model()->addJob( j ); m_queries.insert( reply ); @@ -176,7 +145,7 @@ SpotifyParser::lookupTrack( const QString& link ) void -SpotifyParser::spotifyPlaylistLookupFinished() +SpotifyParser::spotifyBrowseFinished() { QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() ); Q_ASSERT( r ); @@ -192,28 +161,50 @@ SpotifyParser::spotifyPlaylistLookupFinished() if ( !ok ) { - tLog() << "Failed to parse json from Spotify playlist lookup:" << p.errorString() << "On line" << p.errorLine(); + tLog() << "Failed to parse json from Spotify browse item :" << p.errorString() << "On line" << p.errorLine(); checkTrackFinished(); return; } - else if ( !res.contains( "tracks" ) ) + else if ( res.contains( "trackCount" ) && res.value( "trackCount" ).toInt() < 0 ) { - tLog() << "No tracks' item in the spotify playlist lookup result... not doing anything"; + tLog() << "No tracks' item in the spotify browse result... not doing anything"; checkTrackFinished(); return; } - QVariantList trackResponse = res.value( "tracks" ).toList(); - if ( !trackResponse.isEmpty() ) - { - m_title = res.value( "title" ).toString(); - m_creator = res.value( "creator" ).toString(); - qDebug() << "playlist owner: " << m_creator; - } + QVariantMap resultResponse = res.value( res.value( "type" ).toString() ).toMap(); - foreach( QVariant track, trackResponse ) + + if ( !resultResponse.isEmpty() ) { - lookupTrack( track.toString() ); + + m_title = resultResponse.value( "name" ).toString(); + m_single = false; + + if ( res.value( "type" ).toString() == "playlist" ) + m_creator = resultResponse.value( "creator" ).toString(); + + // TODO for now only take the first artist + foreach ( QVariant result, resultResponse.value( "result" ).toList() ) + { + QVariantMap trackResult = result.toMap(); + + QString title, artist, album; + + title = trackResult.value( "title", QString() ).toString(); + artist = trackResult.value( "artist", QString() ).toString(); + album = trackResult.value( "album", QString() ).toString(); + + if ( title.isEmpty() && artist.isEmpty() ) // don't have enough... + { + tLog() << "Didn't get an artist and track name from spotify, not enough to build a query on. Aborting" << title << artist << album; + return; + } + + Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), m_trackMode ); + m_tracks << q; + } + } } else @@ -221,7 +212,10 @@ SpotifyParser::spotifyPlaylistLookupFinished() tLog() << "Error in network request to Spotify for track decoding:" << r->errorString(); } - checkPlaylistFinished(); + if ( m_trackMode ) + checkTrackFinished(); + else + checkBrowseFinished(); } @@ -272,7 +266,6 @@ SpotifyParser::spotifyTrackLookupFinished() Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), m_trackMode ); m_tracks << q; - } else { tLog() << "Error in network request to Spotify for track decoding:" << r->errorString(); @@ -281,18 +274,20 @@ SpotifyParser::spotifyTrackLookupFinished() if ( m_trackMode ) checkTrackFinished(); else - checkPlaylistFinished(); + checkBrowseFinished(); + } void -SpotifyParser::checkPlaylistFinished() +SpotifyParser::checkBrowseFinished() { tDebug() << "Checking for spotify batch playlist job finished" << m_queries.isEmpty() << m_createNewPlaylist; if ( m_queries.isEmpty() ) // we're done { - if ( m_playlistJob ) - m_playlistJob->setFinished(); - if( m_createNewPlaylist ) + if ( m_browseJob ) + m_browseJob->setFinished(); + + if( m_createNewPlaylist && !m_tracks.isEmpty() ) m_playlist = Playlist::create( SourceList::instance()->getLocal(), uuid(), m_title, @@ -301,12 +296,13 @@ SpotifyParser::checkPlaylistFinished() false, m_tracks ); - else if ( !m_tracks.isEmpty() && !m_createNewPlaylist) + else if ( m_single && !m_tracks.isEmpty() ) + emit track( m_tracks.first() ); + else if ( !m_single && !m_tracks.isEmpty() ) emit tracks( m_tracks ); deleteLater(); } - } void @@ -315,6 +311,9 @@ SpotifyParser::checkTrackFinished() tDebug() << "Checking for spotify batch track job finished" << m_queries.isEmpty(); if ( m_queries.isEmpty() ) // we're done { + if ( m_browseJob ) + m_browseJob->setFinished(); + if ( m_single && !m_tracks.isEmpty() ) emit track( m_tracks.first() ); else if ( !m_single && !m_tracks.isEmpty() ) @@ -326,7 +325,7 @@ SpotifyParser::checkTrackFinished() } QPixmap -SpotifyParser::pixmap() +SpotifyParser::pixmap() const { if ( !s_pixmap ) s_pixmap = new QPixmap( RESPATH "images/spotify-logo.png" ); diff --git a/src/libtomahawk/utils/spotifyparser.h b/src/libtomahawk/utils/spotifyparser.h index 654258962..de3e8a4ca 100644 --- a/src/libtomahawk/utils/spotifyparser.h +++ b/src/libtomahawk/utils/spotifyparser.h @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2011, Hugo Lindström * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,40 +31,18 @@ #define SPOTIFY_PLAYLIST_API_URL "http://spotikea.tomahawk-player.org:10380" -class QNetworkReply; -namespace Tomahawk -{ - -class DLLEXPORT SpotifyJobNotifier : public JobStatusItem -{ - Q_OBJECT -public: - // track - SpotifyJobNotifier( QNetworkReply* job ); - // playlist - SpotifyJobNotifier(); - virtual ~SpotifyJobNotifier(); - - virtual QString rightColumnText() const; - virtual QString mainText() const; - virtual QPixmap icon() const; - virtual QString type() const { return m_type; } - virtual bool collapseItem() const { return true; } - -public slots: - void setFinished(); - -private: - QString m_type; - QNetworkReply* m_job; -}; - - /** * Small class to parse spotify links into query_ptrs * * Connect to the signals to get the results */ + +class QNetworkReply; +namespace Tomahawk +{ + +class DropJobNotifier; + class DLLEXPORT SpotifyParser : public QObject { Q_OBJECT @@ -73,6 +52,7 @@ public: explicit SpotifyParser( const QStringList& trackUrls, bool createNewPlaylist = false, QObject* parent = 0 ); virtual ~SpotifyParser(); + signals: void track( const Tomahawk::query_ptr& track ); void tracks( const QList< Tomahawk::query_ptr > tracks ); @@ -80,16 +60,16 @@ signals: private slots: void spotifyTrackLookupFinished(); - void spotifyPlaylistLookupFinished(); + void spotifyBrowseFinished(); private: - static QPixmap pixmap(); + QPixmap pixmap() const; void lookupUrl( const QString& url ); void lookupTrack( const QString& track ); - void lookupPlaylist( const QString& playlist ); + void lookupSpotifyBrowse( const QString& playlist ); void checkTrackFinished(); - void checkPlaylistFinished(); + void checkBrowseFinished(); bool m_single; bool m_trackMode; @@ -98,7 +78,7 @@ private: QSet< QNetworkReply* > m_queries; QString m_title, m_info, m_creator; Tomahawk::playlist_ptr m_playlist; - SpotifyJobNotifier* m_playlistJob; + DropJobNotifier* m_browseJob; static QPixmap* s_pixmap; };