background audio implementation

pull/880/head
Jason 3 years ago
parent a4149e1d12
commit c412155720

@ -29,10 +29,15 @@ opacity = { optional = false, default = 0.9, example = 0.8, explanation = "Sets
storymode = { optional = true, type = "bool", default = false, example = false, options = [true,
false,
], explanation = "not yet implemented" }
[settings.background]
background_choice = { optional = true, default = "minecraft", example = "minecraft", options = ["minecraft", "gta", "rocket-league", "motor-gta", ""], explanation = "Sets the background for the video" }
background_audio = { optional = true, type = "bool", default = false, example = false, options = [true,
false,
], explaination="Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" }
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" }
[settings.tts]
choice = { optional = false, default = "", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", ], example = "streamlabspolly", explanation = "The backend used for TTS generation. This can be left blank and you will be prompted to choose at runtime." }
aws_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for AWS Polly" }

@ -47,7 +47,7 @@ class TTSEngine:
Path(self.path).mkdir(parents=True, exist_ok=True)
# This file needs to be removed in case this post does not use post text, so that it wont appear in the final video
# This file needs to be removed in case this post does not use post text, so that it won't appear in the final video
try:
Path(f"{self.path}/posttext.mp3").unlink()
except OSError:
@ -67,10 +67,12 @@ class TTSEngine:
# ! Stop creating mp3 files if the length is greater than max length.
if self.length > self.max_length:
break
if not self.tts_module.max_chars:
if (
len(comment["comment_body"]) > self.tts_module.max_chars
): # Split the comment if it is too long
self.split_post(comment["comment_body"], idx) # Split the comment
else: # If the comment is not too long, just call the tts engine
self.call_tts(f"{idx}", comment["comment_body"])
else:
self.split_post(comment["comment_body"], idx)
print_substep("Saved Text to MP3 files successfully.", style="bold green")
return self.length, idx
@ -84,9 +86,12 @@ class TTSEngine:
)
]
idy = None
for idy, text_cut in enumerate(split_text):
# print(f"{idx}-{idy}: {text_cut}\n")
if text_cut == "":
print("Empty text cut: tell the devs about this")
continue
self.call_tts(f"{idx}-{idy}.part", text_cut)
split_files.append(AudioFileClip(f"{self.path}/{idx}-{idy}.part.mp3"))
CompositeAudioClip([concatenate_audioclips(split_files)]).write_audiofile(

@ -48,10 +48,12 @@ class StreamlabsPolly:
else:
try:
print(body)
print(response.json())
voice_data = requests.get(response.json()["speak_url"])
with open(filepath, "wb") as f:
f.write(voice_data.content)
except (KeyError, JSONDecodeError):
except (KeyError, JSONDecodeError) as e:
try:
if response.json()["error"] == "No text specified!":
raise ValueError("Please specify a text to convert to speech.")

@ -32,7 +32,7 @@ print(
print_markdown(
"### Thanks for using this tool! [Feel free to contribute to this project on GitHub!](https://lewismenelaws.com) If you have any questions, feel free to reach out to me on Twitter or submit a GitHub issue. You can find solutions to many common problems in the [Documentation](https://luka-hietala.gitbook.io/documentation-for-the-reddit-bot/)"
)
print_step(f"You are using V{VERSION} of the bot")
print_step(f"You are using v{VERSION} of the bot")
def main(POST_ID=None):

@ -18,7 +18,7 @@ def get_subreddit_threads(POST_ID: str):
print_substep("Logging into Reddit.")
content = {}
if settings.config["reddit"]["creds"]["2fa"] == True:
if settings.config["reddit"]["creds"]["2fa"]:
print("\nEnter your two-factor authentication code from your authenticator app.\n")
code = input("> ")
print()
@ -27,7 +27,7 @@ def get_subreddit_threads(POST_ID: str):
else:
passkey = settings.config["reddit"]["creds"]["password"]
username = settings.config["reddit"]["creds"]["username"]
if username.casefold().startswith("u/"):
if str(username).casefold().startswith("u/"):
username = username[2:]
reddit = praw.Reddit(
client_id=settings.config["reddit"]["creds"]["client_id"],
@ -55,7 +55,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 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
@ -65,11 +65,10 @@ def get_subreddit_threads(POST_ID: str):
submission = reddit.submission(id=POST_ID)
elif (
settings.config["reddit"]["thread"]["post_id"]
and len(settings.config["reddit"]["thread"]["post_id"].split("+")) == 1
and len(str(settings.config["reddit"]["thread"]["post_id"]).split("+")) == 1
):
submission = reddit.submission(id=settings.config["reddit"]["thread"]["post_id"])
else:
threads = subreddit.hot(limit=25)
submission = get_subreddit_undone(threads, subreddit)
submission = check_done(submission) # double-checking
@ -104,6 +103,7 @@ def get_subreddit_threads(POST_ID: str):
):
if (
top_level_comment.author is not None
and sanitize_text(top_level_comment.body) is not None
): # if errors occur with this change to if not.
content["comments"].append(
{

@ -36,7 +36,7 @@ def sleep_until(time):
# Convert datetime to unix timestamp and adjust for locality
if isinstance(time, datetime):
# If we're on Python 3 and the user specified a timezone, convert to UTC and get tje timestamp.
# If we're on Python 3 and the user specified a timezone, convert to UTC and get the timestamp.
if sys.version_info[0] >= 3 and time.tzinfo:
end = time.astimezone(timezone.utc).timestamp()
else:

@ -64,7 +64,7 @@ def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int
def get_background_config():
"""Fetch the background/s configuration"""
try:
choice = str(settings.config["settings"]["background_choice"]).casefold()
choice = str(settings.config["settings"]["background"]["background_choice"]).casefold()
except AttributeError:
print_substep("No background selected. Picking random background'")
choice = None

@ -3,30 +3,22 @@ import multiprocessing
import os
import re
from os.path import exists
from typing import Dict, Tuple, Any
from typing import Tuple, Any
import translators as ts
from moviepy.editor import (
VideoFileClip,
AudioFileClip,
ImageClip,
concatenate_videoclips,
concatenate_audioclips,
CompositeAudioClip,
CompositeVideoClip,
)
from moviepy.editor import (VideoFileClip, AudioFileClip, ImageClip, concatenate_videoclips, concatenate_audioclips,
CompositeAudioClip, CompositeVideoClip, )
from moviepy.video.io.ffmpeg_tools import ffmpeg_merge_video_audio, ffmpeg_extract_subclip
from rich.console import Console
import moviepy.editor as mpe
from utils.cleanup import cleanup
from utils.console import print_step, print_substep
from utils.videos import save_data
from utils import settings
console = Console()
VOLUME_MULTIPLIER = settings.config["settings"]['background']["background_audio_volume"]
W, H = 1080, 1920
@ -48,9 +40,7 @@ def name_normalize(name: str) -> str:
return name
def make_final_video(
number_of_clips: int, length: int, reddit_obj: dict, background_config: Tuple[str, str, str, Any]
):
def make_final_video(number_of_clips: int, length: int, reddit_obj: dict, background_config: Tuple[str, str, str, Any]):
"""Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp
Args:
number_of_clips (int): Index to end at when going through the screenshots'
@ -63,11 +53,8 @@ def make_final_video(
VideoFileClip.reH = lambda clip: clip.resize(width=H)
opacity = settings.config["settings"]["opacity"]
background_clip = (
VideoFileClip("assets/temp/background.mp4")
.without_audio()
.resize(height=H)
.crop(x1=1166.6, y1=0, x2=2246.6, y2=1920)
)
VideoFileClip("assets/temp/background.mp4").without_audio().resize(height=H).crop(x1=1166.6, y1=0, x2=2246.6,
y2=1920))
# Gather all audio clips
audio_clips = [AudioFileClip(f"assets/temp/mp3/{i}.mp3") for i in range(number_of_clips)]
@ -80,21 +67,13 @@ def make_final_video(
image_clips = []
# Gather all images
new_opacity = 1 if opacity is None or float(opacity) >= 1 else float(opacity)
image_clips.insert(
0,
ImageClip("assets/temp/png/title.png")
.set_duration(audio_clips[0].duration)
.resize(width=W - 100)
.set_opacity(new_opacity),
)
image_clips.insert(0, ImageClip("assets/temp/png/title.png").set_duration(audio_clips[0].duration).resize(
width=W - 100).set_opacity(new_opacity), )
for i in range(0, number_of_clips):
image_clips.append(
ImageClip(f"assets/temp/png/comment_{i}.png")
.set_duration(audio_clips[i + 1].duration)
.resize(width=W - 100)
.set_opacity(new_opacity)
)
ImageClip(f"assets/temp/png/comment_{i}.png").set_duration(audio_clips[i + 1].duration).resize(
width=W - 100).set_opacity(new_opacity))
# if os.path.exists("assets/mp3/posttext.mp3"):
# image_clips.insert(
@ -122,51 +101,32 @@ def make_final_video(
print_substep("The results folder didn't exist so I made it")
os.makedirs(f"./results/{subreddit}")
final.write_videofile(
"assets/temp/temp.mp4",
fps=30,
audio_codec="aac",
audio_bitrate="192k",
verbose=False,
threads=multiprocessing.cpu_count(),
)
if settings.config["settings"]["background_audio"]:
print("[bold green] Merging background audio with video")
if not exists(f"assets/backgrounds/background.mp3"):
print_substep(
"Cannot find assets/backgrounds/background.mp3 audio file didn't so skipping."
)
ffmpeg_extract_subclip(
"assets/temp/temp.mp4",
0,
final.duration,
targetname=f"results/{subreddit}/{filename}",
)
else:
ffmpeg_merge_video_audio(
"assets/temp/temp.mp4",
"assets/backgrounds/background.mp3",
"assets/temp/temp_audio.mp4",
)
ffmpeg_extract_subclip( # check if this gets run
"assets/temp/temp_audio.mp4",
0,
final.duration,
targetname=f"results/{subreddit}/{filename}",
)
final.write_videofile("assets/temp/temp.mp4", fps=30, audio_codec="aac", audio_bitrate="192k", verbose=False,
threads=multiprocessing.cpu_count(), )
if settings.config["settings"]['background']["background_audio"] and exists(f"assets/backgrounds/background.mp3"):
if not isinstance(VOLUME_MULTIPLIER, float):
print("No background audio volume set, using default of .3 set it in the config.toml file")
assert VOLUME_MULTIPLIER == float(0.3)
print('Merging background audio with video')
my_clip = mpe.VideoFileClip('assets/temp/temp.mp4')
audio_background = AudioFileClip("assets/backgrounds/background.mp3")
lowered_audio = audio_background.multiply_volume(
VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx
lowered_audio = lowered_audio.subclip(0, my_clip.duration) # trim the audio to the length of the video
lowered_audio.set_duration(my_clip.duration) # set the duration of the audio to the length of the video
final_audio = mpe.CompositeAudioClip([my_clip.audio, lowered_audio])
final_clip = my_clip.set_audio(final_audio)
final_clip.write_videofile("assets/temp/temp_audio.mp4", fps=30, audio_codec="aac", audio_bitrate="192k",
verbose=False, threads=multiprocessing.cpu_count())
ffmpeg_extract_subclip( # check if this gets run
"assets/temp/temp_audio.mp4", 0, final.duration, targetname=f"results/{subreddit}/{filename}", )
else:
print("debug duck")
ffmpeg_extract_subclip(
"assets/temp/temp.mp4",
0,
final.duration,
targetname=f"results/{subreddit}/{filename}",
)
ffmpeg_extract_subclip("assets/temp/temp.mp4", 0, final.duration,
targetname=f"results/{subreddit}/{filename}", )
print_step("Removing temporary files 🗑")
cleanups = cleanup()
print_substep(f"Removed {cleanups} temporary files 🗑")
print_substep("See result in the results folder!")
print_step(
f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}'
)
print_step(f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}')

@ -34,7 +34,7 @@ def save_text_to_mp3(reddit_obj) -> Tuple[int, int]:
"""
voice = settings.config["settings"]["tts"]["choice"]
if voice.casefold() in map(lambda _: _.casefold(), TTSProviders):
if str(voice).casefold() in map(lambda _: _.casefold(), TTSProviders):
text_to_mp3 = TTSEngine(get_case_insensitive_key_value(TTSProviders, voice), reddit_obj)
else:
while True:

Loading…
Cancel
Save