File indexing completed on 2024-05-19 04:50:22
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org> * 0003 * Copyright (c) 2008 Casey Link <unnamedrambler@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) any later * 0008 * version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along with * 0015 * this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************************/ 0017 0018 #define DEBUG_PREFIX "Mp3tunesService" 0019 0020 #include "Mp3tunesService.h" 0021 0022 #include "browsers/SingleCollectionTreeItemModel.h" 0023 #include "core-impl/collections/support/CollectionManager.h" 0024 #include "core/logger/Logger.h" 0025 #include "core/support/Components.h" 0026 #include "core/support/Debug.h" 0027 #include "Mp3tunesConfig.h" 0028 0029 #include <QMenuBar> 0030 #include <QRegExp> 0031 0032 #include <KMessageBox> 0033 #include <ThreadWeaver/ThreadWeaver> 0034 #include <ThreadWeaver/Queue> 0035 0036 0037 Mp3tunesServiceFactory::Mp3tunesServiceFactory() 0038 : ServiceFactory() 0039 {} 0040 0041 void Mp3tunesServiceFactory::init() 0042 { 0043 DEBUG_BLOCK 0044 ServiceBase *service = createService(); 0045 if( service ) 0046 { 0047 m_initialized = true; 0048 emit newService( service ); 0049 } 0050 } 0051 0052 ServiceBase* Mp3tunesServiceFactory::createService() 0053 { 0054 Mp3tunesConfig config; 0055 //The user activated the service, but didn't fill the email/password? Don't start it. 0056 // if( config.email().isEmpty() || config.password().isEmpty() ) 0057 // return 0; 0058 ServiceBase* service = new Mp3tunesService( this, "MP3tunes.com", config.partnerToken(), config.email(), config.password(), config.harmonyEnabled() ); 0059 return service; 0060 } 0061 0062 QString Mp3tunesServiceFactory::name() 0063 { 0064 return "MP3tunes.com"; 0065 } 0066 0067 KConfigGroup Mp3tunesServiceFactory::config() 0068 { 0069 return Amarok::config( "Service_Mp3tunes" ); 0070 } 0071 0072 0073 bool 0074 Mp3tunesServiceFactory::possiblyContainsTrack(const QUrl &url) const 0075 { 0076 QRegExp rx( "http://content.mp3tunes.com/storage/locker(?:get|play)/(.*)\\?(?:sid|partner_token)=.*" ) ; 0077 int matches = rx.indexIn( url.url() ); 0078 if( matches == -1 ) { 0079 return false; // not a mp3tunes url 0080 } 0081 QStringList list = rx.capturedTexts(); 0082 QString filekey = list.value( 1 ); // Because list[0] is the url itself. 0083 if ( filekey.isEmpty() ) { 0084 return false; 0085 } 0086 return true; // for now: if it's a mp3tunes url.. it's likely the track is in the locker 0087 } 0088 0089 0090 Mp3tunesService::Mp3tunesService( Mp3tunesServiceFactory* parent, const QString & name, const QString &token, const QString &email, const QString &password, bool harmonyEnabled ) 0091 : ServiceBase( name, parent ) 0092 , m_email( email ) 0093 , m_password( password ) 0094 , m_harmonyEnabled( harmonyEnabled ) 0095 , m_partnerToken( token ) 0096 , m_authenticated( false ) 0097 , m_authenticationFailed( false ) 0098 , m_sessionId ( QString() ) 0099 , m_collection( 0 ) 0100 , m_loginWorker( 0 ) 0101 , m_harmony( 0 ) 0102 { 0103 DEBUG_BLOCK 0104 setShortDescription( i18n( "The MP3tunes Locker: Your Music Everywhere!" ) ); 0105 setIcon( QIcon::fromTheme( "view-services-mp3tunes-amarok" ) ); 0106 debug() << "Making new Locker Object"; 0107 m_locker = new Mp3tunesLocker( "4895500420" ); 0108 0109 debug() << "MP3tunes running automated authenticate. email: " << email << " pass: " << password; 0110 authenticate( email, password ); 0111 0112 if( m_harmonyEnabled ) { 0113 enableHarmony(); 0114 } 0115 0116 polish(); 0117 } 0118 0119 0120 Mp3tunesService::~Mp3tunesService() 0121 { 0122 0123 delete m_locker; 0124 // delete m_daemon; 0125 if( m_collection ) { 0126 CollectionManager::instance()->removeTrackProvider( m_collection ); 0127 delete m_collection; 0128 } 0129 } 0130 0131 0132 void Mp3tunesService::polish() 0133 { 0134 initTopPanel(); 0135 initBottomPanel(); 0136 0137 if ( !m_authenticated && !m_authenticationFailed ) 0138 authenticate( m_email, m_password ); 0139 } 0140 0141 void Mp3tunesService::initTopPanel() 0142 { 0143 m_menubar->clear(); 0144 //Disable this menu bar until liblastfm is improved, and this feature can 0145 //be implemented correctly. 0146 /*QMenu * actionsMenu = m_menubar->addMenu( i18n( "AutoSync" ) ); 0147 if( m_harmonyEnabled ) 0148 { 0149 QAction * action = new QAction( i18n( "Disable AutoSync" ), m_menubar ); 0150 connect( action, SIGNAL(triggered(bool)), SLOT(disableHarmony()) ); 0151 actionsMenu->addAction( action ); 0152 } else { 0153 QAction * action = new QAction( i18n( "Enable AutoSync" ), m_menubar ); 0154 connect( action, SIGNAL(triggered(bool)), SLOT(enableHarmony()) ); 0155 actionsMenu->addAction( action ); 0156 } 0157 0158 m_menubar->show();*/ 0159 } 0160 0161 void Mp3tunesService::initBottomPanel() 0162 { 0163 m_bottomPanel->hide(); 0164 } 0165 0166 void Mp3tunesService::enableHarmony() 0167 { 0168 DEBUG_BLOCK 0169 0170 if( !m_harmony ) 0171 { 0172 debug() << "Making new Daemon"; 0173 Mp3tunesConfig config; 0174 debug () << "Using identifier: " << config.identifier(); 0175 0176 if( config.pin().isEmpty() ) 0177 m_harmony = new Mp3tunesHarmonyHandler( config.identifier() ); //first time harmony login 0178 else 0179 m_harmony = new Mp3tunesHarmonyHandler( config.identifier(), //they're not harmony virgins 0180 config.email(), 0181 config.pin() ); 0182 // qRegisterMetaType<Mp3tunesHarmonyDownload>("Mp3tunesHarmonyDownload"); 0183 0184 connect( m_harmony, &Mp3tunesHarmonyHandler::disconnected, 0185 this, &Mp3tunesService::harmonyDisconnected ); 0186 connect( m_harmony, &Mp3tunesHarmonyHandler::waitingForEmail, 0187 this, &Mp3tunesService::harmonyWaitingForEmail ); 0188 connect( m_harmony, &Mp3tunesHarmonyHandler::waitingForPin, 0189 this, &Mp3tunesService::harmonyWaitingForPin ); 0190 connect( m_harmony, &Mp3tunesHarmonyHandler::connected, 0191 this, &Mp3tunesService::harmonyConnected ); 0192 connect( m_harmony, &Mp3tunesHarmonyHandler::signalError, 0193 this, &Mp3tunesService::harmonyError ); 0194 connect( m_harmony, &Mp3tunesHarmonyHandler::downloadReady, 0195 this, &Mp3tunesService::harmonyDownloadReady ); 0196 connect( m_harmony, &Mp3tunesHarmonyHandler::downloadPending, 0197 this, &Mp3tunesService::harmonyDownloadPending ); 0198 0199 debug() << "starting harmony"; 0200 m_harmony->startDaemon(); 0201 if( m_harmony->daemonRunning() ) 0202 { 0203 debug() << "harmony started.. making connection"; 0204 m_harmony->makeConnection(); 0205 } 0206 if( m_harmony->daemonConnected() ) 0207 debug() << "harmony connected"; 0208 else 0209 debug() << "harmony failed to connected"; 0210 0211 //Close your eyes. Cross your legs. Touch middle fingers to thumbs. Extend your arms. 0212 //OOOooommmmm 0213 } 0214 0215 debug() << "Daemon running"; 0216 m_harmonyEnabled = true; 0217 Amarok::Logger::shortMessage( i18n( "MP3tunes AutoSync Enabled" ) ); 0218 polish(); 0219 } 0220 0221 void Mp3tunesService::disableHarmony() 0222 { 0223 DEBUG_BLOCK 0224 if( !m_harmony ) 0225 return; 0226 0227 debug() << "stopping daemon"; 0228 m_harmony->stopDaemon(); 0229 m_harmony = 0; 0230 m_harmonyEnabled = false; 0231 polish(); 0232 0233 Amarok::Logger::shortMessage( i18n( "MP3tunes AutoSync Disabled" ) ); 0234 } 0235 0236 void Mp3tunesService::authenticate( const QString & uname, const QString & passwd ) 0237 { 0238 DEBUG_BLOCK 0239 if( m_loginWorker ) 0240 return; 0241 0242 if ( uname.isEmpty() || passwd.isEmpty() ) 0243 return; 0244 0245 m_loginWorker = new Mp3tunesLoginWorker( m_locker, uname, passwd); 0246 //debug() << "Connecting finishedLogin -> authentication complete."; 0247 0248 connect( m_loginWorker, &Mp3tunesLoginWorker::finishedLogin, 0249 this, &Mp3tunesService::authenticationComplete ); 0250 //debug() << "Connection complete. Enqueueing.."; 0251 ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(m_loginWorker) ); 0252 //debug() << "LoginWorker queue"; 0253 Amarok::Logger::shortMessage( i18n( "Authenticating" ) ); 0254 0255 } 0256 0257 0258 void Mp3tunesService::authenticationComplete( const QString & sessionId ) 0259 { 0260 DEBUG_BLOCK 0261 m_loginWorker = 0; 0262 debug() << "Authentication reply: " << sessionId; 0263 if ( sessionId.isEmpty() ) 0264 { 0265 QString error = i18n("MP3tunes failed to Authenticate."); 0266 if ( !m_locker->errorMessage().isEmpty() ) 0267 { 0268 error = m_locker->errorMessage(); // Not sure how to i18n this 0269 } 0270 Amarok::Logger::longMessage( error ); 0271 0272 setServiceReady( false ); 0273 m_authenticationFailed = true; 0274 } 0275 else 0276 { 0277 m_sessionId = sessionId; 0278 m_authenticated = true; 0279 0280 m_collection = new Collections::Mp3tunesServiceCollection( this, m_sessionId, m_locker ); 0281 CollectionManager::instance()->addTrackProvider( m_collection ); 0282 QList<CategoryId::CatMenuId> levels; 0283 levels << CategoryId::Artist << CategoryId::Album; 0284 setModel( new SingleCollectionTreeItemModel( m_collection, levels ) ); 0285 0286 setServiceReady( true ); 0287 } 0288 polish(); 0289 } 0290 0291 void Mp3tunesService::harmonyDisconnected() 0292 { 0293 DEBUG_BLOCK 0294 debug() << "Harmony Disconnected!"; 0295 Amarok::Logger::shortMessage( i18n( "MP3tunes Harmony: Disconnected" ) ); 0296 } 0297 0298 void Mp3tunesService::harmonyWaitingForEmail( const QString &pin ) 0299 { 0300 DEBUG_BLOCK 0301 debug() << "Waiting for user to input PIN: " << pin; 0302 Amarok::Logger::shortMessage( i18n( "MP3tunes Harmony: Waiting for PIN Input" ) ); 0303 KMessageBox::information( this, 0304 "Please go to <a href=\"http://www.mp3tunes.com/pin\">mp3tunes.com/pin</a> and enter the following pin.\n\tPIN: " + pin, 0305 "MP3tunes Harmony", 0306 QString(), 0307 KMessageBox::AllowLink ); 0308 } 0309 0310 void Mp3tunesService::harmonyWaitingForPin() 0311 { 0312 DEBUG_BLOCK 0313 QString pin = m_harmony->pin(); 0314 debug() << "Waiting for user to input PIN: " << pin; 0315 Amarok::Logger::shortMessage( i18n( "MP3tunes Harmony: Waiting for PIN Input" ) ); 0316 KMessageBox::information( this, 0317 "Please go to <a href=\"http://www.mp3tunes.com/pin\">mp3tunes.com/pin</a> and enter the following pin.\n\tPIN: " + pin, 0318 "MP3tunes Harmony", 0319 QString(), 0320 KMessageBox::AllowLink ); 0321 } 0322 0323 void Mp3tunesService::harmonyConnected() 0324 { 0325 DEBUG_BLOCK 0326 debug() << "Harmony Connected!"; 0327 Amarok::Logger::shortMessage( i18n( "MP3tunes Harmony: Successfully Connected" ) ); 0328 /* at this point since the user has input the pin, we will save the info 0329 for later authentication*/ 0330 Mp3tunesConfig config; 0331 debug() << "Setting Config email: " << m_harmony->email() << " pin: " << m_harmony->pin(); 0332 config.setHarmonyEmail( m_harmony->email() ); 0333 config.setPin( m_harmony->pin() ); 0334 config.save(); 0335 0336 } 0337 0338 void Mp3tunesService::harmonyError( const QString &error ) 0339 { 0340 DEBUG_BLOCK 0341 debug() << "Harmony Error: " << error; 0342 Amarok::Logger::longMessage( i18n( "MP3tunes Harmony Error\n%1", error ) ); 0343 } 0344 0345 void Mp3tunesService::harmonyDownloadReady( const QVariantMap &download ) 0346 { 0347 DEBUG_BLOCK 0348 debug() << "Got message about ready: " << download["trackTitle"] << " by " << download["artistName"] << " on " << download["albumTitle"]; 0349 foreach( Collections::Collection *coll, CollectionManager::instance()->collections().keys() ) 0350 { 0351 if( coll && coll->isWritable() && m_collection ) 0352 { 0353 debug() << "got collection" << coll->prettyName(); 0354 if ( coll->collectionId() == "localCollection") 0355 { //TODO Allow user to choose which collection to sync down to. 0356 debug() << "got local collection"; 0357 Collections::CollectionLocation *dest = coll->location(); 0358 Collections::CollectionLocation *source = m_collection->location(); 0359 if( !m_collection->possiblyContainsTrack( download["url"].toUrl() ) ) 0360 return; //TODO some sort of error handling 0361 Meta::TrackPtr track( m_collection->trackForUrl( download["url"].toUrl() ) ); 0362 source->prepareCopy( track, dest ); 0363 break; 0364 } 0365 0366 } 0367 } 0368 0369 } 0370 0371 void Mp3tunesService::harmonyDownloadPending( const QVariantMap &download ) 0372 { 0373 DEBUG_BLOCK 0374 debug() << "Got message about ready: " << download["trackTitle"] << " by " << download["artistName"] << " on " << download["albumTitle"]; 0375 }