Przesuwanie napisów z filmów w czasie

Potrzeba matką wynalazków. Tak było i tym razem. Potrzebowałem prostego programiku do przesunięcia napisów z filmu w czasie (wyświetlały się kilka sekund za późno). Znalezione w sieci nie działały prawidłowo.

No i stworzyłem taki prosty program w PHP.

Po kilku miesiącach znów potrzebowałem, jednak okazało się, że tym razem napisy mają inny format. A więc stworzyłem drugi programik.

W końcu postanowiłem się z nim podzielić – może Tobie się przyda?

Skrypt jest dostępny pod adresem napisy.wyremski.pl

Natomiast kod źródłowy pod adresem https://github.com/kamilwyremski/napisy/

Poniżej krótki opis skryptu PHP:

Najpierw sprawdzam czy uploadowany plik jest prawidłowy:

if (
!isset($_FILES['plik']['error']) ||
is_array($_FILES['plik']['error'])
) {
    throw new RuntimeException('Nieznany parametr');
}
switch ($_FILES['plik']['error']) {
    case UPLOAD_ERR_OK:
        break;
    case UPLOAD_ERR_NO_FILE:
        throw new RuntimeException('Nie wysłano pliku');
    case UPLOAD_ERR_INI_SIZE:
    case UPLOAD_ERR_FORM_SIZE:
        throw new RuntimeException('Przekroczono limit wielkości pliku');
    default:
        throw new RuntimeException('Nieznane błędy');
}

$finfo = new finfo(FILEINFO_MIME_TYPE);
if ($finfo->file($_FILES['plik']['tmp_name']) != 'text/plain'){
    throw new RuntimeException('Nieprawidłowy format pliku');
}

Wykorzystałem tutaj fragment kodu ze strony https://www.php.net/manual/en/features.file-upload.php

Następnie otwieram plik i sprawdzam format napisów. Myślałem żeby sprawdzać po prostu pierwszą linijkę ale nie zawsze po pierwszej linijce jest wiadomo w jakim formacie są napisy.

Skrypt obsługuje taki format napisów:

00:00:14:Tutaj jest pierwsza linia tekstu
00:00:20:Tutaj jest druga linia tekstu

Oraz taki:

1
00:00:14,125 --> 00:00:17,916
Tutaj jest pierwsza linia tekstu

2
00:00:20,458 --> 00:00:23,208
Tutaj jest druga linia tekstu

Skrypt do przetwarzania linii z pliku z napisami i ich przesuwania wygląda tak:

$handle = fopen($_FILES['plik']['tmp_name'], "r");
while (($line = fgets($handle)) !== false) {
  if(!$subtitle_type){
    if(preg_match("/^\d\d:\d\d:\d\d:/",$line)) {
        $subtitle_type = 'standard';
    }elseif(preg_match("/^\d\d:\d\d:\d\d,\d\d\d --> \d\d:\d\d:\d\d,\d\d\d$/",$line)) {
        $subtitle_type = 'arrow';
    }
  }

  if($subtitle_type=='standard'){
    $time_original = substr($line, 0, 8);
    $seconds = strtotime($time_original);
    $time_new = date('H:i:s',$seconds + $_POST['przesuniecie']);
    $new_line = str_replace($time_original, $time_new, $line);
    $output .= $new_line;
  }elseif($subtitle_type=='arrow'){
    $match_count = preg_match_all('/(\d\d:\d\d:\d\d),\d\d\d --> (\d\d:\d\d:\d\d),\d\d\d/i', $line, $matches);
    if($match_count){
        $time_original = strtotime($matches[1][0]);
        $time_new = date('H:i:s',$time_original + $_POST['przesuniecie']);
        $new_line = str_replace($matches[1][0], $time_new, $line);
        $time_original = strtotime($matches[2][0]);
        $time_new = date('H:i:s',$time_original + $_POST['przesuniecie']);
        $new_line = str_replace($matches[2][0], $time_new, $new_line);
        $output .= $new_line;
    }else{
        $output .= $line;
    }
  }else{
      $output .= $line;
  }
}
fclose($handle);

Najpierw próbuje określić format napisów. Jeśli w danej linii nie został znaleziony to jest ona kopiowana do docelowego wyniku. Jeśli został znaleziony to jest odpowiednio przekształcany. Korzystam tutaj z wyrażeń regularnych.

Na końcu wymuszam pobranie wygenerowanych nowych napisów przez przeglądarkę:

header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . basename($_FILES['plik']['name']) . "\"");
echo($output);
exit();

Sam formularz wysyłania napisów to standardowy formularz ostylowany w Bootstrap4:

<form action="" method="post" enctype="multipart/form-data" class="col-sm-4">   
  <div class="form-group">
    <label for="plik">Plik z napisami</label>
    <input type="file" class="form-control-file" id="plik" name="plik" required accept=".txt,.srt">
  </div>
  <div class="form-group">                 
    <label for="przesuniecie">Przesunięcie (w sekundach)</label>
    <input type="number" class="form-control" id="przesuniecie" name="przesuniecie" required step="1">              
  </div>             
  <button type="submit" class="btn btn-primary">Wyślij</button>
</form>

Oczywiście można by były rozbudować aplikację i dodać m.in. obsługę więcej liczby formatów napisów – może chciałbyś w tym pomóc? 😉

Ta strona używa ciasteczek (cookies), dzięki którym nasz serwis może działać lepiej. Więcej informacji

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close