From 575ee1548aa63deec0b5727868e843e46a1d71d7 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Sat, 26 Mar 2011 11:47:54 -0400 Subject: [PATCH] Fetch cover art using LastFm via the InfoSystem plugin --- src/audiocontrols.cpp | 62 ++++++++++++++- src/audiocontrols.h | 3 + src/infosystem/infoplugins/lastfmplugin.cpp | 85 ++++++++++++++++++--- src/infosystem/infoplugins/lastfmplugin.h | 2 + 4 files changed, 139 insertions(+), 13 deletions(-) diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index d160df1d6..cd6f7682e 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -31,6 +31,7 @@ #define LASTFM_DEFAULT_COVER "http://cdn.last.fm/flatness/catalogue/noimage" +static QString s_infoIdentifier = QString("AUDIOCONTROLS"); AudioControls::AudioControls( QWidget* parent ) : QWidget( parent ) @@ -166,6 +167,12 @@ AudioControls::AudioControls( QWidget* parent ) m_defaultCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" ) .scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + connect( TomahawkApp::instance()->infoSystem(), + SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash ) ), + SLOT( infoSystemInfo( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash ) ) ); + + connect( TomahawkApp::instance()->infoSystem(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); + onPlaybackStopped(); // initial state } @@ -242,12 +249,59 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result ) onPlaybackLoading( result ); - QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b"; - QNetworkRequest req( imgurl.arg( result->artist()->name() ).arg( result->album()->name() ) ); - QNetworkReply* reply = TomahawkUtils::nam()->get( req ); - connect( reply, SIGNAL( finished() ), SLOT( onCoverArtDownloaded() ) ); + QString artistName = result->artist()->name(); + QString albumName = result->album()->name(); + + Tomahawk::InfoSystem::InfoCustomDataHash trackInfo; + + trackInfo["artist"] = QVariant::fromValue< QString >( result->artist()->name() ); + trackInfo["album"] = QVariant::fromValue< QString >( result->album()->name() ); + TomahawkApp::instance()->infoSystem()->getInfo( + s_infoIdentifier, Tomahawk::InfoSystem::InfoAlbumCoverArt, + QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomDataHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomDataHash() ); } +void +AudioControls::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData ) +{ + qDebug() << Q_FUNC_INFO; + if ( caller != s_infoIdentifier || type != Tomahawk::InfoSystem::InfoAlbumCoverArt ) + { + qDebug() << "info of wrong type or not with our identifier"; + return; + } + + if ( m_currentTrack.isNull() ) + { + qDebug() << "Current track is null when trying to apply fetched cover art"; + return; + } + + if ( !output.canConvert< Tomahawk::InfoSystem::InfoCustomDataHash >() ) + { + qDebug() << "Cannot convert fetched art from a QByteArray"; + return; + } + + Tomahawk::InfoSystem::InfoCustomDataHash returnedData = output.value< Tomahawk::InfoSystem::InfoCustomDataHash >(); + const QByteArray ba = returnedData["imgbytes"].toByteArray(); + if ( ba.length() ) + { + QPixmap pm; + pm.loadFromData( ba ); + + if ( pm.isNull() || returnedData["url"].toString().startsWith( LASTFM_DEFAULT_COVER ) ) + ui->coverImage->setPixmap( m_defaultCover ); + else + ui->coverImage->setPixmap( pm.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); + } +} + +void +AudioControls::infoSystemFinished( QString target ) +{ + qDebug() << Q_FUNC_INFO; +} void AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result ) diff --git a/src/audiocontrols.h b/src/audiocontrols.h index 8de6f765c..0491745c3 100644 --- a/src/audiocontrols.h +++ b/src/audiocontrols.h @@ -23,6 +23,7 @@ #include "result.h" #include "playlistinterface.h" +#include "tomahawk/infosystem.h" namespace Ui { @@ -44,6 +45,8 @@ signals: public slots: void onRepeatModeChanged( PlaylistInterface::RepeatMode mode ); void onShuffleModeChanged( bool enabled ); + void infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData ); + void infoSystemFinished( QString target ); protected: void changeEvent( QEvent* e ); diff --git a/src/infosystem/infoplugins/lastfmplugin.cpp b/src/infosystem/infoplugins/lastfmplugin.cpp index 22e9c70cb..81272b86f 100644 --- a/src/infosystem/infoplugins/lastfmplugin.cpp +++ b/src/infosystem/infoplugins/lastfmplugin.cpp @@ -47,7 +47,7 @@ LastFmPlugin::LastFmPlugin( QObject* parent ) , m_authJob( 0 ) { QSet< InfoType > supportedTypes; - supportedTypes << Tomahawk::InfoSystem::InfoMiscSubmitScrobble << Tomahawk::InfoSystem::InfoMiscSubmitNowPlaying; + supportedTypes << InfoMiscSubmitScrobble << InfoMiscSubmitNowPlaying << InfoAlbumCoverArt; qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes); /* @@ -91,6 +91,14 @@ LastFmPlugin::~LastFmPlugin() delete m_scrobbler; } +void +LastFmPlugin::dataError( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData ) +{ + emit info( caller, type, data, QVariant(), customData ); + emit finished( caller, type ); + return; +} + void LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash customData ) { @@ -99,6 +107,8 @@ LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVarian nowPlaying( caller, type, data, customData ); else if ( type == InfoMiscSubmitScrobble ) scrobble( caller, type, data, customData ); + else if ( type == InfoAlbumCoverArt ) + fetchCoverArt( caller, type, data, customData ); else dataError( caller, type, data, customData ); } @@ -132,14 +142,6 @@ LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVar emit finished( caller, type ); } -void -LastFmPlugin::dataError( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData ) -{ - emit info( caller, type, data, QVariant(), customData ); - emit finished( caller, type ); - return; -} - void LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData ) { @@ -159,6 +161,71 @@ LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVaria emit finished( caller, type ); } +void +LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData ) +{ + qDebug() << Q_FUNC_INFO; + if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomDataHash >() ) + { + dataError( caller, type, data, customData ); + return; + } + InfoCustomDataHash hash = data.value< Tomahawk::InfoSystem::InfoCustomDataHash >(); + if ( !hash.contains( "artist" ) || !hash.contains( "album" ) ) + { + dataError( caller, type, data, customData ); + return; + } + + QString artistName = hash["artist"].toString(); + QString albumName = hash["album"].toString(); + + QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b"; + QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get( req ); + reply->setProperty("customData", QVariant::fromValue(customData)); + reply->setProperty("origData", data); + reply->setProperty("caller", caller); + reply->setProperty("type", (uint)(type) ); + + connect( reply, SIGNAL( finished() ), SLOT( coverArtReturned() ) ); +} + +void +LastFmPlugin::coverArtReturned() +{ + qDebug() << Q_FUNC_INFO; + QNetworkReply* reply = qobject_cast( sender() ); + QUrl redir = reply->attribute( QNetworkRequest::RedirectionTargetAttribute ).toUrl(); + if ( redir.isEmpty() ) + { + const QByteArray ba = reply->readAll(); + Tomahawk::InfoSystem::InfoCustomDataHash returnedData; + returnedData["imgbytes"] = ba; + returnedData["url"] = reply->url().toString(); + emit info( + reply->property( "caller" ).toString(), + (Tomahawk::InfoSystem::InfoType)(reply->property( "type" ).toUInt()), + reply->property( "origData" ), + returnedData, + reply->property( "customData" ).value< Tomahawk::InfoSystem::InfoCustomDataHash >() + ); + emit finished( reply->property( "caller" ).toString(), (Tomahawk::InfoSystem::InfoType)(reply->property( "type" ).toUInt()) ); + } + else + { + // Follow HTTP redirect + QNetworkRequest req( redir ); + QNetworkReply* newReply = TomahawkUtils::nam()->get( req ); + newReply->setProperty( "origData", reply->property( "origData" ) ); + newReply->setProperty( "customData", reply->property( "customData" ) ); + newReply->setProperty( "caller", reply->property( "caller" ) ); + newReply->setProperty( "type", reply->property( "type" ) ); + connect( newReply, SIGNAL( finished() ), SLOT( coverArtReturned() ) ); + } + + reply->deleteLater(); +} void LastFmPlugin::settingsChanged() diff --git a/src/infosystem/infoplugins/lastfmplugin.h b/src/infosystem/infoplugins/lastfmplugin.h index 775bfd3c8..3f396edfb 100644 --- a/src/infosystem/infoplugins/lastfmplugin.h +++ b/src/infosystem/infoplugins/lastfmplugin.h @@ -48,8 +48,10 @@ public: public slots: void settingsChanged(); void onAuthenticated(); + void coverArtReturned(); private: + void fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData ); void scrobble( const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash &customData ); void createScrobbler(); void nowPlaying( const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash &customData );