EN /HU | Belépés

warpstore

Egy áruházmotor beolvas egy WarpEngine-katalógust, és kiírja valamelyik gazdaplatform saját játékkönyvtár-formátumát. Csak ez az utolsó lépés tér el platformonként. Az API-val való beszélgetés, a kiadás kiválasztása, a gép illesztése és annak nyilvántartása, hogy mi hova került, mindenhol ugyanaz a munka — a warpstore pontosan ez a munka, egyetlen fájlban, minden áruházmotor közösen használja.

TXT
                    ┌──────────────────────────────┐
                    │  warpstore.py                │
                    │  catalog · releases · host   │
                    │  state · config · HTTP       │
                    └──────────────┬───────────────┘
                    ┌──────────────┴───────────────┐
                    ▼                              ▼
    warp-engine-batocera-store        warp-engine-retroarch-store
    ROM-mappák + gamelist.xml         .lpl lejátszási listák + bélyegképek
                    │                              │
                    ▼                              ▼
             EmulationStation                  RetroArch

Repó: https://git.teletypegames.org/engines/warpstore Katalógusoldal: WarpEngine Használói: Batocera áruházmotor · RetroArch áruházmotor

Miért létezik

A Batocera-áruház 1073 sor volt, és ennek csak nagyjából a harmada szólt a Batoceráról. A RetroArch-áruháznak a másik kétharmadra volt szüksége, ezért a közös rész kiköltözött — már egy második fogyasztóval a kézben, hogy a vágás ott legyen, ahol a két motor valóban eltér.

Egyetlen fájl, csak a Python 3 szabványkönyvtárával: a gazdagépek a Batocera-doboztól (python3, pip nélkül) az asztali gépig terjednek, és egyiket sem szabad rávenni bármi telepítésére. Egy motor telepítője a warpstore.py fájlt az adapterszkript mellé teszi, az adapter pedig import warpstore-t hív.

Mit ad hozzá egy adapter

  1. DEFAULT_CONFIG — hol vannak a dolgok ezen a gazdagépen, és melyik katalógusplatform mire képződik le.
  2. accept(spec, sw) — mely katalógusbejegyzéseket tudja futtatni ez a gazdagép, és hogyan csoportosulnak.
  3. A kód, amely kiírja a gazdagép könyvtárformátumát.
PYTHON
import warpstore as ws

def accept(spec, sw):
    """Return (scope, extras), or raise ws.Skip(reason) to reject the title."""
    if spec["system"] not in available_systems:
        raise ws.Skip(f"no '{spec['system']}' ROM folder on this box")
    return spec["system"], {"system": spec["system"]}

cfg = ws.load_config(path, DEFAULT_CONFIG, required=("paths.subfolder",))
ws.init(path)
games, skipped = ws.select_games(cfg, ws.fetch_catalog(cfg, use_cache=True), accept)

A scope az, ahogyan a gazdagép csoportosítja a könyvtárát — egy Batocera-rendszer, egy RetroArch-lejátszási lista. A state.json kulcsa <scope>:<name>, így ugyanaz a szoftvernév két scope-ban két külön bejegyzés marad.

Mi van benne

Terület Függvények
Naplózás set_tag, set_verbose, log, debug, die
Fájlok load_json, write_json, write_atomic, within, prune_empty_dirs
Konfiguráció deep_merge, load_config
Áruház-könyvtár init, majd HOME, CONFIG_PATH, STATE_PATH, CATALOG_CACHE
HTTP http_get, http_download, api_url, download_url, user_agent
Gazdagép machine, host_os, host, resolve_for_host
Katalógus fetch_catalog, select_games, survey_catalog, pick_release, asset_basename, download_image
Állapot load_state, save_state, game_key, record_scope, records_by_scope, match_keys, limit_to_names

Öt közülük olyan döntést hordoz, amit érdemes ismerni.

select_games kontra survey_catalog — a select_games azt adja vissza, amit az áruház telepíteni tud. A survey_catalog ezen felül címenként egy rekordot ad azokról is, amelyeket ez a gép nem tud telepíteni, egy reason kóddal (platform_off, host_asset, no_asset, vetoed) és egy mondattal. Egy kliens ezeket kiszürkítheti elrejtés helyett — a WarpEngine Client pontosan ezt teszi. Azok a címek, amelyeket az áruház maga dönt úgy, hogy nem kínál, egyik listában sincsenek benne — egy rossz státusz vagy egy kizárólista szerkesztői döntés, nem a gép korlátja.

resolve_for_host(value, host) — olyan konfigurációs érték, amely függhet a géptől. Egy sima sztring mindenhol ugyanaz — ilyen a cartridge: adat egy emulátornak. Egyébként az érték egy mapping, és a legspecifikusabb kulcs nyer:

PYTHON
{"linux-aarch64":, "aarch64":, "linux":, "*":}

Ha nincs illeszkedő kulcs és nincs * sem, az eredmény None, és a hívó kihagyottként jelenti a címet, ahelyett hogy olyasmit telepítene, ami nem tud futni. Ez a Batocera-motor resolve_for_arch függvényének általánosítása: a Batocera mindig csak linux volt, de egy RetroArch-gazdagép lehet Windows, macOS vagy Android — és ez dönti el, hogy hogyan hívják a libretro core fájlját (.dll, .dylib, _android.so).

within(path, root) — minden törlést ez őriz. Egy áruház csak abból a részfából távolíthat el fájlokat, amely az övé, soha nem a felhasználó könyvtárából és soha nem egy másik áruházéból.

prune_empty_dirs(dirs, root) — ugyanennek a szabálynak az eltávolítási oldala. Csak üres könyvtárak tűnnek el, és csak a root belsejében: egyetlen kósza fájl megtartja a könyvtárat. Ez teszi lehetővé, hogy a purge (és így az uninstall.sh) úgy hagyja a gazdagépet, ahogy volt.

write_atomic — semmi nem íródik a helyén. Egy szinkron közben megszakított áruház különben félig megírt lejátszási listát vagy gamelistet hagyna maga után, ami rosszabb, mint egy régi.

Minden áruház eltávolítása egy gépről

SH
curl -fsSL https://git.teletypegames.org/engines/warpstore/raw/branch/master/uninstall.sh | sh

Ezzel az egész keretrendszer lehúzható anélkül, hogy fejben kellene tartani, mi van telepítve: megkeresi az összes áruház-könyvtárat az ismert gyökerek alatt, mindegyik áruház saját motorjával takaríttatja el, amit telepített, majd törli az áruházat, az indítóját és a motorfájlokat. Egyetlen áruházhoz inkább az adott motor saját uninstall.sh szkriptjét használd — az ismeri a gazdagép extráit is, például egy Batocera Ports-bejegyzést.

Környezeti változó Jelentés
DRY_RUN 1 esetén kiírja, mi tűnne el, és semmit nem távolít el
KEEP_GAMES 1 esetén csak a szkripteket törli, a játékokat megtartja
FORCE 1 esetén futó RetroArch mellett is takarít
BATOCERA_STORE_ROOT, BATOCERA_PORTS_DIR hol keressen egy Batocera-dobozon
STORE_ROOT, BIN_DIR hol keressen egy asztali gépen

Ha egy motor nem tud végezni (fut a RetroArch, nincs felcsatolva a ROM-gyökér), a futás ott megáll, ahelyett hogy törölné azt a motort, amely tudja, mit telepített.

A szkript POSIX sh, nem bash, így a | sh ott is működik, ahol a /bin/sh a dash. A motorok saját telepítői ugyanígy.

Állapot

state.json, 2-es verzió, <scope>:<name> kulccsal:

JSON
{
  "version": 2,
  "installed": {
    "c64:blessingofra": { "name": "blessingofra", "scope": "c64", "asset": "blessingofra-2.0.0.prg", "": "" }
  }
}

A record_scope() visszaesik a rekord system mezőjére, mert a Batocera-áruház ezt írta, mielőtt ez a modul létezett. Ott a kettő ugyanaz a sztring volt, így egy telepített doboz migráció nélkül működik tovább, és semmit nem tölt le újra. Egy version: 1 fájlt, amelynek a kulcsa a csupasz szoftvernév, az első futáskor újrakulcsoz.

Verziózás

Egyik motor sem rögzít verziót: mindkettő a master ágról húzza le a warpstore.py fájlt telepítéskor, így egy itteni változás a következő telepítéskor minden áruházhoz eljut. Pont ez a lényeg, és pont ezért kell a felületet kicsin tartani. A --version mindkét motoron kiírja mindkét számot, például 3.1.0 (warpstore 1.2.0).