8ffddcd45dcf16087766f83b806d2f4a94a9bd8b
[mpd-web.git] / system / mpd_class.php
1 <?php\r
2 /*\r
3  *  mpd.class.php - PHP Object Interface to the MPD Music Player Daemon\r
4  *  Version 1.2, Released 05/05/2004\r
5  *  Copyright (C) 2003-2004  Benjamin Carlisle (bcarlisle@24oz.com)\r
6  *  http://mpd.24oz.com/ | http://www.musicpd.org/\r
7  *\r
8  *  This program is free software; you can redistribute it and/or modify\r
9  *  it under the terms of the GNU General Public License as published by\r
10  *  the Free Software Foundation; either version 2 of the License, or\r
11  *  (at your option) any later version.\r
12  *\r
13  *  This program is distributed in the hope that it will be useful,\r
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  *  GNU General Public License for more details.\r
17  *\r
18  *  You should have received a copy of the GNU General Public License\r
19  *  along with this program; if not, write to the Free Software\r
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
21  */ \r
22 \r
23 // Create common command definitions for MPD to use\r
24 define("MPD_CMD_STATUS",      "status");\r
25 define("MPD_CMD_STATISTICS",  "stats");\r
26 define("MPD_CMD_VOLUME",      "volume");\r
27 define("MPD_CMD_SETVOL",      "setvol");\r
28 define("MPD_CMD_PLAY",        "play");\r
29 define("MPD_CMD_STOP",        "stop");\r
30 define("MPD_CMD_PAUSE",       "pause");\r
31 define("MPD_CMD_NEXT",        "next");\r
32 define("MPD_CMD_PREV",        "previous");\r
33 define("MPD_CMD_PLLIST",      "playlistinfo");\r
34 define("MPD_CMD_PLADD",       "add");\r
35 define("MPD_CMD_PLREMOVE",    "delete");\r
36 define("MPD_CMD_PLCLEAR",     "clear");\r
37 define("MPD_CMD_PLSHUFFLE",   "shuffle");\r
38 define("MPD_CMD_PLLOAD",      "load");\r
39 define("MPD_CMD_PLSAVE",      "save");\r
40 define("MPD_CMD_KILL",        "kill");\r
41 define("MPD_CMD_REFRESH",     "update");\r
42 define("MPD_CMD_REPEAT",      "repeat");\r
43 define("MPD_CMD_LSDIR",       "lsinfo");\r
44 define("MPD_CMD_SEARCH",      "search");\r
45 define("MPD_CMD_START_BULK",  "command_list_begin");\r
46 define("MPD_CMD_END_BULK",    "command_list_end");\r
47 define("MPD_CMD_FIND",        "find");\r
48 define("MPD_CMD_RANDOM",      "random");\r
49 define("MPD_CMD_SEEK",        "seek");\r
50 define("MPD_CMD_PLSWAPTRACK", "swap");\r
51 define("MPD_CMD_PLMOVETRACK", "move");\r
52 define("MPD_CMD_PASSWORD",    "password");\r
53 define("MPD_CMD_TABLE",       "list");\r
54 \r
55 // Predefined MPD Response messages\r
56 define("MPD_RESPONSE_ERR", "ACK");\r
57 define("MPD_RESPONSE_OK",  "OK");\r
58 \r
59 // MPD State Constants\r
60 define("MPD_STATE_PLAYING", "play");\r
61 define("MPD_STATE_STOPPED", "stop");\r
62 define("MPD_STATE_PAUSED",  "pause");\r
63 \r
64 // MPD Searching Constants\r
65 define("MPD_SEARCH_ARTIST", "artist");\r
66 define("MPD_SEARCH_TITLE",  "title");\r
67 define("MPD_SEARCH_ALBUM",  "album");\r
68 \r
69 // MPD Cache Tables\r
70 define("MPD_TBL_ARTIST","artist");\r
71 define("MPD_TBL_ALBUM","album");\r
72 \r
73 class mpd {\r
74         // TCP/Connection variables\r
75         var $host;\r
76         var $port;\r
77     var $password;\r
78 \r
79         var $mpd_sock   = NULL;\r
80         var $connected  = FALSE;\r
81 \r
82         // MPD Status variables\r
83         var $mpd_version    = "(unknown)";\r
84 \r
85         var $state;\r
86         var $current_track_position;\r
87         var $current_track_length;\r
88         var $current_track_id;\r
89         var $volume;\r
90         var $repeat;\r
91         var $random;\r
92 \r
93         var $uptime;\r
94         var $playtime;\r
95         var $db_last_refreshed;\r
96         var $num_songs_played;\r
97         var $playlist_count;\r
98         \r
99         var $num_artists;\r
100         var $num_albums;\r
101         var $num_songs;\r
102         \r
103         var $playlist           = array();\r
104 \r
105         // Misc Other Vars      \r
106         var $mpd_class_version = "1.2";\r
107 \r
108         var $debugging   = FALSE;    // Set to TRUE to turn extended debugging on.\r
109         var $errStr      = "";       // Used for maintaining information about the last error message\r
110 \r
111         var $command_queue;          // The list of commands for bulk command sending\r
112 \r
113     // =================== BEGIN OBJECT METHODS ================\r
114 \r
115         /* mpd() : Constructor\r
116          * \r
117          * Builds the MPD object, connects to the server, and refreshes all local object properties.\r
118          */\r
119         function mpd($srv,$port,$pwd = NULL) {\r
120                 $this->host = $srv;\r
121                 $this->port = $port;\r
122         $this->password = $pwd;\r
123 \r
124                 $resp = $this->Connect();\r
125                 if ( is_null($resp) ) {\r
126             $this->errStr = "Could not connect";\r
127                         return;\r
128                 } else {\r
129                         list ( $this->mpd_version ) = sscanf($resp, MPD_RESPONSE_OK . " MPD %s\n");\r
130             if ( ! is_null($pwd) ) {\r
131                 if ( is_null($this->SendCommand(MPD_CMD_PASSWORD,$pwd)) ) {\r
132                     $this->connected = FALSE;\r
133                     return;  // bad password or command\r
134                 }\r
135                         if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!\r
136                     $this->connected = FALSE;\r
137                     $this->errStr = "Password supplied does not have read access";\r
138                     return;\r
139                 }\r
140             } else {\r
141                         if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!\r
142                     $this->connected = FALSE;\r
143                     $this->errStr = "Password required to access server";\r
144                     return; \r
145                 }\r
146             }\r
147                 }\r
148         }\r
149 \r
150         /* Connect()\r
151          * \r
152          * Connects to the MPD server. \r
153      * \r
154          * NOTE: This is called automatically upon object instantiation; you should not need to call this directly.\r
155          */\r
156         function Connect() {\r
157                 if ( $this->debugging ) echo "mpd->Connect() / host: ".$this->host.", port: ".$this->port."\n";\r
158                 $this->mpd_sock = fsockopen($this->host,$this->port,$errNo,$errStr,10);\r
159                 if (!$this->mpd_sock) {\r
160                         $this->errStr = "Socket Error: $errStr ($errNo)";\r
161                         return NULL;\r
162                 } else {\r
163                         while(!feof($this->mpd_sock)) {\r
164                                 $response =  fgets($this->mpd_sock,1024);\r
165                                 if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {\r
166                                         $this->connected = TRUE;\r
167                                         return $response;\r
168                                         break;\r
169                                 }\r
170                                 if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {\r
171                                         $this->errStr = "Server responded with: $response";\r
172                                         return NULL;\r
173                                 }\r
174                         }\r
175                         // Generic response\r
176                         $this->errStr = "Connection not available";\r
177                         return NULL;\r
178                 }\r
179         }\r
180 \r
181         /* SendCommand()\r
182          * \r
183          * Sends a generic command to the MPD server. Several command constants are pre-defined for \r
184          * use (see MPD_CMD_* constant definitions above). \r
185          */\r
186         function SendCommand($cmdStr,$arg1 = "",$arg2 = "") {\r
187                 if ( $this->debugging ) echo "mpd->SendCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";\r
188                 \r
189                 if ( ! $this->connected ) {\r
190                         echo "mpd->SendCommand() / Error: Not connected\n";\r
191                 } else {\r
192                         // Clear out the error String\r
193                         $this->errStr = "";\r
194                         $respStr = "";\r
195 \r
196                         // Check the command compatibility:\r
197                         if ( ! $this->_checkCompatibility($cmdStr) ) {\r
198                                 echo "Not compatible command!";\r
199                                 return NULL;\r
200                         }\r
201 \r
202                         if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";\r
203 \r
204                         if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";\r
205                         if ( $this->debugging ) echo "mpd-> ".$cmdStr."\n";\r
206                         fputs($this->mpd_sock,"$cmdStr\n");\r
207                         while(!feof($this->mpd_sock)) {\r
208                                 $response = fgets($this->mpd_sock,1024);\r
209                                 if ( $this->debugging ) echo "mpd.response-> ".$response."\n";\r
210 \r
211                                 // An OK signals the end of transmission -- we'll ignore it\r
212                                 if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {\r
213                                         break;\r
214                                 }\r
215 \r
216                                 // An ERR signals the end of transmission with an error! Let's grab the single-line message.\r
217                                 if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {\r
218                                         list ( $junk, $errTmp ) = explode(MPD_RESPONSE_ERR . " ",$response );\r
219                                         $this->errStr = strtok($errTmp,"\n");\r
220                                 }\r
221 \r
222                                 if ( strlen($this->errStr) > 0 ) {\r
223                                         return NULL;\r
224                                 }\r
225 \r
226                                 // Build the response string\r
227                                 $respStr .= $response;\r
228                         }\r
229                         if ( $this->debugging ) echo "mpd->SendCommand() / response: '".$respStr."'\n";\r
230                 }\r
231                 return $respStr;\r
232         }\r
233 \r
234         /* QueueCommand() \r
235          *\r
236          * Queues a generic command for later sending to the MPD server. The CommandQueue can hold \r
237          * as many commands as needed, and are sent all at once, in the order they are queued, using \r
238          * the SendCommandQueue() method. The syntax for queueing commands is identical to SendCommand(). \r
239      */\r
240         function QueueCommand($cmdStr,$arg1 = "",$arg2 = "") {\r
241                 if ( $this->debugging ) echo "mpd->QueueCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";\r
242                 if ( ! $this->connected ) {\r
243                         echo "mpd->QueueCommand() / Error: Not connected\n";\r
244                         return NULL;\r
245                 } else {\r
246                         if ( strlen($this->command_queue) == 0 ) {\r
247                                 $this->command_queue = MPD_CMD_START_BULK . "\n";\r
248                         }\r
249                         if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";\r
250                         if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";\r
251 \r
252                         $this->command_queue .= $cmdStr ."\n";\r
253 \r
254                         if ( $this->debugging ) echo "mpd->QueueCommand() / return\n";\r
255                 }\r
256                 return TRUE;\r
257         }\r
258 \r
259         /* SendCommandQueue() \r
260          *\r
261          * Sends all commands in the Command Queue to the MPD server. See also QueueCommand().\r
262      */\r
263         function SendCommandQueue() {\r
264                 if ( $this->debugging ) echo "mpd->SendCommandQueue()\n";\r
265                 if ( ! $this->connected ) {\r
266                         echo "mpd->SendCommandQueue() / Error: Not connected\n";\r
267                         return NULL;\r
268                 } else {\r
269                         $this->command_queue .= MPD_CMD_END_BULK . "\n";\r
270                         if ( is_null($respStr = $this->SendCommand($this->command_queue)) ) {\r
271                                 return NULL;\r
272                         } else {\r
273                                 $this->command_queue = NULL;\r
274                                 if ( $this->debugging ) echo "mpd->SendCommandQueue() / response: '".$respStr."'\n";\r
275                         }\r
276                 }\r
277                 return $respStr;\r
278         }\r
279 \r
280         /* AdjustVolume() \r
281          *\r
282          * Adjusts the mixer volume on the MPD by <modifier>, which can be a positive (volume increase),\r
283          * or negative (volume decrease) value. \r
284      */\r
285         function AdjustVolume($modifier) {\r
286                 if ( $this->debugging ) echo "mpd->AdjustVolume()\n";\r
287                 if ( ! is_numeric($modifier) ) {\r
288                         $this->errStr = "AdjustVolume() : argument 1 must be a numeric value";\r
289                         return NULL;\r
290                 }\r
291 \r
292         $this->RefreshInfo();\r
293         $newVol = $this->volume + $modifier;\r
294         $ret = $this->SetVolume($newVol);\r
295 \r
296                 if ( $this->debugging ) echo "mpd->AdjustVolume() / return\n";\r
297                 return $ret;\r
298         }\r
299 \r
300         /* SetVolume() \r
301          *\r
302          * Sets the mixer volume to <newVol>, which should be between 1 - 100.\r
303      */\r
304         function SetVolume($newVol) {\r
305                 if ( $this->debugging ) echo "mpd->SetVolume()\n";\r
306                 if ( ! is_numeric($newVol) ) {\r
307                         $this->errStr = "SetVolume() : argument 1 must be a numeric value";\r
308                         return NULL;\r
309                 }\r
310 \r
311         // Forcibly prevent out of range errors\r
312                 if ( $newVol < 0 )   $newVol = 0;\r
313                 if ( $newVol > 100 ) $newVol = 100;\r
314 \r
315         // If we're not compatible with SETVOL, we'll try adjusting using VOLUME\r
316         if ( $this->_checkCompatibility(MPD_CMD_SETVOL) ) {\r
317             if ( ! is_null($ret = $this->SendCommand(MPD_CMD_SETVOL,$newVol))) $this->volume = $newVol;\r
318         } else {\r
319                 $this->RefreshInfo();     // Get the latest volume\r
320                 if ( is_null($this->volume) ) {\r
321                         return NULL;\r
322                 } else {\r
323                         $modifier = ( $newVol - $this->volume );\r
324                 if ( ! is_null($ret = $this->SendCommand(MPD_CMD_VOLUME,$modifier))) $this->volume = $newVol;\r
325                 }\r
326         }\r
327 \r
328                 if ( $this->debugging ) echo "mpd->SetVolume() / return\n";\r
329                 return $ret;\r
330         }\r
331 \r
332         /* GetDir() \r
333          * \r
334      * Retrieves a database directory listing of the <dir> directory and places the results into\r
335          * a multidimensional array. If no directory is specified, the directory listing is at the \r
336          * base of the MPD music path. \r
337          */\r
338         function GetDir($dir = "") {\r
339                 if ( $this->debugging ) echo "mpd->GetDir()\n";\r
340                 $resp = $this->SendCommand(MPD_CMD_LSDIR,$dir);\r
341                 $dirlist = $this->_parseFileListResponse($resp);\r
342                 if ( $this->debugging ) echo "mpd->GetDir() / return ".print_r($dirlist)."\n";\r
343                 return $dirlist;\r
344         }\r
345 \r
346         /* PLAdd() \r
347          * \r
348      * Adds each track listed in a single-dimensional <trackArray>, which contains filenames \r
349          * of tracks to add, to the end of the playlist. This is used to add many, many tracks to \r
350          * the playlist in one swoop.\r
351          */\r
352         function PLAddBulk($trackArray) {\r
353                 if ( $this->debugging ) echo "mpd->PLAddBulk()\n";\r
354                 $num_files = count($trackArray);\r
355                 for ( $i = 0; $i < $num_files; $i++ ) {\r
356                         $this->QueueCommand(MPD_CMD_PLADD,$trackArray[$i]);\r
357                 }\r
358                 $resp = $this->SendCommandQueue();\r
359                 $this->RefreshInfo();\r
360                 if ( $this->debugging ) echo "mpd->PLAddBulk() / return\n";\r
361                 return $resp;\r
362         }\r
363 \r
364         /* PLAdd() \r
365          * \r
366          * Adds the file <file> to the end of the playlist. <file> must be a track in the MPD database. \r
367          */\r
368         function PLAdd($fileName) {\r
369                 if ( $this->debugging ) echo "mpd->PLAdd()\n";\r
370                 if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,$fileName))) $this->RefreshInfo();\r
371                 if ( $this->debugging ) echo "mpd->PLAdd() / return\n";\r
372                 return $resp;\r
373         }\r
374 \r
375         /* PLMoveTrack() \r
376          * \r
377          * Moves track number <origPos> to position <newPos> in the playlist. This is used to reorder \r
378          * the songs in the playlist.\r
379          */\r
380         function PLMoveTrack($origPos, $newPos) {\r
381                 if ( $this->debugging ) echo "mpd->PLMoveTrack()\n";\r
382                 if ( ! is_numeric($origPos) ) {\r
383                         $this->errStr = "PLMoveTrack(): argument 1 must be numeric";\r
384                         return NULL;\r
385                 } \r
386                 if ( $origPos < 0 or $origPos > $this->playlist_count ) {\r
387                         $this->errStr = "PLMoveTrack(): argument 1 out of range";\r
388                         return NULL;\r
389                 }\r
390                 if ( $newPos < 0 ) $newPos = 0;\r
391                 if ( $newPos > $this->playlist_count ) $newPos = $this->playlist_count;\r
392                 \r
393                 if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$origPos,$newPos))) $this->RefreshInfo();\r
394                 if ( $this->debugging ) echo "mpd->PLMoveTrack() / return\n";\r
395                 return $resp;\r
396         }\r
397 \r
398         /* PLShuffle() \r
399          * \r
400          * Randomly reorders the songs in the playlist.\r
401          */\r
402         function PLShuffle() {\r
403                 if ( $this->debugging ) echo "mpd->PLShuffle()\n";\r
404                 if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLSHUFFLE))) $this->RefreshInfo();\r
405                 if ( $this->debugging ) echo "mpd->PLShuffle() / return\n";\r
406                 return $resp;\r
407         }\r
408 \r
409         /* PLLoad() \r
410          * \r
411          * Retrieves the playlist from <file>.m3u and loads it into the current playlist. \r
412          */\r
413         function PLLoad($file) {\r
414                 if ( $this->debugging ) echo "mpd->PLLoad()\n";\r
415                 if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLLOAD,$file))) $this->RefreshInfo();\r
416                 if ( $this->debugging ) echo "mpd->PLLoad() / return\n";\r
417                 return $resp;\r
418         }\r
419 \r
420         /* PLSave() \r
421          * \r
422          * Saves the playlist to <file>.m3u for later retrieval. The file is saved in the MPD playlist\r
423          * directory.\r
424          */\r
425         function PLSave($file) {\r
426                 if ( $this->debugging ) echo "mpd->PLSave()\n";\r
427                 $resp = $this->SendCommand(MPD_CMD_PLSAVE,$file);\r
428                 if ( $this->debugging ) echo "mpd->PLSave() / return\n";\r
429                 return $resp;\r
430         }\r
431 \r
432         /* PLClear() \r
433          * \r
434          * Empties the playlist.\r
435          */\r
436         function PLClear() {\r
437                 if ( $this->debugging ) echo "mpd->PLClear()\n";\r
438                 if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLCLEAR))) $this->RefreshInfo();\r
439                 if ( $this->debugging ) echo "mpd->PLClear() / return\n";\r
440                 return $resp;\r
441         }\r
442 \r
443 \r
444         /* PLMove()\r
445         *\r
446         * Move song from pos to the other\r
447         */\r
448         function Move ($from,$to) {\r
449                 if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$from,$to))) $this->RefreshInfo();\r
450                 //die(print_r($resp));\r
451 \r
452         }\r
453 \r
454 \r
455         /* PLRemove() \r
456          * \r
457          * Removes track <id> from the playlist.\r
458          */\r
459         function PLRemove($id) {\r
460                 if ( $this->debugging ) echo "mpd->PLRemove()\n";\r
461                 if ( ! is_numeric($id) ) {\r
462                         $this->errStr = "PLRemove() : argument 1 must be a numeric value";\r
463                         return NULL;\r
464                 }\r
465                 if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLREMOVE,$id))) $this->RefreshInfo();\r
466                 if ( $this->debugging ) echo "mpd->PLRemove() / return\n";\r
467                 return $resp;\r
468         }\r
469 \r
470         /* SetRepeat() \r
471          * \r
472          * Enables 'loop' mode -- tells MPD continually loop the playlist. The <repVal> parameter \r
473          * is either 1 (on) or 0 (off).\r
474          */\r
475         function SetRepeat($repVal) {\r
476                 if ( $this->debugging ) echo "mpd->SetRepeat()\n";\r
477                 $rpt = $this->SendCommand(MPD_CMD_REPEAT,$repVal);\r
478                 $this->repeat = $repVal;\r
479                 if ( $this->debugging ) echo "mpd->SetRepeat() / return\n";\r
480                 return $rpt;\r
481         }\r
482 \r
483         /* SetRandom() \r
484          * \r
485          * Enables 'randomize' mode -- tells MPD to play songs in the playlist in random order. The\r
486          * <rndVal> parameter is either 1 (on) or 0 (off).\r
487          */\r
488         function SetRandom($rndVal) {\r
489                 if ( $this->debugging ) echo "mpd->SetRandom()\n";\r
490                 $resp = $this->SendCommand(MPD_CMD_RANDOM,$rndVal);\r
491                 $this->random = $rndVal;\r
492                 if ( $this->debugging ) echo "mpd->SetRandom() / return\n";\r
493                 return $resp;\r
494         }\r
495 \r
496         /* Shutdown() \r
497          * \r
498          * Shuts down the MPD server (aka sends the KILL command). This closes the current connection, \r
499          * and prevents future communication with the server. \r
500          */\r
501         function Shutdown() {\r
502                 if ( $this->debugging ) echo "mpd->Shutdown()\n";\r
503                 $resp = $this->SendCommand(MPD_CMD_SHUTDOWN);\r
504 \r
505                 $this->connected = FALSE;\r
506                 unset($this->mpd_version);\r
507                 unset($this->errStr);\r
508                 unset($this->mpd_sock);\r
509 \r
510                 if ( $this->debugging ) echo "mpd->Shutdown() / return\n";\r
511                 return $resp;\r
512         }\r
513 \r
514         /* DBRefresh() \r
515          * \r
516          * Tells MPD to rescan the music directory for new tracks, and to refresh the Database. Tracks \r
517          * cannot be played unless they are in the MPD database.\r
518          */\r
519         function DBRefresh() {\r
520                 if ( $this->debugging ) echo "mpd->DBRefresh()\n";\r
521                 $resp = $this->SendCommand(MPD_CMD_REFRESH);\r
522                 \r
523                 // Update local variables\r
524                 $this->RefreshInfo();\r
525 \r
526                 if ( $this->debugging ) echo "mpd->DBRefresh() / return\n";\r
527                 return $resp;\r
528         }\r
529 \r
530         /* Play() \r
531          * \r
532          * Begins playing the songs in the MPD playlist. \r
533          */\r
534         function Play() {\r
535                 if ( $this->debugging ) echo "mpd->Play()\n";\r
536                 if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY) )) $this->RefreshInfo();\r
537                 if ( $this->debugging ) echo "mpd->Play() / return\n";\r
538                 return $rpt;\r
539         }\r
540 \r
541         /* Stop() \r
542          * \r
543          * Stops playing the MPD. \r
544          */\r
545         function Stop() {\r
546                 if ( $this->debugging ) echo "mpd->Stop()\n";\r
547                 if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_STOP) )) $this->RefreshInfo();\r
548                 if ( $this->debugging ) echo "mpd->Stop() / return\n";\r
549                 return $rpt;\r
550         }\r
551 \r
552         /* Pause() \r
553          * \r
554          * Toggles pausing on the MPD. Calling it once will pause the player, calling it again\r
555          * will unpause. \r
556          */\r
557         function Pause() {\r
558                 if ( $this->debugging ) echo "mpd->Pause()\n";\r
559                 if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PAUSE) )) $this->RefreshInfo();\r
560                 if ( $this->debugging ) echo "mpd->Pause() / return\n";\r
561                 return $rpt;\r
562         }\r
563         \r
564         /* SeekTo() \r
565          * \r
566          * Skips directly to the <idx> song in the MPD playlist. \r
567          */\r
568         function SkipTo($idx) { \r
569                 if ( $this->debugging ) echo "mpd->SkipTo()\n";\r
570                 if ( ! is_numeric($idx) ) {\r
571                         $this->errStr = "SkipTo() : argument 1 must be a numeric value";\r
572                         return NULL;\r
573                 }\r
574                 if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY,$idx))) $this->RefreshInfo();\r
575                 if ( $this->debugging ) echo "mpd->SkipTo() / return\n";\r
576                 return $idx;\r
577         }\r
578 \r
579         /* SeekTo() \r
580          * \r
581          * Skips directly to a given position within a track in the MPD playlist. The <pos> argument,\r
582          * given in seconds, is the track position to locate. The <track> argument, if supplied is\r
583          * the track number in the playlist. If <track> is not specified, the current track is assumed.\r
584          */\r
585         function SeekTo($pos, $track = -1) { \r
586                 if ( $this->debugging ) echo "mpd->SeekTo()\n";\r
587                 if ( ! is_numeric($pos) ) {\r
588                         $this->errStr = "SeekTo() : argument 1 must be a numeric value";\r
589                         return NULL;\r
590                 }\r
591                 if ( ! is_numeric($track) ) {\r
592                         $this->errStr = "SeekTo() : argument 2 must be a numeric value";\r
593                         return NULL;\r
594                 }\r
595                 if ( $track == -1 ) { \r
596                         $track = $this->current_track_id;\r
597                 } \r
598                 \r
599                 if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_SEEK,$track,$pos))) $this->RefreshInfo();\r
600                 if ( $this->debugging ) echo "mpd->SeekTo() / return\n";\r
601                 return $pos;\r
602         }\r
603 \r
604         /* Next() \r
605          * \r
606          * Skips to the next song in the MPD playlist. If not playing, returns an error. \r
607          */\r
608         function Next() {\r
609                 if ( $this->debugging ) echo "mpd->Next()\n";\r
610                 if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_NEXT))) $this->RefreshInfo();\r
611                 if ( $this->debugging ) echo "mpd->Next() / return\n";\r
612                 return $rpt;\r
613         }\r
614 \r
615         /* Previous() \r
616          * \r
617          * Skips to the previous song in the MPD playlist. If not playing, returns an error. \r
618          */\r
619         function Previous() {\r
620                 if ( $this->debugging ) echo "mpd->Previous()\n";\r
621                 if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PREV))) $this->RefreshInfo();\r
622                 if ( $this->debugging ) echo "mpd->Previous() / return\n";\r
623                 return $rpt;\r
624         }\r
625         \r
626         /* Search() \r
627          * \r
628      * Searches the MPD database. The search <type> should be one of the following: \r
629      *        MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM\r
630      * The search <string> is a case-insensitive locator string. Anything that contains \r
631          * <string> will be returned in the results. \r
632          */\r
633         function Search($type,$string) {\r
634                 if ( $this->debugging ) echo "mpd->Search()\n";\r
635                 if ( $type != MPD_SEARCH_ARTIST and\r
636                  $type != MPD_SEARCH_ALBUM and\r
637                          $type != MPD_SEARCH_TITLE ) {\r
638                         $this->errStr = "mpd->Search(): invalid search type";\r
639                         return NULL;\r
640                 } else {\r
641                         if ( is_null($resp = $this->SendCommand(MPD_CMD_SEARCH,$type,$string))) return NULL;\r
642                         $searchlist = $this->_parseFileListResponse($resp);\r
643                 }\r
644                 if ( $this->debugging ) echo "mpd->Search() / return ".print_r($searchlist)."\n";\r
645                 return $searchlist;\r
646         }\r
647 \r
648         /* Find() \r
649          * \r
650          * Find() looks for exact matches in the MPD database. The find <type> should be one of \r
651          * the following: \r
652      *         MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM\r
653      * The find <string> is a case-insensitive locator string. Anything that exactly matches \r
654          * <string> will be returned in the results. \r
655          */\r
656         function Find($type,$string) {\r
657                 if ( $this->debugging ) echo "mpd->Find()\n";\r
658                 if ( $type != MPD_SEARCH_ARTIST and\r
659                  $type != MPD_SEARCH_ALBUM and\r
660                          $type != MPD_SEARCH_TITLE ) {\r
661                         $this->errStr = "mpd->Find(): invalid find type";\r
662                         return NULL;\r
663                 } else {\r
664                         if ( is_null($resp = $this->SendCommand(MPD_CMD_FIND,$type,$string)))   return NULL;\r
665                         $searchlist = $this->_parseFileListResponse($resp);\r
666                 }\r
667                 if ( $this->debugging ) echo "mpd->Find() / return ".print_r($searchlist)."\n";\r
668                 return $searchlist;\r
669         }\r
670 \r
671         /* Disconnect() \r
672          * \r
673          * Closes the connection to the MPD server.\r
674          */\r
675         function Disconnect() {\r
676                 if ( $this->debugging ) echo "mpd->Disconnect()\n";\r
677                 fclose($this->mpd_sock);\r
678 \r
679                 $this->connected = FALSE;\r
680                 unset($this->mpd_version);\r
681                 unset($this->errStr);\r
682                 unset($this->mpd_sock);\r
683         }\r
684 \r
685         /* GetArtists() \r
686          * \r
687          * Returns the list of artists in the database in an associative array.\r
688         */\r
689         function GetArtists() {\r
690                 if ( $this->debugging ) echo "mpd->GetArtists()\n";\r
691                 if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ARTIST)))        return NULL;\r
692         $arArray = array();\r
693         \r
694         $arLine = strtok($resp,"\n");\r
695         $arName = "";\r
696         $arCounter = -1;\r
697         while ( $arLine ) {\r
698             list ( $element, $value ) = explode(": ",$arLine);\r
699             if ( $element == "Artist" ) {\r
700                 $arCounter++;\r
701                 $arName = $value;\r
702                 $arArray[$arCounter] = $arName;\r
703             }\r
704 \r
705             $arLine = strtok("\n");\r
706         }\r
707                 if ( $this->debugging ) echo "mpd->GetArtists()\n";\r
708         return $arArray;\r
709     }\r
710 \r
711     /* GetAlbums() \r
712          * \r
713          * Returns the list of albums in the database in an associative array. Optional parameter\r
714      * is an artist Name which will list all albums by a particular artist.\r
715         */\r
716         function GetAlbums( $ar = NULL) {\r
717                 if ( $this->debugging ) echo "mpd->GetAlbums()\n";\r
718                 if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ALBUM, $ar )))   return NULL;\r
719         $alArray = array();\r
720 \r
721         $alLine = strtok($resp,"\n");\r
722         $alName = "";\r
723         $alCounter = -1;\r
724         while ( $alLine ) {\r
725             list ( $element, $value ) = explode(": ",$alLine);\r
726             if ( $element == "Album" ) {\r
727                 $alCounter++;\r
728                 $alName = $value;\r
729                 $alArray[$alCounter] = $alName;\r
730             }\r
731 \r
732             $alLine = strtok("\n");\r
733         }\r
734                 if ( $this->debugging ) echo "mpd->GetAlbums()\n";\r
735         return $alArray;\r
736     }\r
737 \r
738         //*******************************************************************************//\r
739         //***************************** INTERNAL FUNCTIONS ******************************//\r
740         //*******************************************************************************//\r
741 \r
742     /* _computeVersionValue()\r
743      *\r
744      * Computes a compatibility value from a version string\r
745      *\r
746      */\r
747     function _computeVersionValue($verStr) {\r
748                 list ($ver_maj, $ver_min, $ver_rel ) = explode("\.",$verStr);\r
749                 return ( 100 * $ver_maj ) + ( 10 * $ver_min ) + ( $ver_rel );\r
750     }\r
751 \r
752         /* _checkCompatibility() \r
753          * \r
754          * Check MPD command compatibility against our internal table. If there is no version \r
755          * listed in the table, allow it by default.\r
756         */\r
757         function _checkCompatibility($cmd) {\r
758         // Check minimum compatibility\r
759                 $req_ver_low = $this->COMPATIBILITY_MIN_TBL[$cmd];\r
760                 $req_ver_hi = $this->COMPATIBILITY_MAX_TBL[$cmd];\r
761 \r
762                 $mpd_ver = $this->_computeVersionValue($this->mpd_version);\r
763 \r
764                 if ( $req_ver_low ) {\r
765                         $req_ver = $this->_computeVersionValue($req_ver_low);\r
766 \r
767                         if ( $mpd_ver < $req_ver ) {\r
768                                 $this->errStr = "Command '$cmd' is not compatible with this version of MPD, version ".$req_ver_low." required";\r
769                                 return FALSE;\r
770                         }\r
771                 }\r
772 \r
773         // Check maxmum compatibility -- this will check for deprecations\r
774                 if ( $req_ver_hi ) {\r
775             $req_ver = $this->_computeVersionValue($req_ver_hi);\r
776 \r
777                         if ( $mpd_ver > $req_ver ) {\r
778                                 $this->errStr = "Command '$cmd' has been deprecated in this version of MPD.";\r
779                                 return FALSE;\r
780                         }\r
781                 }\r
782 \r
783                 return TRUE;\r
784         }\r
785 \r
786         /* _parseFileListResponse() \r
787          * \r
788          * Builds a multidimensional array with MPD response lists.\r
789      *\r
790          * NOTE: This function is used internally within the class. It should not be used.\r
791          */\r
792         function _parseFileListResponse($resp) {\r
793                 if ( is_null($resp) ) {\r
794                         return NULL;\r
795                 } else {\r
796                         $plistArray = array();\r
797                         $plistLine = strtok($resp,"\n");\r
798                         $plistFile = "";\r
799                         $plCounter = -1;\r
800                         while ( $plistLine ) {\r
801                                 list ( $element, $value ) = explode(": ",$plistLine);\r
802                                 if($element == "file" || $element=="directory") {\r
803                                   $plCounter++;\r
804                                   $plistArray[$plCounter]['name']=$value;\r
805                                   $plistArray[$plCounter]['type']=$element; \r
806                                   $plistArray[$plCounter]['title']=$value;\r
807                                 }\r
808                                 if($element == "Name") {\r
809                                   $plistArray[$plCounter]['title']=$value;\r
810                                 }\r
811                                 $plistLine = strtok("\n");\r
812                         } \r
813                 }\r
814                 return $plistArray;\r
815         }\r
816 \r
817         /* RefreshInfo() \r
818          * \r
819          * Updates all class properties with the values from the MPD server.\r
820      *\r
821          * NOTE: This function is automatically called upon Connect() as of v1.1.\r
822          */\r
823         function RefreshInfo() {\r
824         // Get the Server Statistics\r
825                 $statStr = $this->SendCommand(MPD_CMD_STATISTICS);\r
826                 if ( !$statStr ) {\r
827                         return NULL;\r
828                 } else {\r
829                         $stats = array();\r
830                         $statLine = strtok($statStr,"\n");\r
831                         while ( $statLine ) {\r
832                                 list ( $element, $value ) = explode(": ",$statLine);\r
833                                 $stats[$element] = $value;\r
834                                 $statLine = strtok("\n");\r
835                         } \r
836                 }\r
837 \r
838         // Get the Server Status\r
839                 $statusStr = $this->SendCommand(MPD_CMD_STATUS);\r
840                 if ( ! $statusStr ) {\r
841                         return NULL;\r
842                 } else {\r
843                         $status = array();\r
844                         $statusLine = strtok($statusStr,"\n");\r
845                         while ( $statusLine ) {\r
846                                 list ( $element, $value ) = explode(": ",$statusLine);\r
847                                 $status[$element] = $value;\r
848                                 $statusLine = strtok("\n");\r
849                         }\r
850                 }\r
851 \r
852         // Get the Playlist\r
853                 $plStr = $this->SendCommand(MPD_CMD_PLLIST);\r
854                 $this->playlist = $this->_parseFileListResponse($plStr);\r
855         $this->playlist_count = count($this->playlist);\r
856 \r
857         // Set Misc Other Variables\r
858                 $this->state = $status['state'];\r
859                 if ( ($this->state == MPD_STATE_PLAYING) || ($this->state == MPD_STATE_PAUSED) ) {\r
860                         $this->current_track_id = $status['song'];\r
861                         list ($this->current_track_position, $this->current_track_length ) = explode(":",$status['time']);\r
862                 } else {\r
863                         $this->current_track_id = -1;\r
864                         $this->current_track_position = -1;\r
865                         $this->current_track_length = -1;\r
866                 }\r
867 \r
868                 $this->repeat = $status['repeat'];\r
869                 $this->random = $status['random'];\r
870 \r
871                 $this->db_last_refreshed = $stats['db_update'];\r
872 \r
873                 $this->volume = $status['volume'];\r
874                 $this->uptime = $stats['uptime'];\r
875                 $this->playtime = $stats['playtime'];\r
876                 $this->num_songs_played = $stats['songs_played'];\r
877                 $this->num_artists = $stats['num_artists'];\r
878                 $this->num_songs = $stats['num_songs'];\r
879                 $this->num_albums = $stats['num_albums'];\r
880                 return TRUE;\r
881         }\r
882 \r
883     /* ------------------ DEPRECATED METHODS -------------------*/\r
884         /* GetStatistics() \r
885          * \r
886          * Retrieves the 'statistics' variables from the server and tosses them into an array.\r
887      *\r
888          * NOTE: This function really should not be used. Instead, use $this->[variable]. The function\r
889          *   will most likely be deprecated in future releases.\r
890          */\r
891         function GetStatistics() {\r
892                 if ( $this->debugging ) echo "mpd->GetStatistics()\n";\r
893                 $stats = $this->SendCommand(MPD_CMD_STATISTICS);\r
894                 if ( !$stats ) {\r
895                         return NULL;\r
896                 } else {\r
897                         $statsArray = array();\r
898                         $statsLine = strtok($stats,"\n");\r
899                         while ( $statsLine ) {\r
900                                 list ( $element, $value ) = explode(": ",$statsLine);\r
901                                 $statsArray[$element] = $value;\r
902                                 $statsLine = strtok("\n");\r
903                         } \r
904                 }\r
905                 if ( $this->debugging ) echo "mpd->GetStatistics() / return: " . print_r($statsArray) ."\n";\r
906                 return $statsArray;\r
907         }\r
908 \r
909         /* GetStatus() \r
910          * \r
911          * Retrieves the 'status' variables from the server and tosses them into an array.\r
912      *\r
913          * NOTE: This function really should not be used. Instead, use $this->[variable]. The function\r
914          *   will most likely be deprecated in future releases.\r
915          */\r
916         function GetStatus() {\r
917                 if ( $this->debugging ) echo "mpd->GetStatus()\n";\r
918                 $status = $this->SendCommand(MPD_CMD_STATUS);\r
919                 if ( ! $status ) {\r
920                         return NULL;\r
921                 } else {\r
922                         $statusArray = array();\r
923                         $statusLine = strtok($status,"\n");\r
924                         while ( $statusLine ) {\r
925                                 list ( $element, $value ) = explode(": ",$statusLine);\r
926                                 $statusArray[$element] = $value;\r
927                                 $statusLine = strtok("\n");\r
928                         }\r
929                 }\r
930                 if ( $this->debugging ) echo "mpd->GetStatus() / return: " . print_r($statusArray) ."\n";\r
931                 return $statusArray;\r
932         }\r
933 \r
934         /* GetVolume() \r
935          * \r
936          * Retrieves the mixer volume from the server.\r
937      *\r
938          * NOTE: This function really should not be used. Instead, use $this->volume. The function\r
939          *   will most likely be deprecated in future releases.\r
940          */\r
941         function GetVolume() {\r
942                 if ( $this->debugging ) echo "mpd->GetVolume()\n";\r
943                 $volLine = $this->SendCommand(MPD_CMD_STATUS);\r
944                 if ( ! $volLine ) {\r
945                         return NULL;\r
946                 } else {\r
947                         list ($vol) = sscanf($volLine,"volume: %d");\r
948                 }\r
949                 if ( $this->debugging ) echo "mpd->GetVolume() / return: $vol\n";\r
950                 return $vol;\r
951         }\r
952 \r
953         /* GetPlaylist() \r
954          * \r
955          * Retrieves the playlist from the server and tosses it into a multidimensional array.\r
956      *\r
957          * NOTE: This function really should not be used. Instead, use $this->playlist. The function\r
958          *   will most likely be deprecated in future releases.\r
959          */\r
960         function GetPlaylist() {\r
961                 if ( $this->debugging ) echo "mpd->GetPlaylist()\n";\r
962                 $resp = $this->SendCommand(MPD_CMD_PLLIST);\r
963                 $playlist = $this->_parseFileListResponse($resp);\r
964                 if ( $this->debugging ) echo "mpd->GetPlaylist() / return ".print_r($playlist)."\n";\r
965                 return $playlist;\r
966         }\r
967 \r
968     /* ----------------- Command compatibility tables --------------------- */\r
969         var $COMPATIBILITY_MIN_TBL = array(\r
970         );\r
971 \r
972     var $COMPATIBILITY_MAX_TBL = array(\r
973     );\r
974 \r
975 }   // ---------------------------- end of class ------------------------------\r
976 ?>\r