Files
EmiiBytee--np2kai-ps4/tools/validate-ps4-package-metadata.py
T
2026-07-28 06:34:41 +02:00

73 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import re
import struct
from pathlib import Path
SELF_MAGIC = bytes.fromhex("4f153d1d")
PNG_MAGIC = b"\x89PNG\r\n\x1a\n"
def fail(message: str) -> None:
raise SystemExit(f"ERROR: {message}")
def main() -> None:
parser = argparse.ArgumentParser(
description="Validate PS4 package metadata before create-gp4/PkgTool."
)
parser.add_argument("--version", required=True)
parser.add_argument("--title-id", required=True)
parser.add_argument("--content-id", required=True)
parser.add_argument("--right-sprx", required=True, type=Path)
parser.add_argument("--icon", required=True, type=Path)
args = parser.parse_args()
if re.fullmatch(r"[0-9]{2}\.[0-9]{2}", args.version) is None:
fail(
f"APP_VER/VERSION '{args.version}' is invalid; PS4 expects XX.YY "
"(for example 01.35)."
)
if re.fullmatch(r"[A-Z]{4}[0-9]{5}", args.title_id) is None:
fail(f"TITLE_ID '{args.title_id}' is not WXYZ12345 format.")
expected_content = (
rf"[A-Z]{{2}}[0-9]{{4}}-{re.escape(args.title_id)}_"
rf"[0-9]{{2}}-[A-Z0-9]{{16}}"
)
if re.fullmatch(expected_content, args.content_id) is None:
fail(f"CONTENT_ID '{args.content_id}' is malformed or mismatches TITLE_ID.")
if not args.right_sprx.is_file():
fail(f"missing game-right module: {args.right_sprx}")
right = args.right_sprx.read_bytes()
if len(right) < 4096:
fail(f"game-right module is unexpectedly small: {len(right)} bytes")
if right[:4] != SELF_MAGIC:
fail(
f"{args.right_sprx} does not have the Orbis SELF magic "
f"{SELF_MAGIC.hex()}."
)
if not args.icon.is_file():
fail(f"missing icon: {args.icon}")
with args.icon.open("rb") as handle:
header = handle.read(24)
if len(header) != 24 or header[:8] != PNG_MAGIC or header[12:16] != b"IHDR":
fail(f"{args.icon} is not a valid PNG with an IHDR header")
width, height = struct.unpack(">II", header[16:24])
if (width, height) != (512, 512):
fail(f"icon0.png must be 512x512, got {width}x{height}")
print("NP2kai PS4 package metadata validation: PASS")
print(f"- SFO APP_VER/VERSION: {args.version} (XX.YY)")
print(f"- TITLE_ID: {args.title_id}")
print(f"- CONTENT_ID: {args.content_id}")
print(f"- right.sprx: Orbis SELF, {len(right)} bytes")
print(f"- icon0.png: {width}x{height} PNG")
if __name__ == "__main__":
main()