feat: screenshot position config & add download progress bar

pull/693/head
William9923 2 years ago
parent c4da2fa55a
commit 421502b93b

@ -81,6 +81,11 @@ AWS_VOICE="Joanna"
TIKTOK_VOICE="en_us_006" TIKTOK_VOICE="en_us_006"
#EXPLANATION Sets the voice for the TikTok TTS Engine. Check the file for more information on different voices. #EXPLANATION Sets the voice for the TikTok TTS Engine. Check the file for more information on different voices.
#OPTIONAL
BackgroundChoice="minecraft"
#EXPLANATION Sets the background for the video. Current available option : (minecraft,gta,rocket-league,motor-gta), but you can add other video easily (1080p). Check the file for more information on different background.
#OPTIONAL #OPTIONAL
STORYMODE="False" STORYMODE="False"
# IN-PROGRESS - not yet implemented # IN-PROGRESS - not yet implemented

@ -9,7 +9,7 @@ from utils.console import print_markdown, print_step
from utils.checker import check_env from utils.checker import check_env
# from utils.checker import envUpdate # from utils.checker import envUpdate
from video_creation.background import download_background, chop_background_video from video_creation.background import download_background, chop_background_video, get_background_config
from video_creation.final_video import make_final_video from video_creation.final_video import make_final_video
from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts
from video_creation.voices import save_text_to_mp3 from video_creation.voices import save_text_to_mp3
@ -37,9 +37,10 @@ def main(POST_ID=None):
length, number_of_comments = save_text_to_mp3(reddit_object) length, number_of_comments = save_text_to_mp3(reddit_object)
length = math.ceil(length) length = math.ceil(length)
download_screenshots_of_reddit_posts(reddit_object, number_of_comments) download_screenshots_of_reddit_posts(reddit_object, number_of_comments)
download_background() bg_config = get_background_config()
chop_background_video(length) download_background(bg_config)
make_final_video(number_of_comments, length, reddit_object) chop_background_video(bg_config, length)
make_final_video(number_of_comments, length, reddit_object, bg_config)
def run_many(times): def run_many(times):

@ -1,15 +1,53 @@
import random import random
from os import listdir, environ from os import listdir, environ, getenv
from pathlib import Path from pathlib import Path
import random
from random import randrange from random import randrange
from typing import Tuple from typing import Any, Tuple
from dotenv import load_dotenv
from moviepy.editor import VideoFileClip from moviepy.editor import VideoFileClip
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from pytube import YouTube from pytube import YouTube
from pytube.cli import on_progress
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
# Supported Background. Can add/remove background video here....
# <key>-<value> : key -> used as keyword for .env file. value -> background configuration
# Format (value):
# 1. Youtube URI
# 2. filename
# 3. Citation (owner of the video)
# 4. Position of image clips in the background. See moviepy reference for more information. (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position)
background_options = {
"motor-gta": ( # Motor-GTA Racing
"https://www.youtube.com/watch?v=vw5L4xCPy9Q",
"bike-parkour-gta.mp4",
"Achy Gaming",
lambda t: ('center', 480 + t)
),
"rocket-league": ( # Rocket League
"https://www.youtube.com/watch?v=2X9QGY__0II",
"rocket_league.mp4",
"Orbital Gameplay",
"top"
),
"minecraft": ( # Minecraft parkour
"https://www.youtube.com/watch?v=n_Dv4JMiwK8",
"parkour.mp4",
"bbswitzer",
"center"
),
"gta": ( # GTA Stunt Race
"https://www.youtube.com/watch?v=qGa9kWREOnE",
"gta-stunt-race.mp4",
"Achy Gaming",
lambda t: ('center', 480 + t)
)
}
def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int, int]: def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int, int]:
"""Generates a random interval of time to be used as the background of the video. """Generates a random interval of time to be used as the background of the video.
@ -25,49 +63,58 @@ def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int
return random_time, random_time + video_length return random_time, random_time + video_length
def download_background(): def get_background_config():
"""Downloads the backgrounds/s video from YouTube.""" """Fetch the background/s configuration"""
load_dotenv()
try:
choice = getenv("BackgroundChoice").casefold()
except AttributeError:
print_substep("No background selected. Picking random background'")
choice = None
# Handle default / not supported background using default option.
# Default : pick random from supported background.
if not choice or choice not in background_options:
choice = random.choice(list(background_options.keys()))
return background_options[choice]
def download_background(background_config: Tuple[str, str, str, Any]):
"""Downloads the background/s video from YouTube."""
Path("./assets/backgrounds/").mkdir(parents=True, exist_ok=True) Path("./assets/backgrounds/").mkdir(parents=True, exist_ok=True)
background_options = [ # uri , filename , credit
("https://www.youtube.com/watch?v=n_Dv4JMiwK8", "parkour.mp4", "bbswitzer"),
# (
# "https://www.youtube.com/watch?v=2X9QGY__0II",
# "rocket_league.mp4",
# "Orbital Gameplay",
# ),
]
# note: make sure the file name doesn't include an - in it # note: make sure the file name doesn't include an - in it
if not len(listdir("./assets/backgrounds")) >= len( uri, filename, credit, _ = background_config
background_options if Path(f"assets/backgrounds/{credit}-{filename}").is_file():
): # if there are any background videos not installed return
print_step( print_step(
"We need to download the backgrounds videos. they are fairly large but it's only done once. 😎" "We need to download the backgrounds videos. they are fairly large but it's only done once. 😎"
) )
print_substep("Downloading the backgrounds videos... please be patient 🙏 ") print_substep("Downloading the backgrounds videos... please be patient 🙏 ")
for uri, filename, credit in background_options:
if Path(f"assets/backgrounds/{credit}-{filename}").is_file():
continue # adds check to see if file exists before downloading
print_substep(f"Downloading {filename} from {uri}") print_substep(f"Downloading {filename} from {uri}")
YouTube(uri).streams.filter(res="1080p").first().download( YouTube(uri, on_progress_callback=on_progress).streams.filter(res="1080p").first().download(
"assets/backgrounds", filename=f"{credit}-{filename}" "assets/backgrounds", filename=f"{credit}-{filename}"
) )
print_substep("Background videos downloaded successfully! 🎉",
print_substep("Background videos downloaded successfully! 🎉", style="bold green") style="bold green")
def chop_background_video(video_length: int): def chop_background_video(background_config: Tuple[str, str, str, Any], video_length: int):
"""Generates the background footage to be used in the video and writes it to assets/temp/background.mp4 """Generates the background footage to be used in the video and writes it to assets/temp/background.mp4
Args: Args:
background_config (Tuple[str, str, str, Any]) : Current background configuration
video_length (int): Length of the clip where the background footage is to be taken out of video_length (int): Length of the clip where the background footage is to be taken out of
""" """
print_step("Finding a spot in the backgrounds video to chop...✂️") print_step("Finding a spot in the backgrounds video to chop...✂️")
choice = random.choice(listdir("assets/backgrounds")) choice = f"{background_config[2]}-{background_config[1]}"
environ["background_credit"] = choice.split("-")[0] environ["background_credit"] = choice.split("-")[0]
background = VideoFileClip(f"assets/backgrounds/{choice}") background = VideoFileClip(f"assets/backgrounds/{choice}")
start_time, end_time = get_start_and_end_times(video_length, background.duration) start_time, end_time = get_start_and_end_times(
video_length, background.duration)
try: try:
ffmpeg_extract_subclip( ffmpeg_extract_subclip(
f"assets/backgrounds/{choice}", f"assets/backgrounds/{choice}",

@ -4,6 +4,7 @@ import os
import re import re
from os.path import exists from os.path import exists
from typing import Dict from typing import Dict
from typing import Tuple, Any
from moviepy.editor import ( from moviepy.editor import (
VideoFileClip, VideoFileClip,
@ -21,12 +22,13 @@ from utils.cleanup import cleanup
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
from utils.videos import save_data from utils.videos import save_data
console = Console() console = Console()
W, H = 1080, 1920 W, H = 1080, 1920
def make_final_video(number_of_clips: int, length: int, reddit_obj: dict): def make_final_video(number_of_clips: int, length: int, reddit_obj: dict[str], background_config: Tuple[str, str, str, Any]):
"""Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp """Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp
Args: Args:
@ -55,24 +57,35 @@ def make_final_video(number_of_clips: int, length: int, reddit_obj: dict):
# add title to video # add title to video
image_clips = [] image_clips = []
# Gather all images # Gather all images
new_opacity = 1 if opacity is None or float(opacity) >= 1 else float(opacity) if opacity is None or float(opacity) >= 1: # opacity not set or is set to one OR MORE
image_clips.insert(
0,
ImageClip("assets/temp/png/title.png")
.set_duration(audio_clips[0].duration)
.resize(width=W - 100),
)
else:
image_clips.insert( image_clips.insert(
0, 0,
ImageClip("assets/temp/png/title.png") ImageClip("assets/temp/png/title.png")
.set_duration(audio_clips[0].duration) .set_duration(audio_clips[0].duration)
.set_position("center")
.resize(width=W - 100) .resize(width=W - 100)
.set_opacity(new_opacity) .set_opacity(new_opacity)
) )
for i in range(0, number_of_clips): for i in range(0, number_of_clips):
if opacity is None or float(opacity) >= 1: # opacity not set or is set to one OR MORE
image_clips.append(
ImageClip(f"assets/temp/png/comment_{i}.png")
.set_duration(audio_clips[i + 1].duration)
.resize(width=W - 100),
)
else:
image_clips.append( image_clips.append(
ImageClip(f"assets/temp/png/comment_{i}.png") ImageClip(f"assets/temp/png/comment_{i}.png")
.set_duration(audio_clips[i + 1].duration) .set_duration(audio_clips[i + 1].duration)
.set_position("center")
.resize(width=W - 100) .resize(width=W - 100)
.set_opacity(new_opacity) .set_opacity(float(opacity)),
) )
# if os.path.exists("assets/mp3/posttext.mp3"): # if os.path.exists("assets/mp3/posttext.mp3"):
@ -85,7 +98,9 @@ def make_final_video(number_of_clips: int, length: int, reddit_obj: dict):
# .set_opacity(float(opacity)), # .set_opacity(float(opacity)),
# ) # )
# else: # else:
image_concat = concatenate_videoclips(image_clips).set_position(("center", "center")) img_clip_pos = background_config[3]
image_concat = concatenate_videoclips(
image_clips).set_position(img_clip_pos)
image_concat.audio = audio_composite image_concat.audio = audio_composite
final = CompositeVideoClip([background_clip, image_concat]) final = CompositeVideoClip([background_clip, image_concat])
title = re.sub(r"[^\w\s-]", "", reddit_obj["thread_title"]) title = re.sub(r"[^\w\s-]", "", reddit_obj["thread_title"])

Loading…
Cancel
Save