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,53 +7,77 @@ 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
"""TODO
- Refactor all .py files
- Write tests in tests/
"""
def main():
if envConfigured():
generateVideo()
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")
)
download_background()
chop_background_video(length)
make_final_video(number_of_comments)
def envConfigured():
console = Console()
configured = True configured = True
REQUIRED_VALUES = [ REQUIRED_VALUES = [
"REDDIT_CLIENT_ID", "REDDIT_CLIENT_ID",
"REDDIT_CLIENT_SECRET", "REDDIT_CLIENT_SECRET",
"REDDIT_USERNAME", "REDDIT_USERNAME",
"REDDIT_PASSWORD", "REDDIT_PASSWORD",
"OPACITY", "OPACITY",
] ]
print_markdown( 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." "### 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.
""" """
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_id = os.getenv("REDDIT_CLIENT_ID")
client_secret = os.getenv("REDDIT_CLIENT_SECRET") client_secret = os.getenv("REDDIT_CLIENT_SECRET")
username = os.getenv("REDDIT_USERNAME") username = os.getenv("REDDIT_USERNAME")
password = os.getenv("REDDIT_PASSWORD") password = os.getenv("REDDIT_PASSWORD")
reddit2fa = os.getenv("REDDIT_2FA") reddit2fa = os.getenv("REDDIT_2FA")
load_dotenv() load_dotenv()
console.log("[bold green]Checking environment variables...") console.log("[bold green]Checking environment variables...")
time.sleep(1) time.sleep(1)
if not Path(".env").is_file(): if not Path(".env").is_file():
configured = False configured = False
console.log("[red] Your .env file is invalid, or was never created. Standby.") console.log("[red] Your .env file is invalid, or was never created. Standby.")
# Checks to see if all values in .env are provided # Checks to see if all values in .env are provided
# If they aren't, then asks to launch setup wizard # If they aren't, then asks to launch setup wizard
for val in REQUIRED_VALUES: for val in REQUIRED_VALUES:
# print(os.getenv(val)) # print(os.getenv(val))
if val not in os.environ or not os.getenv(val): if val not in os.environ or not os.getenv(val):
console.log(f'[bold red]Missing Variable: "{val}"') console.log(f'[bold red]Missing Variable: "{val}"')
@ -81,23 +103,17 @@ for val in REQUIRED_VALUES:
console.print("[red]I don't understand that.") console.print("[red]I don't understand that.")
time.sleep(0.5) time.sleep(0.5)
try: try:
float(os.getenv("OPACITY")) float(os.getenv("OPACITY"))
except: except:
console.log( console.log(
f"[red]Please ensure that OPACITY is set between 0 and 1 in your .env file" f"[red]Please ensure that OPACITY is set between 0 and 1 in your .env file"
) )
configured = False configured = False
exit() exit()
console.log("[bold green]Enviroment Variables are set! Continuing...") console.log("[bold green]Enviroment Variables are set! Continuing...")
return configured
if configured:
# Video generation if __name__ == '__main__':
reddit_object = get_subreddit_threads() main()
length, number_of_comments = save_text_to_mp3(reddit_object)
download_screenshots_of_reddit_posts(
reddit_object, number_of_comments, os.getenv("THEME", "light")
)
download_background()
chop_background_video(length)
final_video = make_final_video(number_of_comments)

@ -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,86 +17,81 @@ 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():
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") 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() exit()
# These lines ensure the user: # These lines ensure the user:
# - knows they are in setup mode # - knows they are in setup mode
# - knows that they are about to erase any other setup files/data. # - knows that they are about to erase any other setup files/data.
print_step("Setup Assistant") print_step("Setup Assistant")
print_markdown( 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." "### 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...")
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)
console.log("Ensure you have the following ready to enter:") ensureSetup()
console.log("[bold green]Reddit Client ID")
console.log("[bold green]Reddit Client Secret") console.log("Ensure you have the following ready to enter:")
console.log("[bold green]Reddit Username") console.log("[bold green]Reddit Client ID")
console.log("[bold green]Reddit Password") console.log("[bold green]Reddit Client Secret")
console.log("[bold green]Reddit 2FA (yes or no)") console.log("[bold green]Reddit Username")
console.log("[bold green]Opacity (range of 0-1, decimals are OK)") console.log("[bold green]Reddit Password")
console.log("[bold green]Subreddit (without r/ or /r/)") console.log("[bold green]Reddit 2FA (yes or no)")
console.log("[bold green]Theme (light or dark)") console.log("[bold green]Opacity (range of 0-1, decimals are OK)")
time.sleep(0.5) console.log("[bold green]Subreddit (without r/ or /r/)")
console.print("[green]If you don't have these, please follow the instructions in the README.md file to set them up.") console.log("[bold green]Theme (light or dark)")
console.print("[green]If you do have these, type yes to continue. If you dont, go ahead and grab those quickly and come back.") time.sleep(0.5)
confirmUserHasCredentials = input("Are you sure you have the credentials? > ").casefold() console.print(
if confirmUserHasCredentials != "yes": "[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]I don't understand that.")
console.print("[red]Exiting...") console.print("[red]Exiting...")
exit() exit()
else: else:
console.print("[bold green]Alright! Let's get started!") console.print("[bold green]Alright! Let's get started!")
time.sleep(1) time.sleep(1)
""" setup()
Begin the setup process. console.log("[bold green]Setup Complete! Returning...")
""" # Post-Setup: send message and try to run main.py again.
os.system("python3 main.py")
console.log("Enter your credentials now.")
cliID = input("Client ID > ") def setup():
cliSec = input("Client Secret > ") """
user = input("Username > ") Begin the setup process.
passw = input("Password > ") """
twofactor = input("2fa Enabled? (yes/no) > ")
opacity = input("Opacity? (range of 0-1) > ") console.log("Enter your credentials now.")
subreddit = input("Subreddit (without r/) > ") cliID = input("Client ID > ")
theme = input("Theme? (light or dark) > ") cliSec = input("Client Secret > ")
console.log("Attempting to save your credentials...") user = input("Username > ")
loader = Loader("Saving Credentials...", "Done!").start() passw = input("Password > ")
# you can also put a while loop here, e.g. while VideoIsBeingMade == True: ... twofactor = input("2fa Enabled? (yes/no) > ")
time.sleep(0.5) opacity = input("Opacity? (range of 0-1) > ")
console.log("Removing old .env file...") subreddit = input("Subreddit (without r/) > ")
os.remove(".env") theme = input("Theme? (light or dark) > ")
time.sleep(0.5) console.log("Attempting to save your credentials...")
console.log("Creating new .env file...") loader = Loader("Saving Credentials...", "Done!").start()
with open('.env', 'a') as f: # 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') f.write(f'REDDIT_CLIENT_ID="{cliID}"\n')
time.sleep(0.5) time.sleep(0.5)
f.write(f'REDDIT_CLIENT_SECRET="{cliSec}"\n') f.write(f'REDDIT_CLIENT_SECRET="{cliSec}"\n')
@ -111,12 +108,38 @@ with open('.env', 'a') as f:
time.sleep(0.5) time.sleep(0.5)
f.write(f'OPACITY="{opacity}"\n') f.write(f'OPACITY="{opacity}"\n')
with open('.setup-done-before', 'a') as f: 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.") f.write(
"This file blocks the setup assistant from running again. Delete this file to run setup again.")
loader.stop()
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)
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