Add the option to customize the resolution of the video

pull/1277/head
John Toniutti 3 years ago
parent dcd0ff5b12
commit b3e288ca21
No known key found for this signature in database
GPG Key ID: 3C5434E3920EE1E1

@ -21,8 +21,9 @@ theme = { optional = false, default = "dark", example = "light", options = ["dar
times_to_run = { optional = false, default = 1, example = 2, explanation = "Used if you want to run multiple times. Set to an int e.g. 4 or 29 or 1", type = "int", nmin = 1, oob_error = "It's very hard to run something less than once." }
opacity = { optional = false, default = 0.9, example = 0.8, explanation = "Sets the opacity of the comments when overlayed over the background", type = "float", nmin = 0, nmax = 1, oob_error = "The opacity HAS to be between 0 and 1", input_error = "The opacity HAS to be a decimal number between 0 and 1" }
transition = { optional = true, default = 0.2, example = 0.2, explanation = "Sets the transition time (in seconds) between the comments. Set to 0 if you want to disable it.", type = "float", nmin = 0, nmax = 2, oob_error = "The transition HAS to be between 0 and 2", input_error = "The opacity HAS to be a decimal number between 0 and 2" }
storymode = { optional = true, type = "bool", default = false, example = false, options = [true, false, ], explanation = "Only read out title and post content, not yet implemented" }
storymode = { optional = false, type = "bool", default = false, example = false, options = [true, false, ], explanation = "Only read out title and post content, not yet implemented" }
resolution_w = { optional = false, default = 1080, example = 1440, explantation = "Sets the width 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]
background_choice = { optional = true, default = "minecraft", example = "rocket-league", options = ["", "minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck"], explanation = "Sets the background for the video based on game name" }

@ -3,7 +3,7 @@ import multiprocessing
import os
import re
from os.path import exists
from typing import Tuple, Any
from typing import Tuple, Any, Final
from moviepy.audio.AudioClip import concatenate_audioclips, CompositeAudioClip
from moviepy.audio.io.AudioFileClip import AudioFileClip
@ -21,7 +21,6 @@ from utils.video import Video
from utils.videos import save_data
console = Console()
W, H = 1080, 1920
def name_normalize(name: str) -> str:
@ -45,6 +44,20 @@ def name_normalize(name: str) -> str:
return name
def prepare_background(id: str, W: int, H: int) -> VideoFileClip:
clip = VideoFileClip(f"assets/temp/{id}/background.mp4").without_audio().resize(height=H)
# calculate the center of the background clip
c = clip.w // 2
# calculate the coordinates where to crop
half_w = W // 2
x1 = c - half_w
x2 = c + half_w
return clip.crop(x1=x1, y1=0, x2=x2, y2=H)
def make_final_video(
number_of_clips: int,
length: int,
@ -58,23 +71,26 @@ def make_final_video(
reddit_obj (dict): The reddit object that contains the posts to read.
background_config (Tuple[str, str, str, Any]): The background config to use.
"""
# settings values
W: Final[int] = int(settings.config["settings"]["resolution_w"])
H: Final[int] = int(settings.config["settings"]["resolution_h"])
# try: # if it isn't found (i.e you just updated and copied over config.toml) it will throw an error
# VOLUME_MULTIPLIER = settings.config["settings"]['background']["background_audio_volume"]
# except (TypeError, KeyError):
# print('No background audio volume found in config.toml. Using default value of 1.')
# VOLUME_MULTIPLIER = 1
id = re.sub(r"[^\w\s-]", "", reddit_obj["thread_id"])
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"]
transition = settings.config["settings"]["transition"]
background_clip = (
VideoFileClip(f"assets/temp/{id}/background.mp4")
.without_audio()
.resize(height=H)
.crop(x1=1166.6, y1=0, x2=2246.6, y2=1920)
)
background_clip = prepare_background(id, W=W, H=H)
# Gather all audio clips
audio_clips = [AudioFileClip(f"assets/temp/{id}/mp3/{i}.mp3") for i in range(number_of_clips)]
@ -88,11 +104,12 @@ def make_final_video(
# Gather all images
new_opacity = 1 if opacity is None or float(opacity) >= 1 else float(opacity)
new_transition = 0 if transition is None or float(transition) > 2 else float(transition)
screenshow_width = int((W*90)//100)
image_clips.insert(
0,
ImageClip(f"assets/temp/{id}/png/title.png")
.set_duration(audio_clips[0].duration)
.resize(width=W - 100)
.resize(width=screenshow_width)
.set_opacity(new_opacity)
.crossfadein(new_transition)
.crossfadeout(new_transition),
@ -102,7 +119,7 @@ def make_final_video(
image_clips.append(
ImageClip(f"assets/temp/{id}/png/comment_{i}.png")
.set_duration(audio_clips[i + 1].duration)
.resize(width=W - 100)
.resize(width=screenshow_width)
.set_opacity(new_opacity)
.crossfadein(new_transition)
.crossfadeout(new_transition)
@ -118,6 +135,7 @@ def make_final_video(
# .set_opacity(float(opacity)),
# )
# else: story mode stuff
img_clip_pos = background_config[3]
image_concat = concatenate_videoclips(image_clips).set_position(img_clip_pos) # note transition kwarg for delay in imgs
image_concat.audio = audio_composite
@ -139,6 +157,7 @@ def make_final_video(
# # 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, redditid=reddit_obj)
final.write_videofile(
f"assets/temp/{id}/temp.mp4",

@ -1,7 +1,7 @@
import json
import re
import json
from pathlib import Path
from typing import Dict
from typing import Final
import translators as ts
from playwright.sync_api import sync_playwright, ViewportSize
@ -10,9 +10,8 @@ from rich.progress import track
from utils import settings
from utils.console import print_step, print_substep
# do not remove the above line
storymode = False
__all__ = ["download_screenshots_of_reddit_posts"]
def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
@ -22,6 +21,12 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
reddit_object (Dict): Reddit object received from reddit/subreddit.py
screenshot_num (int): Number of screenshots to download
"""
# settings values
W: Final[int] = int(settings.config["settings"]["resolution_w"])
H: Final[int] = int(settings.config["settings"]["resolution_h"])
lang: Final[str] = settings.config["reddit"]["thread"]["post_lang"]
storymode: Final[bool] = settings.config["settings"]["storymode"]
print_step("Downloading screenshots of reddit posts...")
id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"])
# ! Make sure the reddit screenshots folder exists
@ -31,18 +36,32 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
print_substep("Launching Headless Browser...")
browser = p.chromium.launch(headless=True) # add headless=False for debug
context = browser.new_context()
# Device scale factor (or dsf for short) allows us to increase the resolution of the screenshots
# When the dsf is 1, the width of the screenshot is 600 pixels
# so we need a dsf such that the width of the screenshot is greater than the final resolution of the video
dsf = (W // 600)+1
context = browser.new_context(
locale=lang or "en-us",
color_scheme="dark",
viewport=ViewportSize(width=W, height=H),
device_scale_factor=dsf
)
# 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")
else:
cookie_file = open("./video_creation/data/cookie-light-mode.json", encoding="utf-8")
cookies = json.load(cookie_file)
context.add_cookies(cookies) # load preference cookies
# Get the thread screenshot
page = context.new_page()
page.goto(reddit_object["thread_url"], timeout=0)
page.set_viewport_size(ViewportSize(width=1920, height=1080))
page.set_viewport_size(ViewportSize(width=W, height=H))
if page.locator('[data-testid="content-gate"]').is_visible():
# This means the post is NSFW and requires to click the proceed button.
@ -55,11 +74,11 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
# translate code
if settings.config["reddit"]["thread"]["post_lang"]:
if lang:
print_substep("Translating post...")
texts_in_tl = ts.google(
reddit_object["thread_title"],
to_language=settings.config["reddit"]["thread"]["post_lang"],
to_language=lang,
)
page.evaluate(
@ -75,7 +94,7 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
if storymode:
page.locator('[data-click-id="text"]').screenshot(path=f"assets/temp/{id}/png/story_content.png")
else:
for idx, comment in enumerate(track(reddit_object["comments"], "Downloading screenshots...")):
for idx, comment in enumerate(track(reddit_object["comments"][:screenshot_num], "Downloading screenshots...")):
# Stop if we have reached the screenshot_num
if idx >= screenshot_num:
break
@ -103,4 +122,8 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
screenshot_num += 1
print("TimeoutError: Skipping screenshot...")
continue
# close browser instance when we are done using it
browser.close()
print_substep("Screenshots downloaded Successfully.", style="bold green")

Loading…
Cancel
Save