From dcb42a4939111fd8b4572c2fd0b78845afe9dfca Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 16 Jun 2022 15:11:51 -0400 Subject: [PATCH 1/2] reworked the tts system --- TTS/GTTS.py | 7 +++++++ video_creation/TTSwrapper.py => TTS/TikTok.py | 2 +- TTS/swapper.py | 20 +++++++++++++++++++ main.py | 2 +- video_creation/voices.py | 20 +++++++++---------- 5 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 TTS/GTTS.py rename video_creation/TTSwrapper.py => TTS/TikTok.py (98%) create mode 100644 TTS/swapper.py diff --git a/TTS/GTTS.py b/TTS/GTTS.py new file mode 100644 index 0000000..20890ed --- /dev/null +++ b/TTS/GTTS.py @@ -0,0 +1,7 @@ +from gtts import gTTS + + +class GTTS: + def tts(self, req_text: str = "Google Text To Speech", filename: str = "title.mp3", random_speaker=False, censer=False): + tts = gTTS(text=req_text, lang="en", slow=False) + tts.save(f"{filename}") diff --git a/video_creation/TTSwrapper.py b/TTS/TikTok.py similarity index 98% rename from video_creation/TTSwrapper.py rename to TTS/TikTok.py index fc104dc..9ec9341 100644 --- a/video_creation/TTSwrapper.py +++ b/TTS/TikTok.py @@ -65,7 +65,7 @@ noneng = [ # 'ok': ['en_au_002', 'en_uk_001']} # less en_us_stormtrooper more less en_us_rocket en_us_ghostface -class TTTTSWrapper: # TikTok Text-to-Speech Wrapper +class TikTok: # TikTok Text-to-Speech Wrapper def __init__(self): self.URI_BASE = "https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker=" diff --git a/TTS/swapper.py b/TTS/swapper.py new file mode 100644 index 0000000..5b01a30 --- /dev/null +++ b/TTS/swapper.py @@ -0,0 +1,20 @@ +from os import getenv + +from dotenv import load_dotenv + +from TTS.GTTS import GTTS +from TTS.TikTok import TikTok + +CHOICE_DIR = { + 'tiktok': TikTok, + 'gtts': GTTS +} + +class TTS: + def __new__(cls): + load_dotenv() + CHOICE = getenv('TTsChoice').casefold() + valid_keys = [key.lower() for key in CHOICE_DIR.keys()] + if CHOICE not in valid_keys: + raise ValueError(f'{CHOICE} is not valid. Please use one of these {valid_keys} options') + return CHOICE_DIR.get(CHOICE)() diff --git a/main.py b/main.py index 4f74a74..1c6316d 100755 --- a/main.py +++ b/main.py @@ -23,7 +23,7 @@ print(banner) load_dotenv() # Modified by JasonLovesDoggo 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. You can find solutions to many common problems in the [Documentation](https://luka-hietala.gitbook.io/documentation-for-the-reddit-bot/)" ) time.sleep(1) diff --git a/video_creation/voices.py b/video_creation/voices.py index 7912314..76c4dc3 100644 --- a/video_creation/voices.py +++ b/video_creation/voices.py @@ -1,20 +1,19 @@ #!/usr/bin/env python3 -from gtts import gTTS +from os import getenv from pathlib import Path -from os import getenv, name import sox from mutagen import MutagenError from mutagen.mp3 import MP3, HeaderNotFoundError -from rich.progress import track from rich.console import Console +from rich.progress import track + +from TTS.swapper import TTS console = Console() -import re from utils.console import print_step, print_substep from utils.voice import sanitize_text -from video_creation.TTSwrapper import TTTTSWrapper VIDEO_LENGTH: int = 40 # secs @@ -29,9 +28,8 @@ def save_text_to_mp3(reddit_obj): # Create a folder for the mp3 files. Path("assets/temp/mp3").mkdir(parents=True, exist_ok=True) - - ttttsw = TTTTSWrapper() # tiktok text to speech wrapper - ttttsw.tts( + TextToSpeech = TTS() + TextToSpeech.tts( sanitize_text(reddit_obj["thread_title"]), filename=f"assets/temp/mp3/title.mp3", random_speaker=False, @@ -41,19 +39,19 @@ def save_text_to_mp3(reddit_obj): except HeaderNotFoundError: # note to self AudioFileClip length += sox.file_info.duration(f"assets/temp/mp3/title.mp3") if getenv("STORYMODE").casefold() == "true": - ttttsw.tts( + TextToSpeech.tts( sanitize_text(reddit_obj["thread_content"]), filename=f"assets/temp/mp3/story_content.mp3", random_speaker=False, ) - #'story_content' + # 'story_content' com = 0 for comment in track((reddit_obj["comments"]), "Saving..."): # ! Stop creating mp3 files if the length is greater than VIDEO_LENGTH seconds. This can be longer, but this is just a good_voices starting point if length > VIDEO_LENGTH: break - ttttsw.tts( + TextToSpeech.tts( sanitize_text(comment["comment_body"]), filename=f"assets/temp/mp3/{com}.mp3", random_speaker=False, From d1faf4824c764eedea8a466a27027f95bc95ff95 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 16 Jun 2022 15:17:57 -0400 Subject: [PATCH 2/2] refactored using black --- TTS/GTTS.py | 8 +++++++- TTS/TikTok.py | 14 +++++++------- TTS/swapper.py | 12 ++++++------ utils/config.py | 14 ++++++++++++-- utils/loader.py | 1 - utils/subreddit.py | 1 + utils/videos.py | 4 +++- video_creation/background.py | 7 ++++--- video_creation/final_video.py | 17 +++++++---------- 9 files changed, 47 insertions(+), 31 deletions(-) diff --git a/TTS/GTTS.py b/TTS/GTTS.py index 20890ed..9100dd8 100644 --- a/TTS/GTTS.py +++ b/TTS/GTTS.py @@ -2,6 +2,12 @@ from gtts import gTTS class GTTS: - def tts(self, req_text: str = "Google Text To Speech", filename: str = "title.mp3", random_speaker=False, censer=False): + def tts( + self, + req_text: str = "Google Text To Speech", + filename: str = "title.mp3", + random_speaker=False, + censer=False, + ): tts = gTTS(text=req_text, lang="en", slow=False) tts.save(f"{filename}") diff --git a/TTS/TikTok.py b/TTS/TikTok.py index 9ec9341..2024ec9 100644 --- a/TTS/TikTok.py +++ b/TTS/TikTok.py @@ -70,11 +70,11 @@ class TikTok: # TikTok Text-to-Speech Wrapper self.URI_BASE = "https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker=" def tts( - self, - req_text: str = "TikTok Text To Speech", - filename: str = "title.mp3", - random_speaker: bool = False, - censer=False, + self, + req_text: str = "TikTok Text To Speech", + filename: str = "title.mp3", + random_speaker: bool = False, + censer=False, ): req_text = req_text.replace("+", "plus").replace(" ", "+").replace("&", "and") if censer: @@ -92,7 +92,7 @@ class TikTok: # TikTok Text-to-Speech Wrapper audio_clips = [] cbn = sox.Combiner() - #cbn.set_input_format(file_type=["mp3" for _ in chunks]) + # cbn.set_input_format(file_type=["mp3" for _ in chunks]) chunkId = 0 for chunk in chunks: @@ -130,7 +130,7 @@ class TikTok: # TikTok Text-to-Speech Wrapper for clip in audio_clips: i = audio_clips.index(clip) # get the index of the clip audio_clips = ( - audio_clips[:i] + [AudioFileClip(clip)] + audio_clips[i + 1:] + audio_clips[:i] + [AudioFileClip(clip)] + audio_clips[i + 1 :] ) # replace the clip with an AudioFileClip audio_concat = concatenate_audioclips(audio_clips) audio_composite = CompositeAudioClip([audio_concat]) diff --git a/TTS/swapper.py b/TTS/swapper.py index 5b01a30..cd18223 100644 --- a/TTS/swapper.py +++ b/TTS/swapper.py @@ -5,16 +5,16 @@ from dotenv import load_dotenv from TTS.GTTS import GTTS from TTS.TikTok import TikTok -CHOICE_DIR = { - 'tiktok': TikTok, - 'gtts': GTTS -} +CHOICE_DIR = {"tiktok": TikTok, "gtts": GTTS} + class TTS: def __new__(cls): load_dotenv() - CHOICE = getenv('TTsChoice').casefold() + CHOICE = getenv("TTsChoice").casefold() valid_keys = [key.lower() for key in CHOICE_DIR.keys()] if CHOICE not in valid_keys: - raise ValueError(f'{CHOICE} is not valid. Please use one of these {valid_keys} options') + raise ValueError( + f"{CHOICE} is not valid. Please use one of these {valid_keys} options" + ) return CHOICE_DIR.get(CHOICE)() diff --git a/utils/config.py b/utils/config.py index 78beb99..000b615 100644 --- a/utils/config.py +++ b/utils/config.py @@ -2,8 +2,18 @@ from dotenv import dotenv_values -DEFAULTS = {'SUBREDDIT': "AskReddit", 'ALLOW_NSFW': "False", 'POST_ID': "", 'THEME': "DARK", 'REDDIT_2FA': "no", - 'TIMES_TO_RUN': "", 'MAX_COMMENT_LENGTH': "500", 'OPACITY': "1", 'VOICE': "en_us_001", 'STORYMODE': "False"} +DEFAULTS = { + "SUBREDDIT": "AskReddit", + "ALLOW_NSFW": "False", + "POST_ID": "", + "THEME": "DARK", + "REDDIT_2FA": "no", + "TIMES_TO_RUN": "", + "MAX_COMMENT_LENGTH": "500", + "OPACITY": "1", + "VOICE": "en_us_001", + "STORYMODE": "False", +} class Config: diff --git a/utils/loader.py b/utils/loader.py index 46c40fe..f23a716 100644 --- a/utils/loader.py +++ b/utils/loader.py @@ -1,4 +1,3 @@ - # Okay, have to admit. This code is from StackOverflow. It's so efficient, that it's probably the best way to do it. # Although, it is edited to use less threads. diff --git a/utils/subreddit.py b/utils/subreddit.py index 7a7dca0..035aed7 100644 --- a/utils/subreddit.py +++ b/utils/subreddit.py @@ -3,6 +3,7 @@ import json from os import getenv from utils.console import print_substep + def get_subreddit_undone(submissions: List, subreddit): """ recursively checks if the top submission in the list was already done. diff --git a/utils/videos.py b/utils/videos.py index a7b2012..51a2704 100755 --- a/utils/videos.py +++ b/utils/videos.py @@ -4,7 +4,9 @@ from os import getenv from utils.console import print_step -def check_done(redditobj): # don't set this to be run anyplace that isn't subreddit.py bc of inspect stack +def check_done( + redditobj, +): # don't set this to be run anyplace that isn't subreddit.py bc of inspect stack """params: reddit_object: The Reddit Object you received in askreddit.py""" with open("./video_creation/data/videos.json", "r") as done_vids_raw: diff --git a/video_creation/background.py b/video_creation/background.py index 533db04..e8f8ad1 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -7,6 +7,7 @@ from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from moviepy.editor import VideoFileClip from utils.console import print_step, print_substep + def get_start_and_end_times(video_length, length_of_clip): random_time = randrange(180, int(length_of_clip) - int(video_length)) return random_time, random_time + video_length @@ -17,11 +18,11 @@ def download_background(): Path("./assets/backgrounds/").mkdir(parents=True, exist_ok=True) background_options = [ # uri , filename , credit ("https://www.youtube.com/watch?v=n_Dv4JMiwK8", "parkour.mp4", "bbswitzer"), - #( + # ( # "https://www.youtube.com/watch?v=2X9QGY__0II", # "rocket_league.mp4", # "Orbital Gameplay", - #), + # ), ] # note: make sure the file name doesn't include an - in it if not len(listdir("./assets/backgrounds")) <= len( @@ -32,7 +33,7 @@ def download_background(): ) print_substep("Downloading the backgrounds videos... please be patient 🙏 ") for uri, filename, credit in background_options: - if Path(f'assets/backgrounds/{credit}-{filename}').is_file(): + if Path(f"assets/backgrounds/{credit}-{filename}").is_file(): continue # adds check to see if file exists before downloading print_substep(f"Downloading {filename} from {uri}") YouTube(uri).streams.filter(res="1080p").first().download( diff --git a/video_creation/final_video.py b/video_creation/final_video.py index f9550da..3a199f7 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -88,7 +88,7 @@ def make_final_video(number_of_clips, length): .resize(width=W - 100) .set_opacity(float(opacity)), ) - #if os.path.exists("assets/mp3/posttext.mp3"): + # if os.path.exists("assets/mp3/posttext.mp3"): # image_clips.insert( # 0, # ImageClip("assets/png/title.png") @@ -97,16 +97,13 @@ def make_final_video(number_of_clips, length): # .resize(width=W - 100) # .set_opacity(float(opacity)), # ) - #else: + # else: image_clips.insert( - 0, - ImageClip("assets/temp/png/title.png") - .set_duration(audio_clips[0].duration) - #.set_duration(audixc vcco_clips[0].duration) - .set_position("center") - .resize(width=W - 100) - .set_opacity(float(opacity)), - ) + 0, + ImageClip("assets/temp/png/title.png").set_duration(audio_clips[0].duration) + # .set_duration(audixc vcco_clips[0].duration) + .set_position("center").resize(width=W - 100).set_opacity(float(opacity)), + ) image_concat = concatenate_videoclips(image_clips).set_position( ("center", "center") )