/** * Performs handshake with Audioscrobbler. */ void ScrobblerSubmitter::performHandshake() { QString handshakeUrl = QString::null; uint currentTime = QDateTime::currentDateTime( Qt::UTC ).toTime_t(); if ( PROTOCOL_VERSION == "1.1" ) { // Audioscrobbler protocol 1.1 (current) // http://post.audioscrobbler.com/?hs=true // &p=1.1 // &c=<clientid> // &v=<clientver> // &u=<user> handshakeUrl = HANDSHAKE_URL + QString( "&p=%1" "&c=%2" "&v=%3" "&u=%4" ) .arg( PROTOCOL_VERSION ) .arg( CLIENT_ID ) .arg( CLIENT_VERSION ) .arg( m_username ); } else if ( PROTOCOL_VERSION == "1.2" ) { // Audioscrobbler protocol 1.2 (RFC) // http://post.audioscrobbler.com/?hs=true // &p=1.2 // &c=<clientid> // &v=<clientversion> // &u=<username> // &t=<unix_timestamp> // &a=<passcode> handshakeUrl = HANDSHAKE_URL + QString( "&p=%1" "&c=%2" "&v=%3" "&u=%4" "&t=%5" "&a=%6" ) .arg( PROTOCOL_VERSION ) .arg( CLIENT_ID ) .arg( CLIENT_VERSION ) .arg( m_username ) .arg( currentTime ) .arg( KMD5( KMD5( m_password.utf8() ).hexDigest() + currentTime ).hexDigest() ); } else { debug() << "Handshake not implemented for protocol version: " << PROTOCOL_VERSION << endl; return; } debug() << "Handshake url: " << handshakeUrl << endl; m_submitResultBuffer = ""; m_inProgress = true; KIO::TransferJob* job = KIO::storedGet( handshakeUrl, false, false ); connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( audioScrobblerHandshakeResult( KIO::Job* ) ) ); }
/** * Flushes the submit queues */ void ScrobblerSubmitter::performSubmit() { QString data; // Audioscrobbler accepts max 10 tracks on one submit. SubmitItem* items[10]; for ( int submitCounter = 0; submitCounter < 10; submitCounter++ ) items[submitCounter] = 0; if ( PROTOCOL_VERSION == "1.1" ) { // Audioscrobbler protocol 1.1 (current) // http://post.audioscrobbler.com/v1.1-lite.php // u=<user> // &s=<MD5 response>& // a[0]=<artist 0>&t[0]=<track 0>&b[0]=<album 0>& // m[0]=<mbid 0>&l[0]=<length 0>&i[0]=<time 0>& // a[1]=<artist 1>&t[1]=<track 1>&b[1]=<album 1>& // m[1]=<mbid 1>&l[1]=<length 1>&i[1]=<time 1>& // ... // a[n]=<artist n>&t[n]=<track n>&b[n]=<album n>& // m[n]=<mbid n>&l[n]=<length n>&i[n]=<time n>& data = "u=" + KURL::encode_string_no_slash( m_username ) + "&s=" + KURL::encode_string_no_slash( KMD5( KMD5( m_password.utf8() ).hexDigest() + m_challenge.utf8() ).hexDigest() ); m_submitQueue.first(); for ( int submitCounter = 0; submitCounter < 10; submitCounter++ ) { SubmitItem* itemFromQueue = dequeueItem(); if ( itemFromQueue == 0 ) { if( submitCounter == 0 ) { // this shouldn't happen, since we shouldn't be scheduled until we have something to do! debug() << "Nothing to submit!" << endl; return; } else { break; } } else data += '&'; items[submitCounter] = itemFromQueue; QDateTime playStartTime = QDateTime(); playStartTime.setTime_t( itemFromQueue->playStartTime() ); const QString count = QString::number( submitCounter ); data += "a[" + count + "]=" + KURL::encode_string_no_slash( itemFromQueue->artist(), 106 /*utf-8*/ ) + "&t[" + count + "]=" + KURL::encode_string_no_slash( itemFromQueue->title(), 106 /*utf-8*/ ) + "&b[" + count + "]=" + KURL::encode_string_no_slash( itemFromQueue->album(), 106 /*utf-8*/ ) + "&m[" + count + "]=" + "&l[" + count + "]=" + QString::number( itemFromQueue->length() ) + "&i[" + count + "]=" + KURL::encode_string_no_slash( playStartTime.toString( "yyyy-MM-dd hh:mm:ss" ) ); } } else { debug() << "Submit not implemented for protocol version: " << PROTOCOL_VERSION << endl; return; } debug() << "Submit data: " << data << endl; m_submitResultBuffer = ""; m_inProgress = true; KIO::TransferJob* job = KIO::http_post( m_submitUrl, data.utf8(), false ); job->addMetaData( "content-type", "Content-Type: application/x-www-form-urlencoded" ); // Loop in reverse order, which helps when items are later fetched from // m_ongoingSubmits and possibly put back to queue, in correct order // (i.e. oldest first). for ( int submitCounter = 9; submitCounter >= 0; submitCounter-- ) if ( items[submitCounter] != 0 ) m_ongoingSubmits.insert( job, items[submitCounter] ); Amarok::StatusBar::instance()->newProgressOperation( job ) .setDescription( i18n( "Submitting to last.fm" ) ); connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( audioScrobblerSubmitResult( KIO::Job* ) ) ); connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), this, SLOT( audioScrobblerSubmitData( KIO::Job*, const QByteArray& ) ) ); }
static QString md5(const QByteArray &data) { return KMD5(data).hexDigest(); }