diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index 2ecbc6fe3..7d87459e2 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -456,7 +456,7 @@ AtticaManager::payloadFetched() if ( reply->property( "createAccount" ).toBool() ) { // Do the install / add to tomahawk - Tomahawk::Accounts::Account* resolver = Tomahawk::Accounts::ResolverAccountFactory::createFromPath( resolverPath, true ); + Tomahawk::Accounts::Account* resolver = Tomahawk::Accounts::ResolverAccountFactory::createFromPath( resolverPath, "resolveraccount", true ); Tomahawk::Accounts::AccountManager::instance()->addAccount( resolver ); TomahawkSettings::instance()->addAccount( resolver->accountId() ); } diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 02f20fe3a..e0e73ce14 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -184,6 +184,7 @@ set( libSources accounts/ResolverAccount.cpp accounts/LastFmAccount.cpp accounts/LastFmConfig.cpp + accounts/SpotifyAccount.cpp sip/SipPlugin.cpp sip/SipHandler.cpp diff --git a/src/libtomahawk/accounts/Account.cpp b/src/libtomahawk/accounts/Account.cpp index 208cc7bac..7450a96a4 100644 --- a/src/libtomahawk/accounts/Account.cpp +++ b/src/libtomahawk/accounts/Account.cpp @@ -58,7 +58,6 @@ Account::Account( const QString& accountId ) Account::~Account() { - sync(); } diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h index 73a7dedee..f2e297241 100644 --- a/src/libtomahawk/accounts/Account.h +++ b/src/libtomahawk/accounts/Account.h @@ -180,6 +180,10 @@ public: virtual AccountTypes types() const = 0; virtual Account* createAccount( const QString& accountId = QString() ) = 0; + + /// If this resolver type accepts this path on disk (For general and special resolver accounts) + virtual bool acceptsPath( const QString& ) const { return false; } + virtual Account* createFromPath( const QString& ) { return 0; } }; }; diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index ae0b96f99..df8177bac 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -22,6 +22,7 @@ #include "sourcelist.h" #include "ResolverAccount.h" #include "LastFmAccount.h" +#include "SpotifyAccount.h" #include #include @@ -59,9 +60,14 @@ AccountManager::AccountManager( QObject *parent ) // We include the resolver factory manually, not in a plugin ResolverAccountFactory* f = new ResolverAccountFactory(); m_accountFactories[ f->factoryId() ] = f; + registerAccountFactoryForFilesystem( f ); LastFmAccountFactory* l = new LastFmAccountFactory(); m_accountFactories[ l->factoryId() ] = l; + + SpotifyAccountFactory* s = new SpotifyAccountFactory; + m_accountFactories[ s->factoryId() ] = s; + registerAccountFactoryForFilesystem( s ); } @@ -331,6 +337,30 @@ AccountManager::removeAccount( Account* account ) } +Account* +AccountManager::accountFromPath( const QString& accountPath ) +{ + foreach ( AccountFactory* factory, m_factoriesForFilesytem ) + { + if ( factory->acceptsPath( accountPath ) ) + { + return factory->createFromPath( accountPath ); + } + } + + Q_ASSERT_X( false, "Shouldn't have had no account factory accepting a path.. at least ResolverAccount!!", ""); + return 0; +} + + +void +AccountManager::registerAccountFactoryForFilesystem( AccountFactory* factory ) +{ + m_factoriesForFilesytem.prepend( factory ); +} + + + void AccountManager::hookupAccount( Account* account ) const { diff --git a/src/libtomahawk/accounts/AccountManager.h b/src/libtomahawk/accounts/AccountManager.h index 969edd27f..acec261d9 100644 --- a/src/libtomahawk/accounts/AccountManager.h +++ b/src/libtomahawk/accounts/AccountManager.h @@ -61,6 +61,21 @@ public: QList< Account* > accounts() const { return m_accounts; }; QList< Account* > accounts( Tomahawk::Accounts::AccountType type ) const { return m_accountsByAccountType[ type ]; } + /** + * Returns a new Account for a certain path on disk. This will go through all on-disk resolver account providers + * to find the most specific account that matches this. + * + * The fallback is ResolverAccount, which handles our generic external script resolvers. + */ + Account* accountFromPath( const QString& path ); + + /** + * Registers an account factory as being able to "handle" resolvers on disk. When accountFromPath is called + * AccountManager will go through all registered account factories in order until it finds one that can handle the path. + * This is searched in LIFO order. + */ + void registerAccountFactoryForFilesystem( AccountFactory* factory ); + public slots: void connectAll(); void disconnectAll(); @@ -97,6 +112,7 @@ private: QHash< AccountType, QList< Account* > > m_accountsByAccountType; QHash< QString, AccountFactory* > m_accountFactories; + QList< AccountFactory* > m_factoriesForFilesytem; static AccountManager* s_instance; }; diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 9c8b78f80..b76e327d1 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -311,7 +311,7 @@ AccountModel::data( const QModelIndex& index, int role ) const case Qt::DecorationRole: return acct->icon(); case DescriptionRole: - return node->type == AccountModelNode::ManualResolverType ? QString() : node->factory->description(); + return node->factory ? node->factory->description() : QString(); case Qt::CheckStateRole: return acct->enabled() ? Qt::Checked : Qt::Unchecked; case AccountData: @@ -597,7 +597,6 @@ void AccountModel::accountStateChanged( Account* account , Account::ConnectionState ) { // Find the factory this belongs up, and update - AccountFactory* factory = AccountManager::instance()->factoryForAccount( account ); for ( int i = 0; i < m_accounts.size(); i++ ) { AccountModelNode* n = m_accounts.at( i ); diff --git a/src/libtomahawk/accounts/AccountModelNode.h b/src/libtomahawk/accounts/AccountModelNode.h index fd6d2c933..28a3a5625 100644 --- a/src/libtomahawk/accounts/AccountModelNode.h +++ b/src/libtomahawk/accounts/AccountModelNode.h @@ -118,6 +118,7 @@ struct AccountModelNode { { init(); resolverAccount = ra; + factory = AccountManager::instance()->factoryForAccount( ra ); } explicit AccountModelNode( Account* account ) : type( CustomAccountType ) diff --git a/src/libtomahawk/accounts/LastFmAccount.cpp b/src/libtomahawk/accounts/LastFmAccount.cpp index 643e92251..c2205d6b0 100644 --- a/src/libtomahawk/accounts/LastFmAccount.cpp +++ b/src/libtomahawk/accounts/LastFmAccount.cpp @@ -83,6 +83,13 @@ LastFmAccount::~LastFmAccount() void LastFmAccount::authenticate() { + if ( !AtticaManager::instance()->resolversLoaded() ) + { + // If we're still waiting to load, wait for the attica resolvers to come down the pipe + connect( AtticaManager::instance(), SIGNAL(resolversLoaded(Attica::Content::List)), this, SLOT( atticaLoaded( Attica::Content::List ) ), Qt::UniqueConnection ); + return; + } + const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" ); const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res ); @@ -106,6 +113,14 @@ LastFmAccount::authenticate() } +void +LastFmAccount::atticaLoaded( Attica::Content::List ) +{ + disconnect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( atticaLoaded( Attica::Content::List ) ) ); + authenticate(); +} + + void LastFmAccount::deauthenticate() { diff --git a/src/libtomahawk/accounts/LastFmAccount.h b/src/libtomahawk/accounts/LastFmAccount.h index 3e7aaf651..7988c37d6 100644 --- a/src/libtomahawk/accounts/LastFmAccount.h +++ b/src/libtomahawk/accounts/LastFmAccount.h @@ -94,6 +94,8 @@ public: Attica::Content atticaContent() const; private slots: + void atticaLoaded( Attica::Content::List ); + void resolverInstalled( const QString& resolverId ); void resolverChanged(); diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 95acbe284..801477fd2 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -46,16 +46,23 @@ ResolverAccountFactory::createAccount( const QString& accountId ) Account* -ResolverAccountFactory::createFromPath( const QString& path, bool isAttica ) +ResolverAccountFactory::createFromPath( const QString& path ) +{ + return createFromPath( path, factoryId(), false ); +} + + +Account* +ResolverAccountFactory::createFromPath( const QString& path, const QString& factory, bool isAttica ) { qDebug() << "Creating ResolverAccount from path:" << path << "is attica" << isAttica; if ( isAttica ) { QFileInfo info( path ); - return new AtticaResolverAccount( generateId( "resolveraccount" ), path, info.baseName() ); + return new AtticaResolverAccount( generateId( factory ), path, info.baseName() ); } else - return new ResolverAccount( generateId( "resolveraccount" ), path ); + return new ResolverAccount( generateId( factory ), path ); } diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index 04da6d283..59b8ef162 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -35,7 +35,7 @@ public: ResolverAccountFactory() {} virtual ~ResolverAccountFactory() {} - virtual Account* createAccount(const QString& accountId = QString()); + virtual Account* createAccount( const QString& accountId = QString() ); virtual QString factoryId() const { return "resolveraccount"; } virtual QString description() const { return QString(); } virtual QString prettyName() const { return QString(); } // Internal, not displayed @@ -44,7 +44,11 @@ public: // Used to create a new resolver from a script on disk, either chosen by // the user, or installed from synchrotron - static Account* createFromPath( const QString& path, bool isAttica ); + virtual bool acceptsPath( const QString& path ) const { return true; } // This is the catch-all filesystem account + virtual Account* createFromPath( const QString& path ); + + // Internal use + static Account* createFromPath( const QString& path, const QString& factoryId, bool isAttica ); }; /** diff --git a/src/libtomahawk/accounts/SpotifyAccount.cpp b/src/libtomahawk/accounts/SpotifyAccount.cpp new file mode 100644 index 000000000..b0567019e --- /dev/null +++ b/src/libtomahawk/accounts/SpotifyAccount.cpp @@ -0,0 +1,148 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * 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 "SpotifyAccount.h" +#include "playlist.h" +#include "utils/tomahawkutils.h" +#include "PlaylistUpdaterInterface.h" +#include "sourcelist.h" + +#include + +using namespace Tomahawk; +using namespace Accounts; + +static QPixmap* s_icon = 0; + +Account* +SpotifyAccountFactory::createAccount( const QString& accountId ) +{ + return new SpotifyAccount( accountId ); +} + + +bool +SpotifyAccountFactory::acceptsPath( const QString& path ) const +{ + QFileInfo info( path ); + return info.baseName().startsWith( "spotify_" ); +} + + +Account* +SpotifyAccountFactory::createFromPath( const QString& path ) +{ + return new SpotifyAccount( generateId( factoryId() ), path ); +} + + +QPixmap +SpotifyAccountFactory::icon() const +{ + if ( !s_icon ) + s_icon = new QPixmap( RESPATH "images/spotify-logo.png" ); + + return *s_icon; +} + + +SpotifyAccount::SpotifyAccount( const QString& accountId ) + : ResolverAccount( accountId ) +{ + +} + + +SpotifyAccount::SpotifyAccount( const QString& accountId, const QString& path ) + : ResolverAccount( accountId, path ) +{ + +} + + +QPixmap +SpotifyAccount::icon() const +{ + if ( !s_icon ) + s_icon = new QPixmap( RESPATH "images/spotify-logo.png" ); + + return *s_icon; +} + + +void +SpotifyAccount::addPlaylist( const QString &qid, const QString& title, QList< Tomahawk::query_ptr > tracks ) +{ + Sync sync; + sync.id_ = qid; + int index = m_syncPlaylists.indexOf( sync ); + + if( !m_syncPlaylists.contains( sync ) ) + { + qDebug() << Q_FUNC_INFO << "Adding playlist to sync" << qid; + playlist_ptr pl; + pl = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), + uuid(), + title, + QString(), + QString(), + false, + tracks ); + sync.playlist = pl; + sync.uuid = pl->guid(); + m_syncPlaylists.append( sync ); + } + else + { + + qDebug() << Q_FUNC_INFO << "Found playlist"; + + if ( index != -1 && !tracks.isEmpty()) + { + + qDebug() << Q_FUNC_INFO << "Got pl" << m_syncPlaylists[ index ].playlist->guid(); + + QList< query_ptr > currTracks; + foreach ( const plentry_ptr ple, m_syncPlaylists[ index ].playlist->entries() ) + currTracks << ple->query(); + + qDebug() << Q_FUNC_INFO << "tracks" << currTracks; + + bool changed = false; + QList< query_ptr > mergedTracks = TomahawkUtils::mergePlaylistChanges( currTracks, tracks, changed ); + + if ( changed ) + { + QList el = m_syncPlaylists[ index ].playlist->entriesFromQueries( mergedTracks, true ); + m_syncPlaylists[ index ].playlist->createNewRevision( uuid(), m_syncPlaylists[ index ].playlist->currentrevision(), el ); + } + } + } + + +} + + + +bool operator==( SpotifyAccount::Sync one, SpotifyAccount::Sync two ) +{ + if( one.id_ == two.id_ ) + return true; + return false; +} + diff --git a/src/libtomahawk/accounts/SpotifyAccount.h b/src/libtomahawk/accounts/SpotifyAccount.h new file mode 100644 index 000000000..67bd97883 --- /dev/null +++ b/src/libtomahawk/accounts/SpotifyAccount.h @@ -0,0 +1,88 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * 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 SpotifyAccount_H +#define SpotifyAccount_H + +#include "playlist.h" +#include "utils/tomahawkutils.h" +#include "sourcelist.h" +#include "ResolverAccount.h" + +class QTimer; + +namespace Tomahawk { + +class ExternalResolverGui; + +namespace Accounts { + + +class SpotifyAccountFactory : public AccountFactory +{ + Q_OBJECT +public: + SpotifyAccountFactory() {} + + virtual Account* createAccount( const QString& accountId = QString() ); + virtual QString description() const { return tr( "Play music from and sync your playlists with Spotify" ); } + virtual QString factoryId() const { return "spotifyaccount"; } + virtual QString prettyName() const { return "Spotify"; } + + virtual bool acceptsPath( const QString& path ) const; + virtual Account* createFromPath( const QString& path ); + + virtual AccountTypes types() const { return AccountTypes( ResolverType ); } + virtual bool allowUserCreation() const { return false; } + virtual QPixmap icon() const; + virtual bool isUnique() const { return true; } + +}; + +class SpotifyAccount : public ResolverAccount +{ + Q_OBJECT +public: + SpotifyAccount( const QString& accountId ); + SpotifyAccount( const QString& accountId, const QString& path ); + virtual ~SpotifyAccount() {} + + virtual QPixmap icon() const; + + virtual QWidget* aclWidget() { return 0; } + virtual InfoSystem::InfoPlugin* infoPlugin() { return 0; } + virtual SipPlugin* sipPlugin() { return 0; } + + void addPlaylist( const QString &qid, const QString& title, QList< Tomahawk::query_ptr > tracks ); + + struct Sync { + QString id_; + QString uuid; + Tomahawk::playlist_ptr playlist; + }; + +private: + QList m_syncPlaylists; + int m_sCount; + +}; +} + +} + +#endif // SpotifyAccount_H diff --git a/src/libtomahawk/resolvers/scriptresolver.cpp b/src/libtomahawk/resolvers/scriptresolver.cpp index 9fd1b96cc..bc72bb1f1 100644 --- a/src/libtomahawk/resolvers/scriptresolver.cpp +++ b/src/libtomahawk/resolvers/scriptresolver.cpp @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -228,7 +229,7 @@ ScriptResolver::handleMsg( const QByteArray& msg ) return; } - if ( msgtype == "results" ) + else if ( msgtype == "results" ) { const QString qid = m.value( "qid" ).toString(); QList< Tomahawk::result_ptr > results; @@ -265,6 +266,25 @@ ScriptResolver::handleMsg( const QByteArray& msg ) Tomahawk::Pipeline::instance()->reportResults( qid, results ); } + else if ( msgtype == "playlist" ) + { + + QList< Tomahawk::query_ptr > tracks; + const QString qid = m.value( "qid" ).toString(); + const QString title = m.value( "identifier" ).toString(); + const QVariantList reslist = m.value( "playlist" ).toList(); + + if( !reslist.isEmpty() ) + { + foreach( const QVariant& rv, reslist ) + { + QVariantMap m = rv.toMap(); + qDebug() << "Found playlist result:" << m; + Tomahawk::query_ptr q = Tomahawk::Query::get( m.value( "artist" ).toString() , m.value( "track" ).toString() , QString(), uuid(), false ); + tracks << q; + } + } + } } diff --git a/src/libtomahawk/resolvers/scriptresolver.h b/src/libtomahawk/resolvers/scriptresolver.h index f8e94b0ff..ffe4e5ae5 100644 --- a/src/libtomahawk/resolvers/scriptresolver.h +++ b/src/libtomahawk/resolvers/scriptresolver.h @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +28,6 @@ #include "query.h" #include "ExternalResolverGui.h" - #include "dllmacro.h" class QWidget; diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index db18dc98e..54081e3f6 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -396,7 +396,8 @@ SettingsDialog::installFromFile() if( !resolver.isEmpty() ) { - Account* acct = ResolverAccountFactory::createFromPath( resolver, false ); + Account* acct = AccountManager::instance()->accountFromPath( resolver ); + AccountManager::instance()->addAccount( acct ); TomahawkSettings::instance()->addAccount( acct->accountId() ); AccountManager::instance()->enableAccount( acct );