232 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/php
 | |
| <?php
 | |
| use wapmorgan\Mp3Info\Mp3Info;
 | |
| 
 | |
| $paths = [
 | |
|     // as a root package or phar
 | |
|     __DIR__.'/../vendor/autoload.php',
 | |
|     // as a dependency from bin
 | |
|     __DIR__.'/../autoload.php',
 | |
|     // as a dependency from package folder
 | |
|     __DIR__.'/../../../autoload.php',
 | |
| ];
 | |
| function init_composer(array $paths) {
 | |
|     foreach ($paths as $path) {
 | |
|         if (file_exists($path)) {
 | |
|             require_once $path;
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| if (!init_composer($paths)) die('Run `composer install` firstly.'.PHP_EOL);
 | |
| if ($argc == 1)
 | |
|     die('Specify file names to scan');
 | |
| 
 | |
| class Mp3InfoConsoleRunner {
 | |
| 
 | |
|     /** @var array */
 | |
|     protected $widths = array(
 | |
|         'filename' => 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((int)$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);
 | |
| 
 |