ci: daily refresh of badge-data.json and README badge cleanup

- Add Gitea Actions workflow and update-badge-data.py to refresh download
  counts and version from the releases API on a schedule.
- Simplify README shields (fewer dynamic badges) and move social badges
  to the footer; document the badge-data maintenance path.
- Drop release_published_date from badge-data.json; ignore __pycache__.

Made-with: Cursor
This commit is contained in:
niklascfw 2026-04-09 23:23:26 +02:00
parent 0671458151
commit 698049c0de
No known key found for this signature in database
5 changed files with 176 additions and 18 deletions

42
.github/workflows/update-badge-data.yml vendored Normal file
View file

@ -0,0 +1,42 @@
# Aktualisiert täglich badge-data.json (Download-Summe, Version aus letztem Release, Switch-FW aus Release-Body).
# Läuft auf Gitea Actions wie die übrigen Workflows (.github/workflows); github.api_url = Gitea-API.
name: Update badge-data
on:
schedule:
- cron: "0 5 * * *"
workflow_dispatch:
permissions:
contents: write
jobs:
refresh:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Regenerate badge-data.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: python3 scripts/update-badge-data.py
- name: Commit and push if changed
run: |
set -euo pipefail
git config user.name "OmniNX CI"
git config user.email "omninx-ci@users.noreply.git.niklascfw.de"
git add badge-data.json
if git diff --staged --quiet; then
echo "badge-data.json unverändert."
exit 0
fi
git commit -m "chore: refresh badge-data.json [skip ci]"
git push

3
.gitignore vendored
View file

@ -1,3 +1,6 @@
# Python
__pycache__/
# Build artifacts
build/
output/

View file

@ -1,12 +1,8 @@
# OmniNX CFW Pack
[![Aktuelle Version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgit.niklascfw.de%2FOmniNX%2FOmniNX%2Fraw%2Fbranch%2Fmain%2Fbadge-data.json&query=%24.omninx_pack_version&label=OmniNX%20Pack%20Version&color=blue)](https://git.niklascfw.de/OmniNX/OmniNX/releases/latest)
[![Firmware](https://img.shields.io/github/v/release/THZoria/NX_Firmware?display_name=release&filter=*22.1.0&label=Kompatibel%20mit%20FW&color=898c8c&logo=nintendoswitch)](https://github.com/THZoria/NX_Firmware/releases/tag/22.1.0)
[![Atmosphere Version](https://img.shields.io/github/v/release/Atmosphere-NX/Atmosphere?include_prereleases&filter=1.11.1&label=Atmosphere%20Version&color=189c11)](https://github.com/Atmosphere-NX/Atmosphere/releases/tag/1.11.1)
[![Release Datum](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgit.niklascfw.de%2FOmniNX%2FOmniNX%2Fraw%2Fbranch%2Fmain%2Fbadge-data.json&query=%24.release_published_date&label=Released&color=222222)](https://git.niklascfw.de/OmniNX/OmniNX/releases)
[![OmniNX Pack Downloads](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgit.niklascfw.de%2FOmniNX%2FOmniNX%2Fraw%2Fbranch%2Fmain%2Fbadge-data.json&query=%24.release_zip_downloads_total&label=OmniNX%20Pack%20Downloads&color=6f42c1)](https://git.niklascfw.de/OmniNX/OmniNX/releases)
[![Discord](https://img.shields.io/discord/733728731432091648?logo=discord&logoColor=white&label=NiklasCFW%20Modding%20Community&color=5865F2)](https://discord.gg/5rMJ4fWQT3)
[![YouTube Channel](https://img.shields.io/youtube/channel/subscribers/UCdEkFmAShnlE15CCimAwnYg?logo=youtube&label=NiklasCFW&color=ff0000)](https://www.youtube.com/@NiklasCFW)
[![Aktuelle Version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgit.niklascfw.de%2FOmniNX%2FOmniNX%2Fraw%2Fbranch%2Fmain%2Fbadge-data.json&query=%24.omninx_pack_version&label=OmniNX%20Version&color=blue)](https://git.niklascfw.de/OmniNX/OmniNX/releases/latest)
[![Firmware](https://img.shields.io/github/v/release/THZoria/NX_Firmware?display_name=release&filter=*22.1.0&label=Kompatibel%20mit%20FW&color=189c11&logo=nintendoswitch)](https://github.com/THZoria/NX_Firmware/releases/tag/22.1.0)
[![OmniNX Pack Downloads](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgit.niklascfw.de%2FOmniNX%2FOmniNX%2Fraw%2Fbranch%2Fmain%2Fbadge-data.json&query=%24.release_zip_downloads_total&label=OmniNX%20Downloads&color=6f42c1)](https://git.niklascfw.de/OmniNX/OmniNX/releases)
OmniNX ist ein vollständiges Custom-Firmware-Setup für die Nintendo Switch, verfügbar in drei Varianten mit Fokus auf Flexibilität und Modularität.
@ -114,7 +110,7 @@ Zusätzlich zum **Standard**-Inhalt liefert die **OC**-Variante u. a.:
```
OmniNX/
├── badge-data.json # README-Shields: Pack-Version, Released-Datum, Download-Summe (Gitea-ZIPs), switch_firmware
├── badge-data.json # README-Shields (Version, Downloads, FW); täglich per CI scripts/update-badge-data.py
├── staging/ # Gemeinsame Install-Stage-Dateien (Bootloader, Payloads, Nyx, etc.)
├── variants/ # Varianten-Inhalt
│ ├── light/ # Light-Variante (minimal)
@ -189,11 +185,11 @@ Die verwendeten Projekte unterliegen ihren jeweiligen Lizenzen. Das OmniNX-Pack
* **Discord:** [NiklasCFW Modding Community](https://discord.gg/5rMJ4fWQT3)
---
<div align="center">
[![OmniNX](https://img.shields.io/badge/OmniNX-CFW%20Pack-7d7d7d?style=for-the-badge)](https://git.niklascfw.de/OmniNX/OmniNX/releases)
[![Variants](https://img.shields.io/badge/Varianten-Standard%20%7C%20Light%20%7C%20OC-7d7d7d?style=for-the-badge)](https://git.niklascfw.de/OmniNX/OmniNX)
### Socials
[![Discord](https://img.shields.io/discord/733728731432091648?logo=discord&logoColor=white&label=NiklasCFW%20Modding%20Community&color=5865F2)](https://discord.gg/5rMJ4fWQT3)
[![YouTube Channel](https://img.shields.io/youtube/channel/subscribers/UCdEkFmAShnlE15CCimAwnYg?logo=youtube&label=NiklasCFW&color=ff0000)](https://www.youtube.com/@NiklasCFW)
</div>

View file

@ -1,6 +1,5 @@
{
"switch_firmware": "22.1.0",
"release_zip_downloads_total": 1016,
"omninx_pack_version": "1.0.0-b9",
"release_published_date": "2026-04-07"
"omninx_pack_version": "1.0.0-b9"
}

View file

@ -0,0 +1,118 @@
#!/usr/bin/env python3
"""Schreibt badge-data.json aus der Releases-API (Gitea/GitHub-kompatibel)."""
from __future__ import annotations
import json
import os
import re
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 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 parse_firmware_from_body(body: str) -> str | None:
if not body:
return None
patterns = (
r"Firmware\s+Version\s*\*\*(\d+\.\d+\.\d+)\*\*",
r"mit\s+Firmware\s+Version\s*\*\*(\d+\.\d+\.\d+)\*\*",
r"\*\*(\d+\.\d+\.\d+)\*\*\s+in\s+der\s+CFW",
)
for p in patterns:
m = re.search(p, body, re.I | re.MULTILINE)
if m:
return m.group(1)
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", "")
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:
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 releases:
print("Keine Releases gefunden.", file=sys.stderr)
return 1
latest = next((r for r in releases if not r.get("draft")), None)
if not latest:
print("Kein nicht-Draft-Release.", file=sys.stderr)
return 1
tag = str(latest.get("tag_name") or "").strip()
body = str(latest.get("body") or "")
fw = parse_firmware_from_body(body) or load_existing_firmware() or "unknown"
data = {
"switch_firmware": fw,
"release_zip_downloads_total": sum_zip_downloads(releases),
"omninx_pack_version": 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())