From 3a77e291a2291cedd20bd3247868afee8a314ed3 Mon Sep 17 00:00:00 2001 From: Almamu Date: Sat, 10 May 2025 06:20:13 +0200 Subject: [PATCH] chore: update script to make use of video generation instead of the old python scripts --- .../Application/CApplicationContext.cpp | 1 + .../Application/CWallpaperApplication.cpp | 19 +++- src/recording.cpp | 2 +- tools/run-over-all-backgrounds.sh | 19 +++- tools/scripts/process.py | 94 ------------------ tools/scripts/run.py | 97 ------------------- 6 files changed, 33 insertions(+), 199 deletions(-) delete mode 100644 tools/scripts/process.py delete mode 100644 tools/scripts/run.py diff --git a/src/WallpaperEngine/Application/CApplicationContext.cpp b/src/WallpaperEngine/Application/CApplicationContext.cpp index 126525b..de9bef7 100644 --- a/src/WallpaperEngine/Application/CApplicationContext.cpp +++ b/src/WallpaperEngine/Application/CApplicationContext.cpp @@ -276,6 +276,7 @@ CApplicationContext::CApplicationContext (int argc, char* argv []) : #if DEMOMODE sLog.error ("WARNING: RUNNING IN DEMO MODE WILL STOP WALLPAPERS AFTER 5 SECONDS SO VIDEO CAN BE RECORDED"); // special settings for demomode + this->settings.render.maximumFPS = 30; this->settings.screenshot.take = false; this->settings.render.pauseOnFullscreen = false; #endif /* DEMOMODE */ diff --git a/src/WallpaperEngine/Application/CWallpaperApplication.cpp b/src/WallpaperEngine/Application/CWallpaperApplication.cpp index ad1fbe6..0c118e1 100644 --- a/src/WallpaperEngine/Application/CWallpaperApplication.cpp +++ b/src/WallpaperEngine/Application/CWallpaperApplication.cpp @@ -404,8 +404,9 @@ void CWallpaperApplication::show () { int width = this->m_renderContext->getWallpapers ().begin ()->second->getWidth (); int height = this->m_renderContext->getWallpapers ().begin ()->second->getHeight (); std::vector pixels(width * height * 3); - init_encoder ("output.webm", width, height); + bool initialized = false; int frame = 0; + int elapsed_frames = 0; #endif /* DEMOMODE */ while (this->m_context.state.general.keepRunning) { @@ -431,8 +432,20 @@ void CWallpaperApplication::show () { } #if DEMOMODE - // do not record frames unless a second has passed - if (g_Time > 1) { + elapsed_frames ++; + + // wait for a full render cycle before actually starting + // this gives some extra time for video and web decoders to set themselves up + // because of size changes + if (elapsed_frames > this->m_context.settings.render.maximumFPS) { + if (!initialized) { + width = this->m_renderContext->getWallpapers ().begin ()->second->getWidth (); + height = this->m_renderContext->getWallpapers ().begin ()->second->getHeight (); + pixels.reserve(width * height * 3); + init_encoder ("output.webm", width, height); + initialized = true; + } + glBindFramebuffer (GL_FRAMEBUFFER, this->m_renderContext->getWallpapers ().begin ()->second->getWallpaperFramebuffer()); glPixelStorei (GL_PACK_ALIGNMENT, 1); diff --git a/src/recording.cpp b/src/recording.cpp index cd1a420..2c10296 100644 --- a/src/recording.cpp +++ b/src/recording.cpp @@ -20,7 +20,7 @@ extern "C" { } const int FPS = 30; -const int FRAME_COUNT = 150; +const int FRAME_COUNT = FPS * 5; int WIDTH = 0; int HEIGHT = 0; int SOURCE_WIDTH = 0; diff --git a/tools/run-over-all-backgrounds.sh b/tools/run-over-all-backgrounds.sh index 521c069..fff362f 100755 --- a/tools/run-over-all-backgrounds.sh +++ b/tools/run-over-all-backgrounds.sh @@ -3,10 +3,21 @@ if [ $# -eq 0 ] then echo "Please provide the current build's executable path. You might want to run this script off the same folder." fi -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) # ensure the output and images directory exists [ -d "output" ] || mkdir output -[ -d "images" ] || mkdir images -python ${SCRIPT_DIR}/scripts/run.py $1 ~/.steam/steam/steamapps/workshop/content/431960/ -python ${SCRIPT_DIR}/scripts/process.py \ No newline at end of file + +for folder in ~/.steam/steam/steamapps/workshop/content/431960/*; do + # only directories matter + if [ -d "$folder" ]; then + bgid=$(basename "$folder") + + echo "Running wallpaperengine for background $bgid and waiting for it to finish" + # run and wait for it to finish + $1 $bgid + # move output.webm to the output folder with the right name + mv output.webm output/$bgid.webm + # take a screenshot + ffmpeg -ss 00:00:03 -i output/$bgid.webm -frames:v 1 output/$bgid.jpg + fi +done \ No newline at end of file diff --git a/tools/scripts/process.py b/tools/scripts/process.py deleted file mode 100644 index 17d2c49..0000000 --- a/tools/scripts/process.py +++ /dev/null @@ -1,94 +0,0 @@ -import os -import re -import base64 -import cv2 -import numpy as np -from bs4 import BeautifulSoup - -def extract_base64_image(html_file): - """Extracts base64-encoded image data from an HTML file.""" - with open(html_file, "r", encoding="utf-8") as f: - soup = BeautifulSoup(f, "html.parser") - img_tag = soup.find("img") - if img_tag and 'src' in img_tag.attrs: - match = re.search(r'data:image/png;base64,(.+)', img_tag['src']) - if match: - return match.group(1) - return None - -def resize_image_base64(image_data, width=100): - """Resizes the image to the specified width while keeping aspect ratio and returns base64.""" - img_array = np.frombuffer(base64.b64decode(image_data), dtype=np.uint8) - img = cv2.imdecode(img_array, cv2.IMREAD_UNCHANGED) - if img is None: - return None - - h, w = img.shape[:2] - new_height = int((width / w) * h) - resized_img = cv2.resize(img, (width, new_height), interpolation=cv2.INTER_AREA) - - _, buffer = cv2.imencode('.png', resized_img) - resized_base64 = base64.b64encode(buffer).decode('utf-8') - return resized_base64 - -def categorize_image(image_data): - """Categorizes the image as 'grey', 'no image', or 'content' and returns resized image.""" - if not image_data: - return "no_image", None - - img_array = np.frombuffer(base64.b64decode(image_data), dtype=np.uint8) - img = cv2.imdecode(img_array, cv2.IMREAD_GRAYSCALE) - - if img is None: - return "no_image", None - - mean_value = cv2.mean(img)[0] - std_dev = np.std(img) - - category = "grey" if mean_value > 200 and std_dev < 10 else "content" - resized_data = resize_image_base64(image_data) - return category, resized_data - -def process_html_files(input_folder, output_html="gallery.html"): - """Processes all HTML files, categorizes them, and generates a gallery.""" - categories = {"no_image": [], "grey": [], "content": []} - - for file in os.listdir(input_folder): - if file.endswith(".html") and not file.startswith('report'): - file_path = os.path.join(input_folder, file) - image_data = extract_base64_image(file_path) - category, resized_image = categorize_image(image_data) - categories[category].append((file, resized_image)) - - with open(output_html, "w", encoding="utf-8") as f: - f.write(""" - - - Image Gallery - - - -

Image Gallery

- """) - - for category, files in categories.items(): - f.write(f"

{category.replace('_', ' ').title()}

") - f.write("") - - f.write("") - - print(f"Gallery created at {output_html}") - -if __name__ == "__main__": - input_folder = "./output" # Change to your directory - process_html_files(input_folder, "output/gallery.html") diff --git a/tools/scripts/run.py b/tools/scripts/run.py deleted file mode 100644 index 5f2488b..0000000 --- a/tools/scripts/run.py +++ /dev/null @@ -1,97 +0,0 @@ -import subprocess -import os -import time -import html -import base64 -import argparse -import signal - -def run_and_monitor(program, program_args=None, output_file="output.png", wait_time=1, timeout=30, html_report="report.html"): - try: - # Build the full command - full_command = [program] + ([program_args] if program_args else []) - - print(f"Running command: {' '.join(full_command)}") - - # Start the program with shell=True for better compatibility - process = subprocess.Popen( - f"exec {" ".join(full_command)}", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, preexec_fn=os.setsid - ) - stdout_data, stderr_data = "", "" - start_time = time.time() - - while time.time() - start_time < timeout: - # wait for the process to die, if it did, stop the waiting already - try: - process.wait(wait_time) - break - except subprocess.TimeoutExpired: - # otherwise check for the file, if it exists stop waiting - print("Polling for file {output_file}".format(output_file=output_file)) - # Check if the file is created - if os.path.exists(output_file): - # give the screenshot some time to be written properly, just in case - time.sleep(wait_time) - break - else: - print("Timeout reached. File not found.") - - # Capture output - if process.poll() is None: - os.killpg(os.getpgid(process.pid), signal.SIGKILL) - stdout_data, stderr_data = process.communicate() - - # Read the created image file as base64 - image_base64 = "" - if os.path.exists(output_file): - with open(output_file, "rb") as f: - image_base64 = base64.b64encode(f.read()).decode('utf-8') - - # Save results to an HTML file - with open(os.path.join("output", html_report), "w", encoding="utf-8") as report: - report.write(""" - - Program Output Review - -

Generated Image

- Generated Image -

Standard Output

-
{stdout_data}
-

Error Output

-
{stderr_data}
- - - """.format( - image_base64=image_base64, - stdout_data=html.escape(stdout_data), - stderr_data=html.escape(stderr_data) - )) - print(f"Report saved to {html_report}") - - if stderr_data: - print("Error output detected:") - print(stderr_data) - - except Exception as e: - print(f"Error: {e}") - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Run a program, monitor a file, and capture output.") - parser.add_argument("program", help="The program to execute.") - parser.add_argument("directory", help="Directory containing folders to process.") - - args = parser.parse_args() - - if not os.path.isdir(args.directory): - print("Error: Specified directory does not exist.") - exit(1) - - folders = [f for f in os.listdir(args.directory) if os.path.isdir(os.path.join(args.directory, f))] - - for folder in folders: - run_and_monitor( - args.program, - program_args="--screenshot {path}/images/{folder}.png --screenshot-delay 420 {folder}".format(path=os.getcwd(), folder=folder), - output_file="{path}/images/{folder}.png".format(path=os.getcwd(), folder=folder), - html_report="{folder}.html".format(folder=folder) - )