1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-09 15:47:38 +02:00

Add spotify infoplugin for album lookups

This commit is contained in:
Leo Franchi
2012-07-05 22:38:04 -04:00
parent 841cef878d
commit 1a1106012b
5 changed files with 376 additions and 1 deletions

View File

@@ -192,6 +192,7 @@ set( libSources
accounts/spotify/SpotifyAccount.cpp accounts/spotify/SpotifyAccount.cpp
accounts/spotify/SpotifyAccountConfig.cpp accounts/spotify/SpotifyAccountConfig.cpp
accounts/spotify/SpotifyPlaylistUpdater.cpp accounts/spotify/SpotifyPlaylistUpdater.cpp
accounts/spotify/SpotifyInfoPlugin.cpp
accounts/lastfm/LastFmAccount.cpp accounts/lastfm/LastFmAccount.cpp
accounts/lastfm/LastFmConfig.cpp accounts/lastfm/LastFmConfig.cpp

View File

@@ -29,6 +29,8 @@
#include "Pipeline.h" #include "Pipeline.h"
#include "accounts/AccountManager.h" #include "accounts/AccountManager.h"
#include "utils/Closure.h" #include "utils/Closure.h"
#include "SpotifyInfoPlugin.h"
#include "infosystem/InfoSystem.h"
#ifndef ENABLE_HEADLESS #ifndef ENABLE_HEADLESS
#include "jobview/JobStatusView.h" #include "jobview/JobStatusView.h"
@@ -106,6 +108,12 @@ SpotifyAccount::init()
AtticaManager::instance()->registerCustomAccount( s_resolverId, this ); AtticaManager::instance()->registerCustomAccount( s_resolverId, this );
qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" ); qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" );
if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() )
{
infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() );
}
if ( !AtticaManager::instance()->resolversLoaded() ) if ( !AtticaManager::instance()->resolversLoaded() )
{ {
// If we're still waiting to load, wait for the attica resolvers to come down the pipe // If we're still waiting to load, wait for the attica resolvers to come down the pipe
@@ -328,6 +336,18 @@ SpotifyAccount::connectionState() const
} }
InfoSystem::InfoPluginPtr
SpotifyAccount::infoPlugin()
{
if ( m_infoPlugin.isNull() )
{
m_infoPlugin = QWeakPointer< InfoSystem::SpotifyInfoPlugin >( new InfoSystem::SpotifyInfoPlugin( this ) );
}
return InfoSystem::InfoPluginPtr( m_infoPlugin.data() );
}
void void
SpotifyAccount::resolverInstalled(const QString& resolverId) SpotifyAccount::resolverInstalled(const QString& resolverId)
{ {
@@ -384,6 +404,14 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath )
} }
bool
SpotifyAccount::loggedIn() const
{
// TODO pending newconfigui branch
return enabled() && !m_spotifyResolver.isNull() && m_spotifyResolver.data()->running();
}
void void
SpotifyAccount::hookupAfterDeletion( bool autoEnable ) SpotifyAccount::hookupAfterDeletion( bool autoEnable )
{ {

View File

@@ -35,6 +35,12 @@ class QTimer;
class ScriptResolver; class ScriptResolver;
namespace Tomahawk { namespace Tomahawk {
namespace InfoSystem
{
class SpotifyInfoPlugin;
}
namespace Accounts { namespace Accounts {
class SpotifyAccountConfig; class SpotifyAccountConfig;
@@ -89,7 +95,7 @@ public:
virtual void deauthenticate(); virtual void deauthenticate();
virtual QWidget* aclWidget() { return 0; } virtual QWidget* aclWidget() { return 0; }
virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); } virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin();
virtual SipPlugin* sipPlugin() { return 0; } virtual SipPlugin* sipPlugin() { return 0; }
virtual bool preventEnabling() const { return m_preventEnabling; } virtual bool preventEnabling() const { return m_preventEnabling; }
@@ -102,6 +108,8 @@ public:
void setManualResolverPath( const QString& resolverPath ); void setManualResolverPath( const QString& resolverPath );
bool loggedIn() const;
public slots: public slots:
void aboutToShow( QAction* action, const Tomahawk::playlist_ptr& playlist ); void aboutToShow( QAction* action, const Tomahawk::playlist_ptr& playlist );
void syncActionTriggered( bool ); void syncActionTriggered( bool );
@@ -143,6 +151,7 @@ private:
QWeakPointer<SpotifyAccountConfig> m_configWidget; QWeakPointer<SpotifyAccountConfig> m_configWidget;
QWeakPointer<QWidget> m_aboutWidget; QWeakPointer<QWidget> m_aboutWidget;
QWeakPointer<ScriptResolver> m_spotifyResolver; QWeakPointer<ScriptResolver> m_spotifyResolver;
QWeakPointer< InfoSystem::SpotifyInfoPlugin > m_infoPlugin;
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap; QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;

View File

@@ -0,0 +1,263 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk 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.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SpotifyInfoPlugin.h"
#include "SpotifyAccount.h"
#include "utils/Closure.h"
using namespace Tomahawk;
using namespace Tomahawk::InfoSystem;
SpotifyInfoPlugin::SpotifyInfoPlugin( Accounts::SpotifyAccount* account )
: InfoPlugin()
, m_account( QWeakPointer< Accounts::SpotifyAccount >( account ) )
{
if ( !m_account.isNull() )
m_supportedGetTypes << InfoAlbumSongs;
}
SpotifyInfoPlugin::~SpotifyInfoPlugin()
{
}
void
SpotifyInfoPlugin::getInfo( InfoRequestData requestData )
{
switch ( requestData.type )
{
case InfoAlbumSongs:
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
if ( !hash.contains( "album" ) )
{
dataError( requestData );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria[ "album" ] = hash[ "album" ];
if ( hash.contains( "artist" ) )
criteria["artist"] = hash["artist"];
emit getCachedInfo( criteria, 2419200000, requestData );
return;
}
default:
dataError( requestData );
}
}
void
SpotifyInfoPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData )
{
switch ( requestData.type )
{
case InfoAlbumSongs:
{
const QString album = criteria[ "album" ];
const QString artist = criteria[ "artist" ];
if ( m_account.isNull() || !m_account.data()->loggedIn() )
{
// No running spotify account, use our webservice
QUrl lookupUrl( "http://ws.spotify.com/search/1/album.json" );
lookupUrl.addQueryItem( "q", QString( "%1 %2" ).arg( album ).arg( album ) );
QNetworkReply * reply = TomahawkUtils::nam()->get( QNetworkRequest( lookupUrl ) );
NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumIdLookupFinished( QNetworkReply*, Tomahawk::InfoSystem::InfoRequestData ) ), reply, requestData );
}
else
{
// Running resolver, so do the lookup through that
qDebug() << Q_FUNC_INFO << "Doing album lookup through spotify:" << album << artist;
QVariantMap message;
message[ "_msgtype" ] = "albumListing";
message[ "artist" ] = artist;
message[ "album" ] = album;
const QString qid = m_account.data()->sendMessage( message, this, "albumListingResult" );
m_waitingForResults[ qid ] = requestData;
}
break;
}
default:
{
Q_ASSERT( false );
break;
}
}
}
void
SpotifyInfoPlugin::albumListingResult( const QString& msgType, const QVariantMap& msg )
{
Q_ASSERT( msg.contains( "qid" ) );
Q_ASSERT( m_waitingForResults.contains( msg.value( "qid" ).toString() ) );
if ( !msg.contains( "qid" ) || !m_waitingForResults.contains( msg.value( "qid" ).toString() ) )
return;
const InfoRequestData requestData = m_waitingForResults.take( msg.value( "qid" ).toString() );
QVariantList tracks = msg.value( "tracks" ).toList();
QStringList trackNameList;
foreach ( const QVariant track, tracks )
{
const QVariantMap trackData = track.toMap();
if ( trackData.contains( "track" ) && !trackData[ "track" ].toString().isEmpty() )
trackNameList << trackData[ "track" ].toString();
}
qDebug() << Q_FUNC_INFO << "Successfully got album listing from spotify resolver";
trackListResult( trackNameList, requestData );
}
void
SpotifyInfoPlugin::albumIdLookupFinished( QNetworkReply* reply, const InfoRequestData& requestData )
{
Q_ASSERT( reply );
reply->deleteLater();
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
const QVariantMap response = p.parse( reply ).toMap();
if ( !response.contains( "albums" ) )
{
dataError( requestData );
return;
}
const QVariantList albums = response.value( "albums" ).toList();
if ( albums.isEmpty() )
{
dataError( requestData );
return;
}
const QVariantMap album = albums.first().toMap();
const QString id = album.value( "href" ).toString();
if ( id.isEmpty() || !id.contains( "spotify:album" ) )
{
qDebug() << "Empty or malformed spotify album ID from json:" << id << response;
dataError( requestData );
return;
}
qDebug() << "Doing spotify album lookup via webservice with ID:" << id;
QUrl lookupUrl( QString( "http://spotikea.tomahawk-player.org/browse/%1" ).arg( id ) );
QNetworkReply * reply = TomahawkUtils::nam()->get( QNetworkRequest( lookupUrl ) );
NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumContentsLookupFinished( QNetworkReply*, Tomahawk::InfoSystem::InfoRequestData ) ), reply, requestData );
}
else
{
qDebug() << "Network Error retrieving ID from spotify metadata service:" << reply->error() << reply->errorString() << reply->url();
}
}
void
SpotifyInfoPlugin::albumContentsLookupFinished( QNetworkReply* reply, const InfoRequestData& requestData )
{
Q_ASSERT( reply );
reply->deleteLater();
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
const QVariantMap response = p.parse( reply ).toMap();
if ( !response.contains( "album" ) )
{
dataError( requestData );
return;
}
const QVariantMap album = response.value( "album" ).toMap();
if ( !album.contains( "result" ) || album.value( "result" ).toList().isEmpty() )
{
dataError( requestData );
return;
}
const QVariantList albumTracks = album.value( "result" ).toList();
QStringList trackNameList;
foreach ( const QVariant& track, albumTracks )
{
const QVariantMap trackMap = track.toMap();
if ( trackMap.contains( "title" ) )
trackNameList << trackMap.value( "title" ).toString();
}
qDebug() << Q_FUNC_INFO << "Successfully got album listing from spotikea service!";
if ( trackNameList.isEmpty() )
dataError( requestData );
else
trackListResult( trackNameList, requestData );
}
else
{
qDebug() << "Network Error retrieving ID from spotify metadata service:" << reply->error() << reply->errorString() << reply->url();
}
}
void
SpotifyInfoPlugin::dataError( InfoRequestData requestData )
{
emit info( requestData, QVariant() );
}
void
SpotifyInfoPlugin::trackListResult( const QStringList& trackNameList, const InfoRequestData& requestData )
{
QVariantMap returnedData;
returnedData["tracks"] = trackNameList;
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = requestData.input.value< InfoStringHash>()["artist"];
criteria["album"] = requestData.input.value< InfoStringHash>()["album"];
emit updateCache( criteria, 0, requestData.type, returnedData );
}

View File

@@ -0,0 +1,74 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk 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.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SPOTIFYINFOPLUGIN_H
#define SPOTIFYINFOPLUGIN_H
#include "infosystem/InfoSystem.h"
#include "DllMacro.h"
#include <QWeakPointer>
class QNetworkReply;
namespace Tomahawk
{
namespace Accounts
{
class SpotifyAccount;
}
namespace InfoSystem
{
class DLLEXPORT SpotifyInfoPlugin : public InfoPlugin
{
Q_OBJECT
public:
explicit SpotifyInfoPlugin( Accounts::SpotifyAccount* account );
virtual ~SpotifyInfoPlugin();
public slots:
void albumListingResult( const QString& msgType, const QVariantMap& msg );
protected slots:
virtual void init() {}
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData ) {}
private slots:
void albumIdLookupFinished( QNetworkReply* reply, const Tomahawk::InfoSystem::InfoRequestData& requestData );
void albumContentsLookupFinished( QNetworkReply* reply, const Tomahawk::InfoSystem::InfoRequestData& requestData );
private:
void dataError( InfoRequestData );
void trackListResult( const QStringList& trackNameList, const Tomahawk::InfoSystem::InfoRequestData& requestData );
QHash< QString, InfoRequestData > m_waitingForResults;
QWeakPointer< Tomahawk::Accounts::SpotifyAccount > m_account;
};
}
}
#endif // SPOTIFYINFOPLUGIN_H