refactor in final_video + fixes

pull/963/head
Drugsosos 2 years ago
parent 1d968ee7b7
commit a01da8a8bf
No known key found for this signature in database
GPG Key ID: 8E35176FE617E28D

@ -13,7 +13,7 @@ from utils import settings
from video_creation.background import ( from video_creation.background import (
get_background_config, get_background_config,
) )
from video_creation.final_video import make_final_video from video_creation.final_video import FinalVideo
from video_creation.screenshot_downloader import RedditScreenshot from video_creation.screenshot_downloader import RedditScreenshot
from video_creation.voices import save_text_to_mp3 from video_creation.voices import save_text_to_mp3
@ -45,7 +45,7 @@ async def main(
comments_created = save_text_to_mp3(reddit_object) comments_created = save_text_to_mp3(reddit_object)
await RedditScreenshot(reddit_object, comments_created).download() await RedditScreenshot(reddit_object, comments_created).download()
bg_config = get_background_config() bg_config = get_background_config()
make_final_video(comments_created, reddit_object, bg_config) FinalVideo().make(comments_created, reddit_object, bg_config)
async def run_many(times): async def run_many(times):

@ -15,6 +15,7 @@ from moviepy.editor import (
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from rich.console import Console from rich.console import Console
from rich.progress import track from rich.progress import track
from attr import attrs
from utils.cleanup import cleanup from utils.cleanup import cleanup
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
@ -23,243 +24,261 @@ from utils.videos import save_data
from utils import settings from utils import settings
from video_creation.background import download_background, chop_background_video from video_creation.background import download_background, chop_background_video
console = Console()
def name_normalize(
name: str
) -> str:
name = re.sub(r'[?\\"%*:|<>]', "", name)
name = re.sub(r"( [w,W]\s?\/\s?[o,O,0])", r" without", name)
name = re.sub(r"( [w,W]\s?\/)", r" with", name)
name = re.sub(r"(\d+)\s?\/\s?(\d+)", r"\1 of \2", name)
name = re.sub(r"(\w+)\s?\/\s?(\w+)", r"\1 or \2", name)
name = re.sub(r"\/", "", name)
# name[:30] # the hell this little guy does? commented until explained
lang = settings.config["reddit"]["thread"]["post_lang"]
if lang:
import translators as ts
print_substep("Translating filename...")
translated_name = ts.google(name, to_language=lang)
return translated_name
return name
def make_final_video(
indexes_of_clips: list,
reddit_obj: dict,
background_config: Tuple[str, str, str, Any],
) -> None:
"""
Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp
Args:
indexes_of_clips (list): Indexes of voiced comments
reddit_obj (dict): The reddit object that contains the posts to read.
background_config (Tuple[str, str, str, Any]): The background config to use.
"""
W: int = int(settings.config["settings"]["video_width"])
H: int = int(settings.config["settings"]["video_height"])
if not W or not H:
W, H = 1080, 1920
max_length: int = int(settings.config["settings"]["video_length"])
time_before_first_picture: float = settings.config["settings"]["time_before_first_picture"]
time_before_tts: float = settings.config["settings"]["time_before_tts"]
time_between_pictures: float = settings.config["settings"]["time_between_pictures"]
delay_before_end: float = settings.config["settings"]["delay_before_end"]
print_step("Creating the final video 🎥")
VideoFileClip.reW = lambda clip: clip.resize(width=W)
VideoFileClip.reH = lambda clip: clip.resize(width=H)
opacity = settings.config["settings"]["opacity"] / 100
@attrs
class FinalVideo:
video_duration: int = 0
console = Console()
def __attrs_post_init__(self):
self.W: int = int(settings.config["settings"]["video_width"])
self.H: int = int(settings.config["settings"]["video_height"])
if not self.W or not self.H:
self.W, self.H = 1080, 1920
self.vertical_video: bool = self.W < self.H
self.max_length: int = int(settings.config["settings"]["video_length"])
self.time_before_first_picture: float = settings.config["settings"]["time_before_first_picture"]
self.time_before_tts: float = settings.config["settings"]["time_before_tts"]
self.time_between_pictures: float = settings.config["settings"]["time_between_pictures"]
self.delay_before_end: float = settings.config["settings"]["delay_before_end"]
self.opacity = settings.config["settings"]["opacity"]
self.opacity = 1 if self.opacity is None or self.opacity >= 1 else self.opacity
@staticmethod
def name_normalize(
name: str
) -> str:
name = re.sub(r'[?\\"%*:|<>]', "", name)
name = re.sub(r"( [w,W]\s?\/\s?[o,O,0])", r" without", name)
name = re.sub(r"( [w,W]\s?\/)", r" with", name)
name = re.sub(r"(\d+)\s?\/\s?(\d+)", r"\1 of \2", name)
name = re.sub(r"(\w+)\s?\/\s?(\w+)", r"\1 or \2", name)
name = re.sub(r"\/", "", name)
# name[:30] # the hell this little guy does? commented until explained
lang = settings.config["reddit"]["thread"]["post_lang"]
if lang:
import translators as ts
print_substep("Translating filename...")
translated_name = ts.google(name, to_language=lang)
return translated_name
return name
@staticmethod
def create_audio_clip( def create_audio_clip(
clip_title: Union[str, int], clip_title: Union[str, int],
clip_start: float, clip_start: float,
) -> 'AudioFileClip': ) -> AudioFileClip:
return ( return (
AudioFileClip(f"assets/temp/mp3/{clip_title}.mp3") AudioFileClip(f"assets/temp/mp3/{clip_title}.mp3")
.set_start(clip_start) .set_start(clip_start)
) )
video_duration = 0
# Gather all audio clips
audio_clips = list()
correct_audio_offset = time_before_tts * 2 + time_between_pictures
audio_title = create_audio_clip(
"title",
time_before_first_picture + time_before_tts,
)
video_duration += audio_title.duration + time_before_first_picture + time_before_tts
audio_clips.append(audio_title)
indexes_for_videos = list()
for audio_title in track(
indexes_of_clips,
description="Gathering audio clips...",
total=indexes_of_clips.__len__()
):
temp_audio_clip = create_audio_clip(
audio_title,
correct_audio_offset + video_duration,
)
if video_duration + temp_audio_clip.duration + correct_audio_offset + delay_before_end <= max_length:
video_duration += temp_audio_clip.duration + correct_audio_offset
audio_clips.append(temp_audio_clip)
indexes_for_videos.append(audio_title)
video_duration += delay_before_end + time_before_tts
# Can't use concatenate_audioclips here, it resets clips' start point
audio_composite = CompositeAudioClip(audio_clips)
console.log("[bold green] Video Will Be: %.2f Seconds Long" % video_duration)
# Gather all images
new_opacity = 1 if opacity is None or opacity >= 1 else opacity
def create_image_clip( def create_image_clip(
self,
image_title: Union[str, int], image_title: Union[str, int],
audio_start: float, audio_start: float,
audio_duration: float, audio_duration: float,
) -> 'ImageClip': clip_position: str,
) -> ImageClip:
return ( return (
ImageClip(f"assets/temp/png/{image_title}.png") ImageClip(f"assets/temp/png/{image_title}.png")
.set_start(audio_start - time_before_tts) .set_start(audio_start - self.time_before_tts)
.set_duration(time_before_tts * 2 + audio_duration) .set_duration(self.time_before_tts * 2 + audio_duration)
.set_opacity(new_opacity) .set_opacity(self.opacity)
.resize(width=W - 100) .set_position(clip_position)
.resize(
width=self.W - self.W / 20 if self.vertical_video else None,
height=self.H - self.H / 5 if not self.vertical_video else None,
)
) )
# add title to video def make(
image_clips = list() self,
indexes_of_clips: list,
# Accounting for title and other stuff if audio_clips reddit_obj: dict,
index_offset = 1 background_config: Tuple[str, str, str, Any],
) -> None:
image_clips.append( """
create_image_clip( Gathers audio clips, gathers all screenshots, stitches them together and saves the final video to assets/temp
Args:
indexes_of_clips (list): Indexes of voiced comments
reddit_obj (dict): The reddit object that contains the posts to read.
background_config (Tuple[str, str, str, Any]): The background config to use.
"""
print_step("Creating the final video 🎥")
# Gather all audio clips
audio_clips = list()
correct_audio_offset = self.time_before_tts * 2 + self.time_between_pictures
audio_title = self.create_audio_clip(
"title", "title",
audio_clips[0].start, self.time_before_first_picture + self.time_before_tts,
audio_clips[0].duration
) )
) self.video_duration += audio_title.duration + self.time_before_first_picture + self.time_before_tts
audio_clips.append(audio_title)
for idx, photo_idx in track( indexes_for_videos = list()
enumerate(
indexes_for_videos, for audio_title in track(
start=index_offset, indexes_of_clips,
), description="Gathering audio clips...",
description="Gathering audio clips...", total=indexes_of_clips.__len__()
total=indexes_for_videos[index_offset:].__len__() ):
): temp_audio_clip = self.create_audio_clip(
audio_title,
correct_audio_offset + self.video_duration,
)
if self.video_duration + temp_audio_clip.duration + \
correct_audio_offset + self.delay_before_end <= self.max_length:
self.video_duration += temp_audio_clip.duration + correct_audio_offset
audio_clips.append(temp_audio_clip)
indexes_for_videos.append(audio_title)
self.video_duration += self.delay_before_end + self.time_before_tts
# Can't use concatenate_audioclips here, it resets clips' start point
audio_composite = CompositeAudioClip(audio_clips)
self.console.log("[bold green] Video Will Be: %.2f Seconds Long" % self.video_duration)
# Gather all images
image_clips = list()
# Accounting for title and other stuff if audio_clips
index_offset = 1
image_clips.append( image_clips.append(
create_image_clip( self.create_image_clip(
f"comment_{photo_idx}", "title",
audio_clips[idx].start, audio_clips[0].start,
audio_clips[idx].duration audio_clips[0].duration,
background_config[3],
) )
) )
# if os.path.exists("assets/mp3/posttext.mp3"): for idx, photo_idx in track(
# image_clips.insert( enumerate(
# 0, indexes_for_videos,
# ImageClip("assets/png/title.png") start=index_offset,
# .set_duration(audio_clips[0].duration + audio_clips[1].duration) ),
# .set_position("center") description="Gathering audio clips...",
# .resize(width=W - 100) total=indexes_for_videos.__len__()
# .set_opacity(float(opacity)), ):
# ) image_clips.append(
# else: story mode stuff self.create_image_clip(
f"comment_{photo_idx}",
# Can't use concatenate_videoclips here, it resets clips' start point audio_clips[idx].start,
image_concat = CompositeVideoClip(image_clips) audio_clips[idx].duration,
image_concat.set_position(background_config[3]) background_config[3],
)
download_background(background_config) )
chop_background_video(background_config, video_duration)
background_clip = ( # if os.path.exists("assets/mp3/posttext.mp3"):
VideoFileClip("assets/temp/background.mp4") # image_clips.insert(
.set_start(0) # 0,
.set_end(video_duration) # ImageClip("assets/png/title.png")
.without_audio() # .set_duration(audio_clips[0].duration + audio_clips[1].duration)
.resize(height=H) # .set_position("center")
) # .resize(width=W - 100)
# .set_opacity(float(opacity)),
back_video_width, back_video_height = background_clip.size # )
# else: story mode stuff
# Fix for crop with vertical videos
if back_video_width < H: # Can't use concatenate_videoclips here, it resets clips' start point
image_concat = CompositeVideoClip(image_clips)
image_concat.set_position(background_config[3])
download_background(background_config)
chop_background_video(background_config, self.video_duration)
background_clip = ( background_clip = (
background_clip VideoFileClip("assets/temp/background.mp4")
.resize(width=W) .set_start(0)
.set_end(self.video_duration)
.without_audio()
.resize(height=self.H)
) )
back_video_width, back_video_height = background_clip.size back_video_width, back_video_height = background_clip.size
background_clip = background_clip.crop(
x1=0, # Fix for crop with vertical videos
x2=back_video_width, if back_video_width < self.H:
y1=back_video_height / 2 - H / 2, background_clip = (
y2=back_video_height / 2 + H / 2 background_clip
) .resize(width=self.W)
else: )
background_clip = background_clip.crop( back_video_width, back_video_height = background_clip.size
x1=back_video_width / 2 - W / 2, background_clip = background_clip.crop(
x2=back_video_width / 2 + W / 2, x1=0,
y1=0, x2=back_video_width,
y2=back_video_height y1=back_video_height / 2 - self.H / 2,
y2=back_video_height / 2 + self.H / 2
)
else:
background_clip = background_clip.crop(
x1=back_video_width / 2 - self.W / 2,
x2=back_video_width / 2 + self.W / 2,
y1=0,
y2=back_video_height
)
final = CompositeVideoClip([background_clip, image_concat])
final.audio = audio_composite
title = re.sub(r"[^\w\s-]", "", reddit_obj["thread_title"])
idx = re.sub(r"[^\w\s-]", "", reddit_obj["thread_id"])
filename = f"{self.name_normalize(title)}.mp4"
subreddit = str(settings.config["reddit"]["thread"]["subreddit"])
if not exists(f"./results/{subreddit}"):
print_substep("The results folder didn't exist so I made it")
os.makedirs(f"./results/{subreddit}")
# if (
# settings.config["settings"]['background']["background_audio"] and
# exists(f"assets/backgrounds/background.mp3")
# ):
# audioclip = (
# AudioFileClip(f"assets/backgrounds/background.mp3")
# .set_duration(final.duration)
# .volumex(0.2)
# )
# final_audio = CompositeAudioClip([final.audio, audioclip])
# # lowered_audio = audio_background.multiply_volume( # TODO get this to work
# # VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx
# final.set_audio(final_audio)
final = Video(final).add_watermark(
text=f"Background credit: {background_config[2]}", opacity=0.4
) )
final = CompositeVideoClip([background_clip, image_concat]) final.write_videofile(
final.audio = audio_composite "assets/temp/temp.mp4",
fps=30,
title = re.sub(r"[^\w\s-]", "", reddit_obj["thread_title"]) audio_codec="aac",
idx = re.sub(r"[^\w\s-]", "", reddit_obj["thread_id"]) audio_bitrate="192k",
verbose=False,
filename = f"{name_normalize(title)}.mp4" threads=multiprocessing.cpu_count(),
subreddit = str(settings.config["reddit"]["thread"]["subreddit"]) )
ffmpeg_extract_subclip(
if not exists(f"./results/{subreddit}"): "assets/temp/temp.mp4",
print_substep("The results folder didn't exist so I made it") 0,
os.makedirs(f"./results/{subreddit}") self.video_duration,
targetname=f"results/{subreddit}/{filename}",
# if settings.config["settings"]['background']["background_audio"] and exists(f"assets/backgrounds/background.mp3"): )
# audioclip = mpe.AudioFileClip(f"assets/backgrounds/background.mp3").set_duration(final.duration) save_data(subreddit, filename, title, idx, background_config[2])
# audioclip = audioclip.fx( volumex, 0.2) print_step("Removing temporary files 🗑")
# final_audio = mpe.CompositeAudioClip([final.audio, audioclip]) cleanups = cleanup()
# # lowered_audio = audio_background.multiply_volume( # todo get this to work print_substep(f"Removed {cleanups} temporary files 🗑")
# # VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx print_substep("See result in the results folder!")
# final.set_audio(final_audio)
print_step(
final = Video(final).add_watermark( f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}'
text=f"Background credit: {background_config[2]}", opacity=0.4 )
)
final.write_videofile(
"assets/temp/temp.mp4",
fps=30,
audio_codec="aac",
audio_bitrate="192k",
verbose=False,
threads=multiprocessing.cpu_count(),
)
ffmpeg_extract_subclip(
"assets/temp/temp.mp4",
0,
video_duration,
targetname=f"results/{subreddit}/{filename}",
)
save_data(subreddit, filename, title, idx, background_config[2])
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]}'
)

Loading…
Cancel
Save