Merge branch 'develop' into joshholly-fix-opacity

pull/1626/head
Josh Holly 2 years ago committed by GitHub
commit 325266dc85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -70,7 +70,7 @@ In its current state, this bot does exactly what it needs to do. However, improv
I have tried to simplify the code so anyone can read it and start contributing at any skill level. Don't be shy :) contribute! I have tried to simplify the code so anyone can read it and start contributing at any skill level. Don't be shy :) contribute!
- [ ] Creating better documentation and adding a command line interface. - [ ] Creating better documentation and adding a command line interface.
- [ ] Allowing the user to choose background music for their videos. - [x] Allowing the user to choose background music for their videos.
- [x] Allowing users to choose a reddit thread instead of being randomized. - [x] Allowing users to choose a reddit thread instead of being randomized.
- [x] Allowing users to choose a background that is picked instead of the Minecraft one. - [x] Allowing users to choose a background that is picked instead of the Minecraft one.
- [x] Allowing users to choose between any subreddit. - [x] Allowing users to choose between any subreddit.

@ -55,9 +55,20 @@ class TTSEngine:
self, self,
): # adds periods to the end of paragraphs (where people often forget to put them) so tts doesn't blend sentences ): # adds periods to the end of paragraphs (where people often forget to put them) so tts doesn't blend sentences
for comment in self.reddit_object["comments"]: for comment in self.reddit_object["comments"]:
# remove links
regex_urls = r"((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:@\-_=#]+\.([a-zA-Z]){2,6}([a-zA-Z0-9\.\&\/\?\:@\-_=#])*"
comment["comment_body"] = re.sub(regex_urls, " ", comment["comment_body"])
comment["comment_body"] = comment["comment_body"].replace("\n", ". ") 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"])
if comment["comment_body"][-1] != ".": if comment["comment_body"][-1] != ".":
comment["comment_body"] += "." comment["comment_body"] += "."
comment["comment_body"] = comment["comment_body"].replace(". . .", ".")
comment["comment_body"] = comment["comment_body"].replace(".. . ", ".")
comment["comment_body"] = comment["comment_body"].replace(". . ", ".")
comment["comment_body"] = re.sub(r'\."\.', '".', comment["comment_body"])
print(comment["comment_body"])
def run(self) -> Tuple[int, int]: def run(self) -> Tuple[int, int]:
Path(self.path).mkdir(parents=True, exist_ok=True) Path(self.path).mkdir(parents=True, exist_ok=True)

@ -6,6 +6,7 @@ from os import name
from pathlib import Path from pathlib import Path
from subprocess import Popen from subprocess import Popen
import ffmpeg
from prawcore import ResponseException from prawcore import ResponseException
from utils.console import print_substep from utils.console import print_substep
from reddit.subreddit import get_subreddit_threads from reddit.subreddit import get_subreddit_threads
@ -15,8 +16,9 @@ from utils.console import print_markdown, print_step
from utils.id import id from utils.id import id
from utils.version import checkversion from utils.version import checkversion
from video_creation.background import ( from video_creation.background import (
download_background, download_background_video,
chop_background_video, download_background_audio,
chop_background,
get_background_config, get_background_config,
) )
from video_creation.final_video import make_final_video from video_creation.final_video import make_final_video
@ -50,10 +52,18 @@ def main(POST_ID=None) -> None:
length, number_of_comments = save_text_to_mp3(reddit_object) length, number_of_comments = save_text_to_mp3(reddit_object)
length = math.ceil(length) length = math.ceil(length)
get_screenshots_of_reddit_posts(reddit_object, number_of_comments) get_screenshots_of_reddit_posts(reddit_object, number_of_comments)
bg_config = get_background_config() bg_config = {
download_background(bg_config) "video": get_background_config("video"),
chop_background_video(bg_config, length, reddit_object) "audio": get_background_config("audio"),
make_final_video(number_of_comments, length, reddit_object, bg_config) }
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)
def run_many(times) -> None: def run_many(times) -> None:
@ -81,6 +91,7 @@ def shutdown():
if __name__ == "__main__": if __name__ == "__main__":
if sys.version_info.major != 3 or sys.version_info.minor != 10: 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.")
exit()
ffmpeg_install() # install ffmpeg if not installed ffmpeg_install() # install ffmpeg if not installed
directory = Path().absolute() directory = Path().absolute()
config = settings.check_toml( config = settings.check_toml(
@ -127,4 +138,4 @@ if __name__ == "__main__":
f"Error: {err} \n" f"Error: {err} \n"
f'Config: {config["settings"]}' f'Config: {config["settings"]}'
) )
raise err raise err

@ -5,18 +5,18 @@ moviepy==1.0.3
playwright==1.23.0 playwright==1.23.0
praw==7.6.1 praw==7.6.1
prawcore~=2.3.0 prawcore~=2.3.0
pytube==12.1.0
requests==2.28.1 requests==2.28.1
rich==13.3.1 rich==13.3.5
toml==0.10.2 toml==0.10.2
translators==5.3.1 translators==5.3.1
pyttsx3==2.90 pyttsx3==2.90
Pillow~=9.4.0 Pillow~=9.4.0
tomlkit==0.11.4 tomlkit==0.11.8
Flask==2.2.2 Flask==2.3.2
clean-text==0.6.0 clean-text==0.6.0
unidecode==1.3.2 unidecode==1.3.2
spacy==3.4.1 spacy==3.4.1
torch==1.12.1 torch==1.12.1
transformers==4.25.1 transformers==4.25.1
ffmpeg-python==0.2.0 ffmpeg-python==0.2.0
yt-dlp==2023.3.4

@ -33,20 +33,21 @@ resolution_w = { optional = false, default = 1080, example = 1440, explantation
resolution_h = { optional = false, default = 1920, example = 2560, explantation = "Sets the height in pixels of the final video" } resolution_h = { optional = false, default = 1920, example = 2560, explantation = "Sets the height in pixels of the final video" }
[settings.background] [settings.background]
background_choice = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" } background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" }
#background_audio = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } background_audio = { optional = true, default = "lofi", example = "chill-summer", options = ["lofi","lofi-2","chill-summer",""], explanation = "Sets the background audio for the video" }
#background_audio_volume = { optional = true, type = "float", default = 0.3, example = 0.1, explanation="Sets the volume of the background audio. only used if the background_audio is also set to true" } background_audio_volume = { optional = true, type = "float", nmin = 0, nmax = 1, default = 0.15, example = 0.05, explanation="Sets the volume of the background audio. If you don't want background audio, set it to 0.", oob_error = "The volume HAS to be between 0 and 1", input_error = "The volume HAS to be a float number between 0 and 1"}
enable_extra_audio = { optional = true, type = "bool", default = false, example = false, explanation="Used if you want to render another video without background audio in a separate folder", input_error = "The value HAS to be true or false"}
background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" } background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" }
background_thumbnail_font_family = { optional = true, default = "arial", example = "arial", explanation = "Font family for the thumbnail text" } background_thumbnail_font_family = { optional = true, default = "arial", example = "arial", explanation = "Font family for the thumbnail text" }
background_thumbnail_font_size = { optional = true, type = "int", default = 96, example = 96, explanation = "Font size in pixels for the thumbnail text" } background_thumbnail_font_size = { optional = true, type = "int", default = 96, example = 96, explanation = "Font size in pixels for the thumbnail text" }
background_thumbnail_font_color = { optional = true, default = "255,255,255", example = "255,255,255", explanation = "Font color in RGB format for the thumbnail text" } background_thumbnail_font_color = { optional = true, default = "255,255,255", example = "255,255,255", explanation = "Font color in RGB format for the thumbnail text" }
[settings.tts] [settings.tts]
voice_choice = { optional = false, default = "tiktok", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", "pyttsx", ], example = "tiktok", explanation = "The voice platform used for TTS generation. This can be left blank and you will be prompted to choose at runtime." } voice_choice = { optional = false, default = "streamlabspolly", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", "pyttsx", ], example = "tiktok", explanation = "The voice platform used for TTS generation. This can be left blank and you will be prompted to choose at runtime." }
aws_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for AWS Polly" } aws_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for AWS Polly" }
streamlabs_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for Streamlabs Polly" } streamlabs_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for Streamlabs Polly" }
tiktok_voice = { optional = true, default = "en_us_001", example = "en_us_006", explanation = "The voice used for TikTok TTS" } tiktok_voice = { optional = true, default = "en_us_001", example = "en_us_006", explanation = "The voice used for TikTok TTS" }
tiktok_sessionid = { optional = true, example = "c76bcc3a7625abcc27b508c7db457ff1", explanation = "TikTok sessionid needed for the TTS API request. Check documentation if you don't know how to obtain it." } 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)" } 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)" } 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" }

@ -0,0 +1,18 @@
{
"__comment": "Supported Backgrounds Audio. Can add/remove background audio here...",
"lofi": [
"https://www.youtube.com/watch?v=LTphVIore3A",
"lofi.mp3",
"Super Lofi World"
],
"lofi-2":[
"https://www.youtube.com/watch?v=BEXL80LS0-I",
"lofi-2.mp3",
"stompsPlaylist"
],
"chill-summer":[
"https://www.youtube.com/watch?v=EZE8JagnBI8",
"chill-summer.mp3",
"Mellow Vibes Radio"
]
}

@ -68,9 +68,9 @@ def imagemaker(theme, reddit_obj: dict, txtclr, padding=5, transparent=False) ->
tfont = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 50) tfont = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 50)
else: else:
tfont = ImageFont.truetype( tfont = ImageFont.truetype(
os.path.join("fonts", "Roboto-Bold.ttf"), 35 os.path.join("fonts", "Roboto-Bold.ttf"), 100
) # for title ) # for title
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Regular.ttf"), 30) font = ImageFont.truetype(os.path.join("fonts", "Roboto-Regular.ttf"), 90)
size = (1920, 1080) size = (1920, 1080)
image = Image.new("RGBA", size, theme) image = Image.new("RGBA", size, theme)

@ -3,29 +3,38 @@ import random
import re import re
from pathlib import Path from pathlib import Path
from random import randrange from random import randrange
from typing import Any, Tuple from typing import Any, Tuple,Dict
from moviepy.editor import VideoFileClip from moviepy.editor import VideoFileClip,AudioFileClip
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from pytube import YouTube
from pytube.cli import on_progress
from utils import settings from utils import settings
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
import yt_dlp
# Load background videos def load_background_options():
with open("./utils/backgrounds.json") as json_file: background_options = {}
background_options = json.load(json_file) # Load background videos
with open("./utils/background_videos.json") as json_file:
background_options["video"] = json.load(json_file)
# Remove "__comment" from backgrounds # Load background audios
background_options.pop("__comment", None) with open("./utils/background_audios.json") as json_file:
background_options["audio"] = json.load(json_file)
# Remove "__comment" from backgrounds
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]
# Add position lambda function if pos != "center":
# (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position) background_options["video"][name][3] = lambda t: ("center", pos + t)
for name in list(background_options.keys()):
pos = background_options[name][3] return background_options
if pos != "center":
background_options[name][3] = lambda t: ("center", pos + t)
def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int, int]: def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int, int]:
@ -42,11 +51,11 @@ def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int
return random_time, random_time + video_length return random_time, random_time + video_length
def get_background_config(): def get_background_config(mode: str):
"""Fetch the background/s configuration""" """Fetch the background/s configuration"""
try: try:
choice = str( choice = str(
settings.config["settings"]["background"]["background_choice"] settings.config["settings"]["background"][f"background_{mode}"]
).casefold() ).casefold()
except AttributeError: except AttributeError:
print_substep("No background selected. Picking random background'") print_substep("No background selected. Picking random background'")
@ -54,57 +63,98 @@ def get_background_config():
# Handle default / not supported background using default option. # Handle default / not supported background using default option.
# Default : pick random from supported background. # Default : pick random from supported background.
if not choice or choice not in background_options: if not choice or choice not in background_options[mode]:
choice = random.choice(list(background_options.keys())) choice = random.choice(list(background_options[mode].keys()))
return background_options[choice]
return background_options[mode][choice]
def download_background(background_config: Tuple[str, str, str, Any]): def download_background_video(background_config: Tuple[str, str, str, Any]):
"""Downloads the background/s video from YouTube.""" """Downloads the background/s video from YouTube."""
Path("./assets/backgrounds/").mkdir(parents=True, exist_ok=True) Path("./assets/backgrounds/video/").mkdir(parents=True, exist_ok=True)
# note: make sure the file name doesn't include an - in it # note: make sure the file name doesn't include an - in it
uri, filename, credit, _ = background_config uri, filename, credit, _ = background_config
if Path(f"assets/backgrounds/{credit}-{filename}").is_file(): if Path(f"assets/backgrounds/video/{credit}-{filename}").is_file():
return return
print_step( print_step(
"We need to download the backgrounds videos. they are fairly large but it's only done once. 😎" "We need to download the backgrounds videos. they are fairly large but it's only done once. 😎"
) )
print_substep("Downloading the backgrounds videos... please be patient 🙏 ") print_substep("Downloading the backgrounds videos... please be patient 🙏 ")
print_substep(f"Downloading {filename} from {uri}") print_substep(f"Downloading {filename} from {uri}")
YouTube(uri, on_progress_callback=on_progress).streams.filter( ydl_opts = {
res="1080p" 'format': "bestvideo[height<=1080][ext=mp4]",
).first().download("assets/backgrounds", filename=f"{credit}-{filename}") "outtmpl": f"assets/backgrounds/video/{credit}-{filename}",
"retries": 10,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download(uri)
print_substep("Background video downloaded successfully! 🎉", style="bold green") print_substep("Background video downloaded successfully! 🎉", style="bold green")
def download_background_audio(background_config: Tuple[str, str, str]):
"""Downloads the background/s audio from YouTube."""
Path("./assets/backgrounds/audio/").mkdir(parents=True, exist_ok=True)
# note: make sure the file name doesn't include an - in it
uri, filename, credit = background_config
if Path(f"assets/backgrounds/audio/{credit}-{filename}").is_file():
return
print_step(
"We need to download the backgrounds audio. they are fairly large but it's only done once. 😎"
)
print_substep("Downloading the backgrounds audio... please be patient 🙏 ")
print_substep(f"Downloading {filename} from {uri}")
ydl_opts = {
'outtmpl': f'./assets/backgrounds/audio/{credit}-{filename}',
'format': 'bestaudio/best',
'extract_audio': True,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([uri])
def chop_background_video( print_substep("Background audio downloaded successfully! 🎉", style="bold green")
background_config: Tuple[str, str, str, Any], video_length: int, reddit_object: dict
def chop_background(
background_config: Dict[str,Tuple], video_length: int, reddit_object: dict
): ):
"""Generates the background footage to be used in the video and writes it to assets/temp/background.mp4 """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: Args:
background_config (Tuple[str, str, str, Any]) : Current background configuration background_config (Dict[str,Tuple]]) : Current background configuration
video_length (int): Length of the clip where the background footage is to be taken out of video_length (int): Length of the clip where the background footage is to be taken out of
""" """
print_step("Finding a spot in the backgrounds video to chop...✂️")
choice = f"{background_config[2]}-{background_config[1]}"
id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"]) id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"])
background = VideoFileClip(f"assets/backgrounds/{choice}")
start_time, end_time = get_start_and_end_times(video_length, background.duration) if(settings.config["settings"]["background"][f"background_audio_volume"] == 0):
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]}"
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)
background_audio = background_audio.subclip(start_time_audio,end_time_audio)
background_audio.write_audiofile(f"assets/temp/{id}/background.mp3")
print_step("Finding a spot in the backgrounds video to chop...✂️")
video_choice = f"{background_config['video'][2]}-{background_config['video'][1]}"
background_video = VideoFileClip(f"assets/backgrounds/video/{video_choice}")
start_time_video, end_time_video = get_start_and_end_times(video_length, background_video.duration)
# Extract video subclip
try: try:
ffmpeg_extract_subclip( ffmpeg_extract_subclip(
f"assets/backgrounds/{choice}", f"assets/backgrounds/video/{video_choice}",
start_time, start_time_video,
end_time, end_time_video,
targetname=f"assets/temp/{id}/background.mp4", targetname=f"assets/temp/{id}/background.mp4",
) )
except (OSError, IOError): # ffmpeg issue see #348 except (OSError, IOError): # ffmpeg issue see #348
print_substep("FFMPEG issue. Trying again...") print_substep("FFMPEG issue. Trying again...")
with VideoFileClip(f"assets/backgrounds/{choice}") as video: with VideoFileClip(f"assets/backgrounds/video/{video_choice}") as video:
new = video.subclip(start_time, end_time) new = video.subclip(start_time_video, end_time_video)
new.write_videofile(f"assets/temp/{id}/background.mp4") new.write_videofile(f"assets/temp/{id}/background.mp4")
print_substep("Background video chopped successfully!", style="bold green") print_substep("Background video chopped successfully!", style="bold green")
return background_config[2] return background_config["video"][2]
# Create a tuple for downloads background (background_audio_options, background_video_options)
background_options = load_background_options()

@ -4,7 +4,7 @@ import re
import shutil import shutil
from os.path import exists # Needs to be imported specifically from os.path import exists # Needs to be imported specifically
from typing import Final from typing import Final
from typing import Tuple, Any from typing import Tuple, Any, Dict
import ffmpeg import ffmpeg
import translators as ts import translators as ts
@ -103,12 +103,34 @@ def prepare_background(reddit_id: str, W: int, H: int) -> str:
exit() exit()
return output_path return output_path
def merge_background_audio(audio: ffmpeg, reddit_id: str):
"""Gather an audio and merge with assets/backgrounds/background.mp3
Args:
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"]
if (background_audio_volume == 0):
return audio # Return the original audio
else:
# sets volume to config
bg_audio = (
ffmpeg.input(f"assets/temp/{reddit_id}/background.mp3")
.filter(
"volume",
background_audio_volume,
)
)
# Merges audio and background_audio
merged_audio = ffmpeg.filter([audio, bg_audio], "amix", duration="longest")
return merged_audio # Return merged audio
def make_final_video( def make_final_video(
number_of_clips: int, number_of_clips: int,
length: int, length: int,
reddit_obj: dict, reddit_obj: dict,
background_config: Tuple[str, str, str, Any], background_config: Dict[str,Tuple],
): ):
"""Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp """Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp
Args: Args:
@ -123,6 +145,10 @@ def make_final_video(
opacity = int(settings.config["settings"]["opacity"]) opacity = int(settings.config["settings"]["opacity"])
reddit_id = re.sub(r"[^\w\s-]", "", reddit_obj["thread_id"]) reddit_id = re.sub(r"[^\w\s-]", "", reddit_obj["thread_id"])
allowOnlyTTSFolder: bool = settings.config["settings"]["background"]["enable_extra_audio"] \
and settings.config["settings"]["background"]["background_audio_volume"] != 0
print_step("Creating the final video 🎥") print_step("Creating the final video 🎥")
background_clip = ffmpeg.input(prepare_background(reddit_id, W=W, H=H)) background_clip = ffmpeg.input(prepare_background(reddit_id, W=W, H=H))
@ -178,6 +204,7 @@ def make_final_video(
screenshot_width = int((W * 45) // 100) screenshot_width = int((W * 45) // 100)
audio = ffmpeg.input(f"assets/temp/{reddit_id}/audio.mp3") audio = ffmpeg.input(f"assets/temp/{reddit_id}/audio.mp3")
final_audio = merge_background_audio(audio,reddit_id)
image_clips = list() image_clips = list()
@ -260,15 +287,19 @@ def make_final_video(
subreddit = settings.config["reddit"]["thread"]["subreddit"] subreddit = settings.config["reddit"]["thread"]["subreddit"]
if not exists(f"./results/{subreddit}"): if not exists(f"./results/{subreddit}"):
print_substep("The results folder didn't exist so I made it") print_substep("The 'results' folder could not be found so it was automatically created.")
os.makedirs(f"./results/{subreddit}") 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.")
os.makedirs(f"./results/{subreddit}/OnlyTTS")
# create a thumbnail for the video # create a thumbnail for the video
settingsbackground = settings.config["settings"]["background"] settingsbackground = settings.config["settings"]["background"]
if settingsbackground["background_thumbnail"]: if settingsbackground["background_thumbnail"]:
if not exists(f"./results/{subreddit}/thumbnails"): if not exists(f"./results/{subreddit}/thumbnails"):
print_substep("The results/thumbnails folder didn't exist so I made it") print_substep("The 'results/thumbnails' folder could not be found so it was automatically created.")
os.makedirs(f"./results/{subreddit}/thumbnails") 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 # get the first file with the .png extension from assets/backgrounds and use it as a background for the thumbnail
first_image = next( first_image = next(
@ -302,7 +333,7 @@ def make_final_video(
f"Thumbnail - Building Thumbnail in assets/temp/{reddit_id}/thumbnail.png" f"Thumbnail - Building Thumbnail in assets/temp/{reddit_id}/thumbnail.png"
) )
text = f"Background by {background_config[2]}" text = f"Background by {background_config['video'][2]}"
background_clip = ffmpeg.drawtext( background_clip = ffmpeg.drawtext(
background_clip, background_clip,
text=text, text=text,
@ -322,15 +353,14 @@ def make_final_video(
old_percentage = pbar.n old_percentage = pbar.n
pbar.update(status - old_percentage) pbar.update(status - old_percentage)
path = f"results/{subreddit}/{filename}" defaultPath = f"results/{subreddit}"
path = path[:251]
path = path + ".mp4"
with ProgressFfmpeg(length, on_update_example) as progress: with ProgressFfmpeg(length, on_update_example) as progress:
path = defaultPath + f"/{filename}"
path = path[:251] + ".mp4" #Prevent a error by limiting the path length, do not change this.
ffmpeg.output( ffmpeg.output(
background_clip, background_clip,
audio, final_audio,
path, path,
f="mp4", f="mp4",
**{ **{
"c:v": "h264", "c:v": "h264",
@ -344,13 +374,35 @@ def make_final_video(
capture_stdout=False, capture_stdout=False,
capture_stderr=False, capture_stderr=False,
) )
old_percentage = pbar.n old_percentage = pbar.n
pbar.update(100 - old_percentage) pbar.update(100 - old_percentage)
if(allowOnlyTTSFolder):
path = defaultPath + f"/OnlyTTS/{filename}"
path = path[:251] + ".mp4" #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,
)
old_percentage = pbar.n
pbar.update(100 - old_percentage)
pbar.close() pbar.close()
path = r"~/Library/Mobile Documents/com~apple~CloudDocs/reddit/" save_data(subreddit, filename + ".mp4", title, idx, background_config['video'][2])
save_data(path+subreddit, filename + ".mp4", title, idx, background_config[2])
print_step("Removing temporary files 🗑") print_step("Removing temporary files 🗑")
cleanups = cleanup(reddit_id) cleanups = cleanup(reddit_id)
print_substep(f"Removed {cleanups} temporary files 🗑") print_substep(f"Removed {cleanups} temporary files 🗑")
print_step("Done! 🎉 The video is in the results folder 📁") print_step("Done! 🎉 The video is in the results folder 📁")

@ -115,6 +115,19 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
) )
page.locator("button[class$='m-full-width']").click() page.locator("button[class$='m-full-width']").click()
page.wait_for_timeout(5000) page.wait_for_timeout(5000)
login_error_div = page.locator(".AnimatedForm__errorMessage").first
if login_error_div.is_visible():
login_error_message = login_error_div.inner_text()
if login_error_message.strip() == "":
# The div element is empty, no error
pass
else:
# The div contains an error message
print_substep("Your reddit credentials are incorrect! Please modify them accordingly in the config.toml file.", style="red")
exit()
else:
pass
page.wait_for_load_state() page.wait_for_load_state()
# Get the thread screenshot # Get the thread screenshot

Loading…
Cancel
Save