From 1a4edfafca88a708f5e6e431c4e4ffc7d02b7683 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 12 Jul 2022 12:41:42 -0400 Subject: [PATCH 01/24] 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 8524051..9d40825 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 d9d62e252c2f2eef46963db5eb1437ddca1cd0f2 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 12 Jul 2022 13:11:33 -0400 Subject: [PATCH 02/24] 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 b19b0fd91b1a6f1c4a7023c02b4e981691244a06 Mon Sep 17 00:00:00 2001 From: RiveN000 <61630074+RiveN000@users.noreply.github.com> Date: Thu, 14 Jul 2022 00:04:32 +0200 Subject: [PATCH 03/24] Added two new background videos Added two cool copyright-free background videos often used in shorts. --- .config.template.toml | 2 +- video_creation/background.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) 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/video_creation/background.py b/video_creation/background.py index be0f46c..6054592 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -44,6 +44,18 @@ background_options = { "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), + ), } From d5db0ce0cfeca27056ddf998c46fb0c08597ea4f Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 18:13:57 -0400 Subject: [PATCH 04/24] 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 9d40825..a6d5d2f 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 9b01aa9f271f176999e5d5b989052660530db440 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 18:15:29 -0400 Subject: [PATCH 05/24] 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 a210011db7b1fd63741666d128fa64dcb76a0ba4 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 13 Jul 2022 21:55:32 -0400 Subject: [PATCH 06/24] 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 1e93121aede538f4807ab73737a884260e388211 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 12 Jul 2022 12:41:42 -0400 Subject: [PATCH 07/24] 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 08/24] 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 09/24] 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 10/24] 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 11/24] 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 12/24] 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 13/24] 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 From cbfdfc3ce762d6a5546e57c010a7861bbf92b6cd Mon Sep 17 00:00:00 2001 From: final Date: Thu, 14 Jul 2022 15:00:39 -0500 Subject: [PATCH 14/24] Fixed video being too long error. --- TTS/engine_wrapper.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/TTS/engine_wrapper.py b/TTS/engine_wrapper.py index c5ed714..c5cc86c 100644 --- a/TTS/engine_wrapper.py +++ b/TTS/engine_wrapper.py @@ -36,12 +36,14 @@ class TTSEngine: reddit_object: dict, path: str = "assets/temp/mp3", max_length: int = DEFUALT_MAX_LENGTH, + last_clip_length: int = 0, ): self.tts_module = tts_module() self.reddit_object = reddit_object self.path = path self.max_length = max_length self.length = 0 + self.last_clip_length = last_clip_length def run(self) -> Tuple[int, int]: @@ -63,9 +65,13 @@ class TTSEngine: self.call_tts("posttext", self.reddit_object["thread_post"]) idx = None - for idx, comment in track(enumerate(self.reddit_object["comments"]), "Saving..."): + for idx, comment in track( + enumerate(self.reddit_object["comments"]), "Saving..." + ): # ! Stop creating mp3 files if the length is greater than max length. if self.length > self.max_length: + self.length -= self.last_clip_length + idx -= 1 break if ( len(comment["comment_body"]) > self.tts_module.max_chars @@ -93,7 +99,9 @@ class TTSEngine: continue self.call_tts(f"{idx}-{idy - offset}.part", text_cut) - split_files.append(AudioFileClip(f"{self.path}/{idx}-{idy - offset}.part.mp3")) + split_files.append( + AudioFileClip(f"{self.path}/{idx}-{idy - offset}.part.mp3") + ) CompositeAudioClip([concatenate_audioclips(split_files)]).write_audiofile( f"{self.path}/{idx}.mp3", fps=44100, verbose=False, logger=None @@ -110,13 +118,17 @@ class TTSEngine: # Path(f"{self.path}/{idx}-{i}.part.mp3").unlink() def call_tts(self, filename: str, text: str): - self.tts_module.run(text=process_text(text), filepath=f"{self.path}/{filename}.mp3") + self.tts_module.run( + text=process_text(text), filepath=f"{self.path}/{filename}.mp3" + ) # try: # self.length += MP3(f"{self.path}/{filename}.mp3").info.length # except (MutagenError, HeaderNotFoundError): # self.length += sox.file_info.duration(f"{self.path}/{filename}.mp3") try: clip = AudioFileClip(f"{self.path}/{filename}.mp3") + if clip.duration + self.length < self.max_length: + self.last_clip_length = clip.duration self.length += clip.duration clip.close() except: From 7ef9bb2747ce592a01416a219ea55e0d75d02acd Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 14 Jul 2022 18:49:47 -0400 Subject: [PATCH 15/24] sugarcoated README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a9e205..0530b2b 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ https://user-images.githubusercontent.com/66544866/173453972-6526e4e6-c6ef-41c5- ## Contributing & Ways to improve 📈 -In its current state, this bot does exactly what it needs to do. However, lots of improvements can be made. +In its current state, this bot does exactly what it needs to do. However, improvements can always be made! I have tried to simplify the code so anyone can read it and start contributing at any skill level. Don't be shy :) contribute! From 839eb6fc2ffc08149145fdc800fbd0f87fa5128d Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 14 Jul 2022 19:36:35 -0400 Subject: [PATCH 16/24] added a potential bypass in case of absolute mad lads --- utils/subreddit.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/utils/subreddit.py b/utils/subreddit.py index 4eb0108..5638f1e 100644 --- a/utils/subreddit.py +++ b/utils/subreddit.py @@ -5,7 +5,7 @@ from utils import settings from utils.console import print_substep -def get_subreddit_undone(submissions: list, subreddit): +def get_subreddit_undone(submissions: list, subreddit, times_checked=0): """_summary_ Args: @@ -41,9 +41,13 @@ def get_subreddit_undone(submissions: list, subreddit): continue return submission print("all submissions have been done going by top submission order") + VALID_TIME_FILTERS = ["day", "hour", "month", "week", "year", 'all'] # set doesn't have __getitem__ + index = times_checked + 1 + if index == len(VALID_TIME_FILTERS): + print("all time filters have been checked you absolute madlad ") + return get_subreddit_undone( - subreddit.top(time_filter="hour"), subreddit - ) # all the videos in hot have already been done + subreddit.top(time_filter=VALID_TIME_FILTERS[index], limit=(50 if int(index) == 0 else index+1 * 50)), subreddit, times_checked=index) # all the videos in hot have already been done def already_done(done_videos: list, submission) -> bool: From bc215f8b3218a7ef1025f5c5dd1ad17c21307ec8 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 14 Jul 2022 22:35:41 -0400 Subject: [PATCH 17/24] Stable implementation of the watermark NOT DESIGNED FOR PRODUCTION USE --- TTS/engine_wrapper.py | 2 +- main.py | 27 ++++++++++++++----- .../.config.template.toml | 0 utils/settings.py | 2 +- utils/video.py | 10 ++++--- 5 files changed, 30 insertions(+), 11 deletions(-) rename .config.template.toml => utils/.config.template.toml (100%) diff --git a/TTS/engine_wrapper.py b/TTS/engine_wrapper.py index 93da092..e22c96b 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 = 10 # video length variable +DEFAULT_MAX_LENGTH: int = 5 # video length variable todo change class TTSEngine: diff --git a/main.py b/main.py index 653703c..adc478d 100755 --- a/main.py +++ b/main.py @@ -2,6 +2,9 @@ import math from subprocess import Popen from os import name + +from prawcore import ResponseException + from reddit.subreddit import get_subreddit_threads from utils.cleanup import cleanup from utils.console import print_markdown, print_step @@ -51,14 +54,20 @@ def main(POST_ID=None): def run_many(times): for x in range(1, times + 1): print_step( - f'on the {x}{("th", "st", "nd", "rd", "th", "th", "th", "th","th", "th")[x%10]} iteration of {times}' + f'on the {x}{("th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th")[x % 10]} iteration of {times}' ) # correct 1st 2nd 3rd 4th 5th.... main() Popen("cls" if name == "nt" else "clear", shell=True).wait() +def shutdown(): + print_markdown("## Clearing temp files") + cleanup() + exit() + + if __name__ == "__main__": - config = settings.check_toml(".config.template.toml", "config.toml") + config = settings.check_toml("utils/.config.template.toml", "config.toml") config is False and exit() try: if config["settings"]["times_to_run"]: @@ -68,13 +77,19 @@ if __name__ == "__main__": for index, post_id in enumerate(config["reddit"]["thread"]["post_id"].split("+")): index += 1 print_step( - f'on the {index}{("st" if index%10 == 1 else ("nd" if index%10 == 2 else ("rd" if index%10 == 3 else "th")))} post of {len(config["reddit"]["thread"]["post_id"].split("+"))}' + f'on the {index}{("st" if index % 10 == 1 else ("nd" if index % 10 == 2 else ("rd" if index % 10 == 3 else "th")))} post of {len(config["reddit"]["thread"]["post_id"].split("+"))}' ) main(post_id) Popen("cls" if name == "nt" else "clear", shell=True).wait() else: main() except KeyboardInterrupt: - print_markdown("## Clearing temp files") - cleanup() - exit() + shutdown() + except ResponseException: + # error for invalid credentials + print_markdown("## Invalid credentials") + print_markdown("Please check your credentials in the config.toml file") + + shutdown() + + # todo error diff --git a/.config.template.toml b/utils/.config.template.toml similarity index 100% rename from .config.template.toml rename to utils/.config.template.toml diff --git a/utils/settings.py b/utils/settings.py index a36f63e..a9d7726 100755 --- a/utils/settings.py +++ b/utils/settings.py @@ -167,4 +167,4 @@ If you see any prompts, that means that you have unset/incorrectly set variables if __name__ == "__main__": - check_toml(".config.template.toml", "config.toml") + check_toml("utils/.config.template.toml", "config.toml") diff --git a/utils/video.py b/utils/video.py index 61dc41c..5c89e3b 100644 --- a/utils/video.py +++ b/utils/video.py @@ -18,7 +18,6 @@ class Video: path = "./assets/temp/png/watermark.png" width = int(fontsize * len(text)) height = int(fontsize * len(text) / 2) - white = (255, 255, 255) transparent = (0, 0, 0, 0) @@ -35,10 +34,15 @@ class Video: im.save(path) return ImageClip(path) - def add_watermark(self, text, opacity=0.5, duration: int | float = 5, position: Tuple = (1, 100), fontsize=15): + def add_watermark(self, text, opacity=0.5, duration: int | float = 5, position: Tuple = (0.7, 0.9), fontsize=15): + print(len(text)) + compensation = round((position[0] / ((len(text) * (fontsize / 5) / 1.5) / 100 + position[0] * position[0])), ndigits=2) + position = (compensation, position[1]) + print(f'{compensation=}') + print(f'{position=}') 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 + img_clip = img_clip.set_position(position, relative=True) # set position doesn't work for some reason # fixme # Overlay the img clip on the first video clip self.video = CompositeVideoClip([self.video, img_clip]) From d5d8cb17219272c62a42714675a2c27b386d267f Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 14 Jul 2022 22:42:04 -0400 Subject: [PATCH 18/24] fix: typo --- video_creation/background.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video_creation/background.py b/video_creation/background.py index 19ded06..7a577e6 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -58,7 +58,7 @@ def download_background(background_config: Tuple[str, str, str, Any]): YouTube(uri, on_progress_callback=on_progress).streams.filter(res="1080p").first().download( "assets/backgrounds", filename=f"{credit}-{filename}" ) - print_substep("Background videos downloaded successfully! 🎉", style="bold green") + print_substep("Background video downloaded successfully! 🎉", style="bold green") def chop_background_video(background_config: Tuple[str, str, str, Any], video_length: int): From 420bac9a5a16d7d5ea22e4f24dfd5a8dabf1eeef Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 14 Jul 2022 22:44:13 -0400 Subject: [PATCH 19/24] fix: typo reverted temp change --- TTS/engine_wrapper.py | 2 +- utils/video.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/TTS/engine_wrapper.py b/TTS/engine_wrapper.py index e22c96b..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 -DEFAULT_MAX_LENGTH: int = 5 # video length variable todo change +DEFAULT_MAX_LENGTH: int = 50 # video length variable class TTSEngine: diff --git a/utils/video.py b/utils/video.py index 5c89e3b..03ed88c 100644 --- a/utils/video.py +++ b/utils/video.py @@ -35,14 +35,13 @@ class Video: return ImageClip(path) def add_watermark(self, text, opacity=0.5, duration: int | float = 5, position: Tuple = (0.7, 0.9), fontsize=15): - print(len(text)) compensation = round((position[0] / ((len(text) * (fontsize / 5) / 1.5) / 100 + position[0] * position[0])), ndigits=2) position = (compensation, position[1]) - print(f'{compensation=}') - print(f'{position=}') + #print(f'{compensation=}') + #print(f'{position=}') 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(position, relative=True) # set position doesn't work for some reason # fixme + img_clip = img_clip.set_position(position, relative=True) # todo get dara from utils/CONSTANTS.py and adapt position accordingly # Overlay the img clip on the first video clip self.video = CompositeVideoClip([self.video, img_clip]) From 4abf80317039b11be240e7aa0c91b01c1c9ed42b Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 14 Jul 2022 22:45:21 -0400 Subject: [PATCH 20/24] reformatted code --- utils/CONSTANTS.py | 1 - utils/subreddit.py | 16 +++++++++-- utils/video.py | 17 ++++++++---- video_creation/background.py | 1 + video_creation/final_video.py | 1 + video_creation/screenshot_downloader.py | 36 +++++++++++++++++-------- 6 files changed, 53 insertions(+), 19 deletions(-) diff --git a/utils/CONSTANTS.py b/utils/CONSTANTS.py index 76d2ee4..e46ebbc 100644 --- a/utils/CONSTANTS.py +++ b/utils/CONSTANTS.py @@ -1,4 +1,3 @@ - # Supported Background. Can add/remove background video here.... # - : key -> used as keyword for TOML file. value -> background configuration # Format (value): diff --git a/utils/subreddit.py b/utils/subreddit.py index 5638f1e..c386868 100644 --- a/utils/subreddit.py +++ b/utils/subreddit.py @@ -41,13 +41,25 @@ def get_subreddit_undone(submissions: list, subreddit, times_checked=0): continue return submission print("all submissions have been done going by top submission order") - VALID_TIME_FILTERS = ["day", "hour", "month", "week", "year", 'all'] # set doesn't have __getitem__ + VALID_TIME_FILTERS = [ + "day", + "hour", + "month", + "week", + "year", + "all", + ] # set doesn't have __getitem__ index = times_checked + 1 if index == len(VALID_TIME_FILTERS): print("all time filters have been checked you absolute madlad ") return get_subreddit_undone( - subreddit.top(time_filter=VALID_TIME_FILTERS[index], limit=(50 if int(index) == 0 else index+1 * 50)), subreddit, times_checked=index) # all the videos in hot have already been done + subreddit.top( + time_filter=VALID_TIME_FILTERS[index], limit=(50 if int(index) == 0 else index + 1 * 50) + ), + subreddit, + times_checked=index, + ) # all the videos in hot have already been done def already_done(done_videos: list, submission) -> bool: diff --git a/utils/video.py b/utils/video.py index 03ed88c..63dc170 100644 --- a/utils/video.py +++ b/utils/video.py @@ -34,14 +34,21 @@ class Video: im.save(path) return ImageClip(path) - def add_watermark(self, text, opacity=0.5, duration: int | float = 5, position: Tuple = (0.7, 0.9), fontsize=15): - compensation = round((position[0] / ((len(text) * (fontsize / 5) / 1.5) / 100 + position[0] * position[0])), ndigits=2) + def add_watermark( + self, text, opacity=0.5, duration: int | float = 5, position: Tuple = (0.7, 0.9), fontsize=15 + ): + compensation = round( + (position[0] / ((len(text) * (fontsize / 5) / 1.5) / 100 + position[0] * position[0])), + ndigits=2, + ) position = (compensation, position[1]) - #print(f'{compensation=}') - #print(f'{position=}') + # print(f'{compensation=}') + # print(f'{position=}') 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(position, relative=True) # todo get dara from utils/CONSTANTS.py and adapt position accordingly + img_clip = img_clip.set_position( + position, relative=True + ) # todo get dara from utils/CONSTANTS.py and adapt position accordingly # Overlay the img clip on the first video clip self.video = CompositeVideoClip([self.video, img_clip]) diff --git a/video_creation/background.py b/video_creation/background.py index 7a577e6..6e656fa 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -13,6 +13,7 @@ from utils import settings from utils.CONSTANTS import background_options from utils.console import print_step, print_substep + 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. diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 3157296..8d12afe 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -35,6 +35,7 @@ def name_normalize(name: str) -> str: 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 diff --git a/video_creation/screenshot_downloader.py b/video_creation/screenshot_downloader.py index 8010862..1f28c74 100644 --- a/video_creation/screenshot_downloader.py +++ b/video_creation/screenshot_downloader.py @@ -51,27 +51,36 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in page.locator('[data-testid="content-gate"] button').click() 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 + 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 @@ -84,16 +93,21 @@ 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"]], ) + [comment_tl, comment["comment_id"]], + ) try: - page.locator(f"#t1_{comment['comment_id']}").screenshot(path=f"assets/temp/png/comment_{idx}.png") + 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...') + print("TimeoutError: Skipping screenshot...") continue print_substep("Screenshots downloaded Successfully.", style="bold green") From 45c840158933ea8e6fb23b47641256eb3b0565b2 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 14 Jul 2022 22:57:26 -0400 Subject: [PATCH 21/24] fix: typo left in causing name error --- TTS/engine_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TTS/engine_wrapper.py b/TTS/engine_wrapper.py index bad4495..267f47a 100644 --- a/TTS/engine_wrapper.py +++ b/TTS/engine_wrapper.py @@ -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, last_clip_length: int = 0, ): self.tts_module = tts_module() From f0e1bdc48a209a712b387c0b8dfef964fdebf663 Mon Sep 17 00:00:00 2001 From: RiveN000 <61630074+RiveN000@users.noreply.github.com> Date: Fri, 15 Jul 2022 12:59:21 +0200 Subject: [PATCH 22/24] Fix: Hide the "Click to see NSFW" button Fixed this issue by making Playwright wait for page to fully load before clicking the button. --- video_creation/screenshot_downloader.py | 1 + 1 file changed, 1 insertion(+) diff --git a/video_creation/screenshot_downloader.py b/video_creation/screenshot_downloader.py index 1f28c74..7898e8d 100644 --- a/video_creation/screenshot_downloader.py +++ b/video_creation/screenshot_downloader.py @@ -49,6 +49,7 @@ 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.wait_for_load_state() # Wait for page to fully load if page.locator('[data-click-id="text"] button').is_visible(): page.locator( From 5920f0d77304e7bde3d325d16c75225390ede4fb Mon Sep 17 00:00:00 2001 From: RocketNinja15 <50027436+RocketNinja15@users.noreply.github.com> Date: Fri, 15 Jul 2022 10:29:36 -0700 Subject: [PATCH 23/24] Documentation for Reddit Script Instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a9e205..db91958 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ On MacOS and Linux (debian, arch, fedora and centos, and based on those), you ca This can also be used to update the installation 4. Run `python main.py` -5. Visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps), and set up an app that is a "script". +5. Visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps), and set up an app that is a "script". Paste any URL in redirect URL. Ex:localhost:8080 6. The bot will ask you to fill in your details to connect to the Reddit API, and configure the bot to your liking 7. Enjoy 😎 8. If you need to reconfigure the bot, simply open the `config.toml` file and delete the lines that need to be changed. On the next run of the bot, it will help you reconfigure those options. From 18e5727859cac0a6c06fe5b3ba318f497ba4db84 Mon Sep 17 00:00:00 2001 From: RocketNinja15 <50027436+RocketNinja15@users.noreply.github.com> Date: Sat, 16 Jul 2022 01:45:11 -0700 Subject: [PATCH 24/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db91958..f819920 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ On MacOS and Linux (debian, arch, fedora and centos, and based on those), you ca This can also be used to update the installation 4. Run `python main.py` -5. Visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps), and set up an app that is a "script". Paste any URL in redirect URL. Ex:localhost:8080 +5. Visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps), and set up an app that is a "script". Paste any URL in redirect URL. Ex:google.com 6. The bot will ask you to fill in your details to connect to the Reddit API, and configure the bot to your liking 7. Enjoy 😎 8. If you need to reconfigure the bot, simply open the `config.toml` file and delete the lines that need to be changed. On the next run of the bot, it will help you reconfigure those options.