Version 3.2.1
This commit is contained in:
27 files changed
+193
-343
No files matched your search
@@ -6,7 +6,7 @@
|
||||
name: autoblack
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
branches: ["develop"]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -24,9 +24,9 @@ jobs:
|
||||
if: failure()
|
||||
run: |
|
||||
black . --line-length 101
|
||||
git config --global user.name 'autoblack'
|
||||
git config --global user.email 'jasoncameron.all@gmail.com'
|
||||
git config --global user.name github-actions
|
||||
git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com
|
||||
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
|
||||
git checkout $GITHUB_HEAD_REF
|
||||
git commit -am "fixup: Format Python code with Black"
|
||||
git push origin HEAD:master
|
||||
git push origin HEAD:develop
|
||||
@@ -82,9 +82,7 @@ def settings():
|
||||
# Change settings
|
||||
config = gui.modify_settings(data, config_load, checks)
|
||||
|
||||
return render_template(
|
||||
"settings.html", file="config.toml", data=config, checks=checks
|
||||
)
|
||||
return render_template("settings.html", file="config.toml", data=config, checks=checks)
|
||||
|
||||
|
||||
# Make videos.json accessible
|
||||
|
||||
+1
-3
@@ -86,9 +86,7 @@ class TikTok:
|
||||
"Cookie": f"sessionid={settings.config['settings']['tts']['tiktok_sessionid']}",
|
||||
}
|
||||
|
||||
self.URI_BASE = (
|
||||
"https://api16-normal-c-useast1a.tiktokv.com/media/api/text/speech/invoke/"
|
||||
)
|
||||
self.URI_BASE = "https://api16-normal-c-useast1a.tiktokv.com/media/api/text/speech/invoke/"
|
||||
self.max_chars = 200
|
||||
|
||||
self._session = requests.Session()
|
||||
|
||||
+1
-3
@@ -41,9 +41,7 @@ class AWSPolly:
|
||||
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()
|
||||
voice = str(settings.config["settings"]["tts"]["aws_polly_voice"]).capitalize()
|
||||
try:
|
||||
# Request speech synthesis
|
||||
response = polly.synthesize_speech(
|
||||
|
||||
+2
-6
@@ -26,9 +26,7 @@ class elevenlabs:
|
||||
if random_voice:
|
||||
voice = self.randomvoice()
|
||||
else:
|
||||
voice = str(
|
||||
settings.config["settings"]["tts"]["elevenlabs_voice_name"]
|
||||
).capitalize()
|
||||
voice = str(settings.config["settings"]["tts"]["elevenlabs_voice_name"]).capitalize()
|
||||
|
||||
if settings.config["settings"]["tts"]["elevenlabs_api_key"]:
|
||||
api_key = settings.config["settings"]["tts"]["elevenlabs_api_key"]
|
||||
@@ -37,9 +35,7 @@ class elevenlabs:
|
||||
"You didn't set an Elevenlabs API key! Please set the config variable ELEVENLABS_API_KEY to a valid API key."
|
||||
)
|
||||
|
||||
audio = generate(
|
||||
api_key=api_key, text=text, voice=voice, model="eleven_multilingual_v1"
|
||||
)
|
||||
audio = generate(api_key=api_key, text=text, voice=voice, model="eleven_multilingual_v1")
|
||||
save(audio=audio, filename=filepath)
|
||||
|
||||
def randomvoice(self):
|
||||
|
||||
+8
-15
@@ -15,8 +15,9 @@ from utils.console import print_step, print_substep
|
||||
from utils.voice import sanitize_text
|
||||
|
||||
|
||||
DEFAULT_MAX_LENGTH: int = 50 # Video length variable, edit this on your own risk. It should work, but it's not supported
|
||||
|
||||
DEFAULT_MAX_LENGTH: int = (
|
||||
50 # Video length variable, edit this on your own risk. It should work, but it's not supported
|
||||
)
|
||||
|
||||
|
||||
class TTSEngine:
|
||||
@@ -59,9 +60,7 @@ class TTSEngine:
|
||||
comment["comment_body"] = re.sub(regex_urls, " ", comment["comment_body"])
|
||||
comment["comment_body"] = comment["comment_body"].replace("\n", ". ")
|
||||
comment["comment_body"] = re.sub(r"\bAI\b", "A.I", comment["comment_body"])
|
||||
comment["comment_body"] = re.sub(
|
||||
r"\bAGI\b", "A.G.I", comment["comment_body"]
|
||||
)
|
||||
comment["comment_body"] = re.sub(r"\bAGI\b", "A.G.I", comment["comment_body"])
|
||||
if comment["comment_body"][-1] != ".":
|
||||
comment["comment_body"] += "."
|
||||
comment["comment_body"] = comment["comment_body"].replace(". . .", ".")
|
||||
@@ -83,17 +82,13 @@ class TTSEngine:
|
||||
if len(self.reddit_object["thread_post"]) > self.tts_module.max_chars:
|
||||
self.split_post(self.reddit_object["thread_post"], "postaudio")
|
||||
else:
|
||||
self.call_tts(
|
||||
"postaudio", process_text(self.reddit_object["thread_post"])
|
||||
)
|
||||
self.call_tts("postaudio", process_text(self.reddit_object["thread_post"]))
|
||||
elif settings.config["settings"]["storymodemethod"] == 1:
|
||||
for idx, text in track(enumerate(self.reddit_object["thread_post"])):
|
||||
self.call_tts(f"postaudio-{idx}", process_text(text))
|
||||
|
||||
else:
|
||||
for idx, comment in track(
|
||||
enumerate(self.reddit_object["comments"]), "Saving..."
|
||||
):
|
||||
for idx, comment in track(enumerate(self.reddit_object["comments"]), "Saving..."):
|
||||
# ! Stop creating mp3 files if the length is greater than max length.
|
||||
if self.length > self.max_length and idx > 1:
|
||||
self.length -= self.last_clip_length
|
||||
@@ -176,9 +171,7 @@ class TTSEngine:
|
||||
fps=44100,
|
||||
)
|
||||
silence = volumex(silence, 0)
|
||||
silence.write_audiofile(
|
||||
f"{self.path}/silence.mp3", fps=44100, verbose=False, logger=None
|
||||
)
|
||||
silence.write_audiofile(f"{self.path}/silence.mp3", fps=44100, verbose=False, logger=None)
|
||||
|
||||
|
||||
def process_text(text: str, clean: bool = True):
|
||||
@@ -186,6 +179,6 @@ def process_text(text: str, clean: bool = True):
|
||||
new_text = sanitize_text(text) if clean else text
|
||||
if lang:
|
||||
print_substep("Translating Text...")
|
||||
translated_text = translators.google(text, to_language=lang)
|
||||
translated_text = translators.translate_text(text, translator="google", to_language=lang)
|
||||
new_text = sanitize_text(translated_text)
|
||||
return new_text
|
||||
+1
-3
@@ -21,9 +21,7 @@ class pyttsx:
|
||||
if voice_id == "" or voice_num == "":
|
||||
voice_id = 2
|
||||
voice_num = 3
|
||||
raise ValueError(
|
||||
"set pyttsx values to a valid value, switching to defaults"
|
||||
)
|
||||
raise ValueError("set pyttsx values to a valid value, switching to defaults")
|
||||
else:
|
||||
voice_id = int(voice_id)
|
||||
voice_num = int(voice_num)
|
||||
|
||||
@@ -42,9 +42,7 @@ class StreamlabsPolly:
|
||||
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()
|
||||
voice = str(settings.config["settings"]["tts"]["streamlabs_polly_voice"]).capitalize()
|
||||
body = {"voice": voice, "text": text, "service": "polly"}
|
||||
response = requests.post(self.url, data=body)
|
||||
if not check_ratelimit(response):
|
||||
|
||||
@@ -25,7 +25,7 @@ from video_creation.screenshot_downloader import get_screenshots_of_reddit_posts
|
||||
from video_creation.voices import save_text_to_mp3
|
||||
from utils.ffmpeg_install import ffmpeg_install
|
||||
|
||||
__VERSION__ = "3.2"
|
||||
__VERSION__ = "3.2.1"
|
||||
|
||||
print(
|
||||
"""
|
||||
@@ -74,14 +74,16 @@ def shutdown() -> NoReturn:
|
||||
if "redditid" in globals():
|
||||
print_markdown("## Clearing temp files")
|
||||
cleanup(redditid)
|
||||
|
||||
|
||||
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.")
|
||||
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()
|
||||
@@ -89,7 +91,7 @@ if __name__ == "__main__":
|
||||
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"] == ""
|
||||
@@ -101,9 +103,7 @@ if __name__ == "__main__":
|
||||
sys.exit()
|
||||
try:
|
||||
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
|
||||
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("+"))}'
|
||||
|
||||
+6
-19
@@ -24,9 +24,7 @@ def get_subreddit_threads(POST_ID: str):
|
||||
|
||||
content = {}
|
||||
if settings.config["reddit"]["creds"]["2fa"]:
|
||||
print(
|
||||
"\nEnter your two-factor authentication code from your authenticator app.\n"
|
||||
)
|
||||
print("\nEnter your two-factor authentication code from your authenticator app.\n")
|
||||
code = input("> ")
|
||||
print()
|
||||
pw = settings.config["reddit"]["creds"]["password"]
|
||||
@@ -59,9 +57,7 @@ def get_subreddit_threads(POST_ID: str):
|
||||
]: # note to user. you can have multiple subreddits via reddit.subreddit("redditdev+learnpython")
|
||||
try:
|
||||
subreddit = reddit.subreddit(
|
||||
re.sub(
|
||||
r"r\/", "", input("What subreddit would you like to pull from? ")
|
||||
)
|
||||
re.sub(r"r\/", "", input("What subreddit would you like to pull from? "))
|
||||
# removes the r/ from the input
|
||||
)
|
||||
except ValueError:
|
||||
@@ -71,9 +67,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 (
|
||||
str(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)
|
||||
|
||||
@@ -84,12 +78,8 @@ def get_subreddit_threads(POST_ID: str):
|
||||
settings.config["reddit"]["thread"]["post_id"]
|
||||
and len(str(settings.config["reddit"]["thread"]["post_id"]).split("+")) == 1
|
||||
):
|
||||
submission = reddit.submission(
|
||||
id=settings.config["reddit"]["thread"]["post_id"]
|
||||
)
|
||||
elif settings.config["ai"][
|
||||
"ai_similarity_enabled"
|
||||
]: # ai sorting based on comparison
|
||||
submission = reddit.submission(id=settings.config["reddit"]["thread"]["post_id"])
|
||||
elif settings.config["ai"]["ai_similarity_enabled"]: # ai sorting based on comparison
|
||||
threads = subreddit.hot(limit=50)
|
||||
keywords = settings.config["ai"]["ai_similarity_keywords"].split(",")
|
||||
keywords = [keyword.strip() for keyword in keywords]
|
||||
@@ -107,10 +97,7 @@ def get_subreddit_threads(POST_ID: str):
|
||||
if submission is None:
|
||||
return get_subreddit_threads(POST_ID) # submission already done. rerun
|
||||
|
||||
elif (
|
||||
not submission.num_comments
|
||||
and settings.config["settings"]["storymode"] == "false"
|
||||
):
|
||||
elif not submission.num_comments and settings.config["settings"]["storymode"] == "false":
|
||||
print_substep("No comments found. Skipping.")
|
||||
exit()
|
||||
|
||||
|
||||
+4
-4
@@ -6,18 +6,18 @@ playwright==1.34.0
|
||||
praw==7.7.0
|
||||
prawcore~=2.3.0
|
||||
requests==2.31.0
|
||||
rich==13.3.5
|
||||
rich==13.4.1
|
||||
toml==0.10.2
|
||||
translators==5.7.6
|
||||
pyttsx3==2.90
|
||||
Pillow==9.5.0
|
||||
tomlkit==0.11.8
|
||||
Flask==2.3.2
|
||||
Flask==2.3.3
|
||||
clean-text==0.6.0
|
||||
unidecode==1.3.6
|
||||
spacy==3.5.3
|
||||
torch==2.0.1
|
||||
transformers==4.29.2
|
||||
ffmpeg-python==0.2.0
|
||||
elevenlabs==0.2.16
|
||||
yt-dlp==2023.3.4
|
||||
elevenlabs==0.2.17
|
||||
yt-dlp==2023.7.6
|
||||
+5
-15
@@ -5,12 +5,8 @@ import torch
|
||||
|
||||
# Mean Pooling - Take attention mask into account for correct averaging
|
||||
def mean_pooling(model_output, attention_mask):
|
||||
token_embeddings = model_output[
|
||||
0
|
||||
] # First element of model_output contains all token embeddings
|
||||
input_mask_expanded = (
|
||||
attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
|
||||
)
|
||||
token_embeddings = model_output[0] # First element of model_output contains all token embeddings
|
||||
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
|
||||
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(
|
||||
input_mask_expanded.sum(1), min=1e-9
|
||||
)
|
||||
@@ -36,19 +32,13 @@ def sort_by_similarity(thread_objects, keywords):
|
||||
)
|
||||
with torch.no_grad():
|
||||
threads_embeddings = model(**encoded_threads)
|
||||
threads_embeddings = mean_pooling(
|
||||
threads_embeddings, encoded_threads["attention_mask"]
|
||||
)
|
||||
threads_embeddings = mean_pooling(threads_embeddings, encoded_threads["attention_mask"])
|
||||
|
||||
# Keywords inference
|
||||
encoded_keywords = tokenizer(
|
||||
keywords, padding=True, truncation=True, return_tensors="pt"
|
||||
)
|
||||
encoded_keywords = tokenizer(keywords, padding=True, truncation=True, return_tensors="pt")
|
||||
with torch.no_grad():
|
||||
keywords_embeddings = model(**encoded_keywords)
|
||||
keywords_embeddings = mean_pooling(
|
||||
keywords_embeddings, encoded_keywords["attention_mask"]
|
||||
)
|
||||
keywords_embeddings = mean_pooling(keywords_embeddings, encoded_keywords["attention_mask"])
|
||||
|
||||
# Compare every keyword w/ every thread embedding
|
||||
threads_embeddings_tensor = torch.tensor(threads_embeddings)
|
||||
|
||||
+3
-14
@@ -49,10 +49,7 @@ def handle_input(
|
||||
optional=False,
|
||||
):
|
||||
if optional:
|
||||
console.print(
|
||||
message
|
||||
+ "\n[green]This is an optional value. Do you want to skip it? (y/n)"
|
||||
)
|
||||
console.print(message + "\n[green]This is an optional value. Do you want to skip it? (y/n)")
|
||||
if input().casefold().startswith("y"):
|
||||
return default if default is not NotImplemented else ""
|
||||
if default is not NotImplemented:
|
||||
@@ -86,11 +83,7 @@ def handle_input(
|
||||
console.print("[red]" + err_message)
|
||||
continue
|
||||
elif match != "" and re.match(match, user_input) is None:
|
||||
console.print(
|
||||
"[red]"
|
||||
+ err_message
|
||||
+ "\nAre you absolutely sure it's correct?(y/n)"
|
||||
)
|
||||
console.print("[red]" + err_message + "\nAre you absolutely sure it's correct?(y/n)")
|
||||
if input().casefold().startswith("y"):
|
||||
break
|
||||
continue
|
||||
@@ -123,9 +116,5 @@ def handle_input(
|
||||
if user_input in options:
|
||||
return user_input
|
||||
console.print(
|
||||
"[red bold]"
|
||||
+ err_message
|
||||
+ "\nValid options are: "
|
||||
+ ", ".join(map(str, options))
|
||||
+ "."
|
||||
"[red bold]" + err_message + "\nValid options are: " + ", ".join(map(str, options)) + "."
|
||||
)
|
||||
+52
-23
@@ -1,3 +1,4 @@
|
||||
import zipfile
|
||||
import requests
|
||||
import os
|
||||
import subprocess
|
||||
@@ -5,28 +6,54 @@ import subprocess
|
||||
|
||||
def ffmpeg_install_windows():
|
||||
try:
|
||||
zip = "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip"
|
||||
r = requests.get(zip)
|
||||
with open("ffmpeg.zip", "wb") as f:
|
||||
f.write(r.content)
|
||||
import zipfile
|
||||
ffmpeg_url = (
|
||||
"https://github.com/GyanD/codexffmpeg/releases/download/6.0/ffmpeg-6.0-full_build.zip"
|
||||
)
|
||||
ffmpeg_zip_filename = "ffmpeg.zip"
|
||||
ffmpeg_extracted_folder = "ffmpeg"
|
||||
|
||||
with zipfile.ZipFile("ffmpeg.zip", "r") as zip_ref:
|
||||
# Check if ffmpeg.zip already exists
|
||||
if os.path.exists(ffmpeg_zip_filename):
|
||||
os.remove(ffmpeg_zip_filename)
|
||||
|
||||
# Download FFmpeg
|
||||
r = requests.get(ffmpeg_url)
|
||||
with open(ffmpeg_zip_filename, "wb") as f:
|
||||
f.write(r.content)
|
||||
|
||||
# Check if the extracted folder already exists
|
||||
if os.path.exists(ffmpeg_extracted_folder):
|
||||
# Remove existing extracted folder and its contents
|
||||
for root, dirs, files in os.walk(ffmpeg_extracted_folder, topdown=False):
|
||||
for file in files:
|
||||
os.remove(os.path.join(root, file))
|
||||
for dir in dirs:
|
||||
os.rmdir(os.path.join(root, dir))
|
||||
os.rmdir(ffmpeg_extracted_folder)
|
||||
|
||||
# Extract FFmpeg
|
||||
with zipfile.ZipFile(ffmpeg_zip_filename, "r") as zip_ref:
|
||||
zip_ref.extractall()
|
||||
os.remove("ffmpeg.zip")
|
||||
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"./{file}")
|
||||
os.rmdir("ffmpeg/bin")
|
||||
for file in os.listdir("ffmpeg/doc"):
|
||||
os.remove(f"ffmpeg/doc/{file}")
|
||||
os.rmdir("ffmpeg/doc")
|
||||
os.remove("ffmpeg/LICENSE.txt")
|
||||
os.rmdir("ffmpeg/")
|
||||
|
||||
print("FFmpeg installed successfully! Please restart your computer and then re-run the program.")
|
||||
# Rename and move files
|
||||
os.rename(f"{ffmpeg_extracted_folder}-6.0-full_build", ffmpeg_extracted_folder)
|
||||
for file in os.listdir(os.path.join(ffmpeg_extracted_folder, "bin")):
|
||||
os.rename(os.path.join(ffmpeg_extracted_folder, "bin", file), os.path.join(".", file))
|
||||
os.rmdir(os.path.join(ffmpeg_extracted_folder, "bin"))
|
||||
for file in os.listdir(os.path.join(ffmpeg_extracted_folder, "doc")):
|
||||
os.remove(os.path.join(ffmpeg_extracted_folder, "doc", file))
|
||||
for file in os.listdir(os.path.join(ffmpeg_extracted_folder, "presets")):
|
||||
os.remove(os.path.join(ffmpeg_extracted_folder, "presets", file))
|
||||
os.rmdir(os.path.join(ffmpeg_extracted_folder, "presets"))
|
||||
os.rmdir(os.path.join(ffmpeg_extracted_folder, "doc"))
|
||||
os.remove(os.path.join(ffmpeg_extracted_folder, "LICENSE"))
|
||||
os.remove(os.path.join(ffmpeg_extracted_folder, "README.txt"))
|
||||
os.rmdir(ffmpeg_extracted_folder)
|
||||
|
||||
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."
|
||||
@@ -73,12 +100,16 @@ 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)
|
||||
subprocess.run(
|
||||
["ffmpeg", "-version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
# 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.')
|
||||
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): "
|
||||
)
|
||||
@@ -91,9 +122,7 @@ def ffmpeg_install():
|
||||
elif os.name == "mac":
|
||||
ffmpeg_install_mac()
|
||||
else:
|
||||
print(
|
||||
"Your OS is not supported. Please install FFmpeg manually and try again."
|
||||
)
|
||||
print("Your OS is not supported. Please install FFmpeg manually and try again.")
|
||||
exit()
|
||||
else:
|
||||
print("Please install FFmpeg manually and try again.")
|
||||
|
||||
+4
-18
@@ -67,11 +67,7 @@ def check(value, checks):
|
||||
and not hasattr(value, "__iter__")
|
||||
and (
|
||||
("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
|
||||
@@ -80,16 +76,8 @@ def check(value, checks):
|
||||
not incorrect
|
||||
and hasattr(value, "__iter__")
|
||||
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
|
||||
@@ -162,9 +150,7 @@ def delete_background(key):
|
||||
# Add background video
|
||||
def add_background(youtube_uri, filename, citation, position):
|
||||
# Validate YouTube URI
|
||||
regex = re.compile(r"(?:\/|%3D|v=|vi=)([0-9A-z\-_]{11})(?:[%#?&]|$)").search(
|
||||
youtube_uri
|
||||
)
|
||||
regex = re.compile(r"(?:\/|%3D|v=|vi=)([0-9A-z\-_]{11})(?:[%#?&]|$)").search(youtube_uri)
|
||||
|
||||
if not regex:
|
||||
flash("YouTube URI is invalid!", "error")
|
||||
|
||||
+4
-12
@@ -17,9 +17,7 @@ def draw_multiple_line_text(
|
||||
Fontperm = font.getsize(text)
|
||||
image_width, image_height = image.size
|
||||
lines = textwrap.wrap(text, width=wrap)
|
||||
y = (image_height / 2) - (
|
||||
((Fontperm[1] + (len(lines) * padding) / len(lines)) * len(lines)) / 2
|
||||
)
|
||||
y = (image_height / 2) - (((Fontperm[1] + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
|
||||
for line in lines:
|
||||
line_width, line_height = font.getsize(line)
|
||||
if transparent:
|
||||
@@ -65,25 +63,19 @@ def imagemaker(theme, reddit_obj: dict, txtclr, padding=5, transparent=False) ->
|
||||
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 100)
|
||||
tfont = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 100)
|
||||
else:
|
||||
tfont = ImageFont.truetype(
|
||||
os.path.join("fonts", "Roboto-Bold.ttf"), 100
|
||||
) # for title
|
||||
tfont = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 100) # for title
|
||||
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Regular.ttf"), 100)
|
||||
size = (1920, 1080)
|
||||
|
||||
image = Image.new("RGBA", size, theme)
|
||||
|
||||
# for title
|
||||
draw_multiple_line_text(
|
||||
image, title, tfont, txtclr, padding, wrap=30, transparent=transparent
|
||||
)
|
||||
draw_multiple_line_text(image, title, tfont, txtclr, padding, wrap=30, transparent=transparent)
|
||||
|
||||
image.save(f"assets/temp/{id}/png/title.png")
|
||||
|
||||
for idx, text in track(enumerate(texts), "Rendering Image"):
|
||||
image = Image.new("RGBA", size, theme)
|
||||
text = process_text(text, False)
|
||||
draw_multiple_line_text(
|
||||
image, text, font, txtclr, padding, wrap=30, transparent=transparent
|
||||
)
|
||||
draw_multiple_line_text(image, text, font, txtclr, padding, wrap=30, transparent=transparent)
|
||||
image.save(f"assets/temp/{id}/png/img{idx}.png")
|
||||
+1
-3
@@ -1,7 +1,5 @@
|
||||
def clear_cookie_by_name(context, cookie_cleared_name):
|
||||
cookies = context.cookies()
|
||||
filtered_cookies = [
|
||||
cookie for cookie in cookies if cookie["name"] != cookie_cleared_name
|
||||
]
|
||||
filtered_cookies = [cookie for cookie in cookies if cookie["name"] != cookie_cleared_name]
|
||||
context.clear_cookies()
|
||||
context.add_cookies(filtered_cookies)
|
||||
@@ -20,7 +20,8 @@ def posttextparser(obj, *, tried: bool = False) -> List[str]:
|
||||
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 ")
|
||||
"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)
|
||||
|
||||
+6
-26
@@ -52,11 +52,7 @@ def check(value, checks, name):
|
||||
and not hasattr(value, "__iter__")
|
||||
and (
|
||||
("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
|
||||
@@ -64,16 +60,8 @@ def check(value, checks, name):
|
||||
not incorrect
|
||||
and hasattr(value, "__iter__")
|
||||
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
|
||||
@@ -81,15 +69,9 @@ def check(value, checks, name):
|
||||
if incorrect:
|
||||
value = handle_input(
|
||||
message=(
|
||||
(
|
||||
("[blue]Example: " + str(checks["example"]) + "\n")
|
||||
if "example" in checks
|
||||
else ""
|
||||
)
|
||||
(("[blue]Example: " + str(checks["example"]) + "\n") if "example" in checks else "")
|
||||
+ "[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]"
|
||||
+ str(name)
|
||||
@@ -130,9 +112,7 @@ def check_toml(template_file, config_file) -> Tuple[bool, Dict]:
|
||||
try:
|
||||
template = toml.load(template_file)
|
||||
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
|
||||
try:
|
||||
config = toml.load(config_file)
|
||||
|
||||
+5
-14
@@ -6,9 +6,7 @@ from utils.console import print_substep
|
||||
from utils.ai_methods import sort_by_similarity
|
||||
|
||||
|
||||
def get_subreddit_undone(
|
||||
submissions: list, subreddit, times_checked=0, similarity_scores=None
|
||||
):
|
||||
def get_subreddit_undone(submissions: list, subreddit, times_checked=0, similarity_scores=None):
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
@@ -20,9 +18,7 @@ def get_subreddit_undone(
|
||||
"""
|
||||
# Second try of getting a valid Submission
|
||||
if times_checked and settings.config["ai"]["ai_similarity_enabled"]:
|
||||
print(
|
||||
"Sorting based on similarity for a different date filter and thread limit.."
|
||||
)
|
||||
print("Sorting based on similarity for a different date filter and thread limit..")
|
||||
submissions = sort_by_similarity(
|
||||
submissions, keywords=settings.config["ai"]["ai_similarity_enabled"]
|
||||
)
|
||||
@@ -31,9 +27,7 @@ def get_subreddit_undone(
|
||||
if not exists("./video_creation/data/videos.json"):
|
||||
with open("./video_creation/data/videos.json", "w+") as f:
|
||||
json.dump([], f)
|
||||
with open(
|
||||
"./video_creation/data/videos.json", "r", encoding="utf-8"
|
||||
) as done_vids_raw:
|
||||
with open("./video_creation/data/videos.json", "r", encoding="utf-8") as done_vids_raw:
|
||||
done_videos = json.load(done_vids_raw)
|
||||
for i, submission in enumerate(submissions):
|
||||
if already_done(done_videos, submission):
|
||||
@@ -49,8 +43,7 @@ def get_subreddit_undone(
|
||||
print_substep("This post was pinned by moderators. Skipping...")
|
||||
continue
|
||||
if (
|
||||
submission.num_comments
|
||||
<= int(settings.config["reddit"]["thread"]["min_comments"])
|
||||
submission.num_comments <= int(settings.config["reddit"]["thread"]["min_comments"])
|
||||
and not settings.config["settings"]["storymode"]
|
||||
):
|
||||
print_substep(
|
||||
@@ -59,9 +52,7 @@ def get_subreddit_undone(
|
||||
continue
|
||||
if settings.config["settings"]["storymode"]:
|
||||
if not submission.selftext:
|
||||
print_substep(
|
||||
"You are trying to use story mode on post with no post text"
|
||||
)
|
||||
print_substep("You are trying to use story mode on post with no post text")
|
||||
continue
|
||||
else:
|
||||
# Check for the length of the post text
|
||||
|
||||
+3
-9
@@ -1,15 +1,11 @@
|
||||
from PIL import ImageDraw, ImageFont
|
||||
|
||||
|
||||
def create_thumbnail(
|
||||
thumbnail, font_family, font_size, font_color, width, height, title
|
||||
):
|
||||
def create_thumbnail(thumbnail, font_family, font_size, font_color, width, height, title):
|
||||
font = ImageFont.truetype(font_family + ".ttf", font_size)
|
||||
Xaxis = width - (width * 0.2) # 20% of the width
|
||||
sizeLetterXaxis = font_size * 0.5 # 50% of the font size
|
||||
XaxisLetterQty = round(
|
||||
Xaxis / sizeLetterXaxis
|
||||
) # Quantity of letters that can fit in the X axis
|
||||
XaxisLetterQty = round(Xaxis / sizeLetterXaxis) # Quantity of letters that can fit in the X axis
|
||||
MarginYaxis = height * 0.12 # 12% of the height
|
||||
MarginXaxis = width * 0.05 # 5% of the width
|
||||
# 1.1 rem
|
||||
@@ -34,8 +30,6 @@ def create_thumbnail(
|
||||
# loop for put the title in the thumbnail
|
||||
for i in range(0, len(arrayTitle)):
|
||||
# 1.1 rem
|
||||
draw.text(
|
||||
(MarginXaxis, MarginYaxis + (LineHeight * i)), arrayTitle[i], rgb, font=font
|
||||
)
|
||||
draw.text((MarginXaxis, MarginYaxis + (LineHeight * i)), arrayTitle[i], rgb, font=font)
|
||||
|
||||
return thumbnail
|
||||
+2
-6
@@ -19,9 +19,7 @@ def check_done(
|
||||
Returns:
|
||||
Submission|None: Reddit object in args
|
||||
"""
|
||||
with open(
|
||||
"./video_creation/data/videos.json", "r", encoding="utf-8"
|
||||
) as done_vids_raw:
|
||||
with open("./video_creation/data/videos.json", "r", encoding="utf-8") as done_vids_raw:
|
||||
done_videos = json.load(done_vids_raw)
|
||||
for video in done_videos:
|
||||
if video["id"] == str(redditobj):
|
||||
@@ -35,9 +33,7 @@ def check_done(
|
||||
return redditobj
|
||||
|
||||
|
||||
def save_data(
|
||||
subreddit: str, filename: str, reddit_title: str, reddit_id: str, credit: str
|
||||
):
|
||||
def save_data(subreddit: str, filename: str, reddit_title: str, reddit_id: str, credit: str):
|
||||
"""Saves the videos that have already been generated to a JSON file in video_creation/data/videos.json
|
||||
|
||||
Args:
|
||||
|
||||
+1
-3
@@ -43,9 +43,7 @@ def sleep_until(time) -> None:
|
||||
if sys.version_info[0] >= 3 and time.tzinfo:
|
||||
end = time.astimezone(timezone.utc).timestamp()
|
||||
else:
|
||||
zoneDiff = (
|
||||
pytime.time() - (datetime.now() - datetime(1970, 1, 1)).total_seconds()
|
||||
)
|
||||
zoneDiff = pytime.time() - (datetime.now() - datetime(1970, 1, 1)).total_seconds()
|
||||
end = (time - datetime(1970, 1, 1)).total_seconds() + zoneDiff
|
||||
|
||||
# Type check
|
||||
|
||||
@@ -59,9 +59,7 @@ def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int
|
||||
def get_background_config(mode: str):
|
||||
"""Fetch the background/s configuration"""
|
||||
try:
|
||||
choice = str(
|
||||
settings.config["settings"]["background"][f"background_{mode}"]
|
||||
).casefold()
|
||||
choice = str(settings.config["settings"]["background"][f"background_{mode}"]).casefold()
|
||||
except AttributeError:
|
||||
print_substep("No background selected. Picking random background'")
|
||||
choice = None
|
||||
@@ -121,9 +119,7 @@ def download_background_audio(background_config: Tuple[str, str, str]):
|
||||
print_substep("Background audio downloaded successfully! 🎉", style="bold green")
|
||||
|
||||
|
||||
def chop_background(
|
||||
background_config: Dict[str, Tuple], video_length: int, reddit_object: dict
|
||||
):
|
||||
def chop_background(background_config: Dict[str, Tuple], video_length: int, reddit_object: dict):
|
||||
"""Generates the background audio and footage to be used in the video and writes it to assets/temp/background.mp3 and assets/temp/background.mp4
|
||||
|
||||
Args:
|
||||
@@ -136,9 +132,7 @@ def chop_background(
|
||||
print_step("Volume was set to 0. Skipping background audio creation . . .")
|
||||
else:
|
||||
print_step("Finding a spot in the backgrounds audio to chop...✂️")
|
||||
audio_choice = (
|
||||
f"{background_config['audio'][2]}-{background_config['audio'][1]}"
|
||||
)
|
||||
audio_choice = f"{background_config['audio'][2]}-{background_config['audio'][1]}"
|
||||
background_audio = AudioFileClip(f"assets/backgrounds/audio/{audio_choice}")
|
||||
start_time_audio, end_time_audio = get_start_and_end_times(
|
||||
video_length, background_audio.duration
|
||||
|
||||
@@ -46,8 +46,12 @@ class ProgressFfmpeg(threading.Thread):
|
||||
if lines:
|
||||
for line in lines:
|
||||
if "out_time_ms" in line:
|
||||
out_time_ms = line.split("=")[1]
|
||||
return int(out_time_ms) / 1000000.0
|
||||
out_time_ms_str = line.split("=")[1].strip()
|
||||
if out_time_ms_str.isnumeric():
|
||||
return float(out_time_ms_str) / 1000000.0
|
||||
else:
|
||||
# Handle the case when "N/A" is encountered
|
||||
return None
|
||||
return None
|
||||
|
||||
def stop(self):
|
||||
@@ -72,7 +76,7 @@ def name_normalize(name: str) -> str:
|
||||
lang = settings.config["reddit"]["thread"]["post_lang"]
|
||||
if lang:
|
||||
print_substep("Translating filename...")
|
||||
translated_name = translators.google(name, to_language=lang)
|
||||
translated_name = translators.translate_text(name, translator="google", to_language=lang)
|
||||
return translated_name
|
||||
else:
|
||||
return name
|
||||
@@ -109,9 +113,7 @@ def merge_background_audio(audio: ffmpeg, reddit_id: str):
|
||||
audio (ffmpeg): The TTS final audio but without background.
|
||||
reddit_id (str): The ID of subreddit
|
||||
"""
|
||||
background_audio_volume = settings.config["settings"]["background"][
|
||||
"background_audio_volume"
|
||||
]
|
||||
background_audio_volume = settings.config["settings"]["background"]["background_audio_volume"]
|
||||
if background_audio_volume == 0:
|
||||
return audio # Return the original audio
|
||||
else:
|
||||
@@ -165,42 +167,27 @@ def make_final_video(
|
||||
if settings.config["settings"]["storymode"]:
|
||||
if settings.config["settings"]["storymodemethod"] == 0:
|
||||
audio_clips = [ffmpeg.input(f"assets/temp/{reddit_id}/mp3/title.mp3")]
|
||||
audio_clips.insert(
|
||||
1, ffmpeg.input(f"assets/temp/{reddit_id}/mp3/postaudio.mp3")
|
||||
)
|
||||
audio_clips.insert(1, ffmpeg.input(f"assets/temp/{reddit_id}/mp3/postaudio.mp3"))
|
||||
elif settings.config["settings"]["storymodemethod"] == 1:
|
||||
audio_clips = [
|
||||
ffmpeg.input(f"assets/temp/{reddit_id}/mp3/postaudio-{i}.mp3")
|
||||
for i in track(
|
||||
range(number_of_clips + 1), "Collecting the audio files..."
|
||||
)
|
||||
for i in track(range(number_of_clips + 1), "Collecting the audio files...")
|
||||
]
|
||||
audio_clips.insert(
|
||||
0, ffmpeg.input(f"assets/temp/{reddit_id}/mp3/title.mp3")
|
||||
)
|
||||
audio_clips.insert(0, ffmpeg.input(f"assets/temp/{reddit_id}/mp3/title.mp3"))
|
||||
|
||||
else:
|
||||
audio_clips = [
|
||||
ffmpeg.input(f"assets/temp/{reddit_id}/mp3/{i}.mp3")
|
||||
for i in range(number_of_clips)
|
||||
ffmpeg.input(f"assets/temp/{reddit_id}/mp3/{i}.mp3") for i in range(number_of_clips)
|
||||
]
|
||||
audio_clips.insert(0, ffmpeg.input(f"assets/temp/{reddit_id}/mp3/title.mp3"))
|
||||
|
||||
audio_clips_durations = [
|
||||
float(
|
||||
ffmpeg.probe(f"assets/temp/{reddit_id}/mp3/{i}.mp3")["format"][
|
||||
"duration"
|
||||
]
|
||||
)
|
||||
float(ffmpeg.probe(f"assets/temp/{reddit_id}/mp3/{i}.mp3")["format"]["duration"])
|
||||
for i in range(number_of_clips)
|
||||
]
|
||||
audio_clips_durations.insert(
|
||||
0,
|
||||
float(
|
||||
ffmpeg.probe(f"assets/temp/{reddit_id}/mp3/title.mp3")["format"][
|
||||
"duration"
|
||||
]
|
||||
),
|
||||
float(ffmpeg.probe(f"assets/temp/{reddit_id}/mp3/title.mp3")["format"]["duration"]),
|
||||
)
|
||||
audio_concat = ffmpeg.concat(*audio_clips, a=1, v=0)
|
||||
ffmpeg.output(
|
||||
@@ -226,19 +213,13 @@ def make_final_video(
|
||||
if settings.config["settings"]["storymode"]:
|
||||
audio_clips_durations = [
|
||||
float(
|
||||
ffmpeg.probe(f"assets/temp/{reddit_id}/mp3/postaudio-{i}.mp3")[
|
||||
"format"
|
||||
]["duration"]
|
||||
ffmpeg.probe(f"assets/temp/{reddit_id}/mp3/postaudio-{i}.mp3")["format"]["duration"]
|
||||
)
|
||||
for i in range(number_of_clips)
|
||||
]
|
||||
audio_clips_durations.insert(
|
||||
0,
|
||||
float(
|
||||
ffmpeg.probe(f"assets/temp/{reddit_id}/mp3/title.mp3")["format"][
|
||||
"duration"
|
||||
]
|
||||
),
|
||||
float(ffmpeg.probe(f"assets/temp/{reddit_id}/mp3/title.mp3")["format"]["duration"]),
|
||||
)
|
||||
if settings.config["settings"]["storymodemethod"] == 0:
|
||||
image_clips.insert(
|
||||
@@ -248,16 +229,14 @@ def make_final_video(
|
||||
),
|
||||
)
|
||||
background_clip = background_clip.overlay(
|
||||
image_clips[1],
|
||||
enable=f"between(t,{current_time},{current_time + audio_clips_durations[1]})",
|
||||
image_clips[0],
|
||||
enable=f"between(t,{current_time},{current_time + audio_clips_durations[0]})",
|
||||
x="(main_w-overlay_w)/2",
|
||||
y="(main_h-overlay_h)/2",
|
||||
)
|
||||
current_time += audio_clips_durations[1]
|
||||
current_time += audio_clips_durations[0]
|
||||
elif settings.config["settings"]["storymodemethod"] == 1:
|
||||
for i in track(
|
||||
range(0, number_of_clips + 1), "Collecting the image files..."
|
||||
):
|
||||
for i in track(range(0, number_of_clips + 1), "Collecting the image files..."):
|
||||
image_clips.append(
|
||||
ffmpeg.input(f"assets/temp/{reddit_id}/png/img{i}.png")["v"].filter(
|
||||
"scale", screenshot_width, -1
|
||||
@@ -273,9 +252,9 @@ def make_final_video(
|
||||
else:
|
||||
for i in range(0, number_of_clips + 1):
|
||||
image_clips.append(
|
||||
ffmpeg.input(f"assets/temp/{reddit_id}/png/comment_{i}.png")[
|
||||
"v"
|
||||
].filter("scale", screenshot_width, -1)
|
||||
ffmpeg.input(f"assets/temp/{reddit_id}/png/comment_{i}.png")["v"].filter(
|
||||
"scale", screenshot_width, -1
|
||||
)
|
||||
)
|
||||
image_overlay = image_clips[i].filter("colorchannelmixer", aa=opacity)
|
||||
background_clip = background_clip.overlay(
|
||||
@@ -294,15 +273,11 @@ def make_final_video(
|
||||
subreddit = settings.config["reddit"]["thread"]["subreddit"]
|
||||
|
||||
if not exists(f"./results/{subreddit}"):
|
||||
print_substep(
|
||||
"The 'results' folder could not be found so it was automatically created."
|
||||
)
|
||||
print_substep("The 'results' folder could not be found so it was automatically created.")
|
||||
os.makedirs(f"./results/{subreddit}")
|
||||
|
||||
if not exists(f"./results/{subreddit}/OnlyTTS") and allowOnlyTTSFolder:
|
||||
print_substep(
|
||||
"The 'OnlyTTS' folder could not be found so it was automatically created."
|
||||
)
|
||||
print_substep("The 'OnlyTTS' folder could not be found so it was automatically created.")
|
||||
os.makedirs(f"./results/{subreddit}/OnlyTTS")
|
||||
|
||||
# create a thumbnail for the video
|
||||
@@ -316,11 +291,7 @@ def make_final_video(
|
||||
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")
|
||||
),
|
||||
(file for file in os.listdir("assets/backgrounds") if file.endswith(".png")),
|
||||
None,
|
||||
)
|
||||
if first_image is None:
|
||||
@@ -342,9 +313,7 @@ def make_final_video(
|
||||
title_thumb,
|
||||
)
|
||||
thumbnailSave.save(f"./assets/temp/{reddit_id}/thumbnail.png")
|
||||
print_substep(
|
||||
f"Thumbnail - Building Thumbnail in 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]}"
|
||||
background_clip = ffmpeg.drawtext(
|
||||
@@ -373,23 +342,27 @@ def make_final_video(
|
||||
path = (
|
||||
path[:251] + ".mp4"
|
||||
) # Prevent a error by limiting the path length, do not change this.
|
||||
ffmpeg.output(
|
||||
background_clip,
|
||||
final_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,
|
||||
final_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)
|
||||
if allowOnlyTTSFolder:
|
||||
|
||||
@@ -38,9 +38,7 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
|
||||
# set the theme and disable non-essential cookies
|
||||
if settings.config["settings"]["theme"] == "dark":
|
||||
cookie_file = open(
|
||||
"./video_creation/data/cookie-dark-mode.json", encoding="utf-8"
|
||||
)
|
||||
cookie_file = open("./video_creation/data/cookie-dark-mode.json", encoding="utf-8")
|
||||
bgcolor = (33, 33, 36, 255)
|
||||
txtcolor = (240, 240, 240)
|
||||
transparent = False
|
||||
@@ -50,21 +48,15 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
bgcolor = (0, 0, 0, 0)
|
||||
txtcolor = (255, 255, 255)
|
||||
transparent = True
|
||||
cookie_file = open(
|
||||
"./video_creation/data/cookie-dark-mode.json", encoding="utf-8"
|
||||
)
|
||||
cookie_file = open("./video_creation/data/cookie-dark-mode.json", encoding="utf-8")
|
||||
else:
|
||||
# Switch to dark theme
|
||||
cookie_file = open(
|
||||
"./video_creation/data/cookie-dark-mode.json", encoding="utf-8"
|
||||
)
|
||||
cookie_file = open("./video_creation/data/cookie-dark-mode.json", encoding="utf-8")
|
||||
bgcolor = (33, 33, 36, 255)
|
||||
txtcolor = (240, 240, 240)
|
||||
transparent = False
|
||||
else:
|
||||
cookie_file = open(
|
||||
"./video_creation/data/cookie-light-mode.json", encoding="utf-8"
|
||||
)
|
||||
cookie_file = open("./video_creation/data/cookie-light-mode.json", encoding="utf-8")
|
||||
bgcolor = (255, 255, 255, 255)
|
||||
txtcolor = (0, 0, 0)
|
||||
transparent = False
|
||||
@@ -108,12 +100,8 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
page.set_viewport_size(ViewportSize(width=1920, height=1080))
|
||||
page.wait_for_load_state()
|
||||
|
||||
page.locator('[name="username"]').fill(
|
||||
settings.config["reddit"]["creds"]["username"]
|
||||
)
|
||||
page.locator('[name="password"]').fill(
|
||||
settings.config["reddit"]["creds"]["password"]
|
||||
)
|
||||
page.locator('[name="username"]').fill(settings.config["reddit"]["creds"]["username"])
|
||||
page.locator('[name="password"]').fill(settings.config["reddit"]["creds"]["password"])
|
||||
page.locator("button[class$='m-full-width']").click()
|
||||
page.wait_for_timeout(5000)
|
||||
|
||||
@@ -168,9 +156,10 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
|
||||
if lang:
|
||||
print_substep("Translating post...")
|
||||
texts_in_tl = translators.google(
|
||||
texts_in_tl = translators.translate_text(
|
||||
reddit_object["thread_title"],
|
||||
to_language=lang,
|
||||
translator="google",
|
||||
)
|
||||
|
||||
page.evaluate(
|
||||
@@ -193,9 +182,7 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
location[i] = float("{:.2f}".format(location[i] * zoom))
|
||||
page.screenshot(clip=location, path=postcontentpath)
|
||||
else:
|
||||
page.locator('[data-test-id="post-content"]').screenshot(
|
||||
path=postcontentpath
|
||||
)
|
||||
page.locator('[data-test-id="post-content"]').screenshot(path=postcontentpath)
|
||||
except Exception as e:
|
||||
print_substep("Something went wrong!", style="red")
|
||||
resp = input(
|
||||
@@ -209,9 +196,7 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
"green",
|
||||
)
|
||||
|
||||
resp = input(
|
||||
"Do you want the error traceback for debugging purposes? (y/n)"
|
||||
)
|
||||
resp = input("Do you want the error traceback for debugging purposes? (y/n)")
|
||||
if not resp.casefold().startswith("y"):
|
||||
exit()
|
||||
|
||||
@@ -237,11 +222,12 @@ 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(
|
||||
comment_tl = translators.translate_text(
|
||||
comment["comment_body"],
|
||||
translator="google",
|
||||
to_language=settings.config["reddit"]["thread"]["post_lang"],
|
||||
)
|
||||
page.evaluate(
|
||||
@@ -255,13 +241,9 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
# zoom the body of the page
|
||||
page.evaluate("document.body.style.zoom=" + str(zoom))
|
||||
# scroll comment into view
|
||||
page.locator(
|
||||
f"#t1_{comment['comment_id']}"
|
||||
).scroll_into_view_if_needed()
|
||||
page.locator(f"#t1_{comment['comment_id']}").scroll_into_view_if_needed()
|
||||
# as zooming the body doesn't change the properties of the divs, we need to adjust for the zoom
|
||||
location = page.locator(
|
||||
f"#t1_{comment['comment_id']}"
|
||||
).bounding_box()
|
||||
location = page.locator(f"#t1_{comment['comment_id']}").bounding_box()
|
||||
for i in location:
|
||||
location[i] = float("{:.2f}".format(location[i] * zoom))
|
||||
page.screenshot(
|
||||
@@ -282,4 +264,3 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
browser.close()
|
||||
|
||||
print_substep("Screenshots downloaded Successfully.", style="bold green")
|
||||
|
||||
@@ -36,9 +36,7 @@ def save_text_to_mp3(reddit_obj) -> Tuple[int, int]:
|
||||
|
||||
voice = settings.config["settings"]["tts"]["voice_choice"]
|
||||
if str(voice).casefold() in map(lambda _: _.casefold(), TTSProviders):
|
||||
text_to_mp3 = TTSEngine(
|
||||
get_case_insensitive_key_value(TTSProviders, voice), reddit_obj
|
||||
)
|
||||
text_to_mp3 = TTSEngine(get_case_insensitive_key_value(TTSProviders, voice), reddit_obj)
|
||||
else:
|
||||
while True:
|
||||
print_step("Please choose one of the following TTS providers: ")
|
||||
@@ -47,18 +45,12 @@ def save_text_to_mp3(reddit_obj) -> Tuple[int, int]:
|
||||
if choice.casefold() in map(lambda _: _.casefold(), TTSProviders):
|
||||
break
|
||||
print("Unknown Choice")
|
||||
text_to_mp3 = TTSEngine(
|
||||
get_case_insensitive_key_value(TTSProviders, choice), reddit_obj
|
||||
)
|
||||
text_to_mp3 = TTSEngine(get_case_insensitive_key_value(TTSProviders, choice), reddit_obj)
|
||||
return text_to_mp3.run()
|
||||
|
||||
|
||||
def get_case_insensitive_key_value(input_dict, key):
|
||||
return next(
|
||||
(
|
||||
value
|
||||
for dict_key, value in input_dict.items()
|
||||
if dict_key.lower() == key.lower()
|
||||
),
|
||||
(value for dict_key, value in input_dict.items() if dict_key.lower() == key.lower()),
|
||||
None,
|
||||
)
|
||||
Reference in new issue
Block a user