File size: 4,267 Bytes
baaf343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
430125e
 
 
 
 
baaf343
 
 
 
 
 
430125e
baaf343
430125e
baaf343
430125e
baaf343
 
 
 
430125e
baaf343
430125e
 
 
 
 
 
 
 
 
 
 
 
 
baaf343
 
371799a
baaf343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1b31ab
baaf343
 
 
 
 
 
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import os, re, uuid, traceback
from moviepy.editor import VideoFileClip
import moviepy.video.fx.all as vfx
from .config import OUT_DIR, W, H

def safe_name(stem, ext=".mp4"):
    stem = re.sub(r"[^\w\-]+", "_", stem)[:40]
    return f"{stem}_{uuid.uuid4().hex[:6]}{ext}"

def prepare_video_presentateur(video_path, audio_duration, position, plein_ecran=False):
    """Prépare la vidéo du présentateur avec la bonne durée et position."""
    try:
        print(f"[Video] Chargement: {video_path}")
        if not os.path.exists(video_path):
            print(f"[Video] ❌ Fichier introuvable: {video_path}")
            return None

        v = VideoFileClip(video_path).without_audio()
        print(f"[Video] Durée vidéo: {v.duration}s, Audio: {audio_duration}s")

        if v.duration < audio_duration:
            print(f"[Video] Bouclage nécessaire ({v.duration}s -> {audio_duration}s)")
            v = v.fx(vfx.loop, duration=audio_duration)
        elif v.duration > audio_duration:
            print(f"[Video] Découpage nécessaire ({v.duration}s -> {audio_duration}s)")
            v = v.subclip(0, audio_duration)

        if plein_ecran:
            print(f"[Video] Mode plein écran")
            v = v.resize(newsize=(W, H)).set_position(("center", "center"))
        else:
            print(f"[Video] Mode incrustation, position: {position}")
            v = v.resize(width=520)
            pos_map = {
                "bottom-right": ("right", "bottom"),
                "bottom-left": ("left", "bottom"),
                "top-right": ("right", "top"),
                "top-left": ("left", "top"),
                "center": ("center", "center"),
            }
            v = v.set_position(pos_map.get(position, ("right", "bottom")))

        print(f"[Video] ✅ Vidéo préparée avec succès")
        return v

    except Exception as e:
        print(f"[Video] ❌ Erreur préparation: {e}")
        print(f"[Video] Traceback: {traceback.format_exc()}")
        return None

def write_srt(text, duration, base_name=None):
    """
    Crée un fichier SRT synchronisé avec la durée audio.
    Si base_name est fourni, le fichier SRT porte ce nom fixe.
    """
    parts = re.split(r'(?<=[\.!?])\s+', text.strip())
    parts = [p for p in parts if p]
    total = len("".join(parts)) or 1
    cur = 0.0
    srt = []
    for i, p in enumerate(parts, 1):
        prop = len(p) / total
        start = cur
        end = min(duration, cur + duration * prop)
        cur = end

        def ts(t):
            m, s = divmod(t, 60)
            h, m = divmod(m, 60)
            return f"{int(h):02}:{int(m):02}:{int(s):02},000"

        srt += [f"{i}", f"{ts(start)} --> {ts(end)}", p, ""]

    # Nom du fichier SRT
    if base_name:
        safe_base = re.sub(r'[^\w\-]+', '_', base_name)[:40]
        path = os.path.join(OUT_DIR, f"{safe_base}.srt")
    else:
        path = os.path.join(OUT_DIR, f"srt_default.srt")

    # Écriture du fichier
    with open(path, "w", encoding="utf-8") as f:
        f.write("\n".join(srt))

    print(f"[SRT] ✅ Fichier SRT généré : {path}")
    return path


def write_video_with_fallback(final_clip, out_path_base, fps=25):
    attempts = [
        {"ext": ".mp4", "codec": "libx264", "audio_codec": "aac"},
        {"ext": ".mp4", "codec": "mpeg4",  "audio_codec": "aac"},
        {"ext": ".mp4", "codec": "libx264", "audio_codec": "libmp3lame"},
    ]
    ffmpeg_params = ["-pix_fmt", "yuv420p", "-movflags", "+faststart", "-threads", "1", "-shortest"]
    last_err = None
    for opt in attempts:
        out = out_path_base if out_path_base.endswith(opt["ext"]) else out_path_base + opt["ext"]
        try:
            final_clip.write_videofile(
                out,
                fps=fps,
                codec=opt["codec"],
                audio_codec=opt["audio_codec"],
                audio=True,
                ffmpeg_params=ffmpeg_params,
                logger=None,
                threads=os.cpu_count(),  # ✅ multi-threading activé
            )
            if os.path.exists(out) and os.path.getsize(out) > 150000:
                return out
        except Exception as e:
            last_err = f"{type(e).__name__}: {e}"
    raise RuntimeError(last_err or "FFmpeg a échoué")