From 1bd39db6f20fa52528059a69c645c1a38571c3f7 Mon Sep 17 00:00:00 2001 From: napuh Date: Wed, 13 Jul 2022 19:47:33 +0200 Subject: [PATCH 1/9] Fix: cutting long file names to avoid errors when saving --- video_creation/final_video.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 8524051..c7e7fc3 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -29,11 +29,11 @@ def name_normalize(name: str) -> str: name = re.sub(r"(\d+)\s?\/\s?(\d+)", r"\1 of \2", name) name = re.sub(r"(\w+)\s?\/\s?(\w+)", r"\1 or \2", name) name = re.sub(r"\/", r"", name) + name[:70] lang = settings.config["reddit"]["thread"]["post_lang"] if lang: import translators as ts - print_substep("Translating filename...") translated_name = ts.google(name, to_language=lang) return translated_name From d7419cf8e3c3524910c6a33c2fc4c0c2d3ae2dee Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 19:07:42 -0400 Subject: [PATCH 2/9] Update final_video.py --- video_creation/final_video.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video_creation/final_video.py b/video_creation/final_video.py index c7e7fc3..eb42247 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -29,7 +29,7 @@ def name_normalize(name: str) -> str: name = re.sub(r"(\d+)\s?\/\s?(\d+)", r"\1 of \2", name) name = re.sub(r"(\w+)\s?\/\s?(\w+)", r"\1 or \2", name) name = re.sub(r"\/", r"", name) - name[:70] + name[:30] lang = settings.config["reddit"]["thread"]["post_lang"] if lang: From 1e93121aede538f4807ab73737a884260e388211 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 12 Jul 2022 12:41:42 -0400 Subject: [PATCH 3/9] Watermark implementation THIS IS IN BETA --- main.py | 4 +-- requirements.txt | 2 ++ utils/video.py | 55 ++++++++++++++++++++++++++++++++ video_creation/final_video.py | 60 +++++++++++------------------------ 4 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 utils/video.py diff --git a/main.py b/main.py index 10ab3c1..653703c 100755 --- a/main.py +++ b/main.py @@ -16,8 +16,8 @@ from video_creation.final_video import make_final_video from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts from video_creation.voices import save_text_to_mp3 -__VERSION__ = "2.3" -__BRANCH__ = "master" +__VERSION__ = "2.3.1" +__BRANCH__ = "develop" print( """ diff --git a/requirements.txt b/requirements.txt index e57a37d..7bccd0d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,5 @@ requests==2.28.1 rich==12.5.1 toml==0.10.2 translators==5.3.1 + +Pillow~=9.1.1 diff --git a/utils/video.py b/utils/video.py new file mode 100644 index 0000000..f49e58f --- /dev/null +++ b/utils/video.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +from moviepy.video.VideoClip import VideoClip, ImageClip +from moviepy.video.io.VideoFileClip import VideoFileClip +from PIL import Image, ImageDraw, ImageFont, ImageEnhance + +class Video: + def __init__(self, video: VideoClip | VideoFileClip, *args, **kwargs): + self.video: VideoClip = video + self.fps = self.video.fps + self.duration = self.video.duration + + @staticmethod + def _create_watermark(text, path, fontsize=15, opacity=0.5): + + width = 500 + height = 200 + + white = (255, 255, 255) + transparent = (0, 0, 0, 0) + + font = ImageFont.load_default() + wm = Image.new('RGBA', (width, height), transparent) + im = Image.new('RGBA', (width, height), transparent) # Change this line too. + + draw = ImageDraw.Draw(wm) + w, h = draw.textsize(text, font) + draw.text(((width - w) / 2, (height - h) / 2), text, white, font) + en = ImageEnhance.Brightness(wm) # todo alow it to use the fontsize + mask = en.enhance(1 - opacity) + im.paste(wm, (25, 25), mask) + im.save(path) + + def add_watermark(self, text, opacity=0.5): + # add a watermark to the video clip with the given text and opacity without importing a new library + from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip + from moviepy.video.compositing.concatenate import concatenate_videoclips + path = './assets/temp/png/watermark.png' + self._create_watermark(text, path, opacity=opacity) + image_clips = [] + image_clips.insert( + 0, + ImageClip(path) + .set_duration(self.video.duration) + #.resize(width=W - 100) + ) + image_concat = concatenate_videoclips(image_clips).set_position((0.1, 0.1)) + self.video = CompositeVideoClip([self.video, image_concat]) + return self.video + + + + +if __name__ == '__main__': # todo delete + Video._create_watermark('Background Video by Jason(example)', '../assets/temp/png/watermark.png') diff --git a/video_creation/final_video.py b/video_creation/final_video.py index eb42247..5a52348 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -15,6 +15,7 @@ from rich.console import Console from utils.cleanup import cleanup from utils.console import print_step, print_substep +from utils.video import Video from utils.videos import save_data from utils import settings @@ -42,12 +43,8 @@ def name_normalize(name: str) -> str: return name -def make_final_video( - number_of_clips: int, - length: int, - reddit_obj: dict, - background_config: Tuple[str, str, str, Any], -): +def make_final_video(number_of_clips: int, length: int, reddit_obj: dict, + background_config: Tuple[str, str, str, Any], ): """Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp Args: number_of_clips (int): Index to end at when going through the screenshots' @@ -65,11 +62,8 @@ def make_final_video( VideoFileClip.reH = lambda clip: clip.resize(width=H) opacity = settings.config["settings"]["opacity"] background_clip = ( - VideoFileClip("assets/temp/background.mp4") - .without_audio() - .resize(height=H) - .crop(x1=1166.6, y1=0, x2=2246.6, y2=1920) - ) + VideoFileClip("assets/temp/background.mp4").without_audio().resize(height=H).crop(x1=1166.6, y1=0, x2=2246.6, + y2=1920)) # Gather all audio clips audio_clips = [AudioFileClip(f"assets/temp/mp3/{i}.mp3") for i in range(number_of_clips)] @@ -82,21 +76,15 @@ def make_final_video( image_clips = [] # Gather all images new_opacity = 1 if opacity is None or float(opacity) >= 1 else float(opacity) - image_clips.insert( - 0, - ImageClip("assets/temp/png/title.png") - .set_duration(audio_clips[0].duration) - .resize(width=W - 100) - .set_opacity(new_opacity), - ) + image_clips.insert(0, + ImageClip("assets/temp/png/title.png").set_duration(audio_clips[0].duration).resize( + width=W - 100).set_opacity( + new_opacity), ) for i in range(0, number_of_clips): image_clips.append( - ImageClip(f"assets/temp/png/comment_{i}.png") - .set_duration(audio_clips[i + 1].duration) - .resize(width=W - 100) - .set_opacity(new_opacity) - ) + ImageClip(f"assets/temp/png/comment_{i}.png").set_duration(audio_clips[i + 1].duration).resize( + width=W - 100).set_opacity(new_opacity)) # if os.path.exists("assets/mp3/posttext.mp3"): # image_clips.insert( @@ -109,7 +97,8 @@ def make_final_video( # ) # else: story mode stuff img_clip_pos = background_config[3] - image_concat = concatenate_videoclips(image_clips).set_position(img_clip_pos) + image_concat = concatenate_videoclips(image_clips).set_position( + img_clip_pos) # note transition kwarg for delay in imgs image_concat.audio = audio_composite final = CompositeVideoClip([background_clip, image_concat]) title = re.sub(r"[^\w\s-]", "", reddit_obj["thread_title"]) @@ -129,27 +118,14 @@ def make_final_video( # # 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) - - final.write_videofile( - "assets/temp/temp.mp4", - fps=30, - audio_codec="aac", - audio_bitrate="192k", - verbose=False, - threads=multiprocessing.cpu_count(), - ) - ffmpeg_extract_subclip( - "assets/temp/temp.mp4", - 0, - final.duration, - targetname=f"results/{subreddit}/{filename}", - ) + final = Video(final).add_watermark(text=f'Background credit: {background_config[2]}', opacity=0.4) + final.write_videofile("assets/temp/temp.mp4", fps=30, audio_codec="aac", audio_bitrate="192k", verbose=False, + threads=multiprocessing.cpu_count(), ) + ffmpeg_extract_subclip("assets/temp/temp.mp4", 0, final.duration, targetname=f"results/{subreddit}/{filename}", ) save_data(subreddit, filename, title, idx, background_config[2]) print_step("Removing temporary files 🗑") cleanups = cleanup() print_substep(f"Removed {cleanups} temporary files 🗑") print_substep("See result in the results folder!") - print_step( - f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}' - ) + print_step(f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}') From 7dcac10d1ef1b6e1c6379545a8a1a3d4d7e54463 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 12 Jul 2022 13:11:33 -0400 Subject: [PATCH 4/9] backup but I will be reverting this. --- utils/video.py | 54 ++++++++++++-------------------------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/utils/video.py b/utils/video.py index f49e58f..2cceae1 100644 --- a/utils/video.py +++ b/utils/video.py @@ -1,8 +1,11 @@ from __future__ import annotations -from moviepy.video.VideoClip import VideoClip, ImageClip +from typing import Tuple + +from moviepy.video.VideoClip import VideoClip, TextClip from moviepy.video.io.VideoFileClip import VideoFileClip -from PIL import Image, ImageDraw, ImageFont, ImageEnhance +from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip + class Video: def __init__(self, video: VideoClip | VideoFileClip, *args, **kwargs): @@ -11,45 +14,14 @@ class Video: self.duration = self.video.duration @staticmethod - def _create_watermark(text, path, fontsize=15, opacity=0.5): - - width = 500 - height = 200 - - white = (255, 255, 255) - transparent = (0, 0, 0, 0) - - font = ImageFont.load_default() - wm = Image.new('RGBA', (width, height), transparent) - im = Image.new('RGBA', (width, height), transparent) # Change this line too. + def _create_watermark(text, fontsize, opacity=0.5): + txt_clip = TextClip(text, fontsize=fontsize, color='black').set_opacity(opacity) + return txt_clip - draw = ImageDraw.Draw(wm) - w, h = draw.textsize(text, font) - draw.text(((width - w) / 2, (height - h) / 2), text, white, font) - en = ImageEnhance.Brightness(wm) # todo alow it to use the fontsize - mask = en.enhance(1 - opacity) - im.paste(wm, (25, 25), mask) - im.save(path) + def add_watermark(self, text, opacity=0.5, position: Tuple = (0.95, 0.95), fontsize=15): + txt_clip = self._create_watermark(text, opacity=opacity, fontsize=fontsize) + txt_clip = txt_clip.set_pos(position).set_duration(10) - def add_watermark(self, text, opacity=0.5): - # add a watermark to the video clip with the given text and opacity without importing a new library - from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip - from moviepy.video.compositing.concatenate import concatenate_videoclips - path = './assets/temp/png/watermark.png' - self._create_watermark(text, path, opacity=opacity) - image_clips = [] - image_clips.insert( - 0, - ImageClip(path) - .set_duration(self.video.duration) - #.resize(width=W - 100) - ) - image_concat = concatenate_videoclips(image_clips).set_position((0.1, 0.1)) - self.video = CompositeVideoClip([self.video, image_concat]) + # Overlay the text clip on the first video clip + self.video = CompositeVideoClip([self.video, txt_clip]) return self.video - - - - -if __name__ == '__main__': # todo delete - Video._create_watermark('Background Video by Jason(example)', '../assets/temp/png/watermark.png') From 36aa2566687e2d1935f50c713d00e330fbd7f8ba Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 18:13:57 -0400 Subject: [PATCH 5/9] refactored final_video.py updated requirements.txt simplified cleanup.py --- requirements.txt | 2 -- utils/cleanup.py | 18 ++++++----- video_creation/final_video.py | 61 ++++++++++++++++++++++++++--------- 3 files changed, 55 insertions(+), 26 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7bccd0d..e57a37d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,5 +9,3 @@ requests==2.28.1 rich==12.5.1 toml==0.10.2 translators==5.3.1 - -Pillow~=9.1.1 diff --git a/utils/cleanup.py b/utils/cleanup.py index ef4fc44..75074b7 100644 --- a/utils/cleanup.py +++ b/utils/cleanup.py @@ -2,6 +2,10 @@ import os from os.path import exists +def _listdir(d): # listdir with full path + return [os.path.join(d, f) for f in os.listdir(d)] + + def cleanup() -> int: """Deletes all temporary assets in assets/temp @@ -14,14 +18,12 @@ def cleanup() -> int: count += len(files) for f in files: os.remove(f) - try: - for file in os.listdir("./assets/temp/mp4"): + REMOVE_DIRS = ["./assets/temp/mp3/", "./assets/temp/png/"] + files_to_remove = list(map(_listdir, REMOVE_DIRS)) + for directory in files_to_remove: + for file in directory: count += 1 - os.remove("./assets/temp/mp4/" + file) - except FileNotFoundError: - pass - for file in os.listdir("./assets/temp/mp3"): - count += 1 - os.remove("./assets/temp/mp3/" + file) + os.remove(file) return count + return 0 diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 5a52348..3157296 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -43,8 +43,12 @@ def name_normalize(name: str) -> str: return name -def make_final_video(number_of_clips: int, length: int, reddit_obj: dict, - background_config: Tuple[str, str, str, Any], ): +def make_final_video( + number_of_clips: int, + length: int, + reddit_obj: dict, + background_config: Tuple[str, str, str, Any], +): """Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp Args: number_of_clips (int): Index to end at when going through the screenshots' @@ -62,8 +66,11 @@ def make_final_video(number_of_clips: int, length: int, reddit_obj: dict, VideoFileClip.reH = lambda clip: clip.resize(width=H) opacity = settings.config["settings"]["opacity"] background_clip = ( - VideoFileClip("assets/temp/background.mp4").without_audio().resize(height=H).crop(x1=1166.6, y1=0, x2=2246.6, - y2=1920)) + VideoFileClip("assets/temp/background.mp4") + .without_audio() + .resize(height=H) + .crop(x1=1166.6, y1=0, x2=2246.6, y2=1920) + ) # Gather all audio clips audio_clips = [AudioFileClip(f"assets/temp/mp3/{i}.mp3") for i in range(number_of_clips)] @@ -76,15 +83,21 @@ def make_final_video(number_of_clips: int, length: int, reddit_obj: dict, image_clips = [] # Gather all images new_opacity = 1 if opacity is None or float(opacity) >= 1 else float(opacity) - image_clips.insert(0, - ImageClip("assets/temp/png/title.png").set_duration(audio_clips[0].duration).resize( - width=W - 100).set_opacity( - new_opacity), ) + image_clips.insert( + 0, + ImageClip("assets/temp/png/title.png") + .set_duration(audio_clips[0].duration) + .resize(width=W - 100) + .set_opacity(new_opacity), + ) for i in range(0, number_of_clips): image_clips.append( - ImageClip(f"assets/temp/png/comment_{i}.png").set_duration(audio_clips[i + 1].duration).resize( - width=W - 100).set_opacity(new_opacity)) + ImageClip(f"assets/temp/png/comment_{i}.png") + .set_duration(audio_clips[i + 1].duration) + .resize(width=W - 100) + .set_opacity(new_opacity) + ) # if os.path.exists("assets/mp3/posttext.mp3"): # image_clips.insert( @@ -98,7 +111,8 @@ def make_final_video(number_of_clips: int, length: int, reddit_obj: dict, # else: story mode stuff img_clip_pos = background_config[3] image_concat = concatenate_videoclips(image_clips).set_position( - img_clip_pos) # note transition kwarg for delay in imgs + img_clip_pos + ) # note transition kwarg for delay in imgs image_concat.audio = audio_composite final = CompositeVideoClip([background_clip, image_concat]) title = re.sub(r"[^\w\s-]", "", reddit_obj["thread_title"]) @@ -118,14 +132,29 @@ def make_final_video(number_of_clips: int, length: int, reddit_obj: dict, # # 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) - final = Video(final).add_watermark(text=f'Background credit: {background_config[2]}', opacity=0.4) - final.write_videofile("assets/temp/temp.mp4", fps=30, audio_codec="aac", audio_bitrate="192k", verbose=False, - threads=multiprocessing.cpu_count(), ) - ffmpeg_extract_subclip("assets/temp/temp.mp4", 0, final.duration, targetname=f"results/{subreddit}/{filename}", ) + final = Video(final).add_watermark( + text=f"Background credit: {background_config[2]}", opacity=0.4 + ) + final.write_videofile( + "assets/temp/temp.mp4", + fps=30, + audio_codec="aac", + audio_bitrate="192k", + verbose=False, + threads=multiprocessing.cpu_count(), + ) + ffmpeg_extract_subclip( + "assets/temp/temp.mp4", + 0, + final.duration, + targetname=f"results/{subreddit}/{filename}", + ) save_data(subreddit, filename, title, idx, background_config[2]) print_step("Removing temporary files 🗑") cleanups = cleanup() print_substep(f"Removed {cleanups} temporary files 🗑") print_substep("See result in the results folder!") - print_step(f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}') + print_step( + f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}' + ) From 2f3efb03a9a7e01e786be121e9aff7f45f1a1c52 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 18:15:29 -0400 Subject: [PATCH 6/9] typo: fixed typo in engine_wrapper.py --- TTS/engine_wrapper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TTS/engine_wrapper.py b/TTS/engine_wrapper.py index c5ed714..213defb 100644 --- a/TTS/engine_wrapper.py +++ b/TTS/engine_wrapper.py @@ -13,7 +13,7 @@ from utils.console import print_step, print_substep from utils.voice import sanitize_text from utils import settings -DEFUALT_MAX_LENGTH: int = 50 # video length variable +DEFAULT_MAX_LENGTH: int = 50 # video length variable class TTSEngine: @@ -35,7 +35,7 @@ class TTSEngine: tts_module, reddit_object: dict, path: str = "assets/temp/mp3", - max_length: int = DEFUALT_MAX_LENGTH, + max_length: int = DEFAULT_MAX_LENGTH, ): self.tts_module = tts_module() self.reddit_object = reddit_object From 891c9945fd02b7003dd7cf9633b9516d0490fe81 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 21:55:32 -0400 Subject: [PATCH 7/9] refactor: moved backgrounds to CONSTANTS.py --- .config.template.toml | 2 +- utils/CONSTANTS.py | 46 ++++++++++++++++++++++++++++++++++++ video_creation/background.py | 35 +-------------------------- 3 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 utils/CONSTANTS.py diff --git a/.config.template.toml b/.config.template.toml index 18f1b00..9fd779e 100644 --- a/.config.template.toml +++ b/.config.template.toml @@ -31,7 +31,7 @@ storymode = { optional = true, type = "bool", default = false, example = false, ], explanation = "not yet implemented" } [settings.background] -background_choice = { optional = true, default = "minecraft", example = "minecraft", options = ["minecraft", "gta", "rocket-league", "motor-gta", ""], explanation = "Sets the background for the video" } +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, 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 new file mode 100644 index 0000000..76d2ee4 --- /dev/null +++ b/utils/CONSTANTS.py @@ -0,0 +1,46 @@ + +# Supported Background. Can add/remove background video here.... +# - : key -> used as keyword for TOML 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", + lambda t: ("center", 200 + t), + ), + "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), + ), + "csgo-surf": ( # CSGO Surf + "https://www.youtube.com/watch?v=E-8JlyO59Io", + "csgo-surf.mp4", + "Aki", + "center", + ), + "cluster-truck": ( # Cluster Truck Gameplay + "https://www.youtube.com/watch?v=uVKxtdMgJVU", + "cluster_truck.mp4", + "No Copyright Gameplay", + lambda t: ("center", 480 + t), + ), +} diff --git a/video_creation/background.py b/video_creation/background.py index be0f46c..bef0c53 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -10,42 +10,9 @@ from pytube import YouTube from pytube.cli import on_progress from utils import settings +from utils.CONSTANTS import background_options from utils.console import print_step, print_substep -# Supported Background. Can add/remove background video here.... -# - : key -> used as keyword for TOML 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", - lambda t: ("center", 200 + t), - ), - "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]: """Generates a random interval of time to be used as the background of the video. From 3b5ab95720160298b275210e1ead357cf8fdc123 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 22:15:35 -0400 Subject: [PATCH 8/9] potentially fixes #978 --- video_creation/screenshot_downloader.py | 44 ++++++++++--------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/video_creation/screenshot_downloader.py b/video_creation/screenshot_downloader.py index 6fb9ef4..8010862 100644 --- a/video_creation/screenshot_downloader.py +++ b/video_creation/screenshot_downloader.py @@ -49,36 +49,29 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in print_substep("Post is NSFW. You are spicy...") page.locator('[data-testid="content-gate"] button').click() - page.locator( - '[data-click-id="text"] button' - ).click() # Remove "Click to see nsfw" Button in Screenshot + + if page.locator('[data-click-id="text"] button').is_visible(): + page.locator('[data-click-id="text"] button').click() # Remove "Click to see nsfw" Button in Screenshot # translate code if settings.config["reddit"]["thread"]["post_lang"]: print_substep("Translating post...") - texts_in_tl = ts.google( - reddit_object["thread_title"], - to_language=settings.config["reddit"]["thread"]["post_lang"], - ) + texts_in_tl = ts.google(reddit_object["thread_title"], + to_language=settings.config["reddit"]["thread"]["post_lang"], ) page.evaluate( "tl_content => document.querySelector('[data-test-id=\"post-content\"] > div:nth-child(3) > div > div').textContent = tl_content", - texts_in_tl, - ) + texts_in_tl, ) else: print_substep("Skipping translation...") page.locator('[data-test-id="post-content"]').screenshot(path="assets/temp/png/title.png") if storymode: - page.locator('[data-click-id="text"]').screenshot( - path="assets/temp/png/story_content.png" - ) + page.locator('[data-click-id="text"]').screenshot(path="assets/temp/png/story_content.png") else: - for idx, comment in enumerate( - track(reddit_object["comments"], "Downloading screenshots...") - ): + for idx, comment in enumerate(track(reddit_object["comments"], "Downloading screenshots...")): # Stop if we have reached the screenshot_num if idx >= screenshot_num: break @@ -91,17 +84,16 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in # translate code if settings.config["reddit"]["thread"]["post_lang"]: - comment_tl = ts.google( - comment["comment_body"], - to_language=settings.config["reddit"]["thread"]["post_lang"], - ) + comment_tl = ts.google(comment["comment_body"], + to_language=settings.config["reddit"]["thread"]["post_lang"], ) page.evaluate( '([tl_content, tl_id]) => document.querySelector(`#t1_${tl_id} > div:nth-child(2) > div > div[data-testid="comment"] > div`).textContent = tl_content', - [comment_tl, comment["comment_id"]], - ) - - page.locator(f"#t1_{comment['comment_id']}").screenshot( - path=f"assets/temp/png/comment_{idx}.png" - ) - + [comment_tl, comment["comment_id"]], ) + try: + page.locator(f"#t1_{comment['comment_id']}").screenshot(path=f"assets/temp/png/comment_{idx}.png") + except TimeoutError: + del reddit_object["comments"] + screenshot_num += 1 + print('TimeoutError: Skipping screenshot...') + continue print_substep("Screenshots downloaded Successfully.", style="bold green") From 78ff605c42ce058d71304710822b481ee1afd61c Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 22:20:17 -0400 Subject: [PATCH 9/9] everything works except for changes the location --- TTS/engine_wrapper.py | 2 +- requirements.txt | 2 ++ utils/video.py | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/TTS/engine_wrapper.py b/TTS/engine_wrapper.py index 213defb..93da092 100644 --- a/TTS/engine_wrapper.py +++ b/TTS/engine_wrapper.py @@ -13,7 +13,7 @@ from utils.console import print_step, print_substep from utils.voice import sanitize_text from utils import settings -DEFAULT_MAX_LENGTH: int = 50 # video length variable +DEFAULT_MAX_LENGTH: int = 10 # video length variable class TTSEngine: diff --git a/requirements.txt b/requirements.txt index e57a37d..7bccd0d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,5 @@ requests==2.28.1 rich==12.5.1 toml==0.10.2 translators==5.3.1 + +Pillow~=9.1.1 diff --git a/utils/video.py b/utils/video.py index 2cceae1..61dc41c 100644 --- a/utils/video.py +++ b/utils/video.py @@ -2,26 +2,44 @@ from __future__ import annotations from typing import Tuple -from moviepy.video.VideoClip import VideoClip, TextClip -from moviepy.video.io.VideoFileClip import VideoFileClip +from PIL import ImageFont, Image, ImageDraw, ImageEnhance +from moviepy.video.VideoClip import VideoClip, ImageClip from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip class Video: - def __init__(self, video: VideoClip | VideoFileClip, *args, **kwargs): + def __init__(self, video: VideoClip, *args, **kwargs): self.video: VideoClip = video self.fps = self.video.fps self.duration = self.video.duration @staticmethod def _create_watermark(text, fontsize, opacity=0.5): - txt_clip = TextClip(text, fontsize=fontsize, color='black').set_opacity(opacity) - return txt_clip + path = "./assets/temp/png/watermark.png" + width = int(fontsize * len(text)) + height = int(fontsize * len(text) / 2) - def add_watermark(self, text, opacity=0.5, position: Tuple = (0.95, 0.95), fontsize=15): - txt_clip = self._create_watermark(text, opacity=opacity, fontsize=fontsize) - txt_clip = txt_clip.set_pos(position).set_duration(10) + white = (255, 255, 255) + transparent = (0, 0, 0, 0) - # Overlay the text clip on the first video clip - self.video = CompositeVideoClip([self.video, txt_clip]) + font = ImageFont.load_default() + wm = Image.new("RGBA", (width, height), transparent) + im = Image.new("RGBA", (width, height), transparent) # Change this line too. + + draw = ImageDraw.Draw(wm) + w, h = draw.textsize(text, font) + draw.text(((width - w) / 2, (height - h) / 2), text, white, font) + en = ImageEnhance.Brightness(wm) # todo allow it to use the fontsize + mask = en.enhance(1 - opacity) + im.paste(wm, (25, 25), mask) + im.save(path) + return ImageClip(path) + + def add_watermark(self, text, opacity=0.5, duration: int | float = 5, position: Tuple = (1, 100), fontsize=15): + img_clip = self._create_watermark(text, opacity=opacity, fontsize=fontsize) + img_clip = img_clip.set_opacity(opacity).set_duration(duration) + img_clip = img_clip.set_position(("center","bottom")) # set position doesn't work for some reason # todo fix + + # Overlay the img clip on the first video clip + self.video = CompositeVideoClip([self.video, img_clip]) return self.video