1 parent
c3eae6feae
commit
bfe577643c
9 files changed
+147
-134
No files matched your search
@@ -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
|
||||
|
||||
Regular → Executable
+41
-24
@@ -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.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.
|
||||
context = browser.new_context(
|
||||
locale=lang or "en-us",
|
||||
color_scheme="dark",
|
||||
viewport=ViewportSize(width=W, height=H),
|
||||
device_scale_factor=dsf,
|
||||
)
|
||||
|
||||
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
|
||||
# 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()
|
||||
|
||||
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
|
||||
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))
|
||||
|
||||
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
|
||||
|
||||
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"],
|
||||
)
|
||||
|
||||
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
|
||||
if lang:
|
||||
print_substep("Translating post...")
|
||||
texts_in_tl = ts.google(
|
||||
reddit_object["thread_title"],
|
||||
to_language=lang,
|
||||
)
|
||||
|
||||
if settings.config["settings"]["storymode"]:
|
||||
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...")
|
||||
|
||||
try: # new change
|
||||
page.locator('[data-click-id="text"]').first.screenshot(
|
||||
path=f"assets/temp/{id}/png/story_content.png"
|
||||
postcontentpath = f"assets/temp/{reddit_id}/png/title.png"
|
||||
page.locator('[data-test-id="post-content"]').screenshot(path=postcontentpath)
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
if page.locator('[data-testid="content-gate"]').is_visible():
|
||||
page.locator('[data-testid="content-gate"] button').click()
|
||||
# close browser instance when we are done using it
|
||||
browser.close()
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
Reference in new issue
Block a user