1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-06 14:16:32 +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" #include "album.h"
#define LASTFM_DEFAULT_COVER "http://cdn.last.fm/flatness/catalogue/noimage"
static QString s_acInfoIdentifier = QString( "AUDIOCONTROLS" ); static QString s_acInfoIdentifier = QString( "AUDIOCONTROLS" );
@@ -257,7 +255,7 @@ AudioControls::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType ty
QPixmap pm; QPixmap pm;
pm.loadFromData( ba ); pm.loadFromData( ba );
if ( pm.isNull() || returnedData["url"].toString().startsWith( LASTFM_DEFAULT_COVER ) ) if ( pm.isNull() )
ui->coverImage->setPixmap( m_defaultCover ); ui->coverImage->setPixmap( m_defaultCover );
else else
ui->coverImage->setPixmap( pm.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); 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 ) , m_authJob( 0 )
{ {
QSet< InfoType > supportedTypes; QSet< InfoType > supportedTypes;
supportedTypes << InfoMiscSubmitScrobble << InfoMiscSubmitNowPlaying << InfoAlbumCoverArt; supportedTypes << InfoMiscSubmitScrobble << InfoMiscSubmitNowPlaying << InfoAlbumCoverArt << InfoArtistImages;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes); qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes);
/* /*
@@ -81,6 +81,10 @@ LastFmPlugin::LastFmPlugin( QObject* parent )
} }
#endif #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() ), connect( TomahawkSettings::instance(), SIGNAL( changed() ),
SLOT( settingsChanged() ), Qt::QueuedConnection ); SLOT( settingsChanged() ), Qt::QueuedConnection );
} }
@@ -91,6 +95,7 @@ LastFmPlugin::~LastFmPlugin()
delete m_scrobbler; delete m_scrobbler;
} }
void void
LastFmPlugin::dataError( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) 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; return;
} }
void void
LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData customData ) LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData customData )
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if ( type == InfoMiscSubmitNowPlaying )
switch ( type )
{
case InfoMiscSubmitNowPlaying:
nowPlaying( caller, type, data, customData ); nowPlaying( caller, type, data, customData );
else if ( type == InfoMiscSubmitScrobble ) break;
case InfoMiscSubmitScrobble:
scrobble( caller, type, data, customData ); scrobble( caller, type, data, customData );
else if ( type == InfoAlbumCoverArt ) break;
case InfoArtistImages:
fetchArtistImages( caller, type, data, customData );
break;
case InfoAlbumCoverArt:
fetchCoverArt( caller, type, data, customData ); fetchCoverArt( caller, type, data, customData );
else break;
default:
dataError( caller, type, data, customData ); dataError( caller, type, data, customData );
}
} }
void void
LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) 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 ); emit info( caller, type, data, QVariant(), customData );
} }
void void
LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) 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 ); emit info( caller, type, data, QVariant(), customData );
} }
void void
LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData )
{ {
@@ -181,16 +204,43 @@ LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const Q
emit getCachedInfo( criteria, 2419200000, caller, type, data, customData ); 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 void
LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData ) LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData )
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if ( type == InfoAlbumCoverArt )
switch ( type )
{
case InfoAlbumCoverArt:
{ {
QString artistName = criteria["artist"]; QString artistName = criteria["artist"];
QString albumName = criteria["album"]; QString albumName = criteria["album"];
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b"; 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 ) ); QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) );
QNetworkReply* reply = TomahawkUtils::nam()->get( req ); QNetworkReply* reply = TomahawkUtils::nam()->get( req );
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) ); reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
@@ -201,10 +251,29 @@ LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, QString caller,
connect( reply, SIGNAL( finished() ), SLOT( coverArtReturned() ) ); connect( reply, SIGNAL( finished() ), SLOT( coverArtReturned() ) );
return; return;
} }
else
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"; qDebug() << "Couldn't figure out what to do with this type of request after cache miss";
}
} }
void void
LastFmPlugin::coverArtReturned() LastFmPlugin::coverArtReturned()
{ {
@@ -213,7 +282,10 @@ LastFmPlugin::coverArtReturned()
QUrl redir = reply->attribute( QNetworkRequest::RedirectionTargetAttribute ).toUrl(); QUrl redir = reply->attribute( QNetworkRequest::RedirectionTargetAttribute ).toUrl();
if ( redir.isEmpty() ) if ( redir.isEmpty() )
{ {
const QByteArray ba = reply->readAll(); QByteArray ba = reply->readAll();
if ( m_badUrls.contains( reply->url() ) )
ba = QByteArray();
InfoCustomData returnedData; InfoCustomData returnedData;
returnedData["imgbytes"] = ba; returnedData["imgbytes"] = ba;
returnedData["url"] = reply->url().toString(); returnedData["url"] = reply->url().toString();
@@ -249,6 +321,54 @@ LastFmPlugin::coverArtReturned()
reply->deleteLater(); 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 void
LastFmPlugin::settingsChanged() LastFmPlugin::settingsChanged()
{ {

View File

@@ -47,21 +47,29 @@ public:
public slots: public slots:
void settingsChanged(); void settingsChanged();
void onAuthenticated(); void onAuthenticated();
void coverArtReturned(); void coverArtReturned();
void artistImagesReturned();
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
private: private:
void fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ); 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 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 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 ); void dataError( const QString &caller, const InfoType type, const QVariant& data, InfoCustomData &customData );
lastfm::MutableTrack m_track; lastfm::MutableTrack m_track;
lastfm::Audioscrobbler* m_scrobbler; lastfm::Audioscrobbler* m_scrobbler;
QString m_pw; QString m_pw;
QList< QUrl > m_badUrls;
QNetworkReply* m_authJob; QNetworkReply* m_authJob;
}; };

View File

@@ -31,14 +31,18 @@
#include "treeitemdelegate.h" #include "treeitemdelegate.h"
#include "playlistmanager.h" #include "playlistmanager.h"
static QString s_tmInfoIdentifier = QString( "TREEMODEL" );
#define SCROLL_TIMEOUT 280
using namespace Tomahawk; using namespace Tomahawk;
ArtistView::ArtistView( QWidget* parent ) ArtistView::ArtistView( QWidget* parent )
: QTreeView( parent ) : QTreeView( parent )
, m_header( new TreeHeader( this ) )
, m_model( 0 ) , m_model( 0 )
, m_proxyModel( 0 ) , m_proxyModel( 0 )
, m_header( new TreeHeader( this ) )
// , m_delegate( 0 ) // , m_delegate( 0 )
{ {
setAlternatingRowColors( true ); setAlternatingRowColors( true );
@@ -67,6 +71,12 @@ ArtistView::ArtistView( QWidget* parent )
setFont( f ); setFont( f );
#endif #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 ) ) ); connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) );
} }
@@ -168,12 +178,57 @@ ArtistView::onFilterChanged( const QString& )
void void
ArtistView::startDrag( Qt::DropActions supportedActions ) ArtistView::startDrag( Qt::DropActions supportedActions )
{ {
Q_UNUSED( supportedActions );
} }
// Inspired from dolphin's draganddrophelper.cpp
QPixmap QPixmap
ArtistView::createDragPixmap( int itemCount ) const ArtistView::createDragPixmap( int itemCount ) const
{ {
Q_UNUSED( itemCount );
return QPixmap(); 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: private slots:
void onFilterChanged( const QString& filter ); void onFilterChanged( const QString& filter );
void onViewChanged();
void onScrollTimeout();
private: private:
QPixmap createDragPixmap( int itemCount ) const; QPixmap createDragPixmap( int itemCount ) const;
@@ -81,6 +83,8 @@ private:
TreeModel* m_model; TreeModel* m_model;
TreeProxyModel* m_proxyModel; TreeProxyModel* m_proxyModel;
// PlaylistItemDelegate* m_delegate; // PlaylistItemDelegate* m_delegate;
QTimer m_timer;
}; };
#endif // ARTISTVIEW_H #endif // ARTISTVIEW_H

View File

@@ -28,8 +28,6 @@
#include "database/database.h" #include "database/database.h"
#include "utils/tomahawkutils.h" #include "utils/tomahawkutils.h"
#define LASTFM_DEFAULT_COVER "http://cdn.last.fm/flatness/catalogue/noimage"
static QString s_tmInfoIdentifier = QString( "TREEMODEL" ); static QString s_tmInfoIdentifier = QString( "TREEMODEL" );
using namespace Tomahawk; using namespace Tomahawk;
@@ -369,6 +367,7 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent )
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_collection ); DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_collection );
cmd->setAlbum( album.data() ); cmd->setAlbum( album.data() );
// cmd->setArtist( album->artist().data() );
QList< QVariant > rows; QList< QVariant > rows;
rows << parent.row(); rows << parent.row();
@@ -442,7 +441,6 @@ TreeModel::onArtistsAdded( const QList<Tomahawk::artist_ptr>& artists )
artistitem = new TreeModelItem( artist, m_rootItem ); artistitem = new TreeModelItem( artist, m_rootItem );
artistitem->cover = m_defaultCover; artistitem->cover = m_defaultCover;
artistitem->index = createIndex( m_rootItem->children.count() - 1, 0, artistitem ); artistitem->index = createIndex( m_rootItem->children.count() - 1, 0, artistitem );
connect( artistitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); connect( artistitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
} }
@@ -544,7 +542,8 @@ TreeModel::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type,
Q_UNUSED( customData ); Q_UNUSED( customData );
qDebug() << Q_FUNC_INFO; 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"; qDebug() << "Info of wrong type or not with our identifier";
return; return;
@@ -567,7 +566,7 @@ TreeModel::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type,
qlonglong p = pptr["pptr"].toLongLong(); qlonglong p = pptr["pptr"].toLongLong();
TreeModelItem* ai = reinterpret_cast<TreeModelItem*>(p); TreeModelItem* ai = reinterpret_cast<TreeModelItem*>(p);
if ( pm.isNull() || returnedData["url"].toString().startsWith( LASTFM_DEFAULT_COVER ) ) if ( pm.isNull() )
ai->cover = m_defaultCover; ai->cover = m_defaultCover;
else else
ai->cover = pm; ai->cover = pm;