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:
@@ -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
|
||||||
|
@@ -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 )
|
||||||
{
|
{
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
263
src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.cpp
Normal file
263
src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.cpp
Normal 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 );
|
||||||
|
}
|
74
src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.h
Normal file
74
src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.h
Normal 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
|
Reference in New Issue
Block a user