From e613b47626786a859577fd3ed5f7a8b566539e04 Mon Sep 17 00:00:00 2001 From: Mihai Date: Wed, 10 May 2023 17:32:59 +0200 Subject: [PATCH] Fix multiple errors and improve code readability - Resolved 'StreamingData' error - Fixed ffmpeg compatibility issues, particularly with M1 Macs - Replaced pytube with yt-dl for better up-to-date functionality and M1 support - Enhanced code readability and provided clear comments for beginners to understand the code easily --- video_creation/background.py | 58 +++++++++++++++-------------------- video_creation/final_video.py | 1 - 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/video_creation/background.py b/video_creation/background.py index 0458ce6..1859801 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -5,45 +5,33 @@ from pathlib import Path from random import randrange from typing import Any, Tuple +import yt_dlp from moviepy.editor import VideoFileClip 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.console import print_step, print_substep -# Load background videos +# Load background video configurations from the JSON file with open("./utils/backgrounds.json") as json_file: background_options = json.load(json_file) -# Remove "__comment" from backgrounds +# Remove any comments from the JSON file background_options.pop("__comment", None) -# Add position lambda function -# (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position) +# Set the position of the background video in the final output for name in list(background_options.keys()): pos = background_options[name][3] if pos != "center": background_options[name][3] = lambda t: ("center", pos + t) - +# Function to generate a random start and end time for the background video 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. - - Args: - video_length (int): Length of the video - length_of_clip (int): Length of the video to be used as the background - - Returns: - tuple[int,int]: Start and end time of the randomized interval - """ random_time = randrange(180, int(length_of_clip) - int(video_length)) return random_time, random_time + video_length - +# Function to get the background configuration from the settings def get_background_config(): - """Fetch the background/s configuration""" try: choice = str( settings.config["settings"]["background"]["background_choice"] @@ -52,18 +40,14 @@ def get_background_config(): 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] - +# Function to download the background video from YouTube 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) - # note: make sure the file name doesn't include an - in it uri, filename, credit, _ = background_config if Path(f"assets/backgrounds/{credit}-{filename}").is_file(): return @@ -72,28 +56,34 @@ def download_background(background_config: Tuple[str, str, str, Any]): ) print_substep("Downloading the backgrounds videos... please be patient 🙏 ") print_substep(f"Downloading {filename} from {uri}") - YouTube(uri, on_progress_callback=on_progress).streams.filter( - res="1080p" - ).first().download("assets/backgrounds", filename=f"{credit}-{filename}") + + # Set the download option for yt-dlp + ydl_opts = { + 'outtmpl': f'assets/backgrounds/{credit}-{filename}', + 'format': 'bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[height<=1080][ext=mp4]' + } + + # Download the video with yt-dlp + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + ydl.download([uri]) + print_substep("Background video downloaded successfully! 🎉", style="bold green") def chop_background_video( background_config: Tuple[str, str, str, Any], video_length: int, reddit_object: dict ): - """Generates the background footage to be used in the video and writes it to assets/temp/background.mp4 - - 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 - """ - print_step("Finding a spot in the backgrounds video to chop...✂️") choice = f"{background_config[2]}-{background_config[1]}" id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"]) + + # Load the background video background = VideoFileClip(f"assets/backgrounds/{choice}") + # Get the start and end times for the portion to extract start_time, end_time = get_start_and_end_times(video_length, background.duration) + + # Extract the portion of the video try: ffmpeg_extract_subclip( f"assets/backgrounds/{choice}", @@ -106,5 +96,7 @@ def chop_background_video( with VideoFileClip(f"assets/backgrounds/{choice}") as video: new = video.subclip(start_time, end_time) new.write_videofile(f"assets/temp/{id}/background.mp4") + + # Output a success message print_substep("Background video chopped successfully!", style="bold green") return background_config[2] diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 4838574..6a1b425 100644 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -1,7 +1,6 @@ import multiprocessing import os import re -import shutil from os.path import exists # Needs to be imported specifically from typing import Final from typing import Tuple, Any