From 4c5855c95d5bfe6bef998a13bc15bf369e11eaa8 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Mon, 9 Apr 2012 20:46:12 -0400 Subject: [PATCH 01/12] Add twitter info plugin. Still needs some work -- when it should delete itself (for instance if you disable the plugin and re-enable) it doesn't seem to, leading to twitter complaining about duplicate statuses. Also get a message about creating children for parent in different thread. Along the way, made lastfm plugin correctly switch to the right thread for the info plugin, fix a couple bugs (such as loving and unloving using the same type), and so on. Need to fix up xmpp info plugin to use the correct thread as well. Also, right now tweets indiscriminately when you love, should turn that off before merging to master. --- src/accounts/lastfm/LastFmAccount.cpp | 17 +- src/accounts/lastfm/lastfmplugin.cpp | 40 +++-- src/accounts/lastfm/lastfmplugin.h | 2 +- src/accounts/twitter/CMakeLists.txt | 2 + src/accounts/twitter/twitteraccount.cpp | 30 +++- src/accounts/twitter/twitteraccount.h | 6 +- src/accounts/twitter/twitterinfoplugin.cpp | 161 ++++++++++++++++++ src/accounts/twitter/twitterinfoplugin.h | 79 +++++++++ src/accounts/xmpp/XmppInfoPlugin.cpp | 1 + src/accounts/xmpp/XmppInfoPlugin.h | 1 + src/accounts/xmpp/sip/xmppsip.cpp | 1 - src/accounts/xmpp/xmppaccount.h | 2 +- src/libtomahawk/accounts/Account.cpp | 2 + src/libtomahawk/accounts/AccountManager.cpp | 3 - src/libtomahawk/globalactionmanager.cpp | 5 +- src/libtomahawk/infosystem/infosystem.cpp | 19 ++- src/libtomahawk/infosystem/infosystem.h | 2 + .../infosystem/infosystemcache.cpp | 8 +- .../infosystem/infosystemworker.cpp | 1 + src/libtomahawk/query.cpp | 4 +- 20 files changed, 347 insertions(+), 39 deletions(-) create mode 100644 src/accounts/twitter/twitterinfoplugin.cpp create mode 100644 src/accounts/twitter/twitterinfoplugin.h diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/accounts/lastfm/LastFmAccount.cpp index 7e4ac519f..f302fb8bf 100644 --- a/src/accounts/lastfm/LastFmAccount.cpp +++ b/src/accounts/lastfm/LastFmAccount.cpp @@ -70,12 +70,20 @@ LastFmAccount::LastFmAccount( const QString& accountId ) { hookupResolver(); } + + + if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() ) + { + infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); + Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); + } } LastFmAccount::~LastFmAccount() { - delete m_infoPlugin.data(); + if ( m_infoPlugin ) + m_infoPlugin.data()->deleteLater(); delete m_resolver.data(); } @@ -158,7 +166,9 @@ LastFmAccount::icon() const InfoPlugin* LastFmAccount::infoPlugin() { - return m_infoPlugin.data(); + if ( m_infoPlugin ) + return m_infoPlugin.data(); + return 0; } bool @@ -178,7 +188,8 @@ LastFmAccount::saveConfig() setScrobble( m_configWidget.data()->scrobble() ); } - m_infoPlugin.data()->settingsChanged(); + if ( m_infoPlugin ) + QTimer::singleShot( 0, m_infoPlugin.data(), SLOT( settingsChanged() ) ); } diff --git a/src/accounts/lastfm/lastfmplugin.cpp b/src/accounts/lastfm/lastfmplugin.cpp index 7e824fa53..cbec482ca 100644 --- a/src/accounts/lastfm/lastfmplugin.cpp +++ b/src/accounts/lastfm/lastfmplugin.cpp @@ -53,10 +53,10 @@ LastFmPlugin::LastFmPlugin( LastFmAccount* account ) lastfm::ws::ApiKey = "7194b85b6d1f424fe1668173a78c0c4a"; lastfm::ws::SharedSecret = "ba80f1df6d27ae63e9cb1d33ccf2052f"; - lastfm::ws::Username = m_account->username(); + lastfm::ws::Username = m_account.data()->username(); lastfm::setNetworkAccessManager( TomahawkUtils::nam() ); - m_pw = m_account->password(); + m_pw = m_account.data()->password(); //HACK work around a bug in liblastfm---it doesn't create its config dir, so when it // tries to write the track cache, it fails silently. until we have a fixed version, do this @@ -707,23 +707,26 @@ LastFmPlugin::artistImagesReturned() void LastFmPlugin::settingsChanged() { - if ( !m_scrobbler && m_account->scrobble() ) + if ( m_account.isNull() ) + return; + + if ( !m_scrobbler && m_account.data()->scrobble() ) { // can simply create the scrobbler - lastfm::ws::Username = m_account->username(); - m_pw = m_account->password(); + lastfm::ws::Username = m_account.data()->username(); + m_pw = m_account.data()->password(); createScrobbler(); } - else if ( m_scrobbler && !m_account->scrobble() ) + else if ( m_scrobbler && !m_account.data()->scrobble() ) { delete m_scrobbler; m_scrobbler = 0; } - else if ( m_account->username() != lastfm::ws::Username || - m_account->password() != m_pw ) + else if ( m_account.data()->username() != lastfm::ws::Username || + m_account.data()->password() != m_pw ) { - lastfm::ws::Username = m_account->username(); - m_pw = m_account->password(); + lastfm::ws::Username = m_account.data()->username(); + m_pw = m_account.data()->password(); // credentials have changed, have to re-create scrobbler for them to take effect if ( m_scrobbler ) { @@ -740,12 +743,12 @@ void LastFmPlugin::onAuthenticated() { QNetworkReply* authJob = dynamic_cast( sender() ); - if ( !authJob ) + if ( !authJob || m_account.isNull() ) { tLog() << Q_FUNC_INFO << "Help! No longer got a last.fm auth job!"; return; } - + if ( authJob->error() == QNetworkReply::NoError ) { lastfm::XmlQuery lfm = lastfm::XmlQuery( authJob->readAll() ); @@ -753,16 +756,16 @@ LastFmPlugin::onAuthenticated() if ( lfm.children( "error" ).size() > 0 ) { tLog() << "Error from authenticating with Last.fm service:" << lfm.text(); - m_account->setSessionKey( QByteArray() ); + m_account.data()->setSessionKey( QByteArray() ); } else { lastfm::ws::SessionKey = lfm[ "session" ][ "key" ].text(); - m_account->setSessionKey( lastfm::ws::SessionKey.toLatin1() ); + m_account.data()->setSessionKey( lastfm::ws::SessionKey.toLatin1() ); // qDebug() << "Got session key from last.fm"; - if ( m_account->scrobble() ) + if ( m_account.data()->scrobble() ) m_scrobbler = new lastfm::Audioscrobbler( "thk" ); } } @@ -778,7 +781,10 @@ LastFmPlugin::onAuthenticated() void LastFmPlugin::createScrobbler() { - if ( m_account->sessionKey().isEmpty() ) // no session key, so get one + if ( m_account.isNull() ) + return; + + if ( m_account.data()->sessionKey().isEmpty() ) // no session key, so get one { qDebug() << "LastFmPlugin::createScrobbler Session key is empty"; QString authToken = TomahawkUtils::md5( ( lastfm::ws::Username.toLower() + TomahawkUtils::md5( m_pw.toUtf8() ) ).toUtf8() ); @@ -794,7 +800,7 @@ LastFmPlugin::createScrobbler() else { qDebug() << "LastFmPlugin::createScrobbler Already have session key"; - lastfm::ws::SessionKey = m_account->sessionKey(); + lastfm::ws::SessionKey = m_account.data()->sessionKey(); m_scrobbler = new lastfm::Audioscrobbler( "thk" ); } diff --git a/src/accounts/lastfm/lastfmplugin.h b/src/accounts/lastfm/lastfmplugin.h index 76d490a37..c071ed7d5 100644 --- a/src/accounts/lastfm/lastfmplugin.h +++ b/src/accounts/lastfm/lastfmplugin.h @@ -79,7 +79,7 @@ private: void dataError( Tomahawk::InfoSystem::InfoRequestData requestData ); - Accounts::LastFmAccount* m_account; + QWeakPointer< Accounts::LastFmAccount > m_account; QList parseTrackList( QNetworkReply * reply ); lastfm::MutableTrack m_track; diff --git a/src/accounts/twitter/CMakeLists.txt b/src/accounts/twitter/CMakeLists.txt index 253bd4e03..62bcf83b6 100644 --- a/src/accounts/twitter/CMakeLists.txt +++ b/src/accounts/twitter/CMakeLists.txt @@ -8,6 +8,7 @@ add_definitions( -DACCOUNTDLLEXPORT_PRO ) set( twitterAccountSources twitteraccount.cpp + twitterinfoplugin.cpp twitterconfigwidget.cpp tomahawkoauthtwitter.cpp sip/twittersip.cpp @@ -15,6 +16,7 @@ set( twitterAccountSources set( twitterAccountHeaders twitteraccount.h + twitterinfoplugin.h twitterconfigwidget.h tomahawkoauthtwitter.h sip/twittersip.h diff --git a/src/accounts/twitter/twitteraccount.cpp b/src/accounts/twitter/twitteraccount.cpp index 92eaab161..ced1cccfc 100644 --- a/src/accounts/twitter/twitteraccount.cpp +++ b/src/accounts/twitter/twitteraccount.cpp @@ -21,6 +21,7 @@ #include "twitteraccount.h" #include "twitterconfigwidget.h" #include "accounts/twitter/tomahawkoauthtwitter.h" +#include "libtomahawk/infosystem/infosystem.h" #include "sip/SipPlugin.h" @@ -99,6 +100,19 @@ TwitterAccount::sipPlugin() } +Tomahawk::InfoSystem::InfoPlugin* +TwitterAccount::infoPlugin() +{ + if ( m_twitterInfoPlugin.isNull() ) + { + m_twitterInfoPlugin = QWeakPointer< Tomahawk::InfoSystem::TwitterInfoPlugin >( new Tomahawk::InfoSystem::TwitterInfoPlugin( this ) ); + + return m_twitterInfoPlugin.data(); + } + return m_twitterInfoPlugin.data(); +} + + void TwitterAccount::authenticate() { @@ -122,10 +136,14 @@ TwitterAccount::authenticate() void TwitterAccount::deauthenticate() { - if ( sipPlugin() ) + if ( m_twitterSipPlugin ) sipPlugin()->disconnectPlugin(); + if ( m_twitterInfoPlugin ) + m_twitterInfoPlugin.data()->deleteLater(); + m_isAuthenticated = false; + emit nowDeauthenticated(); } @@ -139,7 +157,7 @@ TwitterAccount::refreshTwitterAuth() delete m_twitterAuth.data(); Q_ASSERT( TomahawkUtils::nam() != 0 ); - qDebug() << Q_FUNC_INFO << " with nam " << TomahawkUtils::nam(); + tDebug() << Q_FUNC_INFO << " with nam " << TomahawkUtils::nam(); m_twitterAuth = QWeakPointer< TomahawkOAuthTwitter >( new TomahawkOAuthTwitter( TomahawkUtils::nam(), this ) ); if( m_twitterAuth.isNull() ) @@ -170,10 +188,18 @@ TwitterAccount::connectAuthVerifyReply( const QTweetUser &user ) sipPlugin()->connectPlugin(); + if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() ) + { + infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); + Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); + } + m_isAuthenticated = true; emit nowAuthenticated( m_twitterAuth, user ); } } + + QPixmap TwitterAccount::icon() const { return QPixmap( ":/twitter-icon.png" ); diff --git a/src/accounts/twitter/twitteraccount.h b/src/accounts/twitter/twitteraccount.h index 16dcf6242..fb8a08981 100644 --- a/src/accounts/twitter/twitteraccount.h +++ b/src/accounts/twitter/twitteraccount.h @@ -25,6 +25,7 @@ #include "tomahawkoauthtwitter.h" #include "sip/twittersip.h" +#include "twitterinfoplugin.h" #include "accounts/accountdllmacro.h" #include "accounts/Account.h" @@ -49,7 +50,7 @@ public: QString factoryId() const { return "twitteraccount"; } QString description() const { return tr( "Connect to your Twitter followers." ); } QPixmap icon() const { return QPixmap( ":/twitter-icon.png" ); } - AccountTypes types() const { return AccountTypes( SipType ); }; + AccountTypes types() const { return AccountTypes( SipType | StatusPushType ); }; Account* createAccount( const QString& pluginId = QString() ); }; @@ -69,7 +70,7 @@ public: ConnectionState connectionState() const; - Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; } + Tomahawk::InfoSystem::InfoPlugin* infoPlugin(); SipPlugin* sipPlugin(); QWidget* configurationWidget() { return m_configWidget.data(); } @@ -92,6 +93,7 @@ private: QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth; QWeakPointer< TwitterConfigWidget > m_configWidget; QWeakPointer< TwitterSipPlugin > m_twitterSipPlugin; + QWeakPointer< Tomahawk::InfoSystem::TwitterInfoPlugin > m_twitterInfoPlugin; // for settings access friend class TwitterConfigWidget; diff --git a/src/accounts/twitter/twitterinfoplugin.cpp b/src/accounts/twitter/twitterinfoplugin.cpp new file mode 100644 index 000000000..ba12660e5 --- /dev/null +++ b/src/accounts/twitter/twitterinfoplugin.cpp @@ -0,0 +1,161 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Dominik Schmidt + * Copyright 2012, Jeff Mitchell + * + * 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 . + */ + + +#include "twitterinfoplugin.h" + +#include "accounts/twitter/twitteraccount.h" + +#include +#include + +#include "globalactionmanager.h" +#include "utils/logger.h" + +namespace Tomahawk +{ + +namespace InfoSystem +{ + +TwitterInfoPlugin::TwitterInfoPlugin( Tomahawk::Accounts::TwitterAccount* account ) + : m_account( account ) +{ + m_supportedPushTypes << InfoLove; + + QVariantHash credentials = m_account->credentials(); + if ( credentials[ "oauthtoken" ].toString().isEmpty() || credentials[ "oauthtokensecret" ].toString().isEmpty() ) + { + tDebug() << "TwitterInfoPlugin has empty Twitter credentials; not connecting"; + return; + } + + if ( refreshTwitterAuth() ) + { + QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( m_twitterAuth.data(), this ); + connect( credVerifier, SIGNAL( parsedUser( const QTweetUser & ) ), SLOT( connectAuthVerifyReply( const QTweetUser & ) ) ); + credVerifier->verify(); + } +} + + +TwitterInfoPlugin::~TwitterInfoPlugin() +{ +} + + +bool +TwitterInfoPlugin::refreshTwitterAuth() +{ + tDebug() << Q_FUNC_INFO << " begin"; + if( !m_twitterAuth.isNull() ) + delete m_twitterAuth.data(); + + Q_ASSERT( TomahawkUtils::nam() != 0 ); + tDebug() << Q_FUNC_INFO << " with nam " << TomahawkUtils::nam(); + m_twitterAuth = QWeakPointer< TomahawkOAuthTwitter >( new TomahawkOAuthTwitter( TomahawkUtils::nam(), this ) ); + + if( m_twitterAuth.isNull() ) + return false; + + m_twitterAuth.data()->setOAuthToken( m_account->credentials()[ "oauthtoken" ].toString().toLatin1() ); + m_twitterAuth.data()->setOAuthTokenSecret( m_account->credentials()[ "oauthtokensecret" ].toString().toLatin1() ); + + return true; +} + + +void +TwitterInfoPlugin::connectAuthVerifyReply( const QTweetUser &user ) +{ + if ( user.id() == 0 ) + { + tDebug() << "TwitterInfoPlugin could not authenticate to Twitter"; + deleteLater(); + return; + } + else + { + tDebug() << "TwitterInfoPlugin successfully authenticated to Twitter"; + return; + } +} + + +void +TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) +{ + tDebug() << Q_FUNC_INFO; + if ( !isValid() ) + { + deleteLater(); + return; + } + + Tomahawk::InfoSystem::PushInfoPair pushInfoPair = pushData.infoPair; + + if ( !pushInfoPair.second.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + { + tDebug() << Q_FUNC_INFO << "Cannot convert input into an info string hash"; + return; + } + + Tomahawk::InfoSystem::InfoStringHash info = pushInfoPair.second.value< Tomahawk::InfoSystem::InfoStringHash >(); + + QString msg = tr( "Listening to \"%1\" by %2%3 and loving it! %4" ) + .arg( info[ "title" ] ) + .arg( info[ "artist" ] ) + .arg( info[ "album" ].isEmpty() ? QString() : QString( " %1" ).arg( tr( "on \"%1\"" ).arg( info[ "album" ] ) ) ) + .arg( pushInfoPair.first.contains( "shorturl" ) ? + pushInfoPair.first[ "shorturl" ].toUrl().toString() : + GlobalActionManager::instance()->openLink( info[ "title" ], info[ "artist" ], info[ "album" ] ).toString() ); + + QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( m_twitterAuth.data(), this ); + connect( statUpdate, SIGNAL( postedStatus(const QTweetStatus &) ), SLOT( postLovedStatusUpdateReply(const QTweetStatus &) ) ); + connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postLovedStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) ); + statUpdate->post( msg ); +} + + +void +TwitterInfoPlugin::postLovedStatusUpdateReply( const QTweetStatus& status ) +{ + if ( status.id() == 0 ) + tDebug() << Q_FUNC_INFO << "Failed to post loved status"; + else + tDebug() << Q_FUNC_INFO << "Successfully posted loved status"; +} + + +void +TwitterInfoPlugin::postLovedStatusUpdateError( QTweetNetBase::ErrorCode code, const QString& errorMsg ) +{ + tDebug() << Q_FUNC_INFO << "Error posting love message, error code is " << code << ", error message is " << errorMsg; +} + + +bool +TwitterInfoPlugin::isValid() const +{ + return !m_twitterAuth.isNull(); +} + +} + +} \ No newline at end of file diff --git a/src/accounts/twitter/twitterinfoplugin.h b/src/accounts/twitter/twitterinfoplugin.h new file mode 100644 index 000000000..e3da557a0 --- /dev/null +++ b/src/accounts/twitter/twitterinfoplugin.h @@ -0,0 +1,79 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Dominik Schmidt + * Copyright 2012, Jeff Mitchell + * + * 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 . + */ + +#ifndef TWITTERINFOPLUGIN_H +#define TWITTERINFOPLUGIN_H + +#include "infosystem/infosystem.h" +#include "accounts/twitter/tomahawkoauthtwitter.h" + +#include +#include +#include + +namespace Tomahawk { + + namespace Accounts { + class TwitterAccount; + } + + namespace InfoSystem { + + class TwitterInfoPlugin : public InfoPlugin + { + Q_OBJECT + + public: + TwitterInfoPlugin( Tomahawk::Accounts::TwitterAccount* account ); + virtual ~TwitterInfoPlugin(); + + public slots: + void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) + { + Q_UNUSED( criteria ); + Q_UNUSED( requestData ); + } + + protected slots: + void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ); + void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) + { + Q_UNUSED( requestData ); + } + + private slots: + void connectAuthVerifyReply( const QTweetUser &user ); + void postLovedStatusUpdateReply( const QTweetStatus& status ); + void postLovedStatusUpdateError( QTweetNetBase::ErrorCode code, const QString& errorMsg ); + + private: + bool refreshTwitterAuth(); + bool isValid() const; + + Tomahawk::Accounts::TwitterAccount* m_account; + QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth; + }; + + } + +} + +#endif // TWITTERINFOPLUGIN_H + +struct A; diff --git a/src/accounts/xmpp/XmppInfoPlugin.cpp b/src/accounts/xmpp/XmppInfoPlugin.cpp index 728ba4cf5..e13dd64eb 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.cpp +++ b/src/accounts/xmpp/XmppInfoPlugin.cpp @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2012, Dominik Schmidt + * Copyright 2012, Jeff Mitchell * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/accounts/xmpp/XmppInfoPlugin.h b/src/accounts/xmpp/XmppInfoPlugin.h index 223167524..fbe050966 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.h +++ b/src/accounts/xmpp/XmppInfoPlugin.h @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2012, Dominik Schmidt + * Copyright 2012, Jeff Mitchell * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/accounts/xmpp/sip/xmppsip.cpp b/src/accounts/xmpp/sip/xmppsip.cpp index 10fb265b4..da1c105bf 100644 --- a/src/accounts/xmpp/sip/xmppsip.cpp +++ b/src/accounts/xmpp/sip/xmppsip.cpp @@ -165,7 +165,6 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) XmppSipPlugin::~XmppSipPlugin() { - delete m_infoPlugin; delete m_avatarManager; delete m_roster; #ifndef ENABLE_HEADLESS diff --git a/src/accounts/xmpp/xmppaccount.h b/src/accounts/xmpp/xmppaccount.h index 8529d9e11..bae5fbc12 100644 --- a/src/accounts/xmpp/xmppaccount.h +++ b/src/accounts/xmpp/xmppaccount.h @@ -51,7 +51,7 @@ public: QString description() const { return tr( "Log on to your Jabber/XMPP account to connect to your friends" ); } QString factoryId() const { return "xmppaccount"; } QPixmap icon() const { return QPixmap( ":/xmpp-icon.png" ); } - AccountTypes types() const { return AccountTypes( SipType ); }; + AccountTypes types() const { return AccountTypes( SipType | StatusPushType ); }; Account* createAccount( const QString& pluginId = QString() ); }; diff --git a/src/libtomahawk/accounts/Account.cpp b/src/libtomahawk/accounts/Account.cpp index e8a293c2e..b43196f33 100644 --- a/src/libtomahawk/accounts/Account.cpp +++ b/src/libtomahawk/accounts/Account.cpp @@ -37,6 +37,8 @@ accountTypeToString( AccountType type ) case InfoType: case StatusPushType: return QObject::tr( "Status Updaters" ); + case NoType: + return QString(); } return QString(); diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index eb1f7b43d..507e9fe53 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -297,9 +297,6 @@ AccountManager::addAccount( Account* account ) if ( account->types() & Accounts::StatusPushType ) m_accountsByAccountType[ Accounts::StatusPushType ].append( account ); - if ( account->infoPlugin() ) - InfoSystem::InfoSystem::instance()->addInfoPlugin( account->infoPlugin() ); - emit added( account ); } diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index ffde78745..33a97aacc 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -125,6 +125,7 @@ GlobalActionManager::openLink( const QString& title, const QString& artist, cons void GlobalActionManager::shortenLink( const QUrl& url, const QVariant &callbackObj ) { + tDebug() << Q_FUNC_INFO << "callbackObj is valid: " << ( callbackObj.isValid() ? "true" : "false" ); if ( QThread::currentThread() != thread() ) { qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO; @@ -136,7 +137,7 @@ GlobalActionManager::shortenLink( const QUrl& url, const QVariant &callbackObj ) request.setUrl( url ); QNetworkReply *reply = TomahawkUtils::nam()->get( request ); - if ( !callbackObj.isValid() ) + if ( callbackObj.isValid() ) reply->setProperty( "callbackobj", callbackObj ); connect( reply, SIGNAL( finished() ), SLOT( shortenLinkRequestFinished() ) ); connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), SLOT( shortenLinkRequestError( QNetworkReply::NetworkError ) ) ); @@ -901,7 +902,7 @@ GlobalActionManager::shortenLinkRequestFinished() } QVariant callbackObj; - if ( reply->property( "callbackobj" ).canConvert< QVariant >() && reply->property( "callbackobj" ).isValid() ) + if ( reply->property( "callbackobj" ).isValid() ) callbackObj = reply->property( "callbackobj" ); // Check for the redirect attribute, as this should be the shortened link diff --git a/src/libtomahawk/infosystem/infosystem.cpp b/src/libtomahawk/infosystem/infosystem.cpp index c1f6c020b..5cafa1032 100644 --- a/src/libtomahawk/infosystem/infosystem.cpp +++ b/src/libtomahawk/infosystem/infosystem.cpp @@ -137,7 +137,7 @@ InfoSystem::init() bool InfoSystem::getInfo( const InfoRequestData &requestData ) { - qDebug() << Q_FUNC_INFO; + //qDebug() << Q_FUNC_INFO; if ( !m_inited || !m_infoSystemWorkerThreadController->worker() ) { init(); @@ -218,10 +218,27 @@ InfoSystem::addInfoPlugin( InfoPlugin* plugin ) QMetaObject::invokeMethod( this, "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPlugin*, plugin ) ); return; } + + if ( plugin->thread() != m_infoSystemWorkerThreadController->worker()->thread() ) + { + tDebug() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread()"; + return; + } + QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPlugin*, plugin ) ); } +QWeakPointer< QThread > +InfoSystem::workerThread() const +{ + if ( m_infoSystemWorkerThreadController->isRunning() && m_infoSystemWorkerThreadController->worker() ) + return QWeakPointer< QThread >( m_infoSystemWorkerThreadController->worker()->thread() ); + + return QWeakPointer< QThread >(); +} + + InfoSystemCacheThread::InfoSystemCacheThread( QObject *parent ) : QThread( parent ) { diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index 9f0d8a811..f7bab5884 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -282,6 +282,8 @@ public: bool pushInfo( InfoPushData pushData ); bool pushInfo( const QString &caller, const InfoTypeMap &input, const PushInfoFlags pushFlags ); + QWeakPointer< QThread > workerThread() const; + public slots: // InfoSystem takes ownership of InfoPlugins void addInfoPlugin( Tomahawk::InfoSystem::InfoPlugin* plugin ); diff --git a/src/libtomahawk/infosystem/infosystemcache.cpp b/src/libtomahawk/infosystem/infosystemcache.cpp index ac626ecd0..5a2503046 100644 --- a/src/libtomahawk/infosystem/infosystemcache.cpp +++ b/src/libtomahawk/infosystem/infosystemcache.cpp @@ -159,7 +159,7 @@ InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash criteri if ( !fileLocationHash.isEmpty() ) { //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"; + //qDebug() << Q_FUNC_INFO << "notInCache -- filelocationhash empty"; notInCache( sendingObj, criteria, requestData ); return; } @@ -169,7 +169,7 @@ InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash criteri if ( !dir.exists() ) { //Dir doesn't exist so clearly not in cache - qDebug() << Q_FUNC_INFO << "notInCache -- dir doesn't exist"; + //qDebug() << Q_FUNC_INFO << "notInCache -- dir doesn't exist"; notInCache( sendingObj, criteria, requestData ); return; } @@ -186,7 +186,7 @@ InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash criteri if ( !fileLocationHash.contains( criteriaHashVal ) ) { //Still didn't find it? It's really not in the cache then - qDebug() << Q_FUNC_INFO << "notInCache -- filelocationhash doesn't contain criteria val"; + //qDebug() << Q_FUNC_INFO << "notInCache -- filelocationhash doesn't contain criteria val"; notInCache( sendingObj, criteria, requestData ); return; } @@ -250,7 +250,7 @@ InfoSystemCache::notInCache( QObject *receiver, Tomahawk::InfoSystem::InfoString void InfoSystemCache::updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output ) { - qDebug() << Q_FUNC_INFO; + //qDebug() << Q_FUNC_INFO; const QString criteriaHashVal = criteriaMd5( criteria ); const QString criteriaHashValWithType = criteriaMd5( criteria, type ); const QString cacheDir = m_cacheBaseDir + QString::number( (int)type ); diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index be7fb4f2b..ce0b35e6a 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -106,6 +106,7 @@ InfoSystemWorker::init( Tomahawk::InfoSystem::InfoSystemCache* cache ) void InfoSystemWorker::addInfoPlugin( InfoPlugin* plugin ) { + tDebug() << Q_FUNC_INFO << plugin; InfoPluginPtr weakptr( plugin ); m_plugins.append( weakptr ); registerInfoTypes( weakptr, weakptr.data()->supportedGetTypes(), weakptr.data()->supportedPushTypes() ); diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 0702cad40..2b9cabc86 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -588,9 +588,9 @@ Query::setLoved( bool loved ) trackInfo["album"] = album(); Tomahawk::InfoSystem::InfoPushData pushData ( id(), - Tomahawk::InfoSystem::InfoLove, + ( loved ? Tomahawk::InfoSystem::InfoLove : Tomahawk::InfoSystem::InfoUnLove ), QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ), - Tomahawk::InfoSystem::PushNoFlag ); + Tomahawk::InfoSystem::PushShortUrlFlag ); Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData ); From 25fba84b32f72cb7cdfff176e6a950fab1e9bf6b Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Mon, 9 Apr 2012 23:52:06 -0400 Subject: [PATCH 02/12] This should hopefully get rid of the messages about parent being in the wrong thread --- src/accounts/lastfm/LastFmAccount.cpp | 1 + src/accounts/lastfm/lastfmplugin.cpp | 10 ++++++++++ src/accounts/lastfm/lastfmplugin.h | 1 + src/accounts/twitter/twitteraccount.cpp | 1 + src/accounts/twitter/twitterinfoplugin.cpp | 11 +++++++++++ src/accounts/twitter/twitterinfoplugin.h | 1 + 6 files changed, 25 insertions(+) diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/accounts/lastfm/LastFmAccount.cpp index f302fb8bf..a7f566850 100644 --- a/src/accounts/lastfm/LastFmAccount.cpp +++ b/src/accounts/lastfm/LastFmAccount.cpp @@ -76,6 +76,7 @@ LastFmAccount::LastFmAccount( const QString& accountId ) { infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); + QMetaObject::invokeMethod( infoPlugin(), "init", Qt::QueuedConnection ); } } diff --git a/src/accounts/lastfm/lastfmplugin.cpp b/src/accounts/lastfm/lastfmplugin.cpp index cbec482ca..3a9275323 100644 --- a/src/accounts/lastfm/lastfmplugin.cpp +++ b/src/accounts/lastfm/lastfmplugin.cpp @@ -46,7 +46,17 @@ LastFmPlugin::LastFmPlugin( LastFmAccount* account ) { m_supportedGetTypes << InfoAlbumCoverArt << InfoArtistImages << InfoArtistSimilars << InfoArtistSongs << InfoChart << InfoChartCapabilities; m_supportedPushTypes << InfoSubmitScrobble << InfoSubmitNowPlaying << InfoLove << InfoUnLove; +} + +void +LastFmPlugin::init() +{ + if ( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() && thread() != Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ) + { + tDebug() << "Failure: move to the worker thread before running init"; + return; + } // Flush session key cache // TODO WHY FLUSH // m_account->setSessionKey( QByteArray() ); diff --git a/src/accounts/lastfm/lastfmplugin.h b/src/accounts/lastfm/lastfmplugin.h index c071ed7d5..088bf4199 100644 --- a/src/accounts/lastfm/lastfmplugin.h +++ b/src/accounts/lastfm/lastfmplugin.h @@ -49,6 +49,7 @@ public: virtual ~LastFmPlugin(); public slots: + void init(); void settingsChanged(); void onAuthenticated(); diff --git a/src/accounts/twitter/twitteraccount.cpp b/src/accounts/twitter/twitteraccount.cpp index ced1cccfc..ed183db9a 100644 --- a/src/accounts/twitter/twitteraccount.cpp +++ b/src/accounts/twitter/twitteraccount.cpp @@ -192,6 +192,7 @@ TwitterAccount::connectAuthVerifyReply( const QTweetUser &user ) { infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); + QMetaObject::invokeMethod( infoPlugin(), "init", Qt::QueuedConnection ); } m_isAuthenticated = true; diff --git a/src/accounts/twitter/twitterinfoplugin.cpp b/src/accounts/twitter/twitterinfoplugin.cpp index ba12660e5..22a47a25f 100644 --- a/src/accounts/twitter/twitterinfoplugin.cpp +++ b/src/accounts/twitter/twitterinfoplugin.cpp @@ -38,7 +38,18 @@ TwitterInfoPlugin::TwitterInfoPlugin( Tomahawk::Accounts::TwitterAccount* accoun : m_account( account ) { m_supportedPushTypes << InfoLove; +} + +void +TwitterInfoPlugin::init() +{ + if ( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() && thread() != Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ) + { + tDebug() << "Failure: move to the worker thread before running init"; + return; + } + QVariantHash credentials = m_account->credentials(); if ( credentials[ "oauthtoken" ].toString().isEmpty() || credentials[ "oauthtokensecret" ].toString().isEmpty() ) { diff --git a/src/accounts/twitter/twitterinfoplugin.h b/src/accounts/twitter/twitterinfoplugin.h index e3da557a0..77242754d 100644 --- a/src/accounts/twitter/twitterinfoplugin.h +++ b/src/accounts/twitter/twitterinfoplugin.h @@ -44,6 +44,7 @@ namespace Tomahawk { virtual ~TwitterInfoPlugin(); public slots: + void init(); void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( criteria ); From 4eaff7a45f15f353cc854b46f3c5da4be986a36a Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 10 Apr 2012 12:43:47 -0400 Subject: [PATCH 03/12] Get rid of double-additions of info plugins. Still not sure why it doesn't seem to delete itself. --- src/accounts/twitter/twitteraccount.cpp | 7 +++++-- src/accounts/twitter/twitterinfoplugin.cpp | 9 +++++---- src/libtomahawk/infosystem/infosystemworker.cpp | 7 +++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/accounts/twitter/twitteraccount.cpp b/src/accounts/twitter/twitteraccount.cpp index ed183db9a..899f87de7 100644 --- a/src/accounts/twitter/twitteraccount.cpp +++ b/src/accounts/twitter/twitteraccount.cpp @@ -50,7 +50,7 @@ TwitterAccount::TwitterAccount( const QString &accountId ) , m_isAuthenticated( false ) { setAccountServiceName( "Twitter" ); - setTypes( AccountTypes( InfoType | SipType ) ); + setTypes( AccountTypes( StatusPushType | SipType ) ); qDebug() << "Got cached peers:" << configuration() << configuration()[ "cachedpeers" ]; @@ -120,12 +120,13 @@ TwitterAccount::authenticate() if ( credentials()[ "oauthtoken" ].toString().isEmpty() || credentials()[ "oauthtokensecret" ].toString().isEmpty() ) { - qDebug() << "TwitterSipPlugin has empty Twitter credentials; not connecting"; + tDebug() << Q_FUNC_INFO << "TwitterSipPlugin has empty Twitter credentials; not connecting"; return; } if ( refreshTwitterAuth() ) { + tDebug() << Q_FUNC_INFO << "Verifying credentials"; QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( m_twitterAuth.data(), this ); connect( credVerifier, SIGNAL( parsedUser( const QTweetUser & ) ), SLOT( connectAuthVerifyReply( const QTweetUser & ) ) ); credVerifier->verify(); @@ -136,6 +137,8 @@ TwitterAccount::authenticate() void TwitterAccount::deauthenticate() { + tDebug() << Q_FUNC_INFO; + if ( m_twitterSipPlugin ) sipPlugin()->disconnectPlugin(); diff --git a/src/accounts/twitter/twitterinfoplugin.cpp b/src/accounts/twitter/twitterinfoplugin.cpp index 22a47a25f..6811b6b8c 100644 --- a/src/accounts/twitter/twitterinfoplugin.cpp +++ b/src/accounts/twitter/twitterinfoplugin.cpp @@ -68,18 +68,19 @@ TwitterInfoPlugin::init() TwitterInfoPlugin::~TwitterInfoPlugin() { + tDebug() << Q_FUNC_INFO; } bool TwitterInfoPlugin::refreshTwitterAuth() { - tDebug() << Q_FUNC_INFO << " begin"; + tDebug() << Q_FUNC_INFO << " begin" << this; if( !m_twitterAuth.isNull() ) delete m_twitterAuth.data(); Q_ASSERT( TomahawkUtils::nam() != 0 ); - tDebug() << Q_FUNC_INFO << " with nam " << TomahawkUtils::nam(); + tDebug() << Q_FUNC_INFO << " with nam " << TomahawkUtils::nam() << this; m_twitterAuth = QWeakPointer< TomahawkOAuthTwitter >( new TomahawkOAuthTwitter( TomahawkUtils::nam(), this ) ); if( m_twitterAuth.isNull() ) @@ -97,13 +98,13 @@ TwitterInfoPlugin::connectAuthVerifyReply( const QTweetUser &user ) { if ( user.id() == 0 ) { - tDebug() << "TwitterInfoPlugin could not authenticate to Twitter"; + tDebug() << "TwitterInfoPlugin could not authenticate to Twitter" << this; deleteLater(); return; } else { - tDebug() << "TwitterInfoPlugin successfully authenticated to Twitter"; + tDebug() << "TwitterInfoPlugin successfully authenticated to Twitter" << this; return; } } diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index ce0b35e6a..a0ba17c05 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -107,6 +107,13 @@ void InfoSystemWorker::addInfoPlugin( InfoPlugin* plugin ) { tDebug() << Q_FUNC_INFO << plugin; + foreach ( InfoPluginPtr ptr, m_plugins ) + { + if ( ptr.data() == plugin ) + tDebug() << Q_FUNC_INFO << "This plugin is already added to the infosystem."; + return; + } + InfoPluginPtr weakptr( plugin ); m_plugins.append( weakptr ); registerInfoTypes( weakptr, weakptr.data()->supportedGetTypes(), weakptr.data()->supportedPushTypes() ); From 54aef2cd2e482809c71b19bc0e0ba4d53f39dbe7 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 10 Apr 2012 16:39:12 -0400 Subject: [PATCH 04/12] More work towards cleaning up and making safer the info plugins. Twitter should be pretty good, but need to make lastfm and xmpp use the same paradigm --- src/accounts/lastfm/LastFmAccount.cpp | 10 +-- src/accounts/lastfm/LastFmAccount.h | 2 +- src/accounts/spotify/SpotifyAccount.h | 2 +- src/accounts/twitter/twitteraccount.cpp | 45 ++++++++--- src/accounts/twitter/twitteraccount.h | 4 +- src/accounts/twitter/twitterinfoplugin.cpp | 2 + src/accounts/xmpp/sip/xmppsip.cpp | 9 +-- src/accounts/xmpp/sip/xmppsip.h | 4 +- src/accounts/xmpp/xmppaccount.cpp | 4 +- src/accounts/xmpp/xmppaccount.h | 2 +- src/accounts/zeroconf/zeroconfaccount.h | 2 +- src/libtomahawk/accounts/Account.h | 9 +-- src/libtomahawk/accounts/AccountManager.cpp | 38 +++++++-- src/libtomahawk/accounts/AccountManager.h | 5 +- src/libtomahawk/accounts/ResolverAccount.h | 2 +- src/libtomahawk/audio/audioengine.cpp | 1 + src/libtomahawk/infosystem/infosystem.cpp | 46 +++++++++-- src/libtomahawk/infosystem/infosystem.h | 6 +- .../infosystem/infosystemworker.cpp | 81 ++++++++++++++----- src/libtomahawk/infosystem/infosystemworker.h | 7 +- src/musicscanner.cpp | 3 +- src/scanmanager.cpp | 1 - src/tomahawkapp.cpp | 31 ++++--- src/tomahawkapp.h | 1 + 24 files changed, 227 insertions(+), 90 deletions(-) diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/accounts/lastfm/LastFmAccount.cpp index a7f566850..1561d49db 100644 --- a/src/accounts/lastfm/LastFmAccount.cpp +++ b/src/accounts/lastfm/LastFmAccount.cpp @@ -74,9 +74,9 @@ LastFmAccount::LastFmAccount( const QString& accountId ) if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() ) { - infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); + infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - QMetaObject::invokeMethod( infoPlugin(), "init", Qt::QueuedConnection ); + QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); } } @@ -164,12 +164,12 @@ LastFmAccount::icon() const } -InfoPlugin* +InfoPluginPtr LastFmAccount::infoPlugin() { if ( m_infoPlugin ) - return m_infoPlugin.data(); - return 0; + return InfoPluginPtr( m_infoPlugin.data() ); + return InfoPluginPtr(); } bool diff --git a/src/accounts/lastfm/LastFmAccount.h b/src/accounts/lastfm/LastFmAccount.h index 7988c37d6..e7fc5adf6 100644 --- a/src/accounts/lastfm/LastFmAccount.h +++ b/src/accounts/lastfm/LastFmAccount.h @@ -72,7 +72,7 @@ public: virtual void authenticate(); virtual SipPlugin* sipPlugin() { return 0; } - virtual Tomahawk::InfoSystem::InfoPlugin* infoPlugin(); + virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin(); virtual bool isAuthenticated() const; diff --git a/src/accounts/spotify/SpotifyAccount.h b/src/accounts/spotify/SpotifyAccount.h index f83021177..323c989a3 100644 --- a/src/accounts/spotify/SpotifyAccount.h +++ b/src/accounts/spotify/SpotifyAccount.h @@ -66,7 +66,7 @@ public: virtual QPixmap icon() const; virtual QWidget* aclWidget() { return 0; } - virtual InfoSystem::InfoPlugin* infoPlugin() { return 0; } + virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); } virtual SipPlugin* sipPlugin() { return 0; } void addPlaylist( const QString &qid, const QString& title, QList< Tomahawk::query_ptr > tracks ); diff --git a/src/accounts/twitter/twitteraccount.cpp b/src/accounts/twitter/twitteraccount.cpp index 899f87de7..fca1b9932 100644 --- a/src/accounts/twitter/twitteraccount.cpp +++ b/src/accounts/twitter/twitteraccount.cpp @@ -48,6 +48,7 @@ TwitterAccountFactory::createAccount( const QString& accountId ) TwitterAccount::TwitterAccount( const QString &accountId ) : Account( accountId ) , m_isAuthenticated( false ) + , m_isAuthenticating( false ) { setAccountServiceName( "Twitter" ); setTypes( AccountTypes( StatusPushType | SipType ) ); @@ -100,22 +101,48 @@ TwitterAccount::sipPlugin() } -Tomahawk::InfoSystem::InfoPlugin* +Tomahawk::InfoSystem::InfoPluginPtr TwitterAccount::infoPlugin() { if ( m_twitterInfoPlugin.isNull() ) { m_twitterInfoPlugin = QWeakPointer< Tomahawk::InfoSystem::TwitterInfoPlugin >( new Tomahawk::InfoSystem::TwitterInfoPlugin( this ) ); - return m_twitterInfoPlugin.data(); + return Tomahawk::InfoSystem::InfoPluginPtr( m_twitterInfoPlugin.data() ); } - return m_twitterInfoPlugin.data(); + return Tomahawk::InfoSystem::InfoPluginPtr( m_twitterInfoPlugin.data() ); } void TwitterAccount::authenticate() { + // Since we need to have a chance for deletion (via the infosystem) to work on the info plugin, we put this on the event loop + tDebug() << Q_FUNC_INFO; + QTimer::singleShot( 0, this, SLOT( authenticateSlot() ) ); +} + + +void +TwitterAccount::authenticateSlot() +{ + tDebug() << Q_FUNC_INFO; + if ( m_twitterInfoPlugin.isNull() ) + { + if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() ) + { + infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); + Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); + QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); + } + } + + if ( m_isAuthenticating ) + { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Already authenticating"; + return; + } + tDebug() << Q_FUNC_INFO << "credentials: " << credentials().keys(); if ( credentials()[ "oauthtoken" ].toString().isEmpty() || credentials()[ "oauthtokensecret" ].toString().isEmpty() ) @@ -126,6 +153,7 @@ TwitterAccount::authenticate() if ( refreshTwitterAuth() ) { + m_isAuthenticating = true; tDebug() << Q_FUNC_INFO << "Verifying credentials"; QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( m_twitterAuth.data(), this ); connect( credVerifier, SIGNAL( parsedUser( const QTweetUser & ) ), SLOT( connectAuthVerifyReply( const QTweetUser & ) ) ); @@ -143,9 +171,10 @@ TwitterAccount::deauthenticate() sipPlugin()->disconnectPlugin(); if ( m_twitterInfoPlugin ) - m_twitterInfoPlugin.data()->deleteLater(); + Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( m_twitterInfoPlugin.data() ); m_isAuthenticated = false; + m_isAuthenticating = false; emit nowDeauthenticated(); } @@ -176,6 +205,7 @@ TwitterAccount::refreshTwitterAuth() void TwitterAccount::connectAuthVerifyReply( const QTweetUser &user ) { + m_isAuthenticating = false; if ( user.id() == 0 ) { qDebug() << "TwitterAccount could not authenticate to Twitter"; @@ -191,13 +221,6 @@ TwitterAccount::connectAuthVerifyReply( const QTweetUser &user ) sipPlugin()->connectPlugin(); - if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() ) - { - infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); - Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - QMetaObject::invokeMethod( infoPlugin(), "init", Qt::QueuedConnection ); - } - m_isAuthenticated = true; emit nowAuthenticated( m_twitterAuth, user ); } diff --git a/src/accounts/twitter/twitteraccount.h b/src/accounts/twitter/twitteraccount.h index fb8a08981..2ec8e4079 100644 --- a/src/accounts/twitter/twitteraccount.h +++ b/src/accounts/twitter/twitteraccount.h @@ -70,7 +70,7 @@ public: ConnectionState connectionState() const; - Tomahawk::InfoSystem::InfoPlugin* infoPlugin(); + Tomahawk::InfoSystem::InfoPluginPtr infoPlugin(); SipPlugin* sipPlugin(); QWidget* configurationWidget() { return m_configWidget.data(); } @@ -84,12 +84,14 @@ signals: void nowDeauthenticated(); private slots: + void authenticateSlot(); void configDialogAuthedSignalSlot( bool authed ); void connectAuthVerifyReply( const QTweetUser &user ); private: QIcon m_icon; bool m_isAuthenticated; + bool m_isAuthenticating; QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth; QWeakPointer< TwitterConfigWidget > m_configWidget; QWeakPointer< TwitterSipPlugin > m_twitterSipPlugin; diff --git a/src/accounts/twitter/twitterinfoplugin.cpp b/src/accounts/twitter/twitterinfoplugin.cpp index 6811b6b8c..ae8fb373e 100644 --- a/src/accounts/twitter/twitterinfoplugin.cpp +++ b/src/accounts/twitter/twitterinfoplugin.cpp @@ -116,6 +116,7 @@ TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) tDebug() << Q_FUNC_INFO; if ( !isValid() ) { + tDebug() << Q_FUNC_INFO << "Plugin not valid, deleting and returning"; deleteLater(); return; } @@ -141,6 +142,7 @@ TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( m_twitterAuth.data(), this ); connect( statUpdate, SIGNAL( postedStatus(const QTweetStatus &) ), SLOT( postLovedStatusUpdateReply(const QTweetStatus &) ) ); connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postLovedStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) ); + tDebug() << Q_FUNC_INFO << "Posting message: " << msg; statUpdate->post( msg ); } diff --git a/src/accounts/xmpp/sip/xmppsip.cpp b/src/accounts/xmpp/sip/xmppsip.cpp index da1c105bf..698db7613 100644 --- a/src/accounts/xmpp/sip/xmppsip.cpp +++ b/src/accounts/xmpp/sip/xmppsip.cpp @@ -86,7 +86,6 @@ JreenMessageHandler(QtMsgType type, const char *msg) XmppSipPlugin::XmppSipPlugin( Account *account ) : SipPlugin( account ) - , m_infoPlugin( 0 ) , m_state( Account::Disconnected ) #ifndef ENABLE_HEADLESS , m_menu( 0 ) @@ -174,10 +173,10 @@ XmppSipPlugin::~XmppSipPlugin() } -InfoSystem::InfoPlugin* +InfoSystem::InfoPluginPtr XmppSipPlugin::infoPlugin() { - return m_infoPlugin; + return InfoSystem::InfoPluginPtr( m_infoPlugin.data() ); } @@ -273,8 +272,8 @@ XmppSipPlugin::onConnect() // load XmppInfoPlugin if( !m_infoPlugin ) { - m_infoPlugin = new Tomahawk::InfoSystem::XmppInfoPlugin( this ); - InfoSystem::InfoSystem::instance()->addInfoPlugin( m_infoPlugin ); + m_infoPlugin = QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin >( new Tomahawk::InfoSystem::XmppInfoPlugin( this ) ); + InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); } //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P diff --git a/src/accounts/xmpp/sip/xmppsip.h b/src/accounts/xmpp/sip/xmppsip.h index 33b7b61dd..0a56ad9fa 100644 --- a/src/accounts/xmpp/sip/xmppsip.h +++ b/src/accounts/xmpp/sip/xmppsip.h @@ -67,7 +67,7 @@ public: //FIXME: Make this more correct virtual bool isValid() const { return true; } - Tomahawk::InfoSystem::InfoPlugin* infoPlugin(); + Tomahawk::InfoSystem::InfoPluginPtr infoPlugin(); #ifndef ENABLE_HEADLESS virtual QMenu* menu(); @@ -131,7 +131,7 @@ private: int m_currentPort; QString m_currentResource; - Tomahawk::InfoSystem::InfoPlugin* m_infoPlugin; + QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin> m_infoPlugin; Tomahawk::Accounts::Account::ConnectionState m_state; // sort out diff --git a/src/accounts/xmpp/xmppaccount.cpp b/src/accounts/xmpp/xmppaccount.cpp index 4d79fb7fa..cda891237 100644 --- a/src/accounts/xmpp/xmppaccount.cpp +++ b/src/accounts/xmpp/xmppaccount.cpp @@ -91,13 +91,13 @@ XmppAccount::saveConfig() } -InfoSystem::InfoPlugin* +InfoSystem::InfoPluginPtr XmppAccount::infoPlugin() { if( !m_xmppSipPlugin.isNull() ) return m_xmppSipPlugin.data()->infoPlugin(); - return 0; + return InfoSystem::InfoPluginPtr(); } diff --git a/src/accounts/xmpp/xmppaccount.h b/src/accounts/xmpp/xmppaccount.h index bae5fbc12..7b8d215c6 100644 --- a/src/accounts/xmpp/xmppaccount.h +++ b/src/accounts/xmpp/xmppaccount.h @@ -69,7 +69,7 @@ public: void deauthenticate(); bool isAuthenticated() const; - Tomahawk::InfoSystem::InfoPlugin* infoPlugin(); + Tomahawk::InfoSystem::InfoPluginPtr infoPlugin(); SipPlugin* sipPlugin(); diff --git a/src/accounts/zeroconf/zeroconfaccount.h b/src/accounts/zeroconf/zeroconfaccount.h index 29a6673fd..4733cf22b 100644 --- a/src/accounts/zeroconf/zeroconfaccount.h +++ b/src/accounts/zeroconf/zeroconfaccount.h @@ -64,7 +64,7 @@ public: bool isAuthenticated() const; ConnectionState connectionState() const; - Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; } + virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); } SipPlugin* sipPlugin(); QWidget* configurationWidget() { return 0; } diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h index 43e98ff67..66349a724 100644 --- a/src/libtomahawk/accounts/Account.h +++ b/src/libtomahawk/accounts/Account.h @@ -31,16 +31,13 @@ #include "dllmacro.h" #include "tomahawksettings.h" +#include "libtomahawk/infosystem/infosystem.h" + class SipPlugin; namespace Tomahawk { -namespace InfoSystem -{ - class InfoPlugin; -} - namespace Accounts { @@ -100,7 +97,7 @@ public: virtual QString errorMessage() const { QMutexLocker locker( &m_mutex ); return m_cachedError; } - virtual Tomahawk::InfoSystem::InfoPlugin* infoPlugin() = 0; + virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() = 0; virtual SipPlugin* sipPlugin() = 0; AccountTypes types() const; diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index 507e9fe53..7c3f68035 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -51,14 +51,7 @@ AccountManager::AccountManager( QObject *parent ) { s_instance = this; - connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( onSettingsChanged() ) ); - - loadPluginFactories( findPluginFactories() ); - - // We include the resolver factory manually, not in a plugin - ResolverAccountFactory* f = new ResolverAccountFactory(); - m_accountFactories[ f->factoryId() ] = f; - registerAccountFactoryForFilesystem( f ); + QTimer::singleShot( 0, this, SLOT( init() ) ); } @@ -72,6 +65,29 @@ AccountManager::~AccountManager() } +void +AccountManager::init() +{ + if ( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().isNull() ) + { + //We need the info system worker to be alive so that we can move info plugins into its thread + QTimer::singleShot( 0, this, SLOT( init() ) ); + return; + } + + connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( onSettingsChanged() ) ); + + loadPluginFactories( findPluginFactories() ); + + // We include the resolver factory manually, not in a plugin + ResolverAccountFactory* f = new ResolverAccountFactory(); + m_accountFactories[ f->factoryId() ] = f; + registerAccountFactoryForFilesystem( f ); + + emit ready(); +} + + QStringList AccountManager::findPluginFactories() { @@ -180,6 +196,7 @@ AccountManager::loadPluginFactory( const QString& path ) void AccountManager::enableAccount( Account* account ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; if ( account->enabled() ) return; @@ -195,6 +212,7 @@ AccountManager::enableAccount( Account* account ) void AccountManager::disableAccount( Account* account ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; if ( !account->enabled() ) return; @@ -209,6 +227,7 @@ AccountManager::disableAccount( Account* account ) void AccountManager::connectAll() { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; foreach( Account* acc, m_accounts ) { acc->authenticate(); @@ -222,6 +241,7 @@ AccountManager::connectAll() void AccountManager::disconnectAll() { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; foreach( Account* acc, m_enabledAccounts ) acc->deauthenticate(); @@ -234,6 +254,7 @@ AccountManager::disconnectAll() void AccountManager::toggleAccountsConnected() { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; if ( m_connected ) disconnectAll(); else @@ -367,6 +388,7 @@ AccountManager::hookupAccount( Account* account ) const void AccountManager::hookupAndEnable( Account* account, bool startup ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; SipPlugin* p = account->sipPlugin(); if ( p ) SipHandler::instance()->hookUpPlugin( p ); diff --git a/src/libtomahawk/accounts/AccountManager.h b/src/libtomahawk/accounts/AccountManager.h index 16dcf72fc..1e1820476 100644 --- a/src/libtomahawk/accounts/AccountManager.h +++ b/src/libtomahawk/accounts/AccountManager.h @@ -43,7 +43,7 @@ public: explicit AccountManager( QObject *parent ); virtual ~AccountManager(); - + void loadFromConfig(); void initSIP(); @@ -84,6 +84,8 @@ public slots: void toggleAccountsConnected(); signals: + void ready(); + void added( Tomahawk::Accounts::Account* ); void removed( Tomahawk::Accounts::Account* ); @@ -94,6 +96,7 @@ signals: void stateChanged( Account* p, Accounts::Account::ConnectionState state ); private slots: + void init(); void onStateChanged( Tomahawk::Accounts::Account::ConnectionState state ); void onError( int code, const QString& msg ); diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index b115d8fc4..4846d0e59 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -80,7 +80,7 @@ public: // Not relevant virtual QPixmap icon() const { return QPixmap(); } virtual SipPlugin* sipPlugin() { return 0; } - virtual Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; } + virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); } virtual QWidget* aclWidget() { return 0; } private slots: diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 36681e8ab..f5c57489d 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -328,6 +328,7 @@ AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType ty else { _detail::Closure* closure = NewClosure( m_currentTrack->album().data(), SIGNAL( updated() ), const_cast< AudioEngine* >( this ), SLOT( onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType ) ), type ); + Q_UNUSED( closure ); m_currentTrack->album()->cover( QSize( 0, 0 ) ); } #endif diff --git a/src/libtomahawk/infosystem/infosystem.cpp b/src/libtomahawk/infosystem/infosystem.cpp index 5cafa1032..9db1bfe80 100644 --- a/src/libtomahawk/infosystem/infosystem.cpp +++ b/src/libtomahawk/infosystem/infosystem.cpp @@ -210,22 +210,56 @@ InfoSystem::pushInfo( const QString &caller, const InfoTypeMap &input, const Pus void -InfoSystem::addInfoPlugin( InfoPlugin* plugin ) +InfoSystem::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) { - // Init is not complete (waiting for worker th read to start and create worker object) so keep trying till then + // Init is not complete (waiting for worker thread to start and create worker object) so keep trying till then if ( !m_inited || !m_infoSystemWorkerThreadController->worker() ) { - QMetaObject::invokeMethod( this, "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPlugin*, plugin ) ); + QMetaObject::invokeMethod( this, "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) ); return; } - if ( plugin->thread() != m_infoSystemWorkerThreadController->worker()->thread() ) + if ( plugin.isNull() ) + { + tDebug() << Q_FUNC_INFO << "Given plugin is null!"; + return; + } + + if ( plugin.data()->thread() != m_infoSystemWorkerThreadController->worker()->thread() ) { tDebug() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread()"; return; } - - QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPlugin*, plugin ) ); + + tDebug() << Q_FUNC_INFO << plugin.data(); + QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) ); +} + + +void +InfoSystem::removeInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) +{ + // Init is not complete (waiting for worker th read to start and create worker object) so keep trying till then + if ( !m_inited || !m_infoSystemWorkerThreadController->worker() ) + { + QMetaObject::invokeMethod( this, "removeInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) ); + return; + } + + if ( plugin.isNull() ) + { + tDebug() << Q_FUNC_INFO << "Given plugin is null!"; + return; + } + + if ( plugin.data()->thread() != m_infoSystemWorkerThreadController->worker()->thread() ) + { + tDebug() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread()"; + return; + } + + tDebug() << Q_FUNC_INFO << plugin.data(); + QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "removeInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) ); } diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index f7bab5884..c59b6d62e 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -286,7 +286,8 @@ public: public slots: // InfoSystem takes ownership of InfoPlugins - void addInfoPlugin( Tomahawk::InfoSystem::InfoPlugin* plugin ); + void addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ); + void removeInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ); signals: void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); @@ -309,7 +310,6 @@ private: } - inline uint qHash( Tomahawk::InfoSystem::InfoStringHash hash ) { QCryptographicHash md5( QCryptographicHash::Md5 ); @@ -331,6 +331,7 @@ inline uint qHash( Tomahawk::InfoSystem::InfoStringHash hash ) return returnval; } + Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoRequestData ); Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoPushData ); Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoStringHash ); @@ -339,6 +340,7 @@ Q_DECLARE_METATYPE( Tomahawk::InfoSystem::PushInfoFlags ); Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoType ); Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoSystemCache* ); Q_DECLARE_METATYPE( QList< Tomahawk::InfoSystem::InfoStringHash > ); +Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoPluginPtr ); Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoPlugin* ); #endif // TOMAHAWK_INFOSYSTEM_H diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index a0ba17c05..a59bdd4ad 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -82,44 +82,51 @@ InfoSystemWorker::init( Tomahawk::InfoSystem::InfoSystemCache* cache ) m_shortLinksWaiting = 0; m_cache = cache; #ifndef ENABLE_HEADLESS - addInfoPlugin( new EchoNestPlugin() ); - addInfoPlugin( new MusixMatchPlugin() ); - addInfoPlugin( new MusicBrainzPlugin() ); - addInfoPlugin( new ChartsPlugin() ); - addInfoPlugin( new RoviPlugin() ); - addInfoPlugin( new SpotifyPlugin() ); - addInfoPlugin( new hypemPlugin() ); + addInfoPlugin( InfoPluginPtr( new EchoNestPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new MusixMatchPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new MusicBrainzPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new ChartsPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new RoviPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new SpotifyPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new hypemPlugin() ) ); #endif #ifdef Q_WS_MAC - addInfoPlugin( new AdiumPlugin() ); + addInfoPlugin( InfoPluginPtr( new AdiumPlugin() ) ); #endif #ifndef ENABLE_HEADLESS #ifdef Q_WS_X11 - addInfoPlugin( new FdoNotifyPlugin() ); - addInfoPlugin( new MprisPlugin() ); + addInfoPlugin( InfoPluginPtr( new FdoNotifyPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new MprisPlugin() ) ); #endif #endif } void -InfoSystemWorker::addInfoPlugin( InfoPlugin* plugin ) +InfoSystemWorker::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) { tDebug() << Q_FUNC_INFO << plugin; foreach ( InfoPluginPtr ptr, m_plugins ) { - if ( ptr.data() == plugin ) + if ( ptr == plugin ) + { tDebug() << Q_FUNC_INFO << "This plugin is already added to the infosystem."; + return; + } + } + + if ( plugin.isNull() ) + { + tDebug() << Q_FUNC_INFO << "passed-in plugin is null"; return; } - InfoPluginPtr weakptr( plugin ); - m_plugins.append( weakptr ); - registerInfoTypes( weakptr, weakptr.data()->supportedGetTypes(), weakptr.data()->supportedPushTypes() ); + m_plugins.append( plugin ); + registerInfoTypes( plugin, plugin.data()->supportedGetTypes(), plugin.data()->supportedPushTypes() ); connect( - plugin, + plugin.data(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), this, SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), @@ -127,14 +134,14 @@ InfoSystemWorker::addInfoPlugin( InfoPlugin* plugin ) ); connect( - plugin, + plugin.data(), SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ), m_cache, SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ), Qt::QueuedConnection ); connect( - plugin, + plugin.data(), SIGNAL( updateCache( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ), m_cache, SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ), @@ -143,6 +150,32 @@ InfoSystemWorker::addInfoPlugin( InfoPlugin* plugin ) } +void +InfoSystemWorker::removeInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) +{ + tDebug() << Q_FUNC_INFO << plugin; + + if ( plugin.isNull() ) + { + tDebug() << Q_FUNC_INFO << "passed-in plugin is null"; + return; + } + + foreach ( InfoPluginPtr ptr, m_plugins ) + { + if ( ptr == plugin ) + break; + + tDebug() << Q_FUNC_INFO << "This plugin does not exist in the infosystem."; + return; + } + + m_plugins.removeOne( plugin ); + deregisterInfoTypes( plugin, plugin.data()->supportedGetTypes(), plugin.data()->supportedPushTypes() ); + delete plugin.data(); +} + + void InfoSystemWorker::registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType >& getTypes, const QSet< InfoType >& pushTypes ) { @@ -153,6 +186,16 @@ InfoSystemWorker::registerInfoTypes( const InfoPluginPtr &plugin, const QSet< In } +void +InfoSystemWorker::deregisterInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType >& getTypes, const QSet< InfoType >& pushTypes ) +{ + Q_FOREACH( InfoType type, getTypes ) + m_infoGetMap[type].removeOne( plugin ); + Q_FOREACH( InfoType type, pushTypes ) + m_infoPushMap[type].removeOne( plugin ); +} + + QList< InfoPluginPtr > InfoSystemWorker::determineOrderedMatches( const InfoType type ) const { @@ -242,6 +285,8 @@ InfoSystemWorker::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) } } + tDebug() << Q_FUNC_INFO << "number of matching plugins: " << m_infoPushMap[ pushData.type ].size(); + Q_FOREACH( InfoPluginPtr ptr, m_infoPushMap[ pushData.type ] ) { if( ptr ) diff --git a/src/libtomahawk/infosystem/infosystemworker.h b/src/libtomahawk/infosystem/infosystemworker.h index 6a51299b5..e949329ec 100644 --- a/src/libtomahawk/infosystem/infosystemworker.h +++ b/src/libtomahawk/infosystem/infosystemworker.h @@ -49,8 +49,6 @@ public: InfoSystemWorker(); ~InfoSystemWorker(); - void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &getTypes, const QSet< InfoType > &pushTypes ); - signals: void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); void finished( QString target ); @@ -64,7 +62,8 @@ public slots: void infoSlot( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - void addInfoPlugin( Tomahawk::InfoSystem::InfoPlugin* plugin ); + void addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ); + void removeInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ); void getShortUrl( Tomahawk::InfoSystem::InfoPushData data ); void shortLinkReady( QUrl longUrl, QUrl shortUrl, QVariant callbackObj ); @@ -73,6 +72,8 @@ private slots: void checkTimeoutsTimerFired(); private: + void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &getTypes, const QSet< InfoType > &pushTypes ); + void deregisterInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &getTypes, const QSet< InfoType > &pushTypes ); void checkFinished( const Tomahawk::InfoSystem::InfoRequestData &target ); QList< InfoPluginPtr > determineOrderedMatches( const InfoType type ) const; diff --git a/src/musicscanner.cpp b/src/musicscanner.cpp index 0edd230a4..06a0cf2c6 100644 --- a/src/musicscanner.cpp +++ b/src/musicscanner.cpp @@ -174,7 +174,6 @@ MusicScanner::scan() SLOT( commitBatch( QVariantList, QVariantList ) ), Qt::DirectConnection ); m_dirListerThreadController = new QThread( this ); - m_dirListerThreadController->setPriority( QThread::IdlePriority ); m_dirLister = QWeakPointer< DirLister >( new DirLister( m_dirs ) ); m_dirLister.data()->moveToThread( m_dirListerThreadController ); @@ -186,7 +185,7 @@ MusicScanner::scan() connect( m_dirLister.data(), SIGNAL( finished() ), SLOT( listerFinished() ), Qt::QueuedConnection ); - m_dirListerThreadController->start(); + m_dirListerThreadController->start( QThread::IdlePriority ); QMetaObject::invokeMethod( m_dirLister.data(), "go" ); } diff --git a/src/scanmanager.cpp b/src/scanmanager.cpp index c82438481..cf3c8a7bd 100644 --- a/src/scanmanager.cpp +++ b/src/scanmanager.cpp @@ -196,7 +196,6 @@ ScanManager::runDirScan() { m_scanTimer->stop(); m_musicScannerThreadController = new QThread( this ); - m_musicScannerThreadController->setPriority( QThread::IdlePriority ); m_scanner = QWeakPointer< MusicScanner >( new MusicScanner( paths ) ); m_scanner.data()->moveToThread( m_musicScannerThreadController ); connect( m_scanner.data(), SIGNAL( finished() ), SLOT( scannerFinished() ) ); diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index dbd1ab4b7..3d7d5b529 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -35,6 +35,8 @@ #include "collection.h" #include "infosystem/infosystem.h" #include "accounts/AccountManager.h" +#include "accounts/spotify/SpotifyAccount.h" +#include "accounts/lastfm/LastFmAccount.h" #include "database/database.h" #include "database/databasecollection.h" #include "database/databasecommand_collectionstats.h" @@ -60,8 +62,6 @@ #include "utils/jspfloader.h" #include "utils/logger.h" #include "utils/tomahawkutilsgui.h" -#include "accounts/lastfm/LastFmAccount.h" -#include "accounts/spotify/SpotifyAccount.h" #include "config.h" @@ -227,16 +227,8 @@ TomahawkApp::init() tDebug() << "Init AccountManager."; m_accountManager = QWeakPointer< Tomahawk::Accounts::AccountManager >( new Tomahawk::Accounts::AccountManager( this ) ); - - Tomahawk::Accounts::LastFmAccountFactory* lastfmFactory = new Tomahawk::Accounts::LastFmAccountFactory(); - m_accountManager.data()->addAccountFactory( lastfmFactory ); - - Tomahawk::Accounts::SpotifyAccountFactory* spotifyFactory = new Tomahawk::Accounts::SpotifyAccountFactory; - m_accountManager.data()->addAccountFactory( spotifyFactory ); - m_accountManager.data()->registerAccountFactoryForFilesystem( spotifyFactory ); - - Tomahawk::Accounts::AccountManager::instance()->loadFromConfig(); - + connect( m_accountManager.data(), SIGNAL( ready() ), SLOT( accountManagerReady() ) ); + Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() ); #ifndef ENABLE_HEADLESS EchonestGenerator::setupCatalogs(); @@ -447,6 +439,7 @@ TomahawkApp::registerMetaTypes() qRegisterMetaType< Tomahawk::InfoSystem::InfoRequestData >( "Tomahawk::InfoSystem::InfoRequestData" ); qRegisterMetaType< Tomahawk::InfoSystem::InfoPushData >( "Tomahawk::InfoSystem::InfoPushData" ); qRegisterMetaType< Tomahawk::InfoSystem::InfoSystemCache* >( "Tomahawk::InfoSystem::InfoSystemCache*" ); + qRegisterMetaType< Tomahawk::InfoSystem::InfoPluginPtr >( "Tomahawk::InfoSystem::InfoPluginPtr" ); qRegisterMetaType< Tomahawk::InfoSystem::InfoPlugin* >( "Tomahawk::InfoSystem::InfoPlugin*" ); qRegisterMetaType< QList< Tomahawk::InfoSystem::InfoStringHash > >("QList< Tomahawk::InfoSystem::InfoStringHash > "); @@ -598,6 +591,20 @@ TomahawkApp::spotifyApiCheckFinished() } +void +TomahawkApp::accountManagerReady() +{ + Tomahawk::Accounts::LastFmAccountFactory* lastfmFactory = new Tomahawk::Accounts::LastFmAccountFactory(); + m_accountManager.data()->addAccountFactory( lastfmFactory ); + + Tomahawk::Accounts::SpotifyAccountFactory* spotifyFactory = new Tomahawk::Accounts::SpotifyAccountFactory; + m_accountManager.data()->addAccountFactory( spotifyFactory ); + m_accountManager.data()->registerAccountFactoryForFilesystem( spotifyFactory ); + + Tomahawk::Accounts::AccountManager::instance()->loadFromConfig(); +} + + void TomahawkApp::activate() { diff --git a/src/tomahawkapp.h b/src/tomahawkapp.h index 24f2acba8..e9ade964f 100644 --- a/src/tomahawkapp.h +++ b/src/tomahawkapp.h @@ -111,6 +111,7 @@ private slots: void initHTTP(); void spotifyApiCheckFinished(); + void accountManagerReady(); private: void registerMetaTypes(); From 43806aec6255ac97be652526a6ec0ea65f783b98 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 10 Apr 2012 17:59:23 -0400 Subject: [PATCH 05/12] Remove album from love action --- src/accounts/twitter/twitterinfoplugin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/accounts/twitter/twitterinfoplugin.cpp b/src/accounts/twitter/twitterinfoplugin.cpp index ae8fb373e..1de65a9ef 100644 --- a/src/accounts/twitter/twitterinfoplugin.cpp +++ b/src/accounts/twitter/twitterinfoplugin.cpp @@ -131,10 +131,9 @@ TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) Tomahawk::InfoSystem::InfoStringHash info = pushInfoPair.second.value< Tomahawk::InfoSystem::InfoStringHash >(); - QString msg = tr( "Listening to \"%1\" by %2%3 and loving it! %4" ) + QString msg = tr( "Listening to \"%1\" by %2 and loving it! %3" ) .arg( info[ "title" ] ) .arg( info[ "artist" ] ) - .arg( info[ "album" ].isEmpty() ? QString() : QString( " %1" ).arg( tr( "on \"%1\"" ).arg( info[ "album" ] ) ) ) .arg( pushInfoPair.first.contains( "shorturl" ) ? pushInfoPair.first[ "shorturl" ].toUrl().toString() : GlobalActionManager::instance()->openLink( info[ "title" ], info[ "artist" ], info[ "album" ] ).toString() ); From 619373c2e511fff94dd8826530ac5b0ef2f08fd8 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 10 Apr 2012 18:16:14 -0400 Subject: [PATCH 06/12] Make lastfm/xmpp info plugins more robust --- src/accounts/lastfm/LastFmAccount.cpp | 12 ++++++------ src/accounts/twitter/twitteraccount.cpp | 3 --- src/accounts/xmpp/sip/xmppsip.cpp | 11 +++++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/accounts/lastfm/LastFmAccount.cpp index 1561d49db..61de6bec7 100644 --- a/src/accounts/lastfm/LastFmAccount.cpp +++ b/src/accounts/lastfm/LastFmAccount.cpp @@ -54,8 +54,6 @@ LastFmAccountFactory::icon() const LastFmAccount::LastFmAccount( const QString& accountId ) : CustomAtticaAccount( accountId ) { - m_infoPlugin = QWeakPointer< LastFmPlugin >( new LastFmPlugin( this ) ); - setAccountFriendlyName( "Last.Fm" ); m_icon.load( RESPATH "images/lastfm-icon.png" ); @@ -84,7 +82,8 @@ LastFmAccount::LastFmAccount( const QString& accountId ) LastFmAccount::~LastFmAccount() { if ( m_infoPlugin ) - m_infoPlugin.data()->deleteLater(); + Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( infoPlugin() ); + delete m_resolver.data(); } @@ -167,9 +166,10 @@ LastFmAccount::icon() const InfoPluginPtr LastFmAccount::infoPlugin() { - if ( m_infoPlugin ) - return InfoPluginPtr( m_infoPlugin.data() ); - return InfoPluginPtr(); + if ( m_infoPlugin.isNull() ) + m_infoPlugin = QWeakPointer< LastFmPlugin >( new LastFmPlugin( this ) ); + + return InfoPluginPtr( m_infoPlugin.data() ); } bool diff --git a/src/accounts/twitter/twitteraccount.cpp b/src/accounts/twitter/twitteraccount.cpp index fca1b9932..da1fb2467 100644 --- a/src/accounts/twitter/twitteraccount.cpp +++ b/src/accounts/twitter/twitteraccount.cpp @@ -105,11 +105,8 @@ Tomahawk::InfoSystem::InfoPluginPtr TwitterAccount::infoPlugin() { if ( m_twitterInfoPlugin.isNull() ) - { m_twitterInfoPlugin = QWeakPointer< Tomahawk::InfoSystem::TwitterInfoPlugin >( new Tomahawk::InfoSystem::TwitterInfoPlugin( this ) ); - return Tomahawk::InfoSystem::InfoPluginPtr( m_twitterInfoPlugin.data() ); - } return Tomahawk::InfoSystem::InfoPluginPtr( m_twitterInfoPlugin.data() ); } diff --git a/src/accounts/xmpp/sip/xmppsip.cpp b/src/accounts/xmpp/sip/xmppsip.cpp index 698db7613..45e81d369 100644 --- a/src/accounts/xmpp/sip/xmppsip.cpp +++ b/src/accounts/xmpp/sip/xmppsip.cpp @@ -176,6 +176,9 @@ XmppSipPlugin::~XmppSipPlugin() InfoSystem::InfoPluginPtr XmppSipPlugin::infoPlugin() { + if ( m_infoPlugin.isNull() ) + m_infoPlugin = QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin >( new Tomahawk::InfoSystem::XmppInfoPlugin( this ) ); + return InfoSystem::InfoPluginPtr( m_infoPlugin.data() ); } @@ -270,11 +273,8 @@ XmppSipPlugin::onConnect() m_roster->load(); // load XmppInfoPlugin - if( !m_infoPlugin ) - { - m_infoPlugin = QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin >( new Tomahawk::InfoSystem::XmppInfoPlugin( this ) ); + if( infoPlugin() ) InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - } //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P // join MUC with bare jid as nickname @@ -338,6 +338,9 @@ XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) { handlePeerStatus(peer, Jreen::Presence::Unavailable); } + + if ( !m_infoPlugin.isNull() ) + Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( infoPlugin() ); } From 2b09915a0df0d390d8a161b994d8c5ceb65d1fd1 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 10 Apr 2012 18:36:35 -0400 Subject: [PATCH 07/12] Convert sip plugin to a weak pointer so we can check its validity before running invokeMethod on it --- src/accounts/xmpp/XmppInfoPlugin.cpp | 14 +++++++------- src/accounts/xmpp/XmppInfoPlugin.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/accounts/xmpp/XmppInfoPlugin.cpp b/src/accounts/xmpp/XmppInfoPlugin.cpp index e13dd64eb..cb7352a9c 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.cpp +++ b/src/accounts/xmpp/XmppInfoPlugin.cpp @@ -33,7 +33,7 @@ // remove now playing status after PAUSE_TIMEOUT seconds static const int PAUSE_TIMEOUT = 60; -Tomahawk::InfoSystem::XmppInfoPlugin::XmppInfoPlugin(XmppSipPlugin* sipPlugin) +Tomahawk::InfoSystem::XmppInfoPlugin::XmppInfoPlugin( XmppSipPlugin* sipPlugin ) : m_sipPlugin( sipPlugin ) , m_pubSubManager( 0 ) , m_pauseTimer( this ) @@ -67,11 +67,11 @@ Tomahawk::InfoSystem::XmppInfoPlugin::~XmppInfoPlugin() void Tomahawk::InfoSystem::XmppInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) { - tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full(); + tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full(); - if( m_sipPlugin->m_account->configuration().value("publishtracks").toBool() == false ) + if( m_sipPlugin.data()->m_account->configuration().value("publishtracks").toBool() == false ) { - tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; + tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; return; } @@ -121,7 +121,7 @@ Tomahawk::InfoSystem::XmppInfoPlugin::audioStarted( const Tomahawk::InfoSystem:: } Tomahawk::InfoSystem::InfoStringHash info = map[ "trackinfo" ].value< Tomahawk::InfoSystem::InfoStringHash >(); - tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full() << info; + tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full() << info; Jreen::Tune::Ptr tune( new Jreen::Tune() ); @@ -147,13 +147,13 @@ Tomahawk::InfoSystem::XmppInfoPlugin::audioStarted( const Tomahawk::InfoSystem:: void Tomahawk::InfoSystem::XmppInfoPlugin::audioPaused() { - tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full(); + tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full(); } void Tomahawk::InfoSystem::XmppInfoPlugin::audioStopped() { - tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full(); + tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full(); Jreen::Tune::Ptr tune( new Jreen::Tune() ); m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); diff --git a/src/accounts/xmpp/XmppInfoPlugin.h b/src/accounts/xmpp/XmppInfoPlugin.h index fbe050966..c9ff63b91 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.h +++ b/src/accounts/xmpp/XmppInfoPlugin.h @@ -57,7 +57,7 @@ namespace Tomahawk { void audioPaused(); private: - XmppSipPlugin* m_sipPlugin; + QWeakPointer< XmppSipPlugin > m_sipPlugin; Jreen::PubSub::Manager* m_pubSubManager; QTimer m_pauseTimer; }; From 7284a53d0f6554ecd787e1d7d6dcc117b110a8fa Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 08:19:10 -0400 Subject: [PATCH 08/12] Move Jreen bits in xmpp info plugin to the SIP side, allowing the plugin to run in the correct thread. --- src/accounts/xmpp/XmppInfoPlugin.cpp | 73 +++++++++------------------- src/accounts/xmpp/XmppInfoPlugin.h | 11 ++--- src/accounts/xmpp/sip/xmppsip.cpp | 59 +++++++++++++++++++++- src/accounts/xmpp/sip/xmppsip.h | 3 ++ 4 files changed, 87 insertions(+), 59 deletions(-) diff --git a/src/accounts/xmpp/XmppInfoPlugin.cpp b/src/accounts/xmpp/XmppInfoPlugin.cpp index cb7352a9c..b1d822a68 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.cpp +++ b/src/accounts/xmpp/XmppInfoPlugin.cpp @@ -24,31 +24,18 @@ #include "sip/xmppsip.h" #include "utils/logger.h" -#include -#include -#include - -#include // remove now playing status after PAUSE_TIMEOUT seconds -static const int PAUSE_TIMEOUT = 60; +static const int PAUSE_TIMEOUT = 10; Tomahawk::InfoSystem::XmppInfoPlugin::XmppInfoPlugin( XmppSipPlugin* sipPlugin ) : m_sipPlugin( sipPlugin ) - , m_pubSubManager( 0 ) , m_pauseTimer( this ) { Q_ASSERT( sipPlugin->m_client ); m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped; - m_pubSubManager = new Jreen::PubSub::Manager( sipPlugin->m_client ); - m_pubSubManager->addEntityType< Jreen::Tune >(); - - // Clear status - Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); - m_pauseTimer.setSingleShot( true ); connect( &m_pauseTimer, SIGNAL( timeout() ), this, SLOT( audioStopped() ) ); @@ -57,24 +44,28 @@ Tomahawk::InfoSystem::XmppInfoPlugin::XmppInfoPlugin( XmppSipPlugin* sipPlugin ) Tomahawk::InfoSystem::XmppInfoPlugin::~XmppInfoPlugin() { - //Note: the next two lines don't currently work, because the deletion wipes out internally posted events, need to talk to euro about a fix - Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); - m_pubSubManager->deleteLater(); +} + + +void +Tomahawk::InfoSystem::XmppInfoPlugin::init() +{ + if ( QThread::currentThread() != Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ) + { + QMetaObject::invokeMethod( this, "init", Qt::QueuedConnection ); + return; + } + + if ( m_sipPlugin.isNull() ) + return; + + connect( this, SIGNAL( publishTune( QUrl, Tomahawk::InfoSystem::InfoStringHash ) ), m_sipPlugin.data(), SLOT( publishTune( QUrl, Tomahawk::InfoSystem::InfoStringHash ) ), Qt::QueuedConnection ); } void Tomahawk::InfoSystem::XmppInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) { - tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full(); - - if( m_sipPlugin.data()->m_account->configuration().value("publishtracks").toBool() == false ) - { - tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; - return; - } - switch ( pushData.type ) { case InfoNowPlaying: @@ -109,8 +100,7 @@ Tomahawk::InfoSystem::XmppInfoPlugin::audioStarted( const Tomahawk::InfoSystem:: QVariantMap map = pushInfoPair.second.toMap(); if ( map.contains( "private" ) && map[ "private" ] == TomahawkSettings::FullyPrivate ) { - Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); + emit publishTune( QUrl(), Tomahawk::InfoSystem::InfoStringHash() ); return; } @@ -121,42 +111,25 @@ Tomahawk::InfoSystem::XmppInfoPlugin::audioStarted( const Tomahawk::InfoSystem:: } Tomahawk::InfoSystem::InfoStringHash info = map[ "trackinfo" ].value< Tomahawk::InfoSystem::InfoStringHash >(); - tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full() << info; - - Jreen::Tune::Ptr tune( new Jreen::Tune() ); - tune->setTitle( info.value( "title" ) ); - tune->setArtist( info.value( "artist" ) ); - tune->setLength( info.value("duration").toInt() ); - tune->setTrack( info.value("albumpos") ); + QUrl url; if ( pushInfoPair.first.contains( "shorturl" ) ) - tune->setUri( pushInfoPair.first[ "shorturl" ].toUrl() ); + url = pushInfoPair.first[ "shorturl" ].toUrl(); else - tune->setUri( GlobalActionManager::instance()->openLink( info.value( "title" ), info.value( "artist" ), info.value( "album" ) ) ); + url = GlobalActionManager::instance()->openLink( info.value( "title" ), info.value( "artist" ), info.value( "album" ) ); - tDebug() << Q_FUNC_INFO << "Setting URI of " << tune->uri().toString(); - //TODO: provide a rating once available in Tomahawk - tune->setRating( 10 ); - - //TODO: it would be nice to set Spotify, Dilandau etc here, but not the jabber ids of friends - tune->setSource( "Tomahawk" ); - - m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); + emit publishTune( url, info ); } void Tomahawk::InfoSystem::XmppInfoPlugin::audioPaused() { - tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full(); } void Tomahawk::InfoSystem::XmppInfoPlugin::audioStopped() { - tDebug() << Q_FUNC_INFO << m_sipPlugin.data()->m_client->jid().full(); - - Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); + emit publishTune( QUrl(), Tomahawk::InfoSystem::InfoStringHash() ); } diff --git a/src/accounts/xmpp/XmppInfoPlugin.h b/src/accounts/xmpp/XmppInfoPlugin.h index c9ff63b91..c15f1571f 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.h +++ b/src/accounts/xmpp/XmppInfoPlugin.h @@ -24,12 +24,6 @@ #include -namespace Jreen { - namespace PubSub { - class Manager; - } -} - class XmppSipPlugin; namespace Tomahawk { @@ -44,7 +38,11 @@ namespace Tomahawk { XmppInfoPlugin(XmppSipPlugin* parent); virtual ~XmppInfoPlugin(); + signals: + void publishTune( QUrl url, Tomahawk::InfoSystem::InfoStringHash trackInfo ); + public slots: + void init(); void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); protected slots: @@ -58,7 +56,6 @@ namespace Tomahawk { private: QWeakPointer< XmppSipPlugin > m_sipPlugin; - Jreen::PubSub::Manager* m_pubSubManager; QTimer m_pauseTimer; }; diff --git a/src/accounts/xmpp/sip/xmppsip.cpp b/src/accounts/xmpp/sip/xmppsip.cpp index 45e81d369..a36d3fb1e 100644 --- a/src/accounts/xmpp/sip/xmppsip.cpp +++ b/src/accounts/xmpp/sip/xmppsip.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -90,6 +91,7 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) #ifndef ENABLE_HEADLESS , m_menu( 0 ) , m_xmlConsole( 0 ) + , m_pubSubManager( 0 ) #endif { Jreen::Logger::addHandler( JreenMessageHandler ); @@ -160,10 +162,22 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) #ifndef ENABLE_HEADLESS connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString))); #endif + + m_pubSubManager = new Jreen::PubSub::Manager( m_client ); + m_pubSubManager->addEntityType< Jreen::Tune >(); + + // Clear status + Jreen::Tune::Ptr tune( new Jreen::Tune() ); + m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); + } XmppSipPlugin::~XmppSipPlugin() { + //Note: the next two lines don't currently work, because the deletion wipes out internally posted events, need to talk to euro about a fix + Jreen::Tune::Ptr tune( new Jreen::Tune() ); + m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); + delete m_pubSubManager; delete m_avatarManager; delete m_roster; #ifndef ENABLE_HEADLESS @@ -242,6 +256,8 @@ XmppSipPlugin::disconnectPlugin() m_peers.clear(); + publishTune( QUrl(), Tomahawk::InfoSystem::InfoStringHash() ); + m_client->disconnectFromServer( true ); m_state = Account::Disconnecting; emit stateChanged( m_state ); @@ -273,8 +289,12 @@ XmppSipPlugin::onConnect() m_roster->load(); // load XmppInfoPlugin - if( infoPlugin() ) - InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); + if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() ) + { + infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); + Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); + QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); + } //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P // join MUC with bare jid as nickname @@ -510,6 +530,41 @@ XmppSipPlugin::showAddFriendDialog() } +void +XmppSipPlugin::publishTune( const QUrl& url, const InfoSystem::InfoStringHash& trackInfo ) +{ + if( m_account->configuration().value("publishtracks").toBool() == false ) + { + tDebug() << Q_FUNC_INFO << m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; + return; + } + + if ( trackInfo.isEmpty() ) + { + Jreen::Tune::Ptr tune( new Jreen::Tune() ); + m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); + } + + Jreen::Tune::Ptr tune( new Jreen::Tune() ); + + tune->setTitle( trackInfo.value( "title" ) ); + tune->setArtist( trackInfo.value( "artist" ) ); + tune->setLength( trackInfo.value("duration").toInt() ); + tune->setTrack( trackInfo.value("albumpos") ); + + //TODO: provide a rating once available in Tomahawk + tune->setRating( 10 ); + + //TODO: it would be nice to set Spotify, Dilandau etc here, but not the jabber ids of friends + tune->setSource( "Tomahawk" ); + + tune->setUri( url ); + tDebug() << Q_FUNC_INFO << "Setting URI of " << tune->uri().toString(); + + m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); +} + + QString XmppSipPlugin::defaultSuffix() const { diff --git a/src/accounts/xmpp/sip/xmppsip.h b/src/accounts/xmpp/sip/xmppsip.h index 0a56ad9fa..1e570928d 100644 --- a/src/accounts/xmpp/sip/xmppsip.h +++ b/src/accounts/xmpp/sip/xmppsip.h @@ -42,6 +42,7 @@ #include #include #include +#include #ifndef ENABLE_HEADLESS #include @@ -92,6 +93,7 @@ public slots: void broadcastMsg( const QString &msg ); virtual void addContact( const QString &jid, const QString& msg = QString() ); void showAddFriendDialog(); + void publishTune( const QUrl &url, const Tomahawk::InfoSystem::InfoStringHash &trackInfo ); protected: virtual QString defaultSuffix() const; @@ -147,6 +149,7 @@ private: #endif enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard, RequestVersion, RequestedVersion }; AvatarManager *m_avatarManager; + Jreen::PubSub::Manager* m_pubSubManager; }; #endif From 3ea581c4f8d711d768d53a354c89828fc60b9b7c Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 09:55:48 -0400 Subject: [PATCH 09/12] Maybe fix cover temp file writing --- src/libtomahawk/audio/audioengine.cpp | 37 ++++++++++--------- .../infoplugins/unix/fdonotifyplugin.cpp | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index f5c57489d..c83263e26 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -329,7 +329,7 @@ AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType ty { _detail::Closure* closure = NewClosure( m_currentTrack->album().data(), SIGNAL( updated() ), const_cast< AudioEngine* >( this ), SLOT( onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType ) ), type ); Q_UNUSED( closure ); - m_currentTrack->album()->cover( QSize( 0, 0 ) ); + m_currentTrack->album()->cover( QSize( 0, 0 ), true ); } #endif } @@ -354,26 +354,29 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) #ifndef ENABLE_HEADLESS QImage cover; cover = m_currentTrack->album()->cover( QSize( 0, 0 ) ).toImage(); - playInfo["cover"] = cover; - - QTemporaryFile coverTempFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + m_currentTrack->artist()->name() + "_" + m_currentTrack->album()->name() + "_tomahawk_cover.png" ) ); - if ( !coverTempFile.open() ) + if ( !cover.isNull() ) { - tDebug() << "WARNING: could not write temporary file for cover art!"; - } + playInfo["cover"] = cover; - // Finally, save the image to the new temp file - if ( cover.save( &coverTempFile, "PNG" ) ) - { - tDebug( LOGVERBOSE ) << "Saving cover image to:" << QFileInfo( coverTempFile ).absoluteFilePath(); - coverTempFile.close(); - playInfo["coveruri"] = QFileInfo( coverTempFile ).absoluteFilePath(); + QTemporaryFile* coverTempFile = new QTemporaryFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + m_currentTrack->artist()->name() + "_" + m_currentTrack->album()->name() + "_tomahawk_cover.png" ) ); + if ( !coverTempFile->open() ) + tDebug() << Q_FUNC_INFO << "WARNING: could not write temporary file for cover art!"; + else + { + // Finally, save the image to the new temp file + coverTempFile->setAutoRemove( false ); + if ( cover.save( coverTempFile, "PNG" ) ) + { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Saving cover image to:" << QFileInfo( *coverTempFile ).absoluteFilePath(); + playInfo["coveruri"] = QFileInfo( *coverTempFile ).absoluteFilePath(); + } + else + tDebug() << Q_FUNC_INFO << "failed to save cover image!"; + } + delete coverTempFile; } else - { - tDebug() << Q_FUNC_INFO << "failed to save cover image!"; - coverTempFile.close(); - } + tDebug() << Q_FUNC_INFO << "Cover from album is null!"; #endif } diff --git a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp index 4cc973270..dde0f37b4 100644 --- a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp @@ -146,7 +146,7 @@ FdoNotifyPlugin::nowPlaying( const QVariant &input ) arguments << QStringList(); //actions QVariantMap dict; dict["desktop-entry"] = QString( "tomahawk" ); - if ( map.contains( "cover" ) && map[ "cover" ].canConvert< QImage >() ) + if ( map.contains( "cover" ) && map[ "cover" ].canConvert< QImage >() && !map[ "cover" ].value< QImage >().isNull() ) dict[ "image_data" ] = ImageConverter::variantForImage( map[ "cover" ].value< QImage >() ); else dict[ "image_data" ] = ImageConverter::variantForImage( QImage( RESPATH "icons/tomahawk-icon-128x128.png" ) ); From 75d1ab7bbec0f6ceb1e2024e027b94e21382cc39 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 11:32:29 -0400 Subject: [PATCH 10/12] Make now-playing FDO notifications reuse, and fix a logic bug in audioengine that would cause missed notifictions --- src/libtomahawk/audio/audioengine.cpp | 9 +++------ .../infosystem/infoplugins/unix/fdonotifyplugin.cpp | 8 ++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index c83263e26..cd2bc6041 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -327,8 +327,7 @@ AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType ty onNowPlayingInfoReady( type ); else { - _detail::Closure* closure = NewClosure( m_currentTrack->album().data(), SIGNAL( updated() ), const_cast< AudioEngine* >( this ), SLOT( onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType ) ), type ); - Q_UNUSED( closure ); + NewClosure( m_currentTrack->album().data(), SIGNAL( updated() ), const_cast< AudioEngine* >( this ), SLOT( onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType ) ), type ); m_currentTrack->album()->cover( QSize( 0, 0 ), true ); } #endif @@ -338,14 +337,11 @@ AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType ty void AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << type; if ( m_currentTrack.isNull() || m_currentTrack->track().isNull() || m_currentTrack->artist().isNull() ) return; - - if ( !m_currentTrack->album().isNull() && sender() && m_currentTrack->album().data() != sender() ) - return; QVariantMap playInfo; @@ -392,6 +388,7 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) Tomahawk::InfoSystem::InfoPushData pushData ( s_aeInfoIdentifier, type, playInfo, Tomahawk::InfoSystem::PushShortUrlFlag ); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "pushing data with type " << type; Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData ); } diff --git a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp index dde0f37b4..e3bb136d9 100644 --- a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp @@ -49,6 +49,7 @@ using namespace Tomahawk::InfoSystem; +static const int s_nowPlayingNotificationId = 1; FdoNotifyPlugin::FdoNotifyPlugin() : InfoPlugin() @@ -119,6 +120,7 @@ FdoNotifyPlugin::notifyUser( const QString &messageText ) void FdoNotifyPlugin::nowPlaying( const QVariant &input ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; if ( !input.canConvert< QVariantMap >() ) return; @@ -135,11 +137,13 @@ FdoNotifyPlugin::nowPlaying( const QVariant &input ) .arg( hash[ "title" ] ) .arg( hash[ "artist" ] ) .arg( hash[ "album" ].isEmpty() ? QString() : QString( " %1" ).arg( tr( "on \"%1\"" ).arg( hash[ "album" ] ) ) ); - + + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "sending message" << messageText; + QDBusMessage message = QDBusMessage::createMethodCall( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify" ); QList arguments; arguments << QString( "Tomahawk" ); //app_name - arguments << quint32( 0 ); //notification_id + arguments << quint32( s_nowPlayingNotificationId ); //notification_id arguments << QString(); //app_icon arguments << QString( "Tomahawk" ); //summary arguments << messageText; //body From 64fbd230088ff8a54691e54c675cba52215e7d9d Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 12:54:56 -0400 Subject: [PATCH 11/12] Use returned notification ID instead of static version. Thanks to David Rosca for the fix --- .../infosystem/infoplugins/unix/fdonotifyplugin.cpp | 11 +++++++---- .../infosystem/infoplugins/unix/fdonotifyplugin.h | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp index e3bb136d9..b32c00e5e 100644 --- a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp @@ -49,10 +49,9 @@ using namespace Tomahawk::InfoSystem; -static const int s_nowPlayingNotificationId = 1; - FdoNotifyPlugin::FdoNotifyPlugin() : InfoPlugin() + , m_nowPlayingId( 0 ) { qDebug() << Q_FUNC_INFO; m_supportedPushTypes << InfoNotifyUser << InfoNowPlaying << InfoTrackUnresolved << InfoNowStopped; @@ -143,7 +142,7 @@ FdoNotifyPlugin::nowPlaying( const QVariant &input ) QDBusMessage message = QDBusMessage::createMethodCall( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify" ); QList arguments; arguments << QString( "Tomahawk" ); //app_name - arguments << quint32( s_nowPlayingNotificationId ); //notification_id + arguments << m_nowPlayingId; //notification_id arguments << QString(); //app_icon arguments << QString( "Tomahawk" ); //summary arguments << messageText; //body @@ -157,5 +156,9 @@ FdoNotifyPlugin::nowPlaying( const QVariant &input ) arguments << dict; //hints arguments << qint32( -1 ); //expire_timeout message.setArguments( arguments ); - QDBusConnection::sessionBus().send( message ); + + const QDBusMessage &reply = QDBusConnection::sessionBus().call( message ); + const QVariantList &list = reply.arguments(); + if ( list.count() > 0 ) + m_nowPlayingId = list.at( 0 ).toInt(); } diff --git a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.h b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.h index c12621ff3..bba7bc304 100644 --- a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.h @@ -54,6 +54,8 @@ private: void notifyUser( const QString &messageText ); void nowPlaying( const QVariant &input ); + + quint32 m_nowPlayingId; }; } From 511d353cc6e676637e0fa44cb7bde15bbf2672a7 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 15:22:34 -0400 Subject: [PATCH 12/12] Somehow, who knows how, passing a QImage to the FDO notification spec crashes some X servers, but saving the QImage to a file as a PNG, loading it back from the file as a PNG, and passing that QImage is totally cool. Wut. --- .../infosystem/infoplugins/unix/fdonotifyplugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp index b32c00e5e..5c252f820 100644 --- a/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/unix/fdonotifyplugin.cpp @@ -149,8 +149,8 @@ FdoNotifyPlugin::nowPlaying( const QVariant &input ) arguments << QStringList(); //actions QVariantMap dict; dict["desktop-entry"] = QString( "tomahawk" ); - if ( map.contains( "cover" ) && map[ "cover" ].canConvert< QImage >() && !map[ "cover" ].value< QImage >().isNull() ) - dict[ "image_data" ] = ImageConverter::variantForImage( map[ "cover" ].value< QImage >() ); + if ( map.contains( "coveruri" ) && map[ "coveruri" ].canConvert< QString >() ) + dict[ "image_data" ] = ImageConverter::variantForImage( QImage( map[ "coveruri" ].toString(), "PNG" ) ); else dict[ "image_data" ] = ImageConverter::variantForImage( QImage( RESPATH "icons/tomahawk-icon-128x128.png" ) ); arguments << dict; //hints