diff --git a/scripts/cross_reference.py b/scripts/cross_reference.py
index f1b2c941..c3c1f067 100644
--- a/scripts/cross_reference.py
+++ b/scripts/cross_reference.py
@@ -338,6 +338,8 @@ class FileConsumers:
# Under which of its systems each platform declares a file, so a
# link can land on that section rather than the page top.
self.platform_systems: dict[str, dict[str, set[str]]] = {}
+ # Where each platform puts the file in its BIOS directory.
+ self.platform_destinations: dict[str, dict[str, set[str]]] = {}
self.emulators: dict[str, set[str]] = {}
def sha1_of(self, entry: dict, dest: str = "", owner: str = "") -> str | None:
@@ -368,6 +370,13 @@ class FileConsumers:
self.platform_systems.setdefault(sha1, {}).setdefault(
name, set()
).add(system_id)
+ where = str(entry.get("destination") or entry["name"])
+ # EmuDeck matches by md5 alone: its entries carry a
+ # system:md5 key, not a place in the folder.
+ if ":" not in where:
+ self.platform_destinations.setdefault(sha1, {}).setdefault(
+ name, set()
+ ).add(where)
def path_of(self, sha1: str) -> str:
"""The collection path the database records for a file."""
diff --git a/scripts/generate_site.py b/scripts/generate_site.py
index 0e588f59..2a850dbb 100644
--- a/scripts/generate_site.py
+++ b/scripts/generate_site.py
@@ -2083,6 +2083,23 @@ def _fetch_url(path: str) -> str:
)
+def _platform_links(sha1: str, consumers: FileConsumers) -> list[str]:
+ """Each platform declaring the file: a link to its system section, and
+ the destination it gives the file."""
+ systems_of = getattr(consumers, "platform_systems", {}).get(sha1, {})
+ destinations_of = getattr(consumers, "platform_destinations", {}).get(sha1, {})
+ links: list[str] = []
+ for platform in sorted(consumers.platforms.get(sha1, ())):
+ section = sorted(systems_of.get(platform, ()))
+ fragment = f"#{section[0].replace(' ', '-')}" if section else ""
+ link = f"[{platform}](../platforms/{platform}.md{fragment})"
+ destinations = sorted(destinations_of.get(platform, ()))
+ if destinations:
+ link += " " + ", ".join(_code(d) for d in destinations)
+ links.append(link)
+ return links
+
+
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"]
@@ -2112,11 +2129,10 @@ def _system_file_card(f: dict, consumers: FileConsumers) -> list[str]:
if value and value != "unknown":
lines.append(f'- {label}: {_code(value)}')
if plats:
- plat_badges = " ".join(
- f'[{p}](../platforms/{p}.md)'
- for p in plats
- )
- lines.append(f"- Platforms: {plat_badges}")
+ # Each link lands on the platform's system section, and says where
+ # that platform puts the file: from the card, retrodeck sent the
+ # reader to the top of a 2,000-file page.
+ lines.append(f"- Platforms: {', '.join(_platform_links(sha1_full, consumers))}")
if emus:
lines.append(f"- Emulators: {', '.join(_emulator_link(e, '../') for e in emus)}")
provenance = f.get("provenance", {})
@@ -2513,15 +2529,8 @@ def _render_emulator_file(
f"Collection copy: [{_code(held)}]"
f"(../systems/{urllib.parse.quote(page)}.md#sha1-{sha1[:12]})"
)
- plats = sorted(consumers.platforms.get(sha1, ())) if sha1 else []
- if plats:
- systems_of = consumers.platform_systems.get(sha1, {})
- plat_links = []
- for p in plats:
- section = sorted(systems_of.get(p, ()))
- # Land on the system section that gives the destination.
- fragment = f"#{section[0].replace(' ', '-')}" if section else ""
- plat_links.append(f"[{p}](../platforms/{p}.md{fragment})")
+ plat_links = _platform_links(sha1, consumers) if sha1 else []
+ if plat_links:
details.append(f"Platforms: {', '.join(plat_links)}")
if dest and dest != fname and dest != fpath:
diff --git a/tests/test_site_exports.py b/tests/test_site_exports.py
index e19d376a..7acf7bf1 100644
--- a/tests/test_site_exports.py
+++ b/tests/test_site_exports.py
@@ -437,5 +437,26 @@ class AGoneSourceIsSaid(unittest.TestCase):
self.assertIn("| Mirror | [https://example.org/mirror/Citron]", page)
+
+class ASystemCardLandsOnThePlatformsSection(unittest.TestCase):
+ """From scph5000.bin's card, [retrodeck] opened the top of a 2,000-file
+ page; the emulator card already landed on #sony-playstation."""
+
+ def test_section_and_destination(self):
+ import types
+
+ from generate_site import _platform_links
+
+ consumers = types.SimpleNamespace(
+ platforms={"s": {"retrodeck"}},
+ platform_systems={"s": {"retrodeck": {"sony-playstation"}}},
+ platform_destinations={"s": {"retrodeck": {"bios/scph5000.bin"}}},
+ )
+ self.assertEqual(
+ _platform_links("s", consumers),
+ ["[retrodeck](../platforms/retrodeck.md#sony-playstation) `bios/scph5000.bin`"],
+ )
+
+
if __name__ == "__main__":
unittest.main()