mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-13 12:22:33 -05:00
fix: filter baseline by platform-scoped cores, include retroarch cores in emudeck targets
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
"""Scraper for EmuDeck emulator targets.
|
||||
|
||||
Sources:
|
||||
SteamOS: dragoonDorise/EmuDeck — checkBIOS.sh, install scripts
|
||||
Windows: EmuDeck/emudeck-we — checkBIOS.ps1
|
||||
SteamOS: dragoonDorise/EmuDeck — functions/EmuScripts/*.sh
|
||||
Windows: EmuDeck/emudeck-we — functions/EmuScripts/*.ps1
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import urllib.error
|
||||
@@ -19,38 +20,25 @@ from . import BaseTargetScraper
|
||||
|
||||
PLATFORM_NAME = "emudeck"
|
||||
|
||||
STEAMOS_CHECKBIOS_URL = (
|
||||
"https://raw.githubusercontent.com/dragoonDorise/EmuDeck/"
|
||||
"main/functions/checkBIOS.sh"
|
||||
)
|
||||
WINDOWS_CHECKBIOS_URL = (
|
||||
"https://raw.githubusercontent.com/EmuDeck/emudeck-we/"
|
||||
"main/functions/checkBIOS.ps1"
|
||||
)
|
||||
STEAMOS_API = "https://api.github.com/repos/dragoonDorise/EmuDeck/contents/functions/EmuScripts"
|
||||
WINDOWS_API = "https://api.github.com/repos/EmuDeck/emudeck-we/contents/functions/EmuScripts"
|
||||
|
||||
# checkBIOS functions check by system, not by core. Map to actual emulators.
|
||||
# Source: EmuDeck install scripts + wiki documentation.
|
||||
_BIOS_SYSTEM_TO_CORES: dict[str, list[str]] = {
|
||||
"ps1bios": ["beetle_psx", "pcsx_rearmed", "duckstation", "swanstation"],
|
||||
"ps2bios": ["pcsx2"],
|
||||
"segacdbios": ["genesisplusgx", "picodrive"],
|
||||
"saturnbios": ["beetle_saturn", "kronos", "yabasanshiro", "yabause"],
|
||||
"dreamcastbios": ["flycast"],
|
||||
"dsbios": ["melonds", "desmume"],
|
||||
"ryujinxbios": [], # standalone, not libretro
|
||||
"yuzubios": [], # standalone, not libretro
|
||||
"citronbios": ["citron"],
|
||||
# Map EmuDeck script names to emulator profile keys
|
||||
# Script naming: emuDeckDolphin.sh -> dolphin
|
||||
# Some need explicit mapping when names differ
|
||||
_NAME_OVERRIDES: dict[str, str] = {
|
||||
"pcsx2qt": "pcsx2",
|
||||
"rpcs3legacy": "rpcs3",
|
||||
"cemuproton": "cemu",
|
||||
"rmg": "mupen64plus_next",
|
||||
"bigpemu": "bigpemu",
|
||||
"eden": "eden",
|
||||
"suyu": "suyu",
|
||||
"ares": "ares",
|
||||
}
|
||||
|
||||
# Patterns for BIOS check function names
|
||||
_SH_EMULATOR_RE = re.compile(
|
||||
r'(?:function\s+|^)(?:check|install|setup)([A-Za-z0-9_]+)\s*\(',
|
||||
re.MULTILINE,
|
||||
)
|
||||
_PS1_EMULATOR_RE = re.compile(
|
||||
r'function\s+(?:check|install|setup)([A-Za-z0-9_]+)\s*(?:\(\))?\s*\{',
|
||||
re.MULTILINE | re.IGNORECASE,
|
||||
)
|
||||
# Scripts that are not emulators (config helpers, etc.)
|
||||
_SKIP = {"retroarch_maincfg", "retroarch"}
|
||||
|
||||
|
||||
def _fetch(url: str) -> str | None:
|
||||
@@ -65,19 +53,31 @@ def _fetch(url: str) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
def _extract_cores(text: str, pattern: re.Pattern[str]) -> list[str]:
|
||||
"""Extract core names by parsing BIOS check functions and mapping to cores."""
|
||||
seen: set[str] = set()
|
||||
results: list[str] = []
|
||||
for m in pattern.finditer(text):
|
||||
system_name = m.group(1).lower()
|
||||
# Map system BIOS check to actual core names
|
||||
cores = _BIOS_SYSTEM_TO_CORES.get(system_name, [])
|
||||
for core in cores:
|
||||
if core not in seen:
|
||||
seen.add(core)
|
||||
results.append(core)
|
||||
return sorted(results)
|
||||
def _list_emuscripts(api_url: str) -> list[str]:
|
||||
"""List emulator script filenames from GitHub API."""
|
||||
raw = _fetch(api_url)
|
||||
if not raw:
|
||||
return []
|
||||
entries = json.loads(raw)
|
||||
names = []
|
||||
for e in entries:
|
||||
name = e.get("name", "")
|
||||
if name.endswith(".sh") or name.endswith(".ps1"):
|
||||
names.append(name)
|
||||
return names
|
||||
|
||||
|
||||
def _script_to_core(filename: str) -> str | None:
|
||||
"""Convert EmuScripts filename to core profile key."""
|
||||
# Strip extension and emuDeck prefix
|
||||
name = re.sub(r'\.(sh|ps1)$', '', filename, flags=re.IGNORECASE)
|
||||
name = re.sub(r'^emuDeck', '', name, flags=re.IGNORECASE)
|
||||
if not name:
|
||||
return None
|
||||
key = name.lower()
|
||||
if key in _SKIP:
|
||||
return None
|
||||
return _NAME_OVERRIDES.get(key, key)
|
||||
|
||||
|
||||
class Scraper(BaseTargetScraper):
|
||||
@@ -86,25 +86,67 @@ class Scraper(BaseTargetScraper):
|
||||
def __init__(self, url: str = "https://github.com/dragoonDorise/EmuDeck"):
|
||||
super().__init__(url=url)
|
||||
|
||||
def _fetch_cores_for_target(self, api_url: str, label: str,
|
||||
arch: str = "x86_64") -> list[str]:
|
||||
print(f" fetching {label} EmuScripts...", file=sys.stderr)
|
||||
scripts = _list_emuscripts(api_url)
|
||||
cores: list[str] = []
|
||||
seen: set[str] = set()
|
||||
has_retroarch = False
|
||||
for script in scripts:
|
||||
core = _script_to_core(script)
|
||||
if core and core not in seen:
|
||||
seen.add(core)
|
||||
cores.append(core)
|
||||
# Detect RetroArch presence (provides all libretro cores)
|
||||
name = re.sub(r'\.(sh|ps1)$', '', script, flags=re.IGNORECASE)
|
||||
if name.lower() in ("emudeckretroarch", "retroarch_maincfg"):
|
||||
has_retroarch = True
|
||||
|
||||
standalone_count = len(cores)
|
||||
# EmuDeck ships RetroArch = all its libretro cores are available
|
||||
if has_retroarch:
|
||||
ra_cores = self._load_retroarch_cores(arch)
|
||||
for c in ra_cores:
|
||||
if c not in seen:
|
||||
seen.add(c)
|
||||
cores.append(c)
|
||||
|
||||
print(f" {label}: {standalone_count} standalone + "
|
||||
f"{len(cores) - standalone_count} via RetroArch = {len(cores)} total",
|
||||
file=sys.stderr)
|
||||
return sorted(cores)
|
||||
|
||||
@staticmethod
|
||||
def _load_retroarch_cores(arch: str) -> list[str]:
|
||||
"""Load RetroArch target cores for given architecture."""
|
||||
import os
|
||||
target_path = os.path.join("platforms", "targets", "retroarch.yml")
|
||||
if not os.path.exists(target_path):
|
||||
return []
|
||||
with open(target_path) as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
# Find a target matching the architecture
|
||||
for tname, tinfo in data.get("targets", {}).items():
|
||||
if tinfo.get("architecture") == arch:
|
||||
return tinfo.get("cores", [])
|
||||
return []
|
||||
|
||||
def fetch_targets(self) -> dict:
|
||||
print(" fetching SteamOS checkBIOS.sh...", file=sys.stderr)
|
||||
sh_text = _fetch(STEAMOS_CHECKBIOS_URL)
|
||||
steamos_cores = _extract_cores(sh_text, _SH_EMULATOR_RE) if sh_text else []
|
||||
steamos_cores = self._fetch_cores_for_target(STEAMOS_API, "SteamOS")
|
||||
windows_cores = self._fetch_cores_for_target(WINDOWS_API, "Windows")
|
||||
|
||||
print(" fetching Windows checkBIOS.ps1...", file=sys.stderr)
|
||||
ps1_text = _fetch(WINDOWS_CHECKBIOS_URL)
|
||||
windows_cores = _extract_cores(ps1_text, _PS1_EMULATOR_RE) if ps1_text else []
|
||||
|
||||
targets: dict[str, dict] = {
|
||||
"steamos": {
|
||||
targets: dict[str, dict] = {}
|
||||
if steamos_cores:
|
||||
targets["steamos"] = {
|
||||
"architecture": "x86_64",
|
||||
"cores": steamos_cores,
|
||||
},
|
||||
"windows": {
|
||||
}
|
||||
if windows_cores:
|
||||
targets["windows"] = {
|
||||
"architecture": "x86_64",
|
||||
"cores": windows_cores,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"platform": "emudeck",
|
||||
|
||||
Reference in New Issue
Block a user