RETROARCH_STORE.md is the design, written from measurements rather than documentation: the format samples, thumbnail layout and core names come from a real RetroArch install on this machine, the core availability from the libretro buildbot index, and the CRC32s from the catalog itself. Three findings shaped it. The playlist folder is not necessarily inside the RetroArch directory — on the machine measured, playlist_directory is under ~/Documents while cores and thumbnails are under ~/Library — so reading retroarch.cfg is a requirement, not a nicety. Thumbnails must be PNG, and one of our covers is a GIF, which no store had cared about before. And a .lpl entry has nowhere to put a description, so desc and author do not survive the trip. Built the same day, in three repositories: engines/warpstore (the shared core, extracted immediately rather than in the second phase the plan proposed), tools/warp-engine-retroarch-store and tools/ttg-retroarch-store. The closing section of the design records what the implementation changed about it. MORE_STORES.md item 4 is closed, its "a minta" section now points at the extracted core, and REPO_REFACT.md carries the three new repos — check-repos.sh is green at 49. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
25 KiB
RetroArch store — kidolgozott terv
Készült 2026-08-17-én, a MORE_STORES.md 4. pontjának kifejtéseként. Minden
alább szereplő formátum- és útvonal-állítás egy valódi RetroArch-telepítésen
mérve (macOS, ~/Library/Application Support/RetroArch), a mag-elérhetőség
pedig a libretro buildbot indexéből.
Megvalósítva ugyanaznap. Három repó:
engines/warpstore(közös mag),tools/warp-engine-retroarch-store(motor),tools/ttg-retroarch-store(a mi store-unk). A 11. pont javaslatával szemben a közös rész azonnal kiemelve — lásd az „Amit a megvalósítás megváltoztatott" szakaszt a végén. Wiki: warpstore, motor, store.
1. Mit ad, és mit nem
Új asset-fajtát nem fogyaszt: a RetroArch magok emulátorok, tehát pontosan
azt eszik, amit a Batocera-store is — a cartridge-et. A nyereség nem a
katalógus szélessége, hanem a gazdagépek száma: asztali Linux/Windows/macOS,
Android, Steam Deck, konzolportok.
A mai katalógusból (released + archived, 2026-08-17-i mérés) ez 6 cím,
összesen 233 KB:
| Platform | Szoftver | Cím | Fájl | Méret | CRC32 |
|---|---|---|---|---|---|
| c64 | blessingofra | Blessing of Ra | blessingofra-2.0.0.prg |
10 561 | 4253CFC6 |
| c64 | rabbitc64 | Rabbit Scooter | rabbit-1.0.0.prg |
8 072 | 31BF558B |
| c64 | c64demo | C64 Demo for Arok Party 2026 | c64demo-1.0.prg |
4 641 | AF681FFC |
| tic80 | impostor | Definitely not an Impostor | impostor-1.0.tic |
163 497 | 8D9A45DA |
| tic80 | bombexpert | BombExpert | bombexpert-0.2.tic |
25 227 | A67DDF4A |
| tic80 | mranderson | Mr Anderson's Adventure | mranderson-0.1.tic |
21 657 | E98C7712 |
Egy egész store negyed megabájt — ez az, ami miatt a szinkron gyakorlatilag ingyen van, és amiért az Android-célpont zip-ként is elküldhető.
A két mag mindenhol van. A buildbot indexét végigkérdezve:
| Cél | vice_x64 |
tic80 |
Fájlnév-alak |
|---|---|---|---|
apple/osx/arm64, apple/osx/x86_64 |
✔ | ✔ | *_libretro.dylib |
linux/x86_64, linux/aarch64, linux/armhf, linux/armv7-neon-hf |
✔ | ✔ | *_libretro.so |
windows/x86_64 |
✔ | ✔ | *_libretro.dll |
android/arm64-v8a, android/armeabi-v7a |
✔ | ✔ | *_libretro_android.so |
Tehát nincs olyan RetroArch-gazdagép, amin a katalógusunk ne futna — az Androidon
viszont a mag fájlneve más (_android.so), és ez a tervben külön kezelendő.
Amire nem jó. A html és a natív zipek maradnak kiszolgálatlanul: nincs
böngésző-mag, és a LÖVE-hoz sincs valódi mag (a lutro nem LÖVE-kompatibilis).
Batocerán és a többi ES-frontendes gépen szintén nem ez a helyes út — ott a
RetroArch a háttérben fut, a könyvtár az ES-é, tehát a Batocera-store dolgozik.
2. A gazdaplatform, ahogy valóban kinéz
Négy dolgot érdemes tudni, mert mind a négy megcáfol egy kézenfekvő feltevést.
(a) A retroarch.cfg az egyetlen igazságforrás, és a könyvtárak szét vannak
szórva. A mért gépen:
libretro_directory = ~/Library/Application Support/RetroArch/cores
thumbnails_directory = ~/Library/Application Support/RetroArch/thumbnails
playlist_directory = ~/Documents/RetroArch/playlists ← más ág!
system_directory = ~/Documents/RetroArch/system
A playlist-könyvtár tehát nem a RetroArch alapkönyvtárában van. Aki a
<base>/playlists mintát égeti bele, az ezen a gépen csendben a semmibe ír.
A motor kötelezően a retroarch.cfg-ből olvassa a négy útvonalat, és csak
akkor tippel, ha nincs cfg. A ~ feloldandó, ahogy a Windows-os portable
telepítések : prefixe is (a RetroArch saját alapkönyvtárát jelenti).
(b) A .lpl sémája. Egy valódi playlist a gépről (rövidítve) — ez a
formátum, amit írunk, nem egy dokumentációból vett közelítés:
{
"version": "1.5",
"default_core_path": "",
"default_core_name": "",
"label_display_mode": 0,
"right_thumbnail_mode": 0,
"left_thumbnail_mode": 0,
"thumbnail_match_mode": 0,
"sort_mode": 0,
"items": [
{
"path": "/…/Altered Beast (USA).md",
"entry_slot": -1,
"label": "Altered Beast (USA)",
"core_path": "/…/cores/genesis_plus_gx_libretro.dylib",
"core_name": "Sega - MS/GG/MD/CD (Genesis Plus GX)",
"crc32": "00000000|crc",
"db_name": "Sega - Mega Drive - Genesis.lpl"
}
]
}
Két tanulság: a path absztolút út a célgépen (ez a 7. pont egész
problémája), a crc32 pedig "<8 hex>|crc" alakú — a RetroArch maga gyakran
csak nullákat ír bele, mi a valódit tudjuk beírni (zlib.crc32, ingyen).
(c) A borítókép útja a playlist nevéből jön. A mért gépen:
thumbnails/Sega - Mega Drive - Genesis/Named_Boxarts/*.png
Named_Titles/*.png
Named_Snaps/*.png
Vagyis thumbnails/<db_name a .lpl nélkül>/Named_*/<label>.png, és kizárólag
PNG — a RetroArch a fájlnevet .png-re képezi. Ez a 6. pont.
(d) A magok saját nevet és kiterjesztést hoznak. A .info fájlokból:
| Mag | corename |
supported_extensions |
database |
|---|---|---|---|
tic80_libretro |
TIC-80 |
tic |
TIC-80 |
vice_x64_libretro |
VICE x64 |
d64|…|prg|p00|crt|… |
Commodore - 64 |
A prg valóban ott van a VICE listájában, tehát a nyers .prg-ket a mag
közvetlenül indítja — nem kell .d64-be csomagolni.
Amit a formátum nem tud: leírást. A .lpl bejegyzésnek nincs desc vagy
developer mezője. A katalógus desc/author adata itt elveszik — a Batocera
gamelist.xml-hez képest ez visszalépés, és nem konfigurálható. (Elvileg egy
generált .rdb adná meg az Információ-panelt és az Explore nézetet, de az bináris
libretrodb-formátum, külső eszközlánccal — ez a terven kívül, külön feladat.)
3. A megoldás felépítése
A Batocera-store bevált kettéosztását követi, ugyanazokkal a nevekkel:
tools/warp-engine-retroarch-store a motor: retroarch_store.py, install.sh
▲
│ config.json
tools/ttg-retroarch-store a mi store-unk: config + wrapper installer
Amit telepít:
<content_root>/<subfolder>/<platform>/ blessingofra-2.0.0.prg, impostor-1.0.tic, …
<playlists_dir>/Teletype Games - Commodore 64.lpl
<playlists_dir>/Teletype Games - TIC-80.lpl
<thumbnails_dir>/Teletype Games - Commodore 64/Named_Boxarts/Blessing of Ra.png
/Named_Titles/… /Named_Snaps/…
<store_home>/config.json, state.json, catalog.json, store.log
content_root alapértéke <retroarch_dir>/content, a subfolder a store
azonosítója. A retroarch.cfg-hez soha nem nyúlunk — így a store nem tud
elrontani semmit, amit a felhasználó beállított.
Playlist platformonként, nem egyben. Nem esztétikai döntés: a
default_core_path/default_core_name a playlist fejlécében van, tehát csak
akkor tud minden bejegyzés magválasztás nélkül, egy kattintással indulni, ha egy
playlisten egy mag van. Egy összevont „Teletype Games" listánál minden elemnek
saját, gépspecifikus core_path-ot kellene adni — ami az exportnál (7. pont)
azonnal elromlik.
A név sablonból jön: {store} - {label} → Teletype Games - Commodore 64.
Ez egyben a db_name és a borítókép-könyvtár neve is, tehát a store nevével
elszigetelt névtérben vagyunk: nem írunk bele a hivatalos
Commodore - 64.lpl-be, és a hivatalos thumbnail-pakkokkal sem ütközünk.
Cserébe a saját playlist-nevünkhöz nincs ikon. A RetroArch a menü-ikont
assets/xmb/<téma>/png/<Playlist neve>.png alapján keresi (a mért gépen ott
vannak a Commodore - 64.png / Commodore - 64-content.png párok), tehát egy
TTG-ikont le tudnánk tenni — de az assets/ a RetroArch online updaterének
tulajdona, ami a következő frissítéskor felülírja. Opcionális, alapból ki
(branding.icons: false), és a README mondja ki, hogy nem tartós.
CLI, a Batocera-store-ral azonos alakban:
retroarch-store list # kompatibilis címek; * telepítve, ^ frissítés van
retroarch-store sync # letöltés + playlist + borító
retroarch-store sync impostor
retroarch-store -n sync # dry run
retroarch-store remove c64:blessingofra
retroarch-store export <dir> --target-prefix <út> # 7. pont
retroarch-store config
4. A playlist, amit írunk
Konkrétan, valódi adatokkal (a fenti CRC-k mértek):
{
"version": "1.5",
"default_core_path": "/Users/tasi/Library/Application Support/RetroArch/cores/vice_x64_libretro.dylib",
"default_core_name": "VICE x64",
"label_display_mode": 0,
"right_thumbnail_mode": 0,
"left_thumbnail_mode": 0,
"thumbnail_match_mode": 0,
"sort_mode": 0,
"items": [
{
"path": "/Users/tasi/Library/Application Support/RetroArch/content/teletypegames/c64/blessingofra-2.0.0.prg",
"entry_slot": -1,
"label": "Blessing of Ra",
"core_path": "DETECT",
"core_name": "DETECT",
"crc32": "4253CFC6|crc",
"db_name": "Teletype Games - Commodore 64.lpl"
}
]
}
label= a katalógustitle-je, mert ez a megjelenő név és a borítókép-fájlnév egyszerre.core_path/core_namea tételekbenDETECT: a fejléc alapmagja dönt. Így egy playlist-fájl akkor is használható marad, ha a magok máshol vannak — a legrosszabb eset egy magválasztó kérdés, nem egy halott bejegyzés.db_namea saját fájlnevünk, ezen keresztül találja meg a borítót.- A
*_thumbnail_modeéslabel_display_modemarad0= a felhasználó globális beállítása érvényes. Nem írjuk felül a preferenciáit (lásd 6. pont).
5. Mag-feloldás
A configban a mag fájlneve suffix nélkül és a megjelenő neve áll:
"core": { "file": "vice_x64_libretro", "name": "VICE x64" }
A motor a suffixet a célgépből teszi hozzá — darwin → .dylib, linux →
.so, windows → .dll, android → _android.so —, majd megnézi, hogy a
fájl létezik-e a libretro_directory-ban:
- létezik → a playlist fejlécébe absztolút útként bekerül, a
namemellé; - nem létezik →
default_core_pathüres marad,default_core_nameaname, a tételekDETECT-en. A playlist működik, a RetroArch az első indításnál kérdez. Alist/synckiírja:magot nem találtam: vice_x64_libretro (.dylib) — DETECT, és mellé az egy soros megoldást: Online Updater ▸ Core Downloader ▸ VICE x64.
Ez a legfontosabb ergonómiai döntés: a hiányzó mag nem hiba, hanem figyelmeztetés. Egy store, ami magtelepítést követel meg, nem fog lefutni senkinek elsőre.
6. Borítókép
Egy letöltés, három hely. A thumbnail_kinds alapból mindhárom Named_*
könyvtár, mert a felhasználó globális beállítása dönti el, melyiket kéri
(bal/jobb panel), és mi nem akarjuk átírni a beállítását. Három 100 KB-os fájl
6 játéknál semmi; ahol a fájlrendszer engedi, hardlink, egyébként másolat.
A PNG-kényszer valódi problémát is jelent. A katalógus képei ma:
| Formátum | Címek |
|---|---|
image/png |
bombexpert, mranderson, rabbitc64, c64demo, blessingofra (+ nem-cartridge: rabbitroller, trickster-tiles) |
image/gif |
impostor |
A RetroArch PNG-t (és JPEG/TGA/BMP-t) tud, GIF-et nem, a fájlnevet pedig .png-re
képezi. Az impostor borítója tehát ma nem jelenne meg. A /api/image/:id
send_file-lal az eredetit adja vissza, átkódolás nélkül — a szerver nem segít.
A motor sorrendje:
- magic bytes alapján PNG? → kiírjuk, kész.
- nem PNG, és van külső átkódoló? →
sips(macOS gyári),magick/convert(ImageMagick),ffmpeg— az első elérhető nyer. - semmi? → figyelmeztetés, a bejegyzés borító nélkül is jó.
Stdlib-only megkötéssel Pythonból nem kódolunk át (GIF-dekóder kellene) — és nem
is kellene. A helyes javítás felfelé van: a warp_engine imageUrl-je
adhatna PNG-változatot (vagy a feltöltés normalizálhatna). Egy sor a
MORE_STORES.md-be: ez a store az első fogyasztó, aminek a kép formátuma is
számít, nem csak a léte.
7. Út-átírás: a motor egyetlen valódi új képessége
A .lpl absztolút utakat tartalmaz a célgépen. Amíg a store ott fut, ahol a
RetroArch, ez nem kérdés. Csak épp a legérdekesebb célpont, az Android, nem tud
Pythont futtatni — ott a store nem tud „ott" futni.
A megoldás egy kettéválasztás, ami minden esetet lefed:
| hova írunk | mi kerül a playlistbe | |
|---|---|---|
stage_root |
valódi fájlműveletek helye | — |
target_prefix |
— | ezzel az előtaggal az útvonalak |
Alapból a kettő ugyanaz (helyi telepítés). Ha eltér, egy „idegen gépre szánt" RetroArch-alakú fát írunk:
# 1. Android, adb-vel
retroarch-store export /tmp/ra-ttg \
--target-prefix /storage/emulated/0/RetroArch \
--core-suffix _android.so
adb push /tmp/ra-ttg/. /storage/emulated/0/RetroArch/
# 2. SD-kártya: a Mac-en /Volumes/SDCARD, a kézikonzolon /mnt/sdcard
retroarch-store export /Volumes/SDCARD/RetroArch --target-prefix /mnt/sdcard/RetroArch
Ugyanez a mechanizmus adja a Steam Deck flatpak-elrendezését
(~/.var/app/org.libretro.RetroArch/config/retroarch) is, ott viszont
target_prefix nélkül, mert helyben fut.
Az Android útvonalait nem égetjük be: az export --android (2. fázis) az
adb shell cat /storage/emulated/0/RetroArch/retroarch.cfg-ből olvassa ki a
készülék saját könyvtárait, ugyanazzal a parserrel, amivel helyben. A fenti
/storage/emulated/0/RetroArch csak a tartalék tipp — és ez az egyik pont, amit
valódi készüléken meg kell mérni (12. pont).
8. Tulajdonlás, prune, állapot
Ez a store a három közül a legtisztább: minden, amit ír, a nevét viseli.
- Tartalom: csak
<content_root>/<subfolder>/alatt törlünk, soha kívül. - Playlist: a fájl a miénk, de a merge mégis megőrző — újraírás előtt
kiválogatjuk azokat a tételeket, amiknek a
path-ja nem a mi tartalmi könyvtárunkban van, és visszaírjuk őket (ha a felhasználó kézzel vett fel valamit a listánkba, nem tűnik el). Ha a végén nulla tétel marad, a fájlt töröljük, nem hagyunk üres listát a menüben. - Borító:
<thumbnails_dir>/<playlist neve>/Named_*/<label>.png, prune-nál mind a három példány megy. - Állapot:
state.json,<platform>:<name>kulccsal (itt nincs „system", a platform az). Külön store, külön fájl — a Batocera v2 állapotával nincs migrációs viszony. - A verzióváltás (
1.0→2.0.0) a régi fájlt előbb törli, mint ahogy az újat hozza, ahogy ma is.
A label fájlnévvé alakításánál a RetroArch a &*/: ` <>?\|
karaktereket _-ra cseréli; a sanitizert ugyanígy írjuk meg. A mai hat címben
egyik sem szerepel (az Mr Anderson's Adventure aposztrófja nincs a listán),
tehát ez ma elméleti — de egy jövőbeli Foo: Bar cím néma borítóhiba lenne.
9. Verseny a futó RetroArch-csal
Ugyanaz a csapda, mint az EmulationStation gamelistjeivel: a RetroArch a playlisteket memóriában tartja, és visszaírja őket, ha módosultak (kedvencek, utolsó játék, rendezés). Ha futás közben írunk, a kilépése eltörölheti a munkánkat.
Batocerán ezt a sync-from-es + apply-gamelists --wait-pid páros oldja meg, de
ott van egy Ports-menü, ami elindít minket. Itt nincs: a RetroArch nem tud
szkriptet futtatni, tehát a store gazdagépen belüli indítója nem létezik. Ezért
a döntés egyszerűbb és szigorúbb:
behavior.refuse_while_running: true(alapérték) — ha fut RetroArch process, asyncnem ír, hanem kiírja, hogy zárjuk be.--forcefelülbírálja.- A
syncután az új playlistek a RetroArch újraindítása után látszanak; a menü a listát indulásnál építi. Ezt a README első bekezdésében kell kimondani, különben „nem működik" lesz a tapasztalat. - Indítás: shell, illetve ütemezve (
cron,systemd --usertimer, launchd, Task Scheduler). Ez a store-nak nincs in-app belépője, és ezt nem érdemes szépíteni.
10. A store configja
ttg-retroarch-store/config.json teljes egészében:
{
"store": {
"id": "ttg",
"name": "Teletype Games",
"base_url": "https://teletypegames.org",
"api": { "catalog": "/api/software", "download": "/api/download" }
},
"paths": {
"retroarch_dir": null,
"playlists_dir": null,
"thumbnails_dir": null,
"libretro_dir": null,
"content_root": null,
"subfolder": "teletypegames",
"target_prefix": null
},
"playlist": {
"name_template": "{store} - {label}",
"write_crc32": true,
"thumbnail_kinds": ["Named_Boxarts", "Named_Titles", "Named_Snaps"]
},
"catalog": {
"statuses": ["released", "archived"],
"owner_id": null,
"only": [],
"exclude": []
},
"platforms": {
"c64": {
"label": "Commodore 64",
"kind": "cartridge",
"ext": ".prg",
"core": { "file": "vice_x64_libretro", "name": "VICE x64" },
"enabled": true
},
"tic80": {
"label": "TIC-80",
"kind": "cartridge",
"ext": ".tic",
"core": { "file": "tic80_libretro", "name": "TIC-80" },
"enabled": true
}
},
"behavior": {
"prune": true,
"timeout": 30,
"insecure": false,
"refuse_while_running": true,
"convert_images": true
},
"branding": { "icons": false }
}
A null útvonalak mindenütt azt jelentik: derítsd ki — env (RETROARCH_DIR),
majd retroarch.cfg, majd OS-enkénti tipplista. A config alparancs kiírja,
mire jutott, ahogy a Batocera-store a detected_arch-ot:
detected: os=darwin arch=aarch64 core_suffix=.dylib
retroarch_dir ~/Library/Application Support/RetroArch (candidate)
playlists_dir ~/Documents/RetroArch/playlists (retroarch.cfg)
libretro_dir ~/Library/Application Support/RetroArch/cores (retroarch.cfg)
cores vice_x64_libretro ✗ tic80_libretro ✗ → DETECT
11. A közös rész: mit mikor emeljünk ki
A MORE_STORES.md helyesen mondja, hogy a katalógus-lekérés, kiadásválasztás,
state.json, borító és prune-védelem közös. A most kézenfekvő lépés mégis nem
az azonnali kiemelés.
1. fázis — a RetroArch-motor önálló, egyfájlos, és igen, duplikál.
A retroarch_store.py átveszi a HTTP/katalógus/állapot réteget (~250 sor). Ok:
egyetlen minta alapján kiemelt absztrakció rossz absztrakció, és a Batocera-store
élesben fut — nem az a pillanat, hogy alatta cseréljünk réteget, amikor még
azt sem tudjuk, mit tanul a második adapter. A telepítés is egyszerűbb marad:
egy curl egy fájlra.
2. fázis — kiemelés, amikor két adapter már megmondja, mi közös.
Amit ma is látok jelöltnek: http_get/http_download, fetch_catalog +
gyorsítótár, pick_release, a config-merge, a state.json séma és az
atomikus írás. Ezek egy warpstore_core.py-ba mennek, mindkét installer két
fájlt tölt le. Amit a RetroArch már most tanított, és a közös részbe tartozik:
- a
resolve_for_archáltalánosítása: a Batocerán csak az architektúra volt a változó, itt az operációs rendszer is (mag-suffix). Egyresolve_for_host, amix86_64/aarch64/linux/darwin/windows/android/*kulcsokat is fogad, mindkettőt kiszolgálja; - a
stage_root/target_prefixkettősség (7. pont). Ez nem RetroArch-specifikus: az asztali store (MORE_STORES.md2.) és a kézikonzolos ES-disztrók ugyanígy „innen írok, ott fog futni" helyzetben vannak.
12. Munka és ellenőrzés
Becslés, a Batocera-motor mérete alapján (store.py 1073 sor):
| Rész | Új sor (kb.) |
|---|---|
| átvett réteg (HTTP, katalógus, állapot, config) | 250 |
retroarch.cfg parser + útvonal-felderítés |
90 |
playlist írás/merge (.lpl) |
120 |
| mag-feloldás | 60 |
| borító 3 könyvtárba + átkódolás | 80 |
| export / út-átírás | 70 |
| CLI, logolás | 90 |
| összesen | ~760 |
Plusz install.sh (a Batocera-inak asztali változata: ~/.local/share-be, nem
/userdata-ba) és két README.
Amit valódi gépen meg kell mérni — ez a lista a terv gyenge pontjai, nem formalitás:
- A két mag valóban elindítja-e a fájljainkat. Ez a store létjogosultsága.
Nem drága ellenőrizni:
Külön kérdés a
# magok a scratchpadbe, nem a felhasználó RetroArch-jába curl -fsSLO https://buildbot.libretro.com/nightly/apple/osx/arm64/latest/vice_x64_libretro.dylib.zip curl -fsSLO https://buildbot.libretro.com/nightly/apple/osx/arm64/latest/tic80_libretro.dylib.zip unzip -o '*.zip' retroarch -L ./vice_x64_libretro.dylib ./blessingofra-2.0.0.prg retroarch -L ./tic80_libretro.dylib ./impostor-1.0.tic.prgautostartja: a VICE-mag betölti, de futtatja-e magától, vagyRUN-ra vár. Ha vár, kell egy magopció (vice_autostart) vagy.d64-be csomagolás — ez a terv legvalószínűbb sérülési pontja. - A generált playlist megjelenik-e, a saját nevével, és a borító előjön-e a
Named_*könyvtárakból, a felhasználó globális thumbnail-beállításával. - Az Android útvonalai (
playlist_directory,libretro_directorya készülék cfg-jében) és hogy azadb push-olt tartalom olvasható-e a RetroArch-nak scoped storage mellett. - A visszaírás-verseny valódi mérete: mennyit ír vissza a RetroArch a
playlistünkből kilépéskor, elég-e a
refuse_while_running. - A
label→ borító-fájlnév sanitizálás pontos karakterkészlete (a fenti lista következtetés, nem mérés) — egyFoo: Barcímmel kipróbálva kiderül.
Javasolt sorrend
- Az 1. ellenőrzési pont (magok + a két fájltípus indítása) — mielőtt kód íródna. Egy órányi munka, és megválaszolja, hogy a store egyáltalán működhet-e.
warp-engine-retroarch-store: cfg-parser +list+synca helyi telepítéssel, macOS-en és Linuxon.ttg-retroarch-storeconfig, a fenti tartalommal.- Export/út-átírás + Android próba valódi készüléken.
- Kiemelés
warpstore_core.py-ba (11. pont, 2. fázis), és azimageUrlPNG-normalizálása awarp_engine-ben (6. pont).
Amit a megvalósítás megváltoztatott
(2026-08-17, a fenti terv leírása után.)
A közös rész azonnal kiemelve. A 11. pont fázisolását felülírtuk: a
warpstore.py a saját repójában (engines/warpstore) született meg, és a
Batocera-motor ugyanabban a körben átült rá — 1073 sorból 426 eltűnt, 115
jött vissza. A tools/ alá nem került, mert az org-definíció szerint az
engines/ a „saját motor és könyvtár, amitől más repók függnek", és ez pontosan
az. Mindkét telepítő két fájlt tölt le, a warpstore.py-t a saját repójából;
egyik sem pin-el verziót, tehát egy magbeli javítás a következő telepítéssel
mindkét store-hoz megérkezik.
Az élesben futó Batocera-store miatt az átültetés visszamérve: a cartridge-út, a
Ports-út, a borító, a gamelist-merge, az idempotens újraszinkron, a prune és az
eltávolítás ugyanazt adja, mint előtte. A régi state.json (rekordokban system,
scope nélkül) ugyanúgy kulcsolódik, tehát a frissítés után az első szinkron
nem tölt le és nem prune-ol semmit — ezt szándékosan a record_scope()
tartaléka adja, nem migráció.
Két általánosítás, amit a második adapter kényszerített ki:
resolve_for_arch→resolve_for_host. A Batocerán csak az architektúra volt a változó; a RetroArch-nál az OS is (.dll/.dylib/_android.so). A kulcssorrendos-arch,arch,os,*.- Az állapot
scopeszerint kulcsolódik, nem ES-systemszerint. A RetroArch-nál a scope a platform, nem a playlist neve — így a store átnevezése nem kulcsolja újra a telepítést.
Amit a terven felül kapott a motor: paths alparancs. A négy útvonal
felderítése annyira nem magától értetődő (lásd az (a) pontot), hogy önmagában
megérdemel egy kimenetet, ami azt is megmutatja, melyik válasz honnan jött —
config, retroarch.cfg, vagy tartalék. Ezt írja ki a telepítő is.
Ami az 5. pontból pontosításra került: a hiányzó mag nem csak „figyelmeztetés", hanem konkrét lépés is a kimenetben (Online Updater ▸ Core Downloader ▸ VICE x64).
Amit végigmértünk: letöltés, playlist, borító (a GIF sips-szel PNG-vé
konvertálva), idegen playlist-bejegyzés megőrzése, mag-felismerés, prune,
eltávolítás, üres playlist törlése, Android-export _android.so-val és POSIX
célútvonalakkal, végül teljes telepítés a forge-ról curl | bash-sal. A CRC32-k
egyeznek a doksi 1. pontjában független módszerrel mért értékekkel.
Ami továbbra is nyitott, változatlanul: a VICE .prg-autostart és az Android
adb push scoped storage kérdése. Ezt kód nem tudja megválaszolni.