1<?php 2 3/** 4 * Class representing an audio-CD with CDDB information 5 * 6 * @author Keith Palmer <Keith@UglySlug.com> 7 * @category Net 8 * @package Net_CDDB 9 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 10 */ 11 12/** 13 * Require CDDB class, we need the constants 14 */ 15require_once 'Net/CDDB.php'; 16 17/** 18 * Require the CDDB Track class, so we can assign tracks to discs... 19 */ 20require_once 'Net/CDDB/Track.php'; 21 22/** 23 * Class representing an audio-CD with CDDB information 24 * 25 * This class has methods to access all of the information a CDDB server has 26 * available about a specific audio CD. 27 * 28 * @package Net_CDDB 29 */ 30class Net_CDDB_Disc 31{ 32 /** 33 * Array of tracks for the disc, {@link Net_CDDB_Track} objects 34 * 35 * @var array 36 * @access protected 37 */ 38 var $_tracks; 39 40 /** 41 * Artist name 42 * 43 * @var string 44 * @access protected 45 */ 46 var $_artist; 47 48 /** 49 * Disc/audio CD title 50 * 51 * @var string 52 * @access protected 53 */ 54 var $_title; 55 56 /** 57 * 8-char discid field 58 * 59 * @var string 60 * @access protected 61 */ 62 var $_discid; 63 64 /** 65 * CDDB category string (the directory the disc record is stored in) 66 * 67 * @var string 68 * @access protected 69 */ 70 var $_category; 71 72 /** 73 * CDDB genre string 74 * 75 * @var string 76 * @access protected 77 */ 78 var $_genre; 79 80 /** 81 * Year audio CD was published 82 * 83 * @var integer 84 * @access protected 85 */ 86 var $_year; 87 88 /** 89 * Length in seconds of the audio-CD 90 * 91 * @var integer 92 * @access protected 93 */ 94 var $_length; 95 96 /** 97 * Playorder of tracks ( optional CDDB attribute ) 98 * 99 * @var string 100 * @access protected 101 */ 102 var $_playorder; 103 104 /** 105 * CDDB revision attribute 106 * 107 * @var integer 108 * @access protected 109 */ 110 var $_revision; 111 112 /** 113 * The program which submitted this record 114 * 115 * @var string 116 * @access protected 117 */ 118 var $_submitted_via; 119 120 /** 121 * The program which processing the record submission 122 * 123 * @var string 124 * @access protected 125 */ 126 var $_processed_by; 127 128 /** 129 * Revision id if we've edited the record 130 * 131 * @var integer 132 * @access protected 133 */ 134 var $_this_revision; 135 136 /** 137 * Construct a new Net_CDDB_Disc object 138 * 139 * The Net_CDDB_Disc actually supports two differnet methods of constructing 140 * a Net_CDDB_Disc object. The first is to provide all of the parameters. 141 * An alternative constructor allows passing an associative array as the 142 * first *and only* parameter with the following keys: 143 * - discid, 8-char discid 144 * - dartist, string artist name 145 * - dtitle, string title of the cd 146 * - dgenre, string genre of the cd 147 * - dyear, integer year the cd was published 148 * - tracks, array of either {@link Net_CDDB_Track} objects or of arrays containing keys to construct a {@link Net_CDDB_Track} object with 149 * - dlength, length of disc (in seconds) 150 * - revision, CDDB record revision # of disc 151 * - playorder, string describing custom track play order 152 * 153 * @access public 154 * @todo Make sure documentation about field names is correct and complete 155 * 156 * @param string $arr_or_discid *See note above!* 157 * @param string $dartist 158 * @param string $dtitle 159 * @param string $category 160 * @param string $dgenre 161 * @param integer $dyear 162 * @param array $tracks An array of {@link Net_CDDB_Track} objects or an array of arrays to construct {@link Net_CDDB_Track} objects with 163 * @param integer $dlength 164 * @param integer $revision The CDDB revision from the CDDB record 165 * @param string $playorder Optional play-order of the tracks 166 */ 167 function Net_CDDB_Disc($arr_or_discid, $dartist = '', $dtitle = '', $category = '', $dgenre = '', $dyear = '', $tracks = array(), $dlength = 0, $revision = 0, $playorder = '', $submitted_via = '', $processed_by = '') 168 { 169 if (is_array($arr_or_discid)) // If the first parameter is an array, we'll treat this as an associative array constructor 170 { 171 $defaults = array( 172 'discid' => '', 173 'dartist' => '', 174 'dtitle' => '', 175 'category' => '', 176 'dgenre' => '', 177 'dyear' => '', 178 'tracks' => array(), 179 //'extras' => array(), 180 //'offsets' => array(), 181 'dlength' => 0, 182 'revision' => 0, 183 'submitted_via' => '', 184 'processed_by' => '', 185 'playorder' => '' 186 ); 187 188 $arr_or_discid = array_merge($defaults, $arr_or_discid); // Ensure all required variables are set 189 $arr_or_discid['arr_or_discid'] = $arr_or_discid['discid']; 190 191 extract($arr_or_discid); // Extract into local scope so we can assign next 192 } 193 194 $this->_discid = substr(str_pad($arr_or_discid, 8), 0, 8); 195 $this->_artist = '' . $dartist; 196 $this->_title = '' . $dtitle; 197 $this->_category = $category; 198 $this->_genre = '' . $dgenre; 199 $this->_year = (int) $dyear; 200 $this->_length = (int) $dlength; 201 $this->_revision = (int) $revision; 202 $this->_playorder = $playorder; 203 $this->_submitted_via = $submitted_via; 204 $this->_processed_by = $processed_by; 205 206 // Assign the tracks 207 foreach ($tracks as $track) { 208 if (is_array($track)) { 209 $this->_tracks[] = new Net_CDDB_Track($track); 210 } else if (is_a($track, 'Net_CDDB_Track')) { 211 $this->_tracks[] = $track; 212 } 213 } 214 215 // Check the first track, if the first track doesn't have a length set, 216 // we'll go ahead and calculate lengths for all of the tracks 217 /*$count = count($this->_tracks); 218 if ($count and !$this->_tracks[0]->getLength()) { 219 $start = $this->_tracks[0]->getOffset(); // Initial disc offset 220 221 for ($i = 1; $i < $count; $i++) { 222 $end = $this->_tracks[$i]->getOffset(); 223 $this->_tracks[$i - 1]->setLength(round(($end - $start) / 75)); // Set track offsets (seconds get rounded) 224 $start = $this->_tracks[$i]->getOffset(); 225 } 226 227 // Set the final track length 228 $this->_tracks[$count - 1]->setLength($this->_length - round($start / 75)); 229 }*/ 230 231 $this->_this_revision = -1; 232 } 233 234 /** 235 * Get the 8-char discid for the disc 236 * 237 * @access public 238 * 239 * @return string 240 */ 241 function getDiscId() 242 { 243 return $this->_discid; 244 } 245 246 /** 247 * Get the artist for the audio CD 248 * 249 * @access public 250 * 251 * @return string 252 */ 253 function getArtist() 254 { 255 return $this->_artist; 256 } 257 258 /** 259 * Get the title of this disc 260 * 261 * @access public 262 * 263 * @return string 264 */ 265 function getTitle() 266 { 267 return $this->_title; 268 } 269 270 /** 271 * Get the category this disc is stored in (directory on CDDB server) 272 * 273 * CDDB servers usually maintain about 11 different categories for discs 274 * which (very roughly) correspond to a few different genres of music. The 275 * category is needed for disc submission and CDDB reads. There is also a 276 * free-form 'genre' field stored with each disc record which should be used 277 * for a more accurate disc genre description. 278 * 279 * @see Net_CDDB_Disc::getGenre() 280 * 281 * @access public 282 * 283 * @return string 284 */ 285 function getCategory() 286 { 287 return $this->_category; 288 } 289 290 /** 291 * Get the genre this disc belongs to 292 * 293 * @access public 294 * 295 * @return string 296 */ 297 function getGenre() 298 { 299 return $this->_genre; 300 } 301 302 /** 303 * Get the number of tracks the CD contains 304 * 305 * @access public 306 * 307 * @return integer 308 */ 309 function numTracks() 310 { 311 return count($this->_tracks); 312 } 313 314 /** 315 * Get the track title for a specific track number ( track #s start at 0 ) 316 * 317 * <code> 318 * print("The title of the first song is: "); 319 * $disc->getTrackTitle(0); 320 * </code> 321 * 322 * @access public 323 * @see Net_CDDB_Disc::getTrack() 324 * @see Net_CDDB_Track 325 * 326 * @param integer $track_num 327 * @return string 328 */ 329 function getTrackTitle($track_num) 330 { 331 if ($track = $this->getTrack($track_num)) { 332 return $track->getTitle(); 333 } else { 334 return null; 335 } 336 } 337 338 /** 339 * Get the track offset for a specific track 340 * 341 * @access public 342 * @see Net_CDDB_Disc::getTrack() 343 * @see Net_CDDB_Track 344 * 345 * @param integer $track_num 346 * @return integer 347 */ 348 function getTrackOffset($track_num) 349 { 350 if ($track = $this->getTrack($track_num)) { 351 return $track->getOffset(); 352 } else { 353 return null; 354 } 355 } 356 357 /** 358 * Get the track length for the given track number 359 * 360 * @access public 361 * @see Net_CDDB_Disc::getTrack() 362 * @see Net_CDDB_Track 363 * 364 * @param integer $track_num 365 * @param boolean $formatted 366 * @return mixed 367 */ 368 function getTrackLength($track_num, $formatted = false) 369 { 370 if ($track = $this->getTrack($track_num)) { 371 return $track->getLength($formatted); 372 } 373 return null; 374 } 375 376 /** 377 * Get the extra data for the given track number 378 * 379 * @access public 380 * @see Net_CDDB_Disc::getTrack() 381 * 382 * @param integer $track_num 383 * @return string 384 */ 385 function getTrackExtraData($track_num) 386 { 387 if ($track = $this->getTrack($track_num)) { 388 return $track->getExtraData(); 389 } 390 return null; 391 } 392 393 /** 394 * Get the track artist for the given track number 395 * 396 * @access public 397 * @see Net_CDDB_Disc::getTrack() 398 * @param integer $track_num 399 * @return string 400 */ 401 function getTrackArtist($track_num) 402 { 403 if ($track = $this->getTrack($track_num)) { 404 return $track->getArtist(); 405 } 406 return null; 407 } 408 409 /** 410 * Get the {@link Net_CDDB_Track} object representing the given track number 411 * 412 * @access public 413 * 414 * @param integer $track_num 415 * @return Net_CDDB_Track 416 */ 417 function getTrack($track_num) 418 { 419 if (isset($this->_tracks[$track_num])) { 420 return $this->_tracks[$track_num]; 421 } 422 return null; 423 } 424 425 /** 426 * Retrieve the length of this disc in seconds 427 * 428 * @access public 429 * @param bool $formatted Whether or not to return in string format: HH:MM:SS ( defaults to returning an integer number of seconds in length ) 430 * @return integer 431 */ 432 function getDiscLength($formatted = false) 433 { 434 if ($formatted) { 435 $hours = floor($this->_length / (60 * 60)); 436 $minutes = floor(($this->_length / 60) % 60); 437 $seconds = $this->_length % 60; 438 439 return sprintf('%02d', $hours) . ':' . sprintf('%02d', $minutes) . ':' . sprintf('%02d', $seconds); 440 } else { 441 return $this->_length; 442 } 443 } 444 445 /** 446 * Retrieve the year this disc was published 447 * 448 * @access public 449 * @return integer 450 */ 451 function getDiscYear() 452 { 453 return $this->_year; 454 } 455 456 /** 457 * Get the record revision number 458 * 459 * @access public 460 * @return integer 461 */ 462 function getRevision() 463 { 464 return $this->_revision; 465 } 466 467 /** 468 * Get the name of the program which processed the disc 469 * 470 * @access public 471 * @return string 472 */ 473 function getProcessedBy() 474 { 475 return $this->_processed_by; 476 } 477 478 /** 479 * Get the name of the program that submitted the disc record 480 * 481 * @access public 482 * @return string 483 */ 484 function getSubmittedVia() 485 { 486 return $this->_submitted_via; 487 } 488 489 /** 490 * Get any extra data associated with the disc 491 * 492 * @todo Finish supporting this 493 * @access public 494 * @return string 495 */ 496 function getDiscExtraData() 497 { 498 return ''; 499 } 500 501 /** 502 * Get the playorder of the disc 503 * 504 * @todo Make sure this actually works 505 * @access public 506 * @return string 507 */ 508 function getDiscPlayorder() 509 { 510 return $this->_playorder; 511 } 512 513 /** 514 * Return a string representation of this CDDB Disc ( the CDDB file format ) 515 * 516 * @todo Make EXTD data field work 517 * @todo Probably should return an *exact* copy of already submitted record (submitted by, processed by are optoinal) 518 * 519 * @access public 520 * 521 * @return string 522 */ 523 function toString() 524 { 525 $str = "# xcmd\r\n"; 526 $str .= "#\r\n"; 527 $str .= "# Track frame offsets:\r\n"; 528 529 foreach ($this->_tracks as $track) { 530 $str .= '# ' . $track->getOffset() . "\r\n"; 531 } 532 533 //foreach ($this->_offsets as $key => $offset) { 534 // $str .= '# ' . $offset . "\r\n"; 535 //} 536 537 $str .= "#\r\n"; 538 $str .= '# Disc length: ' . $this->_length . " seconds\r\n"; 539 $str .= "#\r\n"; 540 $str .= "# Revision: " . $this->_revision . "\r\n"; 541 $str .= "# Submitted via: " . $this->_submitted_via . "\r\n"; 542 $str .= "# Processed by: " . $this->_processed_by . "\r\n"; 543 $str .= "#\r\n"; 544 $str .= 'DISCID=' . $this->_discid . "\r\n"; 545 $str .= 'DTITLE=' . $this->_artist . ' / ' . $this->_title . "\r\n"; 546 $str .= 'DYEAR=' . $this->_year . "\r\n"; 547 $str .= 'DGENRE=' . $this->_genre . "\r\n"; 548 549 foreach ($this->_tracks as $key => $track) { 550 if ($track->getArtist() != $this->_artist) { 551 $str .= 'TTITLE' . $key . '=' . $track->getArtist() . ' / ' . $track->getTitle() . "\r\n"; 552 } else { 553 $str .= 'TTITLE' . $key . '=' . $track->getTitle() . "\r\n"; 554 } 555 } 556 557 $str .= 'EXTD=' . "\r\n"; 558 559 foreach ($this->_tracks as $key => $track) { 560 $str .= 'EXTT' . $key . '=' . $track->getExtraData() . "\r\n"; 561 } 562 563 $str .= 'PLAYORDER=' . $this->_playorder . "\r\n"; 564 565 return trim($str); 566 } 567} 568 569?>