File size: 3,733 Bytes
d970572
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import re
import subprocess
import os
import glob
import logging

def get_scene_name(manim_code):
    match = re.search(r'class\s+(\w+)\s*\(\s*Scene\s*\)', manim_code)
    if match:
        return match.group(1)
    raise ValueError("No Scene class found in generated code")

def create_manim_video(video_data, manim_code, audio_file=None):
    logging.info("Starting to create Manim video")
    with open("generated_video.py", "w") as f:
        manim_code_clean = re.sub(r"```python", "", manim_code)
        manim_code_clean = manim_code_clean.replace("```", "").strip()
        f.write(manim_code_clean)
    
    scene_name = get_scene_name(manim_code_clean)
    logging.info(f"Identified scene name: {scene_name}")
    
    command = ["manim", "-qh", "generated_video.py", scene_name]
    logging.info(f"Running Manim with command: {' '.join(command)}")
    subprocess.run(command, check=True)
    
    search_pattern = os.path.join("media", "videos", "generated_video", "1080p60", f"{scene_name}.mp4")
    if not os.path.exists(search_pattern):
        logging.error(f"No rendered video found at: {search_pattern}")
        raise Exception(f"No rendered video found for scene {scene_name}")
    
    output_video = search_pattern
    final_output = "final_output.mp4"

    if audio_file and os.path.exists(audio_file):
        logging.info(f"Merging video with audio file: {audio_file}")
        
        video_duration_cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration", 
                             "-of", "default=noprint_wrappers=1:nokey=1", output_video]
        audio_duration_cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration", 
                             "-of", "default=noprint_wrappers=1:nokey=1", audio_file]
        
        video_duration = float(subprocess.check_output(video_duration_cmd).decode('utf-8').strip())
        audio_duration = float(subprocess.check_output(audio_duration_cmd).decode('utf-8').strip())
        
        logging.info(f"Video duration: {video_duration}s, Audio duration: {audio_duration}s")
        
        if audio_duration > video_duration:
            logging.info("Audio is longer than video, extending video duration")
            extended_video = "extended_video.mp4"
            padding_time = audio_duration - video_duration
            
            extend_cmd = [
                "ffmpeg", "-y",
                "-i", output_video,
                "-f", "lavfi", "-i", "color=black:s=1920x1080:r=60",
                "-filter_complex", f"[0:v][1:v]concat=n=2:v=1:a=0[outv]",
                "-map", "[outv]",
                "-c:v", "libx264",
                "-t", str(audio_duration),
                extended_video
            ]
            
            logging.info(f"Extending video with command: {' '.join(extend_cmd)}")
            subprocess.run(extend_cmd, check=True)
            output_video = extended_video
        
        merge_cmd = [
            "ffmpeg", "-y",
            "-i", output_video,
            "-i", audio_file,
            "-c:v", "copy",
            "-c:a", "aac",
            "-map", "0:v:0",
            "-map", "1:a:0",
            final_output
        ]
        
        logging.info(f"Merging with command: {' '.join(merge_cmd)}")
        subprocess.run(merge_cmd, check=True)
        output_video = final_output
        
        if os.path.exists("extended_video.mp4"):
            os.remove("extended_video.mp4")
            logging.info("Removed temporary extended video file")

    if os.path.exists("generated_video.py"):
        os.remove("generated_video.py")
        logging.info("Removed generated_video.py")

    logging.info(f"Final video created at: {output_video}")
    return output_video