From c8e95fd189836def7a9fd78452b088e48ab99ade Mon Sep 17 00:00:00 2001 From: CyberMask367 Date: Mon, 12 Oct 2026 15:51:27 +0100 Subject: [PATCH] Update docs and add custom title tool Refresh the README branding and credits, fix the logo path, and remove the outdated hotspot warning. Add scripts/add_custom_title.py to manage entries in config/custom.json, including interactive add, list, and remove flows. The tool writes compact JSON in the format expected by the payload scanner so community title overrides work reliably without breaking lookups. --- README.md | 7 ++- config/icons/pslogo.png | Bin 14574 -> 0 bytes scripts/add_custom_title.py | 102 ++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 4 deletions(-) delete mode 100644 config/icons/pslogo.png create mode 100644 scripts/add_custom_title.py diff --git a/README.md b/README.md index bcd1689..f73d82d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- orbisRPC + orbisRPC

# orbisRPC — Discord Rich Presence for PS4 (GoldHEN RPC) @@ -228,8 +228,6 @@ nanoDNS — then reboot. (This is the step most people miss.) - Some homebrew (Apollo Save Tool, Cheats Manager, Homebrew Store) isn't detected yet — under investigation. -- Hotspot/mobile connections can send oversized frames that Discord - rejects — use stable Wi-Fi/LAN if presence won't set. ## Building @@ -273,7 +271,8 @@ Build/test/CI details: [`docs/BUILDING.md`](docs/BUILDING.md). - **SirHumza** — project founder, daemon core. - **CyberMask367** — firmware coverage to 13.52, homebrew and retro games resolving, presence flags, tester wrangling. - Testers in `testers-chat` on DIscord — every log file that made a fix possible. -- [*PKG-ZONE*](https://pkg-zone.com) — metadata on ps4 hombrew apps used for resolving +- [OpenOrbis](https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain) - SDK/Toolchain used to make setup PKG +- [*PKG-ZONE*](https://pkg-zone.com) — used for resolving metadata on hombrew apps - [*PSX DATA CENTER*](https://psxdatacenter.com) — source used to make custom json list in [`config`](config/) for resolving retro games ## License diff --git a/config/icons/pslogo.png b/config/icons/pslogo.png deleted file mode 100644 index 14cac6031b4261cf5d6f7f796f92fed3a0e2c1a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14574 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 diff --git a/scripts/add_custom_title.py b/scripts/add_custom_title.py new file mode 100644 index 0000000..5f0ffda --- /dev/null +++ b/scripts/add_custom_title.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""Add an entry to config/custom.json (the community title list). + + python3 scripts/add_custom_title.py ask for id, name, art + python3 scripts/add_custom_title.py --list show every entry + python3 scripts/add_custom_title.py --remove ORPC00042 + +pkg-zone only carries the apps its own scraper knows about, and the retro +indexes are gated on retro prefixes. custom.json is the catch-all: a plain +TITLEID -> name map anyone can contribute to. + +Format matches the retro indexes so the payload reuses the same scanner: + + [{"id":"ORPC00042","name":"Some App","cover":"https://.../a.png"}] + +Compact separators are required. The scanner matches entries on the literal +byte run "id":"", so a space after the colon -- what you get from a +normal pretty-printer -- means the lookup never matches and the payload falls +back to the raw TITLEID with no error. save() below enforces this. + +"cover" is optional; without one the presence falls back to the default art. + +custom runs last in the chain, so TMDB stays authoritative for retail titles. +""" +import json +import os +import sys + +PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), + 'config', 'custom.json') + + +def load(): + try: + with open(PATH, encoding='utf-8') as f: + return json.load(f) + except (OSError, ValueError): + return [] + + +def save(entries): + """One entry per line so a contribution reads as a one-line diff. + + separators=(',', ':') is not cosmetic: the scanner matches entries on the + literal byte run "id":"", so a space after the colon -- what a + normal pretty-printer emits -- means the lookup never matches and the + payload falls back to the raw TITLEID with no error.""" + with open(PATH, 'w', encoding='utf-8', newline='\n') as f: + f.write('[\n') + for i, e in enumerate(entries): + tail = '' if i == len(entries) - 1 else ',' + f.write(' ' + json.dumps(e, ensure_ascii=False, + separators=(',', ':')) + tail + '\n') + f.write(']\n') + + +def main(): + argv = sys.argv[1:] + + if argv and argv[0] == '--list': + entries = load() + for e in entries: + art = e.get('cover', '') + print(' %-12s %s%s' % (e['id'], e['name'], + (' [%s]' % art) if art else '')) + print('%d entries' % len(entries)) + return + + if argv and argv[0] == '--remove': + if len(argv) < 2: + sys.exit('usage: add_custom_title.py --remove TITLEID') + tid = argv[1].upper() + entries = load() + kept = [e for e in entries if e['id'].upper() != tid] + if len(kept) == len(entries): + print('%s not in the list' % tid) + return + save(kept) + print('removed %s (%d entries left)' % (tid, len(kept))) + return + + if argv: + sys.exit('usage: add_custom_title.py [--list | --remove TITLEID]') + + # --- interactive add --------------------------------------------------- + tid = input('TITLEID: ').strip().upper() + name = input('Name: ').strip() + art = input('Cover URL (blank for none): ').strip() + + entry = {'id': tid, 'name': name} + if art: + entry['cover'] = art + + entries = [e for e in load() if e['id'].upper() != tid] + entries.append(entry) + save(entries) + + print('%s -> %s' % (tid, name)) + + +if __name__ == '__main__': + main() \ No newline at end of file