-
Notifications
You must be signed in to change notification settings - Fork 20
/
build
executable file
·133 lines (96 loc) · 3.64 KB
/
build
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/bin/python3
"""A script for building and renaming all of the Manim scenes."""
import subprocess
import shutil
import os
import argparse
import re
from glob import glob
VIDEO_DIRECTORY = "video"
parser = argparse.ArgumentParser()
parser.add_argument(
"-s", "--scenes",
nargs='*',
help="the name of the scenes to build; builds all when omitted",
default=None,
)
parser.add_argument(
"-q", "--quality",
choices=["m", "h", "k"],
default="k",
help="the quality of the video (4K by default)"
)
parser.add_argument(
"-r", "--rename-only",
help="only perform scene renaming",
action='store_true',
)
os.chdir(os.path.dirname(os.path.abspath(__file__)))
arguments = parser.parse_args()
def render_scene(scene: str):
"""Render a single scene."""
quality_mapping = {
"m": (1280, 720, 30),
"h": (1920, 1080, 60),
"k": (3840, 2160, 60),
}
w, h, f = quality_mapping[arguments.quality]
build_dir = os.path.abspath(os.path.dirname(__file__))
if os.path.isfile(os.path.join(build_dir, ".short")):
w, h = h, w
args = ["python3", "-m", "manim", "scenes.py", "--fps", str(f), "-r", f"{w},{h}", "--disable_caching", scene]
if scene.lower().startswith("transparent"):
args.append("-t")
process = subprocess.Popen(args)
process.communicate()
if process.returncode != 0:
print(f"\nBuild failed with exit code {process.returncode}")
quit()
def rename_scene(scene: str):
"""Use Manim's partial movie txt file to rename the videos to 1.mp4, 2.mp4 etc..."""
partial_file_path = os.path.join(VIDEO_DIRECTORY, scene, "partial_movie_file_list.txt")
if os.path.exists(partial_file_path):
with open(partial_file_path) as f:
for i, video in enumerate(f.read().splitlines()[1:]):
path, name = os.path.split(video[11:-1])
ext = os.path.splitext(name)[1][1:]
original_path = os.path.join(path, name)
changed_path = os.path.join(path, f"{i+1}.{ext}")
os.rename(original_path, changed_path)
os.remove(partial_file_path)
else:
print(f"WARNING: Partial movie file list for scene '{scene}' doesn't exists, not doing anything!")
scenes = []
# please lord forgive me for I have sinned
# this is needed because classes ending with Transparent are going to be rendered transparently
# and classes that contain "Test" are ignored
with open("scenes.py", "r") as f:
for line in f.read().splitlines():
if match := re.match(r"\s*class\s+(.+?)\(.*Scene\)\s*:", line):
scenes.append(match.group(1))
if arguments.scenes is None or len(arguments.scenes) == 0:
# remove everything when no scene is specified
if not arguments.rename_only:
if os.path.exists(VIDEO_DIRECTORY):
shutil.rmtree(VIDEO_DIRECTORY)
for scene in scenes:
# skip test scenes
if "Test" in scene:
continue
if not arguments.rename_only:
render_scene(scene)
rename_scene(scene)
else:
for scene in arguments.scenes:
scene_folder = os.path.join(VIDEO_DIRECTORY, scene)
# remove only the scene and its folders when the scene is specified
if not arguments.rename_only:
if os.path.exists(scene_folder):
shutil.rmtree(scene_folder)
for ext in ["mp4", "mov"]:
scene_video = os.path.join(VIDEO_DIRECTORY, scene + f".{ext}")
if os.path.exists(scene_video):
os.remove(scene_video)
if not arguments.rename_only:
render_scene(scene)
rename_scene(scene)