-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
update invoke tasks to build and stitch videos.
- Loading branch information
Showing
4 changed files
with
76 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,20 @@ | ||
# IllustratedGraphBLAS | ||
# IllustratedGraphBLAS | ||
|
||
To build a scene in a chapter | ||
|
||
``` | ||
invoke build-scene --chapter Chapter0 --scene Scene0 --quality l | ||
``` | ||
|
||
To build all scenes in a chapter: | ||
|
||
``` | ||
invoke build-chapter --chapter Chapter0 --quality l | ||
``` | ||
|
||
To stich all scenes in a final video | ||
|
||
``` | ||
invoke stitch-videos --chapter Chapter0 --quality l | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,63 @@ | ||
import os | ||
import shutil | ||
import glob | ||
from invoke import task | ||
from pathlib import Path | ||
import subprocess | ||
|
||
MANIM = "manim" | ||
MANIM_FLAGS = "-ql" | ||
OUTPUT_DIR = Path("media/videos") | ||
@task | ||
def build_scene(ctx, chapter, scene, quality='l'): | ||
command = f"manim -q{quality} {scene}.py" | ||
with ctx.cd(chapter): | ||
ctx.run(command) | ||
|
||
def scenes_in_chapter(chapter): | ||
return sorted(Path(chapter).glob("Scene*.py")) | ||
@task | ||
def build_chapter(ctx, chapter, quality='l'): | ||
for filename in sorted(os.listdir(chapter)): | ||
if filename.startswith("Scene") and filename.endswith(".py"): | ||
scene = filename.replace(".py", "") | ||
build_scene(ctx, chapter, scene, quality) | ||
|
||
@task | ||
def render_scene(c, chapter, scene): | ||
"""Render a specific scene from a chapter.""" | ||
scene_file = f"{chapter}/{scene}.py" | ||
def stitch_videos(ctx, chapter, quality="l"): | ||
os.chdir(chapter) | ||
media_folder = os.path.join("media", "videos") | ||
video_files = [] | ||
resolution = dict(l='480p15', m='720p30', h='1080p60')[quality] | ||
|
||
search_pattern = os.path.join(media_folder, f"Scene*/{resolution}/Scene*.mp4") | ||
for video in glob.glob(search_pattern): | ||
if video.endswith(".mp4"): | ||
video_files.append(video) | ||
|
||
# Sort videos based on scene order (Scene0, Scene1, etc.) | ||
video_files.sort(key=lambda x: int(x.split("Scene")[-1].split(".")[0])) | ||
|
||
if not video_files: | ||
print(f"No videos found for resolution '{resolution}' in {media_folder}") | ||
return | ||
|
||
# Create temporary file list for ffmpeg | ||
with open(f"videos_to_stitch.txt", "w") as f: | ||
for video in video_files: | ||
f.write(f"file '{video}'\n") | ||
|
||
# Stitch videos using ffmpeg | ||
ctx.run(f"ffmpeg -f concat -safe 0 -i videos_to_stitch.txt -c copy video_{resolution}.mp4") | ||
os.unlink('videos_to_stitch.txt') | ||
os.chdir('..') | ||
|
||
if Path(scene_file).exists(): | ||
c.run(f"{MANIM} {MANIM_FLAGS} {scene_file} {scene}") | ||
else: | ||
print(f"Scene {scene_file} not found.") | ||
|
||
@task | ||
def build_chapter(c, chapter): | ||
"""Render all scenes in a chapter.""" | ||
for scene_file in scenes_in_chapter(chapter): | ||
scene_name = scene_file.stem | ||
render_scene(c, chapter, scene_name) | ||
def clean_media(ctx, chapter): | ||
media_folder = os.path.join(chapter, "media") | ||
|
||
if not os.path.exists(media_folder): | ||
print(f"No media folder found in {chapter}") | ||
return | ||
|
||
for root, dirs, files in os.walk(media_folder): | ||
for file in files: | ||
os.remove(os.path.join(root, file)) | ||
for dir in dirs: | ||
shutil.rmtree(os.path.join(root, dir)) | ||
|
||
print(f"Cleaned media folder in {chapter}") |