IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Prgramme pour décaler des sous-titres


Sujet :

Python

  1. #1
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2018
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2018
    Messages : 70
    Par défaut Prgramme pour décaler des sous-titres
    Bonjour,

    On a tous eu ce genre de problème, je pense quand on télécharge (légalement, bien sur ) un film ou un épisode et qu'on télécharge le fichier de sous-titres (.srt ou .sub) à coté, parfois, il y a un décalage. C'est assez énervant, bref, en général, on télécharge un autre fichier, jusqu'à tomber sur le bon mais parfois rien n'y fait, impossible de trouver un sous-titres correspondant.
    Je me suis lancé sur un projet, écrire un programme qui permette de changer le time-code du sous titres, mais je suis un peu perdu. Je ne sais pas vraiment comment commencé. Le premier problème qui se pose à moi est le suivant :
    Je voudrais accéder au time code dans le fichier srt, pour cela j'ai commencé à ecrire ça pour voir le résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    srt_origin = open('D:\musique western et autres\Australia\Peter Weir\Picnic at Hanging Rock (1975)\Picnic at Hanging Rock (1975).srt','r')
    srt_decal = open('D:\musique western et autres\Australia\Peter Weir\Picnic at Hanging Rock (1975)\Picnic at Hanging Rock (1975).srt','w')
    nombre_ligne = 0
    timecode = ""
    for ligne in srt_origin :
        nombre_ligne += 1
        if '-->' in str(ligne):
            timecode = ligne
            print(timecode)
    Sachant qu'un fichier srt peut s'ouvrir avec le bloc-note et se présente comme ça. Merci de votre aide, si vous avez des pistes pour m'aider.

    1
    00:00:23,000 --> 00:00:24,668
    <i>Le 14 février 1900,</i>

    2
    00:00:24,877 --> 00:00:27,004
    <i>des jeunes filles
    du collège Appleyard</i>

    3
    00:00:27,213 --> 00:00:30,549
    <i>pique-niquèrent à Hanging Rock,
    dans le Victoria.</i>

    4
    00:00:30,757 --> 00:00:34,510
    <i>Au cours de l'après-midi,
    plusieurs membres du groupe</i>

    5
    00:00:34,719 --> 00:00:38,306
    <i>disparurent sans laisser de trace...</i>

    6
    00:01:35,982 --> 00:01:41,445
    PIQUE-NIQUE
    À HANGING ROCK

    ...

  2. #2
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    déjà tu ouvres le même fichier 2 fois, une fois en lecture, une fois en écriture; ça ne marche pas.
    l'idée ça va plutôt être de lire tout le fichier en mémoire, le mouliner, et ensuite écrire un nouveau fichier

    ensuite pour travailler avec les horodatages on pourra utiliser le module datetime, particulièrement les fonctions strftime(), strptime() et timedelta()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> import datetime
    >>> a = datetime.datetime.strptime('00:00:24,877', '%H:%M:%S,%f')                                     ; a
    datetime.datetime(1900, 1, 1, 0, 0, 24, 877000)
    >>> b = a + datetime.timedelta(seconds=1, microseconds=87000)                                         ; b
    datetime.datetime(1900, 1, 1, 0, 0, 25, 964000)
    >>> c = datetime.datetime.strftime(b, '%H:%M:%S,%f')                                                  ; c
    '00:00:25,964000'
    >>> c[:-3]
    '00:00:25,964'
    enfin pour isoler les timestamps facilement on pourra avoir recours aux regex, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> import re
    >>> line = '00:00:23,000 --> 00:00:24,668'
    >>> re.findall(r'(\d{2}:\d{2}:\d{2},\d{3})', line)
    ['00:00:23,000', '00:00:24,668']
    refs:

  3. #3
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2018
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2018
    Messages : 70
    Par défaut
    Merci beaucoup, tout ça, va mettre très utile

  4. #4
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2018
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2018
    Messages : 70
    Par défaut
    Du coup, j'ai écrit ce code pour pouvoir changer tout les timecode, ça marche
    Maintenant, je me demande comment, les replacer dans le fichier, c'est pour ça que j'ai essayer de réécrire le fichier à coté pour pouvoir le modifier, mais je ne sais pas trop comment accéder à cette ligne.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    import datetime
    import re
     
    # on ouvre le fichier str pour le modifier
    list_time_code = []
    srt_origin = open('D:\musique western et autres\Australia\Peter Weir\Picnic at Hanging Rock (1975)\Picnic at Hanging Rock (1).srt','r')
     
     
    # on crée une liste de toutes les time code pour les modifier
    for ligne in srt_origin:
        list_time_code += (re.findall(r'(\d{2}:\d{2}:\d{2},\d{3})', ligne))
     
    print (list_time_code)
     
    for indice in range(len(list_time_code)):
        time_code = datetime.datetime.strptime(list_time_code[indice], '%H:%M:%S,%f')
        time_code_add = time_code + datetime.timedelta(seconds=-10)
        time_code = datetime.datetime.strftime(time_code_add, '%H:%M:%S,%f')
        time_code = time_code[:-3]
        list_time_code[indice] = time_code
     
    print(list_time_code)
     
     
     
    ############################################ Réecriture du programme en .txt
    for ligne in srt_origin:
        with open('D:\musique western et autres\Australia\Peter Weir\Picnic at Hanging Rock (1975)\Picnic at Hanging Rock (1).txt_d','a') as srt_copie:
            srt_copie.write(ligne)

  5. #5
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    Citation Envoyé par Eckmül Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for ligne in srt_origin:
        with open('D:\musique western et autres\Australia\Peter Weir\Picnic at Hanging Rock (1975)\Picnic at Hanging Rock (1).txt_d','a') as srt_copie:
            srt_copie.write(ligne)
    là pour chaque ligne tu réécris le fichier, essaye plutôt de faire l'inverse ^^ (et en mode 'w', pas 'a')

    au plus simple tu peux même faire directement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    with open(fichier, 'w') as f:
       f.write(''.join(srt_origin))

  6. #6
    Expert confirmé Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 981
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 981
    Par défaut
    Je vois deux manières de faire:
    • soit tu lis le fichier source ligne par ligne et enregistre chaque ligne dans le fichier destination, en modifiant la ligne des temps lorsque celle-ci est détectée.
    • soit tu lis le fichier d'un seul coup et tu stockes tout son contenu dans une variable à laquelle tu appliques une substitution via une regex (re.sub) qui détecte les lignes de temps.


    Les deux manières ont leurs avantages et inconvénients. La première demande moins de ressources mémoire et processeur, par contre elle générera plus d'accès disque. La deuxième est plus concise et éventuellement plus rapide. Mais quoi qu'il en soit, pour un fichier srt dont la taille n'atteint même pas le mégaoctet, ces différences sont négligeables, mais bonnes à connaître tout de même.

    Pour la première manière de faire:
    Ton idée de départ n'est pas mauvaise: détecter la ligne qu'il faut changer.
    Utiliser if '-->' in ..., pourquoi pas, mais moi la première idée qu'il me vient en tête, c'est de m'appuyer sur la structure même du fichier à savoir: la ligne contenant les temps est toujours la deuxième ligne après la ligne blanche (ou le début du fichier). D'où l'idée d'initialiser un compteur de lignes à zéro à chaque ligne blanche et de l'incrémenter à chaque nouvelle ligne. Lorsque celui-ci est égal à 2, je corrige les temps.
    Je ne prétend pas que ton idée est moins bonne, loin de là, et elle produira sûrement un code plus concis, mais ce n'est pas celle qui me soit venue à l'esprit. Je t'invite d'ailleurs à réécrire le code qui suit en suivant ton idée de départ (donc sans compteur).
    Ce qui donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    from datetime import datetime, timedelta
     
    def shift_time_str(s, interval):
        time_format = '%H:%M:%S,%f'
        dt = datetime.strptime(s, time_format)
        dt += interval
        return dt.strftime(time_format)[:-3]
     
    interval = timedelta(seconds = -10)
    block_line = 0
    mask = '{} --> {}'
    new_line = "\n"
     
    with open('subtitle.txt', 'r') as fi, open('subtitle_new.txt', 'w') as fo:
        for line in fi:
            line = line.rstrip()
            block_line += 1
     
            if not line:
                block_line = 0
            elif block_line == 2:
                times = [shift_time_str(l, interval) for l in line.split(' --> ')]
                line = mask.format(*times)
     
            fo.write(line)
            fo.write(new_line)
    Pour la deuxième manière de faire:
    Là on ne lit plus ligne par ligne, on lit le fichier d'un coup et on recherche un motif particulier (via une regex) pour ensuite modifier toutes les sous-chaînes correspondantes. La regex utilisée est volontairement vague pour ne pas la compliquer inutilement. Elle décrit: au début d'une ligne douze caractères parmi des chiffres, deux-points, la virgule, suivit de -->, puis de nouveau douze caractères parmi des chiffres, deux-points, la virgule, et enfin la fin de ligne. À noter que:
    • le flag re.M change le sens par défaut de ^ et $: début et fin de chaîne en début et fin de ligne.
    • Les parenthèses permettent de capturer des parties de la correspondance. On peut par la suite s'y référer dans une chaîne ou une fonction de remplacement (ici m.group(1) et m.group(2)).

    On obtient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from datetime import datetime, timedelta
    import re
     
    def shift_time_str(s, interval):
        time_format = '%H:%M:%S,%f'
        dt = datetime.strptime(s, time_format)
        dt += interval
        return dt.strftime(time_format)[:-3]
     
    reg = re.compile(r'^([\d:,]{12}) --> ([\d:,]{12})$', re.M)
     
    def reg_replacement(m):
        mask = '{} --> {}'
        times = [shift_time_str(x, interval) for x in [m.group(1), m.group(2)]]
        return mask.format(*times)
     
    interval = timedelta(seconds = -10)
     
    with open('subtitle.txt', 'r') as fi, open('subtitle_new.txt', 'w') as fo:
        fo.write(reg.sub(reg_replacement, fi.read()))

  7. #7
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2018
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2018
    Messages : 70
    Par défaut
    J'y suis presque !

    Dans la première boucle, je créé un nouvel élément à ma ligne text pour pouvoir créer la ligne suivante, contrairement à ce que je croyais la fonction open() lit caractère par caractère et non ligne par ligne.

    Du coup je rassemble les lignes dans une liste. Le problème, c'est qu'une fois le nouveau sous-titres écrit, j'ai des \n en trop, et je voudrais les supprimer

    En gros mon fichier d'arrivé ressemble à ça :

    1
    00:00:05,329 --> 00:00:06,997

    <i>Le 14 février 1900,</i>

    2
    00:00:07,205 --> 00:00:09,334

    <i>des jeunes filles

    du collège Appleyard</i>

    3
    00:00:09,543 --> 00:00:12,878

    <i>pique-niquèrent à Hanging Rock,

    dans le Victoria.</i>
    Je voudrais supprimer les retour à la ligne pour ressembler à ça :

    1
    00:00:15,329 --> 00:00:16,997
    <i>Le 14 février 1900,</i>

    2
    00:00:17,205 --> 00:00:19,334
    <i>des jeunes filles
    du collège Appleyard</i>

    3
    00:00:19,543 --> 00:00:22,878
    <i>pique-niquèrent à Hanging Rock,
    dans le Victoria.</i>

    4
    00:00:23,087 --> 00:00:26,843
    <i>Au cours de l'après-midi,
    plusieurs membres du groupe</i>
    Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
    import datetime
    import re
     
    # on ouvre le fichier srt pour le modifier
    list_time_code = []
    srt_rewrite = []
    text = []
    with open(
        'D:\musique western et autres\Australia\Peter Weir\Picnic at Hanging Rock (1975)\Picnic at Hanging Rock (1).srt'
        ,'r') as srt_origin :
     
        # on crée une liste de toutes les time code pour les modifier
        counter_line = 0
        for line in srt_origin:
            list_time_code += (re.findall(r'(\d{2}:\d{2}:\d{2},\d{3})', line))
            if line == '\n':
                text += str(line)
            else:
                text += ('\n')
                text[counter_line] += str(line)
                counter_line += 1
     
    # On décale tout les sous-titres de 10 secondes avant
    for index in range(len(list_time_code)):
        time_code = datetime.datetime.strptime(list_time_code[index], '%H:%M:%S,%f')
        time_code_add = time_code + datetime.timedelta(seconds=-10)
        time_code = datetime.datetime.strftime(time_code_add, '%H:%M:%S,%f')
        time_code = time_code[:-3]
        list_time_code[index] = time_code
     
    # On modifie la liste des times codes pour avoir les times codes au bon format
    counter_line = 0
    counter_time_code = 0
    while counter_time_code < (len(list_time_code) - 1):
        list_time_code[counter_line] = (list_time_code[counter_time_code] + ' --> '
                                               + list_time_code[counter_time_code + 1] + '\n')
        counter_line += 1
        counter_time_code += 2
     
    # On remplace les times codes
    counter_time_code = 0
    counter_line = 0
    for line in text:
        if '-->' in line:
            text[counter_line] = list_time_code[counter_time_code]
            counter_time_code += 1
        counter_line += 1
    print(text)
     
    # J'essaye de supprimer les retours à la ligne pour avoir un format correct, ça marche pas, je comprends pas -_-
    counter_line = 0
    for line in text:
        text[counter_line].replace('\n','')
        counter_line += 1
    print(text)
     
    # Ecrtiure du fichier
    with open(
            'D:\musique western et autres\Australia\Peter Weir\Picnic at Hanging Rock (1975)\Picnic at Hanging Rock (1)_d.srt'
            ,'w') as srt_copy:
        for line in text:
            srt_copy.write(line)

  8. #8
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    je te propose ça, plus concis, ça n'est pas parfait mais ça doit faire le job :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    from datetime import datetime, timedelta
    from re import findall
     
    fichier_in  = 'Picnic at Hanging Rock.srt'
    fichier_out = 'nouveau.srt'
    intervale   = timedelta(seconds=-10)
     
    with open(fichier_in, 'r') as f:
       buffer = ''
       for line in f:
          if '-->' in line:
             m = findall(r'(\d{2}:\d{2}:\d{2},\d{3})', line)
             buffer += '{} --> {}\n'.format(
                datetime.strftime(datetime.strptime(m[0], '%H:%M:%S,%f') + intervale, '%H:%M:%S,%f')[:-3],
                datetime.strftime(datetime.strptime(m[1], '%H:%M:%S,%f') + intervale, '%H:%M:%S,%f')[:-3]
             )
          else:
             buffer += line
     
    with open(fichier_out, 'w') as f:
       f.write(buffer)

  9. #9
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2018
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2018
    Messages : 70
    Par défaut
    Merci bien, l'étape suivante serait de faire une interface graphique pour pouvoir lire la vidéo et dire où les sous-titres doivent commencer pour que le programme calcule le décalage lui-même. Je vais m'y atteler au travail et je changerai de forum surement pour poser des questions sur le PyQt

  10. #10
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 670
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 670
    Par défaut
    Salut,

    Pour le fun, juste un exemple pour faire çà avec re.sub:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import re
    from datetime import datetime, timedelta
     
    def shift_timecode(data, seconds):
        pattern = r'\d{2}:\d{2}:\d{2},\d{3}'
        rg1, rg2 = re.compile(pattern), re.compile(
                   pattern + ' --> ' + pattern, re.M)
     
        strptime, strftime = datetime.strptime, datetime.strftime
        interval = timedelta(seconds=seconds)
        new_date = lambda s: strftime(
                            strptime(s,'%H:%M:%S,%f') + interval,
                            '%H:%M:%S,%f')[:-3]
        def replace_line(m):
            replace_dt = lambda m: new_date(m.group())
            return rg1.sub(replace_dt, m.group()) 
     
        return rg2.sub(replace_line, data)
     
    if __name__ == '__main__':
        fichier_in  = 'test.srt'
        fichier_out = 'nouveau.srt'
     
        with open(fichier_in) as f1, open(fichier_out, 'w') as f2 :
            f2.write(shift_timecode(f1.read(), -10))
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Ajouter des sous titres dans une combo box
    Par Djaiffe dans le forum VB.NET
    Réponses: 5
    Dernier message: 24/05/2018, 16h55
  2. remplacer des sous titres d une video
    Par kaking dans le forum Vidéo
    Réponses: 0
    Dernier message: 10/06/2009, 14h22
  3. free soft : pour masqué un sous titre dans une vidéo?
    Par devlopassion dans le forum Vidéo
    Réponses: 0
    Dernier message: 03/02/2009, 12h00
  4. Réponses: 0
    Dernier message: 17/01/2009, 11h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo