PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/inc/mpd.class.php

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