Last active
March 12, 2022 18:24
-
-
Save divinity76/5ad23dbf9b3de711ec03915b50c18224 to your computer and use it in GitHub Desktop.
php subtitle tools
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
class Subtitle_tools | |
{ | |
private static function convertToCygpath(string $path): string | |
{ | |
if (PHP_OS !== 'CYGWIN') { | |
return $path; | |
} | |
$cygpath = shell_exec("cygpath " . escapeshellarg($path)); | |
return substr($cygpath, 0, -strlen("\n")); | |
} | |
private static function convertToWinpath(string $path): string | |
{ | |
if (PHP_OS !== 'CYGWIN') { | |
return $path; | |
} | |
$cygpath = shell_exec("cygpath -w " . escapeshellarg($path)); | |
return substr($cygpath, 0, -strlen("\n")); | |
} | |
private static function fixDirPath(string $path): string | |
{ | |
$path = self::convertToCygpath($path); | |
$lastChar = substr($path, -1); | |
if ($lastChar !== '/' && $lastChar !== '\\') { | |
$path .= '/'; | |
} | |
return str_replace('\\', '/', $path); | |
} | |
public static function getSubtitlesFromDirectory(string $directory): array | |
{ | |
$directory = self::fixDirPath($directory); | |
$ret = array(); | |
$files = scandir($directory); | |
foreach ($files as $file) { | |
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); | |
if (in_array($ext, array('srt', 'sub'), true)) { | |
$ret[] = $directory . $file; | |
} | |
} | |
natsort($ret); | |
return $ret; | |
} | |
public static function getVideoFilesFromDirectory(string $directory): array | |
{ | |
$directory = self::fixDirPath($directory); | |
$ret = array(); | |
$files = scandir($directory); | |
foreach ($files as $file) { | |
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); | |
if (in_array($ext, array('avi', 'mkv', 'mp4', 'mpg', 'mpeg', 'wmv'), true)) { | |
$ret[] = $directory . $file; | |
} | |
} | |
natsort($ret); | |
return $ret; | |
} | |
public static function fixSubtitleNames(string $directory): void | |
{ | |
$videos = self::getVideoFilesFromDirectory($directory); | |
$subs = self::getSubtitlesFromDirectory($directory); | |
if (count($videos) !== count($subs)) { | |
throw new \Exception('Number of videos and subtitles do not match. found ' . count($videos) . ' videos and ' . count($subs) . ' subtitles'); | |
} | |
foreach ($videos as $index => $video) { | |
$sub = $subs[$index]; | |
$subExtension = pathinfo($sub, PATHINFO_EXTENSION); | |
$newSub = $video . '.' . $subExtension; | |
if ($newSub !== $sub) { | |
echo "Renaming $sub to $newSub\n"; | |
rename($sub, $newSub); | |
} | |
} | |
} | |
public static function adjustSubtitleTimestamps(string $dir, float $relative_adjust): void | |
{ | |
$subs = self::getSubtitlesFromDirectory($dir); | |
foreach ($subs as $sub) { | |
echo "doing {$sub}\n"; | |
$ext = strtolower(pathinfo($sub, PATHINFO_EXTENSION)); | |
if ($ext === "srt") { | |
$content = file_get_contents($sub); | |
if ($content === false) { | |
throw new \RuntimeException("failed to fetch {$sub}"); | |
} | |
// 00:00:24,024 --> 00:00:26,824 | |
$adjusted = preg_replace_callback('/(?<hour>\d{2})\:(?<minute>\d{2})\:(?<second>\d{2})(?:\,(?<subseconds>\d+))?/m', function ($matches) use ($relative_adjust) { | |
//var_dump($matches);die(); | |
$formatNum = function ($num, int $pad) { | |
return str_pad((string)$num, $pad, '0', STR_PAD_LEFT); | |
}; | |
$hour = $matches['hour']; | |
$minute = $matches['minute']; | |
$second = $matches['second']; | |
$subseconds = (float)("0." . ((string)($matches['subseconds'] ?? 0))); | |
$input = $formatNum($hour, 2) . ':' . $formatNum($minute, 2) . ':' . $formatNum($second, 2) . ',' . $formatNum($subseconds * 1000, 0); | |
$total = ($hour * 3600) + ($minute * 60) + $second + ($subseconds); | |
$total += $relative_adjust; | |
$hour = floor($total / 3600); | |
$total = $total - ($hour * 3600); | |
$minute = floor($total / 60); | |
$total = $total - ($minute * 60); | |
$second = floor($total); | |
$total = $total - $second; | |
$subseconds = $total; | |
$output = $formatNum($hour, 2) . ':' . $formatNum($minute, 2) . ':' . $formatNum($second, 2) . ',' . $formatNum($subseconds * 1000, 0); | |
if (0) { | |
var_dump(["input" => $input, "output" => $output, "equal" => $input === $output]); | |
die(); | |
} | |
return $output; | |
}, $content, -1, $count); | |
file_put_contents($sub, $adjusted, LOCK_EX); | |
} else { | |
throw new \RuntimeException("unsupported subtitle format: {$ext}"); | |
} | |
} | |
} | |
} | |
$path = 'C:\Users\hans\Downloads\The Blacklist Season 2 Complete 720P Bluray x264 [i_c]'; | |
if (0) { | |
var_dump( | |
Subtitle_tools::getSubtitlesFromDirectory($path), | |
Subtitle_tools::getVideoFilesFromDirectory($path), | |
); | |
} | |
var_dump(Subtitle_tools::fixSubtitleNames($path)); | |
var_dump(Subtitle_tools::adjustSubtitleTimestamps($path, +0.5)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment