From 4bb36fe4c86d1580ecde44f9291fdcb4480f184e Mon Sep 17 00:00:00 2001 From: lionel <.> Date: Thu, 26 Jun 2025 15:15:14 +0200 Subject: [PATCH] =?UTF-8?q?[multiplex]=20Correction=20multiple=20+=20premi?= =?UTF-8?q?=C3=A8re=20utilisation=20r=C3=A9elle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- multiplex/multiplex.py | 119 ++++++++++++++++++++++++++++------------- multiplex/setup.py | 2 +- 2 files changed, 83 insertions(+), 38 deletions(-) diff --git a/multiplex/multiplex.py b/multiplex/multiplex.py index bc4ec30..461651a 100644 --- a/multiplex/multiplex.py +++ b/multiplex/multiplex.py @@ -1,9 +1,9 @@ import os import sys import glob -from pymkv import MKVFile, MKVTrack - +import re from pathlib import Path +from pymkv import MKVFile, MKVTrack #: Dictionnaire de correspondance entre les codes de langue et leur nom complet en français LANG_MAP = { @@ -19,23 +19,42 @@ LANG_MAP = { 'nld': 'Néerlandais', } +TRADUCTIONS = { + "Forced": "Forcé", + "Full": "Complet", + "French": "Français", + "English": "Anglais", + "Japan": "Japonais", + "subtitle": "Sous-titre", +} + +def traduire(texte): + for ancien, nouveau in TRADUCTIONS.items(): + texte = re.sub(re.escape(ancien), nouveau, texte, flags=re.IGNORECASE) + return texte + def ligne_bleu(): """Affiche une ligne bleue pleine largeur dans le terminal.""" - cols = os.get_terminal_size().columns + try: + cols = os.get_terminal_size().columns + except OSError: + cols = 100 print("\033[0;34m" + "█" * cols + "\033[0m") def find_episode_file(source_dir, saison, episode): """ - Recherche un fichier d'épisode dans un répertoire donné. + Recherche un fichier d'épisode dans un répertoire donné (insensible à la casse). :param source_dir: Répertoire source :param saison: Numéro de la saison :param episode: Numéro de l'épisode :return: Chemin du fichier trouvé ou None """ - pattern = f"*S0{saison}E{episode}*.mkv" - files = glob.glob(os.path.join(source_dir, pattern)) - return files[0] if files else None + target = f"s0{saison}e{episode}".lower() + for file in glob.glob(os.path.join(source_dir, "*.mkv")): + if target in os.path.basename(file).lower(): + return file + return None def find_first_video_track_index(mkv_file): """ @@ -61,20 +80,26 @@ def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, des """ Traite un épisode en combinant les pistes vidéo et audio/sous-titres de deux sources. - La vidéo provient de source_1_file. - Les pistes audio et sous-titres sont priorisées depuis source_2_file. - Les pistes audio/sous-titres en français sont réorganisées, annotées et une seule est définie par défaut. - :param episode: Numéro de l'épisode (format chaîne "01", "02", etc.) :param source_dir_1: Répertoire contenant la source vidéo :param source_dir_2: Répertoire contenant la source audio/sous-titres :param saison: Numéro de saison :param serie_name: Nom de la série :param dest_dir: Répertoire de sortie + :return: None """ # Affiche une ligne bleue pour la lisibilité dans le terminal ligne_bleu() + # Crée le chemin complet pour le fichier de sortie + output_filename = f"{serie_name} S0{saison} E{episode}.mkv" + output_path = os.path.join(dest_dir, output_filename) + + # Vérifie si le fichier final existe déjà + if os.path.exists(output_path): + print(f'\033[91m{output_filename} existe déjà.\033[0m') + return + # Recherche les fichiers source correspondants à l'épisode source_1_file = find_episode_file(source_dir_1, saison, episode) source_2_file = find_episode_file(source_dir_2, saison, episode) @@ -89,12 +114,8 @@ def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, des if not source_1_file and not source_2_file: return - # Crée le chemin complet pour le fichier de sortie - output_filename = f"{serie_name} S0{saison} E{episode}.mkv" - output_path = os.path.join(dest_dir, output_filename) - # Crée un objet MKVFile pour le fichier final - mkv = MKVFile() + final_mkv = MKVFile() # Charge les fichiers source source_1_mkv = MKVFile(source_1_file) @@ -103,7 +124,7 @@ def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, des # Ajout de la piste vidéo principale video_track_index = find_first_video_track_index(source_1_mkv) if video_track_index is not None: - mkv.add_track(MKVTrack(source_1_file, track_id=video_track_index)) + final_mkv.add_track(source_1_mkv.tracks[video_track_index]) # Sélection des pistes audio (FR prioritaires) audio_tracks_fr = [t for t in source_2_mkv.tracks if t.track_type == 'audio' and t.language == 'fre'] @@ -123,35 +144,59 @@ def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, des subtitle_tracks_fr = [t for t in source_2_mkv.tracks if t.track_type == 'subtitles' and t.language == 'fre'] subtitle_tracks_other = [t for t in source_2_mkv.tracks if t.track_type == 'subtitles' and t.language != 'fre'] - for track in subtitle_tracks_fr + subtitle_tracks_other: - track.default_track = False - - # Renommage des pistes FR si exactement deux - if len(subtitle_tracks_fr) == 2: - for track in subtitle_tracks_fr: - codec = track.codec_id.upper() + for idx, track in enumerate(subtitle_tracks_fr): + track.default_track = (idx == 0) + if not track.track_name: + codec = track._track_codec if track.forced_track: track.track_name = f"FR Forcé [{codec}]" else: track.track_name = f"FR Complet [{codec}]" + for track in subtitle_tracks_other: + track.default_track = False + # Ajout de toutes les pistes audio et sous-titres for track in audio_tracks_fr + audio_tracks_other + subtitle_tracks_fr + subtitle_tracks_other: - mkv.add_track(track) + # Traduction des noms des pistes + track.track_name = traduire(track.track_name) + final_mkv.add_track(track) - # Traitement des chapitres : choix du fichier avec le plus de chapitres valides - chapters_1 = source_1_mkv.chapters or [] - chapters_2 = source_2_mkv.chapters or [] - if len(chapters_1) >= 4 and has_named_chapters(chapters_1) and len(chapters_1) >= len(chapters_2): - mkv.chapters = chapters_1 - elif len(chapters_2) >= 4 and has_named_chapters(chapters_2): - mkv.chapters = chapters_2 + # Traitement des chapitres + try: + chapters_1 = (source_1_mkv._info_json.get('chapters'))[0].get('num_entries') + except (AttributeError, IndexError): + chapters_1 = 0 + try: + chapters_2 = (source_2_mkv._info_json.get('chapters'))[0].get('num_entries') + except (AttributeError, IndexError): + chapters_2 = 0 + + valid_1 = chapters_1 >= 4 + valid_2 = chapters_2 >= 4 + + if valid_1 and len(chapters_1) >= len(chapters_2): + source_2_mkv.no_chapters() + elif valid_2: + source_1_mkv.no_chapters() else: - mkv.chapters = None + source_1_mkv.no_chapters() + source_2_mkv.no_chapters() - # Supprime le titre et génère le fichier final - mkv.title = "" - mkv.mux(output_path) + + # Éffacer tous les tags + source_1_mkv.no_global_tags() + source_2_mkv.no_global_tags() + final_mkv.no_global_tags() + + source_1_mkv.no_track_tags() + source_2_mkv.no_track_tags() + final_mkv.no_track_tags() + + final_mkv.title = "" + + #print(final_mkv.command(output_path)) + final_mkv.mux(output_path) print(f"✔ Fichier généré : {output_path}") def main(): @@ -162,7 +207,7 @@ def main(): et lance le traitement de chaque épisode (de 01 à 30). """ if len(sys.argv) != 5: - print("Usage: script.py ") + print(f'Usage: {sys.argv[0]} ') sys.exit(1) source_dir_1 = sys.argv[1] diff --git a/multiplex/setup.py b/multiplex/setup.py index b37be1f..9bca0d0 100644 --- a/multiplex/setup.py +++ b/multiplex/setup.py @@ -13,5 +13,5 @@ setup( 'multiplex=multiplex:main', ], }, - python_requires='>=3.6', + python_requires='>=3.9', )