diff --git a/main.py b/main.py index 5f01e5f..1666f17 100755 --- a/main.py +++ b/main.py @@ -37,8 +37,6 @@ def main(): load_dotenv() cleanup() - - reddit_object = get_subreddit_threads() length, number_of_comments = save_text_to_mp3(reddit_object) download_screenshots_of_reddit_posts(reddit_object, number_of_comments) diff --git a/reddit/subreddit.py b/reddit/subreddit.py index fbfc285..98bf8a1 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -105,13 +105,13 @@ def get_subreddit_threads(): continue # # see https://github.com/JasonLovesDoggo/RedditVideoMakerBot/issues/78 if not top_level_comment.stickied: if len(top_level_comment.body) <= int(try_env("MAX_COMMENT_LENGTH", 500)): - if not top_level_comment.author == None: - content["comments"].append( - { - "comment_body": top_level_comment.body, - "comment_url": top_level_comment.permalink, - "comment_id": top_level_comment.id, - } - ) + if not top_level_comment.author == None: + content["comments"].append( + { + "comment_body": top_level_comment.body, + "comment_url": top_level_comment.permalink, + "comment_id": top_level_comment.id, + } + ) print_substep("Received subreddit threads Successfully.", style="bold green") return content diff --git a/utils/checker.py b/utils/checker.py index 668b40f..9388029 100755 --- a/utils/checker.py +++ b/utils/checker.py @@ -15,7 +15,7 @@ def check_env() -> bool: Returns: bool: Whether or not everything was put in properly - """ + """ if not os.path.exists(".env.template"): console.print("[red]Couldn't find .env.template. Unable to check variables.") return True @@ -35,7 +35,11 @@ def check_env() -> bool: req_envs = [] var_optional = False for line in template.readlines(): - if line.startswith("#") is not True and "=" in line and var_optional is not True: + if ( + line.startswith("#") is not True + and "=" in line + and var_optional is not True + ): req_envs.append(line.split("=")[0]) if "#" in line: examples[line.split("=")[0]] = "#".join(line.split("#")[1:]).strip() @@ -56,7 +60,9 @@ def check_env() -> bool: ) var_optional = False elif line.startswith("#MATCH_TYPE "): - types[req_envs[-1]] = eval(line.removeprefix("#MATCH_TYPE ")[:-1].split()[0]) + types[req_envs[-1]] = eval( + line.removeprefix("#MATCH_TYPE ")[:-1].split()[0] + ) var_optional = False elif line.startswith("#EXPLANATION "): explanations[req_envs[-1]] = line.removeprefix("#EXPLANATION ")[:-1] @@ -82,9 +88,9 @@ def check_env() -> bool: try: temp = types[env](value) if env in bounds.keys(): - (bounds[env][0] <= temp or incorrect.add(env)) and len(bounds[env]) > 1 and ( - bounds[env][1] >= temp or incorrect.add(env) - ) + (bounds[env][0] <= temp or incorrect.add(env)) and len( + bounds[env] + ) > 1 and (bounds[env][1] >= temp or incorrect.add(env)) except ValueError: incorrect.add(env) @@ -107,11 +113,17 @@ def check_env() -> bool: for env in missing: table.add_row( env, - explanations[env] if env in explanations.keys() else "No explanation given", + explanations[env] + if env in explanations.keys() + else "No explanation given", examples[env] if env in examples.keys() else "", - str(bounds[env][0]) if env in bounds.keys() and bounds[env][1] is not None else "", + str(bounds[env][0]) + if env in bounds.keys() and bounds[env][1] is not None + else "", str(bounds[env][1]) - if env in bounds.keys() and len(bounds[env]) > 1 and bounds[env][1] is not None + if env in bounds.keys() + and len(bounds[env]) > 1 + and bounds[env][1] is not None else "", ) console.print(table) @@ -128,7 +140,9 @@ def check_env() -> bool: title_style="#C0CAF5 bold", ) table.add_column("Variable", justify="left", style="#7AA2F7 bold", no_wrap=True) - table.add_column("Current value", justify="left", style="#F7768E", no_wrap=False) + table.add_column( + "Current value", justify="left", style="#F7768E", no_wrap=False + ) table.add_column("Explanation", justify="left", style="#BB9AF7", no_wrap=False) table.add_column("Example", justify="center", style="#F7768E", no_wrap=True) table.add_column("Min", justify="right", style="#F7768E", no_wrap=True) @@ -137,10 +151,14 @@ def check_env() -> bool: table.add_row( env, os.getenv(env), - explanations[env] if env in explanations.keys() else "No explanation given", + explanations[env] + if env in explanations.keys() + else "No explanation given", str(types[env].__name__) if env in types.keys() else "str", str(bounds[env][0]) if env in bounds.keys() else "None", - str(bounds[env][1]) if env in bounds.keys() and len(bounds[env]) > 1 else "None", + str(bounds[env][1]) + if env in bounds.keys() and len(bounds[env]) > 1 + else "None", ) missing.add(env) console.print(table) @@ -177,11 +195,17 @@ def check_env() -> bool: if env in explanations.keys() else "Incorrect input. Try again.", bounds[env][0] if env in bounds.keys() else None, - bounds[env][1] if env in bounds.keys() and len(bounds[env]) > 1 else None, - oob_errors[env] if env in oob_errors.keys() else "Input too long/short.", + bounds[env][1] + if env in bounds.keys() and len(bounds[env]) > 1 + else None, + oob_errors[env] + if env in oob_errors.keys() + else "Input too long/short.", extra_info="[#C0CAF5 bold]⮶ " + ( - explanations[env] if env in explanations.keys() else "No info available" + explanations[env] + if env in explanations.keys() + else "No info available" ), ) ) diff --git a/utils/cleanup.py b/utils/cleanup.py index 858cfe9..44629a9 100644 --- a/utils/cleanup.py +++ b/utils/cleanup.py @@ -7,10 +7,12 @@ def cleanup() -> int: Returns: int: How many files were deleted - """ + """ if exists("./assets/temp"): count = 0 - files = [f for f in os.listdir(".") if f.endswith(".mp4") and "temp" in f.lower()] + files = [ + f for f in os.listdir(".") if f.endswith(".mp4") and "temp" in f.lower() + ] count += len(files) for f in files: os.remove(f) diff --git a/utils/console.py b/utils/console.py index 5a041ec..2a9296c 100644 --- a/utils/console.py +++ b/utils/console.py @@ -64,10 +64,14 @@ def handle_input( except ValueError: console.print("[red]" + err_message) # Type conversion failed continue - if nmin is not None and len(user_input) < nmin: # Check if string is long enough + if ( + nmin is not None and len(user_input) < nmin + ): # Check if string is long enough console.print("[red]" + oob_error) continue - if nmax is not None and len(user_input) > nmax: # Check if string is not too long + if ( + nmax is not None and len(user_input) > nmax + ): # Check if string is not too long console.print("[red]" + oob_error) continue break diff --git a/utils/subreddit.py b/utils/subreddit.py index 3c5cb22..a40b6c3 100644 --- a/utils/subreddit.py +++ b/utils/subreddit.py @@ -9,11 +9,11 @@ def get_subreddit_undone(submissions: list, subreddit): Args: submissions (list): List of posts that are going to potentially be generated into a video - subreddit (praw.Reddit.SubredditHelper): Chosen subreddit + subreddit (praw.Reddit.SubredditHelper): Chosen subreddit Returns: Any: The submission that has not been done - """ + """ """ recursively checks if the top submission in the list was already done. """ @@ -36,8 +36,8 @@ def get_subreddit_undone(submissions: list, subreddit): ) # all of the videos in hot have already been done -def already_done(done_videos: list, submission)->bool: - """Checks to see if the given submission is in the list of videos +def already_done(done_videos: list, submission) -> bool: + """Checks to see if the given submission is in the list of videos Args: done_videos (list): Finished videos @@ -45,7 +45,7 @@ def already_done(done_videos: list, submission)->bool: Returns: Boolean: Whether the video was found in the list - """ + """ for video in done_videos: if video["id"] == str(submission): diff --git a/utils/videos.py b/utils/videos.py index e6510fe..8d6021f 100755 --- a/utils/videos.py +++ b/utils/videos.py @@ -5,8 +5,10 @@ from utils.console import print_step def check_done( - redditobj:dict[str], -)->dict[str]|None: # don't set this to be run anyplace that isn't subreddit.py bc of inspect stack + redditobj: dict[str], +) -> dict[ + str +] | None: # don't set this to be run anyplace that isn't subreddit.py bc of inspect stack """Checks if the chosen post has already been generated Args: diff --git a/video_creation/background.py b/video_creation/background.py index 347ac35..a99355c 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -10,7 +10,7 @@ from pytube import YouTube from utils.console import print_step, print_substep -def get_start_and_end_times(video_length:int, length_of_clip:int)->tuple[int,int]: +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 beckground of the video. Args: @@ -19,7 +19,7 @@ def get_start_and_end_times(video_length:int, length_of_clip:int)->tuple[int,int Returns: tuple[int,int]: Start and end time of the randomized interval - """ + """ random_time = randrange(180, int(length_of_clip) - int(video_length)) return random_time, random_time + video_length @@ -37,7 +37,7 @@ def download_background(): ] # note: make sure the file name doesn't include an - in it if not len(listdir("./assets/backgrounds")) >= len( - background_options + background_options ): # if there are any background videos not installed print_step( "We need to download the backgrounds videos. they are fairly large but it's only done once. 😎" @@ -56,12 +56,12 @@ def download_background(): ) -def chop_background_video(video_length:int): +def chop_background_video(video_length: int): """Generates the background footage to be used in the video and writes it to assets/temp/background.mp4 Args: video_length (int): Length of the clip where the background footage is to be taken out of - """ + """ print_step("Finding a spot in the backgrounds video to chop...✂️") choice = random.choice(listdir("assets/backgrounds")) environ["background_credit"] = choice.split("-")[0] diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 146fab8..c05006c 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -26,13 +26,13 @@ console = Console() W, H = 1080, 1920 -def make_final_video(number_of_clips:int, length:int): +def make_final_video(number_of_clips: int, length: int): """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 length (int): Length of the video - """ + """ print_step("Creating the final video 🎥") VideoFileClip.reW = lambda clip: clip.resize(width=W) VideoFileClip.reH = lambda clip: clip.resize(width=H) @@ -117,10 +117,8 @@ def make_final_video(number_of_clips:int, length:int): image_concat.audio = audio_composite final = CompositeVideoClip([background_clip, image_concat]) - filename = f"{get_video_title()}.mp4" - save_data(filename) if not exists("./results"): @@ -149,12 +147,13 @@ def make_final_video(number_of_clips:int, length:int): f"Reddit title: {os.getenv('VIDEO_TITLE')} \n Background Credit: {os.getenv('background_credit')}" ) -def save_data(filename:str): + +def save_data(filename: str): """Saves the videos that have already been generated to a JSON file in video_creation/data/videos.json Args: filename (str): The finished video title name - """ + """ with open("./video_creation/data/videos.json", "r+") as raw_vids: done_vids = json.load(raw_vids) if str(subreddit.submission.id) in [video["id"] for video in done_vids]: @@ -170,14 +169,15 @@ def save_data(filename:str): raw_vids.seek(0) json.dump(done_vids, raw_vids, ensure_ascii=False, indent=4) + def get_video_title() -> str: """Gets video title from env variable or gives it the name "final_video" Returns: str: Video title - """ + """ title = os.getenv("VIDEO_TITLE") or "final_video" if len(title) <= 35: return title else: - return title[0:30] + "..." \ No newline at end of file + return title[0:30] + "..." diff --git a/video_creation/screenshot_downloader.py b/video_creation/screenshot_downloader.py index 9317e87..f638abc 100644 --- a/video_creation/screenshot_downloader.py +++ b/video_creation/screenshot_downloader.py @@ -3,7 +3,7 @@ from os import getenv import os from pathlib import Path -from playwright.async_api import async_playwright # do not remove this line +from playwright.async_api import async_playwright # do not remove this line from playwright.sync_api import sync_playwright, ViewportSize from rich.progress import track @@ -18,14 +18,14 @@ console = Console() storymode = False -def download_screenshots_of_reddit_posts(reddit_object:dict[str], screenshot_num:int): +def download_screenshots_of_reddit_posts(reddit_object: dict[str], screenshot_num: int): """Downloads screenshots of reddit posts as seen on the web. Downloads to assets/temp/png Args: reddit_object (dict[str]): Reddit object received from reddit/subreddit.py screenshot_num (int): Number of screenshots to downlaod - """ - + """ + print_step("Downloading screenshots of reddit posts...") # ! Make sure the reddit screenshots folder exists @@ -60,10 +60,13 @@ def download_screenshots_of_reddit_posts(reddit_object:dict[str], screenshot_num if getenv("POSTLANG"): print_substep("Translating post...") - texts_in_tl = ts.google(reddit_object["thread_title"], to_language=os.getenv("POSTLANG")) + texts_in_tl = ts.google( + reddit_object["thread_title"], to_language=os.getenv("POSTLANG") + ) page.evaluate( - 'tl_content => document.querySelector(\'[data-test-id="post-content"] > div:nth-child(3) > div > div\').textContent = tl_content', texts_in_tl + "tl_content => document.querySelector('[data-test-id=\"post-content\"] > div:nth-child(3) > div > div').textContent = tl_content", + texts_in_tl, ) else: print_substep("Skipping translation...") @@ -92,9 +95,12 @@ def download_screenshots_of_reddit_posts(reddit_object:dict[str], screenshot_num # translate code if getenv("POSTLANG"): - comment_tl = ts.google(comment["comment_body"], to_language=os.getenv("POSTLANG")) + comment_tl = ts.google( + comment["comment_body"], to_language=os.getenv("POSTLANG") + ) 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']] + '([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( diff --git a/video_creation/voices.py b/video_creation/voices.py index f5ead42..cbe27f5 100644 --- a/video_creation/voices.py +++ b/video_creation/voices.py @@ -25,7 +25,7 @@ TTSProviders = { VIDEO_LENGTH: int = 40 # secs -def save_text_to_mp3(reddit_obj:dict[str])->tuple[int,int]: +def save_text_to_mp3(reddit_obj: dict[str]) -> tuple[int, int]: """Saves text to MP3 files. Goes through the reddit_obj and generates the title MP3 file and a certain number of comments until the total amount of time exceeds VIDEO_LENGTH seconds. Args: @@ -34,7 +34,7 @@ def save_text_to_mp3(reddit_obj:dict[str])->tuple[int,int]: Returns: tuple[int,int]: (total length of the audio, the number of comments audio was generated for) """ - + env = os.getenv("TTSCHOICE", "") if env.casefold() in map(lambda _: _.casefold(), TTSProviders): text_to_mp3 = TTSEngine(