Path: blob/master/video_creation/background.py
327 views
import json1import random2import re3from pathlib import Path4from random import randrange5from typing import Any, Dict, Tuple67import yt_dlp8from moviepy.editor import AudioFileClip, VideoFileClip9from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip1011from utils import settings12from utils.console import print_step, print_substep131415def load_background_options():16background_options = {}17# Load background videos18with open("./utils/background_videos.json") as json_file:19background_options["video"] = json.load(json_file)2021# Load background audios22with open("./utils/background_audios.json") as json_file:23background_options["audio"] = json.load(json_file)2425# Remove "__comment" from backgrounds26del background_options["video"]["__comment"]27del background_options["audio"]["__comment"]2829for name in list(background_options["video"].keys()):30pos = background_options["video"][name][3]3132if pos != "center":33background_options["video"][name][3] = lambda t: ("center", pos + t)3435return background_options363738def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int, int]:39"""Generates a random interval of time to be used as the background of the video.4041Args:42video_length (int): Length of the video43length_of_clip (int): Length of the video to be used as the background4445Returns:46tuple[int,int]: Start and end time of the randomized interval47"""48initialValue = 18049# Issue #1649 - Ensures that will be a valid interval in the video50while int(length_of_clip) <= int(video_length + initialValue):51if initialValue == initialValue // 2:52raise Exception("Your background is too short for this video length")53else:54initialValue //= 2 # Divides the initial value by 2 until reach 055random_time = randrange(initialValue, int(length_of_clip) - int(video_length))56return random_time, random_time + video_length575859def get_background_config(mode: str):60"""Fetch the background/s configuration"""61try:62choice = str(settings.config["settings"]["background"][f"background_{mode}"]).casefold()63except AttributeError:64print_substep("No background selected. Picking random background'")65choice = None6667# Handle default / not supported background using default option.68# Default : pick random from supported background.69if not choice or choice not in background_options[mode]:70choice = random.choice(list(background_options[mode].keys()))7172return background_options[mode][choice]737475def download_background_video(background_config: Tuple[str, str, str, Any]):76"""Downloads the background/s video from YouTube."""77Path("./assets/backgrounds/video/").mkdir(parents=True, exist_ok=True)78# note: make sure the file name doesn't include an - in it79uri, filename, credit, _ = background_config80if Path(f"assets/backgrounds/video/{credit}-{filename}").is_file():81return82print_step(83"We need to download the backgrounds videos. they are fairly large but it's only done once. 😎"84)85print_substep("Downloading the backgrounds videos... please be patient 🙏 ")86print_substep(f"Downloading {filename} from {uri}")87ydl_opts = {88"format": "bestvideo[height<=1080][ext=mp4]",89"outtmpl": f"assets/backgrounds/video/{credit}-{filename}",90"retries": 10,91}9293with yt_dlp.YoutubeDL(ydl_opts) as ydl:94ydl.download(uri)95print_substep("Background video downloaded successfully! 🎉", style="bold green")969798def download_background_audio(background_config: Tuple[str, str, str]):99"""Downloads the background/s audio from YouTube."""100Path("./assets/backgrounds/audio/").mkdir(parents=True, exist_ok=True)101# note: make sure the file name doesn't include an - in it102uri, filename, credit = background_config103if Path(f"assets/backgrounds/audio/{credit}-{filename}").is_file():104return105print_step(106"We need to download the backgrounds audio. they are fairly large but it's only done once. 😎"107)108print_substep("Downloading the backgrounds audio... please be patient 🙏 ")109print_substep(f"Downloading {filename} from {uri}")110ydl_opts = {111"outtmpl": f"./assets/backgrounds/audio/{credit}-{filename}",112"format": "bestaudio/best",113"extract_audio": True,114}115116with yt_dlp.YoutubeDL(ydl_opts) as ydl:117ydl.download([uri])118119print_substep("Background audio downloaded successfully! 🎉", style="bold green")120121122def chop_background(background_config: Dict[str, Tuple], video_length: int, reddit_object: dict):123"""Generates the background audio and footage to be used in the video and writes it to assets/temp/background.mp3 and assets/temp/background.mp4124125Args:126background_config (Dict[str,Tuple]]) : Current background configuration127video_length (int): Length of the clip where the background footage is to be taken out of128"""129id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"])130131if settings.config["settings"]["background"][f"background_audio_volume"] == 0:132print_step("Volume was set to 0. Skipping background audio creation . . .")133else:134print_step("Finding a spot in the backgrounds audio to chop...✂️")135audio_choice = f"{background_config['audio'][2]}-{background_config['audio'][1]}"136background_audio = AudioFileClip(f"assets/backgrounds/audio/{audio_choice}")137start_time_audio, end_time_audio = get_start_and_end_times(138video_length, background_audio.duration139)140background_audio = background_audio.subclip(start_time_audio, end_time_audio)141background_audio.write_audiofile(f"assets/temp/{id}/background.mp3")142143print_step("Finding a spot in the backgrounds video to chop...✂️")144video_choice = f"{background_config['video'][2]}-{background_config['video'][1]}"145background_video = VideoFileClip(f"assets/backgrounds/video/{video_choice}")146start_time_video, end_time_video = get_start_and_end_times(147video_length, background_video.duration148)149# Extract video subclip150try:151ffmpeg_extract_subclip(152f"assets/backgrounds/video/{video_choice}",153start_time_video,154end_time_video,155targetname=f"assets/temp/{id}/background.mp4",156)157except (OSError, IOError): # ffmpeg issue see #348158print_substep("FFMPEG issue. Trying again...")159with VideoFileClip(f"assets/backgrounds/video/{video_choice}") as video:160new = video.subclip(start_time_video, end_time_video)161new.write_videofile(f"assets/temp/{id}/background.mp4")162print_substep("Background video chopped successfully!", style="bold green")163return background_config["video"][2]164165166# Create a tuple for downloads background (background_audio_options, background_video_options)167background_options = load_background_options()168169170