#!/usr/bin/php 0.3, 'duration' => 6, 'bitRate' => 6, 'sampleRate' => 6, 'song' => 0.13, 'artist' => 0.125, 'track' => 5, 'parseTime' => 4, ); /** @var string */ protected $songRowTempalte; /** @var bool */ protected $compareWithId3; protected $totalDuration = 0; protected $totalParseTime = 0; protected $totalId3ParseTime = 0; /** * @param array $fileNames * @param bool $verbose */ public function run(array $fileNames, $verbose = false) { $this->adjustOutputSize(); $this->songRowTempalte = '%'.$this->widths['filename'].'s | %'.$this->widths['duration'].'s | %'.$this->widths['bitRate'].'s | %'.$this->widths['sampleRate'].'s | %' .$this->widths['song'].'s | %'.$this->widths['artist'].'s | %'.$this->widths['track'].'s | %'.$this->widths['parseTime'].'s'; $this->compareWithId3 = class_exists('getID3'); echo sprintf($this->songRowTempalte, 'File name', 'dur.', 'bitrate', 'sample', 'song', 'artist', 'track', 'time').PHP_EOL; foreach ($fileNames as $originalFile) { $file = realpath($originalFile); if (is_dir($file)) { echo $file.':'.PHP_EOL; foreach (glob(rtrim($file, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.'*.mp3') as $f) { if (is_file($f)) { $this->analyze($f, false, $verbose); if ($this->compareWithId3) $this->analyzeId3($f); } } } else if (is_file($file)) { $this->analyze($file, true, $verbose); if ($this->compareWithId3) $this->analyzeId3($file); } else if (strpos($originalFile, '://') !== false) { $this->analyze($originalFile, true, $verbose); } } echo sprintf('%42s | %34s', 'Total duration: '.self::formatTime($this->totalDuration), 'Total parsing time: '.round($this->totalParseTime, 5)).PHP_EOL; if ($this->compareWithId3) echo sprintf('%79s', 'Total getId3 parsing time: '.round($this->totalId3ParseTime, 5)).PHP_EOL; } /** * @param $time * * @return string */ public static function formatTime($time) { if ($time > 3600) return floor($time / 3600) .':'.str_pad(floor($time % 3600 / 60), 2, 0, STR_PAD_LEFT) .':'.str_pad($time % 60, 2, 0, STR_PAD_LEFT); else return floor($time / 60) .':'.str_pad($time % 60, 2, 0, STR_PAD_LEFT); } /** * @param $string * @param $maxLength * * @return string */ public static function substrIfLonger($string, $maxLength) { if (mb_strlen($string) > $maxLength) { return mb_substr($string, 0, $maxLength-3).'...'; } return $string; } /** * */ protected function adjustOutputSize() { $terminal_width = 80; foreach ($this->widths as $element => $width) { if ($width >= 1) { continue; } $this->widths[$element] = ceil($width * $terminal_width); } } /** * @param $filename * @param bool $id3v2 * * @param bool $verbose * * @return null|void */ protected function analyze($filename, $id3v2 = false, $verbose = false) { if (!is_readable($filename) && strpos($filename, '://') === false) return; try { $audio = new Mp3Info($filename, true); } catch (Exception $e) { echo "Exception when parsing ".$filename.': '.$e->getMessage().PHP_EOL; return null; } echo sprintf($this->songRowTempalte, self::convertToNativeEncoding(self::substrIfLonger(basename($filename), $this->widths['filename'])), self::formatTime($audio->duration), $audio->isVbr ? 'vbr' : ($audio->bitRate / 1000).'kbps', ($audio->sampleRate / 1000), isset($audio->tags['song']) ? self::substrIfLonger($audio->tags['song'], 11) : null, isset($audio->tags['artist']) ? self::substrIfLonger($audio->tags['artist'], 10) : null, isset($audio->tags['track']) ? self::substrIfLonger($audio->tags['track'], 5) : null, $audio->_parsingTime) .PHP_EOL; if ($id3v2 && !empty($audio->tags2)) { foreach ($audio->tags as $tag => $value) { echo ' '.$tag.': '; echo self::convertToNativeEncoding($value).PHP_EOL; } } if ($verbose) { print_r(array_intersect_key(get_object_vars($audio), array_flip([ 'codecVersion', 'layerVersion', 'duration', 'bitRate', 'sampleRate', 'isVbr', 'hasCover', 'channel', 'tags', 'tags1', 'tags2', 'id3v2MajorVersion', 'id3v2MinorVersion', ]))); } $this->totalDuration += $audio->duration; $this->totalParseTime += $audio->_parsingTime; } /** * @param $filename */ protected function analyzeId3($filename) { static $ID3; if ($ID3 === null) $ID3 = new getID3(); $t = microtime(true); $info = $ID3->analyze($filename); $parse_time = microtime(true) - $t; echo sprintf($this->songRowTempalte, self::substrIfLonger(basename($filename), $this->widths['filename']), $info['playtime_string'], $info['audio']['bitrate_mode'] == 'vbr' ? 'vbr' : floor($info['audio']['bitrate'] / 1000).'kbps', ($info['audio']['sample_rate'] / 1000), isset($info['tags']['title']) ? self::substrIfLonger($info['tags']['title'], 11) : null, isset($info['tags']['artist']) ? self::substrIfLonger($info['tags']['artist'], 10) : null, null, $parse_time) .PHP_EOL; $this->totalId3ParseTime += $parse_time; } protected static function convertToNativeEncoding($string) { // if (strncasecmp(PHP_OS, 'win', 3) === 0) // return mb_convert_encoding($string, 'cp1251', 'utf-8'); return $string; } } array_shift($argv); $verbose = false; if (in_array('-v', $argv, true)) { $verbose = true; unset($argv[array_search('-v', $argv, true)]); } $runner = new Mp3InfoConsoleRunner(); $runner->run($argv, $verbose);