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);
|
|
|