diff --git a/main.py b/main.py index 6011c5e..6f35dde 100644 --- a/main.py +++ b/main.py @@ -14,17 +14,16 @@ import os, time console = Console() """TODO - Refactor all .py files - - Done: + - Add function typing: - main - final_video - console - - Not done - background - screenshot_downloader - voices - - Need docs - setup (ADD DOCS) - subreddit (ADD DOCS) + - Need docs - loader (ADD DOCS) - Write tests in tests/ diff --git a/reddit/subreddit.py b/reddit/subreddit.py index 6a3275d..99e4b4c 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -67,7 +67,15 @@ def get_subreddit_threads(): return content -def pickThread(reddit): +def pickThread(reddit:praw.Reddit): + """Picks the reddit thread based on whether the user wants a random one, and then from the chosen subreddit + + Args: + reddit (Reddit): The praw.Reddit object + + Returns: + praw.models.reddit.submission.Submission : The chosen thread + """ # If the user specifies that he doesnt want a random thread, or if he doesn't insert the "RANDOM_THREAD" variable at all, ask the thread link if not os.getenv("RANDOM_THREAD") or os.getenv("RANDOM_THREAD") == "no": print_substep("Insert the full thread link:", style="bold green") @@ -91,9 +99,14 @@ def pickThread(reddit): threads = subreddit.hot(limit=25) submission = list(threads)[random.randrange(0, 25)] - return submission + return submission def configurePasskey(): + """Asks for 2FA code if needed, otherwise configures password + + Returns: + str: Password + """ if os.getenv("REDDIT_2FA", default="no").casefold() == "yes": print( "\nEnter your two-factor authentication code from your authenticator app.\n" diff --git a/setup.py b/setup.py index 1f2f75f..7906fd2 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,8 @@ console = Console() def setup_main(): + """Asks user if they want to run the setup script, then runs the setup script if the user is sure they want to run it. + """ setup_done = Path(".setup-done-before").is_file() if setup_done == True: @@ -35,23 +37,10 @@ def setup_main(): "### You're in the setup wizard. Ensure you're supposed to be here, then type yes to continue. If you're not sure, type no to quit." ) - ensureSetup() - console.log("Ensure you have the following ready to enter:") - console.log("[bold green]Reddit Client ID") - console.log("[bold green]Reddit Client Secret") - console.log("[bold green]Reddit Username") - console.log("[bold green]Reddit Password") - console.log("[bold green]Reddit 2FA (yes or no)") - console.log("[bold green]Opacity (range of 0-1, decimals are OK)") - console.log("[bold green]Subreddit (without r/ or /r/)") - console.log("[bold green]Theme (light or dark)") - time.sleep(0.5) - console.print( - "[green]If you don't have these, please follow the instructions in the README.md file to set them up.") - console.print( - "[green]If you do have these, type yes to continue. If you dont, go ahead and grab those quickly and come back.") + print_setup_criteria() + confirmUserHasCredentials = input( "Are you sure you have the credentials? > ").casefold() if confirmUserHasCredentials != "yes": @@ -69,9 +58,42 @@ def setup_main(): # Post-Setup: send message and try to run main.py again. os.system("python3 main.py") + +def print_setup_criteria(): + """Prints the following: + + Ensure you have the following ready to enter: setup.py:43 + Reddit Client ID setup.py:44 + Reddit Client Secret setup.py:45 + Reddit Username setup.py:46 + Reddit Password setup.py:47 + Reddit 2FA (yes or no) setup.py:48 + Opacity (range of 0-1, decimals are OK) setup.py:49 + Subreddit (without r/ or /r/) setup.py:50 + Theme (light or dark) setup.py:51 +If you don't have these, please follow the instructions in the README.md file to set them up. +If you do have these, type yes to continue. If you dont, go ahead and grab those quickly and come back. + """ + + + console.log("Ensure you have the following ready to enter:") + console.log("[bold green]Reddit Client ID") + console.log("[bold green]Reddit Client Secret") + console.log("[bold green]Reddit Username") + console.log("[bold green]Reddit Password") + console.log("[bold green]Reddit 2FA (yes or no)") + console.log("[bold green]Opacity (range of 0-1, decimals are OK)") + console.log("[bold green]Subreddit (without r/ or /r/)") + console.log("[bold green]Theme (light or dark)") + time.sleep(0.5) + console.print( + "[green]If you don't have these, please follow the instructions in the README.md file to set them up.") + console.print( + "[green]If you do have these, type yes to continue. If you dont, go ahead and grab those quickly and come back.") + def setup(): """ - Begin the setup process. + Takes in user input for .env fields """ console.log("Enter your credentials now.") @@ -116,6 +138,8 @@ def setup(): def ensureSetup(): + """Makes sure the user intends to proceed with the setup process, which overwrites the present .env file + """ # This Input is used to ensure the user is sure they want to continue. ensureSetupIsRequired = input( "Are you sure you want to continue? > ").casefold() diff --git a/utils/loader.py b/utils/loader.py index 58fd662..541f587 100644 --- a/utils/loader.py +++ b/utils/loader.py @@ -11,9 +11,10 @@ from time import sleep class Loader: - def __init__(self, desc="Loading...", end="Done!", timeout=0.1): + + def __init__(self, desc="Loading...", end="Done!", timeout=0.1): """ - A loader-like context manager + A loader-like context manager, used to generate the loading wheel. Args: desc (str, optional): The loader's description. Defaults to "Loading...". diff --git a/video_creation/screenshot_downloader.py b/video_creation/screenshot_downloader.py index d3d32ef..b04af1d 100644 --- a/video_creation/screenshot_downloader.py +++ b/video_creation/screenshot_downloader.py @@ -17,6 +17,7 @@ def download_screenshots_of_reddit_posts(reddit_object, screenshot_num, theme): # ! Make sure the reddit screenshots folder exists Path("assets/png").mkdir(parents=True, exist_ok=True) + with sync_playwright() as p: print_substep("Launching Headless Browser...") @@ -42,6 +43,7 @@ def download_screenshots_of_reddit_posts(reddit_object, screenshot_num, theme): path="assets/png/title.png" ) + # Get comment screenshots for idx, comment in track( enumerate(reddit_object["comments"]), "Downloading screenshots..." ): diff --git a/video_creation/voices.py b/video_creation/voices.py index f0ec298..a555717 100644 --- a/video_creation/voices.py +++ b/video_creation/voices.py @@ -13,7 +13,7 @@ def save_text_to_mp3(reddit_obj): Returns: tuple[int,int]: First index is the video length in seconds, I don't know what the second thing is - """ + """ print_step("Saving Text to MP3 files...") length = 0 @@ -21,31 +21,44 @@ def save_text_to_mp3(reddit_obj): # Create a folder for the mp3 files. Path("assets/mp3").mkdir(parents=True, exist_ok=True) - # Generate title audio - tts = gTTS(text=reddit_obj["thread_title"], lang="en", slow=False) - tts.save(f"assets/mp3/title.mp3") - length += MP3(f"assets/mp3/title.mp3").info.length + # Generate title audio and add to length + length += save_audio( + reddit_obj["thread_title"], f"assets/mp3/title.mp3", lang="en", slow=False) try: Path(f"assets/mp3/posttext.mp3").unlink() except OSError as e: pass - # Generates the thread post audio + # Generates the thread post audio if reddit_obj["thread_post"] != "": - tts = gTTS(text=reddit_obj["thread_post"], lang="en", slow=False) - tts.save(f"assets/mp3/posttext.mp3") - length += MP3(f"assets/mp3/posttext.mp3").info.length + length += save_audio( + reddit_obj["thread_post"], f"assets/mp3/posttext.mp3", lang="en", slow=False) # Generates each comment's audio for idx, comment in track(enumerate(reddit_obj["comments"]), "Saving..."): # ! Stop creating mp3 files if the length is greater than 50 seconds. This can be longer, but this is just a good starting point if length > 50: break - tts = gTTS(text=comment["comment_body"], lang="en", slow=False) - tts.save(f"assets/mp3/{idx}.mp3") - length += MP3(f"assets/mp3/{idx}.mp3").info.length + length += save_audio( + comment["comment_body"], f"assets/mp3/{idx}.mp3", lang="en", slow=False) print_substep("Saved Text to MP3 files successfully.", style="bold green") # ! Return the index so we know how many screenshots of comments we need to make. return length, idx + + +def save_audio(text, filepath, **gtts_kwargs): + """Generates and saves audio + + Args: + text (str): Text to be saved as an MP3 + filepath (str): Path to save the file to + + Returns: + int: Length of the clip generated, in seconds + """ + + tts = gTTS(text, **gtts_kwargs) + tts.save(filepath) + return MP3(filepath).info.length