malvin noel
changes
c6771b3
raw
history blame
2.71 kB
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()