File size: 2,706 Bytes
c6771b3
 
8b05224
c6771b3
 
 
 
8b05224
c6771b3
8b05224
 
 
 
 
c6771b3
8b05224
 
 
c6771b3
8b05224
c6771b3
 
 
 
 
8b05224
 
c6771b3
 
 
8b05224
 
 
 
c6771b3
8b05224
 
 
c6771b3
 
 
8b05224
c6771b3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8b05224
c6771b3
 
8b05224
 
 
 
 
c6771b3
8b05224
c6771b3
8b05224
c6771b3
8b05224
c6771b3
8b05224
 
 
 
 
c6771b3
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
from pathlib import Path
from typing import Optional, List, Dict

from moviepy import (
    VideoFileClip, AudioFileClip, CompositeAudioClip,
    CompositeVideoClip
)

from scripts.generate_subtitles import create_animated_subtitle_clip


def edit_video(

    video_path: str,

    audio_path: str,

    music_path: Optional[str],

    output_path: str,

    *,

    music_volume: float = 0.10,

    subtitles: Optional[List[Dict]] = None,   # ← nouveau

):
    """

    Encodage final : ajoute voix, (optionnel) musique et sous-titres

    en UNE seule passe.

    """
    vid_clip   = VideoFileClip(video_path)
    voice_clip = AudioFileClip(audio_path)

    # ── piste audio composite ─────────────────────────────────
    tracks = [voice_clip]
    if music_path and Path(music_path).is_file():
        try:
            music_clip = (
                AudioFileClip(music_path)
                .with_volume_scaled(music_volume)
                .with_duration(vid_clip.duration)
            )
            tracks.insert(0, music_clip)
        except Exception as err:
            print(f"⚠️ Music ignored: {err}")

    final_audio = CompositeAudioClip(tracks).with_duration(vid_clip.duration)

    # ── couche(s) vidΓ©o / sous-titres ─────────────────────────
    layers = [vid_clip]
    if subtitles:
        w, h = vid_clip.size
        for sub in subtitles:
            layers.append(
                create_animated_subtitle_clip(
                    sub["text"], sub["start"], sub["end"], w, h
                )
            )

    final_clip = (
        CompositeVideoClip(layers, size=vid_clip.size)
        .with_duration(vid_clip.duration)
        .with_audio(final_audio)
    )

    # ── export ────────────────────────────────────────────────
    Path(output_path).parent.mkdir(parents=True, exist_ok=True)
    final_clip.write_videofile(
        output_path,
        codec="libx264",
        audio_codec="aac",
        fps=30,
        threads=os.cpu_count(),
        preset="medium",
        ffmpeg_params=["-pix_fmt", "yuv420p"]
    )
    print(f"βœ… Video written β†’ {output_path}")

    # ── nettoyage ─────────────────────────────────────────────
    voice_clip.close()
    if "music_clip" in locals():
        music_clip.close()
    final_audio.close()
    final_clip.close()
    vid_clip.close()