summaryrefslogtreecommitdiffstats
path: root/amarok/src/scrobbler.h
blob: eaa038b7cdaba1115c7d9527aa2132634c49d608 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// (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 TDEIO { class Job; }

class TQStringList;
class SubmitItem;
class SubmitQueue;
class ScrobblerSubmitter;

class Scrobbler : public TQObject, public EngineObserver
{
    friend class MediaDevice;

    Q_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( TDEIO::Job* /*job*/ );
        void audioScrobblerSimilarArtistsData(
            TDEIO::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;
        TDEIO::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
  

    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( TDEIO::Job* /*job*/ );
        void audioScrobblerSubmitResult( TDEIO::Job* /*job*/ );
        void audioScrobblerSubmitData(
            TDEIO::Job* /*job*/, const TQByteArray& /*data*/ );

    private:
        bool canSubmit() const;
        void enqueueItem( SubmitItem* /* item */ );
        SubmitItem* dequeueItem();
        void enqueueJob( TDEIO::Job* /* job */ );
        void finishJob( TDEIO::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 */