cleaning spaghetti code

pull/2337/head
electro199 3 months ago
parent 64bf647de9
commit 39412e2a35

@ -4,17 +4,17 @@ import sys
from os import name from os import name
from pathlib import Path from pathlib import Path
from subprocess import Popen from subprocess import Popen
from typing import NoReturn from typing import Dict, NoReturn, Optional
from prawcore import ResponseException from prawcore import ResponseException
from reddit.subreddit import get_subreddit_threads from reddit.subreddit import get_subreddit_threads
from utils import settings from utils import settings
from utils.cleanup import cleanup from utils.cleanup import cleanup
from utils.console import print_markdown, print_step, print_substep from utils.console import print_markdown, print_step, format_ordinal
from utils.ffmpeg_install import ffmpeg_install from utils.ffmpeg_install import ffmpeg_install
from utils.id import id from utils.id import extract_id
from utils.version import checkversion from utils.version import checkversion, check_python
from video_creation.background import ( from video_creation.background import (
chop_background, chop_background,
download_background_audio, download_background_audio,
@ -38,15 +38,20 @@ print(
""" """
) )
print_markdown( print_markdown(
"### Thanks for using this tool! Feel free to contribute to this project on GitHub! If you have any questions, feel free to join my Discord server or submit a GitHub issue. You can find solutions to many common problems in the documentation: https://reddit-video-maker-bot.netlify.app/" "### Thanks for using this tool! Feel free to contribute to this project on GitHub! If you have any questions,"
" feel free to join my Discord server or submit a GitHub issue."
" You can find solutions to many common problems in the documentation: https://reddit-video-maker-bot.netlify.app/"
) )
checkversion(__VERSION__) checkversion(__VERSION__)
reddit_id: Optional[str] = None
reddit_object: Dict[str, str | list]
def main(POST_ID=None) -> None: def main(POST_ID=None) -> None:
global redditid, reddit_object global redditid, reddit_object
reddit_object = get_subreddit_threads(POST_ID) reddit_object = get_subreddit_threads(POST_ID)
redditid = id(reddit_object) redditid = extract_id(reddit_object)
length, number_of_comments = save_text_to_mp3(reddit_object) length, number_of_comments = save_text_to_mp3(reddit_object)
length = math.ceil(length) length = math.ceil(length)
get_screenshots_of_reddit_posts(reddit_object, number_of_comments) get_screenshots_of_reddit_posts(reddit_object, number_of_comments)
@ -63,14 +68,14 @@ def main(POST_ID=None) -> None:
def run_many(times) -> None: def run_many(times) -> None:
for x in range(1, times + 1): for x in range(1, times + 1):
print_step( print_step(
f'on the {x}{("th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th")[x % 10]} iteration of {times}' f"on the {format_ordinal(x)} iteration of {times}"
) # correct 1st 2nd 3rd 4th 5th.... ) # correct 1st 2nd 3rd 4th 5th....
main() main()
Popen("cls" if name == "nt" else "clear", shell=True).wait() Popen("cls" if name == "nt" else "clear", shell=True).wait()
def shutdown() -> NoReturn: def shutdown() -> NoReturn:
if "redditid" in globals(): if reddit_id is not None:
print_markdown("## Clearing temp files") print_markdown("## Clearing temp files")
cleanup(redditid) cleanup(redditid)
@ -79,33 +84,19 @@ def shutdown() -> NoReturn:
if __name__ == "__main__": if __name__ == "__main__":
if sys.version_info.major != 3 or sys.version_info.minor not in [10, 11]: check_python()
print(
"Hey! Congratulations, you've made it so far (which is pretty rare with no Python 3.10). Unfortunately, this program only works on Python 3.10. Please install Python 3.10 and try again."
)
sys.exit()
ffmpeg_install() ffmpeg_install()
directory = Path().absolute() directory = Path().absolute()
config = settings.check_toml( config = settings.get_config(directory)
f"{directory}/utils/.config.template.toml", f"{directory}/config.toml"
)
config is False and sys.exit()
if (
not settings.config["settings"]["tts"]["tiktok_sessionid"]
or settings.config["settings"]["tts"]["tiktok_sessionid"] == ""
) and config["settings"]["tts"]["voice_choice"] == "tiktok":
print_substep(
"TikTok voice requires a sessionid! Check our documentation on how to obtain one.",
"bold red",
)
sys.exit()
try: try:
if config["reddit"]["thread"]["post_id"]: if config["reddit"]["thread"]["post_id"]:
for index, post_id in enumerate(config["reddit"]["thread"]["post_id"].split("+")): for index, post_id in enumerate(
config["reddit"]["thread"]["post_id"].split("+")
):
index += 1 index += 1
print_step( print_step(
f'on the {index}{("st" if index % 10 == 1 else ("nd" if index % 10 == 2 else ("rd" if index % 10 == 3 else "th")))} post of {len(config["reddit"]["thread"]["post_id"].split("+"))}' f'on the {format_ordinal(index)} post of {len(config["reddit"]["thread"]["post_id"].split("+"))}'
) )
main(post_id) main(post_id)
Popen("cls" if name == "nt" else "clear", shell=True).wait() Popen("cls" if name == "nt" else "clear", shell=True).wait()

@ -118,3 +118,15 @@ def handle_input(
console.print( console.print(
"[red bold]" + err_message + "\nValid options are: " + ", ".join(map(str, options)) + "." "[red bold]" + err_message + "\nValid options are: " + ", ".join(map(str, options)) + "."
) )
def format_ordinal(x):
if 10 <= x % 100 <= 20:
suffix = 'th'
else:
suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(x % 10, 'th')
return f"{x}{suffix}"
if __name__ == "__main__":
for i in range(20):
print(format_ordinal(i))

@ -3,7 +3,7 @@ import re
from utils.console import print_substep from utils.console import print_substep
def id(reddit_obj: dict): def extract_id(reddit_obj: dict):
""" """
This function takes a reddit object and returns the post id This function takes a reddit object and returns the post id
""" """

@ -1,11 +1,12 @@
import re import re
from pathlib import Path from pathlib import Path
from typing import Dict, Tuple import sys
from typing import Any, Dict, Literal, Tuple
import toml import toml
from rich.console import Console from rich.console import Console
from utils.console import handle_input from utils.console import handle_input, print_substep
console = Console() console = Console()
config = dict # autocomplete config = dict # autocomplete
@ -53,7 +54,11 @@ def check(value, checks, name):
and not hasattr(value, "__iter__") and not hasattr(value, "__iter__")
and ( and (
("nmin" in checks and checks["nmin"] is not None and value < checks["nmin"]) ("nmin" in checks and checks["nmin"] is not None and value < checks["nmin"])
or ("nmax" in checks and checks["nmax"] is not None and value > checks["nmax"]) or (
"nmax" in checks
and checks["nmax"] is not None
and value > checks["nmax"]
)
) )
): ):
incorrect = True incorrect = True
@ -61,8 +66,16 @@ def check(value, checks, name):
not incorrect not incorrect
and hasattr(value, "__iter__") and hasattr(value, "__iter__")
and ( and (
("nmin" in checks and checks["nmin"] is not None and len(value) < checks["nmin"]) (
or ("nmax" in checks and checks["nmax"] is not None and len(value) > checks["nmax"]) "nmin" in checks
and checks["nmin"] is not None
and len(value) < checks["nmin"]
)
or (
"nmax" in checks
and checks["nmax"] is not None
and len(value) > checks["nmax"]
)
) )
): ):
incorrect = True incorrect = True
@ -70,9 +83,15 @@ def check(value, checks, name):
if incorrect: if incorrect:
value = handle_input( value = handle_input(
message=( message=(
(("[blue]Example: " + str(checks["example"]) + "\n") if "example" in checks else "") (
("[blue]Example: " + str(checks["example"]) + "\n")
if "example" in checks
else ""
)
+ "[red]" + "[red]"
+ ("Non-optional ", "Optional ")["optional" in checks and checks["optional"] is True] + ("Non-optional ", "Optional ")[
"optional" in checks and checks["optional"] is True
]
) )
+ "[#C0CAF5 bold]" + "[#C0CAF5 bold]"
+ str(name) + str(name)
@ -107,13 +126,15 @@ def check_vars(path, checks):
crawl_and_check(config, path, checks) crawl_and_check(config, path, checks)
def check_toml(template_file, config_file) -> Tuple[bool, Dict]: def check_toml(template_file, config_file) -> Dict[str, Any] | None | Literal[False]:
global config global config
config = None config = None
try: try:
template = toml.load(template_file) template = toml.load(template_file)
except Exception as error: except Exception as error:
console.print(f"[red bold]Encountered error when trying to to load {template_file}: {error}") console.print(
f"[red bold]Encountered error when trying to to load {template_file}: {error}"
)
return False return False
try: try:
config = toml.load(config_file) config = toml.load(config_file)
@ -164,6 +185,25 @@ If you see any prompts, that means that you have unset/incorrectly set variables
toml.dump(config, f) toml.dump(config, f)
return config return config
def get_config(directory):
config = check_toml(
f"{directory}/utils/.config.template.toml", f"{directory}/config.toml"
)
if not config:
sys.exit()
if (
not config["settings"]["tts"]["tiktok_sessionid"]
or config["settings"]["tts"]["tiktok_sessionid"] == ""
) and config["settings"]["tts"]["voice_choice"] == "tiktok":
print_substep(
"TikTok voice requires a sessionid! Check our documentation on how to obtain one.",
"bold red",
)
sys.exit()
return config
if __name__ == "__main__": if __name__ == "__main__":
directory = Path().absolute() directory = Path().absolute()

@ -1,3 +1,4 @@
import sys
import requests import requests
from utils.console import print_step from utils.console import print_step
@ -19,3 +20,11 @@ def checkversion(__VERSION__: str):
print_step( print_step(
f"Welcome to the test version ({__VERSION__}) of the bot. Thanks for testing and feel free to report any bugs you find." f"Welcome to the test version ({__VERSION__}) of the bot. Thanks for testing and feel free to report any bugs you find."
) )
def check_python() -> None:
minor_versions = [10, 11, 12, 13]
if sys.version_info.major != 3 or sys.version_info.minor not in minor_versions:
print(
f"Hey! Congratulations, you've made it so far (which is pretty rare with no Python 3.{minor_versions}). Unfortunately, this program only works on Python 3.{minor_versions}. Please install Python 3.{minor_versions} and try again."
)
sys.exit()

@ -2,7 +2,6 @@ import multiprocessing
import os import os
import re import re
import tempfile import tempfile
import textwrap
import threading import threading
import time import time
from os.path import exists # Needs to be imported specifically from os.path import exists # Needs to be imported specifically
@ -11,16 +10,16 @@ from typing import Dict, Final, Tuple
import ffmpeg import ffmpeg
import translators import translators
from PIL import Image, ImageDraw, ImageFont from PIL import Image
from rich.console import Console from rich.console import Console
from rich.progress import track from rich.progress import track
from utils import settings from utils import settings
from utils.cleanup import cleanup from utils.cleanup import cleanup
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
from utils.fonts import getheight
from utils.thumbnail import create_thumbnail
from utils.videos import save_data from utils.videos import save_data
from video_creation.thumbnail import background_thumbnail
from .thumbnail import create_fancy_thumbnail
console = Console() console = Console()
@ -108,63 +107,6 @@ def prepare_background(reddit_id: str, W: int, H: int) -> str:
return output_path return output_path
def create_fancy_thumbnail(image, text, text_color, padding, wrap=35):
print_step(f"Creating fancy thumbnail for: {text}")
font_title_size = 47
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
image_width, image_height = image.size
lines = textwrap.wrap(text, width=wrap)
y = (
(image_height / 2)
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
+ 30
)
draw = ImageDraw.Draw(image)
username_font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 30)
draw.text(
(205, 825),
settings.config["settings"]["channel_name"],
font=username_font,
fill=text_color,
align="left",
)
if len(lines) == 3:
lines = textwrap.wrap(text, width=wrap + 10)
font_title_size = 40
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
y = (
(image_height / 2)
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
+ 35
)
elif len(lines) == 4:
lines = textwrap.wrap(text, width=wrap + 10)
font_title_size = 35
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
y = (
(image_height / 2)
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
+ 40
)
elif len(lines) > 4:
lines = textwrap.wrap(text, width=wrap + 10)
font_title_size = 30
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
y = (
(image_height / 2)
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
+ 30
)
for line in lines:
draw.text((120, y), line, font=font, fill=text_color, align="left")
y += getheight(font, line) + padding
return image
def merge_background_audio(audio: ffmpeg, reddit_id: str): def merge_background_audio(audio: ffmpeg, reddit_id: str):
"""Gather an audio and merge with assets/backgrounds/background.mp3 """Gather an audio and merge with assets/backgrounds/background.mp3
Args: Args:
@ -266,17 +208,12 @@ def make_final_video(
# get the title_template image and draw a text in the middle part of it with the title of the thread # get the title_template image and draw a text in the middle part of it with the title of the thread
title_template = Image.open("assets/title_template.png") title_template = Image.open("assets/title_template.png")
title = reddit_obj["thread_title"] title = name_normalize(reddit_obj["thread_title"])
title = name_normalize(title)
font_color = "#000000" font_color = "#000000"
padding = 5 padding = 5
# create_fancy_thumbnail(image, text, text_color, padding
title_img = create_fancy_thumbnail(title_template, title, font_color, padding) title_img = create_fancy_thumbnail(title_template, title, font_color, padding)
title_img.save(f"assets/temp/{reddit_id}/png/title.png") title_img.save(f"assets/temp/{reddit_id}/png/title.png")
image_clips.insert( image_clips.insert(
0, 0,
ffmpeg.input(f"assets/temp/{reddit_id}/png/title.png")["v"].filter( ffmpeg.input(f"assets/temp/{reddit_id}/png/title.png")["v"].filter(
@ -362,36 +299,7 @@ def make_final_video(
settingsbackground = settings.config["settings"]["background"] settingsbackground = settings.config["settings"]["background"]
if settingsbackground["background_thumbnail"]: if settingsbackground["background_thumbnail"]:
if not exists(f"./results/{subreddit}/thumbnails"): background_thumbnail(reddit_id, title_thumb, subreddit)
print_substep(
"The 'results/thumbnails' folder could not be found so it was automatically created."
)
os.makedirs(f"./results/{subreddit}/thumbnails")
# get the first file with the .png extension from assets/backgrounds and use it as a background for the thumbnail
first_image = next(
(file for file in os.listdir("assets/backgrounds") if file.endswith(".png")),
None,
)
if first_image is None:
print_substep("No png files found in assets/backgrounds", "red")
else:
font_family = settingsbackground["background_thumbnail_font_family"]
font_size = settingsbackground["background_thumbnail_font_size"]
font_color = settingsbackground["background_thumbnail_font_color"]
thumbnail = Image.open(f"assets/backgrounds/{first_image}")
width, height = thumbnail.size
thumbnailSave = create_thumbnail(
thumbnail,
font_family,
font_size,
font_color,
width,
height,
title_thumb,
)
thumbnailSave.save(f"./assets/temp/{reddit_id}/thumbnail.png")
print_substep(f"Thumbnail - Building Thumbnail in assets/temp/{reddit_id}/thumbnail.png")
text = f"Background by {background_config['video'][2]}" text = f"Background by {background_config['video'][2]}"
background_clip = ffmpeg.drawtext( background_clip = ffmpeg.drawtext(

@ -0,0 +1,100 @@
import os
import textwrap
from os.path import exists
from PIL import Image, ImageDraw, ImageFont
from utils import settings
from utils.console import print_step, print_substep
from utils.fonts import getheight
from utils.thumbnail import create_thumbnail
def create_fancy_thumbnail(image, text, text_color, padding, wrap=35):
print_step(f"Creating fancy thumbnail for: {text}")
font_title_size = 47
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
image_width, image_height = image.size
lines = textwrap.wrap(text, width=wrap)
y = (
(image_height / 2)
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
+ 30
)
draw = ImageDraw.Draw(image)
username_font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 30)
draw.text(
(205, 825),
settings.config["settings"]["channel_name"],
font=username_font,
fill=text_color,
align="left",
)
if len(lines) == 3:
lines = textwrap.wrap(text, width=wrap + 10)
font_title_size = 40
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
y = (
(image_height / 2)
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
+ 35
)
elif len(lines) == 4:
lines = textwrap.wrap(text, width=wrap + 10)
font_title_size = 35
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
y = (
(image_height / 2)
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
+ 40
)
elif len(lines) > 4:
lines = textwrap.wrap(text, width=wrap + 10)
font_title_size = 30
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
y = (
(image_height / 2)
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
+ 30
)
for line in lines:
draw.text((120, y), line, font=font, fill=text_color, align="left")
y += getheight(font, line) + padding
return image
def background_thumbnail(reddit_id, title_thumb, subreddit):
if not exists(f"./results/{subreddit}/thumbnails"):
print_substep(
"The 'results/thumbnails' folder could not be found so it was automatically created."
)
os.makedirs(f"./results/{subreddit}/thumbnails")
# get the first file with the .png extension from assets/backgrounds and use it as a background for the thumbnail
first_image = next(
(file for file in os.listdir("assets/backgrounds") if file.endswith(".png")),
None,
)
if first_image is None:
print_substep("No png files found in assets/backgrounds", "red")
else:
font_family = settings.config["settings"]["background"]["background_thumbnail_font_family"]
font_size = settings.config["settings"]["background"]["background_thumbnail_font_size"]
font_color = settings.config["settings"]["background"]["background_thumbnail_font_color"]
thumbnail = Image.open(f"assets/backgrounds/{first_image}")
width, height = thumbnail.size
thumbnailSave = create_thumbnail(
thumbnail,
font_family,
font_size,
font_color,
width,
height,
title_thumb,
)
thumbnailSave.save(f"./assets/temp/{reddit_id}/thumbnail.png")
print_substep(f"Thumbnail - Building Thumbnail in assets/temp/{reddit_id}/thumbnail.png")
Loading…
Cancel
Save