From ba5e8b89877f93df22029cb5d0523a7025cb8d1a Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 21 Apr 2023 14:31:13 -0300 Subject: [PATCH 01/13] adaptations in filePath and toml for audio option --- main.py | 4 +- utils/background_audios.json | 8 +++ ...ackgrounds.json => background_videos.json} | 0 video_creation/background.py | 49 ++++++++++++------- 4 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 utils/background_audios.json rename utils/{backgrounds.json => background_videos.json} (100%) diff --git a/main.py b/main.py index b7a1b7f..9ccd1ed 100755 --- a/main.py +++ b/main.py @@ -49,8 +49,10 @@ def main(POST_ID=None) -> None: redditid = id(reddit_object) length, number_of_comments = save_text_to_mp3(reddit_object) length = math.ceil(length) + bg_config = {} get_screenshots_of_reddit_posts(reddit_object, number_of_comments) - bg_config = get_background_config() + bg_config["video"] = get_background_config("video") + bg_config["audio"] = get_background_config("audio") download_background(bg_config) chop_background_video(bg_config, length, reddit_object) make_final_video(number_of_comments, length, reddit_object, bg_config) diff --git a/utils/background_audios.json b/utils/background_audios.json new file mode 100644 index 0000000..5e37445 --- /dev/null +++ b/utils/background_audios.json @@ -0,0 +1,8 @@ +{ + "__comment": "Supported Backgrounds Audio. Can add/remove background audio here...", + "minecraft": [ + "https://www.youtube.com/watch?v=2p3nBYUaJz8", + "minecraft.mp4", + "adriPixs" + ] +} diff --git a/utils/backgrounds.json b/utils/background_videos.json similarity index 100% rename from utils/backgrounds.json rename to utils/background_videos.json diff --git a/video_creation/background.py b/video_creation/background.py index 0458ce6..f6db6fc 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -5,27 +5,37 @@ from pathlib import Path 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.console import print_step, print_substep -# Load background videos -with open("./utils/backgrounds.json") as json_file: - background_options = json.load(json_file) +def load_background_options(): + background_options = {} + # Load background videos + with open("./utils/background_videos.json") as json_file: + background_options["video"] = json.load(json_file) -# Remove "__comment" from backgrounds -background_options.pop("__comment", None) + # Load background audios + with open("./utils/background_audios.json") as json_file: + background_options["audio"] = json.load(json_file) + + # Remove "__comment" from backgrounds + background_options["video"].pop("__comment", None) + background_options["audio"].pop("__comment", None) + + # Add position lambda function + # (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position) + for name in list(background_options["video"].keys()): + pos = background_options["video"][name][3] -# Add position lambda function -# (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position) -for name in list(background_options.keys()): - pos = background_options[name][3] + if pos != "center": + background_options["video"][name][3] = lambda t: ("center", pos + t) + + return background_options - if pos != "center": - background_options[name][3] = lambda t: ("center", pos + t) def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int, int]: @@ -42,11 +52,11 @@ def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int return random_time, random_time + video_length -def get_background_config(): +def get_background_config(mode: str): """Fetch the background/s configuration""" try: choice = str( - settings.config["settings"]["background"]["background_choice"] + settings.config["settings"]["background"][f"background_{mode}_choice"] ).casefold() except AttributeError: print_substep("No background selected. Picking random background'") @@ -54,10 +64,10 @@ def get_background_config(): # 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())) + if not choice or choice not in background_options[mode]: + choice = random.choice(list(background_options[mode].keys())) - return background_options[choice] + return background_options[mode][choice] def download_background(background_config: Tuple[str, str, str, Any]): @@ -78,6 +88,8 @@ def download_background(background_config: Tuple[str, str, str, Any]): 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 ): @@ -108,3 +120,6 @@ def chop_background_video( new.write_videofile(f"assets/temp/{id}/background.mp4") print_substep("Background video chopped successfully!", style="bold green") return background_config[2] + +# Create a tuple for downloads background (background_audio_options, background_video_options) +background_options = load_background_options() \ No newline at end of file From a21c17ef557f43cd6bc7b37a629fabb81a05f1cc Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 21 Apr 2023 19:17:05 -0300 Subject: [PATCH 02/13] composing the video but with no audio --- main.py | 10 +++--- utils/.config.template.toml | 6 ++-- utils/background_audios.json | 2 +- video_creation/background.py | 54 +++++++++++++++++++++------------ video_creation/data/videos.json | 19 +++++++++++- 5 files changed, 63 insertions(+), 28 deletions(-) diff --git a/main.py b/main.py index 9ccd1ed..81fb503 100755 --- a/main.py +++ b/main.py @@ -15,8 +15,9 @@ from utils.console import print_markdown, print_step from utils.id import id from utils.version import checkversion from video_creation.background import ( - download_background, - chop_background_video, + download_background_video, + download_background_audio, + chop_background, get_background_config, ) from video_creation.final_video import make_final_video @@ -53,8 +54,9 @@ def main(POST_ID=None) -> None: get_screenshots_of_reddit_posts(reddit_object, number_of_comments) bg_config["video"] = get_background_config("video") bg_config["audio"] = get_background_config("audio") - download_background(bg_config) - chop_background_video(bg_config, length, reddit_object) + download_background_video(bg_config["video"]) + download_background_audio(bg_config["audio"]) + chop_background(bg_config, length, reddit_object) make_final_video(number_of_comments, length, reddit_object, bg_config) diff --git a/utils/.config.template.toml b/utils/.config.template.toml index b2fa1d4..b146922 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -33,9 +33,9 @@ resolution_w = { optional = false, default = 1080, example = 1440, explantation resolution_h = { optional = false, default = 1920, example = 2560, explantation = "Sets the height in pixels of the final video" } [settings.background] -background_choice = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } -#background_audio = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } -#background_audio_volume = { optional = true, type = "float", default = 0.3, example = 0.1, explanation="Sets the volume of the background audio. only used if the background_audio is also set to true" } +background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } +background_audio = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } +background_audio_volume = { optional = true, type = "float", default = 0.3, example = 0.1, explanation="Sets the volume of the background audio. only used if the background_audio is also set to true" } background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" } background_thumbnail_font_family = { optional = true, default = "arial", example = "arial", explanation = "Font family for the thumbnail text" } background_thumbnail_font_size = { optional = true, type = "int", default = 96, example = 96, explanation = "Font size in pixels for the thumbnail text" } diff --git a/utils/background_audios.json b/utils/background_audios.json index 5e37445..bd34cef 100644 --- a/utils/background_audios.json +++ b/utils/background_audios.json @@ -2,7 +2,7 @@ "__comment": "Supported Backgrounds Audio. Can add/remove background audio here...", "minecraft": [ "https://www.youtube.com/watch?v=2p3nBYUaJz8", - "minecraft.mp4", + "minecraft.mp3", "adriPixs" ] } diff --git a/video_creation/background.py b/video_creation/background.py index f6db6fc..75a88d2 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -3,7 +3,7 @@ import random import re from pathlib import Path from random import randrange -from typing import Any, Tuple +from typing import Any, Tuple,Dict from moviepy.editor import VideoFileClip,AudioFileClip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip @@ -56,7 +56,7 @@ def get_background_config(mode: str): """Fetch the background/s configuration""" try: choice = str( - settings.config["settings"]["background"][f"background_{mode}_choice"] + settings.config["settings"]["background"][f"background_{mode}"] ).casefold() except AttributeError: print_substep("No background selected. Picking random background'") @@ -69,13 +69,12 @@ def get_background_config(mode: str): return background_options[mode][choice] - -def download_background(background_config: Tuple[str, str, str, Any]): +def download_background_video(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/video/").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(): + if Path(f"assets/backgrounds/video/{credit}-{filename}").is_file(): return print_step( "We need to download the backgrounds videos. they are fairly large but it's only done once. 😎" @@ -84,14 +83,26 @@ def download_background(background_config: Tuple[str, str, str, Any]): 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}") + ).first().download("assets/backgrounds/video", filename=f"{credit}-{filename}") print_substep("Background video downloaded successfully! 🎉", style="bold green") +def download_background_audio(background_config: Tuple[str, str, str]): + """Downloads the background/s audio from YouTube.""" + Path("./assets/backgrounds/audio/").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/audio/{credit}-{filename}").is_file(): + return + print_step( + "We need to download the backgrounds audio. they are fairly large but it's only done once. 😎" + ) + print_substep("Downloading the backgrounds audio... please be patient 🙏 ") + print_substep(f"Downloading {filename} from {uri}") + YouTube(uri, on_progress_callback=on_progress).streams.filter(only_audio=True).first().download("assets/backgrounds/audio", filename=f"{credit}-{filename}") + print_substep("Background audio downloaded successfully! 🎉", style="bold green") - - -def chop_background_video( - background_config: Tuple[str, str, str, Any], video_length: int, reddit_object: dict +def chop_background( + background_config: Dict[str,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 @@ -101,22 +112,27 @@ def chop_background_video( """ print_step("Finding a spot in the backgrounds video to chop...✂️") - choice = f"{background_config[2]}-{background_config[1]}" + video_choice = f"{background_config['video'][2]}-{background_config['video'][1]}" + audio_choice = f"{background_config['audio'][2]}-{background_config['audio'][1]}" id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"]) - background = VideoFileClip(f"assets/backgrounds/{choice}") + background_video = VideoFileClip(f"assets/backgrounds/video/{video_choice}") + background_audio = AudioFileClip(f"assets/backgrounds/audio/{audio_choice}") + start_time_video, end_time_video = get_start_and_end_times(video_length, background_video.duration) + start_time_audio, end_time_audio = get_start_and_end_times(video_length, background_audio.duration) + background_audio.subclip(start_time_audio,end_time_audio) + background_video.set_audio(background_audio) - start_time, end_time = get_start_and_end_times(video_length, background.duration) try: ffmpeg_extract_subclip( - f"assets/backgrounds/{choice}", - start_time, - end_time, + f"assets/backgrounds/video/{video_choice}", + start_time_video, + end_time_video, targetname=f"assets/temp/{id}/background.mp4", ) except (OSError, IOError): # ffmpeg issue see #348 print_substep("FFMPEG issue. Trying again...") - with VideoFileClip(f"assets/backgrounds/{choice}") as video: - new = video.subclip(start_time, end_time) + with VideoFileClip(f"assets/backgrounds/video/{video_choice}") as video: + new = video.subclip(start_time_video, end_time_video) new.write_videofile(f"assets/temp/{id}/background.mp4") print_substep("Background video chopped successfully!", style="bold green") return background_config[2] diff --git a/video_creation/data/videos.json b/video_creation/data/videos.json index fe51488..4e0cb8c 100644 --- a/video_creation/data/videos.json +++ b/video_creation/data/videos.json @@ -1 +1,18 @@ -[] +[ + { + "subreddit": "", + "id": "12tt2xe", + "time": "1682111299", + "background_credit": "", + "reddit_title": "skipped", + "filename": "" + }, + { + "subreddit": "", + "id": "12u9m3f", + "time": "1682114905", + "background_credit": "", + "reddit_title": "skipped", + "filename": "" + } +] \ No newline at end of file From 405b1f89eb1ad31a14459aae83c5172d5cacd1b6 Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 21 Apr 2023 21:28:56 -0300 Subject: [PATCH 03/13] Volume down done --- video_creation/background.py | 17 +++++++++--- video_creation/data/videos.json | 48 +++++++++++++++++++++++++++++++++ video_creation/final_video.py | 8 +++--- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/video_creation/background.py b/video_creation/background.py index 75a88d2..55b5399 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -5,7 +5,7 @@ from pathlib import Path from random import randrange from typing import Any, Tuple,Dict -from moviepy.editor import VideoFileClip,AudioFileClip +from moviepy.editor import VideoFileClip,AudioFileClip,afx from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from pytube import YouTube from pytube.cli import on_progress @@ -115,13 +115,24 @@ def chop_background( video_choice = f"{background_config['video'][2]}-{background_config['video'][1]}" audio_choice = f"{background_config['audio'][2]}-{background_config['audio'][1]}" id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"]) + + # audioclip = audioclip.fx( volumex, 0.2) + # final_audio = mpe.CompositeAudioClip([final.audio, audioclip]) + # # lowered_audio = audio_background.multiply_volume( # todo get this to work + # # VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx + # final.set_audio(final_audio) background_video = VideoFileClip(f"assets/backgrounds/video/{video_choice}") background_audio = AudioFileClip(f"assets/backgrounds/audio/{audio_choice}") start_time_video, end_time_video = get_start_and_end_times(video_length, background_video.duration) start_time_audio, end_time_audio = get_start_and_end_times(video_length, background_audio.duration) - background_audio.subclip(start_time_audio,end_time_audio) + #background_audio.set_start(start_time_audio) + #background_audio.set_end(end_time_audio) + background_audio = background_audio.fx(afx.volumex,0.1) + #background_audio = background_audio.subclip(start_time_audio,end_time_audio) + background_audio.write_audiofile(f"assets/temp/{id}/background.mp3") background_video.set_audio(background_audio) + try: ffmpeg_extract_subclip( f"assets/backgrounds/video/{video_choice}", @@ -135,7 +146,7 @@ def chop_background( new = video.subclip(start_time_video, end_time_video) new.write_videofile(f"assets/temp/{id}/background.mp4") print_substep("Background video chopped successfully!", style="bold green") - return background_config[2] + return background_config["video"][2] # Create a tuple for downloads background (background_audio_options, background_video_options) background_options = load_background_options() \ No newline at end of file diff --git a/video_creation/data/videos.json b/video_creation/data/videos.json index 4e0cb8c..a7eb3b8 100644 --- a/video_creation/data/videos.json +++ b/video_creation/data/videos.json @@ -14,5 +14,53 @@ "background_credit": "", "reddit_title": "skipped", "filename": "" + }, + { + "subreddit": "", + "id": "12u5j7a", + "time": "1682116292", + "background_credit": "", + "reddit_title": "skipped", + "filename": "" + }, + { + "subreddit": "", + "id": "12twuvx", + "time": "1682118162", + "background_credit": "", + "reddit_title": "skipped", + "filename": "" + }, + { + "subreddit": "", + "id": "12tir3d", + "time": "1682121760", + "background_credit": "", + "reddit_title": "skipped", + "filename": "" + }, + { + "subreddit": "", + "id": "12u60fn", + "time": "1682122061", + "background_credit": "", + "reddit_title": "skipped", + "filename": "" + }, + { + "subreddit": "", + "id": "12txuo4", + "time": "1682123020", + "background_credit": "", + "reddit_title": "skipped", + "filename": "" + }, + { + "subreddit": "AskReddit", + "id": "12uei9x", + "time": "1682123178", + "background_credit": "bbswitzer", + "reddit_title": "People who pick up trash on the sides of roads what is the coolest grossestmost interesting thing youve found", + "filename": "People who pick up trash on the sides of roads what is the coolest grossestmost interesting thing youve found.mp4" } ] \ No newline at end of file diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 4838574..5e42e12 100644 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -4,7 +4,7 @@ import re import shutil from os.path import exists # Needs to be imported specifically from typing import Final -from typing import Tuple, Any +from typing import Tuple, Any, Dict import ffmpeg import translators as ts @@ -108,7 +108,7 @@ def make_final_video( number_of_clips: int, length: int, reddit_obj: dict, - background_config: Tuple[str, str, str, Any], + background_config: Dict[str,Tuple[str, str, str, Any]], ): """Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp Args: @@ -300,7 +300,7 @@ def make_final_video( f"Thumbnail - Building Thumbnail in assets/temp/{reddit_id}/thumbnail.png" ) - text = f"Background by {background_config[2]}" + text = f"Background by {background_config['video'][2]}" background_clip = ffmpeg.drawtext( background_clip, text=text, @@ -347,7 +347,7 @@ def make_final_video( pbar.update(100 - old_percentage) pbar.close() - save_data(subreddit, filename + ".mp4", title, idx, background_config[2]) + save_data(subreddit, filename + ".mp4", title, idx, background_config['video'][2]) print_step("Removing temporary files 🗑") cleanups = cleanup(reddit_id) print_substep(f"Removed {cleanups} temporary files 🗑") From 5a103e76cddf006ff816af9d448a83173bfdf070 Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 21 Apr 2023 22:09:53 -0300 Subject: [PATCH 04/13] rendering video and audio --- utils/.config.template.toml | 4 ++-- utils/background_audios.json | 10 ++++++++++ video_creation/background.py | 12 ++---------- video_creation/final_video.py | 4 +++- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/utils/.config.template.toml b/utils/.config.template.toml index b146922..75c5e4e 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -34,8 +34,8 @@ resolution_h = { optional = false, default = 1920, example = 2560, explantation [settings.background] background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } -background_audio = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } -background_audio_volume = { optional = true, type = "float", default = 0.3, example = 0.1, explanation="Sets the volume of the background audio. only used if the background_audio is also set to true" } +background_audio = { optional = true, type = "bool", default = false, example = false, options = ["minecraft","lofi"], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } +background_audio_volume = { optional = true, type = "float", default = 0.1, example = 0.05, explanation="Sets the volume of the background audio. Warning: if you set more than 1.0, the volume will be increased" } background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" } background_thumbnail_font_family = { optional = true, default = "arial", example = "arial", explanation = "Font family for the thumbnail text" } background_thumbnail_font_size = { optional = true, type = "int", default = 96, example = 96, explanation = "Font size in pixels for the thumbnail text" } diff --git a/utils/background_audios.json b/utils/background_audios.json index bd34cef..2dcd35c 100644 --- a/utils/background_audios.json +++ b/utils/background_audios.json @@ -4,5 +4,15 @@ "https://www.youtube.com/watch?v=2p3nBYUaJz8", "minecraft.mp3", "adriPixs" + ], + "lofi":[ + "https://www.youtube.com/watch?v=BEXL80LS0-I", + "lofi.mp3", + "stompsPlaylist" + ], + "undertale":[ + "https://www.youtube.com/watch?v=TIokr8jJPkM", + "undertale.mp3", + "abby" ] } diff --git a/video_creation/background.py b/video_creation/background.py index 55b5399..4919519 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -115,20 +115,12 @@ def chop_background( video_choice = f"{background_config['video'][2]}-{background_config['video'][1]}" audio_choice = f"{background_config['audio'][2]}-{background_config['audio'][1]}" id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"]) - - # audioclip = audioclip.fx( volumex, 0.2) - # final_audio = mpe.CompositeAudioClip([final.audio, audioclip]) - # # lowered_audio = audio_background.multiply_volume( # todo get this to work - # # VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx - # final.set_audio(final_audio) background_video = VideoFileClip(f"assets/backgrounds/video/{video_choice}") background_audio = AudioFileClip(f"assets/backgrounds/audio/{audio_choice}") start_time_video, end_time_video = get_start_and_end_times(video_length, background_video.duration) start_time_audio, end_time_audio = get_start_and_end_times(video_length, background_audio.duration) - #background_audio.set_start(start_time_audio) - #background_audio.set_end(end_time_audio) - background_audio = background_audio.fx(afx.volumex,0.1) - #background_audio = background_audio.subclip(start_time_audio,end_time_audio) + background_audio = background_audio.fx(afx.volumex,0.07) + background_audio = background_audio.subclip(start_time_audio,end_time_audio) background_audio.write_audiofile(f"assets/temp/{id}/background.mp3") background_video.set_audio(background_audio) diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 5e42e12..c0e7ad7 100644 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -177,6 +177,8 @@ def make_final_video( screenshot_width = int((W * 45) // 100) audio = ffmpeg.input(f"assets/temp/{reddit_id}/audio.mp3") + background_audio = ffmpeg.input(f"assets/temp/{reddit_id}/background.mp3") + final_audio = ffmpeg.filter([audio, background_audio], "amix") image_clips = list() @@ -327,7 +329,7 @@ def make_final_video( with ProgressFfmpeg(length, on_update_example) as progress: ffmpeg.output( background_clip, - audio, + final_audio, path, f="mp4", **{ From 1abfc4b3218f51a227c581a71a2c9d293ae088ff Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 21 Apr 2023 23:01:26 -0300 Subject: [PATCH 05/13] 2 samples with backgroundMusic and without it --- utils/.config.template.toml | 2 +- video_creation/background.py | 16 ++++++++++------ video_creation/final_video.py | 29 ++++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/utils/.config.template.toml b/utils/.config.template.toml index 75c5e4e..b4074d7 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -34,7 +34,7 @@ resolution_h = { optional = false, default = 1920, example = 2560, explantation [settings.background] background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } -background_audio = { optional = true, type = "bool", default = false, example = false, options = ["minecraft","lofi"], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } +background_audio = { optional = true, default = "lofi", example = "minecraft", options = ["minecraft","lofi","undertale"], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } background_audio_volume = { optional = true, type = "float", default = 0.1, example = 0.05, explanation="Sets the volume of the background audio. Warning: if you set more than 1.0, the volume will be increased" } background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" } background_thumbnail_font_family = { optional = true, default = "arial", example = "arial", explanation = "Font family for the thumbnail text" } diff --git a/video_creation/background.py b/video_creation/background.py index 4919519..36400b2 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -98,16 +98,18 @@ def download_background_audio(background_config: Tuple[str, str, str]): ) print_substep("Downloading the backgrounds audio... please be patient 🙏 ") print_substep(f"Downloading {filename} from {uri}") - YouTube(uri, on_progress_callback=on_progress).streams.filter(only_audio=True).first().download("assets/backgrounds/audio", filename=f"{credit}-{filename}") + YouTube(uri, on_progress_callback=on_progress).streams.filter( + only_audio=True + ).first().download("assets/backgrounds/audio", filename=f"{credit}-{filename}") print_substep("Background audio downloaded successfully! 🎉", style="bold green") def chop_background( - background_config: Dict[str,Tuple[str, str, str, Any]], video_length: int, reddit_object: dict + background_config: Dict[str,Tuple], video_length: int, reddit_object: dict ): - """Generates the background footage to be used in the video and writes it to assets/temp/background.mp4 + """Generates the background audio and footage to be used in the video and writes it to assets/temp/background.mp3 and assets/temp/background.mp4 Args: - background_config (Tuple[str, str, str, Any]) : Current background configuration + background_config (Dict[str,Tuple]]) : Current background configuration video_length (int): Length of the clip where the background footage is to be taken out of """ @@ -119,10 +121,12 @@ def chop_background( background_audio = AudioFileClip(f"assets/backgrounds/audio/{audio_choice}") start_time_video, end_time_video = get_start_and_end_times(video_length, background_video.duration) start_time_audio, end_time_audio = get_start_and_end_times(video_length, background_audio.duration) - background_audio = background_audio.fx(afx.volumex,0.07) + # Create a audio clip + background_audio_volume = settings.config["settings"]["background"][f"background_audio_volume"] + background_audio = background_audio.fx(afx.volumex,background_audio_volume) background_audio = background_audio.subclip(start_time_audio,end_time_audio) background_audio.write_audiofile(f"assets/temp/{id}/background.mp3") - background_video.set_audio(background_audio) + #background_video.set_audio(background_audio) try: diff --git a/video_creation/final_video.py b/video_creation/final_video.py index c0e7ad7..89187ca 100644 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -108,7 +108,7 @@ def make_final_video( number_of_clips: int, length: int, reddit_obj: dict, - background_config: Dict[str,Tuple[str, str, str, Any]], + background_config: Dict[str,Tuple], ): """Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp Args: @@ -262,6 +262,10 @@ def make_final_video( if not exists(f"./results/{subreddit}"): print_substep("The results folder didn't exist so I made it") os.makedirs(f"./results/{subreddit}") + + if not exists(f"./results/{subreddit}/{filename}"): + print_substep("The results folder didn't exist so I made it") + os.makedirs(f"./results/{subreddit}/{filename}") # create a thumbnail for the video settingsbackground = settings.config["settings"]["background"] @@ -324,13 +328,32 @@ def make_final_video( path = f"results/{subreddit}/{filename}" path = path[:251] - path = path + ".mp4" + #path = path + ".mp4" with ProgressFfmpeg(length, on_update_example) as progress: ffmpeg.output( background_clip, final_audio, - path, + path+f"/{filename}.mp4", + f="mp4", + **{ + "c:v": "h264", + "b:v": "20M", + "b:a": "192k", + "threads": multiprocessing.cpu_count(), + }, + ).overwrite_output().global_args("-progress", progress.output_file.name).run( + quiet=True, + overwrite_output=True, + capture_stdout=False, + capture_stderr=False, + ) + + with ProgressFfmpeg(length, on_update_example) as progress: + ffmpeg.output( + background_clip, + audio, + path+"/NoBackgroundAudio.mp4", f="mp4", **{ "c:v": "h264", From 15a4f80f994f231b47e83fbbfa9aeba201b10cbf Mon Sep 17 00:00:00 2001 From: Lucas de Almeida <105776775+propilideno@users.noreply.github.com> Date: Fri, 21 Apr 2023 23:05:48 -0300 Subject: [PATCH 06/13] 2 samples with backgroundMusic and without it --- video_creation/data/videos.json | 67 +-------------------------------- 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/video_creation/data/videos.json b/video_creation/data/videos.json index a7eb3b8..fe51488 100644 --- a/video_creation/data/videos.json +++ b/video_creation/data/videos.json @@ -1,66 +1 @@ -[ - { - "subreddit": "", - "id": "12tt2xe", - "time": "1682111299", - "background_credit": "", - "reddit_title": "skipped", - "filename": "" - }, - { - "subreddit": "", - "id": "12u9m3f", - "time": "1682114905", - "background_credit": "", - "reddit_title": "skipped", - "filename": "" - }, - { - "subreddit": "", - "id": "12u5j7a", - "time": "1682116292", - "background_credit": "", - "reddit_title": "skipped", - "filename": "" - }, - { - "subreddit": "", - "id": "12twuvx", - "time": "1682118162", - "background_credit": "", - "reddit_title": "skipped", - "filename": "" - }, - { - "subreddit": "", - "id": "12tir3d", - "time": "1682121760", - "background_credit": "", - "reddit_title": "skipped", - "filename": "" - }, - { - "subreddit": "", - "id": "12u60fn", - "time": "1682122061", - "background_credit": "", - "reddit_title": "skipped", - "filename": "" - }, - { - "subreddit": "", - "id": "12txuo4", - "time": "1682123020", - "background_credit": "", - "reddit_title": "skipped", - "filename": "" - }, - { - "subreddit": "AskReddit", - "id": "12uei9x", - "time": "1682123178", - "background_credit": "bbswitzer", - "reddit_title": "People who pick up trash on the sides of roads what is the coolest grossestmost interesting thing youve found", - "filename": "People who pick up trash on the sides of roads what is the coolest grossestmost interesting thing youve found.mp4" - } -] \ No newline at end of file +[] From 1f48c53a7451fdd17d2b8f9d6e7eca26b2489d7b Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 23 Apr 2023 11:07:17 -0300 Subject: [PATCH 07/13] new toml config and added background audio feature --- README.md | 2 +- requirements.txt | 3 +- utils/.config.template.toml | 3 +- video_creation/background.py | 40 +++++++++------- video_creation/final_video.py | 88 ++++++++++++++++++++++++----------- 5 files changed, 89 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index e6f61a6..81e37be 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ In its current state, this bot does exactly what it needs to do. However, improv I have tried to simplify the code so anyone can read it and start contributing at any skill level. Don't be shy :) contribute! - [ ] Creating better documentation and adding a command line interface. -- [ ] Allowing the user to choose background music for their videos. +- [x] Allowing the user to choose background music for their videos. - [x] Allowing users to choose a reddit thread instead of being randomized. - [x] Allowing users to choose a background that is picked instead of the Minecraft one. - [x] Allowing users to choose between any subreddit. diff --git a/requirements.txt b/requirements.txt index 22d3d7f..634a24b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,4 +19,5 @@ unidecode==1.3.2 spacy==3.4.1 torch==1.12.1 transformers==4.25.1 -ffmpeg-python==0.2.0 \ No newline at end of file +ffmpeg-python==0.2.0 +yt-dlp==2023.3.4 \ No newline at end of file diff --git a/utils/.config.template.toml b/utils/.config.template.toml index b4074d7..a9d6d27 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -35,7 +35,8 @@ resolution_h = { optional = false, default = 1920, example = 2560, explantation [settings.background] background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } background_audio = { optional = true, default = "lofi", example = "minecraft", options = ["minecraft","lofi","undertale"], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } -background_audio_volume = { optional = true, type = "float", default = 0.1, example = 0.05, explanation="Sets the volume of the background audio. Warning: if you set more than 1.0, the volume will be increased" } +background_audio_volume = { optional = true, type = "float", nmin = 0, nmax = 1, default = 0.1, example = 0.05, explanation="Sets the volume of the background audio. Type a value between 0 and 1.", oob_error = "The volume HAS to be between 0 and 1", input_error = "The volume HAS to be a float number between 0 and 1"} +allow_only_tts = { optional = true, type = "bool", default = false, example = false, explanation="Used if you want to render another video with only TTS audio in a separate folder", input_error = "The value HAS to be true or false"} background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" } background_thumbnail_font_family = { optional = true, default = "arial", example = "arial", explanation = "Font family for the thumbnail text" } background_thumbnail_font_size = { optional = true, type = "int", default = 96, example = 96, explanation = "Font size in pixels for the thumbnail text" } diff --git a/video_creation/background.py b/video_creation/background.py index 36400b2..3b896d9 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -5,12 +5,13 @@ from pathlib import Path from random import randrange from typing import Any, Tuple,Dict -from moviepy.editor import VideoFileClip,AudioFileClip,afx +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.console import print_step, print_substep +import yt_dlp def load_background_options(): background_options = {} @@ -81,9 +82,14 @@ def download_background_video(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/video", filename=f"{credit}-{filename}") + ydl_opts = { + 'format': "bestvideo[height<=1080][ext=mp4]", + "outtmpl": f"assets/backgrounds/video/{credit}-{filename}", + "retries": 10, + } + + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + ydl.download(uri) print_substep("Background video downloaded successfully! 🎉", style="bold green") def download_background_audio(background_config: Tuple[str, str, str]): @@ -103,6 +109,8 @@ def download_background_audio(background_config: Tuple[str, str, str]): ).first().download("assets/backgrounds/audio", filename=f"{credit}-{filename}") print_substep("Background audio downloaded successfully! 🎉", style="bold green") + + def chop_background( background_config: Dict[str,Tuple], video_length: int, reddit_object: dict ): @@ -112,23 +120,23 @@ def chop_background( background_config (Dict[str,Tuple]]) : Current background configuration video_length (int): Length of the clip where the background footage is to be taken out of """ + id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"]) + + if(settings.config["settings"]["background"][f"background_audio_volume"] == 0): + print_step("Volume was set to 0. Skipping background audio creation . . .") + else: + print_step("Finding a spot in the backgrounds audio to chop...✂️") + audio_choice = f"{background_config['audio'][2]}-{background_config['audio'][1]}" + background_audio = AudioFileClip(f"assets/backgrounds/audio/{audio_choice}") + start_time_audio, end_time_audio = get_start_and_end_times(video_length, background_audio.duration) + background_audio = background_audio.subclip(start_time_audio,end_time_audio) + background_audio.write_audiofile(f"assets/temp/{id}/background.mp3") print_step("Finding a spot in the backgrounds video to chop...✂️") video_choice = f"{background_config['video'][2]}-{background_config['video'][1]}" - audio_choice = f"{background_config['audio'][2]}-{background_config['audio'][1]}" - id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"]) background_video = VideoFileClip(f"assets/backgrounds/video/{video_choice}") - background_audio = AudioFileClip(f"assets/backgrounds/audio/{audio_choice}") start_time_video, end_time_video = get_start_and_end_times(video_length, background_video.duration) - start_time_audio, end_time_audio = get_start_and_end_times(video_length, background_audio.duration) - # Create a audio clip - background_audio_volume = settings.config["settings"]["background"][f"background_audio_volume"] - background_audio = background_audio.fx(afx.volumex,background_audio_volume) - background_audio = background_audio.subclip(start_time_audio,end_time_audio) - background_audio.write_audiofile(f"assets/temp/{id}/background.mp3") - #background_video.set_audio(background_audio) - - + # Extract video subclip try: ffmpeg_extract_subclip( f"assets/backgrounds/video/{video_choice}", diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 89187ca..63c5842 100644 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -103,6 +103,28 @@ def prepare_background(reddit_id: str, W: int, H: int) -> str: exit() return output_path +def merge_background_audio(audio: ffmpeg, reddit_id: str): + """Gather an audio and merge with assets/backgrounds/background.mp3 + Args: + audio (ffmpeg): The TTS final audio but without background. + reddit_id (str): The ID of subreddit + """ + background_audio_volume = settings.config["settings"]["background"]["background_audio_volume"] + if (background_audio_volume == 0): + return audio # Return the original audio + else: + # sets volume to config + bg_audio = ( + ffmpeg.input(f"assets/temp/{reddit_id}/background.mp3") + .filter( + "volume", + background_audio_volume, + ) + ) + # Merges audio and background_audio + merged_audio = ffmpeg.filter([audio, bg_audio], "amix", duration="longest") + return merged_audio # Return merged audio + def make_final_video( number_of_clips: int, @@ -122,6 +144,10 @@ def make_final_video( H: Final[int] = int(settings.config["settings"]["resolution_h"]) reddit_id = re.sub(r"[^\w\s-]", "", reddit_obj["thread_id"]) + + allowOnlyTTSFolder: bool = settings.config["settings"]["background"]["allow_only_tts"] \ + and settings.config["settings"]["background"]["background_audio_volume"] != 0 + print_step("Creating the final video 🎥") background_clip = ffmpeg.input(prepare_background(reddit_id, W=W, H=H)) @@ -177,8 +203,7 @@ def make_final_video( screenshot_width = int((W * 45) // 100) audio = ffmpeg.input(f"assets/temp/{reddit_id}/audio.mp3") - background_audio = ffmpeg.input(f"assets/temp/{reddit_id}/background.mp3") - final_audio = ffmpeg.filter([audio, background_audio], "amix") + final_audio = merge_background_audio(audio,reddit_id) image_clips = list() @@ -263,9 +288,9 @@ def make_final_video( print_substep("The results folder didn't exist so I made it") os.makedirs(f"./results/{subreddit}") - if not exists(f"./results/{subreddit}/{filename}"): - print_substep("The results folder didn't exist so I made it") - os.makedirs(f"./results/{subreddit}/{filename}") + if not exists(f"./results/{subreddit}/OnlyTTS") and allowOnlyTTSFolder: + print_substep("The 'OnlyTTS' folder didn't exist so I made it") + os.makedirs(f"./results/{subreddit}/OnlyTTS") # create a thumbnail for the video settingsbackground = settings.config["settings"]["background"] @@ -326,9 +351,10 @@ def make_final_video( old_percentage = pbar.n pbar.update(status - old_percentage) - path = f"results/{subreddit}/{filename}" - path = path[:251] + path = f"results/{subreddit}" #path = path + ".mp4" + if(allowOnlyTTSFolder): + processingLength = 2*length with ProgressFfmpeg(length, on_update_example) as progress: ffmpeg.output( @@ -348,32 +374,38 @@ def make_final_video( capture_stdout=False, capture_stderr=False, ) - - with ProgressFfmpeg(length, on_update_example) as progress: - ffmpeg.output( - background_clip, - audio, - path+"/NoBackgroundAudio.mp4", - f="mp4", - **{ - "c:v": "h264", - "b:v": "20M", - "b:a": "192k", - "threads": multiprocessing.cpu_count(), - }, - ).overwrite_output().global_args("-progress", progress.output_file.name).run( - quiet=True, - overwrite_output=True, - capture_stdout=False, - capture_stderr=False, - ) - old_percentage = pbar.n pbar.update(100 - old_percentage) + if(allowOnlyTTSFolder): + print_step("Rendering the Only TTS Video 🎥") + with ProgressFfmpeg(length, on_update_example) as progress: + ffmpeg.output( + background_clip, + audio, + path+f"/OnlyTTS/{filename}.mp4", + f="mp4", + **{ + "c:v": "h264", + "b:v": "20M", + "b:a": "192k", + "threads": multiprocessing.cpu_count(), + }, + ).overwrite_output().global_args("-progress", progress.output_file.name).run( + quiet=True, + overwrite_output=True, + capture_stdout=False, + capture_stderr=False, + ) + old_percentage = pbar.n + pbar.update(100 - old_percentage) + pbar.close() + + + save_data(subreddit, filename + ".mp4", title, idx, background_config['video'][2]) print_step("Removing temporary files 🗑") cleanups = cleanup(reddit_id) print_substep(f"Removed {cleanups} temporary files 🗑") - print_step("Done! 🎉 The video is in the results folder 📁") + print_step("Done! 🎉 The video is in the results folder 📁") \ No newline at end of file From d9ff36b034e83865080fc7c1a6d4afdfd7908b9a Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 23 Apr 2023 18:10:10 -0300 Subject: [PATCH 08/13] Merge with develop branch and no pytube required --- main.py | 9 +++++++-- requirements.txt | 1 - utils/.config.template.toml | 4 ++-- video_creation/background.py | 16 ++++++++++++---- video_creation/final_video.py | 4 ---- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/main.py b/main.py index 81fb503..0a17968 100755 --- a/main.py +++ b/main.py @@ -6,6 +6,7 @@ from os import name from pathlib import Path from subprocess import Popen +import ffmpeg from prawcore import ResponseException from utils.console import print_substep from reddit.subreddit import get_subreddit_threads @@ -57,7 +58,11 @@ def main(POST_ID=None) -> None: download_background_video(bg_config["video"]) download_background_audio(bg_config["audio"]) chop_background(bg_config, length, reddit_object) - make_final_video(number_of_comments, length, reddit_object, bg_config) + try: + make_final_video(number_of_comments, length, reddit_object, bg_config) + except ffmpeg.Error as e: + print(e.stderr.decode("utf8")) + exit(1) def run_many(times) -> None: @@ -131,4 +136,4 @@ if __name__ == "__main__": f"Error: {err} \n" f'Config: {config["settings"]}' ) - raise err + raise err \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 634a24b..823493e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,6 @@ moviepy==1.0.3 playwright==1.23.0 praw==7.6.1 prawcore~=2.3.0 -pytube==12.1.0 requests==2.28.1 rich==13.3.1 toml==0.10.2 diff --git a/utils/.config.template.toml b/utils/.config.template.toml index a9d6d27..c8d7d61 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -43,11 +43,11 @@ background_thumbnail_font_size = { optional = true, type = "int", default = 96, background_thumbnail_font_color = { optional = true, default = "255,255,255", example = "255,255,255", explanation = "Font color in RGB format for the thumbnail text" } [settings.tts] -voice_choice = { optional = false, default = "tiktok", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", "pyttsx", ], example = "tiktok", explanation = "The voice platform used for TTS generation. This can be left blank and you will be prompted to choose at runtime." } +voice_choice = { optional = false, default = "streamlabspolly", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", "pyttsx", ], example = "tiktok", explanation = "The voice platform used for TTS generation. This can be left blank and you will be prompted to choose at runtime." } aws_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for AWS Polly" } streamlabs_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for Streamlabs Polly" } tiktok_voice = { optional = true, default = "en_us_001", example = "en_us_006", explanation = "The voice used for TikTok TTS" } -tiktok_sessionid = { optional = true, example = "c76bcc3a7625abcc27b508c7db457ff1", explanation = "TikTok sessionid needed for the TTS API request. Check documentation if you don't know how to obtain it." } +tiktok_sessionid = { optional = true, example = "c76bcc3a7625abcc27b508c7db457ff1", explanation = "TikTok sessionid needed if you're using the TikTok TTS. Check documentation if you don't know how to obtain it." } python_voice = { optional = false, default = "1", example = "1", explanation = "The index of the system tts voices (can be downloaded externally, run ptt.py to find value, start from zero)" } py_voice_num = { optional = false, default = "2", example = "2", explanation = "The number of system voices (2 are pre-installed in Windows)" } silence_duration = { optional = true, example = "0.1", explanation = "Time in seconds between TTS comments", default = 0.3, type = "float" } diff --git a/video_creation/background.py b/video_creation/background.py index 3b896d9..8c3dcee 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -7,7 +7,6 @@ from typing import Any, Tuple,Dict 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.console import print_step, print_substep @@ -104,9 +103,18 @@ def download_background_audio(background_config: Tuple[str, str, str]): ) print_substep("Downloading the backgrounds audio... please be patient 🙏 ") print_substep(f"Downloading {filename} from {uri}") - YouTube(uri, on_progress_callback=on_progress).streams.filter( - only_audio=True - ).first().download("assets/backgrounds/audio", filename=f"{credit}-{filename}") + ydl_opts = { + 'outtmpl': f'./assets/backgrounds/audio/{credit}-{filename}', + 'format': 'bestaudio/best', + 'postprocessors': [{ + 'preferredcodec': 'mp3', + 'preferredquality': '192', + }], + } + + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + ydl.download([uri]) + print_substep("Background audio downloaded successfully! 🎉", style="bold green") diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 63c5842..452b128 100644 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -398,12 +398,8 @@ def make_final_video( ) old_percentage = pbar.n pbar.update(100 - old_percentage) - pbar.close() - - - save_data(subreddit, filename + ".mp4", title, idx, background_config['video'][2]) print_step("Removing temporary files 🗑") cleanups = cleanup(reddit_id) From 0258026ebd81e9c068fec6039b37c70e6fbee8de Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 23 Apr 2023 18:30:54 -0300 Subject: [PATCH 09/13] fixed audio post processing audio download bug --- video_creation/background.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/video_creation/background.py b/video_creation/background.py index 8c3dcee..d27ee6b 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -7,7 +7,6 @@ from typing import Any, Tuple,Dict from moviepy.editor import VideoFileClip,AudioFileClip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip -from pytube.cli import on_progress from utils import settings from utils.console import print_step, print_substep import yt_dlp @@ -106,10 +105,7 @@ def download_background_audio(background_config: Tuple[str, str, str]): ydl_opts = { 'outtmpl': f'./assets/backgrounds/audio/{credit}-{filename}', 'format': 'bestaudio/best', - 'postprocessors': [{ - 'preferredcodec': 'mp3', - 'preferredquality': '192', - }], + 'extract_audio': True, } with yt_dlp.YoutubeDL(ydl_opts) as ydl: From e488ef6e0c19ef49898c84594c52a3a9a9c60b0c Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 24 Apr 2023 10:43:14 -0300 Subject: [PATCH 10/13] better explanation on toml and new default value --- utils/.config.template.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/.config.template.toml b/utils/.config.template.toml index c8d7d61..71dcef7 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -34,8 +34,8 @@ resolution_h = { optional = false, default = 1920, example = 2560, explantation [settings.background] background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } -background_audio = { optional = true, default = "lofi", example = "minecraft", options = ["minecraft","lofi","undertale"], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } -background_audio_volume = { optional = true, type = "float", nmin = 0, nmax = 1, default = 0.1, example = 0.05, explanation="Sets the volume of the background audio. Type a value between 0 and 1.", oob_error = "The volume HAS to be between 0 and 1", input_error = "The volume HAS to be a float number between 0 and 1"} +background_audio = { optional = true, default = "lofi", example = "minecraft", options = ["minecraft","lofi","undertale",""], explanation = "Sets the background audio for the video" } +background_audio_volume = { optional = true, type = "float", nmin = 0, nmax = 1, default = 0.15, example = 0.05, explanation="Sets the volume of the background audio. If you don't want background audio, set it to 0.", oob_error = "The volume HAS to be between 0 and 1", input_error = "The volume HAS to be a float number between 0 and 1"} allow_only_tts = { optional = true, type = "bool", default = false, example = false, explanation="Used if you want to render another video with only TTS audio in a separate folder", input_error = "The value HAS to be true or false"} background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" } background_thumbnail_font_family = { optional = true, default = "arial", example = "arial", explanation = "Font family for the thumbnail text" } From 778d9c0c37bb970492a51b93b6a8977b8542acfa Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 24 Apr 2023 16:35:08 -0300 Subject: [PATCH 11/13] changing allow_only_tts to enable_extra_audio --- utils/.config.template.toml | 2 +- video_creation/final_video.py | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/utils/.config.template.toml b/utils/.config.template.toml index 71dcef7..d9d7582 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -36,7 +36,7 @@ resolution_h = { optional = false, default = 1920, example = 2560, explantation background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } background_audio = { optional = true, default = "lofi", example = "minecraft", options = ["minecraft","lofi","undertale",""], explanation = "Sets the background audio for the video" } background_audio_volume = { optional = true, type = "float", nmin = 0, nmax = 1, default = 0.15, example = 0.05, explanation="Sets the volume of the background audio. If you don't want background audio, set it to 0.", oob_error = "The volume HAS to be between 0 and 1", input_error = "The volume HAS to be a float number between 0 and 1"} -allow_only_tts = { optional = true, type = "bool", default = false, example = false, explanation="Used if you want to render another video with only TTS audio in a separate folder", input_error = "The value HAS to be true or false"} +enable_extra_audio = { optional = true, type = "bool", default = false, example = false, explanation="Used if you want to render another video without background audio in a separate folder", input_error = "The value HAS to be true or false"} background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" } background_thumbnail_font_family = { optional = true, default = "arial", example = "arial", explanation = "Font family for the thumbnail text" } background_thumbnail_font_size = { optional = true, type = "int", default = 96, example = 96, explanation = "Font size in pixels for the thumbnail text" } diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 452b128..55e0d39 100644 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -145,7 +145,7 @@ def make_final_video( reddit_id = re.sub(r"[^\w\s-]", "", reddit_obj["thread_id"]) - allowOnlyTTSFolder: bool = settings.config["settings"]["background"]["allow_only_tts"] \ + allowOnlyTTSFolder: bool = settings.config["settings"]["background"]["enable_extra_audio"] \ and settings.config["settings"]["background"]["background_audio_volume"] != 0 print_step("Creating the final video 🎥") @@ -285,7 +285,7 @@ def make_final_video( subreddit = settings.config["reddit"]["thread"]["subreddit"] if not exists(f"./results/{subreddit}"): - print_substep("The results folder didn't exist so I made it") + print_substep("The 'results' folder didn't exist so I made it") os.makedirs(f"./results/{subreddit}") if not exists(f"./results/{subreddit}/OnlyTTS") and allowOnlyTTSFolder: @@ -352,9 +352,6 @@ def make_final_video( pbar.update(status - old_percentage) path = f"results/{subreddit}" - #path = path + ".mp4" - if(allowOnlyTTSFolder): - processingLength = 2*length with ProgressFfmpeg(length, on_update_example) as progress: ffmpeg.output( From d8347e08b9c2a6524823c9b030cce60c27cb06dc Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 24 Apr 2023 23:55:18 -0300 Subject: [PATCH 12/13] Fixed issues and improvements related by Jason --- main.py | 7 ++++--- video_creation/background.py | 4 ++-- video_creation/final_video.py | 17 ++++++++++------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/main.py b/main.py index 0a17968..2b78629 100755 --- a/main.py +++ b/main.py @@ -51,10 +51,11 @@ def main(POST_ID=None) -> None: redditid = id(reddit_object) length, number_of_comments = save_text_to_mp3(reddit_object) length = math.ceil(length) - bg_config = {} get_screenshots_of_reddit_posts(reddit_object, number_of_comments) - bg_config["video"] = get_background_config("video") - bg_config["audio"] = get_background_config("audio") + bg_config = { + "video": get_background_config("video"), + "audio": get_background_config("audio"), + } download_background_video(bg_config["video"]) download_background_audio(bg_config["audio"]) chop_background(bg_config, length, reddit_object) diff --git a/video_creation/background.py b/video_creation/background.py index d27ee6b..010f15e 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -22,8 +22,8 @@ def load_background_options(): background_options["audio"] = json.load(json_file) # Remove "__comment" from backgrounds - background_options["video"].pop("__comment", None) - background_options["audio"].pop("__comment", None) + del background_options["video"]["__comment"] + del background_options["audio"]["__comment"] # Add position lambda function # (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position) diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 55e0d39..ca801c5 100644 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -285,11 +285,11 @@ def make_final_video( subreddit = settings.config["reddit"]["thread"]["subreddit"] if not exists(f"./results/{subreddit}"): - print_substep("The 'results' folder didn't exist so I made it") + print_substep("The 'results' folder could not be found so it was automatically created.") os.makedirs(f"./results/{subreddit}") if not exists(f"./results/{subreddit}/OnlyTTS") and allowOnlyTTSFolder: - print_substep("The 'OnlyTTS' folder didn't exist so I made it") + print_substep("The 'OnlyTTS' folder could not be found so it was automatically created.") os.makedirs(f"./results/{subreddit}/OnlyTTS") # create a thumbnail for the video @@ -297,7 +297,7 @@ def make_final_video( if settingsbackground["background_thumbnail"]: if not exists(f"./results/{subreddit}/thumbnails"): - print_substep("The results/thumbnails folder didn't exist so I made it") + print_substep("The 'results/thumbnails' folder could not be found so it was automatically created.") os.makedirs(f"./results/{subreddit}/thumbnails") # get the first file with the .png extension from assets/backgrounds and use it as a background for the thumbnail first_image = next( @@ -351,13 +351,14 @@ def make_final_video( old_percentage = pbar.n pbar.update(status - old_percentage) - path = f"results/{subreddit}" - + defaultPath = f"results/{subreddit}" with ProgressFfmpeg(length, on_update_example) as progress: + path = defaultPath + f"/{filename}" + path = path[:251] + ".mp4" #Prevent a error by limiting the path length, do not change this. ffmpeg.output( background_clip, final_audio, - path+f"/{filename}.mp4", + path, f="mp4", **{ "c:v": "h264", @@ -374,12 +375,14 @@ def make_final_video( old_percentage = pbar.n pbar.update(100 - old_percentage) if(allowOnlyTTSFolder): + path = defaultPath + f"/OnlyTTS/{filename}" + path = path[:251] + ".mp4" #Prevent a error by limiting the path length, do not change this. print_step("Rendering the Only TTS Video 🎥") with ProgressFfmpeg(length, on_update_example) as progress: ffmpeg.output( background_clip, audio, - path+f"/OnlyTTS/{filename}.mp4", + path, f="mp4", **{ "c:v": "h264", From 7613ac59e7e58ef0db56bf7720749fd2f5046d8d Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 25 Apr 2023 00:05:51 -0300 Subject: [PATCH 13/13] added only no copyright songs --- utils/.config.template.toml | 2 +- utils/background_audios.json | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/utils/.config.template.toml b/utils/.config.template.toml index d9d7582..a360569 100644 --- a/utils/.config.template.toml +++ b/utils/.config.template.toml @@ -34,7 +34,7 @@ resolution_h = { optional = false, default = 1920, example = 2560, explantation [settings.background] background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } -background_audio = { optional = true, default = "lofi", example = "minecraft", options = ["minecraft","lofi","undertale",""], explanation = "Sets the background audio for the video" } +background_audio = { optional = true, default = "lofi", example = "chill-summer", options = ["lofi","lofi-2","chill-summer",""], explanation = "Sets the background audio for the video" } background_audio_volume = { optional = true, type = "float", nmin = 0, nmax = 1, default = 0.15, example = 0.05, explanation="Sets the volume of the background audio. If you don't want background audio, set it to 0.", oob_error = "The volume HAS to be between 0 and 1", input_error = "The volume HAS to be a float number between 0 and 1"} enable_extra_audio = { optional = true, type = "bool", default = false, example = false, explanation="Used if you want to render another video without background audio in a separate folder", input_error = "The value HAS to be true or false"} background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" } diff --git a/utils/background_audios.json b/utils/background_audios.json index 2dcd35c..752436d 100644 --- a/utils/background_audios.json +++ b/utils/background_audios.json @@ -1,18 +1,18 @@ { "__comment": "Supported Backgrounds Audio. Can add/remove background audio here...", - "minecraft": [ - "https://www.youtube.com/watch?v=2p3nBYUaJz8", - "minecraft.mp3", - "adriPixs" + "lofi": [ + "https://www.youtube.com/watch?v=LTphVIore3A", + "lofi.mp3", + "Super Lofi World" ], - "lofi":[ + "lofi-2":[ "https://www.youtube.com/watch?v=BEXL80LS0-I", - "lofi.mp3", + "lofi-2.mp3", "stompsPlaylist" ], - "undertale":[ - "https://www.youtube.com/watch?v=TIokr8jJPkM", - "undertale.mp3", - "abby" + "chill-summer":[ + "https://www.youtube.com/watch?v=EZE8JagnBI8", + "chill-summer.mp3", + "Mellow Vibes Radio" ] }