diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2026-01-28 16:03:16 +0100 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2026-01-28 16:03:16 +0100 |
| commit | 96373c6d93f0c310f8b777494c5a40c27fd78a0b (patch) | |
| tree | bfb9825ac80cd2331ede1adc21f84230813a1f22 /generate-gallery.py | |
| parent | a584e47488212c61defe9e266d23eb036c0148e4 (diff) | |
| download | scratch-gallery-96373c6d93f0c310f8b777494c5a40c27fd78a0b.tar.gz scratch-gallery-96373c6d93f0c310f8b777494c5a40c27fd78a0b.zip | |
initial commit
Diffstat (limited to 'generate-gallery.py')
| -rwxr-xr-x | generate-gallery.py | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/generate-gallery.py b/generate-gallery.py new file mode 100755 index 0000000..454d093 --- /dev/null +++ b/generate-gallery.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +"""Skript um eine HTML-Gallery fuer mehrere Scratch-Spiele zu erstellen""" +import argparse +import os +import pathlib +import tomllib +import shutil +import subprocess +import sys + +from jinja2 import Environment, FileSystemLoader, select_autoescape + + +def nested_get(data_dict, key_sequence): + """ + Retrieves a value from a nested dictionary using an iterative approach. + + Args: + data_dict (dict): The dictionary to traverse. + key_sequence (list): A list of keys representing the path. + + Returns: + Any: The value at the specified path. + """ + current_level = data_dict + for key in key_sequence: + if key not in current_level: + return None + current_level = current_level[key] + return current_level + + +def nested_set(data_dict, key_sequence, value): + """ + Sets a value in a nested dictionary, creating intermediate dictionaries if needed. + + Args: + data_dict (dict): The dictionary to modify. + key_sequence (list): A list of keys representing the path. + value (Any): The value to set. + """ + for key in key_sequence[:-1]: + data_dict = data_dict.setdefault(key, {}) + data_dict[key_sequence[-1]] = value + + +def load_projects(root: str) -> dict: + """Load all game meta data from the games directory""" + projects = {} + + for _parent, _, files in os.walk(root): + parent = pathlib.Path(_parent) + scope = nested_get(projects, parent.parts[1:]) + if scope is None: + scope = {} + nested_set(projects, parent.parts[1:], scope) + + if not 'meta.toml' in files: + continue + + with open(parent / 'meta.toml', 'rb') as meta_file: + game = tomllib.load(meta_file) + + if 'name' not in game: + game['name'] = 'Project' + + if 'authors' not in game: + game['authors'] = ['anonym'] + else: + game['authors'] = ', '.join(game['authors']) + + if 'path' not in game: + game['path'] = parent.relative_to(root) + + if 'license' not in game: + game['license'] = 'Alle Rechte vorbehalten' + + nested_set(projects, parent.parts[1:], game) + + return projects + + +def prepare_outputdir(_outdir: str, all_projects: dict): + """Prepare the output dir recreating the project structure""" + outdir = pathlib.Path(_outdir) + for section, subsections in all_projects.items(): + sectiondir = outdir / section + for subsection, projects in subsections.items(): + subsectiondir = sectiondir / subsection + for title in projects: + projectdir = subsectiondir / title + os.makedirs(projectdir, exist_ok=True) + + +def package_projects(_indir: str, _outdir: str, all_projects: dict): + """Package all scratch projects to html""" + + # Ensure that the local turbowarp-packer-cli is available through npm + subprocess.run('npm install'.split(), cwd='turbowarp-packager-cli', check=True) + _cmd = 'npx turbowarp-packager-cli -s ../turbowarp-packager-settings.json -i "{infile}" -o "{outdir}"' + + indir = pathlib.Path(_indir) + outdir = pathlib.Path(_outdir) + for section, subsections in all_projects.items(): + for subsection, projects in subsections.items(): + for title, project in projects.items(): + print(f'package {title}') + projectindir = indir / section / subsection / title + projectoutdir = outdir / section / subsection / title + infile = projectindir / project['entry'] + + print(projectindir / 'meta.toml', projectoutdir / 'meta.toml') + shutil.copyfile(projectindir / 'meta.toml', projectoutdir / 'meta.toml') + + # The project is not a scratch file + if not infile.suffix == '.sb3': + print(infile, projectoutdir / project['entry']) + shutil.copyfile(infile, projectoutdir / project['entry']) + continue + + cmd = _cmd.format(infile='..' / infile, outdir='..' / projectoutdir) + print(cmd) + subprocess.run(cmd, cwd='turbowarp-packager-cli', check=True, shell=True) + project['entry'] = 'demo_output.html' + + +def main(): + """Main entry point to generate a HTML Gallery""" + parser = argparse.ArgumentParser() + parser.add_argument('--author', default='Florian Fischer') + parser.add_argument('--title', default='Scratch Galerie') + parser.add_argument('--no-license', action='store_true') + parser.add_argument('--projects-dir', default='projects', help='location of the projects') + parser.add_argument('--output-dir', + default='build', + help='output location of the generated HTML code') + args = parser.parse_args() + + env = Environment(loader=FileSystemLoader("templates"), autoescape=select_autoescape()) + + projects = load_projects(args.projects_dir) + print(projects, file=sys.stderr) + + prepare_outputdir(args.output_dir, projects) + + package_projects(args.projects_dir, args.output_dir, projects) + + template = env.get_template("index.html") + with open(pathlib.Path(args.output_dir) / 'index.html', 'w', encoding='utf-8') as outfile: + print(template.render(projects=projects, **args.__dict__), file=outfile) + + +if __name__ == '__main__': + main() |
