File size: 2,639 Bytes
aeaa761
 
 
 
 
 
ac02dae
aeaa761
 
 
ac02dae
aeaa761
 
 
ac02dae
aeaa761
 
 
 
 
ac02dae
aeaa761
 
 
 
ac02dae
aeaa761
ac02dae
aeaa761
 
 
 
 
 
 
 
 
 
ac02dae
aeaa761
 
ac02dae
aeaa761
 
ac02dae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aeaa761
 
ac02dae
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
# src/rendering/video_assembler.py
import re
from pathlib import Path
from datetime import datetime
from moviepy import VideoFileClip, concatenate_videoclips
from src.utils.helpers import get_hash
from src.utils.smart_logger import logger

def assemble_final_video(project_config: dict, output_dir: Path, temp_dir):
    """Workflow Step 5: Combine all rendered scenes into a final video."""
    logger.start_operation("assemble_video", "Assembling final video")
    
    code_file_path = next((s["code_file"] for s in project_config["scenes"].values() if s.get("code_file")), None)
    if not code_file_path:
        logger.end_operation("assemble_video", "Can't find code file for scene order")
        return

    code_content = Path(code_file_path).read_text()
    match = re.search(r"SCENE_ORDER\s*=\s*(\[.*?\])", code_content, re.DOTALL)
    if not match:
        logger.end_operation("assemble_video", "SCENE_ORDER not found in code")
        return

    try:
        scene_order = eval(match.group(1))
        logger.quick_log("info", f"Scene order: {scene_order}")
    except:
        logger.end_operation("assemble_video", "Could not parse SCENE_ORDER")
        return

    video_clips = []
    for scene_name in scene_order:
        scene_data = project_config["scenes"].get(scene_name, {})
        video_path = scene_data.get("final_video_path")
        if video_path and Path(video_path).exists():
            clip = VideoFileClip(video_path)
            video_clips.append(clip)
        else:
            logger.quick_log("warn", f"Skipping {scene_name}: video not found")

    if not video_clips:
        logger.end_operation("assemble_video", "No video clips found to assemble")
        return

    try:
        final_video = concatenate_videoclips(video_clips)
        prompt_hash = get_hash(project_config.get("prompt", "no_prompt"))
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        output_file = output_dir / f"{prompt_hash}_{timestamp}.mp4"
        
        final_video.write_videofile(str(output_file), codec='libx264', audio_codec='aac', logger=None)
        
        for clip in video_clips:
            clip.close()
        
        file_size = output_file.stat().st_size / (1024*1024)
        logger.end_operation("assemble_video", f"Final video created: {output_file.name}", f"{file_size:.1f}MB")
        
    except Exception as e:
        logger.error_with_context("Final video creation failed", str(e))
        logger.end_operation("assemble_video", "Assembly failed")
    
    # Clean up temporary directory
    temp_dir.cleanup()
    logger.quick_log("info", "Temporary files cleaned up")