From 33952369668419cfef2350510b7022804fe3f7fc Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sat, 17 Oct 2026 04:45:13 +0200 Subject: [PATCH] feat: pack the standalone emulators rocknix ships ROCKNIX was declared libretro-only although it packages duckstation, dolphin, ppsspp and 33 other emulators standalone, and its BIOS list was read on the next branch under the latest release's version. The scraper now reads the release tag and lists RetroArch plus every standalone package. --- platforms/_registry.yml | 1 - platforms/rocknix.yml | 132 ++++++++++++++++++++++++++++- scripts/scraper/rocknix_scraper.py | 62 ++++++++++++-- 3 files changed, 185 insertions(+), 10 deletions(-) diff --git a/platforms/_registry.yml b/platforms/_registry.yml index c7adf172..756606e8 100644 --- a/platforms/_registry.yml +++ b/platforms/_registry.yml @@ -391,7 +391,6 @@ platforms: extract_to: /storage/roms/bios/ logo: https://avatars.githubusercontent.com/u/152618023 scraper: rocknix - cores: all_libretro schedule: weekly install: detect: diff --git a/platforms/rocknix.yml b/platforms/rocknix.yml index 4710e4bd..f04670cc 100644 --- a/platforms/rocknix.yml +++ b/platforms/rocknix.yml @@ -1,11 +1,139 @@ platform: ROCKNIX version: "20261001" homepage: "https://rocknix.org" -source: "https://raw.githubusercontent.com/ROCKNIX/distribution/next/projects/ROCKNIX/packages/rocknix/sources/scripts/rocknix-systems" +source: "https://raw.githubusercontent.com/ROCKNIX/distribution/20261001/projects/ROCKNIX/packages/rocknix/sources/scripts/rocknix-systems" base_destination: bios hash_type: md5 verification_mode: md5 -cores: all_libretro +cores: +- retroarch +- aethersx2 +- aethersx2-sa +- amiberry +- ares +- ares-sa +- armsx2 +- armsx2-sa +- azahar +- azahar-sa +- bigpemu +- bigpemu-sa +- cemu +- cemu-sa +- daedalusx64 +- daedalusx64-sa +- dolphin +- dolphin-sa +- drastic +- drastic-sa +- dsperate +- dsperate-sa +- duckstation +- duckstation-sa +- flycast +- flycast-sa +- gopher64 +- gopher64-sa +- gzdoom +- gzdoom-sa +- hatari +- hatarisa +- heroic +- hypseus-singe +- mednafen +- melonds +- melonds-sa +- mupen64plus +- mupen64plus-sa +- nanoboyadvance +- nanoboyadvance-sa +- openbor +- pico-8 +- ppsspp +- ppsspp-sa +- rpcs3 +- rpcs3-sa +- scummvm +- scummvm-sa +- skyemu +- skyemu-sa +- steam +- supermodel +- supermodel-sa +- touchhle +- touchhle-sa +- vice +- vice-sa +- vita3k +- vita3k-sa +- xemu +- xemu-sa +- yabasanshiro +- yabasanshiro-sa +standalone_cores: +- aethersx2 +- aethersx2-sa +- amiberry +- ares +- ares-sa +- armsx2 +- armsx2-sa +- azahar +- azahar-sa +- bigpemu +- bigpemu-sa +- cemu +- cemu-sa +- daedalusx64 +- daedalusx64-sa +- dolphin +- dolphin-sa +- drastic +- drastic-sa +- dsperate +- dsperate-sa +- duckstation +- duckstation-sa +- flycast +- flycast-sa +- gopher64 +- gopher64-sa +- gzdoom +- gzdoom-sa +- hatari +- hatarisa +- heroic +- hypseus-singe +- mednafen +- melonds +- melonds-sa +- mupen64plus +- mupen64plus-sa +- nanoboyadvance +- nanoboyadvance-sa +- openbor +- pico-8 +- ppsspp +- ppsspp-sa +- rpcs3 +- rpcs3-sa +- scummvm +- scummvm-sa +- skyemu +- skyemu-sa +- steam +- supermodel +- supermodel-sa +- touchhle +- touchhle-sa +- vice +- vice-sa +- vita3k +- vita3k-sa +- xemu +- xemu-sa +- yabasanshiro +- yabasanshiro-sa systems: microsoft-xbox: files: diff --git a/scripts/scraper/rocknix_scraper.py b/scripts/scraper/rocknix_scraper.py index 2bb1053d..23e4d9b1 100644 --- a/scripts/scraper/rocknix_scraper.py +++ b/scripts/scraper/rocknix_scraper.py @@ -36,10 +36,33 @@ PLATFORM_NAME = "rocknix" GITHUB_REPO = "ROCKNIX/distribution" -SOURCE_URL = ( - "https://raw.githubusercontent.com/ROCKNIX/distribution/next/" +SOURCE_TEMPLATE = ( + "https://raw.githubusercontent.com/ROCKNIX/distribution/{ref}/" "projects/ROCKNIX/packages/rocknix/sources/scripts/rocknix-systems" ) +# The branch a test or a manual run can still name; a scrape reads the tag +# of the release its YAML is labelled with. +SOURCE_URL = SOURCE_TEMPLATE.format(ref="next") +STANDALONE_TREE_URL = ( + "https://api.github.com/repos/ROCKNIX/distribution/contents/" + "projects/ROCKNIX/packages/emulators/standalone?ref={ref}" +) + + +def standalone_emulators(package_names: list[str]) -> list[str]: + """The standalone emulators ROCKNIX packages, by the names profiles use. + + A package is named after its emulator with an ``-sa`` suffix + (``duckstation-sa``), once without its hyphen (``hatarisa``); both + spellings are kept so a profile listing either is found. + """ + names: set[str] = set() + for package in package_names: + names.add(package) + stripped = re.sub(r"-?sa$", "", package) + if stripped and stripped != package: + names.add(stripped) + return sorted(names) # ROCKNIX system key -> retrobios system ID SYSTEM_SLUG_MAP = { @@ -124,8 +147,29 @@ def parse_systems(source: str) -> dict[str, dict]: class Scraper(BaseScraper): """Scraper for the ROCKNIX rocknix-systems script.""" - def __init__(self, url: str = SOURCE_URL): - super().__init__(url=url) + def __init__(self, url: str | None = None): + self.tag = None if url else fetch_github_latest_version(GITHUB_REPO) + super().__init__(url=url or SOURCE_TEMPLATE.format(ref=self.tag)) + + def _fetch_standalone(self) -> list[str]: + """The packages of projects/ROCKNIX/packages/emulators/standalone.""" + import json + import urllib.error + import urllib.request + + from .base_scraper import github_headers + + url = STANDALONE_TREE_URL.format(ref=self.tag or "next") + req = urllib.request.Request(url, headers=github_headers()) + try: + with urllib.request.urlopen(req, timeout=30) as resp: + listing = json.loads(resp.read()) + except (urllib.error.URLError, json.JSONDecodeError) as e: + raise ConnectionError(f"Failed to list {url}: {e}") from e + packages = [item["name"] for item in listing if item.get("type") == "dir"] + if not packages: + raise RuntimeError(f"no standalone emulator package at {url}") + return standalone_emulators(packages) def validate_format(self, raw_data: str) -> bool: """Validate the rocknix-systems format.""" @@ -179,15 +223,19 @@ class Scraper(BaseScraper): ) entry["files"].append(requirement_entry(req)) + standalone = self._fetch_standalone() return { "platform": "ROCKNIX", - "version": fetch_github_latest_version(GITHUB_REPO), + "version": self.tag or fetch_github_latest_version(GITHUB_REPO), "homepage": "https://rocknix.org", - "source": SOURCE_URL, + "source": self.url, "base_destination": "bios", "hash_type": "md5", "verification_mode": "md5", - "cores": "all_libretro", + # RetroArch with every libretro core, plus the standalone + # emulators ROCKNIX packages beside it. + "cores": ["retroarch", *standalone], + "standalone_cores": standalone, "systems": systems, }