module.misc.cue.php 8.7 KB

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