module.misc.cue.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. // also https://github.com/JamesHeinrich/getID3 //
  7. /////////////////////////////////////////////////////////////////
  8. // See readme.txt for more details //
  9. /////////////////////////////////////////////////////////////////
  10. // //
  11. // module.misc.cue.php //
  12. // module for analyzing CUEsheet files //
  13. // dependencies: NONE //
  14. // //
  15. /////////////////////////////////////////////////////////////////
  16. // //
  17. // Module originally written [2009-Mar-25] by //
  18. // Nigel Barnes <ngbarnesØhotmail*com> //
  19. // Minor reformatting and similar small changes to integrate //
  20. // into getID3 by James Heinrich <info@getid3.org> //
  21. // ///
  22. /////////////////////////////////////////////////////////////////
  23. /*
  24. * CueSheet parser by Nigel Barnes.
  25. *
  26. * This is a PHP conversion of CueSharp 0.5 by Wyatt O'Day (wyday.com/cuesharp)
  27. */
  28. /**
  29. * A CueSheet class used to open and parse cuesheets.
  30. *
  31. */
  32. class getid3_cue extends getid3_handler
  33. {
  34. public $cuesheet = array();
  35. public function Analyze() {
  36. $info = &$this->getid3->info;
  37. $info['fileformat'] = 'cue';
  38. $this->readCueSheetFilename($info['filenamepath']);
  39. $info['cue'] = $this->cuesheet;
  40. return true;
  41. }
  42. public function readCueSheetFilename($filename)
  43. {
  44. $filedata = file_get_contents($filename);
  45. return $this->readCueSheet($filedata);
  46. }
  47. /**
  48. * Parses a cue sheet file.
  49. *
  50. * @param string $filename - The filename for the cue sheet to open.
  51. */
  52. public function readCueSheet(&$filedata)
  53. {
  54. $cue_lines = array();
  55. foreach (explode("\n", str_replace("\r", null, $filedata)) as $line)
  56. {
  57. if ( (strlen($line) > 0) && ($line[0] != '#'))
  58. {
  59. $cue_lines[] = trim($line);
  60. }
  61. }
  62. $this->parseCueSheet($cue_lines);
  63. return $this->cuesheet;
  64. }
  65. /**
  66. * Parses the cue sheet array.
  67. *
  68. * @param array $file - The cuesheet as an array of each line.
  69. */
  70. public function parseCueSheet($file)
  71. {
  72. //-1 means still global, all others are track specific
  73. $track_on = -1;
  74. for ($i=0; $i < count($file); $i++)
  75. {
  76. list($key) = explode(' ', strtolower($file[$i]), 2);
  77. switch ($key)
  78. {
  79. case 'catalog':
  80. case 'cdtextfile':
  81. case 'isrc':
  82. case 'performer':
  83. case 'songwriter':
  84. case 'title':
  85. $this->parseString($file[$i], $track_on);
  86. break;
  87. case 'file':
  88. $currentFile = $this->parseFile($file[$i]);
  89. break;
  90. case 'flags':
  91. $this->parseFlags($file[$i], $track_on);
  92. break;
  93. case 'index':
  94. case 'postgap':
  95. case 'pregap':
  96. $this->parseIndex($file[$i], $track_on);
  97. break;
  98. case 'rem':
  99. $this->parseComment($file[$i], $track_on);
  100. break;
  101. case 'track':
  102. $track_on++;
  103. $this->parseTrack($file[$i], $track_on);
  104. if (isset($currentFile)) // if there's a file
  105. {
  106. $this->cuesheet['tracks'][$track_on]['datafile'] = $currentFile;
  107. }
  108. break;
  109. default:
  110. //save discarded junk and place string[] with track it was found in
  111. $this->parseGarbage($file[$i], $track_on);
  112. break;
  113. }
  114. }
  115. }
  116. /**
  117. * Parses the REM command.
  118. *
  119. * @param string $line - The line in the cue file that contains the TRACK command.
  120. * @param integer $track_on - The track currently processing.
  121. */
  122. public function parseComment($line, $track_on)
  123. {
  124. $explodedline = explode(' ', $line, 3);
  125. $comment_REM = (isset($explodedline[0]) ? $explodedline[0] : '');
  126. $comment_type = (isset($explodedline[1]) ? $explodedline[1] : '');
  127. $comment_data = (isset($explodedline[2]) ? $explodedline[2] : '');
  128. if (($comment_REM == 'REM') && $comment_type) {
  129. $comment_type = strtolower($comment_type);
  130. $commment_data = trim($comment_data, ' "');
  131. if ($track_on != -1) {
  132. $this->cuesheet['tracks'][$track_on]['comments'][$comment_type][] = $comment_data;
  133. } else {
  134. $this->cuesheet['comments'][$comment_type][] = $comment_data;
  135. }
  136. }
  137. }
  138. /**
  139. * Parses the FILE command.
  140. *
  141. * @param string $line - The line in the cue file that contains the FILE command.
  142. * @return array - Array of FILENAME and TYPE of file..
  143. */
  144. public function parseFile($line)
  145. {
  146. $line = substr($line, strpos($line, ' ') + 1);
  147. $type = strtolower(substr($line, strrpos($line, ' ')));
  148. //remove type
  149. $line = substr($line, 0, strrpos($line, ' ') - 1);
  150. //if quotes around it, remove them.
  151. $line = trim($line, '"');
  152. return array('filename'=>$line, 'type'=>$type);
  153. }
  154. /**
  155. * Parses the FLAG command.
  156. *
  157. * @param string $line - The line in the cue file that contains the TRACK command.
  158. * @param integer $track_on - The track currently processing.
  159. */
  160. public function parseFlags($line, $track_on)
  161. {
  162. if ($track_on != -1)
  163. {
  164. foreach (explode(' ', strtolower($line)) as $type)
  165. {
  166. switch ($type)
  167. {
  168. case 'flags':
  169. // first entry in this line
  170. $this->cuesheet['tracks'][$track_on]['flags'] = array(
  171. '4ch' => false,
  172. 'data' => false,
  173. 'dcp' => false,
  174. 'pre' => false,
  175. 'scms' => false,
  176. );
  177. break;
  178. case 'data':
  179. case 'dcp':
  180. case '4ch':
  181. case 'pre':
  182. case 'scms':
  183. $this->cuesheet['tracks'][$track_on]['flags'][$type] = true;
  184. break;
  185. default:
  186. break;
  187. }
  188. }
  189. }
  190. }
  191. /**
  192. * Collect any unidentified data.
  193. *
  194. * @param string $line - The line in the cue file that contains the TRACK command.
  195. * @param integer $track_on - The track currently processing.
  196. */
  197. public function parseGarbage($line, $track_on)
  198. {
  199. if ( strlen($line) > 0 )
  200. {
  201. if ($track_on == -1)
  202. {
  203. $this->cuesheet['garbage'][] = $line;
  204. }
  205. else
  206. {
  207. $this->cuesheet['tracks'][$track_on]['garbage'][] = $line;
  208. }
  209. }
  210. }
  211. /**
  212. * Parses the INDEX command of a TRACK.
  213. *
  214. * @param string $line - The line in the cue file that contains the TRACK command.
  215. * @param integer $track_on - The track currently processing.
  216. */
  217. public function parseIndex($line, $track_on)
  218. {
  219. $type = strtolower(substr($line, 0, strpos($line, ' ')));
  220. $line = substr($line, strpos($line, ' ') + 1);
  221. if ($type == 'index')
  222. {
  223. //read the index number
  224. $number = intval(substr($line, 0, strpos($line, ' ')));
  225. $line = substr($line, strpos($line, ' ') + 1);
  226. }
  227. //extract the minutes, seconds, and frames
  228. $explodedline = explode(':', $line);
  229. $minutes = (isset($explodedline[0]) ? $explodedline[0] : '');
  230. $seconds = (isset($explodedline[1]) ? $explodedline[1] : '');
  231. $frames = (isset($explodedline[2]) ? $explodedline[2] : '');
  232. switch ($type) {
  233. case 'index':
  234. $this->cuesheet['tracks'][$track_on][$type][$number] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames));
  235. break;
  236. case 'pregap':
  237. case 'postgap':
  238. $this->cuesheet['tracks'][$track_on][$type] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames));
  239. break;
  240. }
  241. }
  242. public function parseString($line, $track_on)
  243. {
  244. $category = strtolower(substr($line, 0, strpos($line, ' ')));
  245. $line = substr($line, strpos($line, ' ') + 1);
  246. //get rid of the quotes
  247. $line = trim($line, '"');
  248. switch ($category)
  249. {
  250. case 'catalog':
  251. case 'cdtextfile':
  252. case 'isrc':
  253. case 'performer':
  254. case 'songwriter':
  255. case 'title':
  256. if ($track_on == -1)
  257. {
  258. $this->cuesheet[$category] = $line;
  259. }
  260. else
  261. {
  262. $this->cuesheet['tracks'][$track_on][$category] = $line;
  263. }
  264. break;
  265. default:
  266. break;
  267. }
  268. }
  269. /**
  270. * Parses the TRACK command.
  271. *
  272. * @param string $line - The line in the cue file that contains the TRACK command.
  273. * @param integer $track_on - The track currently processing.
  274. */
  275. public function parseTrack($line, $track_on)
  276. {
  277. $line = substr($line, strpos($line, ' ') + 1);
  278. $track = ltrim(substr($line, 0, strpos($line, ' ')), '0');
  279. //find the data type.
  280. $datatype = strtolower(substr($line, strpos($line, ' ') + 1));
  281. $this->cuesheet['tracks'][$track_on] = array('track_number'=>$track, 'datatype'=>$datatype);
  282. }
  283. }