anthony lloyd 3 years ago
commit f9e5ba2bfa

@ -1,40 +1,31 @@
[reddit.creds] [reddit.creds]
client_id = { optional = false, nmin = 12, nmax = 30, explanation = "the ID of your Reddit app of SCRIPT type", example = "fFAGRNJru1FTz70BzhT3Zg", regex = "^[-a-zA-Z0-9._~+/]+=*$", input_error = "The client ID can only contain printable characters.", oob_error = "The ID should be over 12 and under 30 characters, double check your input." } client_id = { optional = false, example = "fFAGRNJru1FTz70BzhT3Zg", explanation = "the ID of your Reddit app of SCRIPT type", default = "", nmin = 12, nmax = 30, regex = "^[-a-zA-Z0-9._~+/]+=*$", oob_error = "The ID should be over 12 and under 30 characters, double check your input.", input_error = "The client ID can only contain printable characters." }
client_secret = { optional = false, nmin = 20, nmax = 40, explanation = "the SECRET of your Reddit app of SCRIPT type", example = "fFAGRNJru1FTz70BzhT3Zg", regex = "^[-a-zA-Z0-9._~+/]+=*$", input_error = "The client ID can only contain printable characters.", oob_error = "The secret should be over 20 and under 40 characters, double check your input." } client_secret = { optional = false, example = "fFAGRNJru1FTz70BzhT3Zg", explanation = "the SECRET of your Reddit app of SCRIPT type", default = "", nmin = 20, nmax = 40, regex = "^[-a-zA-Z0-9._~+/]+=*$", oob_error = "The secret should be over 20 and under 40 characters, double check your input.", input_error = "The client ID can only contain printable characters." }
username = { optional = false, nmin = 3, nmax = 20, explanation = "the username of your reddit account", example = "JasonLovesDoggo", regex = "^[-_0-9a-zA-Z]+$", oob_error = "A username HAS to be between 3 and 20 characters" } username = { optional = false, example = "JasonLovesDoggo", explanation = "the username of your reddit account", default = "", nmin = 3, nmax = 20,regex = "^[-_0-9a-zA-Z]+$", oob_error = "A username HAS to be between 3 and 20 characters" }
password = { optional = false, nmin = 8, explanation = "the password of your reddit account", example = "fFAGRNJru1FTz70BzhT3Zg", oob_error = "Password too short" } password = { optional = false, example = "fFAGRNJru1FTz70BzhT3Zg", explanation = "the password of your reddit account", default = "", nmin = 8, oob_error = "Password too short" }
2fa = { optional = true, type = "bool", options = [true, 2fa = { optional = true, example = "True", explanation = "Whether you have Reddit 2FA enabled, Valid options are True and False", default = false, options = [true, false], type = "bool" }
false,
], default = false, explanation = "Whether you have Reddit 2FA enabled, Valid options are True and False", example = true }
[reddit.thread] [reddit.thread]
random = { optional = true, options = [true, random = { optional = true, example = "True", explanation = "If set to false, it will ask you a thread link to extract the thread, if true it will randomize it.", default = true, options = [true, false], type = "bool" }
false, subreddit = { optional = false, example = "AskReddit", explanation = "what subreddit to pull posts from, the name of the sub, not the URL", default = "", nmin = 3, nmax = 21,regex = "[_0-9a-zA-Z]+$", oob_error = "A subreddit name HAS to be between 3 and 20 characters" }
], 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" } post_id = { optional = true, example = "urdtfx", explanation = "Used if you want to use a specific post.", regex = "^((?!://|://)[+a-zA-Z])*$" }
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" } max_comment_length = { optional = false, example = 500, explanation = "max number of characters a comment can have. default is 500", default = 500, type = "int", nmin = 10, nmax = 10000, oob_error = "the max comment length should be between 10 and 10000" }
post_id = { optional = true, default = "", regex = "^((?!://|://)[+a-zA-Z])*$", explanation = "Used if you want to use a specific post.", example = "urdtfx" } post_lang = { optional = true, example = "es-cr", explanation = "The language you would like to translate to.", default = "" }
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" } sort = { optional = true, example = "hot ,top, relevance, new", explanation = "method of sorting threads", default = "top", options = ["hot", "top", "relevance", "new"] }
post_lang = { default = "", optional = true, explanation = "The language you would like to translate to.", example = "es-cr" } sort_time = { optional = true, example = "day, hour, week, month, year, all", explanation = "time range to gather threads from", default = "all", options = ["day", "hour", "week", "month", "year", "all"] }
[settings] [settings]
allow_nsfw = { optional = false, type = "bool", default = false, example = false, options = [true, allow_nsfw = { optional = false, example = "false", explanation = "Whether to allow NSFW content, True or False", default = false, options = [true, false], type = "bool" }
false, theme = { optional = false, example = "light, dark", explanation = "sets the Reddit theme, either LIGHT or DARK", default = "dark", options = ["dark", "light"] }
], explanation = "Whether to allow NSFW content, True or False" } times_to_run = { optional = false, example = 2, explanation = "used if you want to run multiple times. set to an int e.g. 4 or 29 or 1", default = 1, type = "int", nmin = 1, oob_error = "It's very hard to run something less than once." }
theme = { optional = false, default = "dark", example = "light", options = ["dark", opacity = { optional = false, example = 0.8, explanation = "Sets the opacity of the comments when overlayed over the background", default = 0.9, type = "float", nmin = 0, nmax = 1, oob_error = "The opacity HAS to be between 0 and 1", input_error = "The opacity HAS to be a decimal number between 0 and 1" }
"light", storymode = { optional = true, example = false, explanation = "not yet implemented", default = false, options = [true, false], type = "bool" }
], explanation = "sets the Reddit theme, either LIGHT or DARK" } background_choice = { optional = true, example = "minecraft", explanation = "Sets the background for the video", default = "minecraft", options = ["minecraft", "gta", "rocket-league", "motor-gta",] }
times_to_run = { optional = false, default = 1, example = 2, explanation = "used if you want to run multiple times. set to an int e.g. 4 or 29 or 1", type = "int", nmin = 1, oob_error = "It's very hard to run something less than once." } background_audio = { optional = true, example = 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.)", default = false, options = [true, false], type = "bool" }
opacity = { optional = false, default = 0.9, example = 0.8, explanation = "Sets the opacity of the comments when overlayed over the background", type = "float", nmin = 0, nmax = 1, oob_error = "The opacity HAS to be between 0 and 1", input_error = "The opacity HAS to be a decimal number between 0 and 1" }
storymode = { optional = true, type = "bool", default = false, example = false, options = [true,
false,
], explanation = "not yet implemented" }
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.)" }
[settings.tts] [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." } choice = { optional = false, example = "streamlabspolly", explanation = "The backend used for TTS generation. This can be left blank and you will be prompted to choose at runtime.", default = "", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", "blank"] }
aws_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for AWS Polly" } aws_polly_voice = { optional = false, example = "Matthew", explanation = "The voice used for AWS Polly", default = "Matthew" }
streamlabs_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for Streamlabs Polly" } streamlabs_polly_voice = { optional = false, example = "Matthew", explanation = "The voice used for Streamlabs Polly", default = "Matthew" }
tiktok_voice = { optional = false, default = "en_us_006", example = "en_us_006", explanation = "The voice used for TikTok TTS" } tiktok_voice = { optional = false, example = "en_us_006", explanation = "The voice used for TikTok TTS", default = "en_us_006" }
silence_duration = { optional = true, example = "0.1", explanation = "time in seconds between TTS comments", default = 0.3, type = "float" }

@ -65,7 +65,7 @@ class TikTok: # TikTok Text-to-Speech Wrapper
self.URI_BASE = ( self.URI_BASE = (
"https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker=" "https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker="
) )
self.max_chars = 300 self.max_chars = 270
self.voices = {"human": human, "nonhuman": nonhuman, "noneng": noneng} self.voices = {"human": human, "nonhuman": nonhuman, "noneng": noneng}
def run(self, text, filepath, random_voice: bool = False): def run(self, text, filepath, random_voice: bool = False):

@ -6,6 +6,11 @@ import re
# import sox # import sox
# from mutagen import MutagenError # from mutagen import MutagenError
# from mutagen.mp3 import MP3, HeaderNotFoundError # from mutagen.mp3 import MP3, HeaderNotFoundError
import os
import numpy as np
from moviepy.audio.AudioClip import AudioClip
from moviepy.audio.fx.volumex import volumex
import translators as ts import translators as ts
from rich.progress import track from rich.progress import track
from moviepy.editor import AudioFileClip, CompositeAudioClip, concatenate_audioclips from moviepy.editor import AudioFileClip, CompositeAudioClip, concatenate_audioclips
@ -13,7 +18,7 @@ from utils.console import print_step, print_substep
from utils.voice import sanitize_text from utils.voice import sanitize_text
from utils import settings from utils import settings
DEFUALT_MAX_LENGTH: int = 50 # video length variable DEFAULT_MAX_LENGTH: int = 45 # video length variable
class TTSEngine: class TTSEngine:
@ -35,7 +40,7 @@ class TTSEngine:
tts_module, tts_module,
reddit_object: dict, reddit_object: dict,
path: str = "assets/temp/mp3", path: str = "assets/temp/mp3",
max_length: int = DEFUALT_MAX_LENGTH, max_length: int = DEFAULT_MAX_LENGTH,
): ):
self.tts_module = tts_module() self.tts_module = tts_module()
self.reddit_object = reddit_object self.reddit_object = reddit_object
@ -76,30 +81,37 @@ class TTSEngine:
return self.length, idx return self.length, idx
def split_post(self, text: str, idx: int): def split_post(self, text: str, idx: int):
split_files = []
split_text = [ split_text = [
x.group().strip() x.group().strip()
for x in re.finditer(rf" *((.{{0,{self.tts_module.max_chars}}})(\.|.$))", text) for x in re.finditer(rf" *((.{{0,{self.tts_module.max_chars}}})(\.|.$))", text)
] ]
try:
silence_duration = settings.config["settings"]["tts"]["silence_duration"]
except ValueError:
silence_duration = 0.3
silence_long = AudioClip(make_frame=lambda t: np.sin(440 * 2 * np.pi * t), duration=silence_duration, fps=44100)
silence_long_new = volumex(silence_long, 0)
silence_long_new.write_audiofile(f"{self.path}/long_silence.mp3", fps=44100, verbose=False, logger=None)
idy = None idy = None
for idy, text_cut in enumerate(split_text): for idy, text_cut in enumerate(split_text):
# print(f"{idx}-{idy}: {text_cut}\n") # print(f"{idx}-{idy}: {text_cut}\n")
self.call_tts(f"{idx}-{idy}.part", text_cut) self.call_tts(f"{idx}-{idy}.part", text_cut)
split_files.append(AudioFileClip(f"{self.path}/{idx}-{idy}.part.mp3"))
CompositeAudioClip([concatenate_audioclips(split_files)]).write_audiofile(
f"{self.path}/{idx}.mp3", fps=44100, verbose=False, logger=None
)
for i in split_files: with open(f"{self.path}/list.txt", 'w') as f:
name = i.filename for newy in range(0, len(split_text)):
i.close() f.write("file " + f"'{idx}-{newy}.part.mp3'"+"\n")
Path(name).unlink() f.write("file " + f"'long_silence.mp3'"+"\n")
os.system("ffmpeg -f concat -y -hide_banner -loglevel panic -safe 0 " +
"-i " + f"{self.path}/list.txt " +
"-c copy " + f"{self.path}/{idx}.mp3")
# for i in range(0, idy + 1):
# print(f"Cleaning up {self.path}/{idx}-{i}.part.mp3")
# Path(f"{self.path}/{idx}-{i}.part.mp3").unlink() for i in range(0, idy + 1):
# print(f"Cleaning up {self.path}/{idx}-{i}.part.mp3")
Path(f"{self.path}/{idx}-{i}.part.mp3").unlink()
def call_tts(self, filename: str, text: str): def call_tts(self, filename: str, text: str):
self.tts_module.run(text=process_text(text), filepath=f"{self.path}/{filename}.mp3") self.tts_module.run(text=process_text(text), filepath=f"{self.path}/{filename}.mp3")

@ -62,16 +62,29 @@ def get_subreddit_threads(POST_ID: str):
if POST_ID: # would only be called if there are multiple queued posts if POST_ID: # would only be called if there are multiple queued posts
submission = reddit.submission(id=POST_ID) submission = reddit.submission(id=POST_ID)
elif ( elif (settings.config["reddit"]["thread"]["post_id"]
settings.config["reddit"]["thread"]["post_id"] and len(settings.config["reddit"]["thread"]["post_id"].split("+")) == 1):
and len(settings.config["reddit"]["thread"]["post_id"].split("+")) == 1
):
submission = reddit.submission(id=settings.config["reddit"]["thread"]["post_id"]) submission = reddit.submission(id=settings.config["reddit"]["thread"]["post_id"])
else:
threads = subreddit.hot(limit=25) comment_type = settings.config["reddit"]["thread"]["sort"]
submission = get_subreddit_undone(threads, subreddit)
try:
if str(comment_type) == "top":
threads = subreddit.top(limit=25)
elif str(comment_type) == "new":
threads = subreddit.new(limit=25)
elif str(comment_type) == "hot":
threads = subreddit.hot(limit=25)
elif str(comment_type) == "relevance":
threads = subreddit.relevance(limit=25)
else:
threads = subreddit.top(limit=25)
except AttributeError:
threads = subreddit.top(limit=25)
submission = get_subreddit_undone(threads, subreddit)
submission = check_done(submission) # double-checking submission = check_done(submission) # double-checking
if submission is None or not submission.num_comments: if submission is None or not submission.num_comments:
return get_subreddit_threads(POST_ID) # submission already done. rerun return get_subreddit_threads(POST_ID) # submission already done. rerun
upvotes = submission.score upvotes = submission.score

@ -9,3 +9,4 @@ requests==2.28.1
rich==12.4.4 rich==12.4.4
toml==0.10.2 toml==0.10.2
translators==5.3.1 translators==5.3.1
numpy~=1.23.0

@ -34,6 +34,9 @@ def get_subreddit_undone(submissions: list, subreddit):
if submission.stickied: if submission.stickied:
print_substep("This post was pinned by moderators. Skipping...") print_substep("This post was pinned by moderators. Skipping...")
continue continue
if submission.num_comments == 0:
print_substep("This post has 0 comments. Skipping...")
continue
return submission return submission
print("all submissions have been done going by top submission order") print("all submissions have been done going by top submission order")
return get_subreddit_undone( return get_subreddit_undone(

@ -38,6 +38,8 @@ def name_normalize(name: str) -> str:
name = re.sub(r"(\w+)\s?\/\s?(\w+)", r"\1 or \2", name) name = re.sub(r"(\w+)\s?\/\s?(\w+)", r"\1 or \2", name)
name = re.sub(r"\/", r"", name) name = re.sub(r"\/", r"", name)
name = name[0:140]
lang = settings.config["reddit"]["thread"]["post_lang"] lang = settings.config["reddit"]["thread"]["post_lang"]
if lang: if lang:
print_substep("Translating filename...") print_substep("Translating filename...")

Loading…
Cancel
Save