Skip to content

Commit e37f2db

Browse files
committed
feat: add dynamic configs for background + progress loader during download process
1 parent 9f117bc commit e37f2db

File tree

9 files changed

+144
-52
lines changed

9 files changed

+144
-52
lines changed

background/Minecraft.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from background.utils import Background
2+
3+
4+
class Minecraft(Background):
5+
def __init__(self):
6+
super().__init__(
7+
"https://www.youtube.com/watch?v=n_Dv4JMiwK8",
8+
"parkour.mp4",
9+
"bbswitzer",
10+
"center"
11+
)

background/MotorGTA.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from background.utils import Background
2+
3+
4+
class MotorGTA(Background):
5+
def __init__(self):
6+
super().__init__(
7+
"https://www.youtube.com/watch?v=vw5L4xCPy9Q",
8+
"bike-parkour-gta.mp4",
9+
"Achy Gaming",
10+
lambda t : ('center', 480 + t)
11+
)

background/RocketLeague.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from background.utils import Background
2+
3+
4+
class RocketLeague(Background):
5+
def __init__(self):
6+
super().__init__(
7+
"https://www.youtube.com/watch?v=2X9QGY__0II",
8+
"rocket_league.mp4",
9+
"Orbital Gameplay",
10+
"top"
11+
)

background/__init__.py

Whitespace-only changes.

background/swapper.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import imp
2+
from os import getenv
3+
4+
from dotenv import load_dotenv
5+
6+
from background.Minecraft import Minecraft
7+
from background.MotorGTA import MotorGTA
8+
from background.RocketLeague import RocketLeague
9+
from utils.console import print_substep
10+
11+
CHOICE_DIR = {"motor-gta": MotorGTA, "rocket-league": RocketLeague, "minecraft": Minecraft}
12+
13+
14+
class BackgroundFactory:
15+
def __new__(cls):
16+
load_dotenv()
17+
try:
18+
CHOICE = getenv("BackgroundChoice").casefold()
19+
except AttributeError:
20+
print_substep("None (background) defined. Defaulting to 'minecraft.'")
21+
CHOICE = "minecraft"
22+
valid_keys = [key.lower() for key in CHOICE_DIR.keys()]
23+
if CHOICE not in valid_keys:
24+
raise ValueError(f"{CHOICE} is not valid. Please use one of these {valid_keys} options")
25+
return CHOICE_DIR.get(CHOICE)()

background/utils.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from os import listdir, path
2+
from pathlib import Path
3+
from pytube import YouTube
4+
from rich.progress import Progress
5+
from utils.console import print_step, print_substep
6+
7+
class DownloaderProgressBar:
8+
def __init__(self):
9+
self.bar = Progress(transient=True)
10+
self.task = self.bar.add_task("Downloading background video...", total=100)
11+
self.p = 0
12+
def progress_function(self,stream, chunk, bytes_remaining):
13+
percentage = lambda rem, total : (float(rem) / float(total)) * float(100)
14+
size = stream.filesize
15+
p = 0
16+
with self.bar as progress:
17+
while p <= 100 and not progress.finished:
18+
p = 100.0 - percentage(bytes_remaining, size)
19+
progress.update(self.task, advance=p)
20+
self.p = p
21+
22+
def download_background(background_option):
23+
"""Downloads the backgrounds/s video from YouTube."""
24+
Path("./assets/backgrounds/").mkdir(parents=True, exist_ok=True)
25+
# note: make sure the file name doesn't include an - in it
26+
uri, filename, credit = background_option
27+
if Path(f"assets/backgrounds/{credit}-{filename}").is_file():
28+
return
29+
print_step(
30+
"We need to download the backgrounds videos. they are fairly large but it's only done once. 😎"
31+
)
32+
print_substep("Downloading the backgrounds videos... please be patient 🙏 ")
33+
print_substep(f"Downloading {filename} from {uri}")
34+
pbar = DownloaderProgressBar()
35+
YouTube(uri, on_progress_callback=pbar.progress_function).streams.filter(res="1080p").first().download(
36+
"assets/backgrounds", filename=f"{credit}-{filename}"
37+
)
38+
print_substep("Background videos downloaded successfully! 🎉", style="bold green")
39+
40+
class Background:
41+
def __init__(self, uri, filename, credit, pos):
42+
self.uri = uri
43+
self.filename = filename
44+
self.credit = credit
45+
self.pos = pos
46+
47+
option = (self.uri, self.filename, self.credit)
48+
download_background(option)
49+
50+
def get_img_clip_pos(self):
51+
return self.pos
52+
53+
def get_filename(self):
54+
return f"{self.credit}-{self.filename}"
55+

main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ def main():
4242
reddit_object = get_subreddit_threads()
4343
length, number_of_comments = save_text_to_mp3(reddit_object)
4444
download_screenshots_of_reddit_posts(reddit_object, number_of_comments)
45-
download_background()
46-
chop_background_video(length)
47-
make_final_video(number_of_comments, length)
45+
bg = download_background()
46+
chop_background_video(bg, length)
47+
make_final_video(bg, number_of_comments, length)
4848

4949

5050
def run_many(times):

video_creation/background.py

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99

1010
from utils.console import print_step, print_substep
1111

12+
from background.swapper import BackgroundFactory
1213

13-
def get_start_and_end_times(video_length:int, length_of_clip:int)->tuple[int,int]:
14+
15+
def get_start_and_end_times(video_length: int, length_of_clip: int) -> tuple[int, int]:
1416
"""Generates a random interval of time to be used as the beckground of the video.
1517
1618
Args:
@@ -19,56 +21,32 @@ def get_start_and_end_times(video_length:int, length_of_clip:int)->tuple[int,int
1921
2022
Returns:
2123
tuple[int,int]: Start and end time of the randomized interval
22-
"""
24+
"""
2325
random_time = randrange(180, int(length_of_clip) - int(video_length))
2426
return random_time, random_time + video_length
2527

2628

2729
def download_background():
2830
"""Downloads the backgrounds/s video from YouTube."""
29-
Path("./assets/backgrounds/").mkdir(parents=True, exist_ok=True)
30-
background_options = [ # uri , filename , credit
31-
("https://www.youtube.com/watch?v=n_Dv4JMiwK8", "parkour.mp4", "bbswitzer"),
32-
# (
33-
# "https://www.youtube.com/watch?v=2X9QGY__0II",
34-
# "rocket_league.mp4",
35-
# "Orbital Gameplay",
36-
# ),
37-
]
38-
# note: make sure the file name doesn't include an - in it
39-
if not len(listdir("./assets/backgrounds")) >= len(
40-
background_options
41-
): # if there are any background videos not installed
42-
print_step(
43-
"We need to download the backgrounds videos. they are fairly large but it's only done once. 😎"
44-
)
45-
print_substep("Downloading the backgrounds videos... please be patient 🙏 ")
46-
for uri, filename, credit in background_options:
47-
if Path(f"assets/backgrounds/{credit}-{filename}").is_file():
48-
continue # adds check to see if file exists before downloading
49-
print_substep(f"Downloading {filename} from {uri}")
50-
YouTube(uri).streams.filter(res="1080p").first().download(
51-
"assets/backgrounds", filename=f"{credit}-{filename}"
52-
)
31+
bg = BackgroundFactory()
32+
return bg
5333

54-
print_substep(
55-
"Background videos downloaded successfully! 🎉", style="bold green"
56-
)
5734

58-
59-
def chop_background_video(video_length:int):
35+
def chop_background_video(bg, video_length: int):
6036
"""Generates the background footage to be used in the video and writes it to assets/temp/background.mp4
6137
6238
Args:
6339
video_length (int): Length of the clip where the background footage is to be taken out of
64-
"""
40+
"""
41+
6542
print_step("Finding a spot in the backgrounds video to chop...✂️")
66-
choice = random.choice(listdir("assets/backgrounds"))
43+
choice = bg.get_filename()
6744
environ["background_credit"] = choice.split("-")[0]
6845

6946
background = VideoFileClip(f"assets/backgrounds/{choice}")
7047

71-
start_time, end_time = get_start_and_end_times(video_length, background.duration)
48+
start_time, end_time = get_start_and_end_times(
49+
video_length, background.duration)
7250
try:
7351
ffmpeg_extract_subclip(
7452
f"assets/backgrounds/{choice}",

video_creation/final_video.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,20 @@
2020
from utils.cleanup import cleanup
2121
from utils.console import print_step, print_substep
2222

23+
2324
console = Console()
2425

2526
W, H = 1080, 1920
2627

2728

28-
def make_final_video(number_of_clips:int, length:int):
29+
def make_final_video(bg, number_of_clips: int, length: int):
2930
"""Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp
3031
3132
Args:
3233
number_of_clips (int): Index to end at when going through the screenshots
3334
length (int): Length of the video
34-
"""
35+
"""
36+
3537
print_step("Creating the final video 🎥")
3638
VideoFileClip.reW = lambda clip: clip.resize(width=W)
3739
VideoFileClip.reH = lambda clip: clip.resize(width=H)
@@ -64,19 +66,20 @@ def make_final_video(number_of_clips:int, length:int):
6466
if (
6567
opacity is None or float(opacity) >= 1
6668
): # opacity not set or is set to one OR MORE
69+
6770
image_clips.insert(
6871
0,
6972
ImageClip("assets/temp/png/title.png")
7073
.set_duration(audio_clips[0].duration)
71-
.set_position("center")
74+
.set_position(bg.get_img_clip_pos())
7275
.resize(width=W - 100),
7376
)
7477
else:
7578
image_clips.insert(
7679
0,
7780
ImageClip("assets/temp/png/title.png")
7881
.set_duration(audio_clips[0].duration)
79-
.set_position("center")
82+
.set_position(bg.get_img_clip_pos())
8083
.resize(width=W - 100)
8184
.set_opacity(float(opacity)),
8285
)
@@ -88,14 +91,12 @@ def make_final_video(number_of_clips:int, length:int):
8891
image_clips.append(
8992
ImageClip(f"assets/temp/png/comment_{i}.png")
9093
.set_duration(audio_clips[i + 1].duration)
91-
.set_position("center")
9294
.resize(width=W - 100),
9395
)
9496
else:
9597
image_clips.append(
9698
ImageClip(f"assets/temp/png/comment_{i}.png")
9799
.set_duration(audio_clips[i + 1].duration)
98-
.set_position("center")
99100
.resize(width=W - 100)
100101
.set_opacity(float(opacity)),
101102
)
@@ -110,16 +111,14 @@ def make_final_video(number_of_clips:int, length:int):
110111
# .set_opacity(float(opacity)),
111112
# )
112113
# else:
113-
image_concat = concatenate_videoclips(image_clips).set_position(
114-
("center", "center")
115-
)
114+
115+
image_concat = concatenate_videoclips(
116+
image_clips).set_position(bg.get_img_clip_pos())
116117
image_concat.audio = audio_composite
117118
final = CompositeVideoClip([background_clip, image_concat])
118119

119-
120120
filename = f"{get_video_title()}.mp4"
121121

122-
123122
save_data(filename)
124123

125124
if not exists("./results"):
@@ -147,12 +146,13 @@ def make_final_video(number_of_clips:int, length:int):
147146
f"Reddit title: {os.getenv('VIDEO_TITLE')} \n Background Credit: {os.getenv('background_credit')}"
148147
)
149148

150-
def save_data(filename:str):
149+
150+
def save_data(filename: str):
151151
"""Saves the videos that have already been generated to a JSON file in video_creation/data/videos.json
152152
153153
Args:
154154
filename (str): The finished video title name
155-
"""
155+
"""
156156
with open("./video_creation/data/videos.json", "r+") as raw_vids:
157157
done_vids = json.load(raw_vids)
158158
if str(subreddit.submission.id) in [video["id"] for video in done_vids]:
@@ -168,14 +168,15 @@ def save_data(filename:str):
168168
raw_vids.seek(0)
169169
json.dump(done_vids, raw_vids, ensure_ascii=False, indent=4)
170170

171+
171172
def get_video_title() -> str:
172173
"""Gets video title from env variable or gives it the name "final_video"
173174
174175
Returns:
175176
str: Video title
176-
"""
177+
"""
177178
title = os.getenv("VIDEO_TITLE") or "final_video"
178179
if len(title) <= 35:
179180
return title
180181
else:
181-
return title[0:30] + "..."
182+
return title[0:30] + "..."

0 commit comments

Comments
 (0)