diff --git a/main.py b/main.py index adc478d..90f0e87 100755 --- a/main.py +++ b/main.py @@ -14,6 +14,9 @@ from video_creation.background import ( download_background, chop_background_video, get_background_config, + download_background_audio, + chop_background_audio, + get_background_audio_config ) from video_creation.final_video import make_final_video from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts @@ -48,6 +51,9 @@ def main(POST_ID=None): bg_config = get_background_config() download_background(bg_config) chop_background_video(bg_config, length) + bg_config_audio = get_background_audio_config() + download_background_audio(bg_config_audio) + chop_background_audio(bg_config_audio, length) make_final_video(number_of_comments, length, reddit_object, bg_config) diff --git a/utils/.config.template.toml b/utils/.config.template.toml index 9fd779e..c10c2f9 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -32,6 +32,8 @@ storymode = { optional = true, type = "bool", default = false, example = false, [settings.background] background_choice = { optional = true, default = "minecraft", example = "minecraft", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", ""], explanation = "Sets the background for the video" } +background_audio = {optional = true, default = "phonk", example = "phonk", options = ["phonk"], explanation = "Sets the background audio"} +background_volume = {optional = true, default = 0.07, example = 0.5, explanation = "Sets the background audio volume", type = "float", nmin = 0, nmax = 1, oob_error = "The volume HAS to be between 0 and 1", input_error = "The volume HAS to be a decimal number between 0 and 1"} #background_audio = { optional = true, type = "bool", default = false, example = false, options = [true, # false, #], explaination="Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } diff --git a/utils/CONSTANTS.py b/utils/CONSTANTS.py index e46ebbc..034dc85 100644 --- a/utils/CONSTANTS.py +++ b/utils/CONSTANTS.py @@ -43,3 +43,17 @@ background_options = { lambda t: ("center", 480 + t), ), } + +# Supported Audio Background. Can add/remove background audio here.... +# - : key -> used as keyword for TOML file. value -> background configuration +# Format (value): +# 1. Youtube URI +# 2. filename +# 3. Citation (owner of the video) +background_audio_options = { + "phonk": ( + "https://www.youtube.com/watch?v=URhQ9iJHIsU", + "phonk.mp3", + "dms mus." + ), +} diff --git a/video_creation/background.py b/video_creation/background.py index 6e656fa..6a079b3 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -4,13 +4,13 @@ from random import randrange from typing import Any, Tuple -from moviepy.editor import VideoFileClip +from moviepy.editor import VideoFileClip, AudioFileClip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from pytube import YouTube from pytube.cli import on_progress from utils import settings -from utils.CONSTANTS import background_options +from utils.CONSTANTS import background_options, background_audio_options from utils.console import print_step, print_substep @@ -44,6 +44,22 @@ def get_background_config(): return background_options[choice] +def get_background_audio_config(): + """Fetch the audio background/s configuration""" + try: + audio = str(settings.config["settings"]["background"]["background_audio"]).casefold() + except AttributeError: + print_substep("No background selected. Picking random background'") + audio = None + + # Handle default / not supported background using default option. + # Default : pick random from supported background. + if not audio or audio not in background_options: + audio = random.choice(list(background_audio_options.keys())) + + return background_audio_options[audio] + + 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) @@ -62,6 +78,19 @@ def download_background(background_config: Tuple[str, str, str, Any]): print_substep("Background video downloaded successfully! 🎉", style="bold green") +def download_background_audio(background_audio_config: Tuple[str, str, str]): + """Downloads the background/s audio from YouTube.""" + Path("./assets/backgrounds/").mkdir(parents=True, exist_ok=True) + uri, filename, credit = background_audio_config + if Path(f"assets/backgrounds/{credit}-{filename}").is_file(): + return + + print_substep("Downloading the backgrounds audios... please be patient 🙏 ") + print_substep(f"Downloading {filename} from {uri}") + YouTube(uri, on_progress_callback=on_progress).streams.filter(type="audio").first().download("assets/backgrounds", filename=f"{credit}-{filename}") + print_substep("Background audios downloaded successfully! 🎉", style="bold green") + + 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 @@ -90,3 +119,26 @@ def chop_background_video(background_config: Tuple[str, str, str, Any], video_le new.write_videofile("assets/temp/background.mp4") print_substep("Background video chopped successfully!", style="bold green") return background_config[2] + + +def chop_background_audio(background_audio_config: Tuple[str, str, str], video_length: int): + """Generates the audio background footage to be used in the video and writes it to assets/temp/background.mp3 + + Args: + background_config (Tuple[str, str, str]) : Current audio background configuration + 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 audio to chop...✂️") + _, filename, credit = background_audio_config + choice = f"{credit}-{filename}" + + background = AudioFileClip(f"assets/backgrounds/{choice}") + + start_time, end_time = get_start_and_end_times(video_length, background.duration) + + # use ffmpeg instead ? + with AudioFileClip(f"assets/backgrounds/{choice}") as audio: + new = audio.subclip(start_time, end_time) + new.write_audiofile("assets/temp/background.mp3") + + print_substep("Background audio chopped successfully!", style="bold green") diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 8d12afe..d3afeae 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -11,6 +11,7 @@ from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip from moviepy.video.compositing.concatenate import concatenate_videoclips from moviepy.video.io.VideoFileClip import VideoFileClip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip +from moviepy.audio.fx.all import volumex from rich.console import Console from utils.cleanup import cleanup @@ -73,11 +74,16 @@ def make_final_video( .crop(x1=1166.6, y1=0, x2=2246.6, y2=1920) ) + # Gather audio background + volume = settings.config["settings"]["background"]["background_volume"] + audio_bg = AudioFileClip("assets/temp/background.mp3") + audio_bg = audio_bg.fx(volumex, volume) + # Gather all audio clips audio_clips = [AudioFileClip(f"assets/temp/mp3/{i}.mp3") for i in range(number_of_clips)] audio_clips.insert(0, AudioFileClip("assets/temp/mp3/title.mp3")) audio_concat = concatenate_audioclips(audio_clips) - audio_composite = CompositeAudioClip([audio_concat]) + audio_composite = CompositeAudioClip([audio_concat, audio_bg]) console.log(f"[bold green] Video Will Be: {length} Seconds Long") # add title to video