Custom resolution (#1277)

Thank you @jotonedev!
pull/1410/head
John Toniutti 2 years ago committed by GitHub
parent c3eae6feae
commit bfe577643c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random
from gtts import gTTS

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random
import sys

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os
import re
from pathlib import Path

@ -27,7 +27,8 @@ storymode = { optional = true, type = "bool", default = false, example = false,
storymodemethod= { optional = true, default = 1, example = 1, explanation = "Style that's used for the storymode. Set to 0 for single picture display in whole video, set to 1 for fancy looking video ", type = "int", nmin = 0, oob_error = "It's very hard to run something less than once.", options = [0, 1] }
storymode_max_length = { optional = true, default = 1000, example = 1000, explanation = "Max length of the storymode video in characters. 200 characters are approximately 50 seconds.", type = "int", nmin = 1, oob_error = "It's very hard to make a video under a second." }
fps = { optional = true, default = 30, example = 30, explanation = "Sets the FPS of the video, 30 is default for best performance. 60 FPS is smoother.", type = "int", nmin = 1, nmax = 60, oob_error = "The FPS HAS to be between 1 and 60" }
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", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" }

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import re
from rich.columns import Columns

@ -1,4 +1,3 @@
#!/usr/bin/env python
import re
from typing import Tuple, Dict
from pathlib import Path

@ -1,8 +1,9 @@
#!/usr/bin/env python3
import multiprocessing
import os
import re
import multiprocessing
from os.path import exists
from typing import Tuple, Any, Final
import translators as ts
import shutil
from typing import Tuple, Any
from PIL import Image
@ -26,7 +27,6 @@ from utils import settings
from utils.thumbnail import create_thumbnail
console = Console()
W, H = 1080, 1920
def name_normalize(name: str) -> str:
@ -36,20 +36,34 @@ def name_normalize(name: str) -> str:
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"\/", r"", name)
name[:30]
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
else:
return name
def prepare_background(reddit_id: str, W: int, H: int) -> VideoFileClip:
clip = (
VideoFileClip(f"assets/temp/{reddit_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,
@ -63,23 +77,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"])
reddit_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(reddit_id, W=W, H=H)
# Gather all audio clips
if settings.config["settings"]["storymode"]:
@ -112,11 +129,12 @@ def make_final_video(
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")
ImageClip(f"assets/temp/{reddit_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),
@ -238,15 +256,14 @@ 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)
# if
final = Video(final).add_watermark(
text=f"Background credit: {background_config[2]}", opacity=0.4, redditid=reddit_obj
text=f"Background credit: {background_config[2]}",
opacity=0.4,
redditid=reddit_obj,
)
final.write_videofile(
f"assets/temp/{id}/temp.mp4",
f"assets/temp/{reddit_id}/temp.mp4",
fps=int(settings.config["settings"]["fps"]),
audio_codec="aac",
audio_bitrate="192k",
@ -254,7 +271,7 @@ def make_final_video(
threads=multiprocessing.cpu_count(),
)
ffmpeg_extract_subclip(
f"assets/temp/{id}/temp.mp4",
f"assets/temp/{reddit_id}/temp.mp4",
0,
length,
targetname=f"results/{subreddit}/{filename}.mp4",
@ -265,7 +282,7 @@ def make_final_video(
save_data(subreddit, filename+".mp4", title, idx, background_config[2])
print_step("Removing temporary files 🗑")
cleanups = cleanup(id)
cleanups = cleanup(reddit_id)
print_substep(f"Removed {cleanups} temporary files 🗑")
print_substep("See result in the results folder!")

@ -1,7 +1,7 @@
import json
import re
from pathlib import Path
from typing import Dict
from typing import Dict, Final
import translators as ts
from playwright.async_api import async_playwright # pylint: disable=unused-import
@ -12,8 +12,8 @@ from utils import settings
from utils.console import print_step, print_substep
from utils.imagenarator import imagemaker
# do not remove the above line
__all__ = ["download_screenshots_of_reddit_posts"]
def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
"""Downloads screenshots of reddit posts as seen on the web. Downloads to assets/temp/png
@ -22,13 +22,16 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
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"])
reddit_id = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"])
# ! Make sure the reddit screenshots folder exists
Path(f"assets/temp/{id}/png").mkdir(parents=True, exist_ok=True)
Path(f"assets/temp/{reddit_id}/png").mkdir(parents=True, exist_ok=True)
def download(cookie_file, num=None):
screenshot_num = num
@ -38,111 +41,110 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
browser = p.chromium.launch() # headless=False #to check for chrome view
context = browser.new_context()
cookies = json.load(cookie_file)
# 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)
cookie_file.close()
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=W, height=H))
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=1080, height=1920))
if page.locator('[data-testid="content-gate"]').is_visible():
# This means the post is NSFW and requires to click the proceed button.
if page.locator('[data-testid="content-gate"]').is_visible():
# This means the post is NSFW and requires to click the proceed button.
print_substep("Post is NSFW. You are spicy...")
page.locator('[data-testid="content-gate"] button').click()
page.wait_for_load_state() # Wait for page to fully load
print_substep("Post is NSFW. You are spicy...")
page.locator('[data-testid="content-gate"] button').click()
page.wait_for_load_state() # Wait for page to fully load
if page.locator('[data-click-id="text"] button').is_visible():
page.locator(
'[data-click-id="text"] button'
).click() # Remove "Click to see nsfw" Button in Screenshot
if page.locator('[data-click-id="text"] button').is_visible():
page.locator(
'[data-click-id="text"] button'
).click() # Remove "Click to see nsfw" Button in Screenshot
# translate code
if settings.config["reddit"]["thread"]["post_lang"]:
print_substep("Translating post...")
texts_in_tl = ts.google(
reddit_object["thread_title"],
to_language=settings.config["reddit"]["thread"]["post_lang"],
)
if lang:
print_substep("Translating post...")
texts_in_tl = ts.google(
reddit_object["thread_title"],
to_language=lang,
)
page.evaluate(
"tl_content => document.querySelector('[data-test-id=\"post-content\"] > div:nth-child(3) > div > div').textContent = tl_content",
texts_in_tl,
)
else:
print_substep("Skipping translation...")
postcontentpath = f"assets/temp/{id}/png/title.png"
page.locator('[data-test-id="post-content"]').screenshot(
path=postcontentpath
page.evaluate(
"tl_content => document.querySelector('[data-test-id=\"post-content\"] > div:nth-child(3) > div > div').textContent = tl_content",
texts_in_tl,
)
else:
print_substep("Skipping translation...")
if settings.config["settings"]["storymode"]:
postcontentpath = f"assets/temp/{reddit_id}/png/title.png"
page.locator('[data-test-id="post-content"]').screenshot(path=postcontentpath)
try: # new change
page.locator('[data-click-id="text"]').first.screenshot(
path=f"assets/temp/{id}/png/story_content.png"
if storymode:
page.locator('[data-click-id="text"]').screenshot(
path=f"assets/temp/{reddit_id}/png/story_content.png"
)
else:
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
if page.locator('[data-testid="content-gate"]').is_visible():
page.locator('[data-testid="content-gate"] button').click()
page.goto(f'https://reddit.com{comment["comment_url"]}', timeout=0)
# translate code
if settings.config["reddit"]["thread"]["post_lang"]:
comment_tl = ts.google(
comment["comment_body"],
to_language=settings.config["reddit"]["thread"]["post_lang"],
)
except:
exit
if not settings.config["settings"]["storymode"]:
for idx, comment in enumerate(
track(reddit_object["comments"], "Downloading screenshots...")
):
# Stop if we have reached the screenshot_num
if idx >= screenshot_num:
break
if page.locator('[data-testid="content-gate"]').is_visible():
page.locator('[data-testid="content-gate"] button').click()
page.goto(f'https://reddit.com{comment["comment_url"]}', timeout=0)
# translate code
if settings.config["reddit"]["thread"]["post_lang"]:
comment_tl = ts.google(
comment["comment_body"],
to_language=settings.config["reddit"]["thread"][
"post_lang"
],
)
page.evaluate(
'([tl_content, tl_id]) => document.querySelector(`#t1_${tl_id} > div:nth-child(2) > div > div[data-testid="comment"] > div`).textContent = tl_content',
[comment_tl, comment["comment_id"]],
)
try:
page.locator(f"#t1_{comment['comment_id']}").screenshot(
path=f"assets/temp/{id}/png/comment_{idx}.png"
)
except TimeoutError:
del reddit_object["comments"]
screenshot_num -= 1
print("TimeoutError: Skipping screenshot...")
continue
print_substep("Screenshots downloaded Successfully.", style="bold green")
# story=False
theme = settings.config["settings"]["theme"]
if theme == "dark":
cookie_file = open(
"./video_creation/data/cookie-dark-mode.json", encoding="utf-8"
)
bgcolor = (33, 33, 36, 255)
txtcolor = (240, 240, 240)
else:
cookie_file = open(
"./video_creation/data/cookie-light-mode.json", encoding="utf-8"
)
bgcolor = (255, 255, 255, 255)
txtcolor = (0, 0, 0)
if settings.config["settings"]["storymode"]:
if settings.config["settings"]["storymodemethod"] == 1:
# for idx,item in enumerate(reddit_object["thread_post"]):
imagemaker(theme=bgcolor, reddit_obj=reddit_object, txtclr=txtcolor)
if (
settings.config["settings"]["storymodemethod"] == 0
or not settings.config["settings"]["storymode"]
):
download(cookie_file, screenshot_num)
page.evaluate(
'([tl_content, tl_id]) => document.querySelector(`#t1_${tl_id} > div:nth-child(2) > div > div[data-testid="comment"] > div`).textContent = tl_content',
[comment_tl, comment["comment_id"]],
)
try:
page.locator(f"#t1_{comment['comment_id']}").screenshot(
path=f"assets/temp/{reddit_id}/png/comment_{idx}.png"
)
except TimeoutError:
del reddit_object["comments"]
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")

@ -1,5 +1,3 @@
#!/usr/bin/env python
from typing import Tuple
from rich.console import Console

Loading…
Cancel
Save