Started refactoring

pull/507/head
HallowedDust5 3 years ago
parent 4af7383e08
commit 9ad18a9004

@ -1,7 +1,5 @@
# Main # Main
from utils.console import print_markdown from utils.console import print_markdown
from utils.console import print_step
from utils.console import print_substep
from rich.console import Console from rich.console import Console
import time import time
from reddit.subreddit import get_subreddit_threads from reddit.subreddit import get_subreddit_threads
@ -9,95 +7,113 @@ from video_creation.background import download_background, chop_background_video
from video_creation.voices import save_text_to_mp3 from video_creation.voices import save_text_to_mp3
from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts
from video_creation.final_video import make_final_video from video_creation.final_video import make_final_video
from utils.loader import Loader
from dotenv import load_dotenv from dotenv import load_dotenv
from pathlib import Path from pathlib import Path
console = Console()
from dotenv import load_dotenv from dotenv import load_dotenv
import os, time, shutil import os, time
configured = True
REQUIRED_VALUES = [
"REDDIT_CLIENT_ID",
"REDDIT_CLIENT_SECRET",
"REDDIT_USERNAME",
"REDDIT_PASSWORD",
"OPACITY",
]
print_markdown( """TODO
"### Thanks for using this tool! [Feel free to contribute to this project on GitHub!](https://lewismenelaws.com) If you have any questions, feel free to reach out to me on Twitter or submit a GitHub issue." - Refactor all .py files
) - Write tests in tests/
"""
Load .env file if exists. If it doesnt exist, print a warning and launch the setup wizard.
If there is a .env file, check if the required variables are set. If not, print a warning and launch the setup wizard.
""" """
client_id = os.getenv("REDDIT_CLIENT_ID")
client_secret = os.getenv("REDDIT_CLIENT_SECRET")
username = os.getenv("REDDIT_USERNAME")
password = os.getenv("REDDIT_PASSWORD")
reddit2fa = os.getenv("REDDIT_2FA")
load_dotenv()
console.log("[bold green]Checking environment variables...")
time.sleep(1)
if not Path(".env").is_file():
configured = False
console.log("[red] Your .env file is invalid, or was never created. Standby.")
# Checks to see if all values in .env are provided
# If they aren't, then asks to launch setup wizard
for val in REQUIRED_VALUES:
# print(os.getenv(val))
if val not in os.environ or not os.getenv(val):
console.log(f'[bold red]Missing Variable: "{val}"')
configured = False
console.log(
"[red]Looks like you need to set your Reddit credentials in the .env file. Please follow the instructions in the README.md file to set them up."
)
time.sleep(0.5)
console.log(
"[red]We can also launch the easy setup wizard. type yes to launch it, or no to quit the program."
)
while True: #Asks user whether they want to launch setup wizard until an understandable input is given
setup_ask = input("Launch setup wizard? > ")
if setup_ask.casefold() == "yes":
console.log("[bold green]Here goes nothing! Launching setup wizard...")
time.sleep(0.5)
os.system("python3 setup.py")
elif setup_ask.casefold() == "no": def main():
console.print("[red]Exiting...") if envConfigured():
time.sleep(0.5) generateVideo()
exit()
console.print("[red]I don't understand that.")
time.sleep(0.5)
try:
float(os.getenv("OPACITY"))
except:
console.log(
f"[red]Please ensure that OPACITY is set between 0 and 1 in your .env file"
)
configured = False
exit()
console.log("[bold green]Enviroment Variables are set! Continuing...")
if configured: def generateVideo():
# Video generation # Video generation
reddit_object = get_subreddit_threads() reddit_object = get_subreddit_threads()
length, number_of_comments = save_text_to_mp3(reddit_object) length, number_of_comments = save_text_to_mp3(reddit_object)
download_screenshots_of_reddit_posts( download_screenshots_of_reddit_posts(
reddit_object, number_of_comments, os.getenv("THEME", "light") reddit_object, number_of_comments, os.getenv("THEME", "light")
) )
download_background() download_background()
chop_background_video(length) chop_background_video(length)
final_video = make_final_video(number_of_comments) make_final_video(number_of_comments)
def envConfigured():
console = Console()
configured = True
REQUIRED_VALUES = [
"REDDIT_CLIENT_ID",
"REDDIT_CLIENT_SECRET",
"REDDIT_USERNAME",
"REDDIT_PASSWORD",
"OPACITY",
]
print_markdown(
"### Thanks for using this tool! [Feel free to contribute to this project on GitHub!](https://lewismenelaws.com) If you have any questions, feel free to reach out to me on Twitter or submit a GitHub issue."
)
"""
Load .env file if exists. If it doesnt exist, print a warning and launch the setup wizard.
If there is a .env file, check if the required variables are set. If not, print a warning and launch the setup wizard.
"""
client_id = os.getenv("REDDIT_CLIENT_ID")
client_secret = os.getenv("REDDIT_CLIENT_SECRET")
username = os.getenv("REDDIT_USERNAME")
password = os.getenv("REDDIT_PASSWORD")
reddit2fa = os.getenv("REDDIT_2FA")
load_dotenv()
console.log("[bold green]Checking environment variables...")
time.sleep(1)
if not Path(".env").is_file():
configured = False
console.log("[red] Your .env file is invalid, or was never created. Standby.")
# Checks to see if all values in .env are provided
# If they aren't, then asks to launch setup wizard
for val in REQUIRED_VALUES:
# print(os.getenv(val))
if val not in os.environ or not os.getenv(val):
console.log(f'[bold red]Missing Variable: "{val}"')
configured = False
console.log(
"[red]Looks like you need to set your Reddit credentials in the .env file. Please follow the instructions in the README.md file to set them up."
)
time.sleep(0.5)
console.log(
"[red]We can also launch the easy setup wizard. type yes to launch it, or no to quit the program."
)
while True: #Asks user whether they want to launch setup wizard until an understandable input is given
setup_ask = input("Launch setup wizard? > ")
if setup_ask.casefold() == "yes":
console.log("[bold green]Here goes nothing! Launching setup wizard...")
time.sleep(0.5)
os.system("python3 setup.py")
elif setup_ask.casefold() == "no":
console.print("[red]Exiting...")
time.sleep(0.5)
exit()
console.print("[red]I don't understand that.")
time.sleep(0.5)
try:
float(os.getenv("OPACITY"))
except:
console.log(
f"[red]Please ensure that OPACITY is set between 0 and 1 in your .env file"
)
configured = False
exit()
console.log("[bold green]Enviroment Variables are set! Continuing...")
return configured
if __name__ == '__main__':
main()

@ -7,23 +7,29 @@ import os, random, praw, re
def get_subreddit_threads(): def get_subreddit_threads():
global submission """Selects subreddit threads and returns them
"""
Returns a list of threads from the AskReddit subreddit. Returns:
dict[str]: Object of all the selected threads' data:
{
thread_post : str,
thread_title : str,
thread_post : str,
comments : list[dict],
}
`comments` is structured as follows:
{
comment_body : str,
comment_url : str,
comment_id : str,
}
""" """
global submission
load_dotenv() load_dotenv()
if os.getenv("REDDIT_2FA", default="no").casefold() == "yes": passkey = configurePasskey()
print(
"\nEnter your two-factor authentication code from your authenticator app.\n"
)
code = input("> ")
print()
pw = os.getenv("REDDIT_PASSWORD")
passkey = f"{pw}:{code}"
else:
passkey = os.getenv("REDDIT_PASSWORD")
content = {} content = {}
reddit = praw.Reddit( reddit = praw.Reddit(
@ -34,28 +40,7 @@ def get_subreddit_threads():
password=passkey, password=passkey,
) )
# 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 pickThread(reddit)
if not os.getenv("RANDOM_THREAD") or os.getenv("RANDOM_THREAD") == "no":
print_substep("Insert the full thread link:", style="bold green")
thread_link = input()
print_step(f"Getting the inserted thread...")
submission = reddit.submission(url=thread_link)
else:
# Otherwise, picks a random thread from the inserted subreddit
if os.getenv("SUBREDDIT"):
subreddit = reddit.subreddit(re.sub(r"r\/", "", os.getenv("SUBREDDIT")))
else:
# ! Prompt the user to enter a subreddit
try:
subreddit = reddit.subreddit(
re.sub(r"r\/", "",input("What subreddit would you like to pull from? "))
)
except ValueError:
subreddit = reddit.subreddit("askreddit")
print_substep("Subreddit not defined. Using AskReddit.")
threads = subreddit.hot(limit=25)
submission = list(threads)[random.randrange(0, 25)]
print_substep(f"Video will be: {submission.title} :thumbsup:") print_substep(f"Video will be: {submission.title} :thumbsup:")
console.log("Getting video comments...") console.log("Getting video comments...")
@ -77,6 +62,44 @@ def get_subreddit_threads():
except AttributeError as e: except AttributeError as e:
pass pass
print_substep("Received AskReddit threads successfully.", style="bold green") print_substep("Received AskReddit threads successfully.", style="bold green")
return content return content
def pickThread(reddit):
# 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")
thread_link = input()
print_step(f"Getting the inserted thread...")
submission = reddit.submission(url=thread_link)
else:
# Otherwise, picks a random thread from the inserted subreddit
if os.getenv("SUBREDDIT"):
subreddit = reddit.subreddit(re.sub(r"r\/", "", os.getenv("SUBREDDIT")))
else:
# ! Prompt the user to enter a subreddit
try:
subreddit = reddit.subreddit(
re.sub(r"r\/", "",input("What subreddit would you like to pull from? "))
)
except ValueError:
subreddit = reddit.subreddit("askreddit")
print_substep("Subreddit not defined. Using AskReddit.")
threads = subreddit.hot(limit=25)
submission = list(threads)[random.randrange(0, 25)]
def configurePasskey():
if os.getenv("REDDIT_2FA", default="no").casefold() == "yes":
print(
"\nEnter your two-factor authentication code from your authenticator app.\n"
)
code = input("> ")
print()
pw = os.getenv("REDDIT_PASSWORD")
passkey = f"{pw}:{code}"
else:
passkey = os.getenv("REDDIT_PASSWORD")
return passkey

@ -7,6 +7,8 @@ Setup Script for RedditVideoMakerBot
# Imports # Imports
import os import os
import time import time
from setuptools import setup
from utils.console import print_markdown from utils.console import print_markdown
from utils.console import print_step from utils.console import print_step
from utils.console import print_substep from utils.console import print_substep
@ -15,108 +17,129 @@ from utils.loader import Loader
from pathlib import Path from pathlib import Path
console = Console() console = Console()
setup_done = Path(".setup-done-before").is_file()
if setup_done == True: def main():
console.log("[red]Setup was already completed! Please make sure you have to run this script again. If you have to, please delete the file .setup-done-before") setup_done = Path(".setup-done-before").is_file()
exit()
if setup_done == True:
console.log("[red]Setup was already completed! Please make sure you have to run this script again. If you have to, please delete the file .setup-done-before")
exit()
# These lines ensure the user:
# - knows they are in setup mode
# - knows that they are about to erase any other setup files/data.
# These lines ensure the user: print_step("Setup Assistant")
# - knows they are in setup mode
# - knows that they are about to erase any other setup files/data.
print_step("Setup Assistant") print_markdown(
"### 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."
)
print_markdown(
"### 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."
)
# This Input is used to ensure the user is sure they want to continue. ensureSetup()
ensureSetupIsRequired = input("Are you sure you want to continue? > ").casefold()
if ensureSetupIsRequired != "yes": console.log("Ensure you have the following ready to enter:")
console.print("[red]Exiting...") 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) time.sleep(0.5)
exit() console.print(
else: "[green]If you don't have these, please follow the instructions in the README.md file to set them up.")
# Again, let them know they are about to erase all other setup data. console.print(
console.print("[bold red] This will overwrite your current settings. Are you sure you want to continue? [bold green]yes/no") "[green]If you do have these, type yes to continue. If you dont, go ahead and grab those quickly and come back.")
overwriteSettings = input("Are you sure you want to continue? > ").casefold() confirmUserHasCredentials = input(
if overwriteSettings != "yes": "Are you sure you have the credentials? > ").casefold()
console.print("[red]Abort mission! Exiting...") if confirmUserHasCredentials != "yes":
time.sleep(0.5) console.print("[red]I don't understand that.")
console.print("[red]Exiting...")
exit() exit()
else: else:
# Once they confirm, move on with the script.
console.print("[bold green]Alright! Let's get started!") console.print("[bold green]Alright! Let's get started!")
time.sleep(1) time.sleep(1)
console.log("Ensure you have the following ready to enter:") setup()
console.log("[bold green]Reddit Client ID")
console.log("[bold green]Reddit Client Secret") console.log("[bold green]Setup Complete! Returning...")
console.log("[bold green]Reddit Username")
console.log("[bold green]Reddit Password") # Post-Setup: send message and try to run main.py again.
console.log("[bold green]Reddit 2FA (yes or no)") os.system("python3 main.py")
console.log("[bold green]Opacity (range of 0-1, decimals are OK)")
console.log("[bold green]Subreddit (without r/ or /r/)") def setup():
console.log("[bold green]Theme (light or dark)") """
time.sleep(0.5) Begin the setup process.
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.")
confirmUserHasCredentials = input("Are you sure you have the credentials? > ").casefold() console.log("Enter your credentials now.")
if confirmUserHasCredentials != "yes": cliID = input("Client ID > ")
console.print("[red]I don't understand that.") cliSec = input("Client Secret > ")
console.print("[red]Exiting...") user = input("Username > ")
exit() passw = input("Password > ")
else: twofactor = input("2fa Enabled? (yes/no) > ")
console.print("[bold green]Alright! Let's get started!") opacity = input("Opacity? (range of 0-1) > ")
time.sleep(1) subreddit = input("Subreddit (without r/) > ")
theme = input("Theme? (light or dark) > ")
console.log("Attempting to save your credentials...")
loader = Loader("Saving Credentials...", "Done!").start()
# you can also put a while loop here, e.g. while VideoIsBeingMade == True: ...
time.sleep(0.5)
console.log("Removing old .env file...")
os.remove(".env")
time.sleep(0.5)
console.log("Creating new .env file...")
with open('.env', 'a') as f:
f.write(f'REDDIT_CLIENT_ID="{cliID}"\n')
time.sleep(0.5)
f.write(f'REDDIT_CLIENT_SECRET="{cliSec}"\n')
time.sleep(0.5)
f.write(f'REDDIT_USERNAME="{user}"\n')
time.sleep(0.5)
f.write(f'REDDIT_PASSWORD="{passw}"\n')
time.sleep(0.5)
f.write(f'REDDIT_2FA="{twofactor}"\n')
time.sleep(0.5)
f.write(f'THEME="{theme}"\n')
time.sleep(0.5)
f.write(f'SUBREDDIT="{subreddit}"\n')
time.sleep(0.5)
f.write(f'OPACITY="{opacity}"\n')
""" with open('.setup-done-before', 'a') as f:
f.write(
"This file blocks the setup assistant from running again. Delete this file to run setup again.")
Begin the setup process. loader.stop()
"""
console.log("Enter your credentials now.") def ensureSetup():
cliID = input("Client ID > ") # This Input is used to ensure the user is sure they want to continue.
cliSec = input("Client Secret > ") ensureSetupIsRequired = input(
user = input("Username > ") "Are you sure you want to continue? > ").casefold()
passw = input("Password > ") if ensureSetupIsRequired != "yes":
twofactor = input("2fa Enabled? (yes/no) > ") console.print("[red]Exiting...")
opacity = input("Opacity? (range of 0-1) > ") time.sleep(0.5)
subreddit = input("Subreddit (without r/) > ") exit()
theme = input("Theme? (light or dark) > ") else:
console.log("Attempting to save your credentials...") # Again, let them know they are about to erase all other setup data.
loader = Loader("Saving Credentials...", "Done!").start() console.print(
# you can also put a while loop here, e.g. while VideoIsBeingMade == True: ... "[bold red] This will overwrite your current settings. Are you sure you want to continue? [bold green]yes/no")
time.sleep(0.5) overwriteSettings = input(
console.log("Removing old .env file...") "Are you sure you want to continue? > ").casefold()
os.remove(".env") if overwriteSettings != "yes":
time.sleep(0.5) console.print("[red]Abort mission! Exiting...")
console.log("Creating new .env file...") time.sleep(0.5)
with open('.env', 'a') as f: exit()
f.write(f'REDDIT_CLIENT_ID="{cliID}"\n') else:
time.sleep(0.5) # Once they confirm, move on with the script.
f.write(f'REDDIT_CLIENT_SECRET="{cliSec}"\n') console.print("[bold green]Alright! Let's get started!")
time.sleep(0.5) time.sleep(1)
f.write(f'REDDIT_USERNAME="{user}"\n')
time.sleep(0.5)
f.write(f'REDDIT_PASSWORD="{passw}"\n')
time.sleep(0.5)
f.write(f'REDDIT_2FA="{twofactor}"\n')
time.sleep(0.5)
f.write(f'THEME="{theme}"\n')
time.sleep(0.5)
f.write(f'SUBREDDIT="{subreddit}"\n')
time.sleep(0.5)
f.write(f'OPACITY="{opacity}"\n')
with open('.setup-done-before', 'a') as f:
f.write("This file blocks the setup assistant from running again. Delete this file to run setup again.")
loader.stop()
console.log("[bold green]Setup Complete! Returning...")
# Post-Setup: send message and try to run main.py again. if __name__ == '__main__':
os.system("python3 main.py") main()

@ -19,7 +19,11 @@ W, H = 1080, 1920
def make_final_video(number_of_clips): def make_final_video(number_of_clips):
"""Generates and saves final video to assets/generated-videos
Args:
number_of_clips (int): The index of clips(comments) to go up to
"""
# Calls opacity from the .env # Calls opacity from the .env
load_dotenv() load_dotenv()
opacity = os.getenv('OPACITY') opacity = os.getenv('OPACITY')
@ -36,28 +40,11 @@ def make_final_video(number_of_clips):
.crop(x1=1166.6, y1=0, x2=2246.6, y2=1920) .crop(x1=1166.6, y1=0, x2=2246.6, y2=1920)
) )
# Gather all audio clips audio_clips, audio_composite = gatherAudioClips(number_of_clips)
audio_clips = []
for i in range(0, number_of_clips): image_clips = gatherImages(number_of_clips, opacity, audio_clips)
audio_clips.append(AudioFileClip(f"assets/mp3/{i}.mp3"))
audio_clips.insert(0, AudioFileClip(f"assets/mp3/title.mp3"))
try:
audio_clips.insert(1, AudioFileClip(f"assets/mp3/posttext.mp3"))
except:
OSError()
audio_concat = concatenate_audioclips(audio_clips)
audio_composite = CompositeAudioClip([audio_concat])
# Gather all images
image_clips = []
for i in range(0, number_of_clips):
image_clips.append(
ImageClip(f"assets/png/comment_{i}.png")
.set_duration(audio_clips[i + 1].duration)
.set_position("center")
.resize(width=W - 100)
.set_opacity(float(opacity)),
)
if Path(f"assets/mp3/posttext.mp3").is_file(): if Path(f"assets/mp3/posttext.mp3").is_file():
image_clips.insert( image_clips.insert(
0, 0,
@ -82,10 +69,57 @@ def make_final_video(number_of_clips):
image_concat.audio = audio_composite image_concat.audio = audio_composite
final = CompositeVideoClip([background_clip, image_concat]) final = CompositeVideoClip([background_clip, image_concat])
saveVideo(final)
def saveVideo(final):
"""Writes video to assets/generated videos
Args:
final (CompositeVideoClip): Final video object
"""
if not Path("assets/generated-videos").is_dir(): if not Path("assets/generated-videos").is_dir():
Path.mkdir("assets/generated-videos") Path.mkdir("assets/generated-videos")
raw_filename = Path("assets", "generated-videos") / (reddit.subreddit.submission.title + ".mp4") raw_filename = Path("assets", "generated-videos") / (reddit.subreddit.submission.title + ".mp4")
cleaned_filename = (re.sub('[?\"%*:|<>]', '', str(raw_filename))) cleaned_filename = (re.sub('[?\"%*:|<>]', '', str(raw_filename)))
final.write_videofile(cleaned_filename, fps=30, audio_codec="aac", audio_bitrate="192k") final.write_videofile(cleaned_filename, fps=30, audio_codec="aac", audio_bitrate="192k")
def gatherImages(number_of_clips, opacity, audio_clips):
"""Gathers thread screenshots from assets/png
Args:
number_of_clips (int): number of screenshots to be put into the video
opacity (float): how clear the comment is going to be in the video
audio_clips (list[AudioFileClip]): TTS of the thread
Returns:
list[ImageClip]: all the comments with TTS over it
"""
# Gather all images
image_clips = []
for i in range(0, number_of_clips):
image_clips.append(
ImageClip(f"assets/png/comment_{i}.png")
.set_duration(audio_clips[i + 1].duration)
.set_position("center")
.resize(width=W - 100)
.set_opacity(float(opacity)),
)
return image_clips
def gatherAudioClips(number_of_clips):
# Gather all audio clips
audio_clips = []
for i in range(0, number_of_clips):
audio_clips.append(AudioFileClip(f"assets/mp3/{i}.mp3"))
audio_clips.insert(0, AudioFileClip(f"assets/mp3/title.mp3"))
try:
audio_clips.insert(1, AudioFileClip(f"assets/mp3/posttext.mp3"))
except:
OSError()
audio_concat = concatenate_audioclips(audio_clips)
audio_composite = CompositeAudioClip([audio_concat])
return audio_clips,audio_composite
Loading…
Cancel
Save