diff --git a/.config.template.toml b/.config.template.toml
index ddfa293..18f1b00 100644
--- a/.config.template.toml
+++ b/.config.template.toml
@@ -12,11 +12,11 @@ password = { optional = false, nmin = 8, explanation = "the password of your red
random = { optional = true, options = [true,
false,
], default = false, type = "bool", explanation = "If set to no, it will ask you a thread link to extract the thread, if yes it will randomize it. Default: 'False'", example = "True" }
-subreddit = { optional = false, regex = "[_0-9a-zA-Z]+$", nmin = 3, nmax = 21, explanation = "what subreddit to pull posts from, the name of the sub, not the URL", example = "AskReddit", oob_error = "A subreddit name HAS to be between 3 and 20 characters" }
+subreddit = { optional = false, regex = "[_0-9a-zA-Z]+$", nmin = 3, explanation = "what subreddit to pull posts from, the name of the sub, not the URL", example = "AskReddit", oob_error = "A subreddit name HAS to be between 3 and 20 characters" }
post_id = { optional = true, default = "", regex = "^((?!://|://)[+a-zA-Z])*$", explanation = "Used if you want to use a specific post.", example = "urdtfx" }
max_comment_length = { default = 500, optional = false, nmin = 10, nmax = 10000, type = "int", explanation = "max number of characters a comment can have. default is 500", example = 500, oob_error = "the max comment length should be between 10 and 10000" }
post_lang = { default = "", optional = true, explanation = "The language you would like to translate to.", example = "es-cr" }
-
+min_comments = { default = 20, optional = false, nmin = 15, type = "int", explanation = "The minimum number of comments a post should have to be included. default is 20", example = 29, oob_error = "the minimum number of comments should be between 15 and 999999" }
[settings]
allow_nsfw = { optional = false, type = "bool", default = false, example = false, options = [true,
false,
@@ -29,10 +29,15 @@ opacity = { optional = false, default = 0.9, example = 0.8, explanation = "Sets
storymode = { optional = true, type = "bool", default = false, example = false, options = [true,
false,
], explanation = "not yet implemented" }
+
+[settings.background]
background_choice = { optional = true, default = "minecraft", example = "minecraft", options = ["minecraft", "gta", "rocket-league", "motor-gta", ""], explanation = "Sets the background for the video" }
-background_audio = { optional = true, type = "bool", default = false, example = false, options = [true,
- false,
-], explaination="Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" }
+#background_audio = { optional = true, type = "bool", default = false, example = false, options = [true,
+# false,
+#], explaination="Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" }
+#background_audio_volume = { optional = true, type = "float", default = 0.3, example = 0.1, explanation="Sets the volume of the background audio. only used if the background_audio is also set to true" }
+
+
[settings.tts]
choice = { optional = false, default = "", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", ], example = "streamlabspolly", explanation = "The backend used for TTS generation. This can be left blank and you will be prompted to choose at runtime." }
aws_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for AWS Polly" }
diff --git a/GUI/index.html b/GUI/index.html
new file mode 100644
index 0000000..807c9e7
--- /dev/null
+++ b/GUI/index.html
@@ -0,0 +1,281 @@
+
+
+
+
+
+ RedditVideoMakerBot
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index f8b5c02..b86b683 100644
--- a/README.md
+++ b/README.md
@@ -109,3 +109,5 @@ CallumIO (c.#6837) - https://github.com/CallumIO
Verq (Verq#2338) - https://github.com/CordlessCoder
LukaHietala (Pix.#0001) - https://github.com/LukaHietala
+
+Freebiell (Freebie#6429) - https://github.com/FreebieII
diff --git a/TTS/aws_polly.py b/TTS/aws_polly.py
index 13eaea1..efd762b 100644
--- a/TTS/aws_polly.py
+++ b/TTS/aws_polly.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
from boto3 import Session
-from botocore.exceptions import BotoCoreError, ClientError
+from botocore.exceptions import BotoCoreError, ClientError, ProfileNotFound
import sys
from utils import settings
import random
@@ -30,36 +30,46 @@ class AWSPolly:
self.voices = voices
def run(self, text, filepath, random_voice: bool = False):
- session = Session(profile_name="polly")
- polly = session.client("polly")
- if random_voice:
- voice = self.randomvoice()
- else:
- if not settings.config["settings"]["tts"]["aws_polly_voice"]:
- return ValueError(
- f"Please set the TOML variable AWS_VOICE to a valid voice. options are: {voices}"
- )
- voice = str(settings.config["settings"]["tts"]["aws_polly_voice"]).capitalize()
try:
- # Request speech synthesis
- response = polly.synthesize_speech(
- Text=text, OutputFormat="mp3", VoiceId=voice, Engine="neural"
- )
- except (BotoCoreError, ClientError) as error:
- # The service returned an error, exit gracefully
- print(error)
- sys.exit(-1)
+ session = Session(profile_name="polly")
+ polly = session.client("polly")
+ if random_voice:
+ voice = self.randomvoice()
+ else:
+ if not settings.config["settings"]["tts"]["aws_polly_voice"]:
+ raise ValueError(
+ f"Please set the TOML variable AWS_VOICE to a valid voice. options are: {voices}"
+ )
+ voice = str(settings.config["settings"]["tts"]["aws_polly_voice"]).capitalize()
+ try:
+ # Request speech synthesis
+ response = polly.synthesize_speech(
+ Text=text, OutputFormat="mp3", VoiceId=voice, Engine="neural"
+ )
+ except (BotoCoreError, ClientError) as error:
+ # The service returned an error, exit gracefully
+ print(error)
+ sys.exit(-1)
- # Access the audio stream from the response
- if "AudioStream" in response:
- file = open(filepath, "wb")
- file.write(response["AudioStream"].read())
- file.close()
- # print_substep(f"Saved Text {idx} to MP3 files successfully.", style="bold green")
+ # Access the audio stream from the response
+ if "AudioStream" in response:
+ file = open(filepath, "wb")
+ file.write(response["AudioStream"].read())
+ file.close()
+ # print_substep(f"Saved Text {idx} to MP3 files successfully.", style="bold green")
- else:
- # The response didn't contain audio data, exit gracefully
- print("Could not stream audio")
+ else:
+ # The response didn't contain audio data, exit gracefully
+ print("Could not stream audio")
+ sys.exit(-1)
+ except ProfileNotFound:
+ print("You need to install the AWS CLI and configure your profile")
+ print(
+ """
+ Linux: https://docs.aws.amazon.com/polly/latest/dg/setup-aws-cli.html
+ Windows: https://docs.aws.amazon.com/polly/latest/dg/install-voice-plugin2.html
+ """
+ )
sys.exit(-1)
def randomvoice(self):
diff --git a/TTS/engine_wrapper.py b/TTS/engine_wrapper.py
index a171db7..c5ed714 100644
--- a/TTS/engine_wrapper.py
+++ b/TTS/engine_wrapper.py
@@ -47,7 +47,7 @@ class TTSEngine:
Path(self.path).mkdir(parents=True, exist_ok=True)
- # This file needs to be removed in case this post does not use post text, so that it wont appear in the final video
+ # This file needs to be removed in case this post does not use post text, so that it won't appear in the final video
try:
Path(f"{self.path}/posttext.mp3").unlink()
except OSError:
@@ -67,10 +67,12 @@ class TTSEngine:
# ! Stop creating mp3 files if the length is greater than max length.
if self.length > self.max_length:
break
- if not self.tts_module.max_chars:
+ if (
+ len(comment["comment_body"]) > self.tts_module.max_chars
+ ): # Split the comment if it is too long
+ self.split_post(comment["comment_body"], idx) # Split the comment
+ else: # If the comment is not too long, just call the tts engine
self.call_tts(f"{idx}", comment["comment_body"])
- else:
- self.split_post(comment["comment_body"], idx)
print_substep("Saved Text to MP3 files successfully.", style="bold green")
return self.length, idx
@@ -79,14 +81,20 @@ class TTSEngine:
split_files = []
split_text = [
x.group().strip()
- for x in re.finditer(rf" *((.{{0,{self.tts_module.max_chars}}})(\.|.$))", text)
+ for x in re.finditer(
+ r" *(((.|\n){0," + str(self.tts_module.max_chars) + "})(\.|.$))", text
+ )
]
-
- idy = None
+ offset = 0
for idy, text_cut in enumerate(split_text):
# print(f"{idx}-{idy}: {text_cut}\n")
- self.call_tts(f"{idx}-{idy}.part", text_cut)
- split_files.append(AudioFileClip(f"{self.path}/{idx}-{idy}.part.mp3"))
+ if not text_cut or text_cut.isspace():
+ offset += 1
+ continue
+
+ self.call_tts(f"{idx}-{idy - offset}.part", text_cut)
+ split_files.append(AudioFileClip(f"{self.path}/{idx}-{idy - offset}.part.mp3"))
+
CompositeAudioClip([concatenate_audioclips(split_files)]).write_audiofile(
f"{self.path}/{idx}.mp3", fps=44100, verbose=False, logger=None
)
@@ -107,9 +115,12 @@ class TTSEngine:
# self.length += MP3(f"{self.path}/{filename}.mp3").info.length
# except (MutagenError, HeaderNotFoundError):
# self.length += sox.file_info.duration(f"{self.path}/{filename}.mp3")
- clip = AudioFileClip(f"{self.path}/{filename}.mp3")
- self.length += clip.duration
- clip.close()
+ try:
+ clip = AudioFileClip(f"{self.path}/{filename}.mp3")
+ self.length += clip.duration
+ clip.close()
+ except:
+ self.length = 0
def process_text(text: str):
diff --git a/TTS/streamlabs_polly.py b/TTS/streamlabs_polly.py
index b7365ab..75c4f49 100644
--- a/TTS/streamlabs_polly.py
+++ b/TTS/streamlabs_polly.py
@@ -37,8 +37,8 @@ class StreamlabsPolly:
voice = self.randomvoice()
else:
if not settings.config["settings"]["tts"]["streamlabs_polly_voice"]:
- return ValueError(
- f"Please set the config variable STREAMLABS_VOICE to a valid voice. options are: {voices}"
+ raise ValueError(
+ f"Please set the config variable STREAMLABS_POLLY_VOICE to a valid voice. options are: {voices}"
)
voice = str(settings.config["settings"]["tts"]["streamlabs_polly_voice"]).capitalize()
body = {"voice": voice, "text": text, "service": "polly"}
diff --git a/main.py b/main.py
index 8ce8725..10ab3c1 100755
--- a/main.py
+++ b/main.py
@@ -7,7 +7,6 @@ from utils.cleanup import cleanup
from utils.console import print_markdown, print_step
from utils import settings
-# from utils.checker import envUpdate
from video_creation.background import (
download_background,
chop_background_video,
@@ -17,7 +16,9 @@ from video_creation.final_video import make_final_video
from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts
from video_creation.voices import save_text_to_mp3
-VERSION = "2.2.9"
+__VERSION__ = "2.3"
+__BRANCH__ = "master"
+
print(
"""
██████╗ ███████╗██████╗ ██████╗ ██╗████████╗ ██╗ ██╗██╗██████╗ ███████╗ ██████╗ ███╗ ███╗ █████╗ ██╗ ██╗███████╗██████╗
@@ -32,7 +33,7 @@ print(
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. You can find solutions to many common problems in the [Documentation](https://luka-hietala.gitbook.io/documentation-for-the-reddit-bot/)"
)
-print_step(f"You are using V{VERSION} of the bot")
+print_step(f"You are using v{__VERSION__} of the bot")
def main(POST_ID=None):
diff --git a/pyproject.toml b/pyproject.toml
index 261a1ba..94e52ef 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,7 +15,7 @@ playwright = "1.23.0"
praw = "7.6.0"
pytube = "12.1.0"
requests = "2.28.1"
-rich = "12.4.4"
+rich = "12.5.1"
toml = "0.10.2"
translators = "5.3.1"
diff --git a/reddit/subreddit.py b/reddit/subreddit.py
index b64a52a..716a7fa 100644
--- a/reddit/subreddit.py
+++ b/reddit/subreddit.py
@@ -7,6 +7,7 @@ from praw.models import MoreComments
from utils.console import print_step, print_substep
from utils.subreddit import get_subreddit_undone
from utils.videos import check_done
+from utils.voice import sanitize_text
def get_subreddit_threads(POST_ID: str):
@@ -17,7 +18,7 @@ def get_subreddit_threads(POST_ID: str):
print_substep("Logging into Reddit.")
content = {}
- if settings.config["reddit"]["creds"]["2fa"] == True:
+ if settings.config["reddit"]["creds"]["2fa"]:
print("\nEnter your two-factor authentication code from your authenticator app.\n")
code = input("> ")
print()
@@ -26,7 +27,7 @@ def get_subreddit_threads(POST_ID: str):
else:
passkey = settings.config["reddit"]["creds"]["password"]
username = settings.config["reddit"]["creds"]["username"]
- if username.casefold().startswith("u/"):
+ if str(username).casefold().startswith("u/"):
username = username[2:]
reddit = praw.Reddit(
client_id=settings.config["reddit"]["creds"]["client_id"],
@@ -54,7 +55,7 @@ def get_subreddit_threads(POST_ID: str):
sub = settings.config["reddit"]["thread"]["subreddit"]
print_substep(f"Using subreddit: r/{sub} from TOML config")
subreddit_choice = sub
- if subreddit_choice.casefold().startswith("r/"): # removes the r/ from the input
+ if str(subreddit_choice).casefold().startswith("r/"): # removes the r/ from the input
subreddit_choice = subreddit_choice[2:]
subreddit = reddit.subreddit(
subreddit_choice
@@ -64,11 +65,10 @@ def get_subreddit_threads(POST_ID: str):
submission = reddit.submission(id=POST_ID)
elif (
settings.config["reddit"]["thread"]["post_id"]
- and len(settings.config["reddit"]["thread"]["post_id"].split("+")) == 1
+ and len(str(settings.config["reddit"]["thread"]["post_id"]).split("+")) == 1
):
submission = reddit.submission(id=settings.config["reddit"]["thread"]["post_id"])
else:
-
threads = subreddit.hot(limit=25)
submission = get_subreddit_undone(threads, subreddit)
submission = check_done(submission) # double-checking
@@ -95,11 +95,15 @@ def get_subreddit_threads(POST_ID: str):
if top_level_comment.body in ["[removed]", "[deleted]"]:
continue # # see https://github.com/JasonLovesDoggo/RedditVideoMakerBot/issues/78
if not top_level_comment.stickied:
+ sanitised = sanitize_text(top_level_comment.body)
+ if not sanitised or sanitised == " ":
+ continue
if len(top_level_comment.body) <= int(
settings.config["reddit"]["thread"]["max_comment_length"]
):
if (
top_level_comment.author is not None
+ and sanitize_text(top_level_comment.body) is not None
): # if errors occur with this change to if not.
content["comments"].append(
{
diff --git a/utils/subreddit.py b/utils/subreddit.py
index 48dceba..4eb0108 100644
--- a/utils/subreddit.py
+++ b/utils/subreddit.py
@@ -34,11 +34,16 @@ def get_subreddit_undone(submissions: list, subreddit):
if submission.stickied:
print_substep("This post was pinned by moderators. Skipping...")
continue
+ if submission.num_comments <= int(settings.config["reddit"]["thread"]["min_comments"]):
+ print_substep(
+ f'This post has under the specified minimum of comments ({settings.config["reddit"]["thread"]["min_comments"]}). Skipping...'
+ )
+ continue
return submission
print("all submissions have been done going by top submission order")
return get_subreddit_undone(
subreddit.top(time_filter="hour"), subreddit
- ) # all of the videos in hot have already been done
+ ) # all the videos in hot have already been done
def already_done(done_videos: list, submission) -> bool:
diff --git a/utils/voice.py b/utils/voice.py
index 0272b09..a0709fa 100644
--- a/utils/voice.py
+++ b/utils/voice.py
@@ -36,7 +36,7 @@ def sleep_until(time):
# Convert datetime to unix timestamp and adjust for locality
if isinstance(time, datetime):
- # If we're on Python 3 and the user specified a timezone, convert to UTC and get tje timestamp.
+ # If we're on Python 3 and the user specified a timezone, convert to UTC and get the timestamp.
if sys.version_info[0] >= 3 and time.tzinfo:
end = time.astimezone(timezone.utc).timestamp()
else:
@@ -81,7 +81,7 @@ def sanitize_text(text: str) -> str:
result = re.sub(regex_urls, " ", text)
# note: not removing apostrophes
- regex_expr = r"\s['|’]|['|’]\s|[\^_~@!&;#:\-%“”‘\"%\*/{}\[\]\(\)\\|<>=+]"
+ regex_expr = r"\s['|’]|['|’]\s|[\^_~@!&;#:\-–—%“”‘\"%\*/{}\[\]\(\)\\|<>=+]"
result = re.sub(regex_expr, " ", result)
result = result.replace("+", "plus").replace("&", "and")
# remove extra whitespace
diff --git a/video_creation/background.py b/video_creation/background.py
index 7ef4321..be0f46c 100644
--- a/video_creation/background.py
+++ b/video_creation/background.py
@@ -30,7 +30,7 @@ background_options = {
"https://www.youtube.com/watch?v=2X9QGY__0II",
"rocket_league.mp4",
"Orbital Gameplay",
- "top",
+ lambda t: ("center", 200 + t),
),
"minecraft": ( # Minecraft parkour
"https://www.youtube.com/watch?v=n_Dv4JMiwK8",
@@ -64,7 +64,7 @@ def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int
def get_background_config():
"""Fetch the background/s configuration"""
try:
- choice = str(settings.config["settings"]["background_choice"]).casefold()
+ choice = str(settings.config["settings"]["background"]["background_choice"]).casefold()
except AttributeError:
print_substep("No background selected. Picking random background'")
choice = None
diff --git a/video_creation/final_video.py b/video_creation/final_video.py
index f1e1f96..eb42247 100755
--- a/video_creation/final_video.py
+++ b/video_creation/final_video.py
@@ -3,20 +3,14 @@ import multiprocessing
import os
import re
from os.path import exists
-from typing import Dict, Tuple, Any
-
-import translators as ts
-
-from moviepy.editor import (
- VideoFileClip,
- AudioFileClip,
- ImageClip,
- concatenate_videoclips,
- concatenate_audioclips,
- CompositeAudioClip,
- CompositeVideoClip,
-)
-from moviepy.video.io.ffmpeg_tools import ffmpeg_merge_video_audio, ffmpeg_extract_subclip
+from typing import Tuple, Any
+from moviepy.audio.AudioClip import concatenate_audioclips, CompositeAudioClip
+from moviepy.audio.io.AudioFileClip import AudioFileClip
+from moviepy.video.VideoClip import ImageClip
+from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
+from moviepy.video.compositing.concatenate import concatenate_videoclips
+from moviepy.video.io.VideoFileClip import VideoFileClip
+from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from rich.console import Console
from utils.cleanup import cleanup
@@ -24,9 +18,7 @@ from utils.console import print_step, print_substep
from utils.videos import save_data
from utils import settings
-
console = Console()
-
W, H = 1080, 1920
@@ -37,9 +29,11 @@ def name_normalize(name: str) -> str:
name = re.sub(r"(\d+)\s?\/\s?(\d+)", r"\1 of \2", name)
name = re.sub(r"(\w+)\s?\/\s?(\w+)", r"\1 or \2", name)
name = re.sub(r"\/", r"", name)
+ name[:30]
lang = settings.config["reddit"]["thread"]["post_lang"]
if lang:
+ import translators as ts
print_substep("Translating filename...")
translated_name = ts.google(name, to_language=lang)
return translated_name
@@ -49,7 +43,10 @@ def name_normalize(name: str) -> str:
def make_final_video(
- number_of_clips: int, length: int, reddit_obj: dict, background_config: Tuple[str, str, str, Any]
+ number_of_clips: int,
+ length: int,
+ reddit_obj: dict,
+ background_config: Tuple[str, str, str, Any],
):
"""Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp
Args:
@@ -58,6 +55,11 @@ def make_final_video(
reddit_obj (dict): The reddit object that contains the posts to read.
background_config (Tuple[str, str, str, Any]): The background config to use.
"""
+ # try: # if it isn't found (i.e you just updated and copied over config.toml) it will throw an error
+ # VOLUME_MULTIPLIER = settings.config["settings"]['background']["background_audio_volume"]
+ # except (TypeError, KeyError):
+ # print('No background audio volume found in config.toml. Using default value of 1.')
+ # VOLUME_MULTIPLIER = 1
print_step("Creating the final video 🎥")
VideoFileClip.reW = lambda clip: clip.resize(width=W)
VideoFileClip.reH = lambda clip: clip.resize(width=H)
@@ -116,12 +118,18 @@ def make_final_video(
filename = f"{name_normalize(title)}.mp4"
subreddit = settings.config["reddit"]["thread"]["subreddit"]
- save_data(subreddit, filename, title, idx, background_config[2])
-
if not exists(f"./results/{subreddit}"):
print_substep("The results folder didn't exist so I made it")
os.makedirs(f"./results/{subreddit}")
+ # if settings.config["settings"]['background']["background_audio"] and exists(f"assets/backgrounds/background.mp3"):
+ # audioclip = mpe.AudioFileClip(f"assets/backgrounds/background.mp3").set_duration(final.duration)
+ # audioclip = audioclip.fx( volumex, 0.2)
+ # final_audio = mpe.CompositeAudioClip([final.audio, audioclip])
+ # # lowered_audio = audio_background.multiply_volume( # todo get this to work
+ # # VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx
+ # final.set_audio(final_audio)
+
final.write_videofile(
"assets/temp/temp.mp4",
fps=30,
@@ -130,38 +138,13 @@ def make_final_video(
verbose=False,
threads=multiprocessing.cpu_count(),
)
- if settings.config["settings"]["background_audio"]:
- print("[bold green] Merging background audio with video")
- if not exists(f"assets/backgrounds/background.mp3"):
- print_substep(
- "Cannot find assets/backgrounds/background.mp3 audio file didn't so skipping."
- )
- ffmpeg_extract_subclip(
- "assets/temp/temp.mp4",
- 0,
- final.duration,
- targetname=f"results/{subreddit}/{filename}",
- )
- else:
- ffmpeg_merge_video_audio(
- "assets/temp/temp.mp4",
- "assets/backgrounds/background.mp3",
- "assets/temp/temp_audio.mp4",
- )
- ffmpeg_extract_subclip( # check if this gets run
- "assets/temp/temp_audio.mp4",
- 0,
- final.duration,
- targetname=f"results/{subreddit}/{filename}",
- )
- else:
- print("debug duck")
- ffmpeg_extract_subclip(
- "assets/temp/temp.mp4",
- 0,
- final.duration,
- targetname=f"results/{subreddit}/{filename}",
- )
+ ffmpeg_extract_subclip(
+ "assets/temp/temp.mp4",
+ 0,
+ final.duration,
+ targetname=f"results/{subreddit}/{filename}",
+ )
+ save_data(subreddit, filename, title, idx, background_config[2])
print_step("Removing temporary files 🗑")
cleanups = cleanup()
print_substep(f"Removed {cleanups} temporary files 🗑")
diff --git a/video_creation/voices.py b/video_creation/voices.py
index ffc0898..ac33dd7 100644
--- a/video_creation/voices.py
+++ b/video_creation/voices.py
@@ -34,7 +34,7 @@ def save_text_to_mp3(reddit_obj) -> Tuple[int, int]:
"""
voice = settings.config["settings"]["tts"]["choice"]
- if voice.casefold() in map(lambda _: _.casefold(), TTSProviders):
+ if str(voice).casefold() in map(lambda _: _.casefold(), TTSProviders):
text_to_mp3 = TTSEngine(get_case_insensitive_key_value(TTSProviders, voice), reddit_obj)
else:
while True:
@@ -45,7 +45,6 @@ def save_text_to_mp3(reddit_obj) -> Tuple[int, int]:
break
print("Unknown Choice")
text_to_mp3 = TTSEngine(get_case_insensitive_key_value(TTSProviders, choice), reddit_obj)
-
return text_to_mp3.run()