From 4c5855c95d5bfe6bef998a13bc15bf369e11eaa8 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Mon, 9 Apr 2012 20:46:12 -0400 Subject: [PATCH 01/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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 9db33b7fb65843933dc6d8a021b70d9478c182a5 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Wed, 11 Apr 2012 12:18:19 -0400 Subject: [PATCH 11/36] New social share icon in now playing controls --- data/images/share.png | Bin 4926 -> 4926 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/images/share.png b/data/images/share.png index c6db17530d57a0afdb7591d88494eb04f1b2a1b1..b6b3dbfb885d9a0a3774f428dbef2b4813bd436e 100644 GIT binary patch delta 1375 zcmai!&r8%n7{+JT&FBZ1VOY{3%NF`!A_R3UTtUU?ut5<~9l8|VqU%L5XS zQ0xb2u#xBf0>d_=TM*qsLBpLs&pY2;wjzAtJM+#n@B6&ZygRcCg@wYa_d7>F=XbQ_ zwjQ7QcEq{Xt3v~4N~ha>sdakIyCy4+l$?tIpq{xhKjQ{RE&xUMZZ7$ix#Lb!Dfjkp?zSS9`w*rm$+bk##vfMY2})z?84&QLcMvE@G)&7g7; zVck%N`tu|{Hx{GG_Un|A3cm^Z3se8uu@=K&ty1l$Is8)%X-Q2(Oy+3X49m#<$sECJ zR-lnWc3Ij?AKRJH=Ko_USyyfa#yFw&NiexOUuujFrPbzGS*;;i7tKA+!EqZoA6OZ# zXD4d4R-Z;&%as}ShbuXf_nI4iH;G`MM_B?tkGn$Bbwcvw`YV7n0G;Ipz&eGQL~FSk zHYhs9AHf2CLI;OS9zaoM+^3&7+Y!gRvBW!+e;C64{(7wXuV-pWB z4&)U#9@_VWi7j2;=c(F4>1VvJd+-?*6d`nvFYRvY&U8dQA@`CSenV{ZP;33ygm9v> xILtpA#@uQSgK_ls7+)RB^y~Ln*XxrRMQ_L6!<})qwy`W|sCaH*_UyF>zX3GUK2ZPw delta 1269 zcmZvcPe@cz7{%`!Uz340&M-m~VXq{GNK!~ri0TbySYV5+U05q=(JsP8^(X>2F>r|p zBC3557Pbg#rcFWAs;EswNV}ko)S`0c^*e9g9aH+?c<%S_-0$A|#%f=+Z~l2l=~H%d zW^2#jrmxqG$xcsY>xb87e}z-K~t86|+#m|+c>3cMX|lOw}_B=*y5_YqoF z0RJ#_8}xt(m|y!z)xYNYHwOR! From 64fbd230088ff8a54691e54c675cba52215e7d9d Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 12:54:56 -0400 Subject: [PATCH 12/36] 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 f42aca9a02945ae09af1643dbf82606733d8c406 Mon Sep 17 00:00:00 2001 From: nowrep Date: Wed, 11 Apr 2012 19:27:12 +0200 Subject: [PATCH 13/36] Fixed position of context menu in ArtistView and TrackView - using viewport()->mapToGlobal() as QTreeView is subclass of QAbstractScrollArea --- src/libtomahawk/playlist/artistview.cpp | 2 +- src/libtomahawk/playlist/trackview.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/artistview.cpp b/src/libtomahawk/playlist/artistview.cpp index 351c76d48..45f55ca19 100644 --- a/src/libtomahawk/playlist/artistview.cpp +++ b/src/libtomahawk/playlist/artistview.cpp @@ -384,7 +384,7 @@ ArtistView::onCustomContextMenu( const QPoint& pos ) m_contextMenu->setArtists( artists ); m_contextMenu->setAlbums( albums ); - m_contextMenu->exec( mapToGlobal( pos ) ); + m_contextMenu->exec( viewport()->mapToGlobal( pos ) ); } diff --git a/src/libtomahawk/playlist/trackview.cpp b/src/libtomahawk/playlist/trackview.cpp index 35ed48376..7939596b1 100644 --- a/src/libtomahawk/playlist/trackview.cpp +++ b/src/libtomahawk/playlist/trackview.cpp @@ -567,7 +567,7 @@ TrackView::onCustomContextMenu( const QPoint& pos ) } m_contextMenu->setQueries( queries ); - m_contextMenu->exec( mapToGlobal( pos ) ); + m_contextMenu->exec( viewport()->mapToGlobal( pos ) ); } From 511d353cc6e676637e0fa44cb7bde15bbf2672a7 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 15:22:34 -0400 Subject: [PATCH 14/36] 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 From 72df1182163f6b556a2eddcc749a28c6cad312b7 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Wed, 11 Apr 2012 16:05:15 -0400 Subject: [PATCH 15/36] Add New Releases icon for sidebar --- data/images/new-releases.png | Bin 0 -> 93598 bytes data/images/share.png | Bin 4926 -> 4926 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/images/new-releases.png diff --git a/data/images/new-releases.png b/data/images/new-releases.png new file mode 100644 index 0000000000000000000000000000000000000000..05252d24e1931dbdb8693b7de7e0ec5406c29498 GIT binary patch literal 93598 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 bR9^m6|E>pq|M%_48M6OZ_PcN26E6FIEu(fU literal 0 HcmV?d00001 diff --git a/data/images/share.png b/data/images/share.png index b6b3dbfb885d9a0a3774f428dbef2b4813bd436e..7cd3e0023f2d8c9b686b90df66468c0d36bec217 100644 GIT binary patch delta 1092 zcmZ8gYeh^v&CzHqljArf5{ZyRlJrI*k<^Wj z^g3Uta&k+`Djo$xq3gLh*+{R`qKx!CWM=j&?jIOIEB;l)FgPleNCR>?+w2+YdF*hc z+A)e7O;8qzM20J^X6{<`MTWwJF1ROuf~0KoagFl zC$toS3?>L90D%jZz~FE=e!+tP*s5yqufV#Gp+96^h1n>uK|mr1ITv@O*dZKJZQl^S zSb$7t3?v*1AEIrG{`!BcNg+_^1d4&PP!Qm7gb!H!46e`wT3TAhlq|@wEc+bV_I>(H z7(10y+;}#DX(t9*gdp%4h9PggljOB$49R4&R!k+E6pO_ssPc|vWTYcnGTMwrQO(sV zRCpqvujuyOhj@DC3zfTsjvz4vJD)Wa3?cvO8dAvRL*t%)W17(@R&U9|U2=o!+)4KpHUiWWUE8YsNf^be-jd3gW; delta 1125 zcmaizO=wd=6oqGA10|9omWtxWs5RhURS?{Z4QNnYL{vo3t>Quux1o0J;_;*|6fA;` z&{BUO6#{1AM)yKRL){AEPFhfD#_!yD$wHA%c=L1aJ?EaeOgfcL<;6^?7#zRZH_a@2 zT-r6fIT=3K{JJlDS9-g%T04J{;B@d|+z02J_e}0J-}QEDK6^GYaim(S-zRWG0Y`G2 zVq!e|-!6pjaHrusNYk-~sVI{IXINhG^+E^fSlAoKPZv89qfNob zNUm)t4lO*ul-J`DYpkCMUTQDRcRgYiG(Lr(`nsriO#PuEcKipU8B~rYtQ+dk(E`LL zreZRAye}!M=$o^@F!i5^wHOU+m1;js*dHHQi*5#H@{N{_uw2|9OGy4{1qKw@4S6$v zg!4h0|Bpqo=dP(Sfz2t@8i6)3o*6MZeb8J^(Un8Xe!CwLF0q8DI0e(@KMOwzyv`*1xdugG= zKBCprbq}B{8@#6 Date: Tue, 10 Apr 2012 17:00:47 -0500 Subject: [PATCH 16/36] Update charts info plugin to use the new API This changes from the /source/billboard/chart/top100 style of uri resource naming to /charts/billboard/top100. The server side changes have been live for several weeks. --- .../infoplugins/generic/chartsplugin.cpp | 140 +++++++++++------- .../infoplugins/generic/chartsplugin.h | 38 ++++- 2 files changed, 117 insertions(+), 61 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp index cf330b695..b9550c1f7 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp @@ -45,10 +45,8 @@ ChartsPlugin::ChartsPlugin() : InfoPlugin() , m_chartsFetchJobs( 0 ) { - /// Add resources here - m_chartResources << "billboard" << "itunes" << "rdio" << "wearehunted" << "ex.fm" << "soundcloudwall"; /// If you add resource, update version aswell - m_chartVersion = "2.1"; + m_chartVersion = "2.2"; m_supportedGetTypes << InfoChart << InfoChartCapabilities; } @@ -104,11 +102,11 @@ ChartsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) } } - fetchChart( requestData ); + fetchChartFromCache( requestData ); break; case InfoChartCapabilities: - fetchChartCapabilities( requestData ); + fetchChartCapabilitiesFromCache( requestData ); break; default: dataError( requestData ); @@ -117,7 +115,7 @@ ChartsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) void -ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData ) +ChartsPlugin::fetchChartFromCache( Tomahawk::InfoSystem::InfoRequestData requestData ) { if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) @@ -145,7 +143,7 @@ ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData ) } void -ChartsPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData ) +ChartsPlugin::fetchChartCapabilitiesFromCache( Tomahawk::InfoSystem::InfoRequestData requestData ) { if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) { @@ -168,53 +166,17 @@ ChartsPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSy case InfoChart: { tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChart not in cache! Fetching..."; - - /// Fetch the chart, we need source and id - QUrl url = QUrl( QString( CHART_URL "source/%1/chart/%2" ).arg( criteria["chart_source"] ).arg( criteria["chart_id"] ) ); - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Getting chart url" << url; - - QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); - reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) ); - - connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) ); + fetchChart( requestData, criteria["chart_source"], criteria["chart_id"] ); return; } case InfoChartCapabilities: { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching..."; - // we never need to re-fetch - //if ( !m_allChartsMap.isEmpty() ) - // return; + fetchChartSourcesList(); + m_cachedRequests.append( requestData ); - /// Then get each chart from resource - - if ( !m_chartResources.isEmpty() && m_allChartsMap.isEmpty() ) - { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChart fetching possible resources"; - foreach ( QString resource, m_chartResources ) - { - QUrl url = QUrl( QString( CHART_URL "source/%1" ).arg( resource ) ); - QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); - reply->setProperty( "chart_resource", resource); - - tDebug() << "fetching:" << url; - connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) ); - - m_chartsFetchJobs++; - } - } - - if ( m_chartsFetchJobs > 0 ) - { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities still fetching!"; - m_cachedRequests.append( requestData ); - return; - } - - emit info( requestData, m_allChartsMap ); return; } @@ -227,21 +189,89 @@ ChartsPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSy } } +void +ChartsPlugin::fetchChartSourcesList() +{ + QUrl url = QUrl( QString( CHART_URL "charts" ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); + + tDebug() << "fetching:" << url; + connect( reply, SIGNAL( finished() ), SLOT( chartSourcesList() ) ); + +} void -ChartsPlugin::chartTypes() +ChartsPlugin::chartSourcesList() { - /// Get possible chart type for specificChartsPlugin: InfoChart types returned chart source - tDebug( LOGVERBOSE ) << "Got chart type result"; + tDebug( LOGVERBOSE ) << "Got chart sources list"; + QNetworkReply* reply = qobject_cast( sender() ); + + if ( reply->error() == QNetworkReply::NoError ) + { + QJson::Parser p; + bool ok; + const QVariantMap res = p.parse( reply, &ok ).toMap(); + const QVariantList sources = res.value( "sources" ).toList(); + + if ( !ok ) + { + tLog() << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine(); + return; + } + + m_chartResources.clear(); + foreach(const QVariant &source, sources) { + m_chartResources << source.toString(); + } + + fetchAllChartSources(); + } +} + +void ChartsPlugin::fetchAllChartSources() +{ + if ( !m_chartResources.isEmpty() && m_allChartsMap.isEmpty() ) + { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChart fetching source data"; + foreach ( QString source, m_chartResources ) + { + QUrl url = QUrl( QString( CHART_URL "charts/%1" ).arg( source ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); + reply->setProperty( "chart_source", source); + + tDebug() << "fetching:" << url; + connect( reply, SIGNAL( finished() ), SLOT( chartsList() ) ); + + m_chartsFetchJobs++; + } + } +} + +void ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData, const QString& source, const QString& chart_id) +{ + /// Fetch the chart, we need source and id + QUrl url = QUrl( QString( CHART_URL "charts/%1/%2" ).arg( source ).arg( chart_id ) ); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "fetching: " << url; + + QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); + reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) ); + + connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) ); +} + + + +void +ChartsPlugin::chartsList() +{ + tDebug( LOGVERBOSE ) << "Got chart list result"; QNetworkReply* reply = qobject_cast( sender() ); - if ( reply->error() == QNetworkReply::NoError ) { QJson::Parser p; bool ok; const QVariantMap res = p.parse( reply, &ok ).toMap(); - const QVariantMap chartObjs = res.value( "charts" ).toMap(); if ( !ok ) { @@ -251,7 +281,7 @@ ChartsPlugin::chartTypes() } /// Got types, append! - const QString source = res.value( "source" ).toString(); + const QString source = reply->property("chart_source").toString(); // We'll populate charts with the data from the server QVariantMap charts; @@ -267,7 +297,7 @@ ChartsPlugin::chartTypes() // WeAreHunted - Type - Artists - Chart Type // - Tracks - Chart Type QHash< QString, QVariantMap > extraType; - foreach( const QVariant& chartObj, chartObjs.values() ) + foreach( const QVariant& chartObj, res.values() ) { if( !chartObj.toMap().isEmpty() ) { @@ -352,7 +382,7 @@ ChartsPlugin::chartTypes() QList< InfoStringHash > trackCharts; QList< InfoStringHash > artistCharts; - foreach( const QVariant& chartObj, chartObjs.values() ) + foreach( const QVariant& chartObj, res.values() ) { if( !chartObj.toMap().isEmpty() ){ const QVariantMap chart = chartObj.toMap(); @@ -407,7 +437,7 @@ ChartsPlugin::chartTypes() } /// Add the possible charts and its types to breadcrumb -// tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "ADDING CHART TYPE TO CHARTS:" << chartName; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "ADDING CHART TO CHARTS:" << chartName; QVariantMap defaultMap = m_allChartsMap.value( "defaults" ).value< QVariantMap >(); defaultMap[ source ] = defaultChain; m_allChartsMap[ "defaults" ] = defaultMap; diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h index 0bebb4629..8ac140854 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h @@ -52,10 +52,6 @@ public: void setChartType( ChartType type ) { m_chartType = type; } ChartType chartType() const { return m_chartType; } -public slots: - void chartReturned(); - void chartTypes(); - protected slots: virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); @@ -65,9 +61,39 @@ protected slots: Q_UNUSED( pushData ); } + /** + * Parses a QNetworkReply of a list of chart sources. + */ + void chartSourcesList(); + + /** + * Parses a QNetworkReply of a list of charts for a particular source + */ + void chartsList(); + + /** + * Parses a QNetworkReply for the chart data for a particular chart + */ + void chartReturned(); + private: - void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData ); - void fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData ); + /** + * Fetch list of chart sources (e.g., itunes, billboard) + * Populates the m_chartResources member. + */ + void fetchChartSourcesList(); + /** + * Requests charts list for each chart source in m_chartResources + */ + void fetchAllChartSources(); + /** + * Fetches a specific chart from a particular source. + * Updates the cache. + */ + void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData, const QString& source, const QString& chart_id ); + + void fetchChartFromCache( Tomahawk::InfoSystem::InfoRequestData requestData ); + void fetchChartCapabilitiesFromCache( Tomahawk::InfoSystem::InfoRequestData requestData ); void dataError( Tomahawk::InfoSystem::InfoRequestData requestData ); QStringList m_chartResources; From 69d1450b5c27341b9a6b6382916864b5208fc977 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Tue, 10 Apr 2012 18:11:58 -0500 Subject: [PATCH 17/36] Implement New Releases info plugin Heavily based off existing charts info plugin, refactoring and consolidating can be done later. --- src/libtomahawk/CMakeLists.txt | 1 + .../infoplugins/generic/newreleasesplugin.cpp | 343 ++++++++++++++++++ .../infoplugins/generic/newreleasesplugin.h | 100 +++++ src/libtomahawk/infosystem/infosystem.h | 5 +- .../infosystem/infosystemworker.cpp | 6 +- 5 files changed, 452 insertions(+), 3 deletions(-) create mode 100644 src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp create mode 100644 src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 797f2acb1..a12425e5c 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -251,6 +251,7 @@ set( libSources infosystem/infoplugins/generic/echonestplugin.cpp infosystem/infoplugins/generic/chartsplugin.cpp + infosystem/infoplugins/generic/newreleasesplugin.cpp infosystem/infoplugins/generic/spotifyPlugin.cpp infosystem/infoplugins/generic/hypemPlugin.cpp infosystem/infoplugins/generic/musixmatchplugin.cpp diff --git a/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp new file mode 100644 index 000000000..d0b2df69e --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp @@ -0,0 +1,343 @@ +#include "newreleasesplugin.h" + +#include +#include +#include +#include + +#include "album.h" +#include "chartsplugin_data_p.h" +#include "typedefs.h" +#include "audio/audioengine.h" +#include "tomahawksettings.h" +#include "utils/tomahawkutils.h" +#include "utils/logger.h" + +#include +#include + +#define CHART_URL "http://charts.tomahawk-player.org/" +//#define CHART_URL "http://localhost:8080/" + +using namespace Tomahawk::InfoSystem; + +NewReleasesPlugin::NewReleasesPlugin() + : InfoPlugin() + , m_nrFetchJobs ( 0 ) +{ + m_nrVersion = "0"; + m_supportedGetTypes << InfoNewReleaseCapabilities << InfoNewRelease; +} + +NewReleasesPlugin::~NewReleasesPlugin() +{ + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO; +} + +void NewReleasesPlugin::dataError ( InfoRequestData requestData ) +{ + emit info ( requestData, QVariant() ); + return; +} + +void NewReleasesPlugin::getInfo ( InfoRequestData requestData ) +{ +//qDebug() << Q_FUNC_INFO << requestData.caller; + //qDebug() << Q_FUNC_INFO << requestData.customData; + + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + bool foundSource = false; + + switch ( requestData.type ) { + case InfoNewRelease: + /// We need something to check if the request is actually ment to go to this plugin + if ( !hash.contains ( "nr_source" ) ) { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required param!"; + dataError ( requestData ); + break; + } else { + foreach ( QString resource, m_nrSources ) { + if ( resource == hash["nr_source"] ) { + foundSource = true; + } + } + + if ( !foundSource ) { + dataError ( requestData ); + break; + } + + } + fetchNRFromCache ( requestData ); + break; + + case InfoNewReleaseCapabilities: + fetchNRCapabilitiesFromCache ( requestData ); + break; + default: + dataError ( requestData ); + } +} + +void NewReleasesPlugin::fetchNRFromCache ( InfoRequestData requestData ) +{ + if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) { + dataError ( requestData ); + return; + } + + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + Tomahawk::InfoSystem::InfoStringHash criteria; + + /// Each request needs to contain both a id and source + if ( !hash.contains ( "nr_id" ) && !hash.contains ( "nr_source" ) ) { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required params!"; + dataError ( requestData ); + return; + + } + /// Set the criterias for current chart + criteria["nr_id"] = hash["nr_id"]; + criteria["nr_source"] = hash["nr_source"]; + + emit getCachedInfo ( criteria, 86400000, requestData ); +} + +void NewReleasesPlugin::fetchNRCapabilitiesFromCache ( InfoRequestData requestData ) +{ + if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Could not convert requestData to InfoStringHash!"; + dataError ( requestData ); + return; + } + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria[ "InfoNewReleaseCapabilities" ] = "newreleasesplugin"; + criteria[ "InfoNewReleaseVersion" ] = m_nrVersion; + emit getCachedInfo ( criteria, 864000000, requestData ); +} + +void NewReleasesPlugin::notInCacheSlot ( InfoStringHash criteria, InfoRequestData requestData ) +{ + switch ( requestData.type ) { + case InfoNewRelease: { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoNewRelease not in cache! Fetching..."; + fetchNR ( requestData, criteria["nr_source"], criteria["nr_id"] ); + return; + + } + + case InfoNewReleaseCapabilities: { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching..."; + fetchNRSourcesList(); + m_cachedRequests.append ( requestData ); + + return; + } + + default: { + tLog() << Q_FUNC_INFO << "Couldn't figure out what to do with this type of request after cache miss"; + emit info ( requestData, QVariant() ); + return; + } + } +} + +void NewReleasesPlugin::fetchNRSourcesList() +{ + QUrl url = QUrl ( QString ( CHART_URL "newreleases" ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) ); + + tDebug() << "fetching:" << url; + connect ( reply, SIGNAL ( finished() ), SLOT ( nrSourcesList() ) ); + +} + +void NewReleasesPlugin::nrSourcesList() +{ + tDebug ( LOGVERBOSE ) << "Got newreleases sources list"; + QNetworkReply* reply = qobject_cast ( sender() ); + + if ( reply->error() == QNetworkReply::NoError ) { + QJson::Parser p; + bool ok; + const QVariantMap res = p.parse ( reply, &ok ).toMap(); + const QVariantList sources = res.value ( "sources" ).toList(); + + if ( !ok ) { + tLog() << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine(); + return; + } + + m_nrSources.clear(); + foreach ( const QVariant &source, sources ) { + m_nrSources << source.toString(); + } + + fetchAllNRSources(); + } +} + +void NewReleasesPlugin::fetchAllNRSources() +{ + if ( !m_nrSources.isEmpty() && m_allNRsMap.isEmpty() ) { + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoNewRelease fetching source data"; + foreach ( QString source, m_nrSources ) { + QUrl url = QUrl ( QString ( CHART_URL "newreleases/%1" ).arg ( source ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) ); + reply->setProperty ( "nr_source", source ); + + tDebug() << "fetching:" << url; + connect ( reply, SIGNAL ( finished() ), SLOT ( nrList() ) ); + + m_nrFetchJobs++; + } + } +} + +void NewReleasesPlugin::fetchNR ( InfoRequestData requestData, const QString& source, const QString& nr_id ) +{ + /// Fetch the chart, we need source and id + QUrl url = QUrl ( QString ( CHART_URL "newreleases/%1/%2" ).arg ( source ).arg ( nr_id ) ); + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "fetching: " << url; + + QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) ); + reply->setProperty ( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData > ( requestData ) ); + + connect ( reply, SIGNAL ( finished() ), SLOT ( nrReturned() ) ); +} + +void NewReleasesPlugin::nrList() +{ + tDebug ( LOGVERBOSE ) << "Got newreleases list result"; + QNetworkReply* reply = qobject_cast ( sender() ); + + if ( reply->error() == QNetworkReply::NoError ) { + QJson::Parser p; + bool ok; + const QVariantMap res = p.parse ( reply, &ok ).toMap(); + + if ( !ok ) { + tLog() << "Failed to parse resources" << p.errorString() << "On line" << p.errorLine(); + + return; + } + + /// Got types, append! + const QString source = reply->property ( "nr_source" ).toString(); + + // We'll populate newreleases with the data from the server + QVariantMap newreleases; + QString nrName; + + // Building: + // [Source] - New Release + QList< InfoStringHash > albumNRs; + + foreach ( const QVariant &nrObj, res.values() ) { + if ( !nrObj.toMap().isEmpty() ) { + const QVariantMap nrMap = nrObj.toMap(); + const QString type = nrMap.value ( "type" ).toString(); + + InfoStringHash nr; + nr["id"] = nrMap.value ( "id" ).toString(); + nr["label"] = nrMap.value ( "name" ).toString(); + nr["date"] = nrMap.value ( "date" ).toString(); + + if ( type == "Album" ) { + nr[ "type" ] = "album"; + albumNRs.append ( nr ); + } else { + tLog() << "Unknown newrelease type " << type; + continue; + } + + } + } + if ( !albumNRs.isEmpty() ) + newreleases.insert ( tr ( "Albums" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > > ( albumNRs ) ); + + /// @note For displaying purposes, upper the first letter + /// @note Remeber to lower it when fetching this! + nrName = source; + nrName[0] = nrName[0].toUpper(); + + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "ADDING newrelease TO NRS:" << nrName; + QVariantMap defaultMap = m_allNRsMap.value ( "defaults" ).value< QVariantMap >(); + m_allNRsMap.insert ( nrName, QVariant::fromValue< QVariantMap > ( newreleases ) ); + + } else { + tLog() << "Error fetching charts:" << reply->errorString(); + } + + m_nrFetchJobs--; + if ( !m_cachedRequests.isEmpty() && m_nrFetchJobs == 0 ) { + foreach ( InfoRequestData request, m_cachedRequests ) { + emit info ( request, m_allNRsMap ); + // update cache + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria[ "InfoNewReleaseCapabilities" ] = "newreleasesplugin"; + criteria[ "InfoNewReleaseVersion" ] = m_nrVersion; + emit updateCache ( criteria, 864000000, request.type, m_allNRsMap ); + } + m_cachedRequests.clear(); + } +} + +void NewReleasesPlugin::nrReturned() +{ + /// Chart request returned something! Woho + QNetworkReply* reply = qobject_cast ( sender() ); + QVariantMap returnedData; + + if ( reply->error() == QNetworkReply::NoError ) { + QJson::Parser p; + bool ok; + QVariantMap res = p.parse ( reply, &ok ).toMap(); + + if ( !ok ) { + tLog() << "Failed to parse json from chart lookup:" << p.errorString() << "On line" << p.errorLine(); + return; + } + + /// SO we have a result, parse it! + QVariantList albumList = res.value ( "list" ).toList(); + QList< Tomahawk::InfoSystem::InfoStringHash > newreleases; + + foreach( const QVariant & albumObj, albumList ) { + QVariantMap albumMap = albumObj.toMap(); + if(!albumMap.isEmpty()) { + const QString album = albumMap.value("album").toString(); + const QString artist = albumMap.value("artist").toString(); + const QString date = albumMap.value("date").toString(); + + Tomahawk::InfoSystem::InfoStringHash pair; + pair["artist"] = artist; + pair["album"] = album; + newreleases.append( pair ); + } + } + + tDebug() << "NewReleasesPlugin:" << "\tgot " << newreleases.size() << " albums"; + returnedData[ "albums" ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( newreleases ); + returnedData[ "type" ] = "albums"; + Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); + + emit info( requestData, returnedData ); + // update cache + Tomahawk::InfoSystem::InfoStringHash criteria; + Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + criteria[ "nr_id" ] = origData[ "nr_id" ]; + criteria[ "nr_source" ] = origData[ "nr_source" ]; + emit updateCache( criteria, 86400000, requestData.type, returnedData ); + } else + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Network error in fetching newrelease:" << reply->url().toString(); +} + + + + + + + + diff --git a/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h new file mode 100644 index 000000000..de17b8fca --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h @@ -0,0 +1,100 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Casey Link + * + * 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 NEWRELEASESPLUGIN_H +#define NEWRELEASESPLUGIN_H + +#include "infosystem/infosystem.h" +#include "infosystem/infosystemworker.h" +#include +#include + +class QNetworkReply; + +namespace Tomahawk +{ + +namespace InfoSystem +{ + +class NewReleasesPlugin : public InfoPlugin +{ + Q_OBJECT + +public: + NewReleasesPlugin(); + virtual ~NewReleasesPlugin(); + +protected slots: + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); + virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); + + virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) + { + Q_UNUSED( pushData ); + } + + /** + * Parses a QNetworkReply of a list of newreleases sources. + */ + void nrSourcesList(); + + /** + * Parses a QNetworkReply of a list of newreleases from a particular source + */ + void nrList(); + + /** + * Parses a QNetworkReply for the newreleases data for a particular newrelease + */ + void nrReturned(); + +private: + /** + * Fetch list of newlreeases sources (e.g., rovi) + * Populates the m_nrSources member. + */ + void fetchNRSourcesList(); + /** + * Requests newrelease list for each source in m_chartSources + */ + void fetchAllNRSources(); + /** + * Fetches a specific newrelease from a particular source. + * Updates the cache. + */ + void fetchNR( Tomahawk::InfoSystem::InfoRequestData requestData, const QString& source, const QString& nr_id ); + void fetchNRFromCache( Tomahawk::InfoSystem::InfoRequestData requestData ); + void fetchNRCapabilitiesFromCache( Tomahawk::InfoSystem::InfoRequestData requestData ); + void dataError( Tomahawk::InfoSystem::InfoRequestData requestData ); + + QStringList m_nrSources; + QString m_nrVersion; + QList< InfoStringHash > m_newreleases; + //ChartType m_chartType; + QVariantMap m_allNRsMap; + uint m_nrFetchJobs; + QList< InfoRequestData > m_cachedRequests; + QHash< QString, QString > m_cachedCountries; + QWeakPointer< QNetworkAccessManager > m_nam; +}; + +} +} + +#endif // NEWRELEASESPLUGIN_H diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index c59b6d62e..bb0716525 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -112,6 +112,9 @@ enum InfoType { // as items are saved in cache, mark them here to not change the */ InfoChart = 51, + InfoNewReleaseCapabilities = 52, + InfoNewRelease = 53, + InfoMiscTopHotttness = 60, InfoMiscTopTerms = 61, @@ -195,7 +198,7 @@ struct InfoPushData { , pushFlags( pflags ) , infoPair( Tomahawk::InfoSystem::PushInfoPair( QVariantMap(), QVariant() ) ) {} - + }; diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index a59bdd4ad..cdefc1095 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -28,6 +28,7 @@ #include "infoplugins/generic/echonestplugin.h" #include "infoplugins/generic/musixmatchplugin.h" #include "infoplugins/generic/chartsplugin.h" +#include "infoplugins/generic/newreleasesplugin.h" #include "infoplugins/generic/spotifyPlugin.h" #include "infoplugins/generic/musicbrainzPlugin.h" #include "infoplugins/generic/hypemPlugin.h" @@ -86,6 +87,7 @@ InfoSystemWorker::init( Tomahawk::InfoSystem::InfoSystemCache* cache ) addInfoPlugin( InfoPluginPtr( new MusixMatchPlugin() ) ); addInfoPlugin( InfoPluginPtr( new MusicBrainzPlugin() ) ); addInfoPlugin( InfoPluginPtr( new ChartsPlugin() ) ); + addInfoPlugin( InfoPluginPtr( new NewReleasesPlugin() ) ); addInfoPlugin( InfoPluginPtr( new RoviPlugin() ) ); addInfoPlugin( InfoPluginPtr( new SpotifyPlugin() ) ); addInfoPlugin( InfoPluginPtr( new hypemPlugin() ) ); @@ -274,7 +276,7 @@ void InfoSystemWorker::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) { tDebug() << Q_FUNC_INFO << "type is " << pushData.type; - + if ( pushData.pushFlags != PushNoFlag ) { if ( pushData.pushFlags & PushShortUrlFlag ) @@ -334,7 +336,7 @@ InfoSystemWorker::shortLinkReady( QUrl longUrl, QUrl shortUrl, QVariant callback m_shortLinksWaiting--; if ( !m_shortLinksWaiting ) disconnect( GlobalActionManager::instance(), SIGNAL( shortLinkReady( QUrl, QUrl, QVariant ) ) ); - + if ( !callbackObj.isValid() ) { tDebug() << Q_FUNC_INFO << "callback object was not valid, cannot continue"; From 548aa1a19445bd9b060527beeb4f7f4ffb772403 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Wed, 11 Apr 2012 15:58:38 -0500 Subject: [PATCH 18/36] First pass at new releases widget --- resources.qrc | 1 + src/libtomahawk/CMakeLists.txt | 2 + src/libtomahawk/viewmanager.cpp | 10 + src/libtomahawk/viewmanager.h | 4 + src/libtomahawk/widgets/newreleaseswidget.cpp | 372 ++++++++++++++++++ src/libtomahawk/widgets/newreleaseswidget.h | 126 ++++++ src/libtomahawk/widgets/newreleaseswidget.ui | 58 +++ src/sourcetree/sourcesmodel.cpp | 7 +- 8 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 src/libtomahawk/widgets/newreleaseswidget.cpp create mode 100644 src/libtomahawk/widgets/newreleaseswidget.h create mode 100644 src/libtomahawk/widgets/newreleaseswidget.ui diff --git a/resources.qrc b/resources.qrc index 5f43a73b5..7ec141532 100644 --- a/resources.qrc +++ b/resources.qrc @@ -87,6 +87,7 @@ data/images/station.png data/images/new-additions.png data/images/charts.png + data/images/new-releases.png data/images/loved_playlist.png data/images/dashboard.png data/images/artist-icon.png diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index a12425e5c..e76a53f04 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -134,6 +134,7 @@ set( libGuiSources widgets/playlisttypeselectordlg.cpp widgets/welcomewidget.cpp widgets/whatshotwidget.cpp + widgets/newreleaseswidget.cpp widgets/ChartDataLoader.cpp widgets/RecentlyPlayedPlaylistsModel.cpp widgets/RecentPlaylistsModel.cpp @@ -303,6 +304,7 @@ set( libUI ${libUI} widgets/searchwidget.ui widgets/welcomewidget.ui widgets/whatshotwidget.ui + widgets/newreleaseswidget.ui widgets/SocialPlaylistWidget.ui widgets/infowidgets/sourceinfowidget.ui widgets/infowidgets/ArtistInfoWidget.ui diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp index 92eb4fba5..3d0beb93e 100644 --- a/src/libtomahawk/viewmanager.cpp +++ b/src/libtomahawk/viewmanager.cpp @@ -75,6 +75,7 @@ ViewManager::ViewManager( QObject* parent ) , m_widget( new QWidget() ) , m_welcomeWidget( new WelcomeWidget() ) , m_whatsHotWidget( new WhatsHotWidget() ) + , m_newReleasesWidget( new NewReleasesWidget() ) , m_topLovedWidget( 0 ) , m_recentPlaysWidget( 0 ) , m_currentMode( PlaylistInterface::Tree ) @@ -119,6 +120,7 @@ ViewManager::ViewManager( QObject* parent ) connect( m_infobar, SIGNAL( autoUpdateChanged( bool ) ), SLOT( autoUpdateChanged( bool ) ) ); connect( this, SIGNAL( tomahawkLoaded() ), m_whatsHotWidget, SLOT( fetchData() ) ); + connect( this, SIGNAL( tomahawkLoaded() ), m_newReleasesWidget, SLOT( fetchData() ) ); connect( this, SIGNAL( tomahawkLoaded() ), m_welcomeWidget, SLOT( loadData() ) ); /* connect( m_infobar, SIGNAL( flatMode() ), SLOT( setTableMode() ) ); @@ -131,6 +133,7 @@ ViewManager::~ViewManager() { saveCurrentPlaylistSettings(); delete m_whatsHotWidget; + delete m_newReleasesWidget; delete m_welcomeWidget; delete m_topLovedWidget; delete m_recentPlaysWidget; @@ -438,6 +441,13 @@ ViewManager::showWhatsHotPage() } +Tomahawk::ViewPage* +ViewManager::showNewReleasesPage() +{ + return show( m_newReleasesWidget ); +} + + Tomahawk::ViewPage* ViewManager::showTopLovedPage() { diff --git a/src/libtomahawk/viewmanager.h b/src/libtomahawk/viewmanager.h index 52a8e3ee0..f7f4ef21e 100644 --- a/src/libtomahawk/viewmanager.h +++ b/src/libtomahawk/viewmanager.h @@ -31,6 +31,7 @@ #include "viewpage.h" #include "widgets/welcomewidget.h" #include "widgets/whatshotwidget.h" +#include "widgets/newreleaseswidget.h" #include "dllmacro.h" @@ -91,6 +92,7 @@ public: Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; } Tomahawk::ViewPage* whatsHotWidget() const { return m_whatsHotWidget; } + Tomahawk::ViewPage* newReleasesWidget() const { return m_newReleasesWidget; } Tomahawk::ViewPage* topLovedWidget() const { return m_topLovedWidget; } Tomahawk::ViewPage* recentPlaysWidget() const { return m_recentPlaysWidget; } ArtistView* superCollectionView() const { return m_superCollectionView; } @@ -140,6 +142,7 @@ public slots: Tomahawk::ViewPage* showSuperCollection(); Tomahawk::ViewPage* showWelcomePage(); Tomahawk::ViewPage* showWhatsHotPage(); + Tomahawk::ViewPage* showNewReleasesPage(); Tomahawk::ViewPage* showTopLovedPage(); Tomahawk::ViewPage* showRecentPlaysPage(); void showCurrentTrack(); @@ -205,6 +208,7 @@ private: QueueView* m_queue; WelcomeWidget* m_welcomeWidget; WhatsHotWidget* m_whatsHotWidget; + NewReleasesWidget* m_newReleasesWidget; Tomahawk::ViewPage* m_topLovedWidget; Tomahawk::ViewPage* m_recentPlaysWidget; diff --git a/src/libtomahawk/widgets/newreleaseswidget.cpp b/src/libtomahawk/widgets/newreleaseswidget.cpp new file mode 100644 index 000000000..59752333d --- /dev/null +++ b/src/libtomahawk/widgets/newreleaseswidget.cpp @@ -0,0 +1,372 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Casey Link + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2011, Leo Franchi + * Copyright 2011, 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 "newreleaseswidget.h" +#include "whatshotwidget_p.h" +#include "ui_newreleaseswidget.h" + +#include +#include +#include + +#include "viewmanager.h" +#include "sourcelist.h" +#include "tomahawksettings.h" +#include "RecentPlaylistsModel.h" +#include "ChartDataLoader.h" + +#include "audio/audioengine.h" +#include "dynamic/GeneratorInterface.h" +#include "playlist/playlistmodel.h" +#include "playlist/treeproxymodel.h" +#include "playlist/PlaylistChartItemDelegate.h" +#include "widgets/overlaywidget.h" +#include "utils/tomahawkutils.h" +#include "utils/logger.h" +#include "pipeline.h" + +#define HISTORY_TRACK_ITEMS 25 +#define HISTORY_PLAYLIST_ITEMS 10 +#define HISTORY_RESOLVING_TIMEOUT 2500 + +using namespace Tomahawk; + +static QString s_newReleasesIdentifier = QString( "NewReleasesWidget" ); + + +NewReleasesWidget::NewReleasesWidget( QWidget* parent ) + : QWidget( parent ) + , ui( new Ui::NewReleasesWidget ) + , m_sortedProxy( 0 ) + , m_workerThread( 0 ) +{ + ui->setupUi( this ); + + ui->albumsView->setFrameShape( QFrame::NoFrame ); + ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + TomahawkUtils::unmarginLayout( layout() ); + TomahawkUtils::unmarginLayout( ui->stackLeft->layout() ); + TomahawkUtils::unmarginLayout( ui->horizontalLayout->layout() ); + TomahawkUtils::unmarginLayout( ui->horizontalLayout_2->layout() ); + TomahawkUtils::unmarginLayout( ui->breadCrumbLeft->layout() ); + TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() ); + + m_crumbModelLeft = new QStandardItemModel( this ); + m_sortedProxy = new QSortFilterProxyModel( this ); + m_sortedProxy->setDynamicSortFilter( true ); + m_sortedProxy->setFilterCaseSensitivity( Qt::CaseInsensitive ); + + ui->breadCrumbLeft->setRootIcon( QPixmap( RESPATH "images/new-releases.png" ) ); + + connect( ui->breadCrumbLeft, SIGNAL( activateIndex( QModelIndex ) ), SLOT( leftCrumbIndexChanged(QModelIndex) ) ); + + + //m_playlistInterface = Tomahawk::playlistinterface_ptr( new ChartsPlaylistInterface( this ) ); + + m_workerThread = new QThread( this ); + m_workerThread->start(); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); +} + + +NewReleasesWidget::~NewReleasesWidget() +{ + qDeleteAll( m_workers ); + m_workers.clear(); + m_workerThread->exit(0); + m_playlistInterface.clear(); + delete ui; +} + + +Tomahawk::playlistinterface_ptr +NewReleasesWidget::playlistInterface() const +{ + return m_playlistInterface; +} + + +bool +NewReleasesWidget::isBeingPlayed() const +{ + return false; +} + + +bool +NewReleasesWidget::jumpToCurrentTrack() +{ + return false; +} + + +void +NewReleasesWidget::fetchData() +{ + Tomahawk::InfoSystem::InfoStringHash artistInfo; + + Tomahawk::InfoSystem::InfoRequestData requestData; + requestData.caller = s_newReleasesIdentifier; + requestData.customData = QVariantMap(); + requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); + requestData.type = Tomahawk::InfoSystem::InfoNewReleaseCapabilities; + requestData.timeoutMillis = 20000; + requestData.allSources = true; + Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); + + tDebug( LOGVERBOSE ) << "NewReleases: requested InfoNewReleaseCapabilities"; +} + + +void +NewReleasesWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) +{ + if ( requestData.caller != s_newReleasesIdentifier ) + return; + + if ( !output.canConvert< QVariantMap >() ) + { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "NewReleases: Could not parse output"; + return; + } + + QVariantMap returnedData = output.toMap(); + switch ( requestData.type ) + { + case InfoSystem::InfoNewReleaseCapabilities: + { + tLog() << "NewReleases: got InfoNewReleaseCapabilities"; + QStandardItem *rootItem= m_crumbModelLeft->invisibleRootItem(); + + foreach ( const QString label, returnedData.keys() ) + { + QStandardItem *childItem = parseNode( rootItem, label, returnedData[label] ); + rootItem->appendRow(childItem); + tLog() << "NewReleases: " << label; + } + + m_sortedProxy->setSourceModel( m_crumbModelLeft ); + m_sortedProxy->sort( 0, Qt::AscendingOrder ); + ui->breadCrumbLeft->setModel( m_sortedProxy ); + break; + } + + case InfoSystem::InfoNewRelease: + { + if( !returnedData.contains("type") ) + break; + const QString type = returnedData["type"].toString(); + if( !returnedData.contains(type) ) + break; + const QString side = requestData.customData["whatshot_side"].toString(); + const QString chartId = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >().value( "nr_id" ); + + m_queuedFetches.remove( chartId ); + + ChartDataLoader* loader = new ChartDataLoader(); + loader->setProperty( "nrid", chartId ); + loader->moveToThread( m_workerThread ); + + if ( type == "albums" ) + { + + loader->setType( ChartDataLoader::Album ); + loader->setData( returnedData[ "albums" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); + + connect( loader, SIGNAL( albums( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ), this, SLOT( newReleasesLoaded( Tomahawk::ChartDataLoader*, QList ) ) ); + + AlbumModel* albumModel = new AlbumModel( ui->albumsView ); + + m_albumModels[ chartId ] = albumModel; + + if ( m_queueItemToShow == chartId ) + setLeftViewAlbums( albumModel ); + } + else + { + // intentionally unhandled + } + + QMetaObject::invokeMethod( loader, "go", Qt::QueuedConnection ); + + break; + } + + default: + return; + } +} + + +void +NewReleasesWidget::infoSystemFinished( QString target ) +{ + Q_UNUSED( target ); +} + + +void +NewReleasesWidget::leftCrumbIndexChanged( QModelIndex index ) +{ + tDebug( LOGVERBOSE ) << "NewReleases:: left crumb changed" << index.data(); + QStandardItem* item = m_crumbModelLeft->itemFromIndex( m_sortedProxy->mapToSource( index ) ); + if( !item ) + return; + if( !item->data( Breadcrumb::ChartIdRole ).isValid() ) + return; + + + QList indexes; + while ( index.parent().isValid() ) + { + indexes.prepend(index); + index = index.parent(); + } + + + const QString nrId = item->data( Breadcrumb::ChartIdRole ).toString(); + + if ( m_albumModels.contains( nrId ) ) + { + setLeftViewAlbums( m_albumModels[ nrId ] ); + return; + } + + if ( m_queuedFetches.contains( nrId ) ) + { + return; + } + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria.insert( "nr_id", nrId ); + /// Remember to lower the source! + criteria.insert( "nr_source", index.data().toString().toLower() ); + + Tomahawk::InfoSystem::InfoRequestData requestData; + QVariantMap customData; + customData.insert( "newrelease_side", "left" ); + requestData.caller = s_newReleasesIdentifier; + requestData.customData = customData; + requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( criteria ); + requestData.type = Tomahawk::InfoSystem::InfoNewRelease; + requestData.timeoutMillis = 20000; + requestData.allSources = true; + + qDebug() << "Making infosystem request for chart of type:" <getInfo( requestData ); + + m_queuedFetches.insert( nrId ); + m_queueItemToShow = nrId; +} + + +void +NewReleasesWidget::changeEvent( QEvent* e ) +{ + QWidget::changeEvent( e ); + switch ( e->type() ) + { + case QEvent::LanguageChange: + ui->retranslateUi( this ); + break; + + default: + break; + } +} + + +QStandardItem* +NewReleasesWidget::parseNode( QStandardItem* parentItem, const QString &label, const QVariant &data ) +{ + Q_UNUSED( parentItem ); +// tDebug( LOGVERBOSE ) << "NewReleases:: parsing " << label; + + QStandardItem *sourceItem = new QStandardItem(label); + + if ( data.canConvert< QList< Tomahawk::InfoSystem::InfoStringHash > >() ) + { + QList< Tomahawk::InfoSystem::InfoStringHash > charts = data.value< QList< Tomahawk::InfoSystem::InfoStringHash > >(); + foreach ( Tomahawk::InfoSystem::InfoStringHash chart, charts ) + { + QStandardItem *childItem= new QStandardItem( chart[ "label" ] ); + childItem->setData( chart[ "id" ], Breadcrumb::ChartIdRole ); + if ( chart.value( "default", "" ) == "true") + { + childItem->setData( true, Breadcrumb::DefaultRole ); + } + sourceItem->appendRow( childItem ); + } + } + else if ( data.canConvert() ) + { + QVariantMap dataMap = data.toMap(); + foreach ( const QString childLabel,dataMap.keys() ) + { + QStandardItem *childItem = parseNode( sourceItem, childLabel, dataMap[childLabel] ); + sourceItem->appendRow( childItem ); + } + } + else if ( data.canConvert() ) + { + QVariantList dataList = data.toList(); + + foreach ( const QVariant value, dataList ) + { + QStandardItem *childItem= new QStandardItem(value.toString()); + sourceItem->appendRow(childItem); + } + } + else + { + QStandardItem *childItem= new QStandardItem( data.toString() ); + sourceItem->appendRow( childItem ); + } + return sourceItem; +} + + +void +NewReleasesWidget::setLeftViewAlbums( AlbumModel* model ) +{ + ui->albumsView->setAlbumModel( model ); + ui->albumsView->proxyModel()->sort( -1 ); // disable sorting, must be called after artistsViewLeft->setTreeModel + ui->stackLeft->setCurrentIndex( 2 ); +} + +void +NewReleasesWidget::newReleasesLoaded( ChartDataLoader* loader, const QList< album_ptr >& albums ) +{ + QString chartId = loader->property( "nrid" ).toString(); + Q_ASSERT( m_albumModels.contains( chartId ) ); + + if ( m_albumModels.contains( chartId ) ) + m_albumModels[ chartId ]->addAlbums( albums ); + + m_workers.remove( loader ); + loader->deleteLater(); +} diff --git a/src/libtomahawk/widgets/newreleaseswidget.h b/src/libtomahawk/widgets/newreleaseswidget.h new file mode 100644 index 000000000..8223f7482 --- /dev/null +++ b/src/libtomahawk/widgets/newreleaseswidget.h @@ -0,0 +1,126 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Casey Link + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2011, Leo Franchi + * Copyright 2011, 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 NEWRELEASESWIDGET_H +#define NEWRELEASESWIDGET_H + +#include +#include +#include + +#include "playlistinterface.h" +#include "infosystem/infosystem.h" +#include "viewpage.h" + +#include "utils/tomahawkutils.h" + +#include "dllmacro.h" + +class QSortFilterProxyModel; +class QStandardItemModel; +class QStandardItem; +class TreeModel; +class PlaylistModel; +class OverlayWidget; +class TreeProxyModel; +class AlbumModel; + +namespace Ui +{ + class NewReleasesWidget; +} + +namespace Tomahawk +{ + class ChartDataLoader; + class ChartsPlaylistInterface; + class ChartDataLoader; +} + +/** + * \class + * \brief The tomahawk page that shows music charts. + */ +class DLLEXPORT NewReleasesWidget : public QWidget, public Tomahawk::ViewPage +{ +Q_OBJECT + +public: + NewReleasesWidget( QWidget* parent = 0 ); + ~NewReleasesWidget(); + + virtual QWidget* widget() { return this; } + virtual Tomahawk::playlistinterface_ptr playlistInterface() const; + + virtual QString title() const { return tr( "New Releases" ); } + virtual QString description() const { return QString(); } + + virtual bool showStatsBar() const { return false; } + virtual bool showInfoBar() const { return false; } + + virtual bool jumpToCurrentTrack(); + virtual bool isBeingPlayed() const; + +protected: + void changeEvent( QEvent* e ); + +signals: + void destroyed( QWidget* widget ); + +public slots: + void fetchData(); + +private slots: + void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); + void infoSystemFinished( QString target ); + void leftCrumbIndexChanged( QModelIndex ); + + void newReleasesLoaded( Tomahawk::ChartDataLoader*, const QList< Tomahawk::album_ptr >& ); + +private: + void setLeftViewArtists( TreeModel* artistModel ); + void setLeftViewAlbums( AlbumModel* albumModel ); + void setLeftViewTracks( PlaylistModel* trackModel ); + + + QStandardItem* parseNode( QStandardItem* parentItem, const QString &label, const QVariant &data ); + Ui::NewReleasesWidget *ui; + Tomahawk::playlistinterface_ptr m_playlistInterface; + + QStandardItemModel* m_crumbModelLeft; + QSortFilterProxyModel* m_sortedProxy; + + // Load artist, album, and track objects in a thread + // {Artist,Album,Track}::get() calls are all synchronous db calls + // and we don't want to lock up out UI in case the db is busy (e.g. on startup) + QThread* m_workerThread; + QSet< Tomahawk::ChartDataLoader* > m_workers; + + // Cache our model data + QHash< QString, AlbumModel* > m_albumModels; + QString m_queueItemToShow; + QSet< QString > m_queuedFetches; + QTimer* m_timer; + + friend class Tomahawk::ChartsPlaylistInterface; +}; + +#endif // NEWRELEASESWIDGET_H diff --git a/src/libtomahawk/widgets/newreleaseswidget.ui b/src/libtomahawk/widgets/newreleaseswidget.ui new file mode 100644 index 000000000..094c4553a --- /dev/null +++ b/src/libtomahawk/widgets/newreleaseswidget.ui @@ -0,0 +1,58 @@ + + + NewReleasesWidget + + + + 0 + 0 + 875 + 513 + + + + + + + + + + + + + + + + + + + + true + + + QAbstractItemView::ExtendedSelection + + + + + + + + + + + + AlbumView + QListView +
playlist/albumview.h
+
+ + Tomahawk::Breadcrumb + QWidget +
widgets/Breadcrumb.h
+ 1 +
+
+ + +
diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp index 7ee3b8b0c..5b0d96ce9 100644 --- a/src/sourcetree/sourcesmodel.cpp +++ b/src/sourcetree/sourcesmodel.cpp @@ -297,6 +297,11 @@ SourcesModel::appendGroups() boost::bind( &ViewManager::whatsHotWidget, ViewManager::instance() ) ); hot->setSortValue( 4 ); + GenericPageItem* newReleases = new GenericPageItem( this, browse, tr( "New Releases" ), QIcon( RESPATH "images/new-releases.png" ), + boost::bind( &ViewManager::showNewReleasesPage, ViewManager::instance() ), + boost::bind( &ViewManager::newReleasesWidget, ViewManager::instance() ) ); + newReleases->setSortValue( 5 ); + m_collectionsGroup = new GroupItem( this, m_rootItem, tr( "Friends" ), 4 ); endInsertRows(); @@ -320,7 +325,7 @@ SourcesModel::appendItem( const Tomahawk::source_ptr& source ) beginInsertRows( idx, rowCount( idx ), rowCount( idx ) ); new SourceItem( this, parent, source ); endInsertRows(); - + parent->checkExpandedState(); } From 066a7a2660192b3bf5aad35095cdae70d6cffb43 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Wed, 11 Apr 2012 22:16:57 +0000 Subject: [PATCH 19/36] Automatic merge of Transifex translations --- lang/tomahawk_bg.ts | 189 ++- lang/tomahawk_de.ts | 163 +- lang/tomahawk_en.ts | 163 +- lang/tomahawk_es.ts | 163 +- lang/tomahawk_fr.ts | 3591 ++++++++++++++++++++++++++++++++++++++++ lang/tomahawk_ja.ts | 163 +- lang/tomahawk_pl.ts | 181 +- lang/tomahawk_pt_BR.ts | 163 +- lang/tomahawk_ru.ts | 163 +- lang/tomahawk_sv.ts | 163 +- 10 files changed, 4693 insertions(+), 409 deletions(-) create mode 100644 lang/tomahawk_fr.ts diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index e36a5aa44..074d83e32 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -296,36 +296,41 @@ Remember: Only allow peers to connect if you trust who they are and if you have + social + социален + + + love Харесай - + Time Продължителност - + Time Left Оставащо време - + Shuffle Разбъркано - + Repeat Повтори - + Low 0 - + High 100% @@ -680,6 +685,14 @@ Remember: Only allow peers to connect if you trust who they are and if you have Създай нов списък + + NewReleasesWidget + + + New Releases + + + PlaylistItemDelegate @@ -1052,6 +1065,49 @@ Remember: Only allow peers to connect if you trust who they are and if you have Най-изпълнявани песни, които нямаш в наличност + + SocialWidget + + + Form + Бланка + + + + Facebook + Facebook + + + + Twitter + Twitter + + + + Cover + Обложка + + + + TextLabel + Етикет + + + + Listening to "%1" by %2 and loving it! %4 + Слушам "%1" от %2 и я харесвам! %4 + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + Слушам "%1" от %2 от "%3" и я харесвам! %4 + + + + %1 characters left + Остават още %1 символа + + SourceDelegate @@ -1265,6 +1321,11 @@ Remember: Only allow peers to connect if you trust who they are and if you have + New Releases + + + + Friends Приятели @@ -1532,7 +1593,7 @@ Spotify e TM на Spotify Group. Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. Свържи се с твоите приятели в Twitter @@ -1732,12 +1793,12 @@ You may wish to try re-authenticating. &Continue Playback after this Track - + &Продължи след тази песен &Stop Playback after this Track - + &Спри след тази песен @@ -2123,7 +2184,7 @@ Try tweaking the filters for a new set of songs to play. about %n minute(s) long - около %n минути + около %n минутаоколо %n минути @@ -2270,22 +2331,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Най-известни - + Artists Артисти - + Albums Албуми - + Tracks Песни @@ -2293,44 +2354,60 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. - + Tomahawk възпроизвежда "%1" от %2%3 - + on "%1" - + от "%1" Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks Най-актуални песни - + Loved Tracks Харесвани песни - + Hyped Tracks Песни слушани най-често - + Top Artists Най-слушани артисти - + Hyped Artists Артисти слушани най-често + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + Слушам "%1" от %2 и я харесвам! %3 + + Tomahawk::ItunesParser @@ -2480,7 +2557,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моята колекция @@ -2521,12 +2598,12 @@ enter the displayed PIN number here: Play - + Изпълни Pause - + Пауза @@ -2534,7 +2611,7 @@ enter the displayed PIN number here: Tomahawk - + Tomahawk @@ -2639,7 +2716,7 @@ enter the displayed PIN number here: Ctrl+M - + Ctrl+M @@ -2649,7 +2726,7 @@ enter the displayed PIN number here: Meta+Ctrl+Z - + Mod+Ctrl+Z @@ -2675,7 +2752,7 @@ enter the displayed PIN number here: Space - + Интервал @@ -3064,7 +3141,7 @@ enter the displayed PIN number here: Status: No saved credentials - + Статус: Няма запазени данни за вход @@ -3126,17 +3203,17 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection Супер колекция - + Combined libraries of all your online friends Комбинирани библиотеки от всичките ми приятели на линия - + All available albums Всички налични албуми @@ -3405,107 +3482,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Действие от потребителя - + Host is unknown Непознат адрес - + Item not found Обектът не е открит - + Authorization Error Грешка при даване на достъп - + Remote Stream Error Грешка в стриймът от отдалечената машина - + Remote Connection failed Отдалечената връзка е неуспешна - + Internal Server Error Вътрешна грешка на сървъра - + System shutdown Изключване на системата - + Conflict Конфликт - + Unknown - + No Compression Support Няма поддръжка на компресия - + No Encryption Support Няма поддръжка на криптиране - + No Authorization Support Няма поддръжка на удостоверяване - + No Supported Feature - + Неподдържана функция - + Add Friend Добави приятел - + Enter Xmpp ID: Въведи Xmpp ID: - + Add Friend... Добави приятел... - + XML Console... XML Конзола... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Извинявай.. Аз съм режимът за автоматични отговори изпълзван от Tomahawk. ( http://gettomahawk.com ) Щом получаваш това съобщение, този с който се опитваш да се свържеш вероятно не е на линия. Моля, опитай отново по-късно. - + Authorize User Оправомощяване на потребител - + Do you want to grant <b>%1</b> access to your Collection? Искате ли да позволите на <b>%1</b> достъп до вашата колекция? diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index ef267e174..73e7379bb 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -296,36 +296,41 @@ Denk dran: Erlaube das nur, wenn du dem Anderen vertraust und du die Rechte zum + social + + + + love Lieben - + Time Zeit - + Time Left Zeit verbleibend - + Shuffle Zufall - + Repeat Wiederholen - + Low Niedrig - + High Hoch @@ -679,6 +684,14 @@ Denk dran: Erlaube das nur, wenn du dem Anderen vertraust und du die Rechte zum Erstelle eine neue Playliste + + NewReleasesWidget + + + New Releases + + + PlaylistItemDelegate @@ -1051,6 +1064,49 @@ Denk dran: Erlaube das nur, wenn du dem Anderen vertraust und du die Rechte zum Meist gehörte Lieder die du nicht kennst + + SocialWidget + + + Form + + + + + Facebook + + + + + Twitter + + + + + Cover + + + + + TextLabel + + + + + Listening to "%1" by %2 and loving it! %4 + + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + + + + + %1 characters left + + + SourceDelegate @@ -1264,6 +1320,11 @@ Denk dran: Erlaube das nur, wenn du dem Anderen vertraust und du die Rechte zum + New Releases + + + + Friends Freunde @@ -1527,7 +1588,7 @@ Denk dran: Erlaube das nur, wenn du dem Anderen vertraust und du die Rechte zum Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. Verbinde dich zu deinen Twitter-Followern @@ -2261,22 +2322,22 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Allgemein - + Artists Künstler - + Albums Alben - + Tracks Stücke @@ -2284,12 +2345,12 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. - + on "%1" @@ -2297,31 +2358,47 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks Größte Hits - + Loved Tracks Lieblings Lieder - + Hyped Tracks Angesagte Stücke - + Top Artists - + Hyped Artists + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + + + Tomahawk::ItunesParser @@ -2471,7 +2548,7 @@ Versuch die Filter anzupassen für neue Lieder. TomahawkApp - + My Collection Meine Sammlung @@ -3108,17 +3185,17 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Alle verfügbaren Alben @@ -3383,107 +3460,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend Freund hinzufügen... - + Enter Xmpp ID: XMPP-Benutzer: - + Add Friend... Freund hinzufügen... - + XML Console... XML-Konsole... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? Willst du <b>%1</b> Zugriff auf deine Sammlung gewähren? diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index f84149a1c..cbfda8236 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -296,36 +296,41 @@ Remember: Only allow peers to connect if you trust who they are and if you have + social + social + + + love love - + Time Time - + Time Left Time Left - + Shuffle Shuffle - + Repeat Repeat - + Low Low - + High High @@ -679,6 +684,14 @@ Remember: Only allow peers to connect if you trust who they are and if you have Create a new playlist + + NewReleasesWidget + + + New Releases + New Releases + + PlaylistItemDelegate @@ -1052,6 +1065,49 @@ Remember: Only allow peers to connect if you trust who they are and if you have Most Played Tracks You Don't Have + + SocialWidget + + + Form + Form + + + + Facebook + Facebook + + + + Twitter + Twitter + + + + Cover + Cover + + + + TextLabel + TextLabel + + + + Listening to "%1" by %2 and loving it! %4 + Listening to "%1" by %2 and loving it! %4 + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + Listening to "%1" by %2 on "%3" and loving it! %4 + + + + %1 characters left + %1 characters left + + SourceDelegate @@ -1265,6 +1321,11 @@ Remember: Only allow peers to connect if you trust who they are and if you have + New Releases + New Releases + + + Friends Friends @@ -1531,7 +1592,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. Connect to your Twitter followers. @@ -2268,22 +2329,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Overall - + Artists Artists - + Albums Albums - + Tracks Tracks @@ -2291,12 +2352,12 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. Tomahawk is playing "%1" by %2%3. - + on "%1" on "%1" @@ -2304,31 +2365,47 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks Top Tracks - + Loved Tracks Loved Tracks - + Hyped Tracks Hyped Tracks - + Top Artists Top Artists - + Hyped Artists Hyped Artists + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + Albums + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + Listening to "%1" by %2 and loving it! %3 + + Tomahawk::ItunesParser @@ -2478,7 +2555,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection My Collection @@ -3120,17 +3197,17 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Combined libraries of all your online friends - + All available albums All available albums @@ -3405,107 +3482,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction User Interaction - + Host is unknown Host is unknown - + Item not found Item not found - + Authorization Error Authorization Error - + Remote Stream Error Remote Stream Error - + Remote Connection failed Remote Connection failed - + Internal Server Error Internal Server Error - + System shutdown System shutdown - + Conflict Conflict - + Unknown Unknown - + No Compression Support No Compression Support - + No Encryption Support No Encryption Support - + No Authorization Support No Authorization Support - + No Supported Feature No Supported Feature - + Add Friend Add Friend - + Enter Xmpp ID: Enter Xmpp ID: - + Add Friend... Add Friend... - + XML Console... XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Authorize User - + Do you want to grant <b>%1</b> access to your Collection? Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 74aa6b86b..ec4221230 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -294,36 +294,41 @@ Remember: Only allow peers to connect if you trust who they are and if you have + social + + + + love favorita - + Time Duración - + Time Left Tiempo restante - + Shuffle Aleatorio - + Repeat Repetir - + Low Bajar volumen - + High Subir volumen @@ -677,6 +682,14 @@ Remember: Only allow peers to connect if you trust who they are and if you have Crear una nueva lista de reproducción + + NewReleasesWidget + + + New Releases + + + PlaylistItemDelegate @@ -1049,6 +1062,49 @@ Remember: Only allow peers to connect if you trust who they are and if you have Pistas más reproducidas no disponibles + + SocialWidget + + + Form + + + + + Facebook + + + + + Twitter + + + + + Cover + + + + + TextLabel + + + + + Listening to "%1" by %2 and loving it! %4 + + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + + + + + %1 characters left + + + SourceDelegate @@ -1262,6 +1318,11 @@ Remember: Only allow peers to connect if you trust who they are and if you have + New Releases + + + + Friends @@ -1528,7 +1589,7 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. @@ -2260,22 +2321,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top total - + Artists Artistas - + Albums Álbumes - + Tracks Pistas @@ -2283,12 +2344,12 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. - + on "%1" @@ -2296,31 +2357,47 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks Pistas más escuchadas - + Loved Tracks Pistas favoritas - + Hyped Tracks Pistas en alza - + Top Artists Artistas más escuchados - + Hyped Artists Artistas en alza + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + + + Tomahawk::ItunesParser @@ -2470,7 +2547,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Mi colección @@ -3112,17 +3189,17 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Todos los álbumes disponibles @@ -3396,107 +3473,107 @@ Letras de "%1" por %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts new file mode 100644 index 000000000..5249cc809 --- /dev/null +++ b/lang/tomahawk_fr.ts @@ -0,0 +1,3591 @@ + + + ACLRegistry + + + Connect to Peer? + Se connecter ? + + + + Another Tomahawk instance that claims to be owned by %1 is attempting to connect to you. Select whether to allow or deny this connection. + +Remember: Only allow peers to connect if you trust who they are and if you have the legal right for them to stream music from you. + Une autre instance de Tomahawk qui dit appartenir à %1 essaie de se connecter. Voulez vous accepter ou interdire cette connexion ? + +Note : N'autorisez à se connecter que les personnes en qui vous avez confiance et qui ont le droit de streamer votre musique. + + + + Deny + Interdire + + + + Allow + Accepter + + + + AccountFactoryWrapper + + + Dialog + Dialog + + + + Description goes here + ici la description + + + + Add Account + Ajouter un compte + + + + AccountFactoryWrapperDelegate + + + Online + En Ligne + + + + Connecting... + Connexion en cours... + + + + Offline + Hors ligne + + + + ActionCollection + + + &Listen Along + &Ecouter avec + + + + Stop &Listening Along + Arrêter d'&écouter avec + + + + &Follow in real-time + &Suivre en temps réel + + + + + &Listen Privately + &Ecouter en privé + + + + + &Listen Publicly + &Ecouter publiquement + + + + &Load Playlist + &Charger une liste de lecture + + + + &Rename Playlist + &Renommer la liste de lecture + + + + &Copy Playlist Link + &Copier le lien de la piste de lecture + + + + &Play + &Lire + + + + &Stop + &Stop + + + + &Previous Track + Piste &Précédente + + + + &Next Track + Piste &Suivante + + + + &Quit + &Quitter + + + + AlbumInfoWidget + + + Form + Form + + + + Other Albums by Artist + Tous les albums par cet artiste + + + + + Click to show Official Tracks + Cliquer pour afficher les pistes officielles + + + + + Click to show SuperCollection Tracks + Cliquer pour afficher les pistes de la SuperCollectio, + + + + + Click to show SuperCollection Albums + Cliquer pour afficher les albums de la SuperCollection + + + + Click to show Official Albums + Cliquer pour afficher les albums officiels + + + + Other Albums by %1 + Autres albums par %1 + + + + AlbumModel + + + Album + Album + + + + + All albums from %1 + Tous les albums de %1 + + + + All albums + Tous les albums + + + + AlbumView + + + After you have scanned your music collection you will find your latest album additions right here. + Après avoir scanné votre collection musicale, vous trouverez les derniers albums ajoutés ici. + + + + This collection doesn't have any recent albums. + Cette collection n'a pas d'albums récents + + + + ArtistInfoWidget + + + Form + Form + + + + Top Hits + Top Hits + + + + Related Artists + Artistes similaires + + + + Albums + Albums + + + + + Click to show SuperCollection Albums + Cliquer pour afficher les albums de la SuperCollection + + + + Click to show Official Albums + Cliquer pour afficher les albums officiels + + + + ArtistView + + + After you have scanned your music collection you will find your tracks right here. + Après avoir scanné votre collection musicale, vous trouverez vos pistes ici. + + + + This collection is currently empty. + La collection est vide actuellement. + + + + Sorry, your filter '%1' did not match any results. + Désolé, votre filtre '%1' ne correspond à aucun résultat + + + + AudioControls + + + Prev + Précédent + + + + Play + Lecture + + + + Pause + Pause + + + + Next + Suivant + + + + Artist + Artiste + + + + Album + Album + + + + Owner + Propriétaire + + + + social + + + + + love + love + + + + Time + Durée + + + + Time Left + Durée restante + + + + Shuffle + Lecture Aléatoire + + + + Repeat + Répéter + + + + Low + Bas + + + + High + Haut + + + + CategoryAddItem + + + + New Playlist + Nouvelle liste de lecture + + + + + + + New Station + Nouvelle Station + + + + + + %1 Station + Station %1 + + + + CategoryItem + + + Playlists + Listes de lecture + + + + Stations + Stations + + + + ClearButton + + + Clear + Vider + + + + CollectionFlatModel + + + My Collection + Ma Collection + + + + Collection of %1 + Collection de %1 + + + + CollectionView + + + This collection is empty. + La collection est vide. + + + + ContextWidget + + + InfoBar + Barre d'information + + + + + Show Footnotes + Afficher les notes + + + + Hide Footnotes + Masquer les notes + + + + CrashReporter + + + Tomahawk Crash Reporter + Tomahawk Crash Reporter + + + + <p><b>Sorry!</b>&nbsp;Tomahawk crashed. Information about the crash is now being sent to Tomahawk HQ so that we can fix the bug.</p> + <p><b>Désolé !</b>&nbsp;Tomahawk a planté. Les informations du plantage sont maintenant envoyés au siège de Tomahawk pour que nous puissions corriger le bug.</p> + + + + Abort + Abandonner + + + + You can disable sending crash reports in the configuration dialog. + Vous pouvez désactiver l'envoi des rapports de plantage dans la boite de dialogue de configuration. + + + + Uploaded %L1 of %L2 KB. + Chargement %L1 de %L2 ko. + + + + + Close + Fermer + + + + Sent! <b>Many thanks</b>. + Envoyé ! <b>Merci beaucoup</b>. + + + + Failed to send crash info. + Échec de l'envoi des informations de plantage + + + + DatabaseCommand_AllAlbums + + + Unknown + Inconnu + + + + DelegateConfigWrapper + + + Delete Account + Supprimer le compte + + + + DiagnosticsDialog + + + Tomahawk Diagnostics + Diagnostics de Tomahawk + + + + Update + Mettre à jour + + + + Copy to Clipboard + Copier dans le presse papier + + + + DropJob + + + No tracks found for given %1 + Aucune piste trouvée pour %1 + + + + GlobalSearchWidget + + + Form + Form + + + + IndexingJobItem + + + Indexing database + Indexation de la base de données + + + + InfoBar + + + InfoBar + Barre d'information + + + + Automatically update + + + + + Filter... + Filtre... + + + + JobStatusView + + + Searching For + Recherche de + + + + Pending + + + + + Idle + + + + + LastFmConfig + + + Form + Form + + + + Scrobble tracks to Last.fm + Scrobbler les pistes sur Last.fm + + + + Username: + Nom d'utilisateur : + + + + Password: + Mot de passe : + + + + Test Login + + + + + LastfmContext + + + Last.fm + Last.fm + + + + LatchedStatusItem + + + %1 is listening along to you! + %1 écoute avec vous + + + + LoadXSPF + + + Load XSPF + Charger XSPF + + + + Playlist URL + URL de la liste de lecture + + + + Enter URL... + Saisir une URL... + + + + ... + ... + + + + Automatically update + + + + + LoadXSPFDialog + + + Load XSPF File + Charger un fichier XSPF + + + + XSPF Files (*.xspf) + Fichiers XSPF (*.xspf) + + + + LocalCollection + + + Bookmarks + + + + + Saved tracks + Pistes sauvegardés + + + + NewPlaylistWidget + + + Enter a title for the new playlist: + Entrer un titre pour la nouvelle liste de lecture + + + + Tomahawk offers a variety of ways to help you create playlists and find music you enjoy! + Tomahawk offre plusieurs façons de créer des listes de lecture et de trouver la musique que vous aimerez ! + + + + Just enter a genre or tag name and Tomahawk will suggest a few songs to get you started with your new playlist: + Entrez un genre ou un tag et Tomahawk vous suggérera quelques morceaux pour commencer votre nouvelle liste de lecture : + + + + &Create Playlist + &Créer une liste de lecture + + + + Create a new playlist + Créer une nouvelle liste de lecture + + + + NewReleasesWidget + + + New Releases + + + + + PlaylistItemDelegate + + + played %1 by you + joué %1 par vous + + + + played %1 by %2 + joué %1 par %2 + + + + PlaylistLargeItemDelegate + + + played %1 by you + joué %1 par vous + + + + played %1 by %2 + joué %1 par %2 + + + + added %1 + + + + + PlaylistModel + + + A playlist by %1, created %2 + Une liste de lecture par %1, créée %2 + + + + you + vous + + + + All tracks by %1 on album %2 + Toutes les pistes par %1 sur l'album %2 + + + + All tracks by %1 + Toutes les pistes par %1 + + + + PlaylistTypeSelectorDlg + + + New Playlist + Nouvelle liste de lecture + + + + Just a regular old playlist... Give it a name, drag in some tracks, and go! + Juste une liste de lecture normale... Donnez lui un nom, faites glisser quelques pistes et c'est parti ! + + + + Don't know exactly what you want? Give Tomahawk a few pointers and let it build a playlist for you! + Vous ne savez pas ce que vous voulez exactement ? Donnez quelques idées à Tomahawk et laissez le créer une liste de lecture pour vous. + + + + Name: + Nom : + + + + New Playlist... + Nouvelle liste de lecture... + + + + Create Manual Playlist + Créer une liste de lecture manuellement + + + + Create Automatic Playlist + Créer une liste de lecture automatiquement + + + + PlaylistView + + + This playlist is currently empty. Add some tracks to it and enjoy the music! + La liste de lecture est vide. Ajoutez des pistes et profitez de la musique ! + + + + ProxyDialog + + + Proxy Settings + Paramètres de proxy + + + + Hostname of proxy server + Nom d'hôte du serveur proxy + + + + Host + Hôte + + + + Port + Port + + + + Proxy login + Login du proxy + + + + User + Utilisateur + + + + Password + Mot de passe + + + + Proxy password + Mot de passe du proxy + + + + Type + Type + + + + No Proxy Hosts: +(Overrides system proxy) + Pas de proxy pour : +(remplace les paramètres système) + + + + localhost *.example.com (space separated) + localhost *.example.com (séparé par espace) + + + + Use proxy for DNS lookups? + Utiliser le proxy pour les requêtes DNS ? + + + + QObject + + + %n year(s) ago + il y a %n anil y a %n ans + + + + %n year(s) + %n an%n ans + + + + %n month(s) ago + il y a %n moisil y a %n mois + + + + %n month(s) + %n mois%n mois + + + + %n week(s) ago + il y a %n semaineil y a %n semaines + + + + %n week(s) + %n semaine%n semaines + + + + %n day(s) ago + il y a %n jouril y a %n jours + + + + %n day(s) + %n jour%n jours + + + + %n hour(s) ago + il y a %n heureil y a %n heures + + + + %n hour(s) + %n heure%n heures + + + + %1 minutes ago + il y a %1 minutes + + + + %1 minutes + %1 minutes + + + + just now + à l'instant + + + + Friend Finders + + + + + Music Finders + + + + + Status Updaters + + + + + QuaZipFilePrivate + + + ZIP/UNZIP API error %1 + + + + + QueueView + + + InfoBar + Barre d'information + + + + + Show Queue + + + + + Hide Queue + + + + + RelatedArtistsContext + + + Related Artists + + + + + ResolverConfigDelegate + + + Not found: %1 + + + + + Failed to load: %1 + + + + + SearchLineEdit + + + Search + + + + + SearchWidget + + + Search: %1 + + + + + Results for '%1' + + + + + SettingsDialog + + + Collection + Collection + + + + Advanced + Avancés + + + + All + + + + + Services + + + + + Install resolver from file + + + + + Information + + + + + Changing this setting requires a restart of Tomahawk! + + + + + SocialPlaylistWidget + + + Popular New Albums From Your Friends + Nouveaux Albums Populaires de vos Amis + + + + Most Played Playlists + Liste de lecture les plus jouées + + + + Most Played Tracks You Don't Have + Pistes les plus joués que vous n'avez pas + + + + SocialWidget + + + Form + Form + + + + Facebook + Facebook + + + + Twitter + Twitter + + + + Cover + + + + + TextLabel + TextLabel + + + + Listening to "%1" by %2 and loving it! %4 + J'écoute "%1" par %2 et j'adore ! %4 + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + J'écoute "%1" par %2 sur "%3" et j'adore ! %4 + + + + %1 characters left + %1 caractères restants + + + + SourceDelegate + + + Track + Piste + + + + Album + Album + + + + Artist + Artiste + + + + Local + Local + + + + Top 10 + Top 10 + + + + Offline + Hors ligne + + + + All available tracks + Toutes les pistes disponibles + + + + Online + En Ligne + + + + + Show + Afficher + + + + + Hide + Masquer + + + + SourceInfoWidget + + + Recent Albums + Derniers Albums + + + + Latest Additions + Derniers ajouts + + + + Recently Played Tracks + Dernières pistes jouées + + + + New Additions + Nouveaux ajouts + + + + My recent activity + Mon activité récente + + + + Recent activity from %1 + Activité récente de %1 + + + + SourceItem + + + Collection + Collection + + + + Latest Additions + Derniers ajouts + + + + Recently Played + Joués récemment + + + + Loved Tracks + + + + + SuperCollection + SuperCollection + + + + SourceTreeView + + + &Copy Link + &Copier le lien + + + + &Delete %1 + &Supprimer %1 + + + + &Export Playlist + &Exporter la liste de lecture + + + + Save XSPF + Enregistrer XSPF + + + + Playlists (*.xspf) + Listes de lecture (*.xspf) + + + + SourcesModel + + + Group + Groupe + + + + Collection + Collection + + + + Playlist + Liste de lecture + + + + Automatic Playlist + Liste de lecture automatique + + + + Station + Station + + + + Browse + Parcourir + + + + Search History + + + + + My Music + Ma Musique + + + + SuperCollection + SuperCollection + + + + Top Loved Tracks + + + + + Dashboard + Tableau de bord + + + + Recently Played + Joués récemment + + + + Charts + + + + + New Releases + + + + + Friends + Amis + + + + SpotifyConfig + + + Form + + + + + Configure your Spotify credentials + + + + + Username: + Nom d'utilisateur : + + + + placeholderUsername + placeholderUsername + + + + Password: + + + + + placeholderPw + + + + + High Quality Streaming + + + + + This product uses SPOTIFY(R) CORE but is not endorsed, certified or otherwise approved in any way by Spotify. Spotify is the registered trade mark of the Spotify Group. + + + + + StackedSettingsDialog + + + Tomahawk Settings + + + + + Local Music Information + + + + + Path to scan for music files: + Chemin à scanner pour des fichiers musicaux : + + + + The Echo Nest supports keeping track of your catalog metadata + and using it to craft personalized radios. Enabling this option + will allow you (and all your friends) to create automatic playlists + and stations based on your personal taste profile. + The Echo Nest peut garder les métadonnées de votre catalogue +et l'utiliser pour créer des radios personnalisées. En activant cette option +vous (et vos amis) pourrez créer des listes de lecture automatiquement +et des stations basés sur vos goûts. + + + + Upload collection list to The Echo Nest to enable user radio + Envoyer la collection à The Echo Nest pour activer la radio utilisateur + + + + Watch for changes + + + + + Time between scans, in seconds: + Période de scan, en secondes : + + + + Internet Services + + + + + Install from file... + + + + + Filter by capability: + + + + + Advanced Network Settings + Paramètres réseaux avancés + + + + If you're having difficulty connecting to peers, try setting this to your external IP address/host name and a port number (default 50210). Make sure to forward that port to this machine! + Si vous rencontrez des difficultés à vous connecter, essayez de saisir ici votre adresse IP externe et un port (défaut 50210). Vérifiez que vous redirigez ce port vers cette machine ! + + + + Static Host Name: + Nom d'hôte statique : + + + + Static Port: + + + + + Always use static host name/port? (Overrides UPnP discovery/port forwarding) + Toujours utiliser un nom d'hôte/port statique? (remplace la découverte UPnP/le transfer de port) + + + + Proxy Settings... + + + + + Send reports after Tomahawk crashed + + + + + Allow web browsers to interact with Tomahawk + Autoriser les navigateurs Web à utiliser Tomahawk + + + + Use UPnP to establish port forward + + + + + Tomahawk::Accounts::AccountDelegate + + + Add Account + Ajouter un compte + + + + Remove Account + Supprimer le compte + + + + %1 downloads + + + + + Online + En Ligne + + + + Connecting... + Connexion en cours... + + + + Offline + Hors ligne + + + + Tomahawk::Accounts::GoogleWrapper + + + Configure this Google Account + Configurer le compte Google + + + + Google Address + Adresse Google + + + + Enter your Google login to connect with your friends using Tomahawk! + Entrer votre login Google pour vous connecter avec vos amis qui utilisent Tomahawk ! + + + + username@gmail.com + utilisateur@gmail.com + + + + Tomahawk::Accounts::GoogleWrapperFactory + + + Connect to Google Talk to find your friends + Connectez vous à Google Talk pour trouver vos amis + + + + Tomahawk::Accounts::GoogleWrapperSip + + + Add Friend + + + + + Enter Google Address: + + + + + Tomahawk::Accounts::LastFmAccountFactory + + + Scrobble your tracks to last.fm, and find freely downloadable tracks to play + Scrobbler vos écoutes sur Last.fm et trouver des morceaux téléchargeables gratuitement + + + + Tomahawk::Accounts::LastFmConfig + + + + Failed + Échec + + + + Success + Succès + + + + Could not contact server + Impossible de contacter le serveur + + + + Tomahawk::Accounts::SpotifyAccountFactory + + + Play music from and sync your playlists with Spotify Premium + Jouer la musique et synchroniser vos listes avec Spotify Premium + + + + Tomahawk::Accounts::TwitterAccountFactory + + + Connect to your Twitter followers. + + + + + Tomahawk::Accounts::TwitterConfigWidget + + + + + Tweet! + Tweet! + + + + + Status: No saved credentials + + + + + + + Authenticate + + + + + + Status: Credentials saved for %1 + + + + + + De-authenticate + + + + + + + + + + + Tweetin' Error + + + + + The credentials could not be verified. +You may wish to try re-authenticating. + + + + + Status: Error validating credentials + + + + + Global Tweet + Tweet Global + + + + Direct Message + + + + + Send Message! + + + + + @Mention + + + + + Send Mention! + + + + + You must enter a user name for this type of tweet. + Vous devez saisir un nom d'utilisateur pour ce type de tweet. + + + + Your saved credentials could not be loaded. +You may wish to try re-authenticating. + + + + + Your saved credentials could not be verified. +You may wish to try re-authenticating. + + + + + + There was an error posting your status -- sorry! + + + + + + Tweeted! + + + + + Your tweet has been posted! + + + + + There was an error posting your direct message -- sorry! + + + + + Your message has been posted! + + + + + Tomahawk::Accounts::XmppAccountFactory + + + Log on to your Jabber/XMPP account to connect to your friends + Connectez vous à votre compte Jabber/XMPP pour vous connecter avec vos amis + + + + Tomahawk::Accounts::ZeroconfFactory + + + Automatically connect to Tomahawks on the local network + Se connecter automatiquement aux Tomahawks sur le réseau local + + + + Tomahawk::ContextMenu + + + &Play + + + + + + + Add to &Queue + + + + + + &Love + + + + + &Copy Track Link + &Copier le lien de la piste + + + + Show &Album page + Afficher la page de l'&album + + + + Show &Artist page + + + + + Un-&Love + + + + + &Delete Items + + + + + &Continue Playback after this Track + &Continuer la lecture après cette piste + + + + &Stop Playback after this Track + &Stopper la lecture après cette piste + + + + &Delete Item + + + + + Tomahawk::CustomPlaylistView + + + Top Loved Tracks + + + + + Your loved tracks + + + + + %1's loved tracks + + + + + The most loved tracks from all your friends + + + + + All of your loved tracks + + + + + All of %1's loved tracks + + + + + Tomahawk::DropJobNotifier + + + Fetching %1 from database + + + + + Parsing %1 %2 + + + + + Tomahawk::DynamicControlList + + + Click to collapse + + + + + Tomahawk::DynamicModel + + + + Could not find a playable track. + +Please change the filters or try again. + + + + + Failed to generate preview with the desired filters + Échec de la génération de l'aperçu avec ces filtres + + + + Tomahawk::DynamicSetupWidget + + + Type: + + + + + Generate + Générer + + + + Tomahawk::DynamicView + + + Add some filters above to seed this station! + Ajoutez des filtres ci dessus pour commencer une station ! + + + + Press Generate to get started! + Appuyez sur Générer pour commencer ! + + + + Add some filters above, and press Generate to get started! + Ajoutez des filtres ci dessus et appuyez sur "Générer" pour commencer ! + + + + Tomahawk::DynamicWidget + + + Station ran out of tracks! + +Try tweaking the filters for a new set of songs to play. + + + + + Tomahawk::EchonestControl + + + + + + + + is + + + + + from user + + + + + + No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings + Aucun utilisateur avec un Catalogue The Echo Nest actif. Essayez d'activer l'option dans les préférences de Collection. + + + + similar to + + + + + + + + + + + Less + Moins + + + + + + + + + + More + Plus + + + + 0 BPM + 0 BPM + + + + 500 BPM + 500 BPM + + + + 0 secs + 0 secs + + + + 3600 secs + 3600 secs + + + + -100 dB + -100 dB + + + + 100 dB + 100 dB + + + + Major + Majeur + + + + Minor + Mineur + + + + C + Do + + + + C Sharp + Do dièse + + + + D + + + + + E Flat + Mi bémol + + + + E + Mi + + + + F + Fa + + + + F Sharp + Fa dièse + + + + G + Sol + + + + A Flat + La bémol + + + + A + La + + + + B Flat + Si bémol + + + + B + Si + + + + Ascending + Croissant + + + + Descending + Décroissant + + + + Tempo + Tempo + + + + Duration + Durée + + + + Loudness + Intensité + + + + Artist Familiarity + + + + + Artist Hotttnesss + + + + + Song Hotttnesss + + + + + Latitude + Latitude + + + + Longitude + Longitude + + + + Mode + Mode + + + + Key + Tonalité + + + + Energy + Energie + + + + Danceability + Dansabilité + + + + only by ~%1 + + + + + similar to ~%1 + + + + + with genre ~%1 + + + + + + from no one + + + + + My Collection + Ma Collection + + + + from %1 radio + + + + + with %1 %2 + + + + + about %1 BPM + environ %1 BPM + + + + about %n minute(s) long + environ %n minuteenviron %n minutes + + + + about %1 dB + environ %1 dB + + + + at around %1%2 %3 + + + + + in %1 + + + + + in a %1 key + + + + + sorted in %1 %2 order + + + + + with a %1 mood + + + + + in a %1 style + + + + + Tomahawk::EchonestSteerer + + + Steer this station: + + + + + Much less + Beaucoup moins + + + + Less + Moins + + + + A bit less + Un peu moins + + + + Keep at current + Garder le même + + + + A bit more + Un peu plus + + + + More + Plus + + + + Much more + Beaucoup plus + + + + Tempo + Tempo + + + + Loudness + Intensité + + + + Danceability + Dansabilité + + + + Energy + Energie + + + + Song Hotttnesss + Hotttnesss du morceau + + + + Artist Hotttnesss + Hotttnesss de l'artiste + + + + Artist Familiarity + + + + + By Description + Par description + + + + Enter a description + Entrer une description + + + + Apply steering command + + + + + Reset all steering commands + + + + + Tomahawk::GroovesharkParser + + + Error fetching Grooveshark information from the network! + Échec du chargement des informations Grooveshark depuis le réseau! + + + + Tomahawk::InfoSystem::ChartsPlugin + + + Top Overall + + + + + Artists + + + + + Albums + Albums + + + + Tracks + Pistes + + + + Tomahawk::InfoSystem::FdoNotifyPlugin + + + Tomahawk is playing "%1" by %2%3. + Tomahawk joue "%1" par %2%3. + + + + on "%1" + + + + + Tomahawk::InfoSystem::LastFmPlugin + + + Top Tracks + + + + + Loved Tracks + + + + + Hyped Tracks + + + + + Top Artists + + + + + Hyped Artists + + + + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + J'écoute "%1" par %2 et j'adore ! %3 + + + + Tomahawk::ItunesParser + + + Error fetching iTunes information from the network! + Échec du chargement des informations iTunes depuis le réseau! + + + + Tomahawk::JSPFLoader + + + New Playlist + Nouvelle liste de lecture + + + + Failed to save tracks + + + + + Some tracks in the playlist do not contain an artist and a title. They will be ignored. + Certaines pistes dans la liste de lecture ne contiennent pas d'artiste ou de titre. Elles seront ignorées. + + + + XSPF Error + Erreur XSPF + + + + This is not a valid XSPF playlist. + Ceci n'est pas une liste de lecture XSPF valide. + + + + Tomahawk::LatchManager + + + &Catch Up + + + + + + &Listen Along + &Ecouter avec + + + + Tomahawk::Query + + + and + et + + + + You + Vous + + + + you + vous + + + + and + et + + + + %n other(s) + %n autre%n autres + + + + %1 people + %1 personnes + + + + loved this track + + + + + Tomahawk::RdioParser + + + Error fetching Rdio information from the network! + Échec du chargement des informations Rdio depuis le réseau! + + + + Tomahawk::ShortenedLinkParser + + + Network error parsing shortened link! + Erreur réseau lors du décodage de l'URL courte! + + + + Tomahawk::Source + + + + Scanning (%L1 tracks) + Scan en cours (%L1 pistes) + + + + Scanning + Scan en cours + + + + Checking + + + + + Fetching + + + + + Parsing + + + + + Saving (%1%) + + + + + Tomahawk::SpotifyParser + + + Error fetching Spotify information from the network! + Échec du chargement des informations Spotify depuis le réseau! + + + + TomahawkApp + + + My Collection + Ma Collection + + + + TomahawkOAuthTwitter + + + Twitter PIN + + + + + After authenticating on Twitter's web site, +enter the displayed PIN number here: + Après vous être authentifier sur le site de Twitter, +saisissez le numéro PIN ici : + + + + TomahawkTrayIcon + + + + Hide Tomahawk Window + Masquer la fenêtre Tomahawk + + + + Show Tomahawk Window + Afficher la fenêtre Tomahawk + + + + Currently not playing. + Pas de lecture en cours + + + + Play + Lecture + + + + Pause + Pause + + + + TomahawkWindow + + + Tomahawk + Tomahawk + + + + &Settings + + + + + &Controls + &Contrôles + + + + &Network + &Réseau + + + + &Window + &Fenêtre + + + + &Help + &Aide + + + + &Quit + &Quitter + + + + Ctrl+Q + Ctrl+Q + + + + Go &Online + Se c&onnecter + + + + Add &Friend... + Ajouter un &ami... + + + + U&pdate Collection + Mettre à Jo&ur la Collection + + + + Update Collection + Mettre à Jour la Collection + + + + &Configure Tomahawk... + &Configurer Tomahawk... + + + + Load &XSPF... + Charger &XSPF + + + + Create &New Playlist... + Créer une &nouvelle liste de lecture... + + + + About &Tomahawk... + A propos de &Tomahawk + + + + Create New &Automatic Playlist + Créer une nouvelle liste de lecture automatique + + + + Create New &Station + Créer une nouvelle &Station + + + + Show Offline Sources + Afficher les sources hors ligne + + + + Hide Offline Sources + Masquer les sources hors ligne + + + + Minimize + Réduire + + + + Ctrl+M + Ctrl+M + + + + Zoom + Zoom + + + + Meta+Ctrl+Z + Meta+Ctrl+Z + + + + Diagnostics... + Diagnostics... + + + + Fully &Rescan Collection + &Rescanner la collection entièrement + + + + Fully Rescan Collection + Rescanner la collection entièrement + + + + + Play + Lecture + + + + Space + Espace + + + + Previous + Précédent + + + + Next + Suivant + + + + Global Search... + Recherche Globale... + + + + + Check For Updates... + Rechercher une mise à jour... + + + + + + Connect To Peer + + + + + Enter peer address: + + + + + Enter peer port: + + + + + Enter peer key: + + + + + XSPF Error + Erreur XSPF + + + + This is not a valid XSPF playlist. + Ceci n'est pas une liste de lecture XSPF valide. + + + + Failed to save tracks + Échec de la sauvegarde des pistes + + + + Some tracks in the playlist do not contain an artist and a title. They will be ignored. + Certaines pistes dans la liste de lecture ne contiennent pas d'artiste ou de titre. Elles seront ignorées. + + + + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. + Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. Vérifiez que vous avez un backend Phonon et les plugins requis installés. + + + + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. + Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. + + + + Create New Station + Créer une nouvelle station + + + + Name: + Nom : + + + + New Station + Nouvelle station + + + + New Playlist + Nouvelle liste de lecture + + + + Pause + Pause + + + + Go &offline + Se &déconnecter + + + + Go &online + Se c&onnecter + + + + Authentication Error + Erreur d'authentification + + + + %1 by %2 + track, artist name + %1 par %2 + + + + %1 - %2 + current track, some window title + %1 - %2 + + + + <h2><b>Tomahawk %1<br/>(%2)</h2> + <h2><b>Tomahawk %1<br/>(%2)</h2> + + + + <h2><b>Tomahawk %1</h2> + <h2><b>Tomahawk %1</h2> + + + + Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + + + About Tomahawk + A propos de Tomahawk + + + + TopBar + + + Form + Form + + + + 0 Sources + 0 Source + + + + 0 Tracks + 0 piste + + + + 0 Artists + 0 Artist + + + + 0 Shown + 0 Affiché + + + + Tracks + Pistes + + + + Artists + Artistes + + + + Filter + Filtre + + + + Artist View + + + + + Flat View + + + + + Sources + + + + + Shown + Affiché + + + + TopTracksContext + + + Top Hits + + + + + TrackModel + + + Artist + Artiste + + + + Title + Titre + + + + Album + Album + + + + Track + Piste + + + + Duration + Durée + + + + Bitrate + + + + + Age + Age + + + + Year + Année + + + + Size + Taille + + + + Origin + Origine + + + + Score + Score + + + + Composer + Compositeur + + + + TrackView + + + Sorry, your filter '%1' did not match any results. + Désolé, votre filtre '%1' ne correspond à aucun résultat + + + + TransferStatusItem + + + from + + + + + to + + + + + TreeItemDelegate + + + Unknown + Inconnu + + + + TreeModel + + + Name + Nom + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Composer + + + + + All Artists + + + + + + My Collection + Ma Collection + + + + + Collection of %1 + Collection de %1 + + + + TwitterConfigWidget + + + Configure this Twitter account + Configurer ce compte Twitter + + + + The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. + Le plugin Twitter vous permet de découvrir et jouer de la musique de vos amis Twitter qui utilisent Tomahawk et de poster des messages sur votre compte. + + + + Status: No saved credentials + + + + + Authenticate with Twitter + + + + + Twitter Connections + + + + + +If you only want to post tweets, you're done. + +If you want to connect Tomahawk to your friends using Twitter, select the type of tweet and press the button below to send a sync message. You must both be following each other as Direct Messages are used. Then be (very) patient -- it can take several minutes! + +You can re-send a sync message at any time simply by sending another tweet using the button. + + + + + Select the kind of tweet you would like, then press the button to post it: + + + + + Global Tweet + Tweet Global + + + + @Mention + + + + + Direct Message + + + + + e.g. @tomahawk + + + + + Send Message + + + + + ViewManager + + + SuperCollection + SuperCollection + + + + Combined libraries of all your online friends + Collections regroupant toutes celles de vos amis en ligne + + + + All available albums + Tous les albums disponibles + + + + WelcomeWidget + + + Recent Additions + Derniers Ajouts + + + + Newest Stations & Playlists + Dernières stations & listes de lecture + + + + Recently Played Tracks + Joués récemment + + + + No recently created playlists in your network. + Pas de liste de lecture créée récemment sur votre réseau. + + + + Welcome to Tomahawk + + + + + WhatsHotWidget + + + Charts + + + + + WikipediaContext + + + Wikipedia + Wikipedia + + + + XMPPBot + + + +Terms for %1: + + + + + + No terms found, sorry. + + + + + +Hotttness for %1: %2 + + + + + + +Familiarity for %1: %2 + + + + + + +Lyrics for "%1" by %2: + +%3 + + + + + + XSPFLoader + + + Failed to parse contents of XSPF playlist + Échec du décodage de la liste de lecture XSPF + + + + Some playlist entries were found without artist and track name, they will be omitted + Certaines entrées de la liste de lecture n'ont pas d'artiste ou de titre, elles seront omises. + + + + Failed to fetch the desired playlist from the network, or the desired file does not exist + Échec du chargement de la liste de lecture depuis le réseau, ou le fichier n'existe pas + + + + New Playlist + Nouvelle liste de lecture + + + + XmlConsole + + + Xml stream console + + + + + + Filter + Filtre + + + + Save log + + + + + Disabled + + + + + By JID + + + + + By namespace uri + Par namespace uri + + + + By all attributes + + + + + Visible stanzas + + + + + Information query + + + + + Message + + + + + Presence + + + + + Custom + + + + + Close + + + + + Save XMPP log to file + + + + + OpenDocument Format (*.odf);;HTML file (*.html);;Plain text (*.txt) + Format OpenDocument (*.odf);;Fichiers HTML (*.html);;Texte (*.txt) + + + + XmppConfigWidget + + + Xmpp Configuration + Configuration XMPP + + + + Configure this Xmpp account + Configurer ce compte XMPP + + + + Enter your Xmpp login to connect with your friends using Tomahawk! + + + + + Login Information + + + + + Xmpp ID: + + + + + e.g. user@example.com + + + + + Password: + + + + + An account with this name already exists! + Un compte avec ce nom existe déjà ! + + + + Advanced Xmpp Settings + Paramètres XMPP avancés + + + + Server: + + + + + Port: + + + + + Lots of servers don't support this (e.g. GTalk, jabber.org) + + + + + Publish currently playing track + Publier la piste en cours de lecture + + + + Enforce secure connection + + + + + XmppSipPlugin + + + User Interaction + + + + + Host is unknown + + + + + Item not found + + + + + Authorization Error + + + + + Remote Stream Error + + + + + Remote Connection failed + + + + + Internal Server Error + + + + + System shutdown + + + + + Conflict + + + + + Unknown + Ajouter un &ami... + + + + No Compression Support + + + + + No Encryption Support + + + + + No Authorization Support + + + + + No Supported Feature + + + + + Add Friend + + + + + Enter Xmpp ID: + + + + + Add Friend... + + + + + XML Console... + + + + + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! + + + + + Authorize User + + + + + Do you want to grant <b>%1</b> access to your Collection? + Voulez vous donner accès à votre collection à %1 ? + + + + ZeroconfConfig + + + Form + + + + + Local Network configuration + Configuration réseau local + + + + This plugin will automatically find other users running Tomahawk on your local network + Ce plugin va automatiquement trouver les autres utilisateurs de Tomahawk sur votre réseau local + + + + Connect automatically when Tomahawk starts + + + + \ No newline at end of file diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index f3fdaa4dc..5fa5dba9f 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -294,36 +294,41 @@ Remember: Only allow peers to connect if you trust who they are and if you have + social + + + + love Love - + Time 時間 - + Time Left 残り時間 - + Shuffle シャッフル - + Repeat リピート - + Low - + High @@ -677,6 +682,14 @@ Remember: Only allow peers to connect if you trust who they are and if you have 新規プレイリストを作成 + + NewReleasesWidget + + + New Releases + + + PlaylistItemDelegate @@ -1051,6 +1064,49 @@ other: %n年前 + + SocialWidget + + + Form + + + + + Facebook + + + + + Twitter + + + + + Cover + + + + + TextLabel + + + + + Listening to "%1" by %2 and loving it! %4 + + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + + + + + %1 characters left + + + SourceDelegate @@ -1264,6 +1320,11 @@ other: %n年前 + New Releases + + + + Friends @@ -1527,7 +1588,7 @@ other: %n年前 Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. @@ -2257,22 +2318,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums - + Tracks @@ -2280,12 +2341,12 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. - + on "%1" @@ -2293,31 +2354,47 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + + + Tomahawk::ItunesParser @@ -2467,7 +2544,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -3103,17 +3180,17 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums @@ -3378,107 +3455,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 36ad68d04..33418b9a8 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -294,36 +294,41 @@ Remember: Only allow peers to connect if you trust who they are and if you have + social + + + + love ulubione - + Time Czas - + Time Left Pozostały czas - + Shuffle Losowo - + Repeat Powtarzaj - + Low Nisko - + High Wysoko @@ -677,6 +682,14 @@ Remember: Only allow peers to connect if you trust who they are and if you have Utwórz nową listę + + NewReleasesWidget + + + New Releases + + + PlaylistItemDelegate @@ -695,7 +708,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have played %1 by you - + odtworzone %1 przez ciebie @@ -713,12 +726,12 @@ Remember: Only allow peers to connect if you trust who they are and if you have A playlist by %1, created %2 - Lista %1, utworzona %2 + %1 lista, utworzona %2 you - ty + Twoja @@ -1049,6 +1062,49 @@ Remember: Only allow peers to connect if you trust who they are and if you have Najczęściej odtwarzane utwory, których nie masz + + SocialWidget + + + Form + + + + + Facebook + + + + + Twitter + + + + + Cover + + + + + TextLabel + + + + + Listening to "%1" by %2 and loving it! %4 + + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + + + + + %1 characters left + + + SourceDelegate @@ -1262,6 +1318,11 @@ Remember: Only allow peers to connect if you trust who they are and if you have + New Releases + + + + Friends @@ -1475,7 +1536,7 @@ indywidualnego profilu gustu. Connect to Google Talk to find your friends - + Połącz z Google Talk, aby znaleźć znajomych @@ -1529,9 +1590,9 @@ indywidualnego profilu gustu. Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. - + Łącz się z osobami śledzącymi cię na Twitterze. @@ -2261,22 +2322,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Wszechczasów - + Artists Artyści - + Albums Albumy - + Tracks Utwory @@ -2284,12 +2345,12 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. - + on "%1" @@ -2297,31 +2358,47 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + + + Tomahawk::ItunesParser @@ -2382,12 +2459,12 @@ Try tweaking the filters for a new set of songs to play. You - + Ty you - + ty @@ -2471,7 +2548,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Moja Kolekcja @@ -3113,17 +3190,17 @@ Możesz wysłać wiadomość synchronizacyjną ponownie kiedykolwiek, po prostu ViewManager - + SuperCollection - + Combined libraries of all your online friends - + Połączone biblioteki wszystkich twoich znajomych online - + All available albums Wszystkie dostępne albumy @@ -3394,109 +3471,109 @@ Tekst dla "%1" wykonawcy %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? - + Czy chcesz udzielić dostępu do swojej kolekcji <b>%1</b>? diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 5075b0e7d..7ca157167 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -294,36 +294,41 @@ Remember: Only allow peers to connect if you trust who they are and if you have + social + + + + love Favorita - + Time Tempo - + Time Left Tempo restante - + Shuffle Embaralhar - + Repeat Repetir - + Low Diminuir - + High Aumentar @@ -677,6 +682,14 @@ Remember: Only allow peers to connect if you trust who they are and if you have Criar uma nova lista de reprodução + + NewReleasesWidget + + + New Releases + + + PlaylistItemDelegate @@ -1049,6 +1062,49 @@ Remember: Only allow peers to connect if you trust who they are and if you have Faixas mais reproduzidas que você não possui + + SocialWidget + + + Form + + + + + Facebook + + + + + Twitter + + + + + Cover + + + + + TextLabel + + + + + Listening to "%1" by %2 and loving it! %4 + + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + + + + + %1 characters left + + + SourceDelegate @@ -1262,6 +1318,11 @@ Remember: Only allow peers to connect if you trust who they are and if you have + New Releases + + + + Friends Amigos @@ -1528,7 +1589,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. @@ -2260,22 +2321,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Classificação geral - + Artists Artistas - + Albums Álbuns - + Tracks Faixas @@ -2283,12 +2344,12 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. - + on "%1" @@ -2296,31 +2357,47 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks Faixas principais - + Loved Tracks Faixas favoritas - + Hyped Tracks Faixas mais populares - + Top Artists Artistas principais - + Hyped Artists Artistas mais populares + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + + + Tomahawk::ItunesParser @@ -2470,7 +2547,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Minha biblioteca @@ -3112,17 +3189,17 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Todos os álbuns disponíveis @@ -3394,107 +3471,107 @@ Letras de "%1" por %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 21b1eb9b0..93db4a98e 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -294,36 +294,41 @@ Remember: Only allow peers to connect if you trust who they are and if you have + social + + + + love Любимая - + Time Прошло - + Time Left Осталось - + Shuffle Случаная - + Repeat Повторять - + Low Тише - + High Громче @@ -677,6 +682,14 @@ Remember: Only allow peers to connect if you trust who they are and if you have Создать Новый Плейлист + + NewReleasesWidget + + + New Releases + + + PlaylistItemDelegate @@ -1049,6 +1062,49 @@ Remember: Only allow peers to connect if you trust who they are and if you have Популярные проигрываемые песни которых у вас нет + + SocialWidget + + + Form + + + + + Facebook + + + + + Twitter + + + + + Cover + + + + + TextLabel + + + + + Listening to "%1" by %2 and loving it! %4 + + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + + + + + %1 characters left + + + SourceDelegate @@ -1262,6 +1318,11 @@ Remember: Only allow peers to connect if you trust who they are and if you have + New Releases + + + + Friends Друзья @@ -1525,7 +1586,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. @@ -2257,22 +2318,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists Исполнители - + Albums Альбомы - + Tracks Песни @@ -2280,12 +2341,12 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. - + on "%1" @@ -2293,31 +2354,47 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks Топ песен - + Loved Tracks Любимые песни - + Hyped Tracks - + Top Artists Любимые исполнители - + Hyped Artists + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + + + Tomahawk::ItunesParser @@ -2467,7 +2544,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моя коллекция @@ -3107,17 +3184,17 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection Общая коллекция - + Combined libraries of all your online friends Комбинированные библиотек всех ваших друзей онлайн - + All available albums Доступные альбомы @@ -3388,107 +3465,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Взаимодействие с пользователем - + Host is unknown Неизвестный хост - + Item not found Песня не найдена - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 3b3be3ab1..c7be10e26 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -296,36 +296,41 @@ Kom ihåg: Tillåt endast anslutning från klienter du litar på, och som har la + social + + + + love älska - + Time Tid - + Time Left Tid kvar - + Shuffle Blanda - + Repeat Upprepa - + Low Låg - + High Hög @@ -679,6 +684,14 @@ Kom ihåg: Tillåt endast anslutning från klienter du litar på, och som har la Erstelle eine neue Playliste + + NewReleasesWidget + + + New Releases + + + PlaylistItemDelegate @@ -1052,6 +1065,49 @@ Kom ihåg: Tillåt endast anslutning från klienter du litar på, och som har la Mest spelade spår som du inte har + + SocialWidget + + + Form + + + + + Facebook + + + + + Twitter + + + + + Cover + + + + + TextLabel + + + + + Listening to "%1" by %2 and loving it! %4 + + + + + Listening to "%1" by %2 on "%3" and loving it! %4 + + + + + %1 characters left + + + SourceDelegate @@ -1265,6 +1321,11 @@ Kom ihåg: Tillåt endast anslutning från klienter du litar på, och som har la + New Releases + + + + Friends @@ -1528,7 +1589,7 @@ Kom ihåg: Tillåt endast anslutning från klienter du litar på, och som har la Tomahawk::Accounts::TwitterAccountFactory - + Connect to your Twitter followers. @@ -2258,22 +2319,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists Artister - + Albums Album - + Tracks Spår @@ -2281,12 +2342,12 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - + Tomahawk is playing "%1" by %2%3. - + on "%1" @@ -2294,31 +2355,47 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists + + Tomahawk::InfoSystem::NewReleasesPlugin + + + Albums + + + + + Tomahawk::InfoSystem::TwitterInfoPlugin + + + Listening to "%1" by %2 and loving it! %3 + + + Tomahawk::ItunesParser @@ -2468,7 +2545,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -3104,17 +3181,17 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Alla tillgängliga album @@ -3379,107 +3456,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? From d93c45fd1e2a1498cbcc0e35c173cba8a16837f2 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 18:29:39 -0400 Subject: [PATCH 20/36] Since we're increasingly using toma.hk, make sure people understand that the option is recommended --- src/stackedsettingsdialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stackedsettingsdialog.ui b/src/stackedsettingsdialog.ui index 63e3674a1..0500d69c6 100644 --- a/src/stackedsettingsdialog.ui +++ b/src/stackedsettingsdialog.ui @@ -393,7 +393,7 @@ Qt::RightToLeft - Allow web browsers to interact with Tomahawk + Allow web browsers to interact with Tomahawk (recommended) true From 78192cc752e8b3fd7be471de033f49c422bae0ad Mon Sep 17 00:00:00 2001 From: Casey Link Date: Wed, 11 Apr 2012 16:26:16 -0500 Subject: [PATCH 21/36] Simplify new releases ui --- src/libtomahawk/widgets/newreleaseswidget.cpp | 15 +++------ src/libtomahawk/widgets/newreleaseswidget.ui | 31 ++++++------------- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/src/libtomahawk/widgets/newreleaseswidget.cpp b/src/libtomahawk/widgets/newreleaseswidget.cpp index 59752333d..21d1b172a 100644 --- a/src/libtomahawk/widgets/newreleaseswidget.cpp +++ b/src/libtomahawk/widgets/newreleaseswidget.cpp @@ -64,11 +64,7 @@ NewReleasesWidget::NewReleasesWidget( QWidget* parent ) ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); TomahawkUtils::unmarginLayout( layout() ); - TomahawkUtils::unmarginLayout( ui->stackLeft->layout() ); - TomahawkUtils::unmarginLayout( ui->horizontalLayout->layout() ); - TomahawkUtils::unmarginLayout( ui->horizontalLayout_2->layout() ); TomahawkUtils::unmarginLayout( ui->breadCrumbLeft->layout() ); - TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() ); m_crumbModelLeft = new QStandardItemModel( this ); m_sortedProxy = new QSortFilterProxyModel( this ); @@ -183,12 +179,12 @@ NewReleasesWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData request if( !returnedData.contains(type) ) break; const QString side = requestData.customData["whatshot_side"].toString(); - const QString chartId = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >().value( "nr_id" ); + const QString releaseId = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >().value( "nr_id" ); - m_queuedFetches.remove( chartId ); + m_queuedFetches.remove( releaseId ); ChartDataLoader* loader = new ChartDataLoader(); - loader->setProperty( "nrid", chartId ); + loader->setProperty( "nrid", releaseId ); loader->moveToThread( m_workerThread ); if ( type == "albums" ) @@ -201,9 +197,9 @@ NewReleasesWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData request AlbumModel* albumModel = new AlbumModel( ui->albumsView ); - m_albumModels[ chartId ] = albumModel; + m_albumModels[ releaseId ] = albumModel; - if ( m_queueItemToShow == chartId ) + if ( m_queueItemToShow == releaseId ) setLeftViewAlbums( albumModel ); } else @@ -355,7 +351,6 @@ NewReleasesWidget::setLeftViewAlbums( AlbumModel* model ) { ui->albumsView->setAlbumModel( model ); ui->albumsView->proxyModel()->sort( -1 ); // disable sorting, must be called after artistsViewLeft->setTreeModel - ui->stackLeft->setCurrentIndex( 2 ); } void diff --git a/src/libtomahawk/widgets/newreleaseswidget.ui b/src/libtomahawk/widgets/newreleaseswidget.ui index 094c4553a..d6122d622 100644 --- a/src/libtomahawk/widgets/newreleaseswidget.ui +++ b/src/libtomahawk/widgets/newreleaseswidget.ui @@ -12,30 +12,17 @@ - + + - - - - - - - - - - - - - true - - - QAbstractItemView::ExtendedSelection - - - - - + + + true + + + QAbstractItemView::ExtendedSelection + From 6c4e6725b471a2c3dc09ac1179ef57e9dddf72a3 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Wed, 11 Apr 2012 17:45:37 -0500 Subject: [PATCH 22/36] Remove unused cruft --- src/libtomahawk/widgets/headerbreadcrumb.cpp | 48 -------------------- src/libtomahawk/widgets/headerbreadcrumb.h | 41 ----------------- 2 files changed, 89 deletions(-) delete mode 100644 src/libtomahawk/widgets/headerbreadcrumb.cpp delete mode 100644 src/libtomahawk/widgets/headerbreadcrumb.h diff --git a/src/libtomahawk/widgets/headerbreadcrumb.cpp b/src/libtomahawk/widgets/headerbreadcrumb.cpp deleted file mode 100644 index a638164d0..000000000 --- a/src/libtomahawk/widgets/headerbreadcrumb.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2011, Casey Link - * - * 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 "headerbreadcrumb.h" - -#include "utils/stylehelper.h" - -#include -#include -#include - -HeaderBreadCrumb::HeaderBreadCrumb( BreadcrumbButtonFactory* buttonFactory, QWidget* parent ) - : BreadcrumbBar( buttonFactory, parent ) -{ -} - - -HeaderBreadCrumb::HeaderBreadCrumb( QWidget* parent ) - : BreadcrumbBar( parent ) -{ -} - - -HeaderBreadCrumb::~HeaderBreadCrumb() -{ -} - - -void HeaderBreadCrumb::paintEvent( QPaintEvent* /* event */ ) -{ - QStylePainter p( this ); - StyleHelper::horizontalHeader( &p, rect() ); -} diff --git a/src/libtomahawk/widgets/headerbreadcrumb.h b/src/libtomahawk/widgets/headerbreadcrumb.h deleted file mode 100644 index 8b15ca5a8..000000000 --- a/src/libtomahawk/widgets/headerbreadcrumb.h +++ /dev/null @@ -1,41 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2011, Casey Link - * - * 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 HEADERBREADCRUMB_H -#define HEADERBREADCRUMB_H - -#include "breadcrumbbar.h" - -class QPaintEvent; - -/** - * \brief a bread crumb widget with Tomahawk's distinctive header style - */ -class HeaderBreadCrumb : public BreadcrumbBar -{ - Q_OBJECT - public: - HeaderBreadCrumb( BreadcrumbButtonFactory* buttonFactory, QWidget* parent = 0 ); - HeaderBreadCrumb( QWidget* parent = 0 ); - ~HeaderBreadCrumb(); - - protected: - virtual void paintEvent( QPaintEvent* event ); -}; - -#endif From 90d3661c5242509d78f88d68f6be70fd4c412641 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Wed, 11 Apr 2012 18:43:32 -0500 Subject: [PATCH 23/36] Bring back the right-arrow that segments the breadcrumbs --- src/libtomahawk/widgets/Breadcrumb.cpp | 4 +- src/libtomahawk/widgets/BreadcrumbButton.cpp | 91 +++++++++++-------- src/libtomahawk/widgets/BreadcrumbButton.h | 2 + src/libtomahawk/widgets/newreleaseswidget.cpp | 1 + 4 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/libtomahawk/widgets/Breadcrumb.cpp b/src/libtomahawk/widgets/Breadcrumb.cpp index 975a5c2b0..fdccebd46 100644 --- a/src/libtomahawk/widgets/Breadcrumb.cpp +++ b/src/libtomahawk/widgets/Breadcrumb.cpp @@ -21,6 +21,7 @@ #include "BreadcrumbButton.h" #include "utils/stylehelper.h" #include "utils/logger.h" +#include "utils/tomahawkutilsgui.h" #include #include @@ -35,8 +36,7 @@ Breadcrumb::Breadcrumb( QWidget* parent, Qt::WindowFlags f ) , m_model( 0 ) , m_buttonlayout( new QHBoxLayout( this ) ) { - m_buttonlayout->setSpacing( 0 ); - m_buttonlayout->setMargin( 0 ); + TomahawkUtils::unmarginLayout( m_buttonlayout ); m_buttonlayout->setAlignment( Qt::AlignLeft ); setAutoFillBackground( true ); diff --git a/src/libtomahawk/widgets/BreadcrumbButton.cpp b/src/libtomahawk/widgets/BreadcrumbButton.cpp index 4b479c21e..12127538b 100644 --- a/src/libtomahawk/widgets/BreadcrumbButton.cpp +++ b/src/libtomahawk/widgets/BreadcrumbButton.cpp @@ -31,21 +31,67 @@ using namespace Tomahawk; +class BreadcrumbArrow : public QWidget +{ +public: + BreadcrumbArrow(QWidget* parent) : QWidget(parent) {} + +protected: + virtual void paintEvent( QPaintEvent* ) { + QPainter p( this ); + QStyleOption opt; + opt.initFrom( this ); + QRect r = rect(); + + const bool reverse = opt.direction == Qt::RightToLeft; + const int menuButtonWidth = 12; + const int rightSpacing = 10; + const int right = !reverse ? r.right() - rightSpacing : r.left() + menuButtonWidth; + const int height = r.height(); + + QLine l1( 1, 0, right, height / 2 ); + QLine l2( 1, height, right, height / 2 ); + + p.setRenderHint( QPainter::Antialiasing, true ); + + // Draw the shadow + QColor shadow( 0, 0, 0, 100 ); + p.translate( 0, 1 ); + p.setPen( shadow ); + p.drawLine( l1 ); + p.drawLine( l2 ); + + // Draw the main arrow + QColor foreGround( "#747474" ); + p.translate( 0, -1 ); + p.setPen( foreGround ); + p.drawLine( l1 ); + p.drawLine( l2 ); + } + virtual QSize sizeHint() const { + return QSize( 20, TomahawkUtils::headerHeight() ); + + } + +}; + BreadcrumbButton::BreadcrumbButton( Breadcrumb* parent, QAbstractItemModel* model ) : QWidget( parent ) , m_breadcrumb( parent ) , m_model( model ) , m_combo( new ComboBox( this ) ) + , m_arrow( new BreadcrumbArrow( this ) ) { setLayout( new QHBoxLayout ); - layout()->setContentsMargins( 0, 0, 0, 0 ); - layout()->setSpacing( 0 ); + + TomahawkUtils::unmarginLayout( layout() ); layout()->addWidget( m_combo ); + layout()->addWidget( m_arrow ); setFixedHeight( TomahawkUtils::headerHeight() ); m_combo->setSizeAdjustPolicy( QComboBox::AdjustToContents ); - setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ); + setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Expanding ); connect( m_combo, SIGNAL( activated( int ) ), SLOT( comboboxActivated( int ) ) ); } @@ -55,44 +101,9 @@ void BreadcrumbButton::paintEvent( QPaintEvent* ) { QPainter p( this ); - QStyleOption opt; - opt.initFrom( this ); - QRect r = rect(); - StyleHelper::horizontalHeader( &p, r ); // draw the background - - if ( !hasChildren() ) - return; - - bool reverse = opt.direction == Qt::RightToLeft; - int menuButtonWidth = 12; - int rightSpacing = 10; - int left = !reverse ? r.right() - rightSpacing - menuButtonWidth : r.left(); - int right = !reverse ? r.right() - rightSpacing : r.left() + menuButtonWidth; - int height = r.height(); - QRect arrowRect( ( left + right ) / 2 + ( reverse ? 6 : -6 ), 0, height, height ); - - QStyleOption arrowOpt = opt; - arrowOpt.rect = arrowRect; - - QLine l1( left, 0, right, height / 2 ); - QLine l2( left, height, right, height / 2 ); - - p.setRenderHint( QPainter::Antialiasing, true ); - - // Draw the shadow - QColor shadow( 0, 0, 0, 100 ); - p.translate( 0, -1 ); - p.setPen( shadow ); - p.drawLine( l1 ); - p.drawLine( l2 ); - - // Draw the main arrow - QColor foreGround( "#747474" ); - p.translate( 0, 1 ); - p.setPen( foreGround ); - p.drawLine( l1 ); - p.drawLine( l2 ); + StyleHelper::horizontalHeader( &p, rect() ); // draw the background + m_arrow->setVisible( hasChildren() ); } diff --git a/src/libtomahawk/widgets/BreadcrumbButton.h b/src/libtomahawk/widgets/BreadcrumbButton.h index 9735bfff7..cf424e7e1 100644 --- a/src/libtomahawk/widgets/BreadcrumbButton.h +++ b/src/libtomahawk/widgets/BreadcrumbButton.h @@ -23,6 +23,7 @@ #include class ComboBox; +class BreadcrumbArrow; class QPaintEvent; namespace Tomahawk { @@ -63,6 +64,7 @@ private: QPersistentModelIndex m_parentIndex; QPersistentModelIndex m_curIndex; ComboBox* m_combo; + BreadcrumbArrow* m_arrow; }; } diff --git a/src/libtomahawk/widgets/newreleaseswidget.cpp b/src/libtomahawk/widgets/newreleaseswidget.cpp index 21d1b172a..5d77d7404 100644 --- a/src/libtomahawk/widgets/newreleaseswidget.cpp +++ b/src/libtomahawk/widgets/newreleaseswidget.cpp @@ -64,6 +64,7 @@ NewReleasesWidget::NewReleasesWidget( QWidget* parent ) ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); TomahawkUtils::unmarginLayout( layout() ); + TomahawkUtils::unmarginLayout( ui->verticalLayout_2 ); TomahawkUtils::unmarginLayout( ui->breadCrumbLeft->layout() ); m_crumbModelLeft = new QStandardItemModel( this ); From add5bdf8de6272f8d7544163bae27ec3fb3557da Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 11 Apr 2012 20:34:42 -0400 Subject: [PATCH 24/36] Add assert to make it obvious during development if an info plugin is not in the right thread, thanks Leo for the suggestion --- src/libtomahawk/infosystem/infosystem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/infosystem/infosystem.cpp b/src/libtomahawk/infosystem/infosystem.cpp index 9db1bfe80..2dca67a95 100644 --- a/src/libtomahawk/infosystem/infosystem.cpp +++ b/src/libtomahawk/infosystem/infosystem.cpp @@ -227,6 +227,7 @@ InfoSystem::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) if ( plugin.data()->thread() != m_infoSystemWorkerThreadController->worker()->thread() ) { + Q_ASSERT( false ); tDebug() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread()"; return; } From 68d2cb38deeefef9ea72512ea6ea833e462f6c12 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Thu, 12 Apr 2012 22:17:09 +0000 Subject: [PATCH 25/36] Automatic merge of Transifex translations --- lang/tomahawk_bg.ts | 24 +++++++++---------- lang/tomahawk_de.ts | 4 ++-- lang/tomahawk_en.ts | 4 ++-- lang/tomahawk_es.ts | 2 +- lang/tomahawk_fr.ts | 4 ++-- lang/tomahawk_ja.ts | 2 +- lang/tomahawk_pl.ts | 52 +++++++++++++++++++++--------------------- lang/tomahawk_pt_BR.ts | 2 +- lang/tomahawk_ru.ts | 2 +- lang/tomahawk_sv.ts | 2 +- 10 files changed, 49 insertions(+), 49 deletions(-) diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 074d83e32..174187328 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -985,7 +985,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Failed to load: %1 - Неуспех при зареждане на %1 + Не мога да заредя %1 @@ -1095,12 +1095,12 @@ Remember: Only allow peers to connect if you trust who they are and if you have Listening to "%1" by %2 and loving it! %4 - Слушам "%1" от %2 и я харесвам! %4 + <3 "%1" от %2 %4 Listening to "%1" by %2 on "%3" and loving it! %4 - Слушам "%1" от %2 от "%3" и я харесвам! %4 + <3 "%1" от %2 от "%3" %4 @@ -1469,8 +1469,8 @@ Spotify e TM на Spotify Group. - Allow web browsers to interact with Tomahawk - Позволи на web браузъри да работят заедно с Tomahawk. + Allow web browsers to interact with Tomahawk (recommended) + @@ -1574,7 +1574,7 @@ Spotify e TM на Spotify Group. Success - Успех! + Ура! @@ -1874,7 +1874,7 @@ Please change the filters or try again. Failed to generate preview with the desired filters - Неуспех при генериране на предварителен преглед на избраните филтри. + Не мога да генерирам предварителен преглед на избраните филтри. @@ -2227,7 +2227,7 @@ Try tweaking the filters for a new set of songs to play. Steer this station: - Задръж тази станция: + Настройки: @@ -2247,7 +2247,7 @@ Try tweaking the filters for a new set of songs to play. Keep at current - Задръж + Запази @@ -2405,7 +2405,7 @@ Try tweaking the filters for a new set of songs to play. Listening to "%1" by %2 and loving it! %3 - Слушам "%1" от %2 и я харесвам! %3 + <3 "%1" от %2 %3 @@ -2426,7 +2426,7 @@ Try tweaking the filters for a new set of songs to play. Failed to save tracks - Неуспех при запаметяване на песни + Не мога да запазя избраните песни @@ -2810,7 +2810,7 @@ enter the displayed PIN number here: Failed to save tracks - Неуспех при запазване на списък с песни + Не мога да запазя списъкът с песни diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 73e7379bb..e30ff51a8 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -1464,8 +1464,8 @@ Denk dran: Erlaube das nur, wenn du dem Anderen vertraust und du die Rechte zum - Allow web browsers to interact with Tomahawk - Erlaube Webbrowsern mit Tomahawk zu interagieren + Allow web browsers to interact with Tomahawk (recommended) + diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index cbfda8236..4b53ebf36 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -1468,8 +1468,8 @@ Remember: Only allow peers to connect if you trust who they are and if you have - Allow web browsers to interact with Tomahawk - Allow web browsers to interact with Tomahawk + Allow web browsers to interact with Tomahawk (recommended) + Allow web browsers to interact with Tomahawk (recommended) diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index ec4221230..d6e866f35 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -1465,7 +1465,7 @@ y estaciones basadas en sus gustos personales. - Allow web browsers to interact with Tomahawk + Allow web browsers to interact with Tomahawk (recommended) diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 5249cc809..6defd655c 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -1468,8 +1468,8 @@ et des stations basés sur vos goûts. - Allow web browsers to interact with Tomahawk - Autoriser les navigateurs Web à utiliser Tomahawk + Allow web browsers to interact with Tomahawk (recommended) + diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 5fa5dba9f..3aef4578b 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -1464,7 +1464,7 @@ other: %n年前 - Allow web browsers to interact with Tomahawk + Allow web browsers to interact with Tomahawk (recommended) diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 33418b9a8..f2053ca42 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -195,7 +195,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have After you have scanned your music collection you will find your latest album additions right here. - Po zeskanowaniu swojej kolekcji muzycznej znajdziesz ostatnio dodane albumy właśnie tutaj. + Po zeskanowaniu swojej kolekcji muzycznej w tym miejscu znajdziesz ostatnio dodane albumy. @@ -242,7 +242,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have After you have scanned your music collection you will find your tracks right here. - Po zeskanowaniu swojej kolekcji muzycznej znajdziesz utwory właśnie tutaj. + Po zeskanowaniu swojej kolekcji muzycznej utwory znajdziesz w tym miejscu. @@ -252,7 +252,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Sorry, your filter '%1' did not match any results. - Przepraszamy, twój filtr %1' nie pasuje do żadnych wyników. + Przepraszamy, twój filtr '%1' nie pasuje do żadnych wyników. @@ -428,7 +428,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have <p><b>Sorry!</b>&nbsp;Tomahawk crashed. Information about the crash is now being sent to Tomahawk HQ so that we can fix the bug.</p> - <p><b>Przepraszamy!</b>&nbsp;Tomahawk uległ awarii. Informacja o incydencie zostanie teraz wysłana do kwatery głównej programu, abyśmy mogli poprawić błędy.</p> + <p><b>Przepraszamy!</b>&nbsp;Tomahawk uległ awarii. Abyśmy mogli poprawić błędy, informacja o incydencie zostanie wysłana do kwatery głównej programu.</p> @@ -664,12 +664,12 @@ Remember: Only allow peers to connect if you trust who they are and if you have Tomahawk offers a variety of ways to help you create playlists and find music you enjoy! - Tomahawk oferuje różne sposoby pomocy w tworzeniu list i poszukiwaniu muzyki, którą lubisz! + Tomahawk oferuje różne sposoby pomocy w tworzeniu list i poszukiwaniu twojej ulubionej muzyki! Just enter a genre or tag name and Tomahawk will suggest a few songs to get you started with your new playlist: - Podaj tylko tag lub gatunek, a Tomahawk zasugeruje kilka piosenek, żeby pomóc ci zacząć z nową listą: + Jeśli podasz chociaż jeden tag lub gatunek, Tomahawk postara się zasugerować ci kilka piosenek na dobry początek: @@ -754,7 +754,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Just a regular old playlist... Give it a name, drag in some tracks, and go! - Po prostu zwykła stara lista... Nazwij, upuść na nią trochę piosenek i gotowe! + Po prostu zwykła stara lista... Nazwij ją, upuść na nią trochę piosenek i gotowe! @@ -800,7 +800,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Hostname of proxy server - Nazwa hosta serwera proxy + Host serwera proxy @@ -961,7 +961,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Hide Queue - Schowaj Kolejkę + Ukryj Kolejkę @@ -977,7 +977,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Not found: %1 - Nie znaleziono %1 + Nie znaleziono: %1 @@ -1157,7 +1157,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Hide - Schowaj + Ukryj @@ -1362,7 +1362,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have High Quality Streaming - Strumieniowanie w wysokiej jakości + Muzyka w wysokiej jakości @@ -1380,7 +1380,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Local Music Information - Lokalne Informacje o Muzyce + Informacje o Lokalnej Muzyce @@ -1407,7 +1407,7 @@ indywidualnego profilu gustu. Watch for changes - Obserwuj pod kątem zmian + Obserwuj zmiany @@ -1466,7 +1466,7 @@ indywidualnego profilu gustu. - Allow web browsers to interact with Tomahawk + Allow web browsers to interact with Tomahawk (recommended) @@ -1536,7 +1536,7 @@ indywidualnego profilu gustu. Connect to Google Talk to find your friends - Połącz z Google Talk, aby znaleźć znajomych + Połącz z Google Talk aby znaleźć znajomych @@ -1749,7 +1749,7 @@ You may wish to try re-authenticating. Add to &Queue - Dodaj do &Kolejki + Dodaj do &kolejki @@ -1888,17 +1888,17 @@ Proszę zmienić filtry lub spróbować ponownie. Add some filters above to seed this station! - Dodaj trochę filtrów powyżej, aby załączyć tą stację! + Dodaj powyzej trochę filtrów, a Tomahawk utworzy stację z podobną muzyką! Press Generate to get started! - Naciśnij Generuj, aby zacząć! + Naciśnij Generuj aby zacząć! Add some filters above, and press Generate to get started! - Dodaj trochę filtrów powyżej i naciśnij Generuj, aby zacząć! + Dodaj powyżej trochę filtrów i naciśnij Generuj aby zacząć! @@ -2558,7 +2558,7 @@ Try tweaking the filters for a new set of songs to play. Twitter PIN - PIN Twitter + Twitter PIN @@ -3119,12 +3119,12 @@ wprowadź pokazany numer PIN tutaj: Configure this Twitter account - Konfiguruj to konto Twitter + Konfiguruj konto na Twitter The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - Wtyczka Twittera pozwala ci odkrywać i odtwarzać muzykę znajomych z Twittera, którzy używają Tomahawka i wysyłać wiadomości ze swojego konta. + Wtyczka Twittera pozwala ci odkrywać i odtwarzać muzykę znajomych z Twittera, którzy używają Tomahawka oraz wysyłać wiadomości ze swojego konta. @@ -3152,14 +3152,14 @@ You can re-send a sync message at any time simply by sending another tweet using Jeśli chcesz jedynie wysyłać tweety, wszystko gotowe. -Jeśli chcesz, aby Tomahawk łączył się z twoimi znajomymi używając Twittera, wybierz rodzaj tweeta i naciśnij przycisk poniżej by wysłać wiadomość synchronizacyjną. Obie strony muszą śledzić się nawzajem, ponieważ używane są Wiadomości Prywatne. Teraz miej (dużo) cierpliwości - może to zająć kilka minut! +Jeśli chcesz, aby Tomahawk łączył się z twoimi znajomymi używając Twittera, wybierz rodzaj tweeta i naciśnij przycisk poniżej by wysłać wiadomość synchronizacyjną. Obie strony muszą śledzić się nawzajem, ponieważ używane są Wiadomości Prywatne. Miej (dużo) cierpliwość - może to zająć kilka minut! -Możesz wysłać wiadomość synchronizacyjną ponownie kiedykolwiek, po prostu wyślij kolejnego tweeta używając przycisku. +Możesz kiedykolwiek, ponownie wysłać wiadomość synchronizacyjną - po prostu wyślij kolejnego tweeta używając przycisku. Select the kind of tweet you would like, then press the button to post it: - Wybierz rodzaj tweeta, który ci odpowiada, a następnie naciśnij przycisk, aby go wysłać: + Wybierz rodzaj tweeta który ci odpowiada, a następnie naciśnij przycisk aby go wysłać: diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 7ca157167..b884a0885 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -1465,7 +1465,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have - Allow web browsers to interact with Tomahawk + Allow web browsers to interact with Tomahawk (recommended) diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 93db4a98e..a866d0e1f 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -1462,7 +1462,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have - Allow web browsers to interact with Tomahawk + Allow web browsers to interact with Tomahawk (recommended) diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index c7be10e26..064b9d6fb 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -1465,7 +1465,7 @@ Kom ihåg: Tillåt endast anslutning från klienter du litar på, och som har la - Allow web browsers to interact with Tomahawk + Allow web browsers to interact with Tomahawk (recommended) From 08fa4bacd1450ef11e57319e664a154a3d842b4c Mon Sep 17 00:00:00 2001 From: Casey Link Date: Thu, 12 Apr 2012 16:24:29 -0500 Subject: [PATCH 26/36] New TomahawkCache utility class. A simple, generic cache utility that various bits and bobs can use. --- src/libtomahawk/CMakeLists.txt | 1 + src/libtomahawk/utils/tomahawkcache.cpp | 140 ++++++++++++++++++++++++ src/libtomahawk/utils/tomahawkcache.h | 72 ++++++++++++ src/tomahawkapp.cpp | 7 +- 4 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 src/libtomahawk/utils/tomahawkcache.cpp create mode 100644 src/libtomahawk/utils/tomahawkcache.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index e76a53f04..2a2716829 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -291,6 +291,7 @@ set( libSources utils/logger.cpp utils/qnr_iodevicestream.cpp utils/xspfloader.cpp + utils/tomahawkcache.cpp thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp thirdparty/kdsingleapplicationguard/kdsharedmemorylocker.cpp diff --git a/src/libtomahawk/utils/tomahawkcache.cpp b/src/libtomahawk/utils/tomahawkcache.cpp new file mode 100644 index 000000000..9859720c1 --- /dev/null +++ b/src/libtomahawk/utils/tomahawkcache.cpp @@ -0,0 +1,140 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Casey Link + * + * 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 "tomahawkcache.h" + +#include "tomahawksettings.h" + +#include +#include + +using namespace TomahawkUtils; + +TomahawkCache*TomahawkCache::s_instance = 0; + +TomahawkCache* TomahawkCache::instance() +{ + if ( !s_instance ) + s_instance = new TomahawkCache(); + + return s_instance; +} + +TomahawkCache::TomahawkCache() + : QObject ( 0 ) + , m_cacheBaseDir ( TomahawkSettings::instance()->storageCacheLocation() + "/GenericCache/" ) + , m_cacheManifest ( m_cacheBaseDir + "cachemanifest.ini", QSettings::IniFormat ) +{ + m_pruneTimer.setInterval ( 300000 ); + m_pruneTimer.setSingleShot ( false ); + connect ( &m_pruneTimer, SIGNAL ( timeout() ), SLOT ( pruneTimerFired() ) ); + m_pruneTimer.start(); +} + +TomahawkCache::~TomahawkCache() +{ + +} + +void TomahawkCache::pruneTimerFired() +{ + qDebug() << Q_FUNC_INFO << "Pruning tomahawkcache"; + qlonglong currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); + + QVariantList clients = m_cacheManifest.value ( "clients" ).toList(); + foreach ( const QVariant &client, clients ) { + const QString client_identifier = client.toString(); + const QString cache_dir = m_cacheBaseDir + client_identifier; + + QSettings cached_settings ( cache_dir, QSettings::IniFormat ); + const QStringList keys = cached_settings.allKeys(); + foreach ( const QString &key, keys ) { + CacheData data = cached_settings.value ( key ).value(); + if ( data.maxAge < currentMSecsSinceEpoch ) { + cached_settings.remove ( key ); + tLog() << Q_FUNC_INFO << "Removed stale entry: " << client_identifier << key; + } + } + cached_settings.sync(); + if ( cached_settings.allKeys().size() == 0 ) + removeClient ( client_identifier ); + } +} + + +QVariant TomahawkCache::getData ( const QString& identifier, const QString& key ) +{ + const QString cacheDir = m_cacheBaseDir + identifier; + QSettings cached_settings ( cacheDir, QSettings::IniFormat ); + + if ( cached_settings.contains ( key ) ) { + CacheData data = cached_settings.value ( key ).value(); + + if ( data.maxAge < QDateTime::currentMSecsSinceEpoch() ) { + cached_settings.remove ( key ); + tLog() << Q_FUNC_INFO << "Removed stale entry: " << identifier << key; + return QVariant(); + } + return data.data; + + } + return QVariant(); +} + +void TomahawkCache::putData ( const QString& identifier, qint64 maxAge, const QString& key, const QVariant& value ) +{ + const QString cacheDir = m_cacheBaseDir + identifier; + addClient ( identifier ); + QSettings cached_settings ( cacheDir, QSettings::IniFormat ); + cached_settings.setValue ( key, QVariant::fromValue ( CacheData ( maxAge, value ) ) ); +} + +void TomahawkCache::addClient ( const QString& identifier ) +{ + QVariantList clients = m_cacheManifest.value ( "clients" ).toList(); + foreach ( const QVariant &client, clients ) { + const QString client_identifier = client.toString(); + if ( identifier == client_identifier ) return; + } + + tLog() << Q_FUNC_INFO << "adding client" << identifier; + clients.append ( identifier ); + m_cacheManifest.setValue ( "clients", clients ); + m_cacheManifest.sync(); +} + +void TomahawkCache::removeClient ( const QString& identifier ) +{ + QVariantList clients = m_cacheManifest.value ( "clients" ).toList(); + QVariantList::iterator it = clients.begin(); + while ( it != clients.end() ) { + const QString client_identifier = it->toString(); + if ( identifier == client_identifier ) { + tLog() << Q_FUNC_INFO << "removing client" << identifier; + clients.erase ( it ); + break; + } + ++it; + } + m_cacheManifest.setValue ( "clients", clients ); + m_cacheManifest.sync(); +} + + + + diff --git a/src/libtomahawk/utils/tomahawkcache.h b/src/libtomahawk/utils/tomahawkcache.h new file mode 100644 index 000000000..175fb2e4f --- /dev/null +++ b/src/libtomahawk/utils/tomahawkcache.h @@ -0,0 +1,72 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Casey Link + * + * 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 TOMAHAWKCACHE_H +#define TOMAHAWKCACHE_H + +#include "dllmacro.h" +#include "utils/tomahawkutils.h" + +#include +#include +#include + +namespace TomahawkUtils { + +struct CacheData { + CacheData(){} + CacheData( qint64 maxAg, QVariant dat ) + : maxAge( maxAg ) + , data( dat ) + {} + + qint64 maxAge; + QVariant data; +}; + +class DLLEXPORT TomahawkCache : public QObject +{ +Q_OBJECT + +public: + static TomahawkCache* instance(); + virtual ~TomahawkCache(); + + void putData( const QString &identifier, qint64 maxAge, const QString &key, const QVariant& value ); + QVariant getData( const QString &identifier, const QString &key ); + +private slots: + void pruneTimerFired(); + +private: + TomahawkCache(); + static TomahawkCache* s_instance; + + void addClient( const QString &identifier ); + void removeClient( const QString &identifier ); + + QString m_cacheBaseDir; + QSettings m_cacheManifest; + QTimer m_pruneTimer; +}; + +} + +Q_DECLARE_METATYPE( TomahawkUtils::CacheData ); + +#endif // TOMAHAWKCACHE_H diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 3d7d5b529..044395aae 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -62,6 +62,7 @@ #include "utils/jspfloader.h" #include "utils/logger.h" #include "utils/tomahawkutilsgui.h" +#include "utils/tomahawkcache.h" #include "config.h" @@ -228,7 +229,7 @@ TomahawkApp::init() tDebug() << "Init AccountManager."; m_accountManager = QWeakPointer< Tomahawk::Accounts::AccountManager >( new Tomahawk::Accounts::AccountManager( this ) ); connect( m_accountManager.data(), SIGNAL( ready() ), SLOT( accountManagerReady() ) ); - + Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() ); #ifndef ENABLE_HEADLESS EchonestGenerator::setupCatalogs(); @@ -318,6 +319,7 @@ TomahawkApp::~TomahawkApp() delete m_audioEngine.data(); delete Tomahawk::Accounts::AccountManager::instance(); + delete TomahawkUtils::TomahawkCache::instance(); #ifndef ENABLE_HEADLESS delete m_mainwindow; @@ -449,6 +451,9 @@ TomahawkApp::registerMetaTypes() qRegisterMetaType< QPersistentModelIndex >( "QPersistentModelIndex" ); qRegisterMetaType< Tomahawk::PlaylistInterface::LatchMode >( "Tomahawk::PlaylistInterface::LatchMode" ); + + qRegisterMetaType< TomahawkUtils::CacheData>( "TomahawkUtils::CacheData" ); + } From 67d943bce34a04b28e6f57d2aa03149622e6b862 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Thu, 12 Apr 2012 17:01:50 -0500 Subject: [PATCH 27/36] Rename TomahawkUtils::TomahawkCache to TomahawkUtils::Cache --- src/libtomahawk/utils/tomahawkcache.cpp | 22 ++++++++++++---------- src/libtomahawk/utils/tomahawkcache.h | 10 +++++----- src/tomahawkapp.cpp | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/libtomahawk/utils/tomahawkcache.cpp b/src/libtomahawk/utils/tomahawkcache.cpp index 9859720c1..47692b2da 100644 --- a/src/libtomahawk/utils/tomahawkcache.cpp +++ b/src/libtomahawk/utils/tomahawkcache.cpp @@ -25,17 +25,17 @@ using namespace TomahawkUtils; -TomahawkCache*TomahawkCache::s_instance = 0; +Cache*Cache::s_instance = 0; -TomahawkCache* TomahawkCache::instance() +Cache* Cache::instance() { if ( !s_instance ) - s_instance = new TomahawkCache(); + s_instance = new Cache(); return s_instance; } -TomahawkCache::TomahawkCache() +Cache::Cache() : QObject ( 0 ) , m_cacheBaseDir ( TomahawkSettings::instance()->storageCacheLocation() + "/GenericCache/" ) , m_cacheManifest ( m_cacheBaseDir + "cachemanifest.ini", QSettings::IniFormat ) @@ -46,12 +46,12 @@ TomahawkCache::TomahawkCache() m_pruneTimer.start(); } -TomahawkCache::~TomahawkCache() +Cache::~Cache() { } -void TomahawkCache::pruneTimerFired() +void Cache::pruneTimerFired() { qDebug() << Q_FUNC_INFO << "Pruning tomahawkcache"; qlonglong currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); @@ -77,7 +77,7 @@ void TomahawkCache::pruneTimerFired() } -QVariant TomahawkCache::getData ( const QString& identifier, const QString& key ) +QVariant Cache::getData ( const QString& identifier, const QString& key ) { const QString cacheDir = m_cacheBaseDir + identifier; QSettings cached_settings ( cacheDir, QSettings::IniFormat ); @@ -96,15 +96,17 @@ QVariant TomahawkCache::getData ( const QString& identifier, const QString& key return QVariant(); } -void TomahawkCache::putData ( const QString& identifier, qint64 maxAge, const QString& key, const QVariant& value ) +void Cache::putData ( const QString& identifier, qint64 maxAge, const QString& key, const QVariant& value ) { + QMutexLocker mutex_locker( &m_mutex ); + const QString cacheDir = m_cacheBaseDir + identifier; addClient ( identifier ); QSettings cached_settings ( cacheDir, QSettings::IniFormat ); cached_settings.setValue ( key, QVariant::fromValue ( CacheData ( maxAge, value ) ) ); } -void TomahawkCache::addClient ( const QString& identifier ) +void Cache::addClient ( const QString& identifier ) { QVariantList clients = m_cacheManifest.value ( "clients" ).toList(); foreach ( const QVariant &client, clients ) { @@ -118,7 +120,7 @@ void TomahawkCache::addClient ( const QString& identifier ) m_cacheManifest.sync(); } -void TomahawkCache::removeClient ( const QString& identifier ) +void Cache::removeClient ( const QString& identifier ) { QVariantList clients = m_cacheManifest.value ( "clients" ).toList(); QVariantList::iterator it = clients.begin(); diff --git a/src/libtomahawk/utils/tomahawkcache.h b/src/libtomahawk/utils/tomahawkcache.h index 175fb2e4f..b28a377c1 100644 --- a/src/libtomahawk/utils/tomahawkcache.h +++ b/src/libtomahawk/utils/tomahawkcache.h @@ -39,13 +39,13 @@ struct CacheData { QVariant data; }; -class DLLEXPORT TomahawkCache : public QObject +class DLLEXPORT Cache : public QObject { Q_OBJECT public: - static TomahawkCache* instance(); - virtual ~TomahawkCache(); + static Cache* instance(); + virtual ~Cache(); void putData( const QString &identifier, qint64 maxAge, const QString &key, const QVariant& value ); QVariant getData( const QString &identifier, const QString &key ); @@ -54,8 +54,8 @@ private slots: void pruneTimerFired(); private: - TomahawkCache(); - static TomahawkCache* s_instance; + Cache(); + static Cache* s_instance; void addClient( const QString &identifier ); void removeClient( const QString &identifier ); diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 044395aae..f10310168 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -319,7 +319,7 @@ TomahawkApp::~TomahawkApp() delete m_audioEngine.data(); delete Tomahawk::Accounts::AccountManager::instance(); - delete TomahawkUtils::TomahawkCache::instance(); + delete TomahawkUtils::Cache::instance(); #ifndef ENABLE_HEADLESS delete m_mainwindow; From c6beda5a7b6acf321d128cf9076a67ee0b1ffd15 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Thu, 12 Apr 2012 17:02:11 -0500 Subject: [PATCH 28/36] Add a Cache mutex to protect shared data --- src/libtomahawk/utils/tomahawkcache.cpp | 5 +++++ src/libtomahawk/utils/tomahawkcache.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/libtomahawk/utils/tomahawkcache.cpp b/src/libtomahawk/utils/tomahawkcache.cpp index 47692b2da..ac4dc06b5 100644 --- a/src/libtomahawk/utils/tomahawkcache.cpp +++ b/src/libtomahawk/utils/tomahawkcache.cpp @@ -22,6 +22,7 @@ #include #include +#include using namespace TomahawkUtils; @@ -53,6 +54,8 @@ Cache::~Cache() void Cache::pruneTimerFired() { + QMutexLocker mutex_locker( &m_mutex ); + qDebug() << Q_FUNC_INFO << "Pruning tomahawkcache"; qlonglong currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); @@ -79,6 +82,8 @@ void Cache::pruneTimerFired() QVariant Cache::getData ( const QString& identifier, const QString& key ) { + QMutexLocker mutex_locker( &m_mutex ); + const QString cacheDir = m_cacheBaseDir + identifier; QSettings cached_settings ( cacheDir, QSettings::IniFormat ); diff --git a/src/libtomahawk/utils/tomahawkcache.h b/src/libtomahawk/utils/tomahawkcache.h index b28a377c1..6fa16d4c2 100644 --- a/src/libtomahawk/utils/tomahawkcache.h +++ b/src/libtomahawk/utils/tomahawkcache.h @@ -22,6 +22,7 @@ #include "dllmacro.h" #include "utils/tomahawkutils.h" +#include #include #include #include @@ -63,6 +64,7 @@ private: QString m_cacheBaseDir; QSettings m_cacheManifest; QTimer m_pruneTimer; + QMutex m_mutex; }; } From 4b6eadd95637098833766fdebd41f5194ca2f362 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Fri, 13 Apr 2012 15:10:19 -0500 Subject: [PATCH 29/36] Add documentation to cache --- src/libtomahawk/utils/tomahawkcache.h | 37 ++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/utils/tomahawkcache.h b/src/libtomahawk/utils/tomahawkcache.h index 6fa16d4c2..aef172860 100644 --- a/src/libtomahawk/utils/tomahawkcache.h +++ b/src/libtomahawk/utils/tomahawkcache.h @@ -29,6 +29,9 @@ namespace TomahawkUtils { +/** + * Internal data structure. Don't use. + */ struct CacheData { CacheData(){} CacheData( qint64 maxAg, QVariant dat ) @@ -36,10 +39,19 @@ struct CacheData { , data( dat ) {} - qint64 maxAge; + qint64 maxAge; //!< milliseconds QVariant data; }; +/** + * A simple generic cache for anyone to use. + * + * Data is segmented according to clients, which specify + * a client identifier. + * + * Structure is a basic key-value store with associated max lifetime in + * milliseconds. + */ class DLLEXPORT Cache : public QObject { Q_OBJECT @@ -48,7 +60,21 @@ public: static Cache* instance(); virtual ~Cache(); + /** + * Store data in the cache. + * @param identifier your unique identifier, used to segment your data. + * @param maxAge lifetime of data in milliseconds (e.g, 3600000 = 1 hour) + * @param key the key to store the data + * @param value the data to store + */ void putData( const QString &identifier, qint64 maxAge, const QString &key, const QVariant& value ); + + /** + * Retrieve data from the cache. + * @param identifier your unique identifier, used to segment your data. + * @param key the key to store the data + * @return the data, if found, if not found an invalid QVariant is returned. + */ QVariant getData( const QString &identifier, const QString &key ); private slots: @@ -58,7 +84,16 @@ private: Cache(); static Cache* s_instance; + /** + * Adds a client to the manifest. + * Does not lock the mutex. + */ void addClient( const QString &identifier ); + + /** + * Removes a client to the manifest. + * Does not lock the mutex. + */ void removeClient( const QString &identifier ); QString m_cacheBaseDir; From 613d40a60505f04da5d4d1e2b2db2aa41ec104e8 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Fri, 13 Apr 2012 15:10:34 -0500 Subject: [PATCH 30/36] Store the correct lifetime for cache data. --- src/libtomahawk/utils/tomahawkcache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/utils/tomahawkcache.cpp b/src/libtomahawk/utils/tomahawkcache.cpp index ac4dc06b5..d56b8de99 100644 --- a/src/libtomahawk/utils/tomahawkcache.cpp +++ b/src/libtomahawk/utils/tomahawkcache.cpp @@ -108,7 +108,7 @@ void Cache::putData ( const QString& identifier, qint64 maxAge, const QString& k const QString cacheDir = m_cacheBaseDir + identifier; addClient ( identifier ); QSettings cached_settings ( cacheDir, QSettings::IniFormat ); - cached_settings.setValue ( key, QVariant::fromValue ( CacheData ( maxAge, value ) ) ); + cached_settings.setValue ( key, QVariant::fromValue ( CacheData ( QDateTime::currentMSecsSinceEpoch() + maxAge, value ) ) ); } void Cache::addClient ( const QString& identifier ) From c46c9bba8e76bdc00fa4bb18aa84e5e9028feeb2 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Fri, 13 Apr 2012 16:07:55 -0500 Subject: [PATCH 31/36] Add some debug to the generic cache --- src/libtomahawk/utils/tomahawkcache.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libtomahawk/utils/tomahawkcache.cpp b/src/libtomahawk/utils/tomahawkcache.cpp index d56b8de99..ac509a194 100644 --- a/src/libtomahawk/utils/tomahawkcache.cpp +++ b/src/libtomahawk/utils/tomahawkcache.cpp @@ -19,6 +19,7 @@ #include "tomahawkcache.h" #include "tomahawksettings.h" +#include "utils/logger.h" #include #include @@ -95,9 +96,11 @@ QVariant Cache::getData ( const QString& identifier, const QString& key ) tLog() << Q_FUNC_INFO << "Removed stale entry: " << identifier << key; return QVariant(); } + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Fetched data for" << identifier << key; return data.data; } + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "No such client" << identifier; return QVariant(); } @@ -109,6 +112,7 @@ void Cache::putData ( const QString& identifier, qint64 maxAge, const QString& k addClient ( identifier ); QSettings cached_settings ( cacheDir, QSettings::IniFormat ); cached_settings.setValue ( key, QVariant::fromValue ( CacheData ( QDateTime::currentMSecsSinceEpoch() + maxAge, value ) ) ); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Storing from client " << identifier << maxAge << key << value; } void Cache::addClient ( const QString& identifier ) @@ -145,3 +149,4 @@ void Cache::removeClient ( const QString& identifier ) + From 6e51739ec944870943817fd533dc8f6667b3dd61 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Fri, 13 Apr 2012 16:08:21 -0500 Subject: [PATCH 32/36] Add stream operators for CacheData --- src/libtomahawk/utils/tomahawkcache.h | 13 +++++++++++++ src/tomahawkapp.cpp | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/utils/tomahawkcache.h b/src/libtomahawk/utils/tomahawkcache.h index aef172860..3bd17885f 100644 --- a/src/libtomahawk/utils/tomahawkcache.h +++ b/src/libtomahawk/utils/tomahawkcache.h @@ -104,6 +104,19 @@ private: } +inline QDataStream& operator<< ( QDataStream& in, const TomahawkUtils::CacheData& data ) +{ + in << data.data << data.maxAge; + return in; +} + +inline QDataStream& operator>> ( QDataStream& out, TomahawkUtils::CacheData& data ) +{ + out >> data.data; + out >> data.maxAge; + return out; +} + Q_DECLARE_METATYPE( TomahawkUtils::CacheData ); #endif // TOMAHAWKCACHE_H diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index f10310168..81751785a 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -452,8 +452,8 @@ TomahawkApp::registerMetaTypes() qRegisterMetaType< Tomahawk::PlaylistInterface::LatchMode >( "Tomahawk::PlaylistInterface::LatchMode" ); - qRegisterMetaType< TomahawkUtils::CacheData>( "TomahawkUtils::CacheData" ); - + qRegisterMetaType< TomahawkUtils::CacheData >( "TomahawkUtils::CacheData" ); + qRegisterMetaTypeStreamOperators< TomahawkUtils::CacheData >( "TomahawkUtils::CacheData" ); } From a6754e7467b274f1a421b07e659a743a71f0f06c Mon Sep 17 00:00:00 2001 From: Casey Link Date: Fri, 13 Apr 2012 16:08:38 -0500 Subject: [PATCH 33/36] Fix charts on subsequent starts by caching the list of sources. --- .../infoplugins/generic/chartsplugin.cpp | 22 +++++++++++++++++-- src/libtomahawk/infosystem/infosystemcache.h | 2 +- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp index b9550c1f7..855b7071a 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp @@ -1,5 +1,6 @@ /* === This file is part of Tomahawk Player - === * + * Copyright 2012, Casey Link * Copyright 2010-2011, Hugo Lindström * Copyright 2011, Leo Franchi * Copyright 2010-2011, Jeff Mitchell @@ -32,6 +33,7 @@ #include "tomahawksettings.h" #include "utils/tomahawkutils.h" #include "utils/logger.h" +#include "utils/tomahawkcache.h" #define CHART_URL "http://charts.tomahawk-player.org/" //#define CHART_URL "http://localhost:8080/" @@ -46,7 +48,14 @@ ChartsPlugin::ChartsPlugin() , m_chartsFetchJobs( 0 ) { /// If you add resource, update version aswell - m_chartVersion = "2.2"; + m_chartVersion = "2.3"; + QVariantList source_qvarlist = TomahawkUtils::Cache::instance()->getData( "ChartsPlugin", "chart_sources" ).toList(); + foreach( const QVariant & source, source_qvarlist ) { + m_chartResources.append( source.toString() ); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "fetched source from cache" << source.toString(); + + } + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "total sources" << m_chartResources.size() << source_qvarlist.size(); m_supportedGetTypes << InfoChart << InfoChartCapabilities; } @@ -91,12 +100,14 @@ ChartsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { if( resource == hash["chart_source"] ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "get source" << resource; foundSource = true; } } if( !foundSource ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "no such source" << hash["chart_source"] << "(" << m_chartResources.size() << " total sources)"; dataError( requestData ); break; } @@ -120,6 +131,7 @@ ChartsPlugin::fetchChartFromCache( Tomahawk::InfoSystem::InfoRequestData request if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Could not convert requestData to InfoStringHash!"; dataError( requestData ); return; } @@ -138,6 +150,8 @@ ChartsPlugin::fetchChartFromCache( Tomahawk::InfoSystem::InfoRequestData request /// Set the criterias for current chart criteria["chart_id"] = hash["chart_id"]; criteria["chart_source"] = hash["chart_source"]; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking cache for " << hash["chart_id"] << " from " << hash["chart_source"]; + emit getCachedInfo( criteria, 86400000, requestData ); } @@ -155,6 +169,7 @@ ChartsPlugin::fetchChartCapabilitiesFromCache( Tomahawk::InfoSystem::InfoRequest Tomahawk::InfoSystem::InfoStringHash criteria; criteria[ "InfoChartCapabilities" ] = "chartsplugin"; criteria[ "InfoChartVersion" ] = m_chartVersion; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking cache for " << "InfoChartCapabilities" << m_chartVersion; emit getCachedInfo( criteria, 864000000, requestData ); } @@ -222,8 +237,10 @@ ChartsPlugin::chartSourcesList() m_chartResources.clear(); foreach(const QVariant &source, sources) { m_chartResources << source.toString(); - } + } + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "storing sources in cache" << m_chartResources; + TomahawkUtils::Cache::instance()->putData( "ChartsPlugin", 172800000 /* 2 days */, "chart_sources", m_chartResources ); fetchAllChartSources(); } } @@ -457,6 +474,7 @@ ChartsPlugin::chartsList() { emit info( request, m_allChartsMap ); // update cache + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Updating cache with " << m_allChartsMap.size() << "charts"; Tomahawk::InfoSystem::InfoStringHash criteria; criteria[ "InfoChartCapabilities" ] = "chartsplugin"; criteria[ "InfoChartVersion" ] = m_chartVersion; diff --git a/src/libtomahawk/infosystem/infosystemcache.h b/src/libtomahawk/infosystem/infosystemcache.h index aa2544816..591f21efb 100644 --- a/src/libtomahawk/infosystem/infosystemcache.h +++ b/src/libtomahawk/infosystem/infosystemcache.h @@ -58,7 +58,7 @@ private: void doUpgrade( uint oldVersion, uint newVersion ); void performWipe( QString directory ); const QString criteriaMd5( const Tomahawk::InfoSystem::InfoStringHash &criteria, Tomahawk::InfoSystem::InfoType type = Tomahawk::InfoSystem::InfoNoInfo ) const; - + QString m_cacheBaseDir; QHash< InfoType, QHash< QString, QString > > m_fileLocationCache; QTimer m_pruneTimer; From 0cf9a26004443045014047b334b122746e6bda6c Mon Sep 17 00:00:00 2001 From: Casey Link Date: Fri, 13 Apr 2012 16:15:44 -0500 Subject: [PATCH 34/36] If we can't retrieve source list from cache, re-fetch. --- .../infosystem/infoplugins/generic/chartsplugin.cpp | 11 ++++++++--- .../infosystem/infoplugins/generic/chartsplugin.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp index 855b7071a..56e005997 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp @@ -56,6 +56,8 @@ ChartsPlugin::ChartsPlugin() } tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "total sources" << m_chartResources.size() << source_qvarlist.size(); + if( m_chartResources.size() == 0 ) + fetchChartSourcesList( true ); m_supportedGetTypes << InfoChart << InfoChartCapabilities; } @@ -189,7 +191,7 @@ ChartsPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSy case InfoChartCapabilities: { tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching..."; - fetchChartSourcesList(); + fetchChartSourcesList( false ); m_cachedRequests.append( requestData ); return; @@ -205,10 +207,12 @@ ChartsPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSy } void -ChartsPlugin::fetchChartSourcesList() +ChartsPlugin::fetchChartSourcesList( bool fetchOnlySourceList ) { QUrl url = QUrl( QString( CHART_URL "charts" ) ); QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); + reply->setProperty( "only_source_list", fetchOnlySourceList ); + tDebug() << "fetching:" << url; connect( reply, SIGNAL( finished() ), SLOT( chartSourcesList() ) ); @@ -241,7 +245,8 @@ ChartsPlugin::chartSourcesList() } tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "storing sources in cache" << m_chartResources; TomahawkUtils::Cache::instance()->putData( "ChartsPlugin", 172800000 /* 2 days */, "chart_sources", m_chartResources ); - fetchAllChartSources(); + if( !reply->property("only_source_list" ).toBool() ) + fetchAllChartSources(); } } diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h index 8ac140854..352ac2a3a 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h @@ -81,7 +81,7 @@ private: * Fetch list of chart sources (e.g., itunes, billboard) * Populates the m_chartResources member. */ - void fetchChartSourcesList(); + void fetchChartSourcesList( bool fetchOnlySourceList ); /** * Requests charts list for each chart source in m_chartResources */ From a54279703846d27a10fac5910218e245821468bd Mon Sep 17 00:00:00 2001 From: Casey Link Date: Fri, 13 Apr 2012 16:21:39 -0500 Subject: [PATCH 35/36] Fix NewReleases loading bug by using the new generic cache --- .../infoplugins/generic/newreleasesplugin.cpp | 21 +++++++++++++++---- .../infoplugins/generic/newreleasesplugin.h | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp index d0b2df69e..0a4cb9338 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.cpp @@ -12,6 +12,7 @@ #include "tomahawksettings.h" #include "utils/tomahawkutils.h" #include "utils/logger.h" +#include "utils/tomahawkcache.h" #include #include @@ -27,6 +28,15 @@ NewReleasesPlugin::NewReleasesPlugin() { m_nrVersion = "0"; m_supportedGetTypes << InfoNewReleaseCapabilities << InfoNewRelease; + QVariantList source_qvarlist = TomahawkUtils::Cache::instance()->getData( "NewReleasesPlugin", "nr_sources" ).toList(); + foreach( const QVariant & source, source_qvarlist ) { + m_nrSources.append( source.toString() ); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "fetched source from cache" << source.toString(); + + } + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "total sources" << m_nrSources.size() << source_qvarlist.size(); + if( m_nrSources.size() == 0 ) + fetchNRSourcesList( true ); } NewReleasesPlugin::~NewReleasesPlugin() @@ -129,7 +139,7 @@ void NewReleasesPlugin::notInCacheSlot ( InfoStringHash criteria, InfoRequestDat case InfoNewReleaseCapabilities: { tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching..."; - fetchNRSourcesList(); + fetchNRSourcesList( false ); m_cachedRequests.append ( requestData ); return; @@ -143,10 +153,12 @@ void NewReleasesPlugin::notInCacheSlot ( InfoStringHash criteria, InfoRequestDat } } -void NewReleasesPlugin::fetchNRSourcesList() +void NewReleasesPlugin::fetchNRSourcesList( bool fetchOnlySourcesList ) { QUrl url = QUrl ( QString ( CHART_URL "newreleases" ) ); QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) ); + reply->setProperty( "only_source_list", fetchOnlySourcesList ); + tDebug() << "fetching:" << url; connect ( reply, SIGNAL ( finished() ), SLOT ( nrSourcesList() ) ); @@ -173,8 +185,9 @@ void NewReleasesPlugin::nrSourcesList() foreach ( const QVariant &source, sources ) { m_nrSources << source.toString(); } - - fetchAllNRSources(); + TomahawkUtils::Cache::instance()->putData( "NewReleasesPlugin", 172800000 /* 2 days */, "nr_sources", m_nrSources ); + if( !reply->property( "only_source_list" ).toBool() ) + fetchAllNRSources(); } } diff --git a/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h index de17b8fca..7fcedbddc 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/generic/newreleasesplugin.h @@ -69,7 +69,7 @@ private: * Fetch list of newlreeases sources (e.g., rovi) * Populates the m_nrSources member. */ - void fetchNRSourcesList(); + void fetchNRSourcesList( bool fetchOnlySourcesList ); /** * Requests newrelease list for each source in m_chartSources */ From ba064206c40abc8b8944b659059b6abeb92bd2a8 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Fri, 13 Apr 2012 22:16:23 +0000 Subject: [PATCH 36/36] Automatic merge of Transifex translations --- lang/tomahawk_bg.ts | 12 ++-- lang/tomahawk_de.ts | 12 ++-- lang/tomahawk_en.ts | 12 ++-- lang/tomahawk_es.ts | 12 ++-- lang/tomahawk_fr.ts | 12 ++-- lang/tomahawk_ja.ts | 12 ++-- lang/tomahawk_pl.ts | 124 ++++++++++++++++++++--------------------- lang/tomahawk_pt_BR.ts | 12 ++-- lang/tomahawk_ru.ts | 12 ++-- lang/tomahawk_sv.ts | 12 ++-- 10 files changed, 116 insertions(+), 116 deletions(-) diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 174187328..84556d15f 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -2331,22 +2331,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Най-известни - + Artists Артисти - + Albums Албуми - + Tracks Песни @@ -2395,7 +2395,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2557,7 +2557,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моята колекция diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index e30ff51a8..0fad17e4e 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -2322,22 +2322,22 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Allgemein - + Artists Künstler - + Albums Alben - + Tracks Stücke @@ -2386,7 +2386,7 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2548,7 +2548,7 @@ Versuch die Filter anzupassen für neue Lieder. TomahawkApp - + My Collection Meine Sammlung diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 4b53ebf36..3eaf7eaea 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -2329,22 +2329,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Overall - + Artists Artists - + Albums Albums - + Tracks Tracks @@ -2393,7 +2393,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albums @@ -2555,7 +2555,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection My Collection diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index d6e866f35..bf8599e69 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -2321,22 +2321,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top total - + Artists Artistas - + Albums Álbumes - + Tracks Pistas @@ -2385,7 +2385,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2547,7 +2547,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Mi colección diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 6defd655c..2912e70ee 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -2322,22 +2322,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums Albums - + Tracks Pistes @@ -2386,7 +2386,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2548,7 +2548,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Ma Collection diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 3aef4578b..f35372285 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -2318,22 +2318,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums - + Tracks @@ -2382,7 +2382,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2544,7 +2544,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index f2053ca42..bfc1a3ab8 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -34,7 +34,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Description goes here - + Tutaj pojawi się opis @@ -75,7 +75,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have &Follow in real-time - + &Podążaj na bieżąco @@ -687,7 +687,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have New Releases - + Nowe Wydania @@ -718,7 +718,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have added %1 - + dodano %1 @@ -1021,12 +1021,12 @@ Remember: Only allow peers to connect if you trust who they are and if you have All - + Wszystkie Services - + Usługi @@ -1072,17 +1072,17 @@ Remember: Only allow peers to connect if you trust who they are and if you have Facebook - + Facebook Twitter - + Twitter Cover - + Okładka @@ -1102,7 +1102,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have %1 characters left - + pozostało znaków: %1 @@ -1198,12 +1198,12 @@ Remember: Only allow peers to connect if you trust who they are and if you have Collection - + Kolekcja Latest Additions - + Ostatnio Dodane @@ -1254,7 +1254,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Group - + Grupa @@ -1279,7 +1279,7 @@ Remember: Only allow peers to connect if you trust who they are and if you have Browse - + Przeglądaj @@ -1309,22 +1309,22 @@ Remember: Only allow peers to connect if you trust who they are and if you have Recently Played - + Ostatnio Odtworzone Charts - + Listy Przebojów New Releases - + Nowe Wydania Friends - + Znajomi @@ -1490,7 +1490,7 @@ indywidualnego profilu gustu. %1 downloads - + pobrań: %1 @@ -1513,7 +1513,7 @@ indywidualnego profilu gustu. Configure this Google Account - + Konfiguruj to Konto Google @@ -1549,7 +1549,7 @@ indywidualnego profilu gustu. Enter Google Address: - + Podaj Adres Google @@ -1718,7 +1718,7 @@ You may wish to try re-authenticating. Your message has been posted! - + Twoja wiadomość została wysłana! @@ -1755,7 +1755,7 @@ You may wish to try re-authenticating. &Love - + &Uwielbiam @@ -1785,12 +1785,12 @@ You may wish to try re-authenticating. &Continue Playback after this Track - + &Kontynuuj odtwarzanie po tym utworze &Stop Playback after this Track - + &Zatrzymaj odtwarzanie po tym utworze @@ -1888,7 +1888,7 @@ Proszę zmienić filtry lub spróbować ponownie. Add some filters above to seed this station! - Dodaj powyzej trochę filtrów, a Tomahawk utworzy stację z podobną muzyką! + Dodaj powyżej trochę filtrów, a Tomahawk utworzy stację z podobną muzyką! @@ -2322,22 +2322,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Wszechczasów - + Artists Artyści - + Albums Albumy - + Tracks Utwory @@ -2352,7 +2352,7 @@ Try tweaking the filters for a new set of songs to play. on "%1" - + z "%1" @@ -2386,9 +2386,9 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums - + Albumy @@ -2454,7 +2454,7 @@ Try tweaking the filters for a new set of songs to play. and - + i @@ -2469,12 +2469,12 @@ Try tweaking the filters for a new set of songs to play. and - + i %n other(s) - + %n inny%n inne%n innych @@ -2548,7 +2548,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Moja Kolekcja @@ -2883,7 +2883,7 @@ wprowadź pokazany numer PIN tutaj: Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - + Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Podziękowania dla: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter oraz Steve Robertson @@ -3022,7 +3022,7 @@ wprowadź pokazany numer PIN tutaj: Composer - + Kompozytor @@ -3094,7 +3094,7 @@ wprowadź pokazany numer PIN tutaj: Composer - + Kompozytor @@ -3152,9 +3152,9 @@ You can re-send a sync message at any time simply by sending another tweet using Jeśli chcesz jedynie wysyłać tweety, wszystko gotowe. -Jeśli chcesz, aby Tomahawk łączył się z twoimi znajomymi używając Twittera, wybierz rodzaj tweeta i naciśnij przycisk poniżej by wysłać wiadomość synchronizacyjną. Obie strony muszą śledzić się nawzajem, ponieważ używane są Wiadomości Prywatne. Miej (dużo) cierpliwość - może to zająć kilka minut! +Jeśli chcesz, aby Tomahawk łączył się z twoimi znajomymi używając Twittera, wybierz rodzaj tweeta i naciśnij przycisk poniżej by wysłać wiadomość synchronizacyjną. Obie strony muszą śledzić się nawzajem, ponieważ używane są Wiadomości Prywatne. Miej (bardzo) dużo cierpliwości - może to zająć kilka minut! -Możesz kiedykolwiek, ponownie wysłać wiadomość synchronizacyjną - po prostu wyślij kolejnego tweeta używając przycisku. +Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyślij kolejnego tweeta używając przycisku. @@ -3192,7 +3192,7 @@ Możesz kiedykolwiek, ponownie wysłać wiadomość synchronizacyjną - po prost SuperCollection - + SuperKolekcja @@ -3425,12 +3425,12 @@ Tekst dla "%1" wykonawcy %2: e.g. user@example.com - + n.p. uzytkownik@example.com Password: - + Hasło: @@ -3445,12 +3445,12 @@ Tekst dla "%1" wykonawcy %2: Server: - + Serwer: Port: - + Port: @@ -3465,7 +3465,7 @@ Tekst dla "%1" wykonawcy %2: Enforce secure connection - + Wymuś bezpieczne połączenie @@ -3478,7 +3478,7 @@ Tekst dla "%1" wykonawcy %2: Host is unknown - + Nieznany Host @@ -3498,52 +3498,52 @@ Tekst dla "%1" wykonawcy %2: Remote Connection failed - + Połączenie sieciowe się nie powiodło Internal Server Error - + Wewnętrzny błąd serwera System shutdown - + Wyłączenie systemu Conflict - + Konflikt Unknown - + Nieznany No Compression Support - + Brak obsługi kompresji No Encryption Support - + Brak obsługi szyfrowania No Authorization Support - + Brak obsługi autoryzacji No Supported Feature - + Brak obsługi danej funkcji Add Friend - + Dodaj Znajomego @@ -3553,12 +3553,12 @@ Tekst dla "%1" wykonawcy %2: Add Friend... - + Dodaj Znajomego... XML Console... - + Konsola XML... @@ -3568,7 +3568,7 @@ Tekst dla "%1" wykonawcy %2: Authorize User - + Autoryzuj Użytkownika diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index b884a0885..d5dec97d5 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -2321,22 +2321,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Classificação geral - + Artists Artistas - + Albums Álbuns - + Tracks Faixas @@ -2385,7 +2385,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2547,7 +2547,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Minha biblioteca diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index a866d0e1f..f3a580596 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -2318,22 +2318,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists Исполнители - + Albums Альбомы - + Tracks Песни @@ -2382,7 +2382,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2544,7 +2544,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моя коллекция diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 064b9d6fb..e1e3bddea 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -2319,22 +2319,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists Artister - + Albums Album - + Tracks Spår @@ -2383,7 +2383,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2545,7 +2545,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection