From cf121d028ece7e5ea37e45d3ef0905566f957a6c Mon Sep 17 00:00:00 2001
From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com>
Date: Sun, 18 Oct 2026 09:51:58 +0200
Subject: [PATCH] feat: give each collection card its path and link
---
scripts/generate_site.py | 32 ++++++++++++++++++++++++++++++--
tests/test_audit_regressions.py | 19 +++++++++++++++++++
tests/test_site_exports.py | 2 +-
3 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/scripts/generate_site.py b/scripts/generate_site.py
index b6475431..62cac939 100644
--- a/scripts/generate_site.py
+++ b/scripts/generate_site.py
@@ -1865,6 +1865,31 @@ def generate_provenance_page(
return "\n".join(lines) + "\n"
+_RELEASE_ASSET_NAMES: dict[str, str] | None = None
+
+
+def _fetch_url(path: str) -> str:
+ """Where a collection file downloads from: its raw URL, or the
+ large-files release asset when .gitignore keeps it out of git."""
+ global _RELEASE_ASSET_NAMES
+ if _RELEASE_ASSET_NAMES is None:
+ from largefiles import ( # noqa: PLC0415
+ LARGE_FILES_RELEASE,
+ asset_names,
+ load_registered_paths,
+ )
+
+ _RELEASE_ASSET_NAMES = {
+ registered: f"{REPO_URL}/releases/download/{LARGE_FILES_RELEASE}/"
+ + urllib.parse.quote(name.replace(" ", "."))
+ for registered, name in asset_names(load_registered_paths()).items()
+ }
+ return _RELEASE_ASSET_NAMES.get(path) or (
+ "https://raw.githubusercontent.com/Abdess/retrobios/main/"
+ + urllib.parse.quote(path)
+ )
+
+
def _system_file_card(f: dict, consumers: FileConsumers) -> list[str]:
"""One file of a system page: hashes, who reads it, its provenance."""
name = f["name"]
@@ -1883,8 +1908,11 @@ def _system_file_card(f: dict, consumers: FileConsumers) -> list[str]:
permalink = f' #' if anchor else ""
lines.append(f'**`{name}`** {size}{permalink}')
lines.append("")
- if "/.variants/" in f.get("path", ""):
- lines.append(f"- Stored as: `{f['path'].rsplit('/', 1)[-1]}`")
+ if f.get("path"):
+ # The card named a file, its hashes and provenance, but not where to
+ # get it: a user missing scph5501.bin found the reference and no way
+ # to the bytes.
+ lines.append(f"- Collection path: `{f['path']}` ([download]({_fetch_url(f['path'])}))")
lines.append(f'- SHA1: `{sha1_short}...`')
lines.append(f'- MD5: `{md5_short}...`')
if plats:
diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py
index a929f56b..09e6aa40 100644
--- a/tests/test_audit_regressions.py
+++ b/tests/test_audit_regressions.py
@@ -4515,5 +4515,24 @@ class UnsourceableCardSaysWhy(unittest.TestCase):
self.assertIn("../gaps.md#acknowledged-gaps", text)
+
+class CollectionCardsSayWhereToGetTheFile(unittest.TestCase):
+ """A system page card gave the hashes, readers and provenance of
+ scph5501.bin and no path or link to the bytes."""
+
+ def test_raw_and_release_asset_urls(self):
+ import scripts.generate_site as site
+
+ site._RELEASE_ASSET_NAMES = None
+ self.addCleanup(setattr, site, "_RELEASE_ASSET_NAMES", None)
+ self.assertEqual(
+ site._fetch_url("bios/Sony/PlayStation/scph5501.bin"),
+ "https://raw.githubusercontent.com/Abdess/retrobios/main/bios/Sony/PlayStation/scph5501.bin",
+ )
+ self.assertTrue(site._fetch_url("bios/Arcade/MAME/MAME 0.174 Arcade XML.dat").endswith(
+ "/releases/download/large-files/MAME.0.174.Arcade.XML.dat"
+ ))
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/tests/test_site_exports.py b/tests/test_site_exports.py
index bfc12912..9ec5f5ed 100644
--- a/tests/test_site_exports.py
+++ b/tests/test_site_exports.py
@@ -351,7 +351,7 @@ class AVariantShowsWhoPinsIt(unittest.TestCase):
page = generate_site.generate_system_page(
"Entex", {"Adventure Vision": [primary, variant]}, consumers)
block = page[page.index('??? note "Variants (1)"'):]
- self.assertIn(" - Stored as: `advision.zip.1c086064`", block)
+ self.assertIn(" - Collection path: `bios/Entex/Adventure Vision/.variants/advision.zip.1c086064`", block)
self.assertIn("[batocera](../platforms/batocera.md)", block)
self.assertIn("[retrobat](../platforms/retrobat.md)", block)
self.assertIn('title="' + "c" * 40 + '"', block)