1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-28 11:42:42 +01:00

Merge branch 'master' into accounts

This commit is contained in:
Jeff Mitchell 2011-11-05 08:32:32 -04:00
commit 988554934b
138 changed files with 3784 additions and 2082 deletions

View File

@ -127,8 +127,16 @@ ENDIF()
#macro_log_feature(LIBLASTFM_FOUND "LastFm" "Qt library for the Last.fm webservices" "https://github.com/mxcl/liblastfm" FALSE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork")
set(LIBLASTFM_FOUND true)
#### submodules start
# this installs headers and such and should really be handled in a separate package by packagers
IF( INTERNAL_JREEN OR INTERNAL_QTWEETLIB )
IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.gitmodules)
EXECUTE_PROCESS(COMMAND git submodule init WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
EXECUTE_PROCESS(COMMAND git submodule update WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.gitmodules)
ENDIF()
IF( INTERNAL_JREEN )
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/jreen )
SET( LIBJREEN_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/include )
@ -141,7 +149,6 @@ ELSE( INTERNAL_JREEN )
ENDIF( INTERNAL_JREEN )
macro_log_feature(LIBJREEN_FOUND "Jreen" "Qt XMPP Library" "https://github.com/euroelessar/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin. \n\n Use -DINTERNAL_JREEN=ON to build the git submodule inside Tomahawk \n Be aware this installs a full jreen with headers and everything!\n")
# this installs headers and such and should really be handled in a separate package by packagers
IF( INTERNAL_QTWEETLIB )
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/qtweetlib )
# copy headers to build/QTweetLib so we can use proper includes inside the code
@ -155,6 +162,7 @@ ELSE( INTERNAL_QTWEETLIB )
macro_optional_find_package(QTweetLib)
ENDIF( INTERNAL_QTWEETLIB )
macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://github.com/minimoog/QTweetLib" FALSE "" "QTweetLib is needed for the Twitter SIP plugin. \n\n Use -DINTERNAL_QTWEETLIB=ON to build the git submodule inside Tomahawk \n")
#### submodules end
### libportfwd
SET( LIBPORTFWD_INCLUDE_DIR ${THIRDPARTY_DIR}/libportfwd/include )

View File

@ -12,7 +12,15 @@
INCLUDE(CheckSymbolExists)
INCLUDE(FindLibraryWithDebug)
# try to locate a patched unstable version (for comp's sake *sigh*) first
FIND_PACKAGE(CLuceneUnstable)
IF(CLUCENEUNSTABLE_FOUND)
SET(CLucene_FOUND TRUE)
SET(CLUCENE_INCLUDE_DIR ${CLUCENE_UNSTABLE_INCLUDE_DIRS})
SET(CLUCENE_LIBRARIES ${CLUCENE_UNSTABLE_LIBS})
#MESSAGE(FATAL_ERROR NARF)
ELSE(CLUCENEUNSTABLE_FOUND)
IF(CLucene_FIND_VERSION)
SET(CLUCENE_MIN_VERSION ${CLucene_FIND_VERSION})
ELSEIF()
@ -99,6 +107,7 @@ ENDIF (CLUCENE_LIBRARY_DIR)
IF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARIES AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION)
SET(CLucene_FOUND TRUE)
ENDIF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARIES AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION)
ENDIF(CLUCENEUNSTABLE_FOUND)
IF(CLucene_FOUND)
IF(NOT CLucene_FIND_QUIETLY)

View File

@ -0,0 +1,37 @@
# - Try to find clucene-unstable
# This is a workaround for distros, that want to ship a recent enough clucene but don't want to replace the old version
#
# CLUCENEUNSTABLE_FOUND - system has clucene-unstable
# CLUCENE_UNSTABLE_INCLUDE_DIR - the clucene-unstable include directories
# CLUCENE_UNSTABLE_LIBS - link these to use clucene-unstable
#
# (c) Dominik Schmidt <dev@dominik-schmidt.de>
#
# Include dir
find_path(CLUCENE_UNSTABLE_INCLUDE_DIR
NAMES CLucene.h
PATH_SUFFIXES clucene-unstable
PATHS ${KDE4_INCLUDE_DIR}
)
# Finally the library itself
find_library(CLUCENE_UNSTABLE_SHARED_LIB
NAMES clucene-unstable-shared
PATHS ${KDE4_LIB_DIR}
)
find_library(CLUCENE_UNSTABLE_CORE_LIB
NAMES clucene-unstable-core
PATHS ${KDE4_LIB_DIR}
)
SET( CLUCENE_UNSTABLE_LIBS ${CLUCENE_UNSTABLE_SHARED_LIB} ${CLUCENE_UNSTABLE_CORE_LIB} )
SET( CLUCENE_UNSTABLE_INCLUDE_DIRS ${CLUCENE_UNSTABLE_INCLUDE_DIR})
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CLuceneUnstable DEFAULT_MSG CLUCENE_UNSTABLE_LIBS CLUCENE_UNSTABLE_INCLUDE_DIRS)
MARK_AS_ADVANCED(CLUCENE_UNSTABLE_LIBS CLUCENE_UNSTABLE_INCLUDE_DIRS)

View File

@ -1,12 +1,72 @@
Version 0.3.0:
* Fixed bug where we would download http:// tracks twice.
* Make artist names in the album view clickable.
* Don't start playing if a tomahawk:// link was clicked while Tomahawk
is paused.
* Make artist name clickable in header of Album pages.
* Fixed adding social actions such as loved tracks from other sources.
* Added a drop shadow to cover images, and put CD placeholder in jewel
case.
* Added shuffle and repeat support to tree view.
* Draw a speaker next to the currently playing playlist.
* Refresh station previews whenever a filter is changed.
* Support and show official releases on album and track pages.
* Filter out duplicates from station previews and upcoming tracks.
* Resolve lists top-down.
* Added YouTube resolver.
* Fixed bug where going offline then online would not re-connect to many
peers.
* Added support for auto-updating live xspf playlists.
* Don't show an age of 41 for tracks that have no age information.
* Show config UI for resolvers that have them as so on as you add the resolver.
* Add support for Echo Nest Personal Catalogs and User Radio. Synchronize
your catalog with The Echo Nest and enable personal recommendations
from you and your friends.
* Added support for Grooveshark resolver (requires Grooveshark Anywhere).
* Fixed re-resolving when resolvers or sources go offline.
* Correctly sort recently played tracks on the Dashboard.
* Show a Lion full-screen toggle button if running on Lion.
* Display list of who is currently listening along to you.
* Show headphone icon in source item to allow users to listen along; paint
headphones red on a source if the user is listening along to it.
* Added new job status view in the bottom of the source list that displays
current jobs such as resolving, parsing playlists, and loading from
database.
* Parse and convert a Spotify playlist url when dropped anywhere on the
sidebar
* Convert resolvers to use asynchronous calls to avoid blocking Tomahawk's
UI, greatly increasing responsiveness of Tomahawk while resolving.
* Fixed no playlists overlay not disappearing when playlists were added.
* Add support for parsing itunes track, artist and album links.
* Fixed crash when syncing playlists with peers.
* Add support for browsing, downloading and rating resolvers
from inside Tomahawk directly.
* Support multi-folder selection and scanning.
* Actually remove deleted files from the collection.
* Fixed handling of special characters in tomahawk:// links
* Improve sidebar performance by caching pixmaps and shrinking them.
* Send updated playlists to peers when tracks are moved/copied.
* Remove splitter handles in sidebar
* Fixed Tomahawk preventing system shutdown / logut.
* Ignore leading 'The' when sorting artists.
* Added Charts page, which shows various sources' top hits & artists.
* The Collection tree-views can now be filtered.
* Fixed crash when pressing enter in an empty playlist.
* Moved the song queue below to the left, below the sidebar.
* Added Footnotes, a contextual view that you can slide it.
* Show recently added playlists in dashboard rather than recently opened
playlists.
* Fixed seek slider and give it some smooth animation between ticks.
* Fixed Twitter issue where it would repeatedly send DMs to friends.
* Add a new drag and drop menu when dropping items onto playlists,
allowing users to drop the dragged tracks, the whole album, or
the whole artists's tracks.
* Bring Tomahawk window to the front when clicking a Tomahawk link.
* Fixed crash in source list when initially syncing with remote sources.
* Open temporary artist, album, and search playlists as temporary items
in the sidebar.
* Fixed sorting of playlists and items in the artist view.
* Allow dragging and dropping albums and artists to playlists.
* Added MPRIS 2.1 support.
Version 0.2.3:

2
README
View File

@ -34,7 +34,7 @@ Dependencies
TagLib 1.6.2 - http://developer.kde.org/~wheeler/taglib.html
Boost 1.3 - http://www.boost.org/
CLucene 0.9.23 (0.9.21 will fail) - http://clucene.sourceforge.net/download.shtml
libechonest 1.1.9 - http://projects.kde.org/projects/playground/libs/libechonest/
libechonest 1.2.0 - http://projects.kde.org/projects/playground/libs/libechonest/
The following dependencies are optional, but recommended:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
data/images/rdio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@
<file>data/images/avatar-dude.png</file>
<file>data/images/back-pressed.png</file>
<file>data/images/back-rest.png</file>
<file>data/images/cover-shadow.png</file>
<file>data/images/filter.png</file>
<file>data/images/loved.png</file>
<file>data/images/not-loved.png</file>
@ -112,7 +111,7 @@
<file>data/sql/dbmigrate-23_to_24.sql</file>
<file>data/sql/dbmigrate-24_to_25.sql</file>
<file>data/sql/dbmigrate-25_to_26.sql</file>
<file>data/sql/dbmigrate-26_to_27.sql</file>
<file>data/sql/dbmigrate-26_to_27.sql</file>
<file>data/js/tomahawk.js</file>
<file>data/images/avatar_frame.png</file>
<file>data/images/drop-all-songs.png</file>
@ -120,7 +119,7 @@
<file>data/images/drop-top-songs.png</file>
<file>data/images/drop-song.png</file>
<file>data/images/drop-album.png</file>
<file>data/images/spotify-logo.png</file>
<file>data/images/spotify-logo.png</file>
<file>data/images/itunes.png</file>
<file>data/images/uploading.png</file>
<file>data/images/downloading.png</file>
@ -128,5 +127,7 @@
<file>data/images/headphones-off.png</file>
<file>data/images/headphones-sidebar.png</file>
<file>data/images/headphones-bigger.png</file>
<file>data/images/no-album-no-case.png</file>
<file>data/images/rdio.png</file>
</qresource>
</RCC>

View File

@ -5,6 +5,6 @@ FOREACH( _file ${_icons} )
INSTALL( FILES ${_file} RENAME tomahawk.png DESTINATION share/icons/hicolor/${_res}/apps )
ENDFOREACH( _file )
INSTALL( FILES ${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon.svg RENAME tomahawk.svg DESTINATION share/icons/hicolor/scalable )
INSTALL( FILES ${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon.svg RENAME tomahawk.svg DESTINATION share/icons/hicolor/scalable/apps )
INSTALL( FILES ${CMAKE_SOURCE_DIR}/admin/unix/tomahawk.desktop DESTINATION share/applications )

View File

@ -40,6 +40,7 @@
GetNewStuffDelegate::GetNewStuffDelegate( QObject* parent )
: QStyledItemDelegate ( parent )
, m_widestTextWidth( 0 )
, m_hoveringOver( -1 )
{
m_defaultCover.load( RESPATH "images/sipplugin-online.png" );
m_ratingStarPositive.load( RESPATH "images/starred.png" );
@ -190,8 +191,10 @@ GetNewStuffDelegate::paint( QPainter* painter, const QStyleOptionViewItem& optio
if ( i == 1 )
m_cachedStarRects[ QPair<int, int>(index.row(), index.column()) ] = r;
QPixmap pm;
if ( m_hoveringOver > -1 )
const bool userHasRated = index.data( GetNewStuffModel::UserHasRatedRole ).toBool();
if ( !userHasRated && // Show on-hover animation if the user hasn't rated it yet, and is hovering over it
m_hoveringOver > -1 &&
m_hoveringItem == index )
{
if ( i <= m_hoveringOver ) // positive star
painter->drawPixmap( r, m_onHoverStar );
@ -200,8 +203,13 @@ GetNewStuffDelegate::paint( QPainter* painter, const QStyleOptionViewItem& optio
}
else
{
if ( i <= rating ) // positive star
painter->drawPixmap( r, m_ratingStarPositive );
if ( i <= rating ) // positive or rated star
{
if ( userHasRated )
painter->drawPixmap( r, m_onHoverStar );
else
painter->drawPixmap( r, m_ratingStarPositive );
}
else
painter->drawPixmap( r, m_ratingStarNegative );
}
@ -258,7 +266,6 @@ bool
GetNewStuffDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
{
Q_UNUSED( option );
m_hoveringOver = -1;
if ( event->type() != QEvent::MouseButtonRelease &&
event->type() != QEvent::MouseMove )
@ -287,25 +294,30 @@ GetNewStuffDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, cons
if ( fullStars.contains( me->pos() ) )
{
tDebug() << "A star was pressed...which one?";
const int eachStar = starsWidth / 5;
const int clickOffset = me->pos().x() - fullStars.x();
const int whichStar = (clickOffset / eachStar) + 1;
if ( event->type() == QEvent::MouseButtonRelease )
{
tDebug() << "Clicked on:" << whichStar;
model->setData( index, whichStar, GetNewStuffModel::RatingRole );
}
else if ( event->type() == QEvent::MouseMove )
{
// 0-indexed
m_hoveringOver = whichStar;
m_hoveringItem = index;
}
return true;
}
}
if ( m_hoveringOver > -1 )
{
emit update( m_hoveringItem );
m_hoveringOver = -1;
m_hoveringItem = QPersistentModelIndex();
}
return false;
}

View File

@ -31,6 +31,9 @@ public:
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
signals:
void update( const QModelIndex& idx );
protected:
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
@ -39,6 +42,7 @@ private:
int m_widestTextWidth;
int m_hoveringOver;
QPersistentModelIndex m_hoveringItem;
mutable QHash< QPair<int, int>, QRect > m_cachedButtonRects;
mutable QHash< QPair<int, int>, QRect > m_cachedStarRects;
};

View File

@ -30,7 +30,9 @@ GetNewStuffDialog::GetNewStuffDialog( QWidget *parent, Qt::WindowFlags f )
ui->setupUi( this );
ui->listView->setModel( m_model );
ui->listView->setItemDelegate( new GetNewStuffDelegate( ui->listView ) );
GetNewStuffDelegate* del = new GetNewStuffDelegate( ui->listView );
connect( del, SIGNAL( update( QModelIndex ) ), ui->listView, SLOT( update( QModelIndex ) ) );
ui->listView->setItemDelegate( del );
ui->listView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
ui->listView->setMouseTracking( true );

View File

@ -94,6 +94,8 @@ GetNewStuffModel::data( const QModelIndex& index, int role ) const
return resolver.author();
case StateRole:
return (int)AtticaManager::instance()->resolverState( resolver );
case UserHasRatedRole:
return AtticaManager::instance()->userHasRated( resolver );
}
return QVariant();
}

View File

@ -38,7 +38,8 @@ public:
DescriptionRole = Qt::UserRole + 5,
TypeRole = Qt::UserRole + 6, // Category in attica-speak. What sort of item this is (resolver, etc).
AuthorRole = Qt::UserRole + 7,
StateRole = Qt::UserRole + 8
StateRole = Qt::UserRole + 8,
UserHasRatedRole = Qt::UserRole + 9
};
enum Types {

View File

@ -128,7 +128,7 @@ AudioControls::AudioControls( QWidget* parent )
connect( AudioEngine::instance(), SIGNAL( timerMilliSeconds( qint64 ) ), SLOT( onPlaybackTimer( qint64 ) ) );
connect( AudioEngine::instance(), SIGNAL( volumeChanged( int ) ), SLOT( onVolumeChanged( int ) ) );
m_defaultCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" )
m_defaultCover = QPixmap( RESPATH "images/no-album-no-case.png" )
.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),

View File

@ -45,7 +45,6 @@ AtticaManager::AtticaManager( QObject* parent )
// resolvers
m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org:10480/resolvers/providers.xml" ) );
QTimer::singleShot( 0, this, SLOT( loadPixmapsFromCache() ) );
}
@ -62,6 +61,8 @@ AtticaManager::loadPixmapsFromCache()
if ( !cacheDir.cd( "atticacache" ) ) // doesn't exist, no cache
return;
qDebug() << "Loading resolvers from cache dir:" << cacheDir.absolutePath();
qDebug() << "Currently we know about these resolvers:" << m_resolverStates.keys();
foreach ( const QString& file, cacheDir.entryList( QStringList() << "*.png", QDir::Files | QDir::NoSymLinks ) )
{
// load all the pixmaps
@ -204,6 +205,8 @@ AtticaManager::resolversList( BaseJob* j )
m_resolverStates = TomahawkSettings::instance()->atticaResolverStates();
// load icon cache from disk, and fetch any we are missing
loadPixmapsFromCache();
foreach ( Content resolver, m_resolvers )
{
if ( !m_resolverStates.contains( resolver.id() ) )

View File

@ -113,8 +113,11 @@ set( libSources
infosystem/infoplugins/generic/echonestplugin.cpp
infosystem/infoplugins/generic/lastfmplugin.cpp
infosystem/infoplugins/generic/chartsplugin.cpp
infosystem/infoplugins/generic/spotifyPlugin.cpp
infosystem/infoplugins/generic/hypemPlugin.cpp
infosystem/infoplugins/generic/musixmatchplugin.cpp
infosystem/infoplugins/generic/musicbrainzPlugin.cpp
infosystem/infoplugins/generic/RoviPlugin.cpp
playlist/treemodel.cpp
playlist/treeproxymodel.cpp
@ -224,11 +227,8 @@ set( libSources
widgets/infowidgets/sourceinfowidget.cpp
widgets/infowidgets/ArtistInfoWidget.cpp
widgets/infowidgets/AlbumInfoWidget.cpp
widgets/kbreadcrumbselectionmodel.cpp
widgets/breadcrumbbar.cpp
widgets/breadcrumbbuttonbase.cpp
widgets/headerbreadcrumb.cpp
widgets/siblingcrumbbutton.cpp
widgets/Breadcrumb.cpp
widgets/BreadcrumbButton.cpp
jobview/JobStatusView.cpp
jobview/JobStatusModel.cpp
@ -345,8 +345,11 @@ set( libHeaders
infosystem/infoplugins/generic/echonestplugin.h
infosystem/infoplugins/generic/lastfmplugin.h
infosystem/infoplugins/generic/chartsplugin.h
infosystem/infoplugins/generic/spotifyPlugin.h
infosystem/infoplugins/generic/hypemPlugin.h
infosystem/infoplugins/generic/musixmatchplugin.h
infosystem/infoplugins/generic/musicbrainzPlugin.h
infosystem/infoplugins/generic/RoviPlugin.h
network/bufferiodevice.h
network/msgprocessor.h
@ -451,13 +454,10 @@ set( libHeaders
widgets/SocialPlaylistWidget.h
widgets/infowidgets/sourceinfowidget.h
widgets/infowidgets/ArtistInfoWidget.h
widgets/infowidgets/ArtistInfoWidget_p.h
widgets/infowidgets/AlbumInfoWidget.h
widgets/kbreadcrumbselectionmodel.h
widgets/kbreadcrumbselectionmodel_p.h
widgets/breadcrumbbar.h
widgets/breadcrumbbuttonbase.h
widgets/headerbreadcrumb.h
widgets/siblingcrumbbutton.h
widgets/Breadcrumb.h
widgets/BreadcrumbButton.h
jobview/JobStatusView.h
jobview/JobStatusModel.h
@ -507,7 +507,6 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
${LIBECHONEST_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}/..
${CLUCENE_INCLUDE_DIR}
${CLUCENE_LIBRARY_DIR}
${PHONON_INCLUDES}
${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src

View File

@ -424,6 +424,9 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
tLog() << "Starting new song:" << m_currentTrack->url();
emit loading( m_currentTrack );
if ( QNetworkReply* qnr_io = qobject_cast< QNetworkReply* >( io.data() ) )
connect( qnr_io, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( ioStreamError( QNetworkReply::NetworkError ) ) );
if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) )
{
if ( QNetworkReply* qnr_io = qobject_cast< QNetworkReply* >( io.data() ) )
@ -573,6 +576,16 @@ AudioEngine::playItem( Tomahawk::PlaylistInterface* playlist, const Tomahawk::re
}
}
void
AudioEngine::ioStreamError( QNetworkReply::NetworkError error )
{
if ( error != QNetworkReply::NoError )
{
if ( canGoNext() )
loadNextTrack();
}
}
void
AudioEngine::playlistNextTrackReady()
@ -682,7 +695,10 @@ AudioEngine::setPlaylist( PlaylistInterface* playlist )
}
if ( !playlist )
{
m_playlist.clear();
return;
}
m_playlist = playlist->getSharedPointer();

View File

@ -21,6 +21,7 @@
#include <QObject>
#include <QTimer>
#include <QNetworkReply>
#include <phonon/MediaObject>
#include <phonon/AudioOutput>
@ -134,6 +135,7 @@ private slots:
void setCurrentTrack( const Tomahawk::result_ptr& result );
void ioStreamError( QNetworkReply::NetworkError );
private:
void setState( AudioState state );

View File

@ -276,10 +276,14 @@ ContextWidget::onAnimationFinished()
m_scene->setSceneRect( ui->contextView->viewport()->rect() );
layoutViews( false );
setQuery( m_query, true );
ui->toggleButton->setText( tr( "Hide Footnotes" ) );
}
else
{
setFixedHeight( m_minHeight );
ui->toggleButton->setText( tr( "Show Footnotes" ) );
}
}

View File

@ -35,7 +35,7 @@
</sizepolicy>
</property>
<property name="text">
<string>Footnotes</string>
<string>Show Footnotes</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>

View File

@ -50,7 +50,7 @@ DatabaseCommand_LoadSocialActions::exec( DatabaseImpl* dbi )
return;
QString whereToken;
whereToken = QString( "WHERE id IS %1" ).arg( trkid );
whereToken = QString( "WHERE id IS %1" ).arg( trkid );
QString sql = QString(
"SELECT k, v, timestamp, source "
@ -66,7 +66,7 @@ DatabaseCommand_LoadSocialActions::exec( DatabaseImpl* dbi )
Tomahawk::SocialAction action;
action.action = query.value( 0 ); // action
action.value = query.value( 1 ); // comment
action.timestamp = query.value( 2 ); // timestamp
action.timestamp = query.value( 2 ); // timestamp
action.source = query.value( 3 ); // source
allSocialActions.append( action );

View File

@ -49,22 +49,17 @@ DatabaseCommand_SocialAction::exec( DatabaseImpl* dbi )
TomahawkSqlQuery query = dbi->newquery();
QVariant srcid = source()->isLocal() ? QVariant( QVariant::Int ) : source()->id();
int trkid = -2;
if ( !m_result.isNull() && !m_artist.isNull() && !m_track.isEmpty() )
{
bool autoCreate = true;
int artid = dbi->artistId( m_artist, autoCreate );
if ( artid < 1 )
return;
if ( m_artist.isNull() || m_track.isEmpty() )
return;
autoCreate = true; // artistId overwrites autoCreate (reference)
trkid = dbi->trackId( artid, m_track, autoCreate );
if ( trkid < 1 )
return;
}
int artid = dbi->artistId( m_artist, true );
if ( artid < 1 )
return;
int trkid = dbi->trackId( artid, m_track, true );
if ( trkid < 1 )
return;
// update if it already exists
TomahawkSqlQuery find = dbi->newquery();
@ -80,12 +75,13 @@ DatabaseCommand_SocialAction::exec( DatabaseImpl* dbi )
.arg( trkid )
.arg( source()->isLocal() ? "IS NULL" : QString( "=%1" ).arg( source()->id() ) )
.arg( m_action ) );
} else
}
else
{
query.prepare( "INSERT INTO social_attributes(id, source, k, v, timestamp) "
query.prepare( "INSERT INTO social_attributes(id, source, k, v, timestamp) "
"VALUES (?, ?, ?, ?, ?)" );
query.bindValue( 0, trkid >= -1 ? trkid : QVariant() );
query.bindValue( 0, trkid );
query.bindValue( 1, srcid );
query.bindValue( 2, m_action );
query.bindValue( 3, m_comment );

View File

@ -112,7 +112,8 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
if ( url.contains( "spotify" ) && url.contains( "track" ) )
return true;
if ( url.contains( "rdio.com" ) && url.contains( "track" ) )
if ( url.contains( "rdio.com" ) && ( ( ( url.contains( "track" ) && url.contains( "artist" ) && url.contains( "album" ) )
|| url.contains( "playlists" ) ) ) )
return true;
}
@ -122,6 +123,8 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
return true;
if ( url.contains( "spotify" ) && url.contains( "album" ) )
return true;
if ( url.contains( "rdio.com" ) && ( url.contains( "artist" ) && url.contains( "album" ) && !url.contains( "track" ) ) )
return true;
}
if ( acceptedType.testFlag( Artist ) )
@ -130,6 +133,8 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
return true;
if ( url.contains( "spotify" ) && url.contains( "artist" ) )
return true;
if ( url.contains( "rdio.com" ) && ( url.contains( "artist" ) && !url.contains( "album" ) && !url.contains( "track" ) ) )
return true;
}
// We whitelist t.co and bit.ly (and j.mp) since they do some link checking. Often playable (e.g. spotify..) links hide behind them,
@ -152,6 +157,16 @@ DropJob::isDropType( DropJob::DropType desired, const QMimeData* data )
// Not the most elegant
if ( url.contains( "spotify" ) && url.contains( "playlist" ) && s_canParseSpotifyPlaylists )
return true;
if ( url.contains( "rdio.com" ) && url.contains( "people" ) && url.contains( "playlist" ) )
return true;
// we don't know about these.. gotta say yes for now
if ( url.contains( "bit.ly" ) ||
url.contains( "j.mp" ) ||
url.contains( "t.co" ) ||
url.contains( "rd.io" ) )
return true;
}
return false;
@ -443,6 +458,25 @@ DropJob::handleSpotifyUrls( const QString& urlsRaw )
m_queryCount++;
}
void
DropJob::handleRdioUrls( const QString& urlsRaw )
{
QStringList urls = urlsRaw.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
qDebug() << "Got Rdio urls!!" << urls;
if ( dropAction() == Default )
setDropAction( Create );
RdioParser* rdio = new RdioParser( this );
connect( rdio, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) );
rdio->setCreatePlaylist( dropAction() == Create );
rdio->parse( urls );
m_queryCount++;
}
void
DropJob::handleAllUrls( const QString& urls )
{
@ -452,6 +486,8 @@ DropJob::handleAllUrls( const QString& urls )
&& ( urls.contains( "playlist" ) || urls.contains( "artist" ) || urls.contains( "album" ) || urls.contains( "track" ) )
&& s_canParseSpotifyPlaylists )
handleSpotifyUrls( urls );
else if ( urls.contains( "rdio.com" ) )
handleRdioUrls( urls );
else
handleTrackUrls ( urls );
}

View File

@ -102,7 +102,9 @@ public:
void setGetWholeAlbums( bool getWholeAlbums );
void tracksFromMimeData( const QMimeData* data, bool allowDuplicates = false, bool onlyLocal = false, bool top10 = false );
void handleXspfs( const QString& files );
void handleSpotifyUrls( const QString& urls );
void handleRdioUrls( const QString& urls );
static bool canParseSpotifyPlaylists() { return s_canParseSpotifyPlaylists; }
static void setCanParseSpotifyPlaylists( bool parseable ) { s_canParseSpotifyPlaylists = parseable; }

View File

@ -50,6 +50,7 @@
#include "utils/spotifyparser.h"
#include "utils/shortenedlinkparser.h"
#include "utils/rdioparser.h"
#include "widgets/searchwidget.h"
GlobalActionManager* GlobalActionManager::s_instance = 0;
@ -269,6 +270,8 @@ GlobalActionManager::parseTomahawkLink( const QString& urlIn )
return handlePlayCommand( u );
} else if( cmdType == "open" ) {
return handleOpenCommand( u );
} else if( cmdType == "view" ) {
return handleViewCommand( u );
} else {
tLog() << "Tomahawk link not supported, command not known!" << cmdType << u.path();
return false;
@ -357,7 +360,7 @@ GlobalActionManager::handleOpenTrack ( const query_ptr& q )
ViewManager::instance()->queue()->model()->append( q );
ViewManager::instance()->showQueue();
if( !AudioEngine::instance()->isPlaying() ) {
if( !AudioEngine::instance()->isPlaying() && !AudioEngine::instance()->isPaused() ) {
connect( q.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( waitingForResolved( bool ) ) );
m_waitingToPlay = q;
}
@ -498,23 +501,71 @@ bool
GlobalActionManager::handleSearchCommand( const QUrl& url )
{
// open the super collection and set this as the search filter
QStringList query;
if( url.hasQueryItem( "artist" ) )
query << url.queryItemValue( "artist" );
if( url.hasQueryItem( "album" ) )
query << url.queryItemValue( "album" );
if( url.hasQueryItem( "title" ) )
query << url.queryItemValue( "title" );
QString queryStr = query.join( " " );
QString queryStr;
if ( url.hasQueryItem( "query" ) )
queryStr = url.queryItemValue( "query" );
else
{
QStringList query;
if( url.hasQueryItem( "artist" ) )
query << url.queryItemValue( "artist" );
if( url.hasQueryItem( "album" ) )
query << url.queryItemValue( "album" );
if( url.hasQueryItem( "title" ) )
query << url.queryItemValue( "title" );
queryStr = query.join( " " );
}
if( queryStr.isEmpty() )
if( queryStr.trimmed().isEmpty() )
return false;
ViewManager::instance()->showSuperCollection();
// ViewManager::instance()->topbar()->setFilter( queryStr );
ViewManager::instance()->show( new SearchWidget( queryStr.trimmed() ) );
return true;
}
bool
GlobalActionManager::handleViewCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
tLog() << "No specific view command:" << url.toString();
return false;
}
if ( parts[ 0 ] == "artist" )
{
const QString artist = url.queryItemValue( "name" );
if ( artist.isEmpty() )
{
tLog() << "Not artist supplied for view/artist command.";
return false;
}
artist_ptr artistPtr = Artist::get( artist );
if ( !artistPtr.isNull() )
ViewManager::instance()->show( artistPtr );
return true;
}
else if ( parts[ 0 ] == "album" )
{
const QString artist = url.queryItemValue( "artist" );
const QString album = url.queryItemValue( "name" );
if ( artist.isEmpty() || album.isEmpty() )
{
tLog() << "Not artist or album supplied for view/artist command:" << url;
return false;
}
album_ptr albumPtr = Album::get( Artist::get( artist, false ), album, false );
if ( !albumPtr.isNull() )
ViewManager::instance()->show( albumPtr );
return true;
}
return false;
}
bool
GlobalActionManager::handleAutoPlaylistCommand( const QUrl& url )

View File

@ -95,6 +95,7 @@ private:
bool handlePlayCommand(const QUrl& url );
bool handleBookmarkCommand(const QUrl& url );
bool handleOpenCommand(const QUrl& url );
bool handleViewCommand(const QUrl& url );
bool doQueueAdd( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems );
bool playSpotify( const QUrl& url );

View File

@ -27,6 +27,7 @@
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include <QCheckBox>
#include <widgets/querylabel.h>
#define ANIMATION_TIME 400
#define IMAGE_HEIGHT 64
@ -37,6 +38,7 @@ using namespace Tomahawk;
InfoBar::InfoBar( QWidget* parent )
: QWidget( parent )
, ui( new Ui::InfoBar )
, m_queryLabel( 0 )
{
ui->setupUi( this );
TomahawkUtils::unmarginLayout( layout() );
@ -71,6 +73,14 @@ InfoBar::InfoBar( QWidget* parent )
ui->longDescriptionLabel->setText( QString() );
ui->imageLabel->setText( QString() );
m_queryLabel = new QueryLabel( this );
m_queryLabel->setType( QueryLabel::Artist );
m_queryLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
m_queryLabel->setTextPen( palette().brightText().color() );
m_queryLabel->setFont( boldFont );
m_queryLabel->hide();
connect( m_queryLabel, SIGNAL( clickedArtist() ), this, SLOT( artistClicked() ) );
m_autoUpdate = new QCheckBox( this );
m_autoUpdate->setText( tr( "Automatically update" ) );
m_autoUpdate->setLayoutDirection( Qt::RightToLeft );
@ -95,6 +105,8 @@ InfoBar::InfoBar( QWidget* parent )
setPalette( p );
setAutoFillBackground( true );
setMinimumHeight( geometry().height() );
setMaximumHeight( geometry().height() );
connect( ViewManager::instance(), SIGNAL( filterAvailable( bool ) ), SLOT( setFilterAvailable( bool ) ) );
connect( ViewManager::instance(), SIGNAL( autoUpdateAvailable( bool ) ), SLOT( setAutoUpdateAvailable( bool ) ) );
}
@ -116,9 +128,49 @@ InfoBar::setCaption( const QString& s )
void
InfoBar::setDescription( const QString& s )
{
if ( m_queryLabel->isVisible() )
{
ui->verticalLayout->removeWidget( m_queryLabel );
m_queryLabel->hide();
ui->verticalLayout->addWidget( ui->descriptionLabel );
ui->verticalLayout->setContentsMargins( 0, 0, 0, 0 );
ui->descriptionLabel->show();
}
ui->descriptionLabel->setText( s );
}
void
InfoBar::setDescription( const artist_ptr& artist )
{
m_queryLabel->setQuery( Query::get( artist->name(), QString(), QString() ) );
m_queryLabel->setExtraContentsMargins( 4, 0, 0, 0 );
if ( !m_queryLabel->isVisible() )
{
ui->verticalLayout->removeWidget( ui->descriptionLabel );
ui->descriptionLabel->hide();
m_queryLabel->show();
ui->verticalLayout->addWidget( m_queryLabel );
ui->verticalLayout->setContentsMargins( 0, 0, 0, 15 );
}
}
void
InfoBar::setDescription( const album_ptr& )
{
// TODO
}
void
InfoBar::artistClicked()
{
if ( m_queryLabel && !m_queryLabel->query().isNull() )
ViewManager::instance()->show( Artist::get( m_queryLabel->artist() ) );
}
void
InfoBar::setLongDescription( const QString& s )

View File

@ -22,7 +22,9 @@
#include <QWidget>
#include "dllmacro.h"
#include "artist.h"
class QueryLabel;
class QCheckBox;
class QTimeLine;
class QSearchField;
@ -43,7 +45,12 @@ public:
public slots:
void setCaption( const QString& s );
void setDescription( const QString& s );
// If you want a querylabel instead of an ElidedLabel
void setDescription( const Tomahawk::artist_ptr& artist );
void setDescription( const Tomahawk::album_ptr& album_ptr );
void setLongDescription( const QString& s );
void setPixmap( const QPixmap& p );
@ -60,12 +67,14 @@ protected:
private slots:
void onFilterEdited();
void artistClicked();
private:
Ui::InfoBar* ui;
QSearchField* m_searchWidget;
QCheckBox* m_autoUpdate;
QueryLabel* m_queryLabel;
};
#endif // INFOBAR_H

View File

@ -65,10 +65,13 @@
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="ElidedLabel" name="captionLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>

View File

@ -0,0 +1,207 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "RoviPlugin.h"
#include "utils/logger.h"
#include <QDateTime>
#include <QNetworkReply>
#include <parser.h>
using namespace Tomahawk::InfoSystem;
static QString
md5( const QByteArray& src )
{
QByteArray const digest = QCryptographicHash::hash( src, QCryptographicHash::Md5 );
return QString::fromLatin1( digest.toHex() ).rightJustified( 32, '0' );
}
RoviPlugin::RoviPlugin()
: InfoPlugin()
{
m_supportedGetTypes << InfoAlbumSongs;
/*
* Your API Key is 7jxr9zggt45h6rg2n4ss3mrj
* Your secret is XUnYutaAW6
*/
m_apiKey = "7jxr9zggt45h6rg2n4ss3mrj";
m_secret = "XUnYutaAW6";
}
RoviPlugin::~RoviPlugin()
{
}
void
RoviPlugin::namChangedSlot( QNetworkAccessManager* nam )
{
if ( !nam )
return;
m_nam = nam;
}
void
RoviPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
emit info( requestData, QVariant() );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
if ( !hash.contains( "artist" ) || !hash.contains( "album" ) )
{
emit info( requestData, QVariant() );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = hash["artist"];
criteria["album"] = hash["album"];
emit getCachedInfo( criteria, 0, requestData );
}
void
RoviPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
switch ( requestData.type )
{
case InfoAlbumSongs:
{
QUrl baseUrl = QUrl( "http://api.rovicorp.com/search/v2/music/search" );
baseUrl.addQueryItem( "query", QString( "%1 %2" ).arg( criteria[ "artist" ] ).arg( criteria[ "album" ] ) );
baseUrl.addQueryItem( "entitytype", "album" );
baseUrl.addQueryItem( "include", "album:tracks" );
QNetworkReply* reply = makeRequest( baseUrl );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), this, SLOT( albumLookupFinished() ) );
connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( albumLookupError( QNetworkReply::NetworkError ) ) );
break;
}
default:
{
Q_ASSERT( false );
break;
}
}
}
void
RoviPlugin::albumLookupError( QNetworkReply::NetworkError error )
{
if ( error == QNetworkReply::NoError )
return;
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
Q_ASSERT( reply );
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( requestData, QVariant() );
}
void
RoviPlugin::albumLookupFinished()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
Q_ASSERT( reply );
if ( reply->error() != QNetworkReply::NoError )
return;
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
QJson::Parser p;
bool ok;
QVariantMap response = p.parse( reply, &ok ).toMap();
if ( !ok || response.isEmpty() || !response.contains( "searchResponse" ) )
{
tLog() << "Error parsing JSON from Rovi!" << p.errorString() << response;
emit info( requestData, QVariant() );
return;
}
QVariantList resultList = response[ "searchResponse" ].toMap().value( "results" ).toList();
if ( resultList.size() == 0 )
{
emit info( requestData, QVariant() );
return;
}
QVariantMap results = resultList.first().toMap();
QVariantList tracks = results[ "album" ].toMap()[ "tracks" ].toList();
if ( tracks.isEmpty() )
{
tLog() << "Error parsing JSON from Rovi!" << p.errorString() << response;
emit info( requestData, QVariant() );
}
QStringList trackNameList;
foreach ( const QVariant& track, tracks )
{
const QVariantMap trackData = track.toMap();
if ( trackData.contains( "title" ) )
trackNameList << trackData[ "title" ].toString();
}
QVariantMap returnedData;
returnedData["tracks"] = trackNameList;
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>()["artist"];
criteria["album"] = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>()["album"];
emit updateCache( criteria, 0, requestData.type, returnedData );
}
QNetworkReply*
RoviPlugin::makeRequest( QUrl url )
{
url.addQueryItem( "apikey", m_apiKey );
url.addEncodedQueryItem( "sig", generateSig() );
qDebug() << "Rovi request url:" << url.toString();
return m_nam->get( QNetworkRequest( url ) );
}
QByteArray
RoviPlugin::generateSig() const
{
QByteArray raw = m_apiKey + m_secret + QString::number( QDateTime::currentMSecsSinceEpoch() / 1000 ).toLatin1();
return md5( raw ).toLatin1();
}

View File

@ -0,0 +1,67 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ROVIPLUGIN_H
#define ROVIPLUGIN_H
#include "infosystem/infosystem.h"
#include <QNetworkReply>
class QNetworkAccessManager;
namespace Tomahawk
{
namespace InfoSystem
{
class RoviPlugin : public InfoPlugin
{
Q_OBJECT
public:
RoviPlugin();
virtual ~RoviPlugin();
protected:
virtual void namChangedSlot( QNetworkAccessManager* nam );
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( QString, Tomahawk::InfoSystem::InfoType, QVariant )
{}
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
private slots:
void albumLookupFinished();
void albumLookupError( QNetworkReply::NetworkError );
private:
QNetworkReply* makeRequest( QUrl url );
QByteArray generateSig() const;
QNetworkAccessManager* m_nam;
QByteArray m_apiKey;
QByteArray m_secret;
};
}
}
#endif // ROVIPLUGIN_H

View File

@ -49,7 +49,7 @@ ChartsPlugin::ChartsPlugin()
/// Add resources here
m_chartResources << "billboard" << "itunes";
m_chartResources << "billboard" << "itunes" << "rdio" << "wearehunted";
m_supportedGetTypes << InfoChart << InfoChartCapabilities;
}
@ -73,9 +73,10 @@ ChartsPlugin::namChangedSlot( QNetworkAccessManager *nam )
m_nam = QWeakPointer< QNetworkAccessManager >( nam );
/// Then get each chart from resource
/// We need to fetch them before they are asked for
/// We want to prepopulate the breadcrumb to fetch them before they are asked for
if( !m_chartResources.isEmpty() && m_nam ){
if ( !m_chartResources.isEmpty() && m_nam && m_allChartsMap.isEmpty() )
{
tDebug() << "ChartsPlugin: InfoChart fetching possible resources";
foreach ( QVariant resource, m_chartResources )
@ -93,21 +94,21 @@ ChartsPlugin::namChangedSlot( QNetworkAccessManager *nam )
void
ChartsPlugin::dataError( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
ChartsPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
void
ChartsPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
ChartsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
qDebug() << Q_FUNC_INFO << requestData.caller;
qDebug() << Q_FUNC_INFO << requestData.customData;
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
bool foundSource;
bool foundSource = false;
switch ( requestData.type )
{
@ -116,7 +117,7 @@ ChartsPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData req
/// We need something to check if the request is actually ment to go to this plugin
if ( !hash.contains( "chart_source" ) )
{
dataError( requestId, requestData );
dataError( requestData );
break;
}
else
@ -131,19 +132,19 @@ ChartsPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData req
if( !foundSource )
{
dataError( requestId, requestData );
dataError( requestData );
break;
}
}
fetchChart( requestId, requestData );
fetchChart( requestData );
break;
case InfoChartCapabilities:
fetchChartCapabilities( requestId, requestData );
fetchChartCapabilities( requestData );
break;
default:
dataError( requestId, requestData );
dataError( requestData );
}
}
@ -158,12 +159,12 @@ ChartsPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoTy
void
ChartsPlugin::fetchChart( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
@ -173,7 +174,7 @@ ChartsPlugin::fetchChart( uint requestId, Tomahawk::InfoSystem::InfoRequestData
/// Each request needs to contain both a id and source
if ( !hash.contains( "chart_id" ) && !hash.contains( "chart_source" ) )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
@ -181,29 +182,30 @@ ChartsPlugin::fetchChart( uint requestId, Tomahawk::InfoSystem::InfoRequestData
criteria["chart_id"] = hash["chart_id"];
criteria["chart_source"] = hash["chart_source"];
emit getCachedInfo( requestId, criteria, 0, requestData );
emit getCachedInfo( criteria, 0, requestData );
}
void
ChartsPlugin::fetchChartCapabilities( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
ChartsPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
emit getCachedInfo( requestId, criteria, 0, requestData );
emit getCachedInfo( criteria, 0, requestData );
}
void
ChartsPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
ChartsPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !m_nam.data() )
{
tLog() << "Have a null QNAM, uh oh";
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
@ -217,7 +219,6 @@ ChartsPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
qDebug() << Q_FUNC_INFO << "Getting chart url" << url;
QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) );
@ -230,22 +231,18 @@ ChartsPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
if ( m_chartsFetchJobs > 0 )
{
qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!";
m_cachedRequests.append( QPair< uint, InfoRequestData >( requestId, requestData ) );
m_cachedRequests.append( requestData );
return;
}
emit info(
requestId,
requestData,
m_allChartsMap
);
emit info( requestData, m_allChartsMap );
return;
}
default:
{
tLog() << Q_FUNC_INFO << "Couldn't figure out what to do with this type of request after cache miss";
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
}
@ -279,96 +276,152 @@ ChartsPlugin::chartTypes()
// We'll populate charts with the data from the server
QVariantMap charts;
QString chartName;
if ( source == "itunes" )
QStringList defaultChain;
if ( source == "wearehunted" || source == "itunes" )
{
// Some charts can have an extra param, itunes has geo, WAH has emerging/mainstream
// Itunes has geographic-area based charts. So we build a breadcrumb of
// ITunes - Country - Albums - Top Chart Type
// - Tracks - Top Chart Type
QHash< QString, QVariantMap > countries;
// WeAreHunted has Mainstream/Emerging
// WeAreHunted - Type - Artists - Chart Type
// - Tracks - Chart Type
QHash< QString, QVariantMap > extraType;
foreach( const QVariant& chartObj, chartObjs.values() )
{
const QVariantMap chart = chartObj.toMap();
const QString id = chart.value( "id" ).toString();
const QString geo = chart.value( "geo" ).toString();
QString name = chart.value( "name" ).toString();
const QString type = chart.value( "type" ).toString();
if( !chartObj.toMap().isEmpty() ){
const QVariantMap chart = chartObj.toMap();
const QString id = chart.value( "id" ).toString();
const QString geo = chart.value( "geo" ).toString();
QString name = chart.value( "genre" ).toString();
const QString type = chart.value( "type" ).toString();
const bool isDefault = ( chart.contains( "default" ) && chart[ "default" ].toInt() == 1 );
QString country;
if ( !m_cachedCountries.contains( geo ) )
{
QLocale l( QString( "en_%1" ).arg( geo ) );
country = Tomahawk::CountryUtils::fullCountryFromCode( geo );
QString extra;
if( !geo.isEmpty() ){
for ( int i = 1; i < country.size(); i++ )
{
if ( country.at( i ).isUpper() )
if ( !m_cachedCountries.contains( geo ) )
{
country.insert( i, " " );
i++;
QLocale l( QString( "en_%1" ).arg( geo ) );
extra = Tomahawk::CountryUtils::fullCountryFromCode( geo );
for ( int i = 1; i < extra.size(); i++ )
{
if ( extra.at( i ).isUpper() )
{
extra.insert( i, " " );
i++;
}
}
m_cachedCountries[ geo ] = extra;
}
else
{
extra = m_cachedCountries[ geo ];
}
}else extra = chart.value( "extra" ).toString();
if ( name.isEmpty() ) // not a specific chart, an all chart
name = tr( "Top Overall" );
InfoStringHash c;
c[ "id" ] = id;
c[ "label" ] = name;
c[ "type" ] = "album";
if ( isDefault )
c[ "default" ] = "true";
QList<InfoStringHash> extraTypeData = extraType[ extra ][ type ].value< QList< InfoStringHash > >();
extraTypeData.append( c );
extraType[ extra ].insert( type, QVariant::fromValue< QList< InfoStringHash > >( extraTypeData ) );
if ( isDefault )
{
defaultChain.clear();
defaultChain.append( extra );
defaultChain.append( type );
defaultChain.append( name );
}
m_cachedCountries[ geo ] = country;
}
else
foreach( const QString& c, extraType.keys() )
{
country = m_cachedCountries[ geo ];
charts[ c ] = extraType[ c ];
// qDebug() << "extraType has types:" << c;
}
if( source == "itunes" ){
chartName = "iTunes";
}
if( source == "wearehunted" ){
chartName = "WeAreHunted";
}
if ( name.startsWith( "iTunes Store:" ) ) // truncate
name = name.mid( 13 );
InfoStringHash c;
c[ "id" ] = id;
c[ "label" ] = name;
c[ "type" ] = "album";
QList<InfoStringHash> countryTypeData = countries[ country ][ type ].value< QList< InfoStringHash > >();
countryTypeData.append( c );
countries[ country ].insert( type, QVariant::fromValue< QList< InfoStringHash > >( countryTypeData ) );
}
foreach( const QString& c, countries.keys() )
{
charts[ c ] = countries[ c ];
// qDebug() << "Country has types:" << countries[ c ];
}
chartName = "iTunes";
} else
}else
{
// We'll just build:
// [Source] - Album - Chart Type
// [Source] - Track - Chart Type
QList< InfoStringHash > albumCharts;
QList< InfoStringHash > trackCharts;
QList< InfoStringHash > artistCharts;
foreach( const QVariant& chartObj, chartObjs.values() )
{
const QVariantMap chart = chartObj.toMap();
const QString type = chart.value( "type" ).toString();
InfoStringHash c;
c[ "id" ] = chart.value( "id" ).toString();
c[ "label" ] = chart.value( "name" ).toString();
if ( type == "Album" )
{
c[ "type" ] = "album";
albumCharts.append( c );
}
else if ( type == "Track" )
{
c[ "type" ] = "tracks";
trackCharts.append( c );
}
}
charts.insert( tr( "Albums" ), QVariant::fromValue< QList< InfoStringHash > >( albumCharts ) );
charts.insert( tr( "Tracks" ), QVariant::fromValue< QList< InfoStringHash > >( trackCharts ) );
if( !chartObj.toMap().isEmpty() ){
const QVariantMap chart = chartObj.toMap();
const QString type = chart.value( "type" ).toString();
const bool isDefault = ( chart.contains( "default" ) && chart[ "default" ].toInt() == 1 );
/// @note For displaying purposes, upper the first letter
/// @note Remeber to lower it when fetching this!
chartName = source;
chartName[0] = chartName[0].toUpper();
InfoStringHash c;
c[ "id" ] = chart.value( "id" ).toString();
c[ "label" ] = chart.value( "name" ).toString();
if ( isDefault )
c[ "default" ] = "true";
if ( type == "Album" )
{
c[ "type" ] = "album";
albumCharts.append( c );
}
else if ( type == "Track" )
{
c[ "type" ] = "tracks";
trackCharts.append( c );
}else if ( type == "Artist" )
{
c[ "type" ] = "artists";
artistCharts.append( c );
}
if ( isDefault )
{
defaultChain.clear();
defaultChain.append( type + "s" ); //UGLY but it's plural to the user, see below
defaultChain.append( c[ "label" ] );
}
}
if( !artistCharts.isEmpty() )
charts.insert( tr( "Artists" ), QVariant::fromValue< QList< InfoStringHash > >( artistCharts ) );
if( !albumCharts.isEmpty() )
charts.insert( tr( "Albums" ), QVariant::fromValue< QList< InfoStringHash > >( albumCharts ) );
if( !trackCharts.isEmpty() )
charts.insert( tr( "Tracks" ), QVariant::fromValue< QList< InfoStringHash > >( trackCharts ) );
/// @note For displaying purposes, upper the first letter
/// @note Remeber to lower it when fetching this!
chartName = source;
chartName[0] = chartName[0].toUpper();
}
}
/// Add the possible charts and its types to breadcrumb
// qDebug() << "ADDING CHART TYPE TO CHARTS:" << chartName;
QVariantMap defaultMap = m_allChartsMap.value( "defaults" ).value< QVariantMap >();
defaultMap[ source ] = defaultChain;
m_allChartsMap[ "defaults" ] = defaultMap;
m_allChartsMap[ "defaultSource" ] = "itunes";
m_allChartsMap.insert( chartName , QVariant::fromValue< QVariantMap >( charts ) );
}
@ -380,10 +433,9 @@ ChartsPlugin::chartTypes()
m_chartsFetchJobs--;
if ( !m_cachedRequests.isEmpty() && m_chartsFetchJobs == 0 )
{
QPair< uint, InfoRequestData > request;
foreach ( request, m_cachedRequests )
foreach ( InfoRequestData request, m_cachedRequests )
{
emit info( request.first, request.second, m_allChartsMap );
emit info( request, m_allChartsMap );
}
m_cachedRequests.clear();
}
@ -414,6 +466,7 @@ ChartsPlugin::chartReturned()
QVariantList chartResponse = res.value( "list" ).toList();
QList< InfoStringHash > top_tracks;
QList< InfoStringHash > top_albums;
QStringList top_artists;
/// Deside what type, we need to handle it differently
/// @todo: We allready know the type, append it to breadcrumb hash
@ -422,6 +475,8 @@ ChartsPlugin::chartReturned()
setChartType( Album );
else if( res.value( "type" ).toString() == "Track" )
setChartType( Track );
else if( res.value( "type" ).toString() == "Artist" )
setChartType( Artist );
else
setChartType( None );
@ -477,10 +532,29 @@ ChartsPlugin::chartReturned()
top_tracks << pair;
}
}else if( chartType() == Artist )
{
if ( artist.isEmpty() ) // don't have enough...
{
tLog() << "Didn't get an artist from charts, not enough to build a query on. Aborting" << artist;
}
else
{
top_artists << artist;
}
}
}
}
if( chartType() == Artist )
{
tDebug() << "ChartsPlugin:" << "\tgot " << top_artists.size() << " artists";
returnedData["artists"] = QVariant::fromValue( top_artists );
returnedData["type"] = "artists";
}
if( chartType() == Track )
{
tDebug() << "ChartsPlugin:" << "\tgot " << top_tracks.size() << " tracks";
@ -498,11 +572,7 @@ ChartsPlugin::chartReturned()
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info(
reply->property( "requestId" ).toUInt(),
requestData,
returnedData
);
emit info( requestData, returnedData );
// TODO update cache
}
else

View File

@ -56,15 +56,15 @@ public slots:
void namChangedSlot( QNetworkAccessManager *nam );
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data );
private:
void fetchChart( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChartCapabilities( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void dataError( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData );
void dataError( Tomahawk::InfoSystem::InfoRequestData requestData );
QVariantList m_chartResources;
QList<InfoStringHash> m_charts;
@ -73,7 +73,7 @@ private:
QVariantMap m_allChartsMap;
uint m_chartsFetchJobs;
QList< QPair< uint, InfoRequestData > > m_cachedRequests;
QList< InfoRequestData > m_cachedRequests;
QHash< QString, QString > m_cachedCountries;

View File

@ -68,37 +68,37 @@ EchoNestPlugin::namChangedSlot( QNetworkAccessManager *nam )
}
void
EchoNestPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
EchoNestPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
switch ( requestData.type )
{
case Tomahawk::InfoSystem::InfoArtistBiography:
return getArtistBiography( requestId, requestData );
return getArtistBiography( requestData );
case Tomahawk::InfoSystem::InfoArtistFamiliarity:
return getArtistFamiliarity( requestId, requestData );
return getArtistFamiliarity( requestData );
case Tomahawk::InfoSystem::InfoArtistHotttness:
return getArtistHotttnesss( requestId, requestData );
return getArtistHotttnesss( requestData );
case Tomahawk::InfoSystem::InfoArtistTerms:
return getArtistTerms( requestId, requestData );
return getArtistTerms( requestData );
case Tomahawk::InfoSystem::InfoTrackEnergy:
return getSongProfile( requestId, requestData, "energy" );
return getSongProfile( requestData, "energy" );
case Tomahawk::InfoSystem::InfoMiscTopTerms:
return getMiscTopTerms( requestId, requestData );
return getMiscTopTerms( requestData );
default:
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
}
}
void
EchoNestPlugin::getSongProfile( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData, const QString &item )
EchoNestPlugin::getSongProfile( const Tomahawk::InfoSystem::InfoRequestData &requestData, const QString &item )
{
//WARNING: Totally not implemented yet
Q_UNUSED( item );
if( !isValidTrackData( requestId, requestData ) )
if( !isValidTrackData( requestData ) )
return;
// Track track( input.toString() );
@ -110,67 +110,62 @@ EchoNestPlugin::getSongProfile( uint requestId, const Tomahawk::InfoSystem::Info
}
void
EchoNestPlugin::getArtistBiography( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData )
EchoNestPlugin::getArtistBiography( const Tomahawk::InfoSystem::InfoRequestData &requestData )
{
if( !isValidArtistData( requestId, requestData ) )
if( !isValidArtistData( requestData ) )
return;
Echonest::Artist artist( requestData.input.toString() );
QNetworkReply *reply = artist.fetchBiographies();
reply->setProperty( "artist", QVariant::fromValue< Echonest::Artist >( artist ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( getArtistBiographySlot() ) );
}
void
EchoNestPlugin::getArtistFamiliarity( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData )
EchoNestPlugin::getArtistFamiliarity( const Tomahawk::InfoSystem::InfoRequestData &requestData )
{
if( !isValidArtistData( requestId, requestData ) )
if( !isValidArtistData( requestData ) )
return;
qDebug() << "Fetching artist familiarity!" << requestData.input;
Echonest::Artist artist( requestData.input.toString() );
QNetworkReply* reply = artist.fetchFamiliarity();
reply->setProperty( "artist", QVariant::fromValue< Echonest::Artist >( artist ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( getArtistFamiliaritySlot() ) );
}
void
EchoNestPlugin::getArtistHotttnesss( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData )
EchoNestPlugin::getArtistHotttnesss( const Tomahawk::InfoSystem::InfoRequestData &requestData )
{
if( !isValidArtistData( requestId, requestData ) )
if( !isValidArtistData( requestData ) )
return;
Echonest::Artist artist( requestData.input.toString() );
QNetworkReply* reply = artist.fetchHotttnesss();
reply->setProperty( "artist", QVariant::fromValue< Echonest::Artist >( artist ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( getArtistHotttnesssSlot() ) );
}
void
EchoNestPlugin::getArtistTerms( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData )
EchoNestPlugin::getArtistTerms( const Tomahawk::InfoSystem::InfoRequestData &requestData )
{
if( !isValidArtistData( requestId, requestData ) )
if( !isValidArtistData( requestData ) )
return;
Echonest::Artist artist( requestData.input.toString() );
QNetworkReply* reply = artist.fetchTerms( Echonest::Artist::Weight );
reply->setProperty( "artist", QVariant::fromValue< Echonest::Artist >( artist ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( getArtistTermsSlot() ) );
}
void
EchoNestPlugin::getMiscTopTerms( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData )
EchoNestPlugin::getMiscTopTerms( const Tomahawk::InfoSystem::InfoRequestData &requestData )
{
QNetworkReply* reply = Echonest::Artist::topTerms( 20 );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( getMiscTopSlot() ) );
}
@ -195,9 +190,7 @@ EchoNestPlugin::getArtistBiographySlot()
biographyMap[ biography.site() ] = siteData;
}
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( reply->property( "requestId" ).toUInt(),
requestData,
biographyMap );
emit info( requestData, biographyMap );
reply->deleteLater();
}
@ -208,9 +201,7 @@ EchoNestPlugin::getArtistFamiliaritySlot()
Echonest::Artist artist = artistFromReply( reply );
qreal familiarity = artist.familiarity();
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( reply->property( "requestId" ).toUInt(),
requestData,
familiarity );
emit info( requestData, familiarity );
reply->deleteLater();
}
@ -221,9 +212,7 @@ EchoNestPlugin::getArtistHotttnesssSlot()
Echonest::Artist artist = artistFromReply( reply );
qreal hotttnesss = artist.hotttnesss();
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( reply->property( "requestId" ).toUInt(),
requestData,
hotttnesss );
emit info( requestData, hotttnesss );
reply->deleteLater();
}
@ -241,9 +230,7 @@ EchoNestPlugin::getArtistTermsSlot()
termsMap[ term.name() ] = termHash;
}
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( reply->property( "requestId" ).toUInt(),
requestData,
termsMap );
emit info( requestData, termsMap );
reply->deleteLater();
}
@ -260,46 +247,44 @@ EchoNestPlugin::getMiscTopSlot()
termsMap[ term.name() ] = termHash;
}
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( reply->property( "requestId" ).toUInt(),
requestData,
termsMap );
emit info( requestData, termsMap );
reply->deleteLater();
}
bool
EchoNestPlugin::isValidArtistData( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData )
EchoNestPlugin::isValidArtistData( const Tomahawk::InfoSystem::InfoRequestData &requestData )
{
if ( requestData.input.isNull() || !requestData.input.isValid() || !requestData.input.canConvert< QString >() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return false;
}
QString artistName = requestData.input.toString();
if ( artistName.isEmpty() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return false;
}
return true;
}
bool
EchoNestPlugin::isValidTrackData( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData )
EchoNestPlugin::isValidTrackData( const Tomahawk::InfoSystem::InfoRequestData &requestData )
{
if ( requestData.input.isNull() || !requestData.input.isValid() || !requestData.input.canConvert< QString >() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return false;
}
QString trackName = requestData.input.toString();
if ( trackName.isEmpty() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return false;
}
if ( !requestData.customData.contains( "artistName" ) || requestData.customData[ "artistName" ].toString().isEmpty() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return false;
}
return true;

View File

@ -46,7 +46,7 @@ public:
virtual ~EchoNestPlugin();
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data )
{
@ -55,9 +55,8 @@ protected slots:
Q_UNUSED( data );
}
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( criteria );
Q_UNUSED( requestData );
}
@ -66,15 +65,15 @@ public slots:
void namChangedSlot( QNetworkAccessManager *nam );
private:
void getSongProfile( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData, const QString &item = QString() );
void getArtistBiography( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getArtistFamiliarity( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getArtistHotttnesss( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getArtistTerms( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getMiscTopTerms( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getSongProfile( const Tomahawk::InfoSystem::InfoRequestData &requestData, const QString &item = QString() );
void getArtistBiography( const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getArtistFamiliarity( const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getArtistHotttnesss( const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getArtistTerms( const Tomahawk::InfoSystem::InfoRequestData &requestData );
void getMiscTopTerms( const Tomahawk::InfoSystem::InfoRequestData &requestData );
bool isValidArtistData( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData );
bool isValidTrackData( uint requestId, const Tomahawk::InfoSystem::InfoRequestData &requestData );
bool isValidArtistData( const Tomahawk::InfoSystem::InfoRequestData &requestData );
bool isValidTrackData( const Tomahawk::InfoSystem::InfoRequestData &requestData );
Echonest::Artist artistFromReply( QNetworkReply* );
private slots:

View File

@ -0,0 +1,420 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Hugo Lindström <hugolm84@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hypemPlugin.h"
#include <QDir>
#include <QSettings>
#include <QCryptographicHash>
#include <QNetworkConfiguration>
#include <QNetworkReply>
#include <QDomElement>
#include "album.h"
#include "typedefs.h"
#include "audio/audioengine.h"
#include "tomahawksettings.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#define HYPEM_URL "http://hypem.com/playlist/"
#define HYPEM_END_URL "json/1/data.js"
#include <qjson/parser.h>
#include <qjson/serializer.h>
using namespace Tomahawk::InfoSystem;
hypemPlugin::hypemPlugin()
: InfoPlugin()
, m_chartsFetchJobs( 0 )
{
m_supportedGetTypes << InfoChart << InfoChartCapabilities;
m_types << "Artists" << "Tracks" << "Recent by Tag";
m_trackTypes << "Last 3 Days"
<< "Last Week"
<< "No Remixes"
<< "On Twitter";
m_byTagTypes << "Dance"
<< "Experimental"
<< "Electronic"
<< "Funk"
<< "Hip-hop"
<< "Indie"
<< "Instrumental"
<< "Post-punk"
<< "Rock"
<< "Singer-songwriter"
<< "Alternative"
<< "Pop"
<< "Female"
<< "Vocalist"
<< "Folk"
<< "Electro"
<< "Lo-fi"
<< "Psychedelic"
<< "Rap"
<< "British"
<< "Ambient"
<< "Dubstep"
<< "House"
<< "Chillwave"
<< "Dreampop"
<< "Shoegaze"
<< "Chillout"
<< "Soul"
<< "French"
<< "Acoustic"
<< "Canadian"
<< "60s"
<< "80s"
<< "Techno"
<< "Punk"
<< "New wave";
chartTypes();
}
hypemPlugin::~hypemPlugin()
{
qDebug() << Q_FUNC_INFO;
}
void
hypemPlugin::namChangedSlot( QNetworkAccessManager *nam )
{
tDebug() << "hypemPlugin: namChangedSLot";
qDebug() << Q_FUNC_INFO;
if( !nam )
return;
m_nam = QWeakPointer< QNetworkAccessManager >( nam );
}
void
hypemPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData )
{
emit info( requestData, QVariant() );
return;
}
void
hypemPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
qDebug() << Q_FUNC_INFO << requestData.caller;
qDebug() << Q_FUNC_INFO << requestData.customData;
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
switch ( requestData.type )
{
case InfoChart:
if ( !hash.contains( "chart_source" ) || hash["chart_source"].toLower() != "hype machine" )
{
dataError( requestData );
break;
}
qDebug() << Q_FUNC_INFO << "InfoCHart req for" << hash["chart_source"];
fetchChart( requestData );
break;
case InfoChartCapabilities:
fetchChartCapabilities( requestData );
break;
default:
dataError( requestData );
}
}
void
hypemPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
{
Q_UNUSED( caller )
Q_UNUSED( type)
Q_UNUSED( input )
}
void
hypemPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
Tomahawk::InfoSystem::InfoStringHash criteria;
/// Each request needs to contain both a id and source
if ( !hash.contains( "chart_id" ) && !hash.contains( "chart_source" ) )
{
dataError( requestData );
return;
}
/// Set the criterias for current chart
criteria["chart_id"] = hash["chart_id"];
criteria["chart_source"] = hash["chart_source"];
emit getCachedInfo( criteria, 0, requestData );
}
void
hypemPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestData );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
emit getCachedInfo( criteria, 0, requestData );
}
void
hypemPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !m_nam.data() )
{
tLog() << "Have a null QNAM, uh oh";
emit info( requestData, QVariant() );
return;
}
switch ( requestData.type )
{
case InfoChart:
{
/// Fetch the chart, we need source and id
QUrl url = QUrl( QString( HYPEM_URL "%1/%2" ).arg( criteria["chart_id"].toLower() ).arg(HYPEM_END_URL) );
qDebug() << Q_FUNC_INFO << "Getting chart url" << url;
QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) );
return;
}
case InfoChartCapabilities:
{
if ( m_chartsFetchJobs > 0 )
{
qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!";
m_cachedRequests.append( requestData );
return;
}
emit info( requestData, m_allChartsMap );
return;
}
default:
{
tLog() << Q_FUNC_INFO << "Couldn't figure out what to do with this type of request after cache miss";
emit info( requestData, QVariant() );
return;
}
}
}
void
hypemPlugin::chartTypes()
{
/// Get possible chart type for specifichypemPlugin: InfoChart types returned chart source
tDebug() << Q_FUNC_INFO << "Got hypem types";
QVariantMap charts;
foreach(QVariant types, m_types )
{
QList< InfoStringHash > chart_types;
QList< InfoStringHash > pop_charts;
InfoStringHash c;
if(types.toString() != "Artists")
{
if(types.toString() == "Tracks")
{
foreach(QVariant trackType, m_trackTypes)
{
QString typeId;
if(trackType.toString() == "Last 3 Days")
typeId = "popular/3day";
if(trackType.toString() == "Last Week")
typeId = "popular/lastweek";
if(trackType.toString() == "No Remixes")
typeId = "popular/noremix";
if(trackType.toString() == "On Twitter")
typeId = "popular/twitter";
c[ "id" ] = typeId;
c[ "label" ] = trackType.toString();
c[ "type" ] = "tracks";
pop_charts.append( c );
}
chart_types.append( pop_charts );
}
else if(types.toString() == "Recent by Tag")
{
foreach(QVariant tagTypes, m_byTagTypes)
{
c[ "id" ] = "tags/" + tagTypes.toString().toLower();
c[ "label" ] = tagTypes.toString();
c[ "type" ] = tagTypes.toString();
chart_types.append( c );
}
}
}else
{
InfoStringHash c;
c[ "id" ] = "popular/artists";
c[ "label" ] = "Most Recent";
c[ "type" ] = "artists";
chart_types.append( c );
}
charts.insert( types.toString(), QVariant::fromValue<QList< InfoStringHash > >( chart_types ) );
}
m_allChartsMap.insert( "Hype Machine", QVariant::fromValue<QVariantMap>( charts ) );
qDebug() << "hypemPlugin:Chartstype: " << m_allChartsMap;
}
void
hypemPlugin::chartReturned()
{
/// Chart request returned something! Woho
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
QString url = reply->url().toString();
QVariantMap returnedData;
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
bool ok;
QVariantMap res = p.parse( reply, &ok ).toMap();
if ( !ok )
{
tLog() << "Failed to parse json from chart lookup:" << p.errorString() << "On line" << p.errorLine();
return;
}
/// SO we have a result, parse it!
QList< InfoStringHash > top_tracks;
QStringList top_artists;
if( url.contains( "artists" ) )
setChartType( Artist );
else
setChartType( Track );
foreach(QVariant result, res )
{
QString title, artist;
QVariantMap chartMap = result.toMap();
if ( !chartMap.isEmpty() )
{
title = chartMap.value( "title" ).toString();
artist = chartMap.value( "artist" ).toString();
if( chartType() == Track )
{
InfoStringHash pair;
pair["artist"] = artist;
pair["track"] = title;
top_tracks << pair;
qDebug() << "HypemChart type is track";
}
if( chartType() == Artist )
{
top_artists << artist;
qDebug() << "HypemChart type is artist";
}
}
}
if( chartType() == Track )
{
tDebug() << "HypemPlugin:" << "\tgot " << top_tracks.size() << " tracks";
returnedData["tracks"] = QVariant::fromValue( top_tracks );
returnedData["type"] = "tracks";
}
if( chartType() == Artist )
{
tDebug() << "HypemPlugin:" << "\tgot " << top_artists.size() << " artists";
returnedData["artists"] = top_artists;
returnedData["type"] = "artists";
}
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( requestData, returnedData );
// TODO update cache
}
else
qDebug() << "Network error in fetching chart:" << reply->url().toString();
}

View File

@ -0,0 +1,93 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Hugo Lindström <hugolm84@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef hypemPlugin_H
#define hypemPlugin_H
#include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
#include <QNetworkReply>
#include <QObject>
class QNetworkReply;
namespace Tomahawk
{
namespace InfoSystem
{
class hypemPlugin : public InfoPlugin
{
Q_OBJECT
public:
hypemPlugin();
virtual ~hypemPlugin();
enum ChartType {
None = 0x00,
Track = 0x01,
Album = 0x02,
Artist = 0x04
};
void setChartType( ChartType type ) { m_chartType = type; }
ChartType chartType() const { return m_chartType; }
public slots:
void chartReturned();
void chartTypes();
void namChangedSlot( QNetworkAccessManager *nam );
protected slots:
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data );
private:
void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData );
void dataError( Tomahawk::InfoSystem::InfoRequestData requestData );
QVariantList m_chartResources;
QList<InfoStringHash> m_charts;
ChartType m_chartType;
QVariantMap m_allChartsMap;
QVariantList m_types;
QVariantList m_popularTypes;
QVariantList m_trackTypes;
QVariantList m_byTagTypes;
uint m_chartsFetchJobs;
QList< InfoRequestData > m_cachedRequests;
QHash< QString, QString > m_cachedCountries;
QWeakPointer< QNetworkAccessManager > m_nam;
};
}
}
#endif // hypemPlugin_H

View File

@ -123,43 +123,43 @@ LastFmPlugin::namChangedSlot( QNetworkAccessManager *nam )
void
LastFmPlugin::dataError( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
void
LastFmPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
switch ( requestData.type )
{
case InfoArtistImages:
fetchArtistImages( requestId, requestData );
fetchArtistImages( requestData );
break;
case InfoAlbumCoverArt:
fetchCoverArt( requestId, requestData );
fetchCoverArt( requestData );
break;
case InfoArtistSimilars:
fetchSimilarArtists( requestId, requestData );
fetchSimilarArtists( requestData );
break;
case InfoArtistSongs:
fetchTopTracks( requestId, requestData );
fetchTopTracks( requestData );
break;
case InfoChart:
fetchChart( requestId, requestData );
fetchChart( requestData );
break;
case InfoChartCapabilities:
fetchChartCapabilities( requestId, requestData );
fetchChartCapabilities( requestData );
break;
default:
dataError( requestId, requestData );
dataError( requestData );
}
}
@ -267,95 +267,95 @@ LastFmPlugin::sendLoveSong( const InfoType type, QVariant input )
void
LastFmPlugin::fetchSimilarArtists( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::fetchSimilarArtists( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
if ( !hash.contains( "artist" ) )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = hash["artist"];
emit getCachedInfo( requestId, criteria, 2419200000, requestData );
emit getCachedInfo( criteria, 2419200000, requestData );
}
void
LastFmPlugin::fetchTopTracks( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::fetchTopTracks( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
if ( !hash.contains( "artist" ) )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = hash["artist"];
emit getCachedInfo( requestId, criteria, 2419200000, requestData );
emit getCachedInfo( criteria, 2419200000, requestData );
}
void
LastFmPlugin::fetchChart( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
Tomahawk::InfoSystem::InfoStringHash criteria;
if ( !hash.contains( "chart_id" ) )
{
dataError( requestId, requestData );
dataError( requestData );
return;
} else {
criteria["chart_id"] = hash["chart_id"];
}
emit getCachedInfo( requestId, criteria, 0, requestData );
emit getCachedInfo( criteria, 0, requestData );
}
void
LastFmPlugin::fetchChartCapabilities( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
Tomahawk::InfoSystem::InfoStringHash criteria;
emit getCachedInfo( requestId, criteria, 0, requestData );
emit getCachedInfo( criteria, 0, requestData );
}
void
LastFmPlugin::fetchCoverArt( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::fetchCoverArt( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
if ( !hash.contains( "artist" ) || !hash.contains( "album" ) )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
@ -363,39 +363,39 @@ LastFmPlugin::fetchCoverArt( uint requestId, Tomahawk::InfoSystem::InfoRequestDa
criteria["artist"] = hash["artist"];
criteria["album"] = hash["album"];
emit getCachedInfo( requestId, criteria, 2419200000, requestData );
emit getCachedInfo( criteria, 2419200000, requestData );
}
void
LastFmPlugin::fetchArtistImages( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::fetchArtistImages( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
if ( !hash.contains( "artist" ) )
{
dataError( requestId, requestData );
dataError( requestData );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = hash["artist"];
emit getCachedInfo( requestId, criteria, 2419200000, requestData );
emit getCachedInfo( criteria, 2419200000, requestData );
}
void
LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !lastfm::nam() )
{
tLog() << "Have a null QNAM, uh oh";
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
@ -407,14 +407,14 @@ LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
/// We need something to check if the request is actually ment to go to this plugin
if ( !hash.contains( "chart_source" ) )
{
dataError( requestId, requestData );
dataError( requestData );
break;
}
else
{
if( "last.fm" != hash["chart_source"] )
{
dataError( requestId, requestData );
dataError( requestData );
break;
}
@ -425,7 +425,6 @@ LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
args["method"] = criteria["chart_id"];
args["limit"] = "100";
QNetworkReply* reply = lastfm::ws::get(args);
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) );
@ -466,11 +465,7 @@ LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
result.insert( "Last.fm", QVariant::fromValue<QVariantMap>( charts ) );
tDebug() << "LASTFM RETURNING CHART LIST!";
emit info(
requestId,
requestData,
result
);
emit info( requestData, result );
return;
}
@ -478,7 +473,6 @@ LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
{
lastfm::Artist a( criteria["artist"] );
QNetworkReply* reply = a.getSimilar();
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( similarArtistsReturned() ) );
@ -489,7 +483,6 @@ LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
{
lastfm::Artist a( criteria["artist"] );
QNetworkReply* reply = a.getTopTracks();
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( topTracksReturned() ) );
@ -504,7 +497,6 @@ LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&autocorrect=1&size=large&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) );
QNetworkReply* reply = lastfm::nam()->get( req );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( coverArtReturned() ) );
@ -518,7 +510,6 @@ LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=large&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ) );
QNetworkReply* reply = lastfm::nam()->get( req );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( artistImagesReturned() ) );
@ -528,7 +519,7 @@ LastFmPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
default:
{
tLog() << "Couldn't figure out what to do with this type of request after cache miss";
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
}
@ -553,11 +544,7 @@ LastFmPlugin::similarArtistsReturned()
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info(
reply->property( "requestId" ).toUInt(),
requestData,
returnedData
);
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>();
Tomahawk::InfoSystem::InfoStringHash criteria;
@ -609,11 +596,7 @@ LastFmPlugin::chartReturned()
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info(
reply->property( "requestId" ).toUInt(),
requestData,
returnedData
);
emit info( requestData, returnedData );
// TODO update cache
}
@ -629,11 +612,7 @@ LastFmPlugin::topTracksReturned()
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info(
reply->property( "requestId" ).toUInt(),
requestData,
returnedData
);
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>();
Tomahawk::InfoSystem::InfoStringHash criteria;
@ -653,7 +632,7 @@ LastFmPlugin::coverArtReturned()
if ( ba.isNull() || !ba.length() )
{
tLog() << Q_FUNC_INFO << "Uh oh, null byte array";
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
foreach ( const QUrl& url, m_badUrls )
@ -668,11 +647,7 @@ LastFmPlugin::coverArtReturned()
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info(
reply->property( "requestId" ).toUInt(),
requestData,
returnedData
);
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>();
Tomahawk::InfoSystem::InfoStringHash criteria;
@ -685,13 +660,12 @@ LastFmPlugin::coverArtReturned()
if ( !lastfm::nam() )
{
tLog() << Q_FUNC_INFO << "Uh oh, nam is null";
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
// Follow HTTP redirect
QNetworkRequest req( redir );
QNetworkReply* newReply = lastfm::nam()->get( req );
newReply->setProperty( "requestId", reply->property( "requestId" ) );
newReply->setProperty( "requestData", reply->property( "requestData" ) );
connect( newReply, SIGNAL( finished() ), SLOT( coverArtReturned() ) );
}
@ -711,7 +685,7 @@ LastFmPlugin::artistImagesReturned()
if ( ba.isNull() || !ba.length() )
{
tLog() << Q_FUNC_INFO << "Uh oh, null byte array";
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
foreach ( const QUrl& url, m_badUrls )
@ -725,7 +699,7 @@ LastFmPlugin::artistImagesReturned()
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( reply->property( "requestId" ).toUInt(), requestData, returnedData );
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>();
Tomahawk::InfoSystem::InfoStringHash criteria;
@ -737,13 +711,12 @@ LastFmPlugin::artistImagesReturned()
if ( !lastfm::nam() )
{
tLog() << Q_FUNC_INFO << "Uh oh, nam is null";
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
// Follow HTTP redirect
QNetworkRequest req( redir );
QNetworkReply* newReply = lastfm::nam()->get( req );
newReply->setProperty( "requestId", reply->property( "requestId" ) );
newReply->setProperty( "requestData", reply->property( "requestData" ) );
connect( newReply, SIGNAL( finished() ), SLOT( artistImagesReturned() ) );
}

View File

@ -56,25 +56,25 @@ public slots:
void namChangedSlot( QNetworkAccessManager *nam );
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data );
private:
void fetchCoverArt( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchArtistImages( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchSimilarArtists( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchTopTracks( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChart( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChartCapabilities( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchCoverArt( Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchArtistImages( Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchSimilarArtists( Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchTopTracks( Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData );
void createScrobbler();
void nowPlaying( const QVariant &input );
void scrobble();
void sendLoveSong( const InfoType type, QVariant input );
void dataError( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void dataError( Tomahawk::InfoSystem::InfoRequestData requestData );
QList<lastfm::Track> parseTrackList( QNetworkReply * reply );

View File

@ -50,31 +50,64 @@ MusicBrainzPlugin::namChangedSlot( QNetworkAccessManager *nam )
m_nam = QWeakPointer< QNetworkAccessManager >( nam );
}
void
MusicBrainzPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
MusicBrainzPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
if ( !hash.contains( "artist" ) )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
switch ( requestData.type )
{
case InfoArtistReleases:
{
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = hash["artist"];
emit getCachedInfo( criteria, 2419200000, requestData );
break;
}
case InfoAlbumSongs:
{
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = hash["artist"];
criteria["album"] = hash["album"];
emit getCachedInfo( criteria, 2419200000, requestData );
break;
}
default:
{
Q_ASSERT( false );
break;
}
}
}
void
MusicBrainzPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData )
{
switch ( requestData.type )
{
case InfoArtistReleases:
{
QString requestString( "http://musicbrainz.org/ws/2/artist" );
QUrl url( requestString );
url.addQueryItem( "query", hash["artist"] );
url.addQueryItem( "query", criteria["artist"] );
QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( artistSearchSlot() ) );
@ -85,9 +118,8 @@ MusicBrainzPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestDat
{
QString requestString( "http://musicbrainz.org/ws/2/artist" );
QUrl url( requestString );
url.addQueryItem( "query", hash["artist"] );
url.addQueryItem( "query", criteria["artist"] );
QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( albumSearchSlot() ) );
@ -104,24 +136,24 @@ MusicBrainzPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestDat
bool
MusicBrainzPlugin::isValidTrackData( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
MusicBrainzPlugin::isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( requestData.input.isNull() || !requestData.input.isValid() || !requestData.input.canConvert< QVariantMap >() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
qDebug() << Q_FUNC_INFO << "Data null, invalid, or can't convert";
return false;
}
QVariantMap hash = requestData.input.value< QVariantMap >();
if ( hash[ "trackName" ].toString().isEmpty() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
qDebug() << Q_FUNC_INFO << "Track name is empty";
return false;
}
if ( hash[ "artistName" ].toString().isEmpty() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
qDebug() << Q_FUNC_INFO << "No artist name found";
return false;
}
@ -141,7 +173,7 @@ MusicBrainzPlugin::artistSearchSlot()
QDomNodeList domNodeList = doc.elementsByTagName( "artist" );
if ( domNodeList.isEmpty() )
{
emit info( oldReply->property( "requestId" ).toUInt(), oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
@ -151,7 +183,6 @@ MusicBrainzPlugin::artistSearchSlot()
url.addQueryItem( "artist", artist_id );
QNetworkReply* newReply = m_nam.data()->get( QNetworkRequest( url ) );
newReply->setProperty( "requestId", oldReply->property( "requestId" ) );
newReply->setProperty( "requestData", oldReply->property( "requestData" ) );
connect( newReply, SIGNAL( finished() ), SLOT( albumFoundSlot() ) );
}
@ -169,7 +200,7 @@ MusicBrainzPlugin::albumSearchSlot()
QDomNodeList domNodeList = doc.elementsByTagName( "artist" );
if ( domNodeList.isEmpty() )
{
emit info( oldReply->property( "requestId" ).toUInt(), oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
@ -179,7 +210,6 @@ MusicBrainzPlugin::albumSearchSlot()
url.addQueryItem( "artist", artist_id );
QNetworkReply* newReply = m_nam.data()->get( QNetworkRequest( url ) );
newReply->setProperty( "requestId", oldReply->property( "requestId" ) );
newReply->setProperty( "requestData", oldReply->property( "requestData" ) );
connect( newReply, SIGNAL( finished() ), SLOT( tracksSearchSlot() ) );
}
@ -197,7 +227,7 @@ MusicBrainzPlugin::tracksSearchSlot()
QDomNodeList domNodeList = doc.elementsByTagName( "release" );
if ( domNodeList.isEmpty() )
{
emit info( oldReply->property( "requestId" ).toUInt(), oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
@ -214,7 +244,7 @@ MusicBrainzPlugin::tracksSearchSlot()
if ( element.isNull() )
{
emit info( oldReply->property( "requestId" ).toUInt(), oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
@ -223,7 +253,6 @@ MusicBrainzPlugin::tracksSearchSlot()
QUrl url( requestString );
QNetworkReply* newReply = m_nam.data()->get( QNetworkRequest( url ) );
newReply->setProperty( "requestId", oldReply->property( "requestId" ) );
newReply->setProperty( "requestData", oldReply->property( "requestData" ) );
connect( newReply, SIGNAL( finished() ), SLOT( tracksFoundSlot() ) );
}
@ -241,7 +270,7 @@ MusicBrainzPlugin::albumFoundSlot()
QDomNodeList domNodeList = doc.elementsByTagName( "title" );
if ( domNodeList.isEmpty() )
{
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
@ -256,7 +285,7 @@ MusicBrainzPlugin::albumFoundSlot()
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
QVariantMap returnedData;
returnedData["albums"] = albums;
emit info( reply->property( "requestId" ).toUInt(), requestData, returnedData );
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>();
Tomahawk::InfoSystem::InfoStringHash criteria;
@ -277,7 +306,7 @@ MusicBrainzPlugin::tracksFoundSlot()
QDomNodeList domNodeList = doc.elementsByTagName( "recording" );
if ( domNodeList.isEmpty() )
{
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
@ -297,7 +326,7 @@ MusicBrainzPlugin::tracksFoundSlot()
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
QVariantMap returnedData;
returnedData["tracks"] = tracks;
emit info( reply->property( "requestId" ).toUInt(), requestData, returnedData );
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>();
Tomahawk::InfoSystem::InfoStringHash criteria;

View File

@ -42,7 +42,8 @@ public slots:
void namChangedSlot( QNetworkAccessManager *nam );
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData );
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data )
{
@ -51,12 +52,6 @@ protected slots:
Q_UNUSED( data );
}
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( criteria );
Q_UNUSED( requestData );
}
private slots:
void artistSearchSlot();
@ -67,7 +62,7 @@ private slots:
void tracksFoundSlot();
private:
bool isValidTrackData( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
bool isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData );
QWeakPointer< QNetworkAccessManager > m_nam;
};

View File

@ -53,17 +53,17 @@ MusixMatchPlugin::namChangedSlot( QNetworkAccessManager *nam )
}
void
MusixMatchPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
MusixMatchPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
qDebug() << Q_FUNC_INFO;
if( !isValidTrackData( requestId, requestData ) || !requestData.input.canConvert< QVariantMap >() || m_nam.isNull() || requestData.type != Tomahawk::InfoSystem::InfoTrackLyrics )
if( !isValidTrackData( requestData ) || !requestData.input.canConvert< QVariantMap >() || m_nam.isNull() || requestData.type != Tomahawk::InfoSystem::InfoTrackLyrics )
return;
QVariantMap hash = requestData.input.value< QVariantMap >();
QString artist = hash["artistName"].toString();
QString track = hash["trackName"].toString();
if( artist.isEmpty() || track.isEmpty() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
return;
}
qDebug() << "artist is " << artist << ", track is " << track;
@ -73,32 +73,31 @@ MusixMatchPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData
url.addQueryItem( "q_artist", artist );
url.addQueryItem( "q_track", track );
QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( trackSearchSlot() ) );
}
bool
MusixMatchPlugin::isValidTrackData( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
MusixMatchPlugin::isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData )
{
qDebug() << Q_FUNC_INFO;
if ( requestData.input.isNull() || !requestData.input.isValid() || !requestData.input.canConvert< QVariantMap >() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
qDebug() << "MusixMatchPlugin::isValidTrackData: Data null, invalid, or can't convert";
return false;
}
QVariantMap hash = requestData.input.value< QVariantMap >();
if ( hash[ "trackName" ].toString().isEmpty() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
qDebug() << "MusixMatchPlugin::isValidTrackData: Track name is empty";
return false;
}
if ( hash[ "artistName" ].toString().isEmpty() )
{
emit info( requestId, requestData, QVariant() );
emit info( requestData, QVariant() );
qDebug() << "MusixMatchPlugin::isValidTrackData: No artist name found";
return false;
}
@ -119,7 +118,7 @@ MusixMatchPlugin::trackSearchSlot()
QDomNodeList domNodeList = doc.elementsByTagName("track_id");
if ( domNodeList.isEmpty() )
{
emit info( oldReply->property( "requestId" ).toUInt(), oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
QString track_id = domNodeList.at(0).toElement().text();
@ -128,7 +127,6 @@ MusixMatchPlugin::trackSearchSlot()
url.addQueryItem( "apikey", m_apiKey );
url.addQueryItem( "track_id", track_id );
QNetworkReply* newReply = m_nam.data()->get( QNetworkRequest( url ) );
newReply->setProperty( "requestId", oldReply->property( "requestId" ) );
newReply->setProperty( "requestData", oldReply->property( "requestData" ) );
connect( newReply, SIGNAL( finished() ), SLOT( trackLyricsSlot() ) );
}
@ -146,10 +144,10 @@ MusixMatchPlugin::trackLyricsSlot()
QDomNodeList domNodeList = doc.elementsByTagName( "lyrics_body" );
if ( domNodeList.isEmpty() )
{
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
QString lyrics = domNodeList.at(0).toElement().text();
qDebug() << "Emitting lyrics: " << lyrics;
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant( lyrics ) );
emit info( reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant( lyrics ) );
}

View File

@ -45,7 +45,7 @@ public slots:
void namChangedSlot( QNetworkAccessManager *nam );
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data )
{
@ -54,15 +54,14 @@ protected slots:
Q_UNUSED( data );
}
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( criteria );
Q_UNUSED( requestData );
}
private:
bool isValidTrackData( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
bool isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData );
QString m_apiKey;

View File

@ -0,0 +1,410 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Hugo Lindström <hugolm84@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "spotifyPlugin.h"
#include <QDir>
#include <QSettings>
#include <QCryptographicHash>
#include <QNetworkConfiguration>
#include <QNetworkReply>
#include <QDomElement>
#include "album.h"
#include "typedefs.h"
#include "audio/audioengine.h"
#include "tomahawksettings.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include "chartsplugin_data_p.h"
#define SPOTIFY_API_URL "http://spotikea.tomahawk-player.org:10380/"
#include <qjson/parser.h>
#include <qjson/serializer.h>
using namespace Tomahawk::InfoSystem;
SpotifyPlugin::SpotifyPlugin()
: InfoPlugin()
, m_chartsFetchJobs( 0 )
{
m_supportedGetTypes << InfoChart << InfoChartCapabilities;
}
SpotifyPlugin::~SpotifyPlugin()
{
qDebug() << Q_FUNC_INFO;
}
void
SpotifyPlugin::namChangedSlot( QNetworkAccessManager *nam )
{
tDebug() << "SpotifyPlugin: namChangedSLot";
qDebug() << Q_FUNC_INFO;
if( !nam )
return;
m_nam = QWeakPointer< QNetworkAccessManager >( nam );
// we never need to re-fetch
if ( !m_allChartsMap.isEmpty() )
return;
/// We need to fetch possible types before they are asked for
tDebug() << "SpotifyPlugin: InfoChart fetching possible resources";
QUrl url = QUrl( QString( SPOTIFY_API_URL "toplist/charts" ) );
QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) );
tDebug() << Q_FUNC_INFO << "fetching:" << url;
connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) );
m_chartsFetchJobs++;
}
void
SpotifyPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData )
{
emit info( requestData, QVariant() );
return;
}
void
SpotifyPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
qDebug() << Q_FUNC_INFO << requestData.caller;
qDebug() << Q_FUNC_INFO << requestData.customData;
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
switch ( requestData.type )
{
case InfoChart:
if ( !hash.contains( "chart_source" ) || hash["chart_source"] != "spotify" )
{
dataError( requestData );
break;
}
qDebug() << Q_FUNC_INFO << "InfoCHart req for" << hash["chart_source"];
fetchChart( requestData );
break;
case InfoChartCapabilities:
fetchChartCapabilities( requestData );
break;
default:
dataError( requestData );
}
}
void
SpotifyPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
{
Q_UNUSED( caller )
Q_UNUSED( type)
Q_UNUSED( input )
}
void
SpotifyPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
Tomahawk::InfoSystem::InfoStringHash criteria;
if ( !hash.contains( "chart_id" ) )
{
dataError( requestData );
return;
} else {
criteria["chart_id"] = hash["chart_id"];
}
emit getCachedInfo( criteria, 604800000 /* Expire chart cache in 1 week */, requestData );
}
void
SpotifyPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestData );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
emit getCachedInfo( criteria, 0, requestData );
}
void
SpotifyPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
if ( !m_nam.data() )
{
tLog() << Q_FUNC_INFO << "Have a null QNAM, uh oh";
emit info( requestData, QVariant() );
return;
}
switch ( requestData.type )
{
case InfoChart:
{
/// Fetch the chart, we need source and id
QUrl url = QUrl( QString( SPOTIFY_API_URL "toplist/%1/" ).arg( criteria["chart_id"] ) );
qDebug() << Q_FUNC_INFO << "Getting chart url" << url;
QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) );
return;
}
case InfoChartCapabilities:
{
if ( m_chartsFetchJobs > 0 )
{
qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!";
m_cachedRequests.append( requestData );
return;
}
emit info( requestData, m_allChartsMap );
return;
}
default:
{
tLog() << Q_FUNC_INFO << "Couldn't figure out what to do with this type of request after cache miss";
emit info( requestData, QVariant() );
return;
}
}
}
void
SpotifyPlugin::chartTypes()
{
/// Get possible chart type for specificSpotifyPlugin: InfoChart types returned chart source
tDebug() << Q_FUNC_INFO << "Got spotifychart type result";
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
bool ok;
const QVariantMap res = p.parse( reply, &ok ).toMap();
const QVariantMap chartObj = res;
if ( !ok )
{
tLog() << Q_FUNC_INFO << "Failed to parse resources" << p.errorString() << "On line" << p.errorLine();
return;
}
QVariantMap charts;
foreach(QVariant geos, chartObj.value("Charts").toList().takeLast().toMap().value("geo").toList() )
{
const QString geo = geos.toMap().value( "name" ).toString();
const QString geoId = geos.toMap().value( "id" ).toString();
QString country;
if( geo == "For me" )
continue; /// country = geo; Lets use this later, when we can get the spotify username from tomahawk
else if( geo == "Everywhere" )
country = geo;
else
{
QLocale l( QString( "en_%1" ).arg( geo ) );
country = Tomahawk::CountryUtils::fullCountryFromCode( geo );
for ( int i = 1; i < country.size(); i++ )
{
if ( country.at( i ).isUpper() )
{
country.insert( i, " " );
i++;
}
}
}
QList< InfoStringHash > chart_types;
foreach(QVariant types, chartObj.value("Charts").toList().takeFirst().toMap().value("types").toList() )
{
QString type = types.toMap().value( "id" ).toString();
QString label = types.toMap().value( "name" ).toString();
InfoStringHash c;
c[ "id" ] = type + "/" + geoId;
c[ "label" ] = label;
c[ "type" ] = type;
chart_types.append( c );
}
charts.insert( country.toUtf8(), QVariant::fromValue<QList< InfoStringHash > >( chart_types ) );
}
QVariantMap defaultMap;
defaultMap[ "spotify" ] = QStringList() << "United States" << "Top Albums";
m_allChartsMap[ "defaults" ] = defaultMap;
m_allChartsMap.insert( "Spotify", QVariant::fromValue<QVariantMap>( charts ) );
}
else
{
tLog() << Q_FUNC_INFO << "Error fetching charts:" << reply->errorString();
}
m_chartsFetchJobs--;
if ( !m_cachedRequests.isEmpty() && m_chartsFetchJobs == 0 )
{
foreach ( InfoRequestData request, m_cachedRequests )
{
emit info( request, m_allChartsMap );
}
m_cachedRequests.clear();
}
}
void
SpotifyPlugin::chartReturned()
{
/// Chart request returned something! Woho
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
QString url = reply->url().toString();
QVariantMap returnedData;
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
bool ok;
QVariantMap res = p.parse( reply, &ok ).toMap();
if ( !ok )
{
tLog() << "Failed to parse json from chart lookup:" << p.errorString() << "On line" << p.errorLine();
return;
}
/// SO we have a result, parse it!
QList< InfoStringHash > top_tracks;
QList< InfoStringHash > top_albums;
QStringList top_artists;
if( url.contains( "albums" ) )
setChartType( Album );
else if( url.contains( "tracks" ) )
setChartType( Track );
else if( url.contains( "artists" ) )
setChartType( Artist );
else
setChartType( None );
foreach(QVariant result, res.value("toplist").toMap().value("result").toList() )
{
QString title, artist;
QVariantMap chartMap = result.toMap();
if ( !chartMap.isEmpty() )
{
title = chartMap.value( "title" ).toString();
artist = chartMap.value( "artist" ).toString();
if( chartType() == Track )
{
InfoStringHash pair;
pair["artist"] = artist;
pair["track"] = title;
top_tracks << pair;
qDebug() << "SpotifyChart type is track";
}
if( chartType() == Album )
{
InfoStringHash pair;
pair["artist"] = artist;
pair["album"] = title;
top_albums << pair;
qDebug() << "SpotifyChart type is album";
}
if( chartType() == Artist )
{
top_artists << chartMap.value( "name" ).toString();
qDebug() << "SpotifyChart type is artist";
}
}
}
if( chartType() == Track )
{
tDebug() << "ChartsPlugin:" << "\tgot " << top_tracks.size() << " tracks";
returnedData["tracks"] = QVariant::fromValue( top_tracks );
returnedData["type"] = "tracks";
}
if( chartType() == Album )
{
tDebug() << "ChartsPlugin:" << "\tgot " << top_albums.size() << " albums";
returnedData["albums"] = QVariant::fromValue( top_albums );
returnedData["type"] = "albums";
}
if( chartType() == Artist )
{
tDebug() << "ChartsPlugin:" << "\tgot " << top_artists.size() << " artists";
returnedData["artists"] = top_artists;
returnedData["type"] = "artists";
}
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
emit info( requestData, returnedData );
}
else
qDebug() << "Network error in fetching chart:" << reply->url().toString();
}

View File

@ -0,0 +1,80 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Hugo Lindström <hugolm84@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SpotifyPlugin_H
#define SpotifyPlugin_H
#include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
#include <QNetworkReply>
#include <QObject>
class QNetworkReply;
namespace Tomahawk
{
namespace InfoSystem
{
class SpotifyPlugin : public InfoPlugin
{
Q_OBJECT
public:
SpotifyPlugin();
virtual ~SpotifyPlugin();
enum ChartType {
None = 0x00,
Track = 0x01,
Album = 0x02,
Artist = 0x04
};
void setChartType( ChartType type ) { m_chartType = type; }
ChartType chartType() const { return m_chartType; }
public slots:
void chartReturned();
void chartTypes();
void namChangedSlot( QNetworkAccessManager *nam );
protected slots:
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data );
private:
void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData );
void fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData );
void dataError( Tomahawk::InfoSystem::InfoRequestData requestData );
ChartType m_chartType;
QVariantMap m_allChartsMap;
uint m_chartsFetchJobs;
QList< InfoRequestData > m_cachedRequests;
QWeakPointer< QNetworkAccessManager > m_nam;
};
}
}
#endif // SpotifyPlugin_H

View File

@ -41,9 +41,8 @@ public:
virtual ~AdiumPlugin();
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( requestData );
}
@ -52,9 +51,8 @@ protected slots:
public slots:
void namChangedSlot( QNetworkAccessManager* nam );
virtual void notInCacheSlot( uint requestId, const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( criteria );
Q_UNUSED( requestData );
}

View File

@ -38,17 +38,15 @@ public:
virtual void namChangedSlot( QNetworkAccessManager* ) {}
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( requestData );
}
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant pushData );
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( criteria );
Q_UNUSED( requestData );
}

View File

@ -432,9 +432,8 @@ MprisPlugin::Stop()
// InfoPlugin Methods
void
MprisPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
MprisPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( requestData );
qDebug() << Q_FUNC_INFO;

View File

@ -119,9 +119,8 @@ public:
public slots:
void namChangedSlot( QNetworkAccessManager* /*nam*/ ) {} // unused
virtual void notInCacheSlot( uint requestId, const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( criteria );
Q_UNUSED( requestData );
}
@ -143,7 +142,7 @@ public slots:
protected slots:
void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input );
private slots:

View File

@ -74,12 +74,16 @@ InfoSystem::InfoSystem( QObject *parent )
connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( newNam() ) );
connect( m_cache.data(), SIGNAL( info( uint, Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
m_worker.data(), SLOT( infoSlot( uint, Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
connect( m_cache.data(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
m_worker.data(), SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
connect( m_worker.data(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
connect( m_worker.data(), SIGNAL( finished( QString ) ), this, SIGNAL( finished( QString ) ), Qt::UniqueConnection );
connect( m_worker.data(), SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ),
this, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ), Qt::UniqueConnection );
}
InfoSystem::~InfoSystem()
@ -120,10 +124,10 @@ InfoSystem::newNam() const
void
InfoSystem::getInfo( const InfoRequestData &requestData, uint timeoutMillis, bool allSources )
InfoSystem::getInfo( const InfoRequestData &requestData )
{
qDebug() << Q_FUNC_INFO;
QMetaObject::invokeMethod( m_worker.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ), Q_ARG( uint, timeoutMillis ), Q_ARG( bool, allSources ) );
QMetaObject::invokeMethod( m_worker.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
}
@ -133,11 +137,13 @@ InfoSystem::getInfo( const QString &caller, const QVariantMap &customData, const
InfoRequestData requestData;
requestData.caller = caller;
requestData.customData = customData;
requestData.allSources = allSources;
Q_FOREACH( InfoType type, inputMap.keys() )
{
requestData.type = type;
requestData.input = inputMap[ type ];
QMetaObject::invokeMethod( m_worker.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ), Q_ARG( uint, ( timeoutMap.contains( type ) ? timeoutMap[ type ] : 0 ) ), Q_ARG( bool, allSources ) );
requestData.timeoutMillis = timeoutMap.contains( type ) ? timeoutMap[ type ] : 10000;
QMetaObject::invokeMethod( m_worker.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
}
}

View File

@ -32,6 +32,7 @@
#include <QtCore/QStringList>
#include "dllmacro.h"
#include "utils/tomahawkutils.h"
class QNetworkAccessManager;
@ -43,28 +44,29 @@ class InfoSystemCache;
class InfoSystemWorker;
enum InfoType { // as items are saved in cache, mark them here to not change them
InfoTrackID = 0,
InfoTrackArtist = 1,
InfoTrackAlbum = 2,
InfoTrackGenre = 3,
InfoTrackComposer = 4,
InfoTrackDate = 5,
InfoTrackNumber = 6,
InfoTrackDiscNumber = 7,
InfoTrackBitRate = 8,
InfoTrackLength = 9,
InfoTrackSampleRate = 10,
InfoTrackFileSize = 11,
InfoTrackBPM = 12,
InfoTrackReplayGain = 13,
InfoTrackReplayPeakGain = 14,
InfoTrackLyrics = 15,
InfoTrackLocation = 16,
InfoTrackProfile = 17,
InfoTrackEnergy = 18,
InfoTrackDanceability = 19,
InfoTrackTempo = 20,
InfoTrackLoudness = 21,
InfoNoInfo = 0, //WARNING: *ALWAYS* keep this first!
InfoTrackID = 1,
InfoTrackArtist = 2,
InfoTrackAlbum = 3,
InfoTrackGenre = 4,
InfoTrackComposer = 5,
InfoTrackDate = 6,
InfoTrackNumber = 7,
InfoTrackDiscNumber = 8,
InfoTrackBitRate = 9,
InfoTrackLength = 10,
InfoTrackSampleRate = 11,
InfoTrackFileSize = 12,
InfoTrackBPM = 13,
InfoTrackReplayGain = 14,
InfoTrackReplayPeakGain = 15,
InfoTrackLyrics = 16,
InfoTrackLocation = 17,
InfoTrackProfile = 18,
InfoTrackEnergy = 19,
InfoTrackDanceability = 20,
InfoTrackTempo = 21,
InfoTrackLoudness = 22,
InfoArtistID = 25,
InfoArtistName = 26,
@ -120,14 +122,40 @@ enum InfoType { // as items are saved in cache, mark them here to not change the
InfoNotifyUser = 100,
InfoNoInfo = 101 //WARNING: *ALWAYS* keep this last!
InfoLastInfo = 101 //WARNING: *ALWAYS* keep this last!
};
struct InfoRequestData {
quint64 requestId;
quint64 internalId; //do not assign to this; it may get overwritten by the InfoSystem
QString caller;
Tomahawk::InfoSystem::InfoType type;
QVariant input;
QVariantMap customData;
uint timeoutMillis;
bool allSources;
InfoRequestData()
: requestId( TomahawkUtils::infosystemRequestId() )
, internalId( TomahawkUtils::infosystemRequestId() )
, caller( QString() )
, type( Tomahawk::InfoSystem::InfoNoInfo )
, input( QVariant() )
, customData( QVariantMap() )
, timeoutMillis( 10000 )
, allSources( false )
{}
InfoRequestData( const quint64 rId, const QString &callr, const Tomahawk::InfoSystem::InfoType typ, const QVariant &inputvar, const QVariantMap &custom )
: requestId( rId )
, internalId( TomahawkUtils::infosystemRequestId() )
, caller( callr )
, type( typ )
, input( inputvar )
, customData( custom )
, timeoutMillis( 10000 )
, allSources( false )
{}
};
typedef QMap< InfoType, QVariant > InfoTypeMap;
@ -147,15 +175,15 @@ public:
QSet< InfoType > supportedPushTypes() const { return m_supportedPushTypes; }
signals:
void getCachedInfo( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, qint64 newMaxAge, Tomahawk::InfoSystem::InfoRequestData requestData );
void info( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void getCachedInfo( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 newMaxAge, Tomahawk::InfoSystem::InfoRequestData requestData );
void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void updateCache( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output );
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData ) = 0;
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) = 0;
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data ) = 0;
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) = 0;
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) = 0;
virtual void namChangedSlot( QNetworkAccessManager *nam ) = 0;
@ -212,7 +240,7 @@ public:
InfoSystem( QObject *parent );
~InfoSystem();
void getInfo( const InfoRequestData &requestData, uint timeoutMillis = 0, bool allSources = false );
void getInfo( const InfoRequestData &requestData );
//WARNING: if changing timeoutMillis above, also change in below function in .cpp file
void getInfo( const QString &caller, const QVariantMap &customData, const InfoTypeMap &inputMap, const InfoTimeoutMap &timeoutMap = InfoTimeoutMap(), bool allSources = false );
void pushInfo( const QString &caller, const InfoType type, const QVariant &input );
@ -221,6 +249,7 @@ public:
signals:
void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void finished( QString target );
void finished( QString target, Tomahawk::InfoSystem::InfoType type );
public slots:
void newNam() const;

View File

@ -75,7 +75,7 @@ InfoSystemCache::doUpgrade( uint oldVersion, uint newVersion )
{
qDebug() << Q_FUNC_INFO << "Wiping cache";
for ( int i = 0; i <= InfoNoInfo; i++ )
for ( int i = InfoNoInfo; i <= InfoLastInfo; i++ )
{
InfoType type = (InfoType)(i);
const QString cacheDirName = m_cacheBaseDir + QString::number( (int)type );
@ -96,7 +96,7 @@ InfoSystemCache::pruneTimerFired()
qDebug() << Q_FUNC_INFO << "Pruning infosystemcache";
qlonglong currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch();
for ( int i = 0; i <= InfoNoInfo; i++ )
for ( int i = InfoNoInfo; i <= InfoLastInfo; i++ )
{
InfoType type = (InfoType)(i);
QHash< QString, QString > fileLocationHash = m_fileLocationCache[type];
@ -121,7 +121,7 @@ InfoSystemCache::pruneTimerFired()
void
InfoSystemCache::getCachedInfoSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, qint64 newMaxAge, Tomahawk::InfoSystem::InfoRequestData requestData )
InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 newMaxAge, Tomahawk::InfoSystem::InfoRequestData requestData )
{
QObject* sendingObj = sender();
const QString criteriaHashVal = criteriaMd5( criteria );
@ -133,7 +133,7 @@ InfoSystemCache::getCachedInfoSlot( uint requestId, Tomahawk::InfoSystem::InfoSt
{
//We already know of some values, so no need to re-read the directory again as it's already happened
qDebug() << Q_FUNC_INFO << "notInCache -- filelocationhash empty";
notInCache( sendingObj, requestId, criteria, requestData );
notInCache( sendingObj, criteria, requestData );
return;
}
@ -143,7 +143,7 @@ InfoSystemCache::getCachedInfoSlot( uint requestId, Tomahawk::InfoSystem::InfoSt
{
//Dir doesn't exist so clearly not in cache
qDebug() << Q_FUNC_INFO << "notInCache -- dir doesn't exist";
notInCache( sendingObj, requestId, criteria, requestData );
notInCache( sendingObj, criteria, requestData );
return;
}
@ -160,7 +160,7 @@ InfoSystemCache::getCachedInfoSlot( uint requestId, Tomahawk::InfoSystem::InfoSt
{
//Still didn't find it? It's really not in the cache then
qDebug() << Q_FUNC_INFO << "notInCache -- filelocationhash doesn't contain criteria val";
notInCache( sendingObj, requestId, criteria, requestData );
notInCache( sendingObj, criteria, requestData );
return;
}
}
@ -180,7 +180,7 @@ InfoSystemCache::getCachedInfoSlot( uint requestId, Tomahawk::InfoSystem::InfoSt
m_dataCache.remove( criteriaHashValWithType );
qDebug() << Q_FUNC_INFO << "notInCache -- file was stale";
notInCache( sendingObj, requestId, criteria, requestData );
notInCache( sendingObj, criteria, requestData );
return;
}
else if ( newMaxAge > 0 )
@ -190,7 +190,7 @@ InfoSystemCache::getCachedInfoSlot( uint requestId, Tomahawk::InfoSystem::InfoSt
if ( !QFile::rename( file.canonicalFilePath(), newFilePath ) )
{
qDebug() << Q_FUNC_INFO << "notInCache -- failed to move old cache file to new location";
notInCache( sendingObj, requestId, criteria, requestData );
notInCache( sendingObj, criteria, requestData );
return;
}
@ -204,25 +204,26 @@ InfoSystemCache::getCachedInfoSlot( uint requestId, Tomahawk::InfoSystem::InfoSt
QVariant output = cachedSettings.value( "data" );
m_dataCache.insert( criteriaHashValWithType, new QVariant( output ) );
emit info( requestId, requestData, output );
emit info( requestData, output );
}
else
{
emit info( requestId, requestData, QVariant( *( m_dataCache[ criteriaHashValWithType ] ) ) );
emit info( requestData, QVariant( *( m_dataCache[ criteriaHashValWithType ] ) ) );
}
}
void
InfoSystemCache::notInCache( QObject *receiver, uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
InfoSystemCache::notInCache( QObject *receiver, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
QMetaObject::invokeMethod( receiver, "notInCacheSlot", Q_ARG( uint, requestId ), Q_ARG( Tomahawk::InfoSystem::InfoStringHash, criteria ), Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
QMetaObject::invokeMethod( receiver, "notInCacheSlot", Q_ARG( Tomahawk::InfoSystem::InfoStringHash, criteria ), Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
}
void
InfoSystemCache::updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output )
{
qDebug() << Q_FUNC_INFO;
const QString criteriaHashVal = criteriaMd5( criteria );
const QString criteriaHashValWithType = criteriaMd5( criteria, type );
const QString cacheDir = m_cacheBaseDir + QString::number( (int)type );
@ -283,7 +284,7 @@ InfoSystemCache::criteriaMd5( const Tomahawk::InfoSystem::InfoStringHash &criter
md5.addData( key.toUtf8() );
md5.addData( criteria[key].toUtf8() );
}
if ( type != Tomahawk::InfoSystem::InfoNoInfo )
if ( type != Tomahawk::InfoSystem::InfoNoInfo && type != Tomahawk::InfoSystem::InfoLastInfo )
md5.addData( QString::number( (int)type ).toUtf8() );
return md5.result().toHex();
}

View File

@ -43,17 +43,17 @@ public:
virtual ~InfoSystemCache();
signals:
void info( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
public slots:
void getCachedInfoSlot( uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, qint64 newMaxAge, Tomahawk::InfoSystem::InfoRequestData requestData );
void getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 newMaxAge, Tomahawk::InfoSystem::InfoRequestData requestData );
void updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output );
private slots:
void pruneTimerFired();
private:
void notInCache( QObject *receiver, uint requestId, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
void notInCache( QObject *receiver, Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
void doUpgrade( uint oldVersion, uint newVersion );
const QString criteriaMd5( const Tomahawk::InfoSystem::InfoStringHash &criteria, Tomahawk::InfoSystem::InfoType type = Tomahawk::InfoSystem::InfoNoInfo ) const;

View File

@ -26,8 +26,10 @@
#include "infoplugins/generic/echonestplugin.h"
#include "infoplugins/generic/musixmatchplugin.h"
#include "infoplugins/generic/chartsplugin.h"
#include "infoplugins/generic/spotifyPlugin.h"
#include "infoplugins/generic/lastfmplugin.h"
#include "infoplugins/generic/musicbrainzPlugin.h"
#include "infoplugins/generic/hypemPlugin.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
@ -40,6 +42,7 @@
#endif
#include "lastfm/NetworkAccessManager"
#include "infoplugins/generic/RoviPlugin.h"
namespace Tomahawk
{
@ -49,7 +52,6 @@ namespace InfoSystem
InfoSystemWorker::InfoSystemWorker()
: QObject()
, m_nextRequest( 0 )
{
// qDebug() << Q_FUNC_INFO;
@ -92,6 +94,15 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac
InfoPluginPtr sptr( new ChartsPlugin() );
m_plugins.append( sptr );
registerInfoTypes( sptr, sptr.data()->supportedGetTypes(), sptr.data()->supportedPushTypes() );
InfoPluginPtr roviptr( new RoviPlugin() );
m_plugins.append( roviptr );
registerInfoTypes( roviptr, roviptr.data()->supportedGetTypes(), roviptr.data()->supportedPushTypes() );
InfoPluginPtr spotptr( new SpotifyPlugin() );
m_plugins.append( spotptr );
registerInfoTypes( spotptr, spotptr.data()->supportedGetTypes(), spotptr.data()->supportedPushTypes() );
InfoPluginPtr hypeptr( new hypemPlugin() );
m_plugins.append( hypeptr );
registerInfoTypes( hypeptr, hypeptr.data()->supportedGetTypes(), hypeptr.data()->supportedPushTypes() );
#ifdef Q_WS_MAC
@ -105,24 +116,24 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac
registerInfoTypes( fdonotifyptr, fdonotifyptr.data()->supportedGetTypes(), fdonotifyptr.data()->supportedPushTypes() );
InfoPluginPtr mprisptr( new MprisPlugin() );
m_plugins.append( mprisptr );
registerInfoTypes( mprisptr, mprisptr.data()->supportedGetTypes(), mprisptr.data()->supportedPushTypes() );
registerInfoTypes( mprisptr, mprisptr.data()->supportedGetTypes(), mprisptr.data()->supportedPushTypes() );
#endif
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
connect(
plugin.data(),
SIGNAL( info( uint, Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this,
SLOT( infoSlot( uint, Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
Qt::UniqueConnection
);
connect(
plugin.data(),
SIGNAL( getCachedInfo( uint, Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
cache.data(),
SLOT( getCachedInfoSlot( uint, Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) )
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) )
);
connect(
plugin.data(),
@ -165,19 +176,19 @@ InfoSystemWorker::determineOrderedMatches( const InfoType type ) const
void
InfoSystemWorker::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData, uint timeoutMillis, bool allSources )
InfoSystemWorker::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
{
// qDebug() << Q_FUNC_INFO;
//qDebug() << Q_FUNC_INFO << "type is " << requestData.type << " and allSources = " << (allSources ? "true" : "false" );
QList< InfoPluginPtr > providers = determineOrderedMatches( requestData.type );
if ( providers.isEmpty() )
{
emit info( requestData, QVariant() );
checkFinished( requestData.caller );
checkFinished( requestData );
return;
}
if ( !allSources )
if ( !requestData.allSources )
providers = QList< InfoPluginPtr >( providers.mid( 0, 1 ) );
bool foundOne = false;
@ -187,12 +198,22 @@ InfoSystemWorker::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData, ui
continue;
foundOne = true;
uint requestId = ++m_nextRequest;
if ( requestData.allSources || m_savedRequestMap.contains( requestData.requestId ) )
{
if ( m_savedRequestMap.contains( requestData.requestId ) )
tDebug() << Q_FUNC_INFO << "Warning: reassigning requestId because it already exists";
requestData.internalId = TomahawkUtils::infosystemRequestId();
}
else
requestData.internalId = requestData.requestId;
quint64 requestId = requestData.internalId;
m_requestSatisfiedMap[ requestId ] = false;
if ( timeoutMillis != 0 )
if ( requestData.timeoutMillis != 0 )
{
qint64 currMs = QDateTime::currentMSecsSinceEpoch();
m_timeRequestMapper.insert( currMs + timeoutMillis, requestId );
m_timeRequestMapper.insert( currMs + requestData.timeoutMillis, requestId );
}
// qDebug() << "Assigning request with requestId" << requestId << "and type" << requestData.type;
m_dataTracker[ requestData.caller ][ requestData.type ] = m_dataTracker[ requestData.caller ][ requestData.type ] + 1;
@ -205,19 +226,19 @@ InfoSystemWorker::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData, ui
data->customData = requestData.customData;
m_savedRequestMap[ requestId ] = data;
QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( uint, requestId ), Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
}
if ( !foundOne )
{
emit info( requestData, QVariant() );
checkFinished( requestData.caller );
checkFinished( requestData );
}
}
void
InfoSystemWorker::pushInfo( QString caller, InfoType type, QVariant input )
InfoSystemWorker::pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input )
{
// qDebug() << Q_FUNC_INFO;
@ -230,10 +251,12 @@ InfoSystemWorker::pushInfo( QString caller, InfoType type, QVariant input )
void
InfoSystemWorker::infoSlot( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
InfoSystemWorker::infoSlot( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
{
// qDebug() << Q_FUNC_INFO << "with requestId" << requestId;
quint64 requestId = requestData.internalId;
if ( m_dataTracker[ requestData.caller ][ requestData.type ] == 0 )
{
// qDebug() << Q_FUNC_INFO << "Caller was not waiting for that type of data!";
@ -252,23 +275,23 @@ InfoSystemWorker::infoSlot( uint requestId, Tomahawk::InfoSystem::InfoRequestDat
// qDebug() << "Current count in dataTracker for target" << requestData.caller << "and type" << requestData.type << "is" << m_dataTracker[ requestData.caller ][ requestData.type ];
delete m_savedRequestMap[ requestId ];
m_savedRequestMap.remove( requestId );
checkFinished( requestData.caller );
checkFinished( requestData );
}
void
InfoSystemWorker::checkFinished( const QString &target )
InfoSystemWorker::checkFinished( const Tomahawk::InfoSystem::InfoRequestData &requestData )
{
Q_FOREACH( InfoType testtype, m_dataTracker[ target ].keys() )
if ( m_dataTracker[ requestData.caller ][ requestData.type ] == 0 )
emit finished( requestData.caller, requestData.type );
Q_FOREACH( InfoType testtype, m_dataTracker[ requestData.caller ].keys() )
{
if ( m_dataTracker[ target ][ testtype ] != 0)
{
// qDebug() << "Found outstanding request of type" << testtype;
if ( m_dataTracker[ requestData.caller ][ testtype ] != 0 )
return;
}
}
// qDebug() << "Emitting finished with target" << target;
emit finished( target );
emit finished( requestData.caller );
}
@ -278,7 +301,7 @@ InfoSystemWorker::checkTimeoutsTimerFired()
qint64 currTime = QDateTime::currentMSecsSinceEpoch();
Q_FOREACH( qint64 time, m_timeRequestMapper.keys() )
{
Q_FOREACH( uint requestId, m_timeRequestMapper.values( time ) )
Q_FOREACH( quint64 requestId, m_timeRequestMapper.values( time ) )
{
if ( time < currTime )
{
@ -313,7 +336,7 @@ InfoSystemWorker::checkTimeoutsTimerFired()
if ( !m_timeRequestMapper.count( time ) )
m_timeRequestMapper.remove( time );
checkFinished( returnData.caller );
checkFinished( returnData );
}
else
{
@ -338,18 +361,31 @@ InfoSystemWorker::nam() const
void
InfoSystemWorker::newNam()
{
// qDebug() << Q_FUNC_INFO << " begin";
QNetworkAccessManager *oldNam = TomahawkUtils::nam();
if ( oldNam && oldNam->thread() == thread() )
{
// qDebug() << Q_FUNC_INFO << "Using old nam as it's the same thread (GUI) as me";
m_nam = QWeakPointer< QNetworkAccessManager >( oldNam );
emit namChanged( m_nam.data() );
if ( m_nam.data() != oldNam )
{
m_nam = QWeakPointer< QNetworkAccessManager >( oldNam );
emit namChanged( m_nam.data() );
}
return;
}
// qDebug() << Q_FUNC_INFO << "No nam exists, or it's a different thread, creating a new one";
if
(
oldNam &&
!m_nam.isNull() &&
oldNam->configuration() == m_nam.data()->configuration() &&
oldNam->networkAccessible() == m_nam.data()->networkAccessible()
)
{
TomahawkUtils::NetworkProxyFactory fac1 = *( dynamic_cast< TomahawkUtils::NetworkProxyFactory * >( oldNam->proxyFactory() ) );
TomahawkUtils::NetworkProxyFactory fac2 = *( dynamic_cast< TomahawkUtils::NetworkProxyFactory * >( m_nam.data()->proxyFactory() ) );
if ( fac1 == fac2 )
return;
}
QNetworkAccessManager* newNam;
#ifdef LIBLASTFM_FOUND
newNam = new lastfm::NetworkAccessManager( this );

View File

@ -52,15 +52,16 @@ public:
signals:
void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void finished( QString target );
void finished( QString target, Tomahawk::InfoSystem::InfoType type );
void namChanged( QNetworkAccessManager* );
public slots:
void init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache > cache );
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData, uint timeoutMillis, bool allSources );
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input );
void infoSlot( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void infoSlot( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void newNam();
@ -69,11 +70,11 @@ private slots:
private:
void checkFinished( const QString &target );
void checkFinished( const Tomahawk::InfoSystem::InfoRequestData &target );
QList< InfoPluginPtr > determineOrderedMatches( const InfoType type ) const;
QHash< QString, QHash< InfoType, int > > m_dataTracker;
QMultiMap< qint64, uint > m_timeRequestMapper;
QMultiMap< qint64, quint64 > m_timeRequestMapper;
QHash< uint, bool > m_requestSatisfiedMap;
QHash< uint, InfoRequestData* > m_savedRequestMap;
@ -85,8 +86,6 @@ private:
QWeakPointer< QNetworkAccessManager> m_nam;
uint m_nextRequest;
QTimer m_checkTimeoutsTimer;
};

View File

@ -81,7 +81,7 @@ PortFwdThread::work()
qDebug() << "Trying to setup portfwd on" << tryport;
if ( m_portfwd->add( tryport, m_port ) )
{
QString pubip = QString( m_portfwd->external_ip().c_str() );
QString pubip = QString( m_portfwd->external_ip().c_str() ).trimmed();
m_externalAddress = QHostAddress( pubip );
m_externalPort = tryport;
tDebug() << "External servent address detected as" << pubip << ":" << m_externalPort;

View File

@ -31,6 +31,8 @@
#include "playlist/albumitem.h"
#include "playlist/albumproxymodel.h"
#include <QMouseEvent>
#include <viewmanager.h>
AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, AlbumProxyModel* proxy )
@ -38,7 +40,6 @@ AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, AlbumProxyModel
, m_view( parent )
, m_model( proxy )
{
m_shadowPixmap = QPixmap( RESPATH "images/cover-shadow.png" );
m_defaultCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" );
}
@ -63,9 +64,30 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter );
painter->save();
painter->setRenderHint( QPainter::Antialiasing );
// painter->setRenderHint( QPainter::Antialiasing );
// painter->drawPixmap( option.rect.adjusted( 4, 4, -4, -38 ), m_shadowPixmap );
if ( !( option.state & QStyle::State_Selected ) )
{
QRect shadowRect = option.rect.adjusted( 5, 4, -5, -40 );
painter->setPen( QColor( 90, 90, 90 ) );
painter->drawRoundedRect( shadowRect, 0.5, 0.5 );
QPen shadowPen( QColor( 30, 30, 30 ) );
shadowPen.setWidth( 0.4 );
painter->drawLine( shadowRect.bottomLeft() + QPoint( -1, 2 ), shadowRect.bottomRight() + QPoint( 1, 2 ) );
shadowPen.setColor( QColor( 160, 160, 160 ) );
painter->setPen( shadowPen );
painter->drawLine( shadowRect.topLeft() + QPoint( -1, 2 ), shadowRect.bottomLeft() + QPoint( -1, 2 ) );
painter->drawLine( shadowRect.topRight() + QPoint( 2, 2 ), shadowRect.bottomRight() + QPoint( 2, 2 ) );
painter->drawLine( shadowRect.bottomLeft() + QPoint( 0, 3 ), shadowRect.bottomRight() + QPoint( 0, 3 ) );
shadowPen.setColor( QColor( 180, 180, 180 ) );
painter->setPen( shadowPen );
painter->drawLine( shadowRect.topLeft() + QPoint( -2, 3 ), shadowRect.bottomLeft() + QPoint( -2, 1 ) );
painter->drawLine( shadowRect.topRight() + QPoint( 3, 3 ), shadowRect.bottomRight() + QPoint( 3, 1 ) );
painter->drawLine( shadowRect.bottomLeft() + QPoint( 0, 4 ), shadowRect.bottomRight() + QPoint( 0, 4 ) );
}
QPixmap cover = item->cover.isNull() ? m_defaultCover : item->cover;
QRect r = option.rect.adjusted( 6, 5, -6, -41 );
@ -117,7 +139,7 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
oneLiner = true;
else
oneLiner = ( textRect.height() / 2 < painter->fontMetrics().boundingRect( item->album()->name() ).height() ||
textRect.height() / 2 < painter->fontMetrics().boundingRect( item->album()->artist()->name() ).height() );
textRect.height() / 2 < painter->fontMetrics().boundingRect( item->album()->artist()->name() ).height() );
if ( oneLiner )
{
@ -127,15 +149,95 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
}
else
{
painter->setFont( boldFont );
to.setAlignment( Qt::AlignHCenter | Qt::AlignTop );
text = painter->fontMetrics().elidedText( item->album()->name(), Qt::ElideRight, textRect.width() - 3 );
painter->drawText( textRect, text, to );
painter->setFont( boldFont );
// If the user is hovering over an artist rect, draw a background so she knows it's clickable
QRect r = textRect;
r.setTop( r.bottom() - painter->fontMetrics().height() );
r.adjust( 4, 0, -4, -1 );
if ( m_hoveringOver == index )
TomahawkUtils::drawQueryBackground( painter, opt.palette, r, 1.5 );
#ifdef Q_WS_MAC
painter->setPen( opt.palette.color( QPalette::Dark ).darker( 200 ) );
#else
painter->setPen( opt.palette.color( QPalette::Dark ) );
#endif
to.setAlignment( Qt::AlignHCenter | Qt::AlignBottom );
text = painter->fontMetrics().elidedText( item->album()->artist()->name(), Qt::ElideRight, textRect.width() - 3 );
painter->drawText( textRect, text, to );
// Calculate rect of artist on-hover button click area
m_artistNameRects[ index ] = r;
}
painter->restore();
}
bool
AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
{
Q_UNUSED( option );
if ( event->type() != QEvent::MouseButtonRelease &&
event->type() != QEvent::MouseMove &&
event->type() != QEvent::MouseButtonPress &&
event->type() != QEvent::Leave )
return false;
if ( m_artistNameRects.contains( index ) )
{
QMouseEvent* ev = static_cast< QMouseEvent* >( event );
QRect artistNameRect = m_artistNameRects[ index ];
if ( artistNameRect.contains( ev->pos() ) )
{
if ( event->type() == QEvent::MouseMove )
{
if ( m_hoveringOver != index )
{
QModelIndex old = m_hoveringOver;
m_hoveringOver = index;
emit updateIndex( old );
emit updateIndex( index );
}
event->accept();
return true;
}
else if ( event->type() == QEvent::MouseButtonRelease )
{
AlbumItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
if ( !item || item->album().isNull() || item->album()->artist().isNull() )
return false;
ViewManager::instance()->show( item->album()->artist() );
event->accept();
return true;
} else if ( event->type() == QEvent::MouseButtonPress )
{
// Stop the whole album from having a down click action as we just want the artist name to be clicked
event->accept();
return true;
}
}
}
whitespaceMouseEvent();
return false;
}
void
AlbumItemDelegate::whitespaceMouseEvent()
{
if ( m_hoveringOver.isValid() )
{
QModelIndex old = m_hoveringOver;
m_hoveringOver = QPersistentModelIndex();
emit updateIndex( old );
}
}

View File

@ -23,6 +23,7 @@
#include "dllmacro.h"
class QEvent;
class AlbumProxyModel;
class DLLEXPORT AlbumItemDelegate : public QStyledItemDelegate
@ -32,17 +33,26 @@ Q_OBJECT
public:
AlbumItemDelegate( QAbstractItemView* parent = 0, AlbumProxyModel* proxy = 0 );
void whitespaceMouseEvent();
protected:
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
// QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
signals:
void updateIndex( const QModelIndex& idx );
private:
QAbstractItemView* m_view;
AlbumProxyModel* m_model;
mutable QHash< qint64, QPixmap > m_cache;
mutable QHash< QPersistentModelIndex, QRect > m_artistNameRects;
QPersistentModelIndex m_hoveringOver;
QPixmap m_shadowPixmap;
QPixmap m_defaultCover;
};

View File

@ -254,6 +254,8 @@ AlbumModel::addCollection( const collection_ptr& collection, bool overwrite )
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() );
emit loadingStarted();
}
@ -280,6 +282,8 @@ AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned in
m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() );
else
m_title = tr( "All albums" );
emit loadingStarted();
}
@ -292,6 +296,8 @@ AlbumModel::addAlbums( const QList<Tomahawk::album_ptr>& albums )
if ( m_overwriteOnAdd )
clear();
emit loadingFinished();
int c = rowCount( QModelIndex() );
QPair< int, int > crows;
crows.first = c;

View File

@ -94,6 +94,8 @@ signals:
void trackCountChanged( unsigned int tracks );
void loadingStarted();
void loadingFinished();
private slots:
void onDataChanged();

View File

@ -22,6 +22,7 @@
#include <QKeyEvent>
#include <QPainter>
#include <QScrollBar>
#include <qmath.h>
#include "audio/audioengine.h"
#include "tomahawksettings.h"
@ -31,6 +32,7 @@
#include "albummodel.h"
#include "viewmanager.h"
#include "utils/logger.h"
#include "dynamic/widgets/LoadingSpinner.h"
#define SCROLL_TIMEOUT 280
@ -41,13 +43,16 @@ AlbumView::AlbumView( QWidget* parent )
: QListView( parent )
, m_model( 0 )
, m_proxyModel( 0 )
// , m_delegate( 0 )
, m_delegate( 0 )
, m_loadingSpinner( new LoadingSpinner( this ) )
{
setDragEnabled( true );
setDropIndicatorShown( false );
setDragDropOverwriteMode( false );
setUniformItemSizes( true );
setSpacing( 20 );
setSpacing( 16 );
setContentsMargins( 0, 0, 0, 0 );
setMouseTracking( true );
setResizeMode( Adjust );
setViewMode( IconMode );
@ -75,7 +80,9 @@ void
AlbumView::setProxyModel( AlbumProxyModel* model )
{
m_proxyModel = model;
setItemDelegate( new AlbumItemDelegate( this, m_proxyModel ) );
m_delegate = new AlbumItemDelegate( this, m_proxyModel );
connect( m_delegate, SIGNAL( updateIndex( QModelIndex ) ), this, SLOT( update( QModelIndex ) ) );
setItemDelegate( m_delegate );
QListView::setModel( m_proxyModel );
}
@ -104,6 +111,9 @@ AlbumView::setAlbumModel( AlbumModel* model )
connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) );
connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) );
connect( m_model, SIGNAL( loadingStarted() ), m_loadingSpinner, SLOT( fadeIn() ) );
connect( m_model, SIGNAL( loadingFinished() ), m_loadingSpinner, SLOT( fadeOut() ) );
setAcceptDrops( false );
onViewChanged(); // Fetch covers if albums were added to model before model was attached to view
}
@ -179,6 +189,30 @@ AlbumView::paintEvent( QPaintEvent* event )
}
void
AlbumView::resizeEvent( QResizeEvent* event )
{
QListView::resizeEvent( event );
#ifdef Q_WS_X11
int scrollbar = !verticalScrollBar()->isVisible() ? verticalScrollBar()->rect().width() : 0;
#else
int scrollbar = verticalScrollBar()->rect().width();
#endif
int rectWidth = contentsRect().width() - scrollbar - 16 - 3;
QSize itemSize = m_proxyModel->data( QModelIndex(), Qt::SizeHintRole ).toSize();
int itemsPerRow = qFloor( rectWidth / ( itemSize.width() + 16 ) );
int rightSpacing = rectWidth - ( itemsPerRow * ( itemSize.width() + 16 ) );
int newSpacing = 16 + floor( rightSpacing / ( itemsPerRow + 1 ) );
if ( itemsPerRow < 1 )
setSpacing( 16 );
else
setSpacing( newSpacing );
}
void
AlbumView::onFilterChanged( const QString& )
{

View File

@ -28,6 +28,8 @@
#include "albumproxymodel.h"
class AlbumModel;
class LoadingSpinner;
class AlbumItemDelegate;
class DLLEXPORT AlbumView : public QListView, public Tomahawk::ViewPage
{
@ -63,6 +65,7 @@ protected:
virtual void startDrag( Qt::DropActions supportedActions );
void paintEvent( QPaintEvent* event );
void resizeEvent( QResizeEvent* event );
private slots:
void onFilterChanged( const QString& filter );
@ -73,7 +76,8 @@ private slots:
private:
AlbumModel* m_model;
AlbumProxyModel* m_proxyModel;
// PlaylistItemDelegate* m_delegate;
AlbumItemDelegate* m_delegate;
LoadingSpinner* m_loadingSpinner;
QTimer m_timer;
};

View File

@ -158,7 +158,7 @@ ArtistView::onItemActivated( const QModelIndex& index )
if ( !item->artist().isNull() )
ViewManager::instance()->show( item->artist() );
else if ( !item->album().isNull() )
ViewManager::instance()->show( item->album() );
ViewManager::instance()->show( item->album(), m_model->mode() );
else if ( !item->result().isNull() && item->result()->isOnline() )
{
m_model->setCurrentItem( item->index );

View File

@ -52,8 +52,11 @@ CustomPlaylistView::CustomPlaylistView( CustomPlaylistView::PlaylistType type, c
}
}
CustomPlaylistView::~CustomPlaylistView()
{}
{
}
bool
CustomPlaylistView::isBeingPlayed() const
@ -61,6 +64,7 @@ CustomPlaylistView::isBeingPlayed() const
return AudioEngine::instance()->currentTrackPlaylist() == playlistInterface();
}
bool
CustomPlaylistView::jumpToCurrentTrack()
{
@ -80,7 +84,7 @@ CustomPlaylistView::generateTracks()
"FROM social_attributes, track, artist "
"WHERE social_attributes.id = track.id AND artist.id = track.artist AND social_attributes.k = 'Love' AND social_attributes.v = 'true' AND social_attributes.source %1 "
"GROUP BY track.id "
"ORDER BY counter DESC, social_attributes.timestamp DESC " ).arg( m_source->isLocal() ? "IS NULL" : QString( "=%1" ).arg( m_source->id() ) );
"ORDER BY counter DESC, social_attributes.timestamp DESC " ).arg( m_source->isLocal() ? "IS NULL" : QString( "= %1" ).arg( m_source->id() ) );
break;
case AllLovedTracks:
sql = QString( "SELECT track.name, artist.name, source, COUNT(*) as counter "
@ -96,6 +100,7 @@ CustomPlaylistView::generateTracks()
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
void
CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks )
{
@ -103,6 +108,7 @@ CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks )
m_model->append( q );
}
QString
CustomPlaylistView::title() const
{
@ -132,18 +138,21 @@ CustomPlaylistView::description() const
}
}
QString
CustomPlaylistView::longDescription() const
{
return QString();
}
QPixmap
CustomPlaylistView::pixmap() const
{
return QPixmap( RESPATH "images/loved_playlist.png" );
}
void
CustomPlaylistView::reload()
{
@ -153,7 +162,7 @@ CustomPlaylistView::reload()
void
CustomPlaylistView::sourceAdded( const source_ptr& s)
CustomPlaylistView::sourceAdded( const source_ptr& s )
{
connect( s.data(), SIGNAL( socialAttributesChanged() ), this, SLOT( reload() ) );
}

View File

@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -58,6 +58,9 @@ LoadingSpinner::~LoadingSpinner()
void
LoadingSpinner::fadeIn()
{
if ( isVisible() )
return;
show();
m_anim->start();

View File

@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -54,4 +54,4 @@ private:
#endif
class QPaintEvent;
class QPaintEvent;

View File

@ -384,7 +384,7 @@ PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int r
// so check if the drag originated in this playlist to determine whether or not to copy
#ifdef Q_WS_MAC
if ( !data->hasFormat( "application/tomahawk.playlist.id" ) ||
data->data( "application/tomahawk.playlist.id" ) != m_playlist->guid() )
( !m_playlist.isNull() && data->data( "application/tomahawk.playlist.id" ) != m_playlist->guid() ) )
dj->setDropAction( DropJob::Append );
#else
if ( action & Qt::CopyAction )

View File

@ -556,7 +556,8 @@ TrackView::mousePressEvent( QMouseEvent* event )
}
else
{
//TODO
artist_ptr artist = Artist::get( item->query()->artist() );
ViewManager::instance()->show( Album::get( artist, item->query()->album() ) );
}
break;
}

View File

@ -40,7 +40,7 @@ TreeItemDelegate::TreeItemDelegate( ArtistView* parent, TreeProxyModel* proxy )
, m_model( proxy )
{
m_nowPlayingIcon = QPixmap( RESPATH "images/now-playing-speaker.png" );
m_defaultAlbumCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" );
m_defaultAlbumCover = QPixmap( RESPATH "images/no-album-no-case.png" );
m_defaultArtistImage = QPixmap( RESPATH "images/no-artist-image-placeholder.png" );
}

View File

@ -38,7 +38,7 @@ TreeModel::TreeModel( QObject* parent )
, m_rootItem( new TreeModelItem( 0, this ) )
, m_infoId( uuid() )
, m_columnStyle( AllColumns )
, m_mode( Database )
, m_mode( DatabaseMode )
{
setIcon( QPixmap( RESPATH "images/music-icon.png" ) );
@ -576,7 +576,7 @@ TreeModel::addAlbums( const artist_ptr& artist, const QModelIndex& parent )
{
emit loadingStarted();
if ( m_mode == Database )
if ( m_mode == DatabaseMode )
{
DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( m_collection, artist );
cmd->setData( parent.row() );
@ -586,7 +586,7 @@ TreeModel::addAlbums( const artist_ptr& artist, const QModelIndex& parent )
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
else if ( m_mode == InfoSystem )
else if ( m_mode == InfoSystemMode )
{
Tomahawk::InfoSystem::InfoStringHash artistInfo;
artistInfo["artist"] = artist->name();
@ -612,7 +612,7 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent )
rows << parent.row();
rows << parent.parent().row();
if ( m_mode == Database )
if ( m_mode == DatabaseMode )
{
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_collection );
cmd->setAlbum( album.data() );
@ -623,17 +623,20 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent )
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
else if ( m_mode == InfoSystem )
else if ( m_mode == InfoSystemMode )
{
Tomahawk::InfoSystem::InfoStringHash artistInfo;
artistInfo["artist"] = album->artist()->name();
artistInfo["album"] = album->name();
m_receivedInfoData.remove( artistInfo );
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = m_infoId;
requestData.customData["rows"] = QVariant( rows );
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
requestData.type = Tomahawk::InfoSystem::InfoAlbumSongs;
requestData.timeoutMillis = 0;
requestData.allSources = true;
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
}
else
@ -826,7 +829,7 @@ TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QV
QStringList albums = returnedData[ "albums" ].toStringList();
QList<album_ptr> al;
InfoSystem::InfoStringHash inputInfo;
Tomahawk::InfoSystem::InfoStringHash inputInfo;
inputInfo = requestData.input.value< InfoSystem::InfoStringHash >();
artist_ptr artist = Artist::get( inputInfo[ "artist" ], false );
@ -845,12 +848,23 @@ TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QV
case Tomahawk::InfoSystem::InfoAlbumSongs:
{
if ( m_receivedInfoData.contains( requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >() ) )
break;
emit loadingFinished();
QVariantMap returnedData = output.value< QVariantMap >();
if ( returnedData.isEmpty() )
break;
m_receivedInfoData.insert( requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >() );
QStringList tracks = returnedData[ "tracks" ].toStringList();
QList<query_ptr> ql;
InfoSystem::InfoStringHash inputInfo;
inputInfo = requestData.input.value< InfoSystem::InfoStringHash >();
Tomahawk::InfoSystem::InfoStringHash inputInfo;
inputInfo = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
foreach ( const QString& trackName, tracks )
{

View File

@ -33,6 +33,7 @@
#include "infosystem/infosystem.h"
#include "dllmacro.h"
#include "typedefs.h"
class QMetaData;
@ -55,9 +56,6 @@ public:
enum ColumnStyle
{ AllColumns = 0, TrackOnly };
enum ModelMode
{ Database = 0, InfoSystem };
explicit TreeModel( QObject* parent = 0 );
virtual ~TreeModel();
@ -73,8 +71,8 @@ public:
virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const;
virtual ModelMode mode() const { return m_mode; }
virtual void setMode( ModelMode mode ) { m_mode = mode; }
virtual Tomahawk::ModelMode mode() const { return m_mode; }
virtual void setMode( Tomahawk::ModelMode mode ) { m_mode = mode; }
virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
@ -165,12 +163,13 @@ private:
QString m_description;
QPixmap m_icon;
ColumnStyle m_columnStyle;
ModelMode m_mode;
Tomahawk::ModelMode m_mode;
QList<Tomahawk::artist_ptr> m_artistsFilter;
Tomahawk::collection_ptr m_collection;
QHash<qlonglong, QPersistentModelIndex> m_coverHash;
QSet<Tomahawk::InfoSystem::InfoStringHash> m_receivedInfoData;
};
#endif // ALBUMMODEL_H

View File

@ -195,7 +195,7 @@ TreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent
TreeModelItem* pi = sourceModel()->itemFromIndex( sourceModel()->index( sourceRow, 0, sourceParent ) );
Q_ASSERT( pi );
if ( m_model->mode() == TreeModel::Database && !pi->result().isNull() )
if ( m_model->mode() == Tomahawk::DatabaseMode && !pi->result().isNull() )
{
QList< Tomahawk::result_ptr > rl = m_cache.values( sourceParent );
foreach ( const Tomahawk::result_ptr& result, rl )
@ -329,14 +329,34 @@ TreeProxyModel::siblingItem( int itemsAway )
Tomahawk::result_ptr
TreeProxyModel::siblingItem( int itemsAway, bool readOnly )
{
qDebug() << Q_FUNC_INFO;
QModelIndex idx = currentIndex();
if ( !idx.isValid() )
return Tomahawk::result_ptr();
if ( m_shuffled )
idx = index( qrand() % rowCount( idx.parent() ), 0, idx.parent() );
else if ( m_repeatMode == PlaylistInterface::RepeatOne )
idx = index( idx.row(), 0, idx.parent() );
else
idx = index( idx.row() + ( itemsAway > 0 ? 1 : -1 ), 0, idx.parent() );
if ( !idx.isValid() && m_repeatMode == PlaylistInterface::RepeatAll )
{
if ( itemsAway > 0 )
{
// reset to first item
idx = index( 0, 0, currentIndex().parent() );
}
else
{
// reset to last item
idx = index( rowCount( currentIndex().parent() ) - 1, 0, currentIndex().parent() );
}
}
// Try to find the next available PlaylistItem (with results)
if ( idx.isValid() ) do
{
idx = index( idx.row() + ( itemsAway > 0 ? 1 : -1 ), 0, idx.parent() );
if ( !idx.isValid() )
break;

Some files were not shown because too many files have changed in this diff Show More