11 files changed
+96
-107
No files matched your search
+1
-1
@@ -244,4 +244,4 @@ video_creation/data/videos.json
|
||||
video_creation/data/envvars.txt
|
||||
|
||||
config.toml
|
||||
video_creation/data/videos.json
|
||||
*.exe
|
||||
@@ -14,7 +14,9 @@ from utils import settings
|
||||
from utils.console import print_step, print_substep
|
||||
from utils.voice import sanitize_text
|
||||
|
||||
DEFAULT_MAX_LENGTH: int = 50 # video length variable
|
||||
|
||||
DEFAULT_MAX_LENGTH: int = 50 # Video length variable, edit this on your own risk. It should work, but it's not supported
|
||||
|
||||
|
||||
|
||||
class TTSEngine:
|
||||
@@ -74,7 +76,7 @@ class TTSEngine:
|
||||
self.add_periods()
|
||||
self.call_tts("title", process_text(self.reddit_object["thread_title"]))
|
||||
# processed_text = ##self.reddit_object["thread_post"] != ""
|
||||
idx = None
|
||||
idx = 0
|
||||
|
||||
if settings.config["settings"]["storymode"]:
|
||||
if settings.config["settings"]["storymodemethod"] == 0:
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
import math
|
||||
import sys
|
||||
from logging import error
|
||||
from os import name
|
||||
from pathlib import Path
|
||||
from subprocess import Popen
|
||||
from typing import NoReturn
|
||||
|
||||
import ffmpeg
|
||||
from prawcore import ResponseException
|
||||
from utils.console import print_substep
|
||||
from reddit.subreddit import get_subreddit_threads
|
||||
@@ -59,11 +58,7 @@ def main(POST_ID=None) -> None:
|
||||
download_background_video(bg_config["video"])
|
||||
download_background_audio(bg_config["audio"])
|
||||
chop_background(bg_config, length, reddit_object)
|
||||
try:
|
||||
make_final_video(number_of_comments, length, reddit_object, bg_config)
|
||||
except ffmpeg.Error as e:
|
||||
print(e.stderr.decode("utf8"))
|
||||
exit(1)
|
||||
make_final_video(number_of_comments, length, reddit_object, bg_config)
|
||||
|
||||
|
||||
def run_many(times) -> None:
|
||||
@@ -75,31 +70,26 @@ def run_many(times) -> None:
|
||||
Popen("cls" if name == "nt" else "clear", shell=True).wait()
|
||||
|
||||
|
||||
def shutdown():
|
||||
try:
|
||||
redditid
|
||||
except NameError:
|
||||
print("Exiting...")
|
||||
exit()
|
||||
else:
|
||||
def shutdown() -> NoReturn:
|
||||
if "redditid" in globals():
|
||||
print_markdown("## Clearing temp files")
|
||||
cleanup(redditid)
|
||||
print("Exiting...")
|
||||
exit()
|
||||
|
||||
print("Exiting...")
|
||||
sys.exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.version_info.major != 3 or sys.version_info.minor != 10:
|
||||
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."
|
||||
)
|
||||
exit()
|
||||
ffmpeg_install() # install ffmpeg if not installed
|
||||
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()
|
||||
directory = Path().absolute()
|
||||
config = settings.check_toml(
|
||||
f"{directory}/utils/.config.template.toml", "config.toml"
|
||||
f"{directory}/utils/.config.template.toml", f"{directory}/config.toml"
|
||||
)
|
||||
config is False and exit()
|
||||
config is False and sys.exit()
|
||||
|
||||
if (
|
||||
not settings.config["settings"]["tts"]["tiktok_sessionid"]
|
||||
or settings.config["settings"]["tts"]["tiktok_sessionid"] == ""
|
||||
@@ -108,7 +98,7 @@ if __name__ == "__main__":
|
||||
"TikTok voice requires a sessionid! Check our documentation on how to obtain one.",
|
||||
"bold red",
|
||||
)
|
||||
exit()
|
||||
sys.exit()
|
||||
try:
|
||||
if config["reddit"]["thread"]["post_id"]:
|
||||
for index, post_id in enumerate(
|
||||
@@ -127,10 +117,8 @@ if __name__ == "__main__":
|
||||
except KeyboardInterrupt:
|
||||
shutdown()
|
||||
except ResponseException:
|
||||
# error for invalid credentials
|
||||
print_markdown("## Invalid credentials")
|
||||
print_markdown("Please check your credentials in the config.toml file")
|
||||
|
||||
shutdown()
|
||||
except Exception as err:
|
||||
config["settings"]["tts"]["tiktok_sessionid"] = "REDACTED"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
set VENV_DIR=.venv
|
||||
|
||||
if exist "%VENV_DIR%" (
|
||||
echo Activating virtual environment...
|
||||
call "%VENV_DIR%\Scripts\activate.bat"
|
||||
)
|
||||
|
||||
echo Running Python script...
|
||||
python main.py
|
||||
|
||||
if errorlevel 1 (
|
||||
echo An error occurred. Press any key to exit.
|
||||
pause >nul
|
||||
)
|
||||
@@ -14,7 +14,6 @@ max_comment_length = { default = 500, optional = false, nmin = 10, nmax = 10000,
|
||||
min_comment_length = { default = 1, optional = true, nmin = 0, nmax = 10000, type = "int", explanation = "min_comment_length number of characters a comment can have. default is 0", example = 50, oob_error = "the max comment length should be between 1 and 100" }
|
||||
post_lang = { default = "", optional = true, explanation = "The language you would like to translate to.", example = "es-cr", options = ['','af', 'ak', 'am', 'ar', 'as', 'ay', 'az', 'be', 'bg', 'bho', 'bm', 'bn', 'bs', 'ca', 'ceb', 'ckb', 'co', 'cs', 'cy', 'da', 'de', 'doi', 'dv', 'ee', 'el', 'en', 'en-US', 'eo', 'es', 'et', 'eu', 'fa', 'fi', 'fr', 'fy', 'ga', 'gd', 'gl', 'gn', 'gom', 'gu', 'ha', 'haw', 'hi', 'hmn', 'hr', 'ht', 'hu', 'hy', 'id', 'ig', 'ilo', 'is', 'it', 'iw', 'ja', 'jw', 'ka', 'kk', 'km', 'kn', 'ko', 'kri', 'ku', 'ky', 'la', 'lb', 'lg', 'ln', 'lo', 'lt', 'lus', 'lv', 'mai', 'mg', 'mi', 'mk', 'ml', 'mn', 'mni-Mtei', 'mr', 'ms', 'mt', 'my', 'ne', 'nl', 'no', 'nso', 'ny', 'om', 'or', 'pa', 'pl', 'ps', 'pt', 'qu', 'ro', 'ru', 'rw', 'sa', 'sd', 'si', 'sk', 'sl', 'sm', 'sn', 'so', 'sq', 'sr', 'st', 'su', 'sv', 'sw', 'ta', 'te', 'tg', 'th', 'ti', 'tk', 'tl', 'tr', 'ts', 'tt', 'ug', 'uk', 'ur', 'uz', 'vi', 'xh', 'yi', 'yo', 'zh-CN', 'zh-TW', 'zu'] }
|
||||
min_comments = { default = 20, optional = false, nmin = 10, 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" }
|
||||
#post_url = { optional = true, default = "", regex = "^https:\\/\\/www\\.reddit\\.com\\/r\\/[a-zA-Z0-9]+\\/comments\\/[a-zA-Z0-9]+\\/[a-zA-Z0-9_]+\\/$", explanation = "Not working currently Use if you want to use a specific post.", example = "https://www.reddit.com/r/buildapc/comments/yzh07p/have_you_switched_to_windows_11/" }
|
||||
|
||||
[ai]
|
||||
ai_similarity_enabled = {optional = true, option = [true, false], default = false, type = "bool", explanation = "Threads read from Reddit are sorted based on their similarity to the keywords given below"}
|
||||
@@ -25,7 +24,7 @@ allow_nsfw = { optional = false, type = "bool", default = false, example = false
|
||||
theme = { optional = false, default = "dark", example = "light", options = ["dark", "light", "transparent", ], explanation = "Sets the Reddit theme, either LIGHT or DARK. For story mode you can also use a transparent background." }
|
||||
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." }
|
||||
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" }
|
||||
transition = { optional = true, default = 0.2, example = 0.2, explanation = "Sets the transition time (in seconds) between the comments. Set to 0 if you want to disable it.", type = "float", nmin = 0, nmax = 2, oob_error = "The transition HAS to be between 0 and 2", input_error = "The opacity HAS to be a decimal number between 0 and 2" }
|
||||
#transition = { optional = true, default = 0.2, example = 0.2, explanation = "Sets the transition time (in seconds) between the comments. Set to 0 if you want to disable it.", type = "float", nmin = 0, nmax = 2, oob_error = "The transition HAS to be between 0 and 2", input_error = "The opacity HAS to be a decimal number between 0 and 2" }
|
||||
storymode = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Only read out title and post content, great for subreddits with stories" }
|
||||
storymodemethod= { optional = true, default = 1, example = 1, explanation = "Style that's used for the storymode. Set to 0 for single picture display in whole video, set to 1 for fancy looking video ", type = "int", nmin = 0, oob_error = "It's very hard to run something less than once.", options = [0, 1] }
|
||||
storymode_max_length = { optional = true, default = 1000, example = 1000, explanation = "Max length of the storymode video in characters. 200 characters are approximately 50 seconds.", type = "int", nmin = 1, oob_error = "It's very hard to make a video under a second." }
|
||||
@@ -54,5 +53,5 @@ tiktok_voice = { optional = true, default = "en_us_001", example = "en_us_006",
|
||||
tiktok_sessionid = { optional = true, example = "c76bcc3a7625abcc27b508c7db457ff1", explanation = "TikTok sessionid needed if you're using the TikTok TTS. Check documentation if you don't know how to obtain it." }
|
||||
python_voice = { optional = false, default = "1", example = "1", explanation = "The index of the system tts voices (can be downloaded externally, run ptt.py to find value, start from zero)" }
|
||||
py_voice_num = { optional = false, default = "2", example = "2", explanation = "The number of system voices (2 are pre-installed in Windows)" }
|
||||
silence_duration = { optional = true, example = "0.1", explanation = "Time in seconds between TTS comments", default = 0.3, type = "float" }
|
||||
#silence_duration = { optional = true, example = "0.1", explanation = "Time in seconds between TTS comments", default = 0.3, type = "float" }
|
||||
no_emojis = { optional = false, type = "bool", default = false, example = false, options = [true, false,], explanation = "Whether to remove emojis from the comments" }
|
||||
+7
-16
@@ -1,29 +1,20 @@
|
||||
import os
|
||||
from os.path import exists
|
||||
import shutil
|
||||
|
||||
|
||||
def _listdir(d): # listdir with full path
|
||||
return [os.path.join(d, f) for f in os.listdir(d)]
|
||||
|
||||
|
||||
def cleanup(id) -> int:
|
||||
def cleanup(reddit_id) -> int:
|
||||
"""Deletes all temporary assets in assets/temp
|
||||
|
||||
Returns:
|
||||
int: How many files were deleted
|
||||
"""
|
||||
if exists(f"../assets/temp/{id}/"):
|
||||
count = 0
|
||||
files = [f for f in os.listdir(f"../assets/temp/{id}/") if f.endswith(".mp4")]
|
||||
count += len(files)
|
||||
for f in files:
|
||||
os.remove(f"../assets/temp/{id}/{f}")
|
||||
REMOVE_DIRS = [f"../assets/temp/{id}/mp3/", f"../assets/temp/{id}/png/"]
|
||||
for d in REMOVE_DIRS:
|
||||
if exists(d):
|
||||
count += len(_listdir(d))
|
||||
for f in _listdir(d):
|
||||
os.remove(f)
|
||||
os.rmdir(d)
|
||||
os.rmdir(f"../assets/temp/{id}/")
|
||||
return count
|
||||
directory = f"../assets/temp/{reddit_id}/"
|
||||
if exists(directory):
|
||||
shutil.rmtree(directory)
|
||||
|
||||
return 1
|
||||
+11
-22
@@ -17,22 +17,16 @@ def ffmpeg_install_windows():
|
||||
os.rename("ffmpeg-master-latest-win64-gpl", "ffmpeg")
|
||||
# Move the files inside bin to the root
|
||||
for file in os.listdir("ffmpeg/bin"):
|
||||
os.rename(f"ffmpeg/bin/{file}", f"ffmpeg/{file}")
|
||||
os.rename(f"ffmpeg/bin/{file}", f"./{file}")
|
||||
os.rmdir("ffmpeg/bin")
|
||||
for file in os.listdir("ffmpeg/doc"):
|
||||
os.remove(f"ffmpeg/doc/{file}")
|
||||
os.rmdir("ffmpeg/doc")
|
||||
# Add to the path
|
||||
subprocess.run(
|
||||
'setx PATH "%PATH%;%CD%\\ffmpeg"',
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
print(
|
||||
"FFmpeg installed successfully! Please restart your computer and then re-run the program."
|
||||
)
|
||||
exit()
|
||||
os.remove("ffmpeg/LICENSE.txt")
|
||||
os.rmdir("ffmpeg/")
|
||||
|
||||
print("FFmpeg installed successfully! Please restart your computer and then re-run the program.")
|
||||
|
||||
except Exception as e:
|
||||
print(
|
||||
"An error occurred while trying to install FFmpeg. Please try again. Otherwise, please install FFmpeg manually and try again."
|
||||
@@ -79,17 +73,12 @@ def ffmpeg_install_mac():
|
||||
def ffmpeg_install():
|
||||
try:
|
||||
# Try to run the FFmpeg command
|
||||
subprocess.run(
|
||||
["ffmpeg", "-version"],
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
print(
|
||||
"FFmpeg is installed on this system! If you are seeing this error for the second time, restart your computer."
|
||||
)
|
||||
subprocess.run(['ffmpeg', '-version'], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
except FileNotFoundError as e:
|
||||
print("FFmpeg is not installed on this system.")
|
||||
# Check if there's ffmpeg.exe in the current directory
|
||||
if os.path.exists("./ffmpeg.exe"):
|
||||
print('FFmpeg is installed on this system! If you are seeing this error for the second time, restart your computer.')
|
||||
print('FFmpeg is not installed on this system.')
|
||||
resp = input(
|
||||
"We can try to automatically install it for you. Would you like to do that? (y/n): "
|
||||
)
|
||||
|
||||
+12
-9
@@ -1,4 +1,7 @@
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from typing import List
|
||||
|
||||
import spacy
|
||||
|
||||
@@ -7,25 +10,25 @@ from utils.voice import sanitize_text
|
||||
|
||||
|
||||
# working good
|
||||
def posttextparser(obj):
|
||||
text = re.sub("\n", "", obj)
|
||||
|
||||
def posttextparser(obj, *, tried: bool = False) -> List[str]:
|
||||
text: str = re.sub("\n", " ", obj)
|
||||
try:
|
||||
nlp = spacy.load("en_core_web_sm")
|
||||
except OSError:
|
||||
except OSError as e:
|
||||
if not tried:
|
||||
os.system("python -m spacy download en_core_web_sm")
|
||||
time.sleep(5)
|
||||
return posttextparser(obj, tried=True)
|
||||
print_step(
|
||||
"The spacy model can't load. You need to install it with the command \npython -m spacy download en_core_web_sm"
|
||||
)
|
||||
exit()
|
||||
"The spacy model can't load. You need to install it with the command \npython -m spacy download en_core_web_sm ")
|
||||
raise e
|
||||
|
||||
doc = nlp(text)
|
||||
|
||||
newtext: list = []
|
||||
|
||||
# to check for space str
|
||||
for line in doc.sents:
|
||||
if sanitize_text(line.text):
|
||||
newtext.append(line.text)
|
||||
# print(line)
|
||||
|
||||
return newtext
|
||||
@@ -26,8 +26,6 @@ def load_background_options():
|
||||
del background_options["video"]["__comment"]
|
||||
del background_options["audio"]["__comment"]
|
||||
|
||||
# Add position lambda function
|
||||
# (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position)
|
||||
for name in list(background_options["video"].keys()):
|
||||
pos = background_options["video"][name][3]
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ from PIL import Image
|
||||
from rich.console import Console
|
||||
from rich.progress import track
|
||||
|
||||
from utils import settings
|
||||
from utils.cleanup import cleanup
|
||||
from utils.console import print_step, print_substep
|
||||
from utils.thumbnail import create_thumbnail
|
||||
from utils.videos import save_data
|
||||
from utils import settings
|
||||
|
||||
import tempfile
|
||||
import threading
|
||||
@@ -97,9 +97,9 @@ def prepare_background(reddit_id: str, W: int, H: int) -> str:
|
||||
)
|
||||
try:
|
||||
output.run(quiet=True)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
exit()
|
||||
except ffmpeg.Error as e:
|
||||
print(e.stderr.decode("utf8"))
|
||||
exit(1)
|
||||
return output_path
|
||||
|
||||
|
||||
@@ -352,7 +352,7 @@ def make_final_video(
|
||||
text=text,
|
||||
x=f"(w-text_w)",
|
||||
y=f"(h-text_h)",
|
||||
fontsize=12,
|
||||
fontsize=5,
|
||||
fontcolor="White",
|
||||
fontfile=os.path.join("fonts", "Roboto-Regular.ttf"),
|
||||
)
|
||||
@@ -362,7 +362,7 @@ def make_final_video(
|
||||
|
||||
pbar = tqdm(total=100, desc="Progress: ", bar_format="{l_bar}{bar}", unit=" %")
|
||||
|
||||
def on_update_example(progress):
|
||||
def on_update_example(progress) -> None:
|
||||
status = round(progress * 100, 2)
|
||||
old_percentage = pbar.n
|
||||
pbar.update(status - old_percentage)
|
||||
@@ -399,25 +399,28 @@ def make_final_video(
|
||||
) # Prevent a error by limiting the path length, do not change this.
|
||||
print_step("Rendering the Only TTS Video 🎥")
|
||||
with ProgressFfmpeg(length, on_update_example) as progress:
|
||||
ffmpeg.output(
|
||||
background_clip,
|
||||
audio,
|
||||
path,
|
||||
f="mp4",
|
||||
**{
|
||||
"c:v": "h264",
|
||||
"b:v": "20M",
|
||||
"b:a": "192k",
|
||||
"threads": multiprocessing.cpu_count(),
|
||||
},
|
||||
).overwrite_output().global_args(
|
||||
"-progress", progress.output_file.name
|
||||
).run(
|
||||
quiet=True,
|
||||
overwrite_output=True,
|
||||
capture_stdout=False,
|
||||
capture_stderr=False,
|
||||
)
|
||||
try:
|
||||
ffmpeg.output(
|
||||
background_clip,
|
||||
audio,
|
||||
path,
|
||||
f="mp4",
|
||||
**{
|
||||
"c:v": "h264",
|
||||
"b:v": "20M",
|
||||
"b:a": "192k",
|
||||
"threads": multiprocessing.cpu_count(),
|
||||
},
|
||||
).overwrite_output().global_args("-progress", progress.output_file.name).run(
|
||||
quiet=True,
|
||||
overwrite_output=True,
|
||||
capture_stdout=False,
|
||||
capture_stderr=False,
|
||||
)
|
||||
except ffmpeg.Error as e:
|
||||
print(e.stderr.decode("utf8"))
|
||||
exit(1)
|
||||
|
||||
old_percentage = pbar.n
|
||||
pbar.update(100 - old_percentage)
|
||||
pbar.close()
|
||||
|
||||
@@ -237,7 +237,7 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
|
||||
page.goto(f'https://reddit.com{comment["comment_url"]}', timeout=0)
|
||||
|
||||
# translate code
|
||||
# translate code
|
||||
|
||||
if settings.config["reddit"]["thread"]["post_lang"]:
|
||||
comment_tl = translators.google(
|
||||
@@ -282,3 +282,4 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
browser.close()
|
||||
|
||||
print_substep("Screenshots downloaded Successfully.", style="bold green")
|
||||
|
||||
Reference in new issue
Block a user