-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
114 lines (80 loc) · 3.27 KB
/
main.py
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
import os
from collections import namedtuple
from datetime import datetime, timedelta
from enum import Enum
from multiprocessing import Pool
from moviepy.editor import CompositeAudioClip, VideoFileClip
THREADS = int(os.getenv("THREADS", 1))
PROCESSES = int(os.getenv("PROCESSES", os.cpu_count()))
# This is the master-piece from Maccio
master = VideoFileClip("auguri.mp4")
# Here we extract the sub-clips for all the different occasions:
BaseVideoClip = namedtuple("BaseVideoClip", ["name", "clip"])
class BaseClip(Enum):
BIRTHDAY = "compleanno"
DIPLOMA = "laurea"
WEDDING = "matrimonio"
DEATH = "morte"
BASE_CLIPS = {
BaseClip.BIRTHDAY: BaseVideoClip("compleanno", master.subclip(49.5, 55)),
BaseClip.DIPLOMA: BaseVideoClip("laurea", master.subclip(57.3, 62)),
BaseClip.WEDDING: BaseVideoClip("matrimonio", master.subclip(63.8, 70)),
BaseClip.DEATH: BaseVideoClip(
"morte", master.subclip(17 * 60 + 31.8, 17 * 60 + 36)
),
}
# For each name we'll keep a data structure with the corresponding
# starting and ending time on the master track, so we can extract
# the relevant audio clip:
NameClip = namedtuple("NameClip", ["start", "stop"])
def load_names(path="names.txt"):
loaded_names = {}
with open(path, "r") as names:
while True:
start_time_line = names.readline().rstrip()
if not start_time_line:
break
try:
start_time = datetime.strptime(start_time_line, "%M:%S.%f")
except ValueError:
start_time = datetime.strptime(start_time_line, "%M:%S")
end_time = (start_time + timedelta(seconds=2)).strftime("%M:%S.%f")
name = names.readline().rstrip()
loaded_names[name] = NameClip(start_time_line, end_time)
return loaded_names
NAMES = load_names()
def get_name_clip(name):
found = NAMES[name]
return master.subclip(found.start, found.stop).audio
def overlay_name(name_clip, base_clip=BaseClip.BIRTHDAY):
master_clip = BASE_CLIPS[base_clip].clip
composite_audio = CompositeAudioClip(
clips=[master_clip.audio, name_clip.set_start(1.2)],
)
return master_clip.set_audio(composite_audio)
def make_clip(name, base_clip=BaseClip.BIRTHDAY):
name_clip = get_name_clip(name)
return overlay_name(name_clip, base_clip=base_clip)
def reload_clip(name, base_clip=BaseClip.BIRTHDAY):
global NAMES
NAMES = load_names()
make_clip(name, base_clip=base_clip).write_videofile(
f"output/{base_clip.value}/{name}.mp4", threads=THREADS
)
def generate_and_save_clip(name, clip_type):
output_file = f"output/{clip_type.value}/{name}.mp4"
if os.path.exists(output_file):
return
print(f"Making clip {output_file}")
clip = make_clip(name=name, base_clip=clip_type)
clip.write_videofile(output_file, threads=THREADS)
if __name__ == "__main__":
with Pool(PROCESSES) as pool:
# Pre-generate all possible clips
clip_combinations = []
for clip_type in BaseClip:
os.makedirs(f"output/{clip_type.value}", exist_ok=True)
for name in NAMES:
clip_combinations.append((name, clip_type))
# Run them on the multiprocess pool
pool.starmap(generate_and_save_clip, clip_combinations)