forked from Mirrors/OmniNX
Gitea Actions GITHUB_TOKEN often returns 404 on sibling repos. Try unauthenticated API first (public releases), then job token; optional FIRMWARE_API_TOKEN for private firmware repo. Made-with: Cursor
148 lines
4.5 KiB
Python
148 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Schreibt badge-data.json aus der Releases-API (OmniNX-Pack + NX_Firmware-Tag, Gitea/GitHub-kompatibel)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
BADGE_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "badge-data.json")
|
|
|
|
|
|
def api_get(url: str, token: str) -> bytes:
|
|
req = urllib.request.Request(url)
|
|
if token:
|
|
req.add_header("Authorization", f"Bearer {token}")
|
|
req.add_header("Accept", "application/json")
|
|
with urllib.request.urlopen(req, timeout=120) as resp:
|
|
return resp.read()
|
|
|
|
|
|
def fetch_releases(api_base: str, repo: str, token: str) -> list:
|
|
out: list = []
|
|
page = 1
|
|
while True:
|
|
url = f"{api_base}/repos/{repo}/releases?limit=100&page={page}"
|
|
batch = json.loads(api_get(url, token))
|
|
if not batch:
|
|
break
|
|
out.extend(batch)
|
|
if len(batch) < 100:
|
|
break
|
|
page += 1
|
|
return out
|
|
|
|
|
|
def _token_attempt_order(pack_token: str) -> list[str]:
|
|
"""Repos/branches the job token cannot see on Gitea often return 404; public /releases works without auth."""
|
|
pat = os.environ.get("FIRMWARE_API_TOKEN", "").strip()
|
|
order = [pat, "", pack_token] if pat else ["", pack_token]
|
|
seen: set[str] = set()
|
|
out: list[str] = []
|
|
for t in order:
|
|
if t in seen:
|
|
continue
|
|
seen.add(t)
|
|
out.append(t)
|
|
return out
|
|
|
|
|
|
def fetch_releases_with_token_fallback(
|
|
api_base: str, repo: str, pack_token: str
|
|
) -> tuple[list | None, urllib.error.HTTPError | None]:
|
|
last_err: urllib.error.HTTPError | None = None
|
|
for t in _token_attempt_order(pack_token):
|
|
try:
|
|
return fetch_releases(api_base, repo, t), None
|
|
except urllib.error.HTTPError as e:
|
|
last_err = e
|
|
if e.code in (401, 403, 404):
|
|
continue
|
|
raise
|
|
return None, last_err
|
|
|
|
|
|
def sum_zip_downloads(releases: list) -> int:
|
|
total = 0
|
|
for rel in releases:
|
|
for asset in rel.get("assets") or []:
|
|
name = str(asset.get("name", ""))
|
|
if name.endswith(".zip"):
|
|
total += int(asset.get("download_count") or 0)
|
|
return total
|
|
|
|
|
|
def first_non_draft_tag(releases: list) -> str | None:
|
|
for rel in releases:
|
|
if rel.get("draft"):
|
|
continue
|
|
tag = str(rel.get("tag_name") or "").strip()
|
|
if tag:
|
|
return tag
|
|
return None
|
|
|
|
|
|
def load_existing_firmware() -> str | None:
|
|
if not os.path.isfile(BADGE_PATH):
|
|
return None
|
|
try:
|
|
with open(BADGE_PATH, encoding="utf-8") as f:
|
|
return json.load(f).get("switch_firmware")
|
|
except (OSError, json.JSONDecodeError, TypeError):
|
|
return None
|
|
|
|
|
|
def main() -> int:
|
|
api_base = os.environ.get("GITHUB_API_URL", "").rstrip("/")
|
|
repo = os.environ.get("GITHUB_REPOSITORY", "")
|
|
fw_repo = os.environ.get("FIRMWARE_REPOSITORY", "OmniNX/NX_Firmware").strip()
|
|
token = os.environ.get("GITHUB_TOKEN", "")
|
|
|
|
if not api_base or not repo:
|
|
print("GITHUB_API_URL und GITHUB_REPOSITORY werden benötigt.", file=sys.stderr)
|
|
return 1
|
|
|
|
try:
|
|
omninx_releases = fetch_releases(api_base, repo, token)
|
|
except urllib.error.HTTPError as e:
|
|
print(f"API: HTTP {e.code} — {e.reason}", file=sys.stderr)
|
|
return 1
|
|
|
|
if not omninx_releases:
|
|
print("Keine Releases gefunden.", file=sys.stderr)
|
|
return 1
|
|
|
|
omninx_tag = first_non_draft_tag(omninx_releases)
|
|
if not omninx_tag:
|
|
print("Kein nicht-Draft-Release.", file=sys.stderr)
|
|
return 1
|
|
|
|
fw: str | None = None
|
|
fw_releases, fw_err = fetch_releases_with_token_fallback(api_base, fw_repo, token)
|
|
if fw_releases is not None:
|
|
fw = first_non_draft_tag(fw_releases)
|
|
elif fw_err is not None:
|
|
print(f"Firmware-Repo ({fw_repo}): HTTP {fw_err.code} — {fw_err.reason}", file=sys.stderr)
|
|
|
|
if not fw:
|
|
fw = load_existing_firmware() or "unknown"
|
|
|
|
data = {
|
|
"switch_firmware": fw,
|
|
"release_zip_downloads_total": sum_zip_downloads(omninx_releases),
|
|
"omninx_pack_version": omninx_tag,
|
|
}
|
|
|
|
with open(BADGE_PATH, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
f.write("\n")
|
|
|
|
print(json.dumps(data, indent=2))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|