1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-04-20 07:52:30 +02:00

* Show artist images in ArtistView (lazy-loading).

* Added artist image api to LastFmPlugin.
This commit is contained in:
Christian Muehlhaeuser 2011-04-15 07:35:42 +02:00
parent df8a333aee
commit 04d30913f9
6 changed files with 219 additions and 35 deletions

View File

@ -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 ) );

View File

@ -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<QString, QString> 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<Tomahawk::InfoSystem::InfoCustomData>( 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<Tomahawk::InfoSystem::InfoCustomData>( 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<Tomahawk::InfoSystem::InfoCustomData>( 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<QNetworkReply*>( 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()
{

View File

@ -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;
};

View File

@ -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() );
}
}

View File

@ -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

View File

@ -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<Tomahawk::artist_ptr>& 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<TreeModelItem*>(p);
if ( pm.isNull() || returnedData["url"].toString().startsWith( LASTFM_DEFAULT_COVER ) )
if ( pm.isNull() )
ai->cover = m_defaultCover;
else
ai->cover = pm;