From 54aef2cd2e482809c71b19bc0e0ba4d53f39dbe7 Mon Sep 17 00:00:00 2001
From: Jeff Mitchell <tomahawk@jefferai.org>
Date: Tue, 10 Apr 2012 16:39:12 -0400
Subject: [PATCH] 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();