#!/usr/bin/env python3 from __future__ import annotations import argparse import base64 import hashlib import json from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parent.parent DEFAULT_SCRIPT = ROOT / "services" / "neko" / "provisioning" / "youtube-studio-auto-dismiss.user.js" DEFAULT_OUTPUT = ROOT / "services" / "neko" / "provisioning" / "tampermonkey-provisioning.json" GREASYFORK_URL = "https://greasyfork.org/scripts/557378-youtube-studio-auto-dismiss/code/YouTube%20Studio%20Auto%20Dismiss.user.js" def tm_sha256(text: str) -> str: return hashlib.sha256(text.encode("utf-8")).hexdigest() def tm_hash(value: Any, seen: list[int] | None = None) -> str: if seen is None: seen = [] if value is None: return tm_sha256("object:null") if isinstance(value, dict): ident = id(value) if ident in seen: raise ValueError("Found circular structure") seen.append(ident) try: parts = [tm_hash(value[key], seen) for key in sorted(value)] finally: seen.pop() return tm_sha256("".join(parts)) if isinstance(value, list): ident = id(value) if ident in seen: raise ValueError("Found circular structure") seen.append(ident) try: parts = [tm_hash(item, seen) for item in value] finally: seen.pop() return tm_sha256("".join(parts)) if isinstance(value, bool): return tm_sha256(f"boolean:{str(value).lower()}") if isinstance(value, (int, float)) and not isinstance(value, bool): return tm_sha256(f"number:{value}") if isinstance(value, str): return tm_sha256(f"string:{value}") raise TypeError(f"Unsupported provisioning value: {type(value)!r}") def build_payload(script_text: str) -> dict[str, Any]: encoded_source = base64.b64encode(script_text.encode("utf-8")).decode("ascii") return { "version": "1", "scripts": [ { "name": "YouTube Studio Auto Dismiss", "file_url": GREASYFORK_URL, "source": encoded_source, "enabled": True, "position": 1, "options": {}, } ], "settings": { "runtime_content_mode": "content", }, } def main() -> int: parser = argparse.ArgumentParser(description="Render Tampermonkey provisioning JSON and hash.") parser.add_argument("--script", type=Path, default=DEFAULT_SCRIPT) parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT) parser.add_argument("--write", action="store_true", help="Write the rendered JSON to --output.") args = parser.parse_args() script_text = args.script.read_text(encoding="utf-8").strip() + "\n" payload = build_payload(script_text) rendered = json.dumps(payload, ensure_ascii=False, indent=2) + "\n" if args.write: args.output.write_text(rendered, encoding="utf-8") print(rendered, end="") print(f"hash=1:{tm_hash(payload)}") return 0 if __name__ == "__main__": raise SystemExit(main())