+<?php\r
+/*\r
+ * mpd.class.php - PHP Object Interface to the MPD Music Player Daemon\r
+ * Version 1.2, Released 05/05/2004\r
+ * Copyright (C) 2003-2004 Benjamin Carlisle (bcarlisle@24oz.com)\r
+ * http://mpd.24oz.com/ | http://www.musicpd.org/\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+ */ \r
+\r
+// Create common command definitions for MPD to use\r
+define("MPD_CMD_STATUS", "status");\r
+define("MPD_CMD_STATISTICS", "stats");\r
+define("MPD_CMD_VOLUME", "volume");\r
+define("MPD_CMD_SETVOL", "setvol");\r
+define("MPD_CMD_PLAY", "play");\r
+define("MPD_CMD_STOP", "stop");\r
+define("MPD_CMD_PAUSE", "pause");\r
+define("MPD_CMD_NEXT", "next");\r
+define("MPD_CMD_PREV", "previous");\r
+define("MPD_CMD_PLLIST", "playlistinfo");\r
+define("MPD_CMD_PLADD", "add");\r
+define("MPD_CMD_PLREMOVE", "delete");\r
+define("MPD_CMD_PLCLEAR", "clear");\r
+define("MPD_CMD_PLSHUFFLE", "shuffle");\r
+define("MPD_CMD_PLLOAD", "load");\r
+define("MPD_CMD_PLSAVE", "save");\r
+define("MPD_CMD_KILL", "kill");\r
+define("MPD_CMD_REFRESH", "update");\r
+define("MPD_CMD_REPEAT", "repeat");\r
+define("MPD_CMD_LSDIR", "lsinfo");\r
+define("MPD_CMD_SEARCH", "search");\r
+define("MPD_CMD_START_BULK", "command_list_begin");\r
+define("MPD_CMD_END_BULK", "command_list_end");\r
+define("MPD_CMD_FIND", "find");\r
+define("MPD_CMD_RANDOM", "random");\r
+define("MPD_CMD_SEEK", "seek");\r
+define("MPD_CMD_PLSWAPTRACK", "swap");\r
+define("MPD_CMD_PLMOVETRACK", "move");\r
+define("MPD_CMD_PASSWORD", "password");\r
+define("MPD_CMD_TABLE", "list");\r
+define("MPD_CMD_LISTS", "listplaylists");\r
+\r
+// Predefined MPD Response messages\r
+define("MPD_RESPONSE_ERR", "ACK");\r
+define("MPD_RESPONSE_OK", "OK");\r
+\r
+// MPD State Constants\r
+define("MPD_STATE_PLAYING", "play");\r
+define("MPD_STATE_STOPPED", "stop");\r
+define("MPD_STATE_PAUSED", "pause");\r
+\r
+// MPD Searching Constants\r
+define("MPD_SEARCH_ARTIST", "artist");\r
+define("MPD_SEARCH_TITLE", "title");\r
+define("MPD_SEARCH_ALBUM", "album");\r
+\r
+// MPD Cache Tables\r
+define("MPD_TBL_ARTIST","artist");\r
+define("MPD_TBL_ALBUM","album");\r
+\r
+class mpd {\r
+ // TCP/Connection variables\r
+ var $host;\r
+ var $port;\r
+ var $password;\r
+\r
+ var $mpd_sock = NULL;\r
+ var $connected = FALSE;\r
+\r
+ // MPD Status variables\r
+ var $mpd_version = "(unknown)";\r
+\r
+ var $state;\r
+ var $current_track_position;\r
+ var $current_track_length;\r
+ var $current_track_id;\r
+ var $volume;\r
+ var $repeat;\r
+ var $random;\r
+\r
+ var $uptime;\r
+ var $playtime;\r
+ var $db_last_refreshed;\r
+ var $num_songs_played;\r
+ var $playlist_count;\r
+ \r
+ var $num_artists;\r
+ var $num_albums;\r
+ var $num_songs;\r
+ \r
+ var $playlist = array();\r
+\r
+ // Misc Other Vars \r
+ var $mpd_class_version = "1.2";\r
+\r
+ var $debugging = TRUE; // Set to TRUE to turn extended debugging on.\r
+ var $errStr = ""; // Used for maintaining information about the last error message\r
+\r
+ var $command_queue; // The list of commands for bulk command sending\r
+\r
+ // =================== BEGIN OBJECT METHODS ================\r
+\r
+ /* mpd() : Constructor\r
+ * \r
+ * Builds the MPD object, connects to the server, and refreshes all local object properties.\r
+ */\r
+ function mpd($srv,$port,$pwd = NULL) {\r
+ $this->host = $srv;\r
+ $this->port = $port;\r
+ $this->password = $pwd;\r
+\r
+ $resp = $this->Connect();\r
+ if ( is_null($resp) ) {\r
+ $this->errStr = "Could not connect";\r
+ return;\r
+ } else {\r
+ list ( $this->mpd_version ) = sscanf($resp, MPD_RESPONSE_OK . " MPD %s\n");\r
+ if ( ! is_null($pwd) ) {\r
+ if ( is_null($this->SendCommand(MPD_CMD_PASSWORD,$pwd)) ) {\r
+ $this->connected = FALSE;\r
+ return; // bad password or command\r
+ }\r
+ if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!\r
+ $this->connected = FALSE;\r
+ $this->errStr = "Password supplied does not have read access";\r
+ return;\r
+ }\r
+ } else {\r
+ if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!\r
+ $this->connected = FALSE;\r
+ $this->errStr = "Password required to access server";\r
+ return; \r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* Connect()\r
+ * \r
+ * Connects to the MPD server. \r
+ * \r
+ * NOTE: This is called automatically upon object instantiation; you should not need to call this directly.\r
+ */\r
+ function Connect() {\r
+ if ( $this->debugging ) echo "mpd->Connect() / host: ".$this->host.", port: ".$this->port."\n";\r
+ $this->mpd_sock = fsockopen($this->host,$this->port,$errNo,$errStr,10);\r
+ if (!$this->mpd_sock) {\r
+ $this->errStr = "Socket Error: $errStr ($errNo)";\r
+ return NULL;\r
+ } else {\r
+ while(!feof($this->mpd_sock)) {\r
+ $response = fgets($this->mpd_sock,1024);\r
+ if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {\r
+ $this->connected = TRUE;\r
+ return $response;\r
+ break;\r
+ }\r
+ if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {\r
+ $this->errStr = "Server responded with: $response";\r
+ return NULL;\r
+ }\r
+ }\r
+ // Generic response\r
+ $this->errStr = "Connection not available";\r
+ return NULL;\r
+ }\r
+ }\r
+\r
+ /* SendCommand()\r
+ * \r
+ * Sends a generic command to the MPD server. Several command constants are pre-defined for \r
+ * use (see MPD_CMD_* constant definitions above). \r
+ */\r
+ function SendCommand($cmdStr,$arg1 = "",$arg2 = "") {\r
+ if ( $this->debugging ) echo "mpd->SendCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";\r
+ \r
+ if ( ! $this->connected ) {\r
+ echo "mpd->SendCommand() / Error: Not connected\n";\r
+ } else {\r
+ // Clear out the error String\r
+ $this->errStr = "";\r
+ $respStr = "";\r
+\r
+ // Check the command compatibility:\r
+ if ( ! $this->_checkCompatibility($cmdStr) ) {\r
+ echo "Not compatible command!";\r
+ return NULL;\r
+ }\r
+\r
+ if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";\r
+\r
+ if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";\r
+ if ( $this->debugging ) echo "mpd-> ".$cmdStr."\n";\r
+ fputs($this->mpd_sock,"$cmdStr\n");\r
+ while(!feof($this->mpd_sock)) {\r
+ $response = fgets($this->mpd_sock,1024);\r
+ if ( $this->debugging ) echo "mpd.response-> ".$response."\n";\r
+\r
+ // An OK signals the end of transmission -- we'll ignore it\r
+ if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {\r
+ break;\r
+ }\r
+\r
+ // An ERR signals the end of transmission with an error! Let's grab the single-line message.\r
+ if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {\r
+ list ( $junk, $errTmp ) = explode(MPD_RESPONSE_ERR . " ",$response );\r
+ $this->errStr = strtok($errTmp,"\n");\r
+ }\r
+\r
+ if ( strlen($this->errStr) > 0 ) {\r
+ return NULL;\r
+ }\r
+\r
+ // Build the response string\r
+ $respStr .= $response;\r
+ }\r
+ if ( $this->debugging ) echo "mpd->SendCommand() / response: '".$respStr."'\n";\r
+ }\r
+ return $respStr;\r
+ }\r
+\r
+ /* QueueCommand() \r
+ *\r
+ * Queues a generic command for later sending to the MPD server. The CommandQueue can hold \r
+ * as many commands as needed, and are sent all at once, in the order they are queued, using \r
+ * the SendCommandQueue() method. The syntax for queueing commands is identical to SendCommand(). \r
+ */\r
+ function QueueCommand($cmdStr,$arg1 = "",$arg2 = "") {\r
+ if ( $this->debugging ) echo "mpd->QueueCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";\r
+ if ( ! $this->connected ) {\r
+ echo "mpd->QueueCommand() / Error: Not connected\n";\r
+ return NULL;\r
+ } else {\r
+ if ( strlen($this->command_queue) == 0 ) {\r
+ $this->command_queue = MPD_CMD_START_BULK . "\n";\r
+ }\r
+ if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";\r
+ if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";\r
+\r
+ $this->command_queue .= $cmdStr ."\n";\r
+\r
+ if ( $this->debugging ) echo "mpd->QueueCommand() / return\n";\r
+ }\r
+ return TRUE;\r
+ }\r
+\r
+ /* SendCommandQueue() \r
+ *\r
+ * Sends all commands in the Command Queue to the MPD server. See also QueueCommand().\r
+ */\r
+ function SendCommandQueue() {\r
+ if ( $this->debugging ) echo "mpd->SendCommandQueue()\n";\r
+ if ( ! $this->connected ) {\r
+ echo "mpd->SendCommandQueue() / Error: Not connected\n";\r
+ return NULL;\r
+ } else {\r
+ $this->command_queue .= MPD_CMD_END_BULK . "\n";\r
+ if ( is_null($respStr = $this->SendCommand($this->command_queue)) ) {\r
+ return NULL;\r
+ } else {\r
+ $this->command_queue = NULL;\r
+ if ( $this->debugging ) echo "mpd->SendCommandQueue() / response: '".$respStr."'\n";\r
+ }\r
+ }\r
+ return $respStr;\r
+ }\r
+\r
+ /* AdjustVolume() \r
+ *\r
+ * Adjusts the mixer volume on the MPD by <modifier>, which can be a positive (volume increase),\r
+ * or negative (volume decrease) value. \r
+ */\r
+ function AdjustVolume($modifier) {\r
+ if ( $this->debugging ) echo "mpd->AdjustVolume()\n";\r
+ if ( ! is_numeric($modifier) ) {\r
+ $this->errStr = "AdjustVolume() : argument 1 must be a numeric value";\r
+ return NULL;\r
+ }\r
+\r
+ $this->RefreshInfo();\r
+ $newVol = $this->volume + $modifier;\r
+ $ret = $this->SetVolume($newVol);\r
+\r
+ if ( $this->debugging ) echo "mpd->AdjustVolume() / return\n";\r
+ return $ret;\r
+ }\r
+\r
+ /* SetVolume() \r
+ *\r
+ * Sets the mixer volume to <newVol>, which should be between 1 - 100.\r
+ */\r
+ function SetVolume($newVol) {\r
+ if ( $this->debugging ) echo "mpd->SetVolume()\n";\r
+ if ( ! is_numeric($newVol) ) {\r
+ $this->errStr = "SetVolume() : argument 1 must be a numeric value";\r
+ return NULL;\r
+ }\r
+\r
+ // Forcibly prevent out of range errors\r
+ if ( $newVol < 0 ) $newVol = 0;\r
+ if ( $newVol > 100 ) $newVol = 100;\r
+\r
+ // If we're not compatible with SETVOL, we'll try adjusting using VOLUME\r
+ if ( $this->_checkCompatibility(MPD_CMD_SETVOL) ) {\r
+ if ( ! is_null($ret = $this->SendCommand(MPD_CMD_SETVOL,$newVol))) $this->volume = $newVol;\r
+ } else {\r
+ $this->RefreshInfo(); // Get the latest volume\r
+ if ( is_null($this->volume) ) {\r
+ return NULL;\r
+ } else {\r
+ $modifier = ( $newVol - $this->volume );\r
+ if ( ! is_null($ret = $this->SendCommand(MPD_CMD_VOLUME,$modifier))) $this->volume = $newVol;\r
+ }\r
+ }\r
+\r
+ if ( $this->debugging ) echo "mpd->SetVolume() / return\n";\r
+ return $ret;\r
+ }\r
+\r
+ /* GetDir() \r
+ * \r
+ * Retrieves a database directory listing of the <dir> directory and places the results into\r
+ * a multidimensional array. If no directory is specified, the directory listing is at the \r
+ * base of the MPD music path. \r
+ */\r
+ function GetDir($dir = "") {\r
+ if ( $this->debugging ) echo "mpd->GetDir()\n";\r
+ $resp = $this->SendCommand(MPD_CMD_LSDIR,$dir);\r
+ $dirlist = $this->_parseFileListResponse($resp);\r
+ if ( $this->debugging ) echo "mpd->GetDir() / return ".print_r($dirlist)."\n";\r
+ return $dirlist;\r
+ }\r
+\r
+ /* PLAdd() \r
+ * \r
+ * Adds each track listed in a single-dimensional <trackArray>, which contains filenames \r
+ * of tracks to add, to the end of the playlist. This is used to add many, many tracks to \r
+ * the playlist in one swoop.\r
+ */\r
+ function PLAddBulk($trackArray) {\r
+ if ( $this->debugging ) echo "mpd->PLAddBulk()\n";\r
+ $num_files = count($trackArray);\r
+ for ( $i = 0; $i < $num_files; $i++ ) {\r
+ $this->QueueCommand(MPD_CMD_PLADD,$trackArray[$i]);\r
+ }\r
+ $resp = $this->SendCommandQueue();\r
+ $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->PLAddBulk() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* PLAdd() \r
+ * \r
+ * Adds the file <file> to the end of the playlist. <file> must be a track in the MPD database. \r
+ */\r
+ function PLAdd($fileName) {\r
+ if ( $this->debugging ) echo "mpd->PLAdd()\n";\r
+ if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,$fileName))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->PLAdd() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* PLMoveTrack() \r
+ * \r
+ * Moves track number <origPos> to position <newPos> in the playlist. This is used to reorder \r
+ * the songs in the playlist.\r
+ */\r
+ function PLMoveTrack($origPos, $newPos) {\r
+ if ( $this->debugging ) echo "mpd->PLMoveTrack()\n";\r
+ if ( ! is_numeric($origPos) ) {\r
+ $this->errStr = "PLMoveTrack(): argument 1 must be numeric";\r
+ return NULL;\r
+ } \r
+ if ( $origPos < 0 or $origPos > $this->playlist_count ) {\r
+ $this->errStr = "PLMoveTrack(): argument 1 out of range";\r
+ return NULL;\r
+ }\r
+ if ( $newPos < 0 ) $newPos = 0;\r
+ if ( $newPos > $this->playlist_count ) $newPos = $this->playlist_count;\r
+ \r
+ if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$origPos,$newPos))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->PLMoveTrack() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* PLShuffle() \r
+ * \r
+ * Randomly reorders the songs in the playlist.\r
+ */\r
+ function PLShuffle() {\r
+ if ( $this->debugging ) echo "mpd->PLShuffle()\n";\r
+ if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLSHUFFLE))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->PLShuffle() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* PLLoad() \r
+ * \r
+ * Retrieves the playlist from <file>.m3u and loads it into the current playlist. \r
+ */\r
+ function PLLoad($file) {\r
+ if ( $this->debugging ) echo "mpd->PLLoad()\n";\r
+ if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLLOAD,$file))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->PLLoad() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* PLList() \r
+ * \r
+ * Retrieves the playlists info. \r
+ */\r
+ function PLList() {\r
+ if ( $this->debugging ) echo "mpd->PLList()\n";\r
+ if ( ! is_null($resp = $this->SendCommand(MPD_CMD_LISTS))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->PLList() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* PLSave() \r
+ * \r
+ * Saves the playlist to <file>.m3u for later retrieval. The file is saved in the MPD playlist\r
+ * directory.\r
+ */\r
+ function PLSave($file) {\r
+ if ( $this->debugging ) echo "mpd->PLSave()\n";\r
+ $resp = $this->SendCommand(MPD_CMD_PLSAVE,$file);\r
+ if ( $this->debugging ) echo "mpd->PLSave() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* PLClear() \r
+ * \r
+ * Empties the playlist.\r
+ */\r
+ function PLClear() {\r
+ if ( $this->debugging ) echo "mpd->PLClear()\n";\r
+ if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLCLEAR))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->PLClear() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+\r
+ /* PLMove()\r
+ *\r
+ * Move song from pos to the other\r
+ */\r
+ function Move ($from,$to) {\r
+ if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$from,$to))) $this->RefreshInfo();\r
+ //die(print_r($resp));\r
+\r
+ }\r
+\r
+\r
+ /* PLRemove() \r
+ * \r
+ * Removes track <id> from the playlist.\r
+ */\r
+ function PLRemove($id) {\r
+ if ( $this->debugging ) echo "mpd->PLRemove()\n";\r
+ if ( ! is_numeric($id) ) {\r
+ $this->errStr = "PLRemove() : argument 1 must be a numeric value";\r
+ return NULL;\r
+ }\r
+ if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLREMOVE,$id))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->PLRemove() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* SetRepeat() \r
+ * \r
+ * Enables 'loop' mode -- tells MPD continually loop the playlist. The <repVal> parameter \r
+ * is either 1 (on) or 0 (off).\r
+ */\r
+ function SetRepeat($repVal) {\r
+ if ( $this->debugging ) echo "mpd->SetRepeat()\n";\r
+ $rpt = $this->SendCommand(MPD_CMD_REPEAT,$repVal);\r
+ $this->repeat = $repVal;\r
+ if ( $this->debugging ) echo "mpd->SetRepeat() / return\n";\r
+ return $rpt;\r
+ }\r
+\r
+ /* SetRandom() \r
+ * \r
+ * Enables 'randomize' mode -- tells MPD to play songs in the playlist in random order. The\r
+ * <rndVal> parameter is either 1 (on) or 0 (off).\r
+ */\r
+ function SetRandom($rndVal) {\r
+ if ( $this->debugging ) echo "mpd->SetRandom()\n";\r
+ $resp = $this->SendCommand(MPD_CMD_RANDOM,$rndVal);\r
+ $this->random = $rndVal;\r
+ if ( $this->debugging ) echo "mpd->SetRandom() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* Shutdown() \r
+ * \r
+ * Shuts down the MPD server (aka sends the KILL command). This closes the current connection, \r
+ * and prevents future communication with the server. \r
+ */\r
+ function Shutdown() {\r
+ if ( $this->debugging ) echo "mpd->Shutdown()\n";\r
+ $resp = $this->SendCommand(MPD_CMD_SHUTDOWN);\r
+\r
+ $this->connected = FALSE;\r
+ unset($this->mpd_version);\r
+ unset($this->errStr);\r
+ unset($this->mpd_sock);\r
+\r
+ if ( $this->debugging ) echo "mpd->Shutdown() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* DBRefresh() \r
+ * \r
+ * Tells MPD to rescan the music directory for new tracks, and to refresh the Database. Tracks \r
+ * cannot be played unless they are in the MPD database.\r
+ */\r
+ function DBRefresh() {\r
+ if ( $this->debugging ) echo "mpd->DBRefresh()\n";\r
+ $resp = $this->SendCommand(MPD_CMD_REFRESH);\r
+ \r
+ // Update local variables\r
+ $this->RefreshInfo();\r
+\r
+ if ( $this->debugging ) echo "mpd->DBRefresh() / return\n";\r
+ return $resp;\r
+ }\r
+\r
+ /* Play() \r
+ * \r
+ * Begins playing the songs in the MPD playlist. \r
+ */\r
+ function Play() {\r
+ if ( $this->debugging ) echo "mpd->Play()\n";\r
+ if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY) )) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->Play() / return\n";\r
+ return $rpt;\r
+ }\r
+\r
+ /* Stop() \r
+ * \r
+ * Stops playing the MPD. \r
+ */\r
+ function Stop() {\r
+ if ( $this->debugging ) echo "mpd->Stop()\n";\r
+ if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_STOP) )) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->Stop() / return\n";\r
+ return $rpt;\r
+ }\r
+\r
+ /* Pause() \r
+ * \r
+ * Toggles pausing on the MPD. Calling it once will pause the player, calling it again\r
+ * will unpause. \r
+ */\r
+ function Pause() {\r
+ if ( $this->debugging ) echo "mpd->Pause()\n";\r
+ if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PAUSE) )) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->Pause() / return\n";\r
+ return $rpt;\r
+ }\r
+ \r
+ /* SeekTo() \r
+ * \r
+ * Skips directly to the <idx> song in the MPD playlist. \r
+ */\r
+ function SkipTo($idx) { \r
+ if ( $this->debugging ) echo "mpd->SkipTo()\n";\r
+ if ( ! is_numeric($idx) ) {\r
+ $this->errStr = "SkipTo() : argument 1 must be a numeric value";\r
+ return NULL;\r
+ }\r
+ if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY,$idx))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->SkipTo() / return\n";\r
+ return $idx;\r
+ }\r
+\r
+ /* SeekTo() \r
+ * \r
+ * Skips directly to a given position within a track in the MPD playlist. The <pos> argument,\r
+ * given in seconds, is the track position to locate. The <track> argument, if supplied is\r
+ * the track number in the playlist. If <track> is not specified, the current track is assumed.\r
+ */\r
+ function SeekTo($pos, $track = -1) { \r
+ if ( $this->debugging ) echo "mpd->SeekTo()\n";\r
+ if ( ! is_numeric($pos) ) {\r
+ $this->errStr = "SeekTo() : argument 1 must be a numeric value";\r
+ return NULL;\r
+ }\r
+ if ( ! is_numeric($track) ) {\r
+ $this->errStr = "SeekTo() : argument 2 must be a numeric value";\r
+ return NULL;\r
+ }\r
+ if ( $track == -1 ) { \r
+ $track = $this->current_track_id;\r
+ } \r
+ \r
+ if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_SEEK,$track,$pos))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->SeekTo() / return\n";\r
+ return $pos;\r
+ }\r
+\r
+ /* Next() \r
+ * \r
+ * Skips to the next song in the MPD playlist. If not playing, returns an error. \r
+ */\r
+ function Next() {\r
+ if ( $this->debugging ) echo "mpd->Next()\n";\r
+ if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_NEXT))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->Next() / return\n";\r
+ return $rpt;\r
+ }\r
+\r
+ /* Previous() \r
+ * \r
+ * Skips to the previous song in the MPD playlist. If not playing, returns an error. \r
+ */\r
+ function Previous() {\r
+ if ( $this->debugging ) echo "mpd->Previous()\n";\r
+ if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PREV))) $this->RefreshInfo();\r
+ if ( $this->debugging ) echo "mpd->Previous() / return\n";\r
+ return $rpt;\r
+ }\r
+ \r
+ /* Search() \r
+ * \r
+ * Searches the MPD database. The search <type> should be one of the following: \r
+ * MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM\r
+ * The search <string> is a case-insensitive locator string. Anything that contains \r
+ * <string> will be returned in the results. \r
+ */\r
+ function Search($type,$string) {\r
+ if ( $this->debugging ) echo "mpd->Search()\n";\r
+ if ( $type != MPD_SEARCH_ARTIST and\r
+ $type != MPD_SEARCH_ALBUM and\r
+ $type != MPD_SEARCH_TITLE ) {\r
+ $this->errStr = "mpd->Search(): invalid search type";\r
+ return NULL;\r
+ } else {\r
+ if ( is_null($resp = $this->SendCommand(MPD_CMD_SEARCH,$type,$string))) return NULL;\r
+ $searchlist = $this->_parseFileListResponse($resp);\r
+ }\r
+ if ( $this->debugging ) echo "mpd->Search() / return ".print_r($searchlist)."\n";\r
+ return $searchlist;\r
+ }\r
+\r
+ /* Find() \r
+ * \r
+ * Find() looks for exact matches in the MPD database. The find <type> should be one of \r
+ * the following: \r
+ * MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM\r
+ * The find <string> is a case-insensitive locator string. Anything that exactly matches \r
+ * <string> will be returned in the results. \r
+ */\r
+ function Find($type,$string) {\r
+ if ( $this->debugging ) echo "mpd->Find()\n";\r
+ if ( $type != MPD_SEARCH_ARTIST and\r
+ $type != MPD_SEARCH_ALBUM and\r
+ $type != MPD_SEARCH_TITLE ) {\r
+ $this->errStr = "mpd->Find(): invalid find type";\r
+ return NULL;\r
+ } else {\r
+ if ( is_null($resp = $this->SendCommand(MPD_CMD_FIND,$type,$string))) return NULL;\r
+ $searchlist = $this->_parseFileListResponse($resp);\r
+ }\r
+ if ( $this->debugging ) echo "mpd->Find() / return ".print_r($searchlist)."\n";\r
+ return $searchlist;\r
+ }\r
+\r
+ /* Disconnect() \r
+ * \r
+ * Closes the connection to the MPD server.\r
+ */\r
+ function Disconnect() {\r
+ if ( $this->debugging ) echo "mpd->Disconnect()\n";\r
+ fclose($this->mpd_sock);\r
+\r
+ $this->connected = FALSE;\r
+ unset($this->mpd_version);\r
+ unset($this->errStr);\r
+ unset($this->mpd_sock);\r
+ }\r
+\r
+ /* GetArtists() \r
+ * \r
+ * Returns the list of artists in the database in an associative array.\r
+ */\r
+ function GetArtists() {\r
+ if ( $this->debugging ) echo "mpd->GetArtists()\n";\r
+ if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ARTIST))) return NULL;\r
+ $arArray = array();\r
+ \r
+ $arLine = strtok($resp,"\n");\r
+ $arName = "";\r
+ $arCounter = -1;\r
+ while ( $arLine ) {\r
+ list ( $element, $value ) = explode(": ",$arLine);\r
+ if ( $element == "Artist" ) {\r
+ $arCounter++;\r
+ $arName = $value;\r
+ $arArray[$arCounter] = $arName;\r
+ }\r
+\r
+ $arLine = strtok("\n");\r
+ }\r
+ if ( $this->debugging ) echo "mpd->GetArtists()\n";\r
+ return $arArray;\r
+ }\r
+\r
+ /* GetAlbums() \r
+ * \r
+ * Returns the list of albums in the database in an associative array. Optional parameter\r
+ * is an artist Name which will list all albums by a particular artist.\r
+ */\r
+ function GetAlbums( $ar = NULL) {\r
+ if ( $this->debugging ) echo "mpd->GetAlbums()\n";\r
+ if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ALBUM, $ar ))) return NULL;\r
+ $alArray = array();\r
+\r
+ $alLine = strtok($resp,"\n");\r
+ $alName = "";\r
+ $alCounter = -1;\r
+ while ( $alLine ) {\r
+ list ( $element, $value ) = explode(": ",$alLine);\r
+ if ( $element == "Album" ) {\r
+ $alCounter++;\r
+ $alName = $value;\r
+ $alArray[$alCounter] = $alName;\r
+ }\r
+\r
+ $alLine = strtok("\n");\r
+ }\r
+ if ( $this->debugging ) echo "mpd->GetAlbums()\n";\r
+ return $alArray;\r
+ }\r
+\r
+ //*******************************************************************************//\r
+ //***************************** INTERNAL FUNCTIONS ******************************//\r
+ //*******************************************************************************//\r
+\r
+ /* _computeVersionValue()\r
+ *\r
+ * Computes a compatibility value from a version string\r
+ *\r
+ */\r
+ function _computeVersionValue($verStr) {\r
+ list ($ver_maj, $ver_min, $ver_rel ) = explode("\.",$verStr);\r
+ return ( 100 * $ver_maj ) + ( 10 * $ver_min ) + ( $ver_rel );\r
+ }\r
+\r
+ /* _checkCompatibility() \r
+ * \r
+ * Check MPD command compatibility against our internal table. If there is no version \r
+ * listed in the table, allow it by default.\r
+ */\r
+ function _checkCompatibility($cmd) {\r
+ // Check minimum compatibility\r
+ $req_ver_low = $this->COMPATIBILITY_MIN_TBL[$cmd];\r
+ $req_ver_hi = $this->COMPATIBILITY_MAX_TBL[$cmd];\r
+\r
+ $mpd_ver = $this->_computeVersionValue($this->mpd_version);\r
+\r
+ if ( $req_ver_low ) {\r
+ $req_ver = $this->_computeVersionValue($req_ver_low);\r
+\r
+ if ( $mpd_ver < $req_ver ) {\r
+ $this->errStr = "Command '$cmd' is not compatible with this version of MPD, version ".$req_ver_low." required";\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ // Check maxmum compatibility -- this will check for deprecations\r
+ if ( $req_ver_hi ) {\r
+ $req_ver = $this->_computeVersionValue($req_ver_hi);\r
+\r
+ if ( $mpd_ver > $req_ver ) {\r
+ $this->errStr = "Command '$cmd' has been deprecated in this version of MPD.";\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ /* _parseFileListResponse() \r
+ * \r
+ * Builds a multidimensional array with MPD response lists.\r
+ *\r
+ * NOTE: This function is used internally within the class. It should not be used.\r
+ */\r
+ function _parseFileListResponse($resp) {\r
+ if ( is_null($resp) ) {\r
+ return NULL;\r
+ } else {\r
+ $plistArray = array();\r
+ $plistLine = strtok($resp,"\n");\r
+ $plistFile = "";\r
+ $plCounter = -1;\r
+ while ( $plistLine ) {\r
+ list ( $element, $value ) = explode(": ",$plistLine);\r
+ if($element == "file" || $element=="directory") {\r
+ $plCounter++;\r
+ $plistArray[$plCounter]['name']=$value;\r
+ $plistArray[$plCounter]['type']=$element; \r
+ $plistArray[$plCounter]['title']=$value;\r
+ }\r
+ if($element == "Name") {\r
+ $plistArray[$plCounter]['title']=$value;\r
+ }\r
+ $plistLine = strtok("\n");\r
+ } \r
+ }\r
+ return $plistArray;\r
+ }\r
+\r
+ /* _parsePlayListsResponse() \r
+ * \r
+ * Builds a multidimensional array with MPD response lists.\r
+ *\r
+ * NOTE: This function is used internally within the class. It should not be used.\r
+ */\r
+ function _parsePlayListsResponse($resp) {\r
+ if ( is_null($resp) ) {\r
+ return NULL;\r
+ } else {\r
+ $plistArray = array();\r
+ $plistLine = strtok($resp,"\n");\r
+ $plistFile = "";\r
+ $plCounter = -1;\r
+ while ( $plistLine ) {\r
+ list ( $element, $value ) = explode(": ",$plistLine);\r
+ if($element == "playlist") {\r
+ $plCounter++;\r
+ $plistArray[$plCounter]['name']=$value;\r
+ }\r
+ if($element == "Last-Modified") {\r
+ $plistArray[$plCounter]['timestamp']=$value;\r
+ }\r
+ $plistLine = strtok("\n");\r
+ } \r
+ }\r
+ return $plistArray;\r
+ }\r
+\r
+ /* RefreshInfo() \r
+ * \r
+ * Updates all class properties with the values from the MPD server.\r
+ *\r
+ * NOTE: This function is automatically called upon Connect() as of v1.1.\r
+ */\r
+ function RefreshInfo() {\r
+ // Get the Server Statistics\r
+ $statStr = $this->SendCommand(MPD_CMD_STATISTICS);\r
+ if ( !$statStr ) {\r
+ return NULL;\r
+ } else {\r
+ $stats = array();\r
+ $statLine = strtok($statStr,"\n");\r
+ while ( $statLine ) {\r
+ list ( $element, $value ) = explode(": ",$statLine);\r
+ $stats[$element] = $value;\r
+ $statLine = strtok("\n");\r
+ } \r
+ }\r
+\r
+ // Get the Server Status\r
+ $statusStr = $this->SendCommand(MPD_CMD_STATUS);\r
+ if ( ! $statusStr ) {\r
+ return NULL;\r
+ } else {\r
+ $status = array();\r
+ $statusLine = strtok($statusStr,"\n");\r
+ while ( $statusLine ) {\r
+ list ( $element, $value ) = explode(": ",$statusLine);\r
+ $status[$element] = $value;\r
+ $statusLine = strtok("\n");\r
+ }\r
+ }\r
+\r
+ // Get list of lists\r
+ $plStr = $this->SendCommand(MPD_CMD_LISTS);\r
+ $this->playlists = $this->_parsePlayListsResponse($plStr);\r
+\r
+ // Get the Playlist\r
+ $plStr = $this->SendCommand(MPD_CMD_PLLIST);\r
+ $this->playlist = $this->_parseFileListResponse($plStr);\r
+ $this->playlist_count = count($this->playlist);\r
+\r
+ // Set Misc Other Variables\r
+ $this->state = $status['state'];\r
+ if ( ($this->state == MPD_STATE_PLAYING) || ($this->state == MPD_STATE_PAUSED) ) {\r
+ $this->current_track_id = $status['song'];\r
+ list ($this->current_track_position, $this->current_track_length ) = explode(":",$status['time']);\r
+ } else {\r
+ $this->current_track_id = -1;\r
+ $this->current_track_position = -1;\r
+ $this->current_track_length = -1;\r
+ }\r
+\r
+ $this->repeat = $status['repeat'];\r
+ $this->random = $status['random'];\r
+\r
+ $this->db_last_refreshed = $stats['db_update'];\r
+\r
+ $this->volume = $status['volume'];\r
+ $this->uptime = $stats['uptime'];\r
+ $this->playtime = $stats['playtime'];\r
+ $this->num_songs_played = $stats['songs_played'];\r
+ $this->num_artists = $stats['num_artists'];\r
+ $this->num_songs = $stats['num_songs'];\r
+ $this->num_albums = $stats['num_albums'];\r
+ return TRUE;\r
+ }\r
+\r
+ /* ------------------ DEPRECATED METHODS -------------------*/\r
+ /* GetStatistics() \r
+ * \r
+ * Retrieves the 'statistics' variables from the server and tosses them into an array.\r
+ *\r
+ * NOTE: This function really should not be used. Instead, use $this->[variable]. The function\r
+ * will most likely be deprecated in future releases.\r
+ */\r
+ function GetStatistics() {\r
+ if ( $this->debugging ) echo "mpd->GetStatistics()\n";\r
+ $stats = $this->SendCommand(MPD_CMD_STATISTICS);\r
+ if ( !$stats ) {\r
+ return NULL;\r
+ } else {\r
+ $statsArray = array();\r
+ $statsLine = strtok($stats,"\n");\r
+ while ( $statsLine ) {\r
+ list ( $element, $value ) = explode(": ",$statsLine);\r
+ $statsArray[$element] = $value;\r
+ $statsLine = strtok("\n");\r
+ } \r
+ }\r
+ if ( $this->debugging ) echo "mpd->GetStatistics() / return: " . print_r($statsArray) ."\n";\r
+ return $statsArray;\r
+ }\r
+\r
+ /* GetStatus() \r
+ * \r
+ * Retrieves the 'status' variables from the server and tosses them into an array.\r
+ *\r
+ * NOTE: This function really should not be used. Instead, use $this->[variable]. The function\r
+ * will most likely be deprecated in future releases.\r
+ */\r
+ function GetStatus() {\r
+ if ( $this->debugging ) echo "mpd->GetStatus()\n";\r
+ $status = $this->SendCommand(MPD_CMD_STATUS);\r
+ if ( ! $status ) {\r
+ return NULL;\r
+ } else {\r
+ $statusArray = array();\r
+ $statusLine = strtok($status,"\n");\r
+ while ( $statusLine ) {\r
+ list ( $element, $value ) = explode(": ",$statusLine);\r
+ $statusArray[$element] = $value;\r
+ $statusLine = strtok("\n");\r
+ }\r
+ }\r
+ if ( $this->debugging ) echo "mpd->GetStatus() / return: " . print_r($statusArray) ."\n";\r
+ return $statusArray;\r
+ }\r
+\r
+ /* GetVolume() \r
+ * \r
+ * Retrieves the mixer volume from the server.\r
+ *\r
+ * NOTE: This function really should not be used. Instead, use $this->volume. The function\r
+ * will most likely be deprecated in future releases.\r
+ */\r
+ function GetVolume() {\r
+ if ( $this->debugging ) echo "mpd->GetVolume()\n";\r
+ $volLine = $this->SendCommand(MPD_CMD_STATUS);\r
+ if ( ! $volLine ) {\r
+ return NULL;\r
+ } else {\r
+ list ($vol) = sscanf($volLine,"volume: %d");\r
+ }\r
+ if ( $this->debugging ) echo "mpd->GetVolume() / return: $vol\n";\r
+ return $vol;\r
+ }\r
+\r
+ /* GetPlaylist() \r
+ * \r
+ * Retrieves the playlist from the server and tosses it into a multidimensional array.\r
+ *\r
+ * NOTE: This function really should not be used. Instead, use $this->playlist. The function\r
+ * will most likely be deprecated in future releases.\r
+ */\r
+ function GetPlaylist() {\r
+ if ( $this->debugging ) echo "mpd->GetPlaylist()\n";\r
+ $resp = $this->SendCommand(MPD_CMD_PLLIST);\r
+ $playlist = $this->_parseFileListResponse($resp);\r
+ if ( $this->debugging ) echo "mpd->GetPlaylist() / return ".print_r($playlist)."\n";\r
+ return $playlist;\r
+ }\r
+\r
+ /* ----------------- Command compatibility tables --------------------- */\r
+ var $COMPATIBILITY_MIN_TBL = array(\r
+ );\r
+\r
+ var $COMPATIBILITY_MAX_TBL = array(\r
+ );\r
+\r
+} // ---------------------------- end of class ------------------------------\r
+?>\r