~ubuntu-branches/debian/sid/ampache/sid

« back to all changes in this revision

Viewing changes to lib/class/scrobbler.class.php

  • Committer: Package Import Robot
  • Author(s): Charlie Smotherman
  • Date: 2013-08-27 13:19:48 UTC
  • mfrom: (1.2.9)
  • Revision ID: package-import@ubuntu.com-20130827131948-1czew0zxn6u70dtv
Tags: 3.6-rzb2752+dfsg-1
* New upsteam snapshot.  Contains important bug fixes to the installer.
* Correct typo in ampache-common.postrm.
* Remove courtousy copy of php-getid3, during repack.  Closes: #701526
* Update package to use dh_linktree to make the needed sym links to the
  needed system libs that were removed during repack.
* Update debian/rules to reflect upstreams removing/moving of modules.
* Update debian/ampache-common.install to reflect upstreams removal of files.
* Updated to use new apache2.4 API. Closes: #669756
* Updated /debian/po/de.po thx David Prévot for the patch.  Closes:  #691963
* M3U import is now ordered, fixed upstream.  Closes: #684984
* Text input area has been resized so IPv6 addresses will now fit, fixed
  upstream.  Closes:  #716230
* Added ampache-common.preinst to make sure that the courtousy copies of code
  dirs are empty so dh_linktree can do it's magic on upgrades.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
<?php
2
 
/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */
 
2
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
3
3
/**
4
 
 * scrobbler Class
5
 
 *
6
4
 *
7
5
 * LICENSE: GNU General Public License, version 2 (GPLv2)
8
 
 * Copyright (c) 2001 - 2011 Ampache.org All Rights Reserved
 
6
 * Copyright 2001 - 2013 Ampache.org
9
7
 *
10
8
 * This program is free software; you can redistribute it and/or
11
9
 * modify it under the terms of the GNU General Public License v2
20
18
 * along with this program; if not, write to the Free Software
21
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
20
 *
23
 
 * @package     Ampache
24
 
 * @copyright   2001 - 2011 Ampache.org
25
 
 * @license     http://opensource.org/licenses/gpl-2.0 GPLv2
26
 
 * @link        http://www.ampache.org/
27
21
 */
28
22
 
29
 
/**
30
 
 * scrobbler Class
31
 
 *
32
 
 * Description here...
33
 
 *
34
 
 * @package     Ampache
35
 
 * @copyright   2001 - 2011 Ampache.org
36
 
 * @license     http://opensource.org/licenses/gpl-2.0 GPLv2
37
 
 * @link        http://www.ampache.org/
38
 
 */
39
23
class scrobbler {
40
24
 
41
 
        public $error_msg;
42
 
        public $username;
43
 
        public $password;
44
 
        public $challenge;
45
 
        public $submit_host;
46
 
        public $submit_port;
47
 
        public $submit_url;
48
 
        public $queued_tracks;
49
 
        public $reset_handshake = false;
50
 
        public $scrobble_host = 'post.audioscrobbler.com';
51
 
 
52
 
        /**
53
 
         * Constructor
54
 
         * This is the constructer it takes a username and password
55
 
         */
56
 
        public function __construct($username, $password,$host='',$port='',$url='',$challenge='',$scrobble_host='') {
57
 
 
58
 
                $this->error_msg = '';
59
 
                $this->username = trim($username);
60
 
                $this->password = trim($password);
61
 
                $this->challenge = $challenge;
62
 
                $this->submit_host = $host;
63
 
                $this->submit_port = $port;
64
 
                $this->submit_url = $url;
65
 
                $this->queued_tracks = array();
66
 
                if ($scrobble_host) { $this->scrobble_host = $scrobble_host; }
67
 
 
68
 
        } // scrobbler
69
 
 
70
 
        /**
71
 
         * get_error_msg
72
 
         */
73
 
        public function get_error_msg() {
74
 
 
75
 
                return $this->error_msg;
76
 
 
77
 
        } // get_error_msg
78
 
 
79
 
        /**
80
 
         * get_queue_count
81
 
         */
82
 
        public function get_queue_count() {
83
 
 
84
 
                return count($this->queued_tracks);
85
 
 
86
 
        } // get_queue_count
87
 
 
88
 
        /**
89
 
         * handshake
90
 
         * This does a handshake with the audioscrobber server it doesn't pass the password, but
91
 
         * it does pass the username and has a 10 second timeout
92
 
         */
93
 
        public function handshake() {
94
 
 
95
 
                $as_socket = fsockopen($this->scrobble_host, 80, $errno, $errstr, 2);
96
 
                if(!$as_socket) {
97
 
                        $this->error_msg = $errstr;
98
 
                        return false;
99
 
                }
100
 
 
101
 
                $username       = rawurlencode($this->username);
102
 
                $timestamp      = time();
103
 
                $auth_token     = rawurlencode(md5($this->password . $timestamp));
104
 
 
105
 
                $get_string = "GET /?hs=true&p=1.2&c=apa&v=0.1&u=$username&t=$timestamp&a=$auth_token HTTP/1.1\r\n";
106
 
 
107
 
                fwrite($as_socket, $get_string);
108
 
                fwrite($as_socket, "Host: $this->scrobble_host\r\n");
109
 
                fwrite($as_socket, "Accept: */*\r\n\r\n");
110
 
 
111
 
                $buffer = '';
112
 
                while(!feof($as_socket)) {
113
 
                        $buffer .= fread($as_socket, 4096);
114
 
                }
115
 
                fclose($as_socket);
116
 
                $split_response = preg_split("/\r\n\r\n/", $buffer);
117
 
                if(!isset($split_response[1])) {
118
 
                        $this->error_msg = 'Did not receive a valid response';
119
 
                        return false;
120
 
                }
121
 
                $response = explode("\n", $split_response[1]);
122
 
 
123
 
                // Handle the fact Libre.FM has extranious values at the start of it's handshake response
124
 
                if(is_numeric(trim($response['0']))) { 
125
 
                        array_shift($response); 
126
 
                        debug_event('SCROBBLER','Junk in handshake, removing first line',1); 
127
 
                } 
128
 
                if(substr($response[0], 0, 6) == 'FAILED') {
129
 
                        $this->error_msg = substr($response[0], 7);
130
 
                        return false;
131
 
                }
132
 
                if(substr($response[0], 0, 7) == 'BADUSER') {
133
 
                        $this->error_msg = 'Invalid Username';
134
 
                        return false;
135
 
                }
136
 
                if(substr($response[0],0,7) == 'BADTIME') {
137
 
                        $this->error_msg = 'Your time is too far off from the server, or your PHP timezone is incorrect';
138
 
                        return false;
139
 
                }
140
 
                if(substr($response[0], 0, 6) == 'UPDATE') {
141
 
                        $this->error_msg = 'You need to update your client: '.substr($response[0], 7);
142
 
                        return false;
143
 
                }
144
 
 
145
 
                if(preg_match('/http:\/\/([^\/]+)\/(.*)$/', $response[3], $matches)) {
146
 
                        $host_parts = explode(":",$matches[1]);
147
 
                        $data['submit_host'] = $host_parts[0];
148
 
                        $data['submit_port'] = $host_parts[1] ? $host_parts[1] : '80';
149
 
                        $data['submit_url'] = '/' . $matches[2];
150
 
                } else {
151
 
                        $this->error_msg = "Invalid POST URL returned, unable to continue. Sent:\n$get_string\n----\nReceived:\n" . $buffer .
152
 
                                "\n---------\nExpeceted:" . print_r($response,1);
153
 
                        return false;
154
 
                }
155
 
 
156
 
                // Remove any extra junk around the challenge
157
 
                $data['challenge'] = trim($response[1]); 
158
 
                return $data;
159
 
 
160
 
        } // handshake
161
 
 
162
 
        /**
163
 
         * queue_track
164
 
         * This queues the LastFM track by storing it in this object, it doesn't actually
165
 
         * submit the track or talk to LastFM in anyway, kind of useless for our uses but its
166
 
         * here, and that's how it is.
167
 
         */
168
 
        public function queue_track($artist, $album, $title, $timestamp, $length,$track) {
169
 
 
170
 
                if ($length < 30) {
171
 
                        debug_event('Scrobbler',"Not queuing track, too short",'5');
172
 
                        return false;
173
 
                }
174
 
 
175
 
                $newtrack = array();
176
 
                $newtrack['artist'] = $artist;
177
 
                $newtrack['album'] = $album;
178
 
                $newtrack['title'] = $title;
179
 
                $newtrack['track'] = $track;
180
 
                $newtrack['length'] = $length;
181
 
                $newtrack['time'] = $timestamp;
182
 
 
183
 
                $this->queued_tracks[$timestamp] = $newtrack;
184
 
                return true;
185
 
 
186
 
        } // queue_track
187
 
 
188
 
        /**
189
 
         * submit_tracks
190
 
         * This actually talks to LastFM submiting the tracks that are queued up. It
191
 
         * passed the md5'd password combinted with the challenge, which is then md5'd
192
 
         */
193
 
        public function submit_tracks() {
194
 
 
195
 
                // Check and make sure that we've got some queued tracks
196
 
                if(!count($this->queued_tracks)) {
197
 
                        $this->error_msg = "No tracks to submit";
198
 
                        return false;
199
 
                }
200
 
 
201
 
                //sort array by timestamp
202
 
                ksort($this->queued_tracks);
203
 
 
204
 
                // build the query string
205
 
                $query_str = 's='.rawurlencode($this->challenge).'&';
206
 
 
207
 
                $i = 0;
208
 
 
209
 
                foreach($this->queued_tracks as $track) {
210
 
                        $query_str .= "a[$i]=".rawurlencode($track['artist'])."&t[$i]=".rawurlencode($track['title'])."&b[$i]=".rawurlencode($track['album'])."&";
211
 
                        $query_str .= "m[$i]=&l[$i]=".rawurlencode($track['length'])."&i[$i]=".rawurlencode($track['time'])."&";
212
 
                        $query_str .= "n[$i]=" . rawurlencode($track['track']) . "&o[$i]=P&r[$i]=&";
213
 
                        $i++;
214
 
                }
215
 
 
216
 
                if (!trim($this->submit_host) || !$this->submit_port) {
217
 
                        $this->reset_handshake = true;
218
 
                        return false;
219
 
                }
220
 
 
221
 
                $as_socket = fsockopen($this->submit_host, intval($this->submit_port), $errno, $errstr, 2);
222
 
 
223
 
                if(!$as_socket) {
224
 
                        $this->error_msg = $errstr;
225
 
                        $this->reset_handshake = true;
226
 
                        return false;
227
 
                }
228
 
 
229
 
                $action = "POST ".$this->submit_url." HTTP/1.0\r\n";
230
 
                fwrite($as_socket, $action);
231
 
                fwrite($as_socket, "Host: ".$this->submit_host."\r\n");
232
 
                fwrite($as_socket, "Accept: */*\r\n");
233
 
                fwrite($as_socket, "User-Agent: Ampache/3.6\r\n");
234
 
                fwrite($as_socket, "Content-type: application/x-www-form-urlencoded\r\n");
235
 
                fwrite($as_socket, "Content-length: ".strlen($query_str)."\r\n\r\n");
236
 
 
237
 
                fwrite($as_socket, $query_str."\r\n\r\n");
238
 
                // Allow us to debug this
239
 
                debug_event('SCROBBLER','Query String:' . $query_str,6); 
240
 
 
241
 
                $buffer = '';
242
 
                while(!feof($as_socket)) {
243
 
                        $buffer .= fread($as_socket, 8192);
244
 
                }
245
 
                fclose($as_socket);
246
 
 
247
 
                $split_response = preg_split("/\r\n\r\n/", $buffer);
248
 
                if(!isset($split_response[1])) {
249
 
                        $this->error_msg = 'Did not receive a valid response';
250
 
                        $this->reset_handshake = true;
251
 
                        return false;
252
 
                }
253
 
                $response = explode("\n", $split_response[1]);
254
 
                if(!isset($response[0])) {
255
 
                        $this->error_msg = 'Unknown error submitting tracks'.
256
 
                                          "\nDebug output:\n".$buffer;
257
 
                        $this->reset_handshake = true;
258
 
                        return false;
259
 
                }
260
 
                if(substr($response[0], 0, 6) == 'FAILED') {
261
 
                        $this->error_msg = $response[0];
262
 
                        $this->reset_handshake = true;
263
 
                        return false;
264
 
                }
265
 
                if(substr($response[0], 0, 7) == 'BADAUTH') {
266
 
                        $this->error_msg = 'Invalid username/password (' . trim($response[0]) . ')';
267
 
                        return false;
268
 
                }
269
 
                if (substr($response[0],0,10) == 'BADSESSION') {
270
 
                        $this->error_msg = 'Invalid Session passed (' . trim($response[0]) . ')';
271
 
                        $this->reset_handshake = true;
272
 
                        return false;
273
 
                }
274
 
                if(substr($response[0], 0, 2) != 'OK') {
275
 
                        $this->error_msg = 'Response Not ok, unknown error'.
276
 
                                          "\nDebug output:\n".$buffer;
277
 
                        $this->reset_handshake = true;
278
 
                        return false;
279
 
                }
280
 
 
281
 
                return true;
282
 
 
283
 
        } // submit_tracks
 
25
    public $error_msg;
 
26
    public $username;
 
27
    public $password;
 
28
    public $challenge;
 
29
    public $submit_host;
 
30
    public $submit_port;
 
31
    public $submit_url;
 
32
    public $queued_tracks;
 
33
    public $reset_handshake = false;
 
34
    public $scrobble_host = 'post.audioscrobbler.com';
 
35
 
 
36
    /**
 
37
     * Constructor
 
38
     * This is the constructer it takes a username and password
 
39
     */
 
40
    public function __construct($username, $password,$host='',$port='',$url='',$challenge='',$scrobble_host='') {
 
41
 
 
42
        $this->error_msg = '';
 
43
        $this->username = trim($username);
 
44
        $this->password = trim($password);
 
45
        $this->challenge = $challenge;
 
46
        $this->submit_host = $host;
 
47
        $this->submit_port = $port;
 
48
        $this->submit_url = $url;
 
49
        $this->queued_tracks = array();
 
50
        if ($scrobble_host) { $this->scrobble_host = $scrobble_host; }
 
51
 
 
52
    } // scrobbler
 
53
 
 
54
    /**
 
55
     * get_error_msg
 
56
     */
 
57
    public function get_error_msg() {
 
58
 
 
59
        return $this->error_msg;
 
60
 
 
61
    } // get_error_msg
 
62
 
 
63
    /**
 
64
     * get_queue_count
 
65
     */
 
66
    public function get_queue_count() {
 
67
 
 
68
        return count($this->queued_tracks);
 
69
 
 
70
    } // get_queue_count
 
71
 
 
72
    /**
 
73
     * handshake
 
74
     * This does a handshake with the audioscrobber server it doesn't pass the password, but
 
75
     * it does pass the username and has a 10 second timeout
 
76
     */
 
77
    public function handshake() {
 
78
 
 
79
        $as_socket = fsockopen($this->scrobble_host, 80, $errno, $errstr, 2);
 
80
        if(!$as_socket) {
 
81
            $this->error_msg = $errstr;
 
82
            return false;
 
83
        }
 
84
 
 
85
        $username    = rawurlencode($this->username);
 
86
        $timestamp    = time();
 
87
        $auth_token    = rawurlencode(md5($this->password . $timestamp));
 
88
 
 
89
        $get_string = "GET /?hs=true&p=1.2&c=apa&v=0.1&u=$username&t=$timestamp&a=$auth_token HTTP/1.1\r\n";
 
90
 
 
91
        fwrite($as_socket, $get_string);
 
92
        fwrite($as_socket, "Host: $this->scrobble_host\r\n");
 
93
        fwrite($as_socket, "Accept: */*\r\n\r\n");
 
94
 
 
95
        $buffer = '';
 
96
        while(!feof($as_socket)) {
 
97
            $buffer .= fread($as_socket, 4096);
 
98
        }
 
99
        fclose($as_socket);
 
100
        $split_response = preg_split("/\r\n\r\n/", $buffer);
 
101
        if(!isset($split_response[1])) {
 
102
            $this->error_msg = 'Did not receive a valid response';
 
103
            return false;
 
104
        }
 
105
        $response = explode("\n", $split_response[1]);
 
106
 
 
107
        // Handle the fact Libre.FM has extranious values at the start of it's handshake response
 
108
        if(is_numeric(trim($response['0']))) { 
 
109
            array_shift($response); 
 
110
            debug_event('SCROBBLER','Junk in handshake, removing first line',1); 
 
111
        } 
 
112
        if(substr($response[0], 0, 6) == 'FAILED') {
 
113
            $this->error_msg = substr($response[0], 7);
 
114
            return false;
 
115
        }
 
116
        if(substr($response[0], 0, 7) == 'BADUSER') {
 
117
            $this->error_msg = 'Invalid Username';
 
118
            return false;
 
119
        }
 
120
        if(substr($response[0],0,7) == 'BADTIME') {
 
121
            $this->error_msg = 'Your time is too far off from the server, or your PHP timezone is incorrect';
 
122
            return false;
 
123
        }
 
124
        if(substr($response[0], 0, 6) == 'UPDATE') {
 
125
            $this->error_msg = 'You need to update your client: '.substr($response[0], 7);
 
126
            return false;
 
127
        }
 
128
 
 
129
        if(preg_match('/http:\/\/([^\/]+)\/(.*)$/', $response[3], $matches)) {
 
130
            $host_parts = explode(":",$matches[1]);
 
131
            $data['submit_host'] = $host_parts[0];
 
132
            $data['submit_port'] = $host_parts[1] ? $host_parts[1] : '80';
 
133
            $data['submit_url'] = '/' . $matches[2];
 
134
        } else {
 
135
            $this->error_msg = "Invalid POST URL returned, unable to continue. Sent:\n$get_string\n----\nReceived:\n" . $buffer .
 
136
                "\n---------\nExpected:" . print_r($response, true);
 
137
            return false;
 
138
        }
 
139
 
 
140
        // Remove any extra junk around the challenge
 
141
        $data['challenge'] = trim($response[1]); 
 
142
        return $data;
 
143
 
 
144
    } // handshake
 
145
 
 
146
    /**
 
147
     * queue_track
 
148
     * This queues the LastFM track by storing it in this object, it doesn't actually
 
149
     * submit the track or talk to LastFM in anyway, kind of useless for our uses but its
 
150
     * here, and that's how it is.
 
151
     */
 
152
    public function queue_track($artist, $album, $title, $timestamp, $length,$track) {
 
153
 
 
154
        if ($length < 30) {
 
155
            debug_event('Scrobbler',"Not queuing track, too short",'5');
 
156
            return false;
 
157
        }
 
158
 
 
159
        $newtrack = array();
 
160
        $newtrack['artist'] = $artist;
 
161
        $newtrack['album'] = $album;
 
162
        $newtrack['title'] = $title;
 
163
        $newtrack['track'] = $track;
 
164
        $newtrack['length'] = $length;
 
165
        $newtrack['time'] = $timestamp;
 
166
 
 
167
        $this->queued_tracks[$timestamp] = $newtrack;
 
168
        return true;
 
169
 
 
170
    } // queue_track
 
171
 
 
172
    /**
 
173
     * submit_tracks
 
174
     * This actually talks to LastFM submiting the tracks that are queued up. It
 
175
     * passed the md5'd password combinted with the challenge, which is then md5'd
 
176
     */
 
177
    public function submit_tracks() {
 
178
 
 
179
        // Check and make sure that we've got some queued tracks
 
180
        if(!count($this->queued_tracks)) {
 
181
            $this->error_msg = "No tracks to submit";
 
182
            return false;
 
183
        }
 
184
 
 
185
        //sort array by timestamp
 
186
        ksort($this->queued_tracks);
 
187
 
 
188
        // build the query string
 
189
        $query_str = 's='.rawurlencode($this->challenge).'&';
 
190
 
 
191
        $i = 0;
 
192
 
 
193
        foreach($this->queued_tracks as $track) {
 
194
            $query_str .= "a[$i]=".rawurlencode($track['artist'])."&t[$i]=".rawurlencode($track['title'])."&b[$i]=".rawurlencode($track['album'])."&";
 
195
            $query_str .= "m[$i]=&l[$i]=".rawurlencode($track['length'])."&i[$i]=".rawurlencode($track['time'])."&";
 
196
            $query_str .= "n[$i]=" . rawurlencode($track['track']) . "&o[$i]=P&r[$i]=&";
 
197
            $i++;
 
198
        }
 
199
 
 
200
        if (!trim($this->submit_host) || !$this->submit_port) {
 
201
            $this->reset_handshake = true;
 
202
            return false;
 
203
        }
 
204
 
 
205
        $as_socket = fsockopen($this->submit_host, intval($this->submit_port), $errno, $errstr, 2);
 
206
 
 
207
        if(!$as_socket) {
 
208
            $this->error_msg = $errstr;
 
209
            $this->reset_handshake = true;
 
210
            return false;
 
211
        }
 
212
 
 
213
        $action = "POST ".$this->submit_url." HTTP/1.0\r\n";
 
214
        fwrite($as_socket, $action);
 
215
        fwrite($as_socket, "Host: ".$this->submit_host."\r\n");
 
216
        fwrite($as_socket, "Accept: */*\r\n");
 
217
        fwrite($as_socket, "User-Agent: Ampache/3.6\r\n");
 
218
        fwrite($as_socket, "Content-type: application/x-www-form-urlencoded\r\n");
 
219
        fwrite($as_socket, "Content-length: ".strlen($query_str)."\r\n\r\n");
 
220
 
 
221
        fwrite($as_socket, $query_str."\r\n\r\n");
 
222
        // Allow us to debug this
 
223
        debug_event('SCROBBLER','Query String:' . $query_str,6); 
 
224
 
 
225
        $buffer = '';
 
226
        while(!feof($as_socket)) {
 
227
            $buffer .= fread($as_socket, 8192);
 
228
        }
 
229
        fclose($as_socket);
 
230
 
 
231
        $split_response = preg_split("/\r\n\r\n/", $buffer);
 
232
        if(!isset($split_response[1])) {
 
233
            $this->error_msg = 'Did not receive a valid response';
 
234
            $this->reset_handshake = true;
 
235
            return false;
 
236
        }
 
237
        $response = explode("\n", $split_response[1]);
 
238
        if(!isset($response[0])) {
 
239
            $this->error_msg = 'Unknown error submitting tracks'.
 
240
                      "\nDebug output:\n".$buffer;
 
241
            $this->reset_handshake = true;
 
242
            return false;
 
243
        }
 
244
        if(substr($response[0], 0, 6) == 'FAILED') {
 
245
            $this->error_msg = $response[0];
 
246
            $this->reset_handshake = true;
 
247
            return false;
 
248
        }
 
249
        if(substr($response[0], 0, 7) == 'BADAUTH') {
 
250
            $this->error_msg = 'Invalid username/password (' . trim($response[0]) . ')';
 
251
            return false;
 
252
        }
 
253
        if (substr($response[0],0,10) == 'BADSESSION') {
 
254
            $this->error_msg = 'Invalid Session passed (' . trim($response[0]) . ')';
 
255
            $this->reset_handshake = true;
 
256
            return false;
 
257
        }
 
258
        if(substr($response[0], 0, 2) != 'OK') {
 
259
            $this->error_msg = 'Response Not ok, unknown error'.
 
260
                      "\nDebug output:\n".$buffer;
 
261
            $this->reset_handshake = true;
 
262
            return false;
 
263
        }
 
264
 
 
265
        return true;
 
266
 
 
267
    } // submit_tracks
284
268
 
285
269
} // end audioscrobbler class
286
270
?>