forked from Mirrors/OmniNX
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:
parent
0671458151
commit
698049c0de
5 changed files with 176 additions and 18 deletions
42
.github/workflows/update-badge-data.yml
vendored
Normal file
42
.github/workflows/update-badge-data.yml
vendored
Normal 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
3
.gitignore
vendored
|
|
@ -1,3 +1,6 @@
|
|||
# Python
|
||||
__pycache__/
|
||||
|
||||
# Build artifacts
|
||||
build/
|
||||
output/
|
||||
|
|
|
|||
20
README.md
20
README.md
|
|
@ -1,12 +1,8 @@
|
|||
# OmniNX CFW Pack
|
||||
|
||||
[](https://git.niklascfw.de/OmniNX/OmniNX/releases/latest)
|
||||
[](https://github.com/THZoria/NX_Firmware/releases/tag/22.1.0)
|
||||
[](https://github.com/Atmosphere-NX/Atmosphere/releases/tag/1.11.1)
|
||||
[](https://git.niklascfw.de/OmniNX/OmniNX/releases)
|
||||
[](https://git.niklascfw.de/OmniNX/OmniNX/releases)
|
||||
[](https://discord.gg/5rMJ4fWQT3)
|
||||
[](https://www.youtube.com/@NiklasCFW)
|
||||
[](https://git.niklascfw.de/OmniNX/OmniNX/releases/latest)
|
||||
[](https://github.com/THZoria/NX_Firmware/releases/tag/22.1.0)
|
||||
[](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">
|
||||
|
||||
[](https://git.niklascfw.de/OmniNX/OmniNX/releases)
|
||||
[](https://git.niklascfw.de/OmniNX/OmniNX)
|
||||
### Socials
|
||||
|
||||
[](https://discord.gg/5rMJ4fWQT3)
|
||||
[](https://www.youtube.com/@NiklasCFW)
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
118
scripts/update-badge-data.py
Normal file
118
scripts/update-badge-data.py
Normal 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())
|
||||
Loading…
Reference in a new issue