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