fix: pin ryujinx to its Gitea mirror

Gitea answers /raw/commit with an HTML proof-of-work page, so
Forgejo-family files are fetched through the API raw route.
This commit is contained in:
Abdessamad Derraz committed 2026-10-18 13:40:50 +02:00
1 parent 658c5a4959
commit 37633043db
4 files changed
+47 -11

No files matched your search

+9 -9
View File
@@ -3,38 +3,38 @@ type: standalone
source: "https://git.ngram.ca/mirrors/Ryujinx"
upstream: "https://github.com/Ryujinx/Ryujinx"
profiled_date: "2026-03-26"
core_version: "1.1.1403"
source_commit: "7d158acc3b5826a08941d6e8d50d3a3897021bcd"
core_version: "1.1.1402"
display_name: "Ryujinx (Nintendo Switch)"
cores:
- ryujinx
systems: [nintendo-switch]
analysis_date: "2026-03-26"
analysis_commit: "HEAD (depth=1, ngram.ca mirror)"
mode: standalone
# Key files are read from {BaseDirPath}/system/ (AppDataManager.cs:229)
# Also searched in ~/.switch/ (AppDataManager.cs:47)
# Batocera copies bios/switch/prod.keys to Ryujinx/system/prod.keys (ryujinxGenerator.py:108)
# Firmware NCAs are installed via UI (ContentManager.cs:429), not placed as files
# Key files are read from {BaseDirPath}/system/ (src/Ryujinx.Common/Configuration/AppDataManager.cs:229)
# Also searched in ~/.switch/ (src/Ryujinx.Common/Configuration/AppDataManager.cs:47)
# Batocera copied bios/switch/prod.keys to Ryujinx/system/prod.keys (batocera ryujinxGenerator.py:108 at 1f69a46e) until it dropped the package in ee8a418f
# Firmware NCAs are installed via UI (src/Ryujinx.HLE/FileSystem/ContentManager.cs:429), not placed as files
files:
- name: "prod.keys"
required: true
path: "switch/prod.keys"
note: "Switch production keys for NCA decryption"
source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:239"
source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:238"
- name: "title.keys"
required: false
path: "switch/title.keys"
note: "Per-title decryption keys, needed for specific game content"
source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:240"
source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:239"
- name: "console.keys"
required: false
path: "switch/console.keys"
note: "Console-specific keys for encrypted content"
source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:241"
source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:240"
notes: |
Ryujinx is a standalone Nintendo Switch emulator written in C#, created by gdkchan.
+1 -1
View File
@@ -62,7 +62,7 @@ def find_revision(
"""The newest revision whose copy of the path has this md5, and its bytes."""
wanted = md5.lower()
for sha in path_history(repo, path, cache_dir):
data = upstream._fetch(upstream.raw_url(repo, sha, path))
data = upstream._fetch(upstream.content_url(repo, sha, path))
if data is not None and hashlib.md5(data).hexdigest() == wanted:
return sha, data
return None
+22 -1
View File
@@ -51,6 +51,13 @@ _HOSTS: dict[str, tuple[str, str, str]] = {
"https://codeberg.org/api/v1",
"https://codeberg.org",
),
# The Ryujinx repository left GitHub in October 2024; this Gitea pull
# mirror kept its history up to 1.1.1402.
"git.ngram.ca": (
"forgejo",
"https://git.ngram.ca/api/v1",
"https://git.ngram.ca",
),
"git.citron-emu.org": (
"forgejo",
"https://git.citron-emu.org/api/v1",
@@ -180,6 +187,20 @@ def raw_url(repo: Repo, sha: str, path: str) -> str:
return f"{repo.raw_base}/{repo.owner}/{repo.name}/raw/commit/{sha}/{quoted}"
def content_url(repo: Repo, sha: str, path: str) -> str:
"""URL the tooling fetches one path from.
Forgejo and Gitea hosts put their web routes, /raw/commit included,
behind a proof-of-work page (git.ngram.ca answers 200 with an HTML
challenge); the API raw route is not challenged. raw_url stays the
link a reader opens.
"""
if repo.family != "forgejo":
return raw_url(repo, sha, path)
quoted = urllib.parse.quote(path)
return f"{repo.api_base}/repos/{repo.owner}/{repo.name}/raw/{quoted}?ref={sha}"
def _headers(url: str, accept_json: bool = False) -> dict[str, str]:
"""Request headers. GITHUB_TOKEN is only ever sent to GitHub."""
headers = {"User-Agent": USER_AGENT}
@@ -336,7 +357,7 @@ def fetch_file(
return None if text == ABSENT else text.splitlines()
if offline:
raise NotCachedError(f"{repo.slug}@{sha[:8]}:{path} is not in the offline cache")
text = _http_text(raw_url(repo, sha, path))
text = _http_text(content_url(repo, sha, path))
write_cache(target, ABSENT if text is None else text)
return None if text is None else text.splitlines()
+15
View File
@@ -115,6 +115,21 @@ class TestRawUrl(unittest.TestCase):
"https://codeberg.org/g/p/raw/commit/abc123/a.c",
)
def test_forgejo_fetches_through_the_api(self):
# git.ngram.ca serves an HTML proof-of-work page on /raw/commit,
# which fetch_file would have cached as the file's lines.
import upstream
repo = parse_repo("https://git.ngram.ca/mirrors/Ryujinx")
self.assertEqual(
upstream.content_url(repo, "abc123", "src/a b.cs"),
"https://git.ngram.ca/api/v1/repos/mirrors/Ryujinx/raw/src/a%20b.cs?ref=abc123",
)
github = parse_repo("https://github.com/o/n")
self.assertEqual(
upstream.content_url(github, "s", "a.c"), raw_url(github, "s", "a.c")
)
def test_path_is_quoted(self):
repo = parse_repo("https://github.com/o/n")
self.assertIn("src/a%20b.cpp", raw_url(repo, "s", "src/a b.cpp"))