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:
parent
df8a333aee
commit
04d30913f9
@ -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 ) );
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user