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 }