суббота, 2 апреля 2011 г.

PHP .srt shifter

Вдруг приспичило мне посмотреть фильм с субтитрами. Ну, допустим, анимешный мультик без русской аудиодорожки. Но оказалось, что огромное расхождение во времени между репликами персонажей в мултике и в субтитрах. Я не долго горевал, а набросал на PHP скриптик для сдвига субтитров формата .SRT на указанную величину.

$ php srt_shifter.php subtitles.srt '-31.5'
Сдвинет временные метки всех субтитров в файле subtitles.srt на 31.5 секунду раньше.

/**
* Сдвиг времени.
* @param array $time = array('h' => часы, 'm' => минуты, 's' => секунды) что сдвигать
* @param array $shift = array('h' => часы, 'm' => минуты, 's' => секунды) на сколько сдвигать
* @return array('h' => часы, 'm' => минуты, 's' => секунды)
*/
function shifttime($time, $shift)
{
$result = array();

// секунды
$result['s'] = $time['s'] + $shift['s'];
if($result['s'] >= 60)
{
$result['s'] -= 60;
$shift['m']++;
}
if($result['s'] < 0)
{
$result['s'] -= 60;
$shift['m']--;
}
$result['s'] = sprintf('%.3f', $result['s']);
if($result['s'] < 10)
{
$result['s'] = '0'.$result['s'];
}

// минуты
$result['m'] = $time['m'] + $shift['m'];
if($result['m'] >= 60)
{
$result['m'] -= 60;
$shift['h']++;
}
if($result['m'] < 0)
{
$result['m'] -= 60;
$shift['h']--;
}
if($result['m'] < 10)
{
$result['m'] = '0'.$result['m'];
}

// часы
$result['h'] = $time['h'] + $shift['h'];
if($result['h'] < 0)
{
// отрицательное время
return array('s' => '00,000', 'm' => '00', 'h' => '00');
}
if($result['h'] < 10)
{
$result['h'] = '0'.$result['h'];
}

return $result;
}

// проверка вводимых параметров
if(!$argv[1])
{
echo "No file specified\n";
die();
}
if(!$argv[2])
{
echo "No shift specified\n";
die();
}
$shift = (float)$argv[2];
if(!$shift)
{
echo "Shift must be floationg number of seconds\n";
die();
}

// открытие файлов
$fi = fopen($argv[1], "r");
if(!$fi)
{
echo "Cannot open input file for reading\n";
die();
}
$fo = fopen("out.srt", "w");
if(!$fo)
{
echo "Cannot open output file for writing\n";
die();
}

// небольшая подготовка
$shift_h = floor($shift / 3600); // сдвиг в часах, вряд ли пригодится, но учесть надо
$shift_m = floor(($shift - $shift_h * 3600) / 60); // сдвиг в минутах
$shift = $shift - $shift_h * 3600 - $shift_m * 60; // оставшийся сдвиг в секундах

// собственно процесс сдвига
while($s = fgets($fi))
{
// hh:mm:ss,sss --> hh:mm:ss,sss
if(preg_match('/([\d]{2,})\:([\d]{2})\:([\d]{2},[\d]{3}) --> ([\d]{2,})\:([\d]{2})\:([\d]{2},[\d]{3})/', $s, $_ar))
{
$t1 = shifttime
(
array
(
'h' => $_ar[1],
'm' => $_ar[2],
's' => str_replace(',', '.', $_ar[3])
),
array
(
'h' => $shift_h,
'm' => $shift_m,
's' => $shift
)
);
$t2 = shifttime
(
array
(
'h' => $_ar[4],
'm' => $_ar[5],
's' => str_replace(',', '.', $_ar[6])
),
array
(
'h' => $shift_h,
'm' => $shift_m,
's' => $shift
)
);
$s = $t1['h'].':'.$t1['m'].':'.str_replace('.', ',', $t1['s']).' --> '.$t2['h'].':'.$t2['m'].':'.str_replace('.', ',', $t2['s'])."\n";
}
fputs($fo, $s);
}

// закрытие файлов
fclose($fi);
fclose($fo);


Смысла подписывать что-нибудь типа "published under GNU GPL license" нет, такое любой школьник накатает с полтычка.

4 комментария:

  1. Ммм, у меня короче решение:

    ~# mplayer -subdelay

    :)

    ОтветитьУдалить
  2. парсер - лох, там еще к параметру число в сек (как положительное, так и отрицательное).

    ОтветитьУдалить
  3. Мне уже сказали, что в VLC можно прямо во время проигрывания подстраивать задержку субтитров клавишами g и h.

    ОтветитьУдалить
  4. Пожалуйста:

    in Smplayer-gui use 'x' or 'z'

    ОтветитьУдалить

Ублюдочный Гугл поломал форму комментариев. Извините.