From d70262b3dc51f24a406c9d07e08b0af599249953 Mon Sep 17 00:00:00 2001 From: Lawrence Onah Date: Sat, 7 Aug 2021 14:27:12 +0100 Subject: [PATCH 1/2] Improved PSR-4 code compliance and minor refactoring --- bin/mp3scan | 78 +++++++++++++++----------- composer.json | 2 +- data/bitRateTable.php | 17 +++--- data/sampleRateTable.php | 3 +- src/Mp3Info.php | 117 ++++++++++++++++++++++++--------------- 5 files changed, 132 insertions(+), 85 deletions(-) diff --git a/bin/mp3scan b/bin/mp3scan index d2b97d6..ca940a4 100644 --- a/bin/mp3scan +++ b/bin/mp3scan @@ -1,16 +1,23 @@ #!/usr/bin/php 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->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; + 'time') . PHP_EOL; foreach ($fileNames as $file) { $file = realpath($file); if (is_dir($file)) { - echo $file.':'.PHP_EOL; - foreach (glob(rtrim($file, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.'*.mp3') as $f) { + 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); @@ -78,9 +87,9 @@ class Mp3InfoConsoleRunner { } - echo sprintf('%42s | %34s', 'Total duration: '.self::formatTime($this->totalDuration), 'Total parsing time: '.round($this->totalParseTime, 5)).PHP_EOL; + 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; + echo sprintf('%79s', 'Total getId3 parsing time: ' . round($this->totalId3ParseTime, 5)) . PHP_EOL; } /** @@ -88,14 +97,15 @@ class Mp3InfoConsoleRunner { * * @return string */ - public static function formatTime($time) { + 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); + . ':' . 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); + . ':' . str_pad($time % 60, 2, 0, STR_PAD_LEFT); } /** @@ -104,9 +114,10 @@ class Mp3InfoConsoleRunner { * * @return string */ - public static function substrIfLonger($string, $maxLength) { + public static function substrIfLonger($string, $maxLength) + { if (mb_strlen($string) > $maxLength) { - return mb_substr($string, 0, $maxLength-3).'...'; + return mb_substr($string, 0, $maxLength - 3) . '...'; } return $string; } @@ -134,30 +145,31 @@ class Mp3InfoConsoleRunner { * * @return null|void */ - protected function analyze($filename, $id3v2 = false, $verbose = false) { + protected function analyze($filename, $id3v2 = false, $verbose = false) + { if (!is_readable($filename)) return; try { $audio = new Mp3Info($filename, true); } catch (Exception $e) { - var_dump("Exception when parsing ".$filename.': '.$e->getMessage()); + var_dump("Exception when parsing " . $filename . ': ' . $e->getMessage()); 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->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; + . PHP_EOL; if ($id3v2 && !empty($audio->tags2)) { foreach ($audio->tags as $tag => $value) { - echo ' '.$tag.': '; - echo self::convertToNativeEncoding($value).PHP_EOL; + echo ' ' . $tag . ': '; + echo self::convertToNativeEncoding($value) . PHP_EOL; } } @@ -172,7 +184,8 @@ class Mp3InfoConsoleRunner { /** * @param $filename */ - protected function analyzeId3($filename) { + protected function analyzeId3($filename) + { static $ID3; if ($ID3 === null) $ID3 = new getID3(); @@ -182,18 +195,22 @@ class Mp3InfoConsoleRunner { 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']['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; + . PHP_EOL; $this->totalId3ParseTime += $parse_time; } + /** + * @param $string + * @return mixed + */ protected static function convertToNativeEncoding($string) { // if (strncasecmp(PHP_OS, 'win', 3) === 0) @@ -211,4 +228,3 @@ if (in_array('-v', $argv, true)) { $runner = new Mp3InfoConsoleRunner(); $runner->run($argv, $verbose); - diff --git a/composer.json b/composer.json index 781b7e4..e628c04 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "description": "The fastest php library to extract mp3 tags & meta information.", "autoload": { "psr-4": { - "wapmorgan\\Mp3Info\\": "src/" + "Wapmorgan\\Mp3Info\\": "src/" } }, "require": { diff --git a/data/bitRateTable.php b/data/bitRateTable.php index 8101334..e30bd33 100644 --- a/data/bitRateTable.php +++ b/data/bitRateTable.php @@ -1,16 +1,17 @@ [ - 1 => [null, 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, false], // MPEG 1 layer 1 - 2 => [null, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, false], // MPEG 1 layer 2 - 3 => [null, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, false], // MPEG 1 layer 3 + 1 => [null, 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, false], // MPEG 1 layer 1 + 2 => [null, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, false], // MPEG 1 layer 2 + 3 => [null, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, false], // MPEG 1 layer 3 ], - Mp3Info::MPEG_2 => [ - 1 => [null, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000, false], // MPEG 2 layer 1 - 2 => [null, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, false], // MPEG 2 layer 2 - 3 => [null, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, false], // MPEG 2 layer 3 + Mp3Info::MPEG_2 => [ + 1 => [null, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000, false], // MPEG 2 layer 1 + 2 => [null, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, false], // MPEG 2 layer 2 + 3 => [null, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, false], // MPEG 2 layer 3 ], ]; diff --git a/data/sampleRateTable.php b/data/sampleRateTable.php index 6bccee3..7fbc9a9 100644 --- a/data/sampleRateTable.php +++ b/data/sampleRateTable.php @@ -1,5 +1,6 @@ [44100, 48000, 32000, false], // MPEG 1 diff --git a/src/Mp3Info.php b/src/Mp3Info.php index 85e430f..349900f 100644 --- a/src/Mp3Info.php +++ b/src/Mp3Info.php @@ -1,5 +1,6 @@ audioSize = $this->parseAudio($this->_fileName = $filename, $this->_fileSize = filesize($filename), $mode); @@ -237,7 +240,8 @@ public function __construct($filename, $parseTags = false) { * @return float|int * @throws \Exception */ - private function parseAudio($filename, $fileSize, $mode) { + private function parseAudio($filename, $fileSize, $mode) + { $time = microtime(true); $fp = fopen($filename, 'rb'); @@ -310,7 +314,8 @@ private function parseAudio($filename, $fileSize, $mode) { * @return int Number of frames (if present if first frame of VBR-file) * @throws \Exception */ - private function readMpegFrame($fp) { + private function readMpegFrame($fp) + { $header_seek_pos = ftell($fp) + self::$headerSeekLimit; do { $pos = ftell($fp); @@ -327,31 +332,53 @@ private function readMpegFrame($fp) { } while (ftell($fp) <= $header_seek_pos); if (!isset($header_bytes) || $header_bytes[0] !== 0xFF || (($header_bytes[1] >> 5) & 0b111) != 0b111) { - throw new \Exception('At '.$pos - .'(0x'.dechex($pos).') should be a frame header!'); + throw new \Exception('At ' . $pos + . '(0x' . dechex($pos) . ') should be a frame header!'); } switch ($header_bytes[1] >> 3 & 0b11) { - case 0b00: $this->codecVersion = self::MPEG_25; break; - case 0b01: $this->codecVersion = self::CODEC_UNDEFINED; break; - case 0b10: $this->codecVersion = self::MPEG_2; break; - case 0b11: $this->codecVersion = self::MPEG_1; break; + case 0b00: + $this->codecVersion = self::MPEG_25; + break; + case 0b01: + $this->codecVersion = self::CODEC_UNDEFINED; + break; + case 0b10: + $this->codecVersion = self::MPEG_2; + break; + case 0b11: + $this->codecVersion = self::MPEG_1; + break; } switch ($header_bytes[1] >> 1 & 0b11) { - case 0b01: $this->layerVersion = self::LAYER_3; break; - case 0b10: $this->layerVersion = self::LAYER_2; break; - case 0b11: $this->layerVersion = self::LAYER_1; break; + case 0b01: + $this->layerVersion = self::LAYER_3; + break; + case 0b10: + $this->layerVersion = self::LAYER_2; + break; + case 0b11: + $this->layerVersion = self::LAYER_1; + break; } $this->bitRate = self::$_bitRateTable[$this->codecVersion][$this->layerVersion][$header_bytes[2] >> 4]; $this->sampleRate = self::$_sampleRateTable[$this->codecVersion][($header_bytes[2] >> 2) & 0b11]; switch ($header_bytes[3] >> 6) { - case 0b00: $this->channel = self::STEREO; break; - case 0b01: $this->channel = self::JOINT_STEREO; break; - case 0b10: $this->channel = self::DUAL_MONO; break; - case 0b11: $this->channel = self::MONO; break; + case 0b00: + $this->channel = self::STEREO; + break; + case 0b01: + $this->channel = self::JOINT_STEREO; + break; + case 0b10: + $this->channel = self::DUAL_MONO; + break; + case 0b11: + $this->channel = self::MONO; + break; } $vbr_offset = self::$_vbrOffsets[$this->codecVersion][$this->channel == self::MONO ? 0 : 1]; @@ -399,11 +426,12 @@ private function readMpegFrame($fp) { * @return array * @throws \Exception */ - private function readBytes($fp, $n) { + private function readBytes($fp, $n) + { $raw = fread($fp, $n); if (strlen($raw) !== $n) throw new \Exception('Unexpected end of file!'); $bytes = array(); - for($i = 0; $i < $n; $i++) $bytes[$i] = ord($raw[$i]); + for ($i = 0; $i < $n; $i++) $bytes[$i] = ord($raw[$i]); return $bytes; } @@ -411,7 +439,8 @@ private function readBytes($fp, $n) { * Reads id3v1 tag. * @return int Returns length of id3v1 tag. */ - private function readId3v1Body($fp) { + private function readId3v1Body($fp) + { $this->tags1['song'] = trim(fread($fp, 30)); $this->tags1['artist'] = trim(fread($fp, 30)); $this->tags1['album'] = trim(fread($fp, 30)); @@ -523,7 +552,7 @@ private function readId3v2Body($fp) } else if ($this->id3v2MajorVersion == 3) { // parse id3v2.3.0 body $this->parseId3v23Body($fp, 10 + $size); - } else if ($this->id3v2MajorVersion == 4) { + } else if ($this->id3v2MajorVersion == 4) { // parse id3v2.4.0 body $this->parseId3v24Body($fp, 10 + $size); } @@ -535,7 +564,8 @@ private function readId3v2Body($fp) * Parses id3v2.3.0 tag body. * @todo Complete. */ - private function parseId3v23Body($fp, $lastByte) { + private function parseId3v23Body($fp, $lastByte) + { while (ftell($fp) < $lastByte) { $raw = fread($fp, 10); $frame_id = substr($raw, 0, 4); @@ -662,8 +692,7 @@ private function parseId3v23Body($fp, $lastByte) { } else # no condition for iso-8859-1 $actual_text = null; - } - else if ($actual_text !== false) $actual_text .= $char; + } else if ($actual_text !== false) $actual_text .= $char; else $short_description .= $char; } if ($actual_text === false) $actual_text = $short_description; @@ -852,8 +881,7 @@ protected function parseId3v24Body($fp, $lastByte) } else # no condition for iso-8859-1 $actual_text = null; - } - else if ($actual_text !== false) $actual_text .= $char; + } else if ($actual_text !== false) $actual_text .= $char; else $short_description .= $char; } if ($actual_text === false) $actual_text = $short_description; @@ -917,9 +945,10 @@ protected function parseId3v24Body($fp, $lastByte) * @return boolean True if file looks that correct mpeg audio, False otherwise. * @throws \Exception */ - public static function isValidAudio($filename) { + public static function isValidAudio($filename) + { if (!file_exists($filename)) - throw new Exception('File '.$filename.' is not present!'); + throw new Exception('File ' . $filename . ' is not present!'); $raw = file_get_contents($filename, false, null, 0, 3); return $raw == self::TAG2_SYNC // id3v2 tag @@ -927,8 +956,8 @@ public static function isValidAudio($filename) { || ( filesize($filename) > 128 && file_get_contents($filename, false, null, -128, 3) === self::TAG1_SYNC - ) // id3v1 tag - ; + ) // id3v1 tag + ; } /** @@ -941,7 +970,7 @@ private function handleTextFrame($frameSize, $raw) { $data = unpack('C1encoding/A' . ($frameSize - 1) . 'information', $raw); - switch($data['encoding']) { + switch ($data['encoding']) { case 0x00: # ISO-8859-1 return mb_convert_encoding($data['information'], 'utf-8', 'iso-8859-1'); case 0x01: # utf-16 with BOM @@ -954,7 +983,7 @@ private function handleTextFrame($frameSize, $raw) return $data['information']; default: - throw new RuntimeException('Unknown text encoding type: '.$data['encoding']); + throw new RuntimeException('Unknown text encoding type: ' . $data['encoding']); } } @@ -964,14 +993,14 @@ private function handleTextFrame($frameSize, $raw) protected function fillTags() { foreach ([ - 'song' => 'TIT2', - 'artist' => 'TPE1', - 'album' => 'TALB', - 'year' => 'TYER', - 'comment' => 'COMM', - 'track' => 'TRCK', - 'genre' => 'TCON', - ] as $tag => $id3v2_tag) { + 'song' => 'TIT2', + 'artist' => 'TPE1', + 'album' => 'TALB', + 'year' => 'TYER', + 'comment' => 'COMM', + 'track' => 'TRCK', + 'genre' => 'TCON', + ] as $tag => $id3v2_tag) { if (!isset($this->tags2[$id3v2_tag]) && (!isset($this->tags1[$tag]) || empty($this->tags1[$tag]))) continue; From a33412f4bef7b5b4b1c324526709a589154a165c Mon Sep 17 00:00:00 2001 From: Lawrence Onah Date: Sat, 7 Aug 2021 14:34:29 +0100 Subject: [PATCH 2/2] :books: Updated readme.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9edfdbc..4764b07 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ This class extracts information from mpeg/mp3 audio: After creating an instance of `Mp3Info` with passing filename as the first argument to the constructor, you can retrieve data from object properties (listed below). ```php -use wapmorgan\Mp3Info\Mp3Info; +use Wapmorgan\Mp3Info\Mp3Info; // To get basic audio information $audio = new Mp3Info('./audio.mp3'); @@ -66,7 +66,7 @@ echo 'Song '.$audio->tags1['song'].' from '.$audio->tags1['artist'].PHP_EOL; // specific id3v2 tags echo 'Song '.$audio->tags2['TIT2'].' from '.$audio->tags2['TPE1'].PHP_EOL; -// combined tags (simplies way to get as more information as possible) +// combined tags (simplest way to get as more information as possible) echo 'Song '.$audio->tags['song'].' from '.$audio->tags['artist'].PHP_EOL; ```