Started refactoring

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

@ -1,7 +1,5 @@
# Main
from utils.console import print_markdown
from utils.console import print_step
from utils.console import print_substep
from rich.console import Console
import time
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.screenshot_downloader import download_screenshots_of_reddit_posts
from video_creation.final_video import make_final_video
from utils.loader import Loader
from dotenv import load_dotenv
from pathlib import Path
console = Console()
from dotenv import load_dotenv
import os, time, shutil
configured = True
REQUIRED_VALUES = [
"REDDIT_CLIENT_ID",
"REDDIT_CLIENT_SECRET",
"REDDIT_USERNAME",
"REDDIT_PASSWORD",
"OPACITY",
]
import os, time
"""TODO
- Refactor all .py files
- Write tests in tests/
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()
def main():
if envConfigured():
generateVideo()
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...")
if configured:
def generateVideo():
# Video generation
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, os.getenv("THEME", "light")
)
reddit_object, number_of_comments, os.getenv("THEME", "light")
)
download_background()
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():
global submission
"""
Returns a list of threads from the AskReddit subreddit.
"""
"""Selects subreddit threads and returns them
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()
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")
passkey = configurePasskey()
content = {}
reddit = praw.Reddit(
@ -34,28 +40,7 @@ def get_subreddit_threads():
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
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)]
pickThread(reddit)
print_substep(f"Video will be: {submission.title} :thumbsup:")
console.log("Getting video comments...")
@ -77,6 +62,44 @@ def get_subreddit_threads():
except AttributeError as e:
pass
print_substep("Received AskReddit threads successfully.", style="bold green")
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
import os
import time
from setuptools import setup
from utils.console import print_markdown
from utils.console import print_step
from utils.console import print_substep
@ -15,108 +17,129 @@ from utils.loader import Loader
from pathlib import Path
console = Console()
setup_done = Path(".setup-done-before").is_file()
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()
def main():
setup_done = Path(".setup-done-before").is_file()
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:
# - knows they are in setup mode
# - knows that they are about to erase any other setup files/data.
print_step("Setup Assistant")
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.
ensureSetupIsRequired = input("Are you sure you want to continue? > ").casefold()
if ensureSetupIsRequired != "yes":
console.print("[red]Exiting...")
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)
exit()
else:
# Again, let them know they are about to erase all other setup data.
console.print("[bold red] This will overwrite your current settings. Are you sure you want to continue? [bold green]yes/no")
overwriteSettings = input("Are you sure you want to continue? > ").casefold()
if overwriteSettings != "yes":
console.print("[red]Abort mission! Exiting...")
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.")
confirmUserHasCredentials = input(
"Are you sure you have the credentials? > ").casefold()
if confirmUserHasCredentials != "yes":
console.print("[red]I don't understand that.")
console.print("[red]Exiting...")
exit()
else:
# Once they confirm, move on with the script.
console.print("[bold green]Alright! Let's get started!")
time.sleep(1)
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.")
confirmUserHasCredentials = input("Are you sure you have the credentials? > ").casefold()
if confirmUserHasCredentials != "yes":
console.print("[red]I don't understand that.")
console.print("[red]Exiting...")
exit()
else:
console.print("[bold green]Alright! Let's get started!")
time.sleep(1)
setup()
console.log("[bold green]Setup Complete! Returning...")
# Post-Setup: send message and try to run main.py again.
os.system("python3 main.py")
def setup():
"""
Begin the setup process.
"""
console.log("Enter your credentials now.")
cliID = input("Client ID > ")
cliSec = input("Client Secret > ")
user = input("Username > ")
passw = input("Password > ")
twofactor = input("2fa Enabled? (yes/no) > ")
opacity = input("Opacity? (range of 0-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.")
cliID = input("Client ID > ")
cliSec = input("Client Secret > ")
user = input("Username > ")
passw = input("Password > ")
twofactor = input("2fa Enabled? (yes/no) > ")
opacity = input("Opacity? (range of 0-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')
def ensureSetup():
# This Input is used to ensure the user is sure they want to continue.
ensureSetupIsRequired = input(
"Are you sure you want to continue? > ").casefold()
if ensureSetupIsRequired != "yes":
console.print("[red]Exiting...")
time.sleep(0.5)
exit()
else:
# Again, let them know they are about to erase all other setup data.
console.print(
"[bold red] This will overwrite your current settings. Are you sure you want to continue? [bold green]yes/no")
overwriteSettings = input(
"Are you sure you want to continue? > ").casefold()
if overwriteSettings != "yes":
console.print("[red]Abort mission! Exiting...")
time.sleep(0.5)
exit()
else:
# Once they confirm, move on with the script.
console.print("[bold green]Alright! Let's get started!")
time.sleep(1)
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.
os.system("python3 main.py")
if __name__ == '__main__':
main()

@ -19,7 +19,11 @@ W, H = 1080, 1920
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
load_dotenv()
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)
)
# 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])
audio_clips, audio_composite = gatherAudioClips(number_of_clips)
image_clips = gatherImages(number_of_clips, opacity, audio_clips)
# 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():
image_clips.insert(
0,
@ -82,10 +69,57 @@ def make_final_video(number_of_clips):
image_concat.audio = audio_composite
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():
Path.mkdir("assets/generated-videos")
raw_filename = Path("assets", "generated-videos") / (reddit.subreddit.submission.title + ".mp4")
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