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