From 87a4e8e1b612e9507bf32eaa89b2f97df0cc72b3 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Thu, 22 Oct 2026 11:04:25 +0200 Subject: [PATCH] fix: send unreleased platforms to the installer A release recorded without a platform's pack linked its button to that release, which serves no pack for AmberELEC, EmuELEC, KNULLI, MinUI, NextUI or MyMinUI. The cell now names the release and points to the installer, which reads the file lists on main. Core folder links resolve each core name to the profile page that describes it (mednafen_vb is beetle_vb). --- README.md | 14 +++++++------- scripts/generate_readme.py | 10 +++++++--- scripts/generate_site.py | 31 ++++++++++++++++++++++++++++++- tests/test_doc_surfaces.py | 9 ++++++++- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d8368b16..e69a4ce0 100644 --- a/README.md +++ b/README.md @@ -47,17 +47,17 @@ The Files column counts what a pack holds once extracted, the figure a file mana | Platform | Files | Extracted size | Extract to | Download | |----------|------:|---------------:|-----------|----------| -| AmberELEC | - | - | `/storage/roms/` | [Download](../../releases/latest) | +| AmberELEC | - | - | `/storage/roms/` | Not in v2026.10.10: [use the installer](https://abdess.github.io/retrobios/wiki/installer/) | | Batocera | 12,810 | 7.5 GB | `/userdata/bios/` | Download: [part 1 of 3](../../releases/download/v2026.10.10/Batocera_43.1_BIOS_Pack.part1of3.zip), [part 2 of 3](../../releases/download/v2026.10.10/Batocera_43.1_BIOS_Pack.part2of3.zip), [part 3 of 3](../../releases/download/v2026.10.10/Batocera_43.1_BIOS_Pack.part3of3.zip) | | BizHawk | 950 | 2.4 GB | `Firmware/` | [Download](../../releases/download/v2026.10.10/BizHawk_2.11.1_BIOS_Pack.zip) | | EmuDeck | 620 | 3.2 GB | `~/Emulation/bios/` | [Download](../../releases/download/v2026.10.10/EmuDeck_2.7EA_BIOS_Pack.zip) | -| EmuELEC | - | - | `/storage/roms/` | [Download](../../releases/latest) | -| KNULLI | - | - | `/userdata/bios/` | [Download](../../releases/latest) | +| EmuELEC | - | - | `/storage/roms/` | Not in v2026.10.10: [use the installer](https://abdess.github.io/retrobios/wiki/installer/) | +| KNULLI | - | - | `/userdata/bios/` | Not in v2026.10.10: [use the installer](https://abdess.github.io/retrobios/wiki/installer/) | | Lakka | 8,504 | 6.0 GB | `/storage/system/` | Download: [part 1 of 2](../../releases/download/v2026.10.10/RetroArch_Lakka_v1.22.2_BIOS_Pack.part1of2.zip), [part 2 of 2](../../releases/download/v2026.10.10/RetroArch_Lakka_v1.22.2_BIOS_Pack.part2of2.zip) | | MiSTer FPGA | 83 | 29 MB | `/media/fat/games/` | [Download](../../releases/download/v2026.10.10/MiSTer_FPGA_2026-09-29_BIOS_Pack.zip) | -| MinUI | - | - | `/` | [Download](../../releases/latest) | -| MyMinUI | - | - | `/` | [Download](../../releases/latest) | -| NextUI | - | - | `/` | [Download](../../releases/latest) | +| MinUI | - | - | `/` | Not in v2026.10.10: [use the installer](https://abdess.github.io/retrobios/wiki/installer/) | +| MyMinUI | - | - | `/` | Not in v2026.10.10: [use the installer](https://abdess.github.io/retrobios/wiki/installer/) | +| NextUI | - | - | `/` | Not in v2026.10.10: [use the installer](https://abdess.github.io/retrobios/wiki/installer/) | | ROCKNIX | 5,804 | 6.1 GB | `/storage/roms/bios/` | Download: [part 1 of 2](../../releases/download/v2026.10.10/ROCKNIX_20261001_BIOS_Pack.part1of2.zip), [part 2 of 2](../../releases/download/v2026.10.10/ROCKNIX_20261001_BIOS_Pack.part2of2.zip) | | Recalbox | 3,222 | 3.9 GB | `/recalbox/share/bios/` | Download: [part 1 of 2](../../releases/download/v2026.10.10/Recalbox_10.1.1_BIOS_Pack.part1of2.zip), [part 2 of 2](../../releases/download/v2026.10.10/Recalbox_10.1.1_BIOS_Pack.part2of2.zip) | | RetroArch | 8,504 | 6.0 GB | `system/` | Download: [part 1 of 2](../../releases/download/v2026.10.10/RetroArch_Lakka_v1.22.2_BIOS_Pack.part1of2.zip), [part 2 of 2](../../releases/download/v2026.10.10/RetroArch_Lakka_v1.22.2_BIOS_Pack.part2of2.zip) | @@ -208,4 +208,4 @@ The scripts and tooling are released under the [MIT License](LICENSE). The BIOS and firmware files are not covered by that license: they are third-party system software, preserved and provided for personal backup, archival, and interoperability with emulation software. [NOTICE](NOTICE) sets out their status and how to ask for a file to be removed. The reasoning, and where it is weakest, is in the [FAQ](https://abdess.github.io/retrobios/wiki/faq/#is-this-legal). -*Auto-generated on 2026-10-22T08:44:18Z* +*Auto-generated on 2026-10-22T08:57:23Z* diff --git a/scripts/generate_readme.py b/scripts/generate_readme.py index b0cd1e7a..57a5cb4b 100644 --- a/scripts/generate_readme.py +++ b/scripts/generate_readme.py @@ -134,14 +134,18 @@ def download_links( A pack published whole gets one link labelled *label*. A pack in parts gets one link per part, since every part is needed. *repo* is the repository URL, absolute or relative, and *attrs* a MkDocs attribute list - put after each link. Without a pack in the record the link falls back to - the latest release page. + put after each link. Without a recorded release the link is the latest + release page. A release recorded without this platform's pack says so and + names the installer, which reads the file lists on main: a button to the + release served six platforms a page with no pack for them. """ pack = release_record.pack_for(platform_name, record) tag = record.get("tag") assets = pack.get("assets") if pack else None - if not tag or not assets: + if not tag: return f"[{label}]({repo}/releases/latest){attrs}" + if not assets: + return f"Not in {tag}: [use the installer]({SITE_URL}wiki/installer/)" urls = [f"{repo}/releases/download/{tag}/{asset}" for asset in assets] if len(urls) == 1: return f"[{label}]({urls[0]}){attrs}" diff --git a/scripts/generate_site.py b/scripts/generate_site.py index f051a779..55573f1e 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -15,6 +15,7 @@ from siterender import WIKI_SRC_DIR import argparse import csv import hashlib +import functools import html import io import json @@ -33,6 +34,7 @@ from pathlib import Path sys.path.insert(0, os.path.dirname(__file__)) from common import ( + upstream_profile_index, build_zip_contents_index, compute_composition, count_catalog_matched, @@ -2088,6 +2090,33 @@ def _category_evidence_md(evidence: dict) -> str: return f"No reader found ({cores})" +@functools.lru_cache(maxsize=1) +def _profiles_by_core_name() -> dict[str, list[str]]: + """Core name as a platform writes it -> the profiles with a page for it. + + MinUI writes `mednafen_vb`, the profile and its page are `beetle_vb`. + """ + profiles = load_emulator_profiles(str(_REPO_ROOT / "emulators")) + with_page = {k for k, v in profiles.items() if v.get("type") not in ("alias", "test")} + return { + core: sorted(k for k in keys if k in with_page) + for core, keys in upstream_profile_index(profiles).items() + } + + +def _core_name_links(cores: list[str]) -> list[str]: + """A link per core to its profile page, the bare name where none exists.""" + index = _profiles_by_core_name() + links = [] + for core in cores: + keys = [core] if core in index.get(core, []) else index.get(core, []) + if keys: + links.extend(_emulator_link(k, "../") for k in keys) + else: + links.append(f"`{core}`") + return links + + def _core_folders_section(name: str, config: dict) -> list[str]: """Each folder the frontend hands a core, and the files the pack puts in it. @@ -2111,7 +2140,7 @@ def _core_folders_section(name: str, config: dict) -> list[str]: f["dest"][len(folder) + 1:] for f in files if f.get("dest", "").startswith(folder + "/") ) - cores = ", ".join(_emulator_link(c, "../") for c in info.get("cores", [])) + cores = ", ".join(_core_name_links(info.get("cores", []))) shown = ", ".join(f"`{n}`" for n in held) if held else "none needed" lines.append(f"| `{folder}/` | {cores} | {shown} |") lines.append("") diff --git a/tests/test_doc_surfaces.py b/tests/test_doc_surfaces.py index 18703ec3..770c4690 100644 --- a/tests/test_doc_surfaces.py +++ b/tests/test_doc_surfaces.py @@ -112,9 +112,16 @@ class DownloadLinksNameTheFile(unittest.TestCase): cell = download_links("batocera", SPLIT_RECORD, REPO, "Pack", " { .x }") self.assertEqual(cell.count("{ .x }"), 2) - def test_without_a_pack_the_link_is_the_release_page(self): + def test_a_release_without_the_pack_names_the_installer(self): self.assertEqual( download_links("bizhawk", SPLIT_RECORD, "../..", "Download"), + "Not in v2000.01.01: " + "[use the installer](https://abdess.github.io/retrobios/wiki/installer/)", + ) + + def test_without_a_recorded_release_the_link_is_the_release_page(self): + self.assertEqual( + download_links("bizhawk", {}, "../..", "Download"), "[Download](../../releases/latest)", )