logo rss

Décaler le Timing des Sous-titres SRT avec un Script Python

Python logo

Les problèmes de synchronisation des sous-titres sont fréquents. Très souvent, le fichier de sous-titres ne correspond pas au timing de la vidéo, ce qui provoque un décalage de quelques millisecondes à plusieurs secondes — rendant le visionnage rapidement désagréable.

La plupart des lecteurs multimédias comme VLC, MPV ou MPlayer permettent de corriger temporairement ce décalage (voir ce guide), mais l’ajustement est perdu dès que vous relancez la vidéo. Une solution durable consiste à modifier directement le fichier SRT.

J’avais déjà rédigé un script Bash pour faire cela, mais j’ai décidé de le réécrire en Python pour plus de flexibilité et de lisibilité. Voici comment cela fonctionne.

Utilisation

Pour décaler le timing des sous-titres dans un fichier SRT, utilisez le script comme suit :

user@host:~$ ./shebangthesubtitles.py [srt file] [+/- time]
user@host:~$ ./shebangthesubtitles.py -h
usage: shebangthesubtitles.py /movies/mysubtitle.srt -1.400

add/substract delay on a srt file

positional arguments:
  file        srt file path
  delay       delay in seconds with 0.000 format

optional arguments:
  -h, --help  show this help message and exit

Exemples

Avancer les sous-titres de 400 millisecondes :

user@host:~$ ./shebangthesubtitles.py /home/std/Running.on.Empty.1988.1080p.BluRay.x264.AAC.5.1-POOP.srt -0.400

Retarder les sous-titres de 1,4 seconde :

user@host:~$ ./shebangthesubtitles.py /home/std/Running.on.Empty.1988.1080p.BluRay.x264.AAC.5.1-POOP.srt 1.400

Remarque : Le fichier de sous-titres ajusté sera enregistré dans le même répertoire que l’original, avec _new.srt ajouté au nom du fichier.

Format du fichier SRT

Ce script est conçu pour fonctionner spécifiquement avec les fichiers de sous-titres .srt standards, qui suivent le format typique illustré ci-dessous :

[…]
1126
01:55:12,527 --> 01:55:14,461
I love you.

1127
01:55:20,735 --> 01:55:22,669
I really love you.

Script Python

Voici le script Python complet utilisé pour décaler le timing des fichiers de sous-titres SRT. Il permet d’ajouter ou de retirer un délai (en secondes) en indiquant une valeur positive ou négative.

#! /usr/bin/python

# Role : Add or subtract delay to a srt file
# Author : http://shebangthedolphins.net/
# 1.0 first version

import argparse
import re, sys
from datetime import datetime, timedelta
import shutil
from tempfile import mkstemp
from os import path

###START PARSER : https://docs.python.org/3/library/argparse.html
parser = argparse.ArgumentParser(description='add/subtract delay on a srt file',prog='shebangthesubtitles.py', usage='%(prog)s /movies/mysubtitle.srt -1.400')
parser.add_argument('file', help='srt file path')
parser.add_argument('delay', help='delay in seconds with 0.000 format')
args = parser.parse_args()
###END PARSER

###FUNCTION
def timeop (hours, minutes, seconds, milliseconds, delay):
        "function which add or subtract delayed time then return result"
        time_src = datetime(year=1983, month=12, day=12, hour=int(hours), minute=int(minutes), second=int(seconds), microsecond=int(milliseconds)).timestamp()
        result = time_src + delay
        return result

###CHECK ARGUMENTS
try:
        delay = float(args.delay)
except:
        print("Error, float argument needed.")
        parser.print_help()
        sys.exit(1)

if not path.exists(args.file):
        print("Error, file doesn't exist.")
        parser.print_help()
        sys.exit(1)


fs = open(args.file, 'r') #open srt file, read mode
fd, name = mkstemp() #returns a tuple containing an OS-level handle to an open file and the absolute pathname of that file, in that order.
fout = open(name, 'w') #open temp file, write mode
while 1:
        txt = fs.readline()
        if re.match(".*-->.*", txt): #if ".*-->.*" characters is in current line
                seq=txt.split(" --> ")
                hours_start, minutes_start, seconds_start = seq[0].split(":")
                hours_start = hours_start[-1:]
                seconds_start, milliseconds_start = seconds_start.split(",")
                milliseconds_start = int(milliseconds_start) * 1000
                new_start = timeop(hours_start, minutes_start, seconds_start, milliseconds_start, delay)

                hours_end, minutes_end, seconds_end = seq[1].split(":")
                hours_end = hours_end[-1:]
                seconds_end, milliseconds_end = seconds_end.split(",")
                milliseconds_end = int(milliseconds_end) * 1000
                new_end = timeop(hours_end, minutes_end, seconds_end, milliseconds_end, delay)

                txt = re.sub(seq[0], datetime.fromtimestamp(new_start).strftime('%H:%M:%S,%f')[:-3], txt)
                txt = re.sub(seq[1], datetime.fromtimestamp(new_end).strftime('%H:%M:%S,%f')[:-3], txt) + "\n"
                fout.write(txt) #write to tmp file
        else:
                fout.write(txt) #write to tmp file

        if txt == "":
                break
fout.close() #close tmp file
shutil.move(name, args.file.split(".srt")[0] + "_new.srt") #copy tmp file to srtfile_new.srt
fs.close() #close srt file