PageRenderTime 62ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/classes/mpdSystem.class.php

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