-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstitch.py
150 lines (120 loc) · 4.57 KB
/
stitch.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
"""
stitch.py
Automated Video Branding Tool
Author: Marko Prodanovic
"""
# Standard imports
import os
import logging
# Moviepy (primary library)
# Docs: https://zulko.github.io/moviepy/index.html
from moviepy.editor import VideoFileClip, concatenate_videoclips
from moviepy.video.fx.fadein import fadein
from moviepy.video.fx.fadeout import fadeout
from moviepy.audio.fx.audio_fadeout import audio_fadeout
from moviepy.audio.fx.audio_fadein import audio_fadein
# Additional dependencies
from termcolor import cprint
# Local modules
from top.top import Top
from helpers import load_specifications, get_video_attributes, archive_folder_contents
def stitch():
"""
Stitch the top, body and tail clips together
"""
# project root directory
root = os.path.dirname(os.path.abspath(__file__))
cprint("\nLoading Specifications from CSV...", "yellow")
specs = load_specifications(root + "/input")
cprint("Archiving & clearing output folder...", "yellow")
logging.info("Archiving & clearing output folder...")
archive_folder_contents("output")
for index, row in specs.iterrows():
print("\n------------------------------------------\n")
try:
specs = get_video_attributes(row)
except ValueError:
cprint("Skipping video...", "red")
attempted_video_title = row["Title"]
logging.error(
"Invalid values in specs. Skipping video: %s, row: %i",
attempted_video_title,
index,
)
continue
video_id = specs["id"]
course = specs["course"]
section = specs["section"]
instructor = specs["instructor"]
title = specs["title"]
tail = specs["tail"]
top_slate = specs["top_slate"]
cprint(f"Starting top/tail stitching for <row {index}>:", "yellow")
logging.info(
"Starting TOP/TAIL STITCHING for <row %i> | %s - %s",
index,
title,
instructor,
)
print(f"\nVIDEO TITLE: {title}")
print(f"COURSE: {course}")
print(f"INSTRUCTOR NAME: {instructor}")
print(f"UNIQUE ID: {video_id}\n")
top = Top(
top_slate=top_slate,
title=title,
course=course,
section=section,
instructor=instructor,
)
top_rendered = top.get_video()
tail = VideoFileClip(f"input/tail/{tail}").fx(audio_fadein, duration=1.5)
input_folder = f"input/body/PROCESSED/{title}_{instructor}_{video_id}"
output_folder = f"output/{title}_{instructor}_{video_id}"
if not instructor:
input_folder = f"input/body/PROCESSED/{title}_{video_id}"
output_folder = f"output/{title}_{video_id}"
for clip_name in os.listdir(input_folder):
try:
body_video = (
VideoFileClip(f"{input_folder}/{clip_name}")
.fx(fadein, duration=1, initial_color=[255, 255, 255])
.fx(fadeout, duration=1, final_color=[255, 255, 255])
.fx(audio_fadeout, duration=2)
.fx(audio_fadein, duration=1.5)
)
final_clip = concatenate_videoclips([top_rendered, body_video, tail])
except OSError:
cprint(
f'Could not find specifiied clip: "{clip_name}" in folder: ', "red"
)
logging.error(
'Could not find specifiied clip: "%s" in folder: "%s". Skipping video...',
clip_name,
input_folder,
)
cprint(input_folder, "yellow")
cprint("Skipping video...", "red")
continue
if not os.path.exists(output_folder):
os.makedirs(output_folder)
cprint(f"Writing to output folder: \n=> {output_folder}\n", "blue")
output_video_path = f"{output_folder}/{clip_name}"
try:
final_clip.write_videofile(
output_video_path,
fps=30,
threads=8,
preset="ultrafast",
temp_audiofile="temp-audio.m4a",
remove_temp=True,
codec="libx264",
audio_codec="aac",
)
cprint("\nSUCCESS", "green")
except Exception as error:
logging.error(error)
cprint(error, "red")
continue
if __name__ == "__main__":
stitch()