|
|
|
// (c) 2004 Christian Muehlhaeuser <chris@chris.de>
|
|
|
|
// (c) 2004 Sami Nieminen <sami.nieminen@iki.fi>
|
|
|
|
// (c) 2006 Shane King <kde@dontletsstart.com>
|
|
|
|
// (c) 2006 Iain Benson <iain@arctos.me.uk>
|
|
|
|
// See COPYING file for licensing information
|
|
|
|
|
|
|
|
#ifndef AMAROK_SCROBBLER_H
|
|
|
|
#define AMAROK_SCROBBLER_H
|
|
|
|
|
|
|
|
#include "engineobserver.h"
|
|
|
|
#include <tqdom.h>
|
|
|
|
#include <tqobject.h>
|
|
|
|
#include <tqptrdict.h>
|
|
|
|
#include <tqptrlist.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
|
|
|
|
//some setups require this
|
|
|
|
#undef PROTOCOL_VERSION
|
|
|
|
|
|
|
|
namespace KIO { class Job; }
|
|
|
|
|
|
|
|
class TQStringList;
|
|
|
|
class SubmitItem;
|
|
|
|
class SubmitQueue;
|
|
|
|
class ScrobblerSubmitter;
|
|
|
|
|
|
|
|
class Scrobbler : public TQObject, public EngineObserver
|
|
|
|
{
|
|
|
|
friend class MediaDevice;
|
|
|
|
|
|
|
|
Q_OBJECT
|
|
|
|
TQ_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
static Scrobbler *instance();
|
|
|
|
|
|
|
|
void similarArtists( const TQString & /*artist*/ );
|
|
|
|
void applySettings();
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void similarArtistsFetched( const TQString& artist, const TQStringList& suggestions );
|
|
|
|
|
|
|
|
public slots:
|
|
|
|
void subTrack( long currentPos, long startPos, long endPos ); // cuefiles can update length without track change
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Scrobbler();
|
|
|
|
~Scrobbler();
|
|
|
|
|
|
|
|
void engineNewMetaData( const MetaBundle& /*bundle*/, bool /*state*/ );
|
|
|
|
void engineTrackPositionChanged( long /*position*/ , bool /*userSeek*/ );
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void audioScrobblerSimilarArtistsResult( KIO::Job* /*job*/ );
|
|
|
|
void audioScrobblerSimilarArtistsData(
|
|
|
|
KIO::Job* /*job*/, const TQByteArray& /*data*/ );
|
|
|
|
|
|
|
|
private:
|
|
|
|
TQTimer m_timer; //works around xine bug
|
|
|
|
//http://sourceforge.net/tracker/index.php?func=detail&aid=1401026&group_id=9655&atid=109655
|
|
|
|
TQByteArray m_similarArtistsBuffer;
|
|
|
|
KIO::Job* m_similarArtistsJob;
|
|
|
|
TQString m_artist;
|
|
|
|
bool m_validForSending;
|
|
|
|
long m_startPos;
|
|
|
|
ScrobblerSubmitter* m_submitter;
|
|
|
|
SubmitItem* m_item;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class SubmitItem
|
|
|
|
{
|
|
|
|
friend class ScrobblerSubmitter;
|
|
|
|
|
|
|
|
public:
|
|
|
|
SubmitItem(
|
|
|
|
const TQString& /*artist*/,
|
|
|
|
const TQString& /*album*/,
|
|
|
|
const TQString& /*title*/,
|
|
|
|
int /*length*/,
|
|
|
|
bool now = true );
|
|
|
|
SubmitItem( const TQDomElement& /* domElement */ );
|
|
|
|
SubmitItem();
|
|
|
|
|
|
|
|
bool operator==( const SubmitItem& item );
|
|
|
|
|
|
|
|
void setArtist( const TQString& artist ) { m_artist = artist; }
|
|
|
|
void setAlbum( const TQString& album ) { m_album = album; }
|
|
|
|
void setTitle( const TQString& title ) { m_title = title; }
|
|
|
|
const TQString artist() const { return m_artist; }
|
|
|
|
const TQString album() const { return m_album; }
|
|
|
|
const TQString title() const { return m_title; }
|
|
|
|
int length() const { return m_length; }
|
|
|
|
uint playStartTime() const { return m_playStartTime; }
|
|
|
|
|
|
|
|
TQDomElement toDomElement( TQDomDocument& /* document */ ) const;
|
|
|
|
|
|
|
|
bool valid() const { return !m_artist.isEmpty() && !m_title.isEmpty() && m_length >= 30; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
TQString m_artist;
|
|
|
|
TQString m_album;
|
|
|
|
TQString m_title;
|
|
|
|
int m_length;
|
|
|
|
uint m_playStartTime;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class SubmitQueue : public TQPtrList<SubmitItem>
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
int compareItems( TQPtrCollection::Item item1, TQPtrCollection::Item item2 );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class ScrobblerSubmitter : public TQObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
TQ_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
static TQString PROTOCOL_VERSION;
|
|
|
|
static TQString CLIENT_ID;
|
|
|
|
static TQString CLIENT_VERSION;
|
|
|
|
static TQString HANDSHAKE_URL;
|
|
|
|
|
|
|
|
ScrobblerSubmitter();
|
|
|
|
~ScrobblerSubmitter();
|
|
|
|
|
|
|
|
void submitItem( SubmitItem* /* item */ );
|
|
|
|
|
|
|
|
void configure( const TQString& /*username*/, const TQString& /* password*/, bool /*enabled*/ );
|
|
|
|
|
|
|
|
void syncComplete();
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void scheduledTimeReached();
|
|
|
|
void audioScrobblerHandshakeResult( KIO::Job* /*job*/ );
|
|
|
|
void audioScrobblerSubmitResult( KIO::Job* /*job*/ );
|
|
|
|
void audioScrobblerSubmitData(
|
|
|
|
KIO::Job* /*job*/, const TQByteArray& /*data*/ );
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool canSubmit() const;
|
|
|
|
void enqueueItem( SubmitItem* /* item */ );
|
|
|
|
SubmitItem* dequeueItem();
|
|
|
|
void enqueueJob( KIO::Job* /* job */ );
|
|
|
|
void finishJob( KIO::Job* /* job */ );
|
|
|
|
void announceSubmit(
|
|
|
|
SubmitItem* /* item */, int /* tracks */, bool /* success */ ) const;
|
|
|
|
void saveSubmitQueue();
|
|
|
|
void readSubmitQueue();
|
|
|
|
bool schedule( bool failure );
|
|
|
|
void performHandshake();
|
|
|
|
void performSubmit();
|
|
|
|
|
|
|
|
// on failure, start at MIN_BACKOFF, and double on subsequent failures
|
|
|
|
// until MAX_BACKOFF is reached
|
|
|
|
static const int MIN_BACKOFF = 60;
|
|
|
|
static const int MAX_BACKOFF = 60 * 60;
|
|
|
|
|
|
|
|
TQString m_submitResultBuffer;
|
|
|
|
TQString m_username;
|
|
|
|
TQString m_password;
|
|
|
|
TQString m_submitUrl;
|
|
|
|
TQString m_challenge;
|
|
|
|
TQString m_savePath;
|
|
|
|
bool m_scrobblerEnabled;
|
|
|
|
bool m_holdFakeQueue;
|
|
|
|
bool m_inProgress;
|
|
|
|
bool m_needHandshake;
|
|
|
|
uint m_prevSubmitTime;
|
|
|
|
uint m_interval;
|
|
|
|
uint m_backoff;
|
|
|
|
uint m_lastSubmissionFinishTime;
|
|
|
|
uint m_fakeQueueLength;
|
|
|
|
|
|
|
|
TQPtrDict<SubmitItem> m_ongoingSubmits;
|
|
|
|
SubmitQueue m_submitQueue; // songs played by Amarok
|
|
|
|
SubmitQueue m_fakeQueue; // songs for which play times have to be faked (e.g. when submitting from media device)
|
|
|
|
|
|
|
|
TQTimer m_timer;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* AMAROK_SCROBBLER_H */
|