diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index 93bfd71e7..d80efd846 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -28,8 +28,6 @@ #include "album.h" -#define LASTFM_DEFAULT_COVER "http://cdn.last.fm/flatness/catalogue/noimage" - static QString s_acInfoIdentifier = QString( "AUDIOCONTROLS" ); @@ -257,7 +255,7 @@ AudioControls::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType ty QPixmap pm; pm.loadFromData( ba ); - if ( pm.isNull() || returnedData["url"].toString().startsWith( LASTFM_DEFAULT_COVER ) ) + if ( pm.isNull() ) ui->coverImage->setPixmap( m_defaultCover ); else ui->coverImage->setPixmap( pm.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); diff --git a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp index 0cb840265..f3a8f8b49 100644 --- a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp @@ -47,7 +47,7 @@ LastFmPlugin::LastFmPlugin( QObject* parent ) , m_authJob( 0 ) { QSet< InfoType > supportedTypes; - supportedTypes << InfoMiscSubmitScrobble << InfoMiscSubmitNowPlaying << InfoAlbumCoverArt; + supportedTypes << InfoMiscSubmitScrobble << InfoMiscSubmitNowPlaying << InfoAlbumCoverArt << InfoArtistImages; qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes); /* @@ -81,6 +81,10 @@ LastFmPlugin::LastFmPlugin( QObject* parent ) } #endif + + m_badUrls << QUrl( "http://cdn.last.fm/flatness/catalogue/noimage" ) + << QUrl( "http://cdn.last.fm/flatness/catalogue/noimage/2/default_artist_medium.png" ); + connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( settingsChanged() ), Qt::QueuedConnection ); } @@ -91,6 +95,7 @@ LastFmPlugin::~LastFmPlugin() delete m_scrobbler; } + void LastFmPlugin::dataError( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) { @@ -98,20 +103,36 @@ LastFmPlugin::dataError( const QString &caller, const InfoType type, const QVari return; } + void LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData customData ) { qDebug() << Q_FUNC_INFO; - if ( type == InfoMiscSubmitNowPlaying ) - 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 ); + + switch ( type ) + { + case InfoMiscSubmitNowPlaying: + nowPlaying( caller, type, data, customData ); + break; + + case InfoMiscSubmitScrobble: + scrobble( caller, type, data, customData ); + break; + + case InfoArtistImages: + fetchArtistImages( caller, type, data, customData ); + break; + + case InfoAlbumCoverArt: + fetchCoverArt( caller, type, data, customData ); + break; + + default: + dataError( caller, type, data, customData ); + } } + void LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) { @@ -140,6 +161,7 @@ LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVar emit info( caller, type, data, QVariant(), customData ); } + void LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) { @@ -158,6 +180,7 @@ LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVaria emit info( caller, type, data, QVariant(), customData ); } + void LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) { @@ -181,30 +204,76 @@ LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const Q emit getCachedInfo( criteria, 2419200000, caller, type, data, customData ); } + +void +LastFmPlugin::fetchArtistImages( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) +{ + qDebug() << Q_FUNC_INFO; + if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() ) + { + dataError( caller, type, data, customData ); + return; + } + InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >(); + if ( !hash.contains( "artist" ) ) + { + dataError( caller, type, data, customData ); + return; + } + + Tomahawk::InfoSystem::InfoCacheCriteria criteria; + criteria["artist"] = hash["artist"].toString(); + + emit getCachedInfo( criteria, 2419200000, caller, type, data, customData ); +} + + void LastFmPlugin::notInCacheSlot( QHash criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData ) { qDebug() << Q_FUNC_INFO; - if ( type == InfoAlbumCoverArt ) + + switch ( type ) { - QString artistName = criteria["artist"]; - QString albumName = criteria["album"]; + case InfoAlbumCoverArt: + { + QString artistName = criteria["artist"]; + QString albumName = criteria["album"]; - 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", input ); - reply->setProperty( "caller", caller ); - reply->setProperty( "type", (uint)(type) ); + QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&autocorrect=1&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", input ); + reply->setProperty( "caller", caller ); + reply->setProperty( "type", (uint)(type) ); - connect( reply, SIGNAL( finished() ), SLOT( coverArtReturned() ) ); - return; + connect( reply, SIGNAL( finished() ), SLOT( coverArtReturned() ) ); + return; + } + + case InfoArtistImages: + { + QString artistName = criteria["artist"]; + + QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b"; + QNetworkRequest req( imgurl.arg( artistName ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get( req ); + reply->setProperty( "customData", QVariant::fromValue( customData ) ); + reply->setProperty( "origData", input ); + reply->setProperty( "caller", caller ); + reply->setProperty( "type", (uint)(type) ); + + connect( reply, SIGNAL( finished() ), SLOT( artistImagesReturned() ) ); + return; + } + + default: + qDebug() << "Couldn't figure out what to do with this type of request after cache miss"; } - else - qDebug() << "Couldn't figure out what to do with this type of request after cache miss"; } + void LastFmPlugin::coverArtReturned() { @@ -213,7 +282,10 @@ LastFmPlugin::coverArtReturned() QUrl redir = reply->attribute( QNetworkRequest::RedirectionTargetAttribute ).toUrl(); if ( redir.isEmpty() ) { - const QByteArray ba = reply->readAll(); + QByteArray ba = reply->readAll(); + if ( m_badUrls.contains( reply->url() ) ) + ba = QByteArray(); + InfoCustomData returnedData; returnedData["imgbytes"] = ba; returnedData["url"] = reply->url().toString(); @@ -249,6 +321,54 @@ LastFmPlugin::coverArtReturned() reply->deleteLater(); } + +void +LastFmPlugin::artistImagesReturned() +{ + qDebug() << Q_FUNC_INFO; + QNetworkReply* reply = qobject_cast( sender() ); + QUrl redir = reply->attribute( QNetworkRequest::RedirectionTargetAttribute ).toUrl(); + if ( redir.isEmpty() ) + { + QByteArray ba = reply->readAll(); + if ( m_badUrls.contains( reply->url() ) ) + ba = QByteArray(); + + InfoCustomData returnedData; + returnedData["imgbytes"] = ba; + returnedData["url"] = reply->url().toString(); + + InfoCustomData customData = reply->property( "customData" ).value< Tomahawk::InfoSystem::InfoCustomData >(); + InfoType type = (Tomahawk::InfoSystem::InfoType)(reply->property( "type" ).toUInt()); + emit info( + reply->property( "caller" ).toString(), + type, + reply->property( "origData" ), + returnedData, + customData + ); + + InfoCustomData origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCustomData >(); + Tomahawk::InfoSystem::InfoCacheCriteria criteria; + criteria["artist"] = origData["artist"].toString(); + emit updateCache( criteria, 2419200000, type, returnedData ); + } + 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( artistImagesReturned() ) ); + } + + reply->deleteLater(); +} + + void LastFmPlugin::settingsChanged() { diff --git a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.h b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.h index 00b27b15e..1b97b0e0c 100644 --- a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.h @@ -47,21 +47,29 @@ public: public slots: void settingsChanged(); + void onAuthenticated(); void coverArtReturned(); + void artistImagesReturned(); + virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData ); private: void fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ); - void scrobble( const QString &caller, const InfoType type, const QVariant& data, InfoCustomData &customData ); + void fetchArtistImages( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ); + void createScrobbler(); + void scrobble( const QString &caller, const InfoType type, const QVariant& data, InfoCustomData &customData ); void nowPlaying( const QString &caller, const InfoType type, const QVariant& data, InfoCustomData &customData ); + void dataError( const QString &caller, const InfoType type, const QVariant& data, InfoCustomData &customData ); lastfm::MutableTrack m_track; lastfm::Audioscrobbler* m_scrobbler; QString m_pw; + QList< QUrl > m_badUrls; + QNetworkReply* m_authJob; }; diff --git a/src/libtomahawk/playlist/artistview.cpp b/src/libtomahawk/playlist/artistview.cpp index 2c8412057..126f99ecd 100644 --- a/src/libtomahawk/playlist/artistview.cpp +++ b/src/libtomahawk/playlist/artistview.cpp @@ -31,14 +31,18 @@ #include "treeitemdelegate.h" #include "playlistmanager.h" +static QString s_tmInfoIdentifier = QString( "TREEMODEL" ); + +#define SCROLL_TIMEOUT 280 + using namespace Tomahawk; ArtistView::ArtistView( QWidget* parent ) : QTreeView( parent ) + , m_header( new TreeHeader( this ) ) , m_model( 0 ) , m_proxyModel( 0 ) - , m_header( new TreeHeader( this ) ) // , m_delegate( 0 ) { setAlternatingRowColors( true ); @@ -67,6 +71,12 @@ ArtistView::ArtistView( QWidget* parent ) setFont( f ); #endif + m_timer.setInterval( SCROLL_TIMEOUT ); + + connect( verticalScrollBar(), SIGNAL( rangeChanged( int, int ) ), SLOT( onViewChanged() ) ); + connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), SLOT( onViewChanged() ) ); + connect( &m_timer, SIGNAL( timeout() ), SLOT( onScrollTimeout() ) ); + connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); } @@ -168,12 +178,57 @@ ArtistView::onFilterChanged( const QString& ) void ArtistView::startDrag( Qt::DropActions supportedActions ) { + Q_UNUSED( supportedActions ); } -// Inspired from dolphin's draganddrophelper.cpp QPixmap ArtistView::createDragPixmap( int itemCount ) const { + Q_UNUSED( itemCount ); return QPixmap(); } + + +void +ArtistView::onViewChanged() +{ + if ( m_timer.isActive() ) + m_timer.stop(); + + m_timer.start(); +} + + +void +ArtistView::onScrollTimeout() +{ + qDebug() << Q_FUNC_INFO; + if ( m_timer.isActive() ) + m_timer.stop(); + + QModelIndex left = indexAt( viewport()->rect().topLeft() ); + while ( left.isValid() && left.parent().isValid() ) + left = left.parent(); + + QModelIndex right = indexAt( viewport()->rect().bottomLeft() ); + while ( right.isValid() && right.parent().isValid() ) + right = right.parent(); + + int max = m_proxyModel->trackCount(); + if ( right.isValid() ) + max = right.row() + 1; + + for ( int i = left.row(); i < max; i++ ) + { + TreeModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( m_proxyModel->index( i, 0 ) ) ); + + Tomahawk::InfoSystem::InfoCustomData trackInfo; + trackInfo["artist"] = QVariant::fromValue< QString >( item->artist()->name() ); + trackInfo["pptr"] = QVariant::fromValue< qlonglong >( (qlonglong)item ); + + Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( + s_tmInfoIdentifier, Tomahawk::InfoSystem::InfoArtistImages, + QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); + } +} diff --git a/src/libtomahawk/playlist/artistview.h b/src/libtomahawk/playlist/artistview.h index 6f9b94b1f..e02107cbb 100644 --- a/src/libtomahawk/playlist/artistview.h +++ b/src/libtomahawk/playlist/artistview.h @@ -73,6 +73,8 @@ protected: private slots: void onFilterChanged( const QString& filter ); + void onViewChanged(); + void onScrollTimeout(); private: QPixmap createDragPixmap( int itemCount ) const; @@ -81,6 +83,8 @@ private: TreeModel* m_model; TreeProxyModel* m_proxyModel; // PlaylistItemDelegate* m_delegate; + + QTimer m_timer; }; #endif // ARTISTVIEW_H diff --git a/src/libtomahawk/playlist/treemodel.cpp b/src/libtomahawk/playlist/treemodel.cpp index 247735999..7d7974974 100644 --- a/src/libtomahawk/playlist/treemodel.cpp +++ b/src/libtomahawk/playlist/treemodel.cpp @@ -28,8 +28,6 @@ #include "database/database.h" #include "utils/tomahawkutils.h" -#define LASTFM_DEFAULT_COVER "http://cdn.last.fm/flatness/catalogue/noimage" - static QString s_tmInfoIdentifier = QString( "TREEMODEL" ); using namespace Tomahawk; @@ -369,6 +367,7 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent ) DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_collection ); cmd->setAlbum( album.data() ); +// cmd->setArtist( album->artist().data() ); QList< QVariant > rows; rows << parent.row(); @@ -442,7 +441,6 @@ TreeModel::onArtistsAdded( const QList& artists ) artistitem = new TreeModelItem( artist, m_rootItem ); artistitem->cover = m_defaultCover; artistitem->index = createIndex( m_rootItem->children.count() - 1, 0, artistitem ); - connect( artistitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } @@ -544,7 +542,8 @@ TreeModel::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, Q_UNUSED( customData ); qDebug() << Q_FUNC_INFO; - if ( caller != s_tmInfoIdentifier || type != Tomahawk::InfoSystem::InfoAlbumCoverArt ) + if ( caller != s_tmInfoIdentifier || + ( type != Tomahawk::InfoSystem::InfoAlbumCoverArt && type != Tomahawk::InfoSystem::InfoArtistImages ) ) { qDebug() << "Info of wrong type or not with our identifier"; return; @@ -567,7 +566,7 @@ TreeModel::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, qlonglong p = pptr["pptr"].toLongLong(); TreeModelItem* ai = reinterpret_cast(p); - if ( pm.isNull() || returnedData["url"].toString().startsWith( LASTFM_DEFAULT_COVER ) ) + if ( pm.isNull() ) ai->cover = m_defaultCover; else ai->cover = pm;