Python can save your ass!

Définition du besoin

Je suis fan de la série NCIS… Et cette semaine j’ai récupéré la première saison en VO. J’ai téléchargé le pack de sous-titres sur www.tvsubtitles.net. Je copie les épisodes et leur sous-titre sur ma FreeBox et lance le premier épisode.

Et la, c’est le drame! Un gros décalage de 2 secondes environ entre la bande sonore et le sous-titre :(

Un collègue du  boulot m’a donné une idée : écrire un programme pour mettre à jour les sous-titres!

En effet, les fichiers de sous-titre sont de simple fichier textes qui sont composés de la manière suivante :

1
00:01:16,577 --> 00:01:18,579
NCIS ENQUETES SPECIALES

2
00:01:53,572 --> 00:01:56,408
"L'affrontement"

3
00:02:01,288 --> 00:02:02,706
Réveille-le.

Il suffit donc d’écrire un petit programme qui lit le fichier et qui analyse les lignes. Si la ligne est une ligne du type : “00:02:01,288 –> 00:02:02,706″ et si c’est le cas, il faut extraire les valeurs numériques pour créer des objets de type date avec et ainsi pouvoir faire le calcul pour ajouter/soustraire un delay. Enfin on écrit chaque ligne dans un nouveau fichier texte.

Comme une série se compose de 23 épisodes et que je suis une loutre, il faut aussi que le programme se débrouille tout seul pour trouver les fichiers sous-titres et les corriger les uns après les autres…

Et oui, Python peut vous sauver la vie!

Résultat

Ce petit programme en Python3 : reprise_sous_titres.py.

#!/usr/bin/python3
#--------------------------------------------------------------------#
# Programme :   reprise_sous_titres.py                               #
# Auteur :      Julien PECQUEUR (JPEC)                               #
# Home :        http://julienpecqueur.com                            #
# License :     GPL                                                  #
#                                                                    #
# Description :                                                      #
# Ce programme va reprendre tous les fichiers de type sous-titre     #
# contenus dans le répertoire REPERTOIRE et va leur appliquer un     #
# décalage DECALAGE.                                                 #
#--------------------------------------------------------------------#
#--------------------------------------------------------------------#
# IMPORT DES MODULES                                                 #
#--------------------------------------------------------------------#
import os           # Fonctions système
import datetime     # Fonctions date/heure
import re           # Expressions régulières
#--------------------------------------------------------------------#
# PARAMETRAGE                                                        #
#--------------------------------------------------------------------#
# REPERTOIRE    Chemin du répertoire dans lequel se trouvent les
#               fichiers sous-titre.
REPERTOIRE = "/home/jpec/"
# EXTENSION     Extension des fichiers de type sous-titre.
EXTENSION = ".srt"
# MASQUE        Format d'une ligne avec le positionnement horaire.
#               ex: 00:02:18,639 --> 00:02:21,099
MASQUE = "([0-9][0-9]):([0-9][0-9]):([0-9][0-9]),([0-9][0-9][0-9])"+\
         " --> " + \
         "([0-9][0-9]):([0-9][0-9]):([0-9][0-9]),([0-9][0-9][0-9])"
# DECALAGE_*    Valeurs du décalage pour les sous-titres.
DECALAGE_HEU = 0        # Heures
DECALAGE_MIN = 0        # Minutes
DECALAGE_SEC = 2        # Secondes
DECALAGE_MSC = 500000   # Micro-secondes
# SUPPR_SOURCE  Suppression du fichier source? ("OUI" ou "NON")
SUPPR_SOURCE = "NON"
#--------------------------------------------------------------------#
# FONCTIONS                                                          #
#--------------------------------------------------------------------#
def corriger(Fichier):
    # Fonction corriger(Nom du fichier) - Elle corrige le fichier de
    # sous-titre passé en paramêtre en lui appliquant le décalage
    # définit : DECALAGE_*.
    print("*** Correction fichier '" + Fichier + "\'...")
    FichierSource = open(REPERTOIRE + Fichier, \
                         'r', \
                         encoding="iso8859_15")
    # Fichier temporaire :
    FichierCible = open(REPERTOIRE + Fichier + ".tmp", \
                        'w', \
                        encoding="iso8859_15")
    # On boucle sur les lignes du fichier source pour alimenter le
    # fichier temporaire :
    for Ligne in FichierSource:
        if Regex.match(Ligne):
            # On est sur une ligne de positionnement horaire :
            StartH = int(Regex.match(Ligne).group(1))
            StartM = int(Regex.match(Ligne).group(2))
            StartS = int(Regex.match(Ligne).group(3))
            Startm = int(Regex.match(Ligne).group(4))*1000
            EndH = int(Regex.match(Ligne).group(5))
            EndM = int(Regex.match(Ligne).group(6))
            EndS = int(Regex.match(Ligne).group(7))
            Endm = int(Regex.match(Ligne).group(8))*1000
            Start = datetime.datetime(2000, 1, 1, \
                                      StartH,
                                      StartM,
                                      StartS,
                                      Startm)
            End = datetime.datetime(2000, 1, 1, \
                                    EndH,
                                    EndM,
                                    EndS,
                                    Endm)
            Start = Start + Delay
            End = End + Delay
            StartH = Start.strftime('%H')
            StartM = Start.strftime('%M')
            StartS = Start.strftime('%S')
            Startm = Start.strftime('%f')[0:3]
            EndH = End.strftime('%H')
            EndM = End.strftime('%M')
            EndS = End.strftime('%S')
            Endm = End.strftime('%f')   [0:3]
            # Construction de la nouvelle ligne :
            Ligne = StartH +":"+ StartM +":"+ StartS +","+ Startm \
                    + " --> " + \
                    EndH +":"+ EndM +":"+ EndS +","+ Endm + "\n"
        FichierCible.write(Ligne)
    # Fermeture des fichiers :
    FichierSource.close
    FichierCible.close
    # Gestion copie/remplace :
    if SUPPR_SOURCE == "OUI":
        print("*** Suppression fichier source \'" + Fichier + "\'...")
        os.remove(REPERTOIRE + Fichier)
        print("*** '" + Fichier + ".tmp\' -> \'" + Fichier + "\'...")
        os.rename(REPERTOIRE + Fichier + ".tmp", REPERTOIRE + Fichier)
    print("*** \'" + Fichier + "\' DONE !")
#--------------------------------------------------------------------#
# CODE                                                               #
#--------------------------------------------------------------------#
# Récupération de la liste des fichiers du répertoire de travail :
print("*** Liste des fichiers de \'" + REPERTOIRE + "\'...")
ListeFichiers = os.listdir(REPERTOIRE)
ListeFichiers.sort()
# Création de l'expression régulière pour le masque :
Regex = re.compile(MASQUE)
# Création du décalage pour les sous-titres :
Delay = datetime.timedelta(hours=DECALAGE_HEU, \
                           minutes=DECALAGE_MIN, \
                           seconds=DECALAGE_SEC, \
                           microseconds=DECALAGE_MSC)
# Boucle sur les fichiers du répertoire de travail. Si c'est un
# fichier de type sous-titre, alors on appelle la fonction corriger :
print("*** Boucle sur les fichiers de type \'" + EXTENSION + "\'...")
for Fichier in ListeFichiers:
    if Fichier[len(Fichier)-len(EXTENSION):len(Fichier)] == EXTENSION:
        corriger(Fichier)
#--------------------------------------------------------------------#
# FIN DU PROGRAMME                                                   #
#--------------------------------------------------------------------#

About Julien

Unix, code & web from Picardie!
This entry was posted in Archlinux, Code, Python 3. Bookmark the permalink.

7 Responses to Python can save your ass!

  1. catwell says:

    Le “Do It Yourself” c’est sympa, mais j’aurais utilisé un logiciel existant comme Gaupol dans ce cas… J’aurais eu moins à attendre avant de regarder l’épisode :)

  2. jokester says:

    C’est bien sympa tout ça !
    Sinon dans vlc, il me semble que tu peux paramétrer le décalage de l’image et du son selon tes envies. (à paramétrer à chaque visionnage de vidéo du coup, contrairement à ta solution, brute de force !)
    Tchuss,

    Jk.

  3. Julien says:

    Catwell, En effet s’aurait été plus rapide! :)
    Jk, je regarde les films sur ma tv via le player de la freebox bd… et malheureusement il n’y a aucun réglage…
    Et puis c’était aussi pour démontrer que Python est universel et peut tout faire ( comme Perl mais en plus simple)!

    Ps : la matrix EST codée en Python! MDR

  4. Pingback: Julien Pecqueur (jpec) 's status on Tuesday, 10-Nov-09 06:19:18 UTC - Identi.ca

  5. Canard wc says:

    Franchement, utiliser python quand on utilise autant de regex, … autant coder en java ou le faire en C

  6. Julien says:

    Utiliser C ou Java pour un programme qui ne servira qu’une fois est une idée à mettre dans la seconde partie de ton pseudo!
    Pour les lignes “StartH = int(Regex.match(Ligne).group(1))” peuvent s’écrire en une seule ligne mais ce n’est pas très lisible…

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>