The Batocera store reaches one kind of machine. RetroArch reads the same
cartridges on desktop Linux, Windows and macOS, on Android, on the Steam
Deck and on the console ports — the same seven titles, a far larger
audience — so this writes RetroArch's own library format instead:
one .lpl playlist per platform, with box art in the thumbnail folders that
playlist's name points at.
Three things it does differently, each because RetroArch is not one
machine:
- It reads retroarch.cfg for its directories. On the macOS install this
was developed against, playlist_directory is ~/Documents/RetroArch/
playlists while cores and thumbnails are under ~/Library/Application
Support/RetroArch — an engine assuming <base>/playlists writes into the
void. The leading ':' of a portable install is expanded too.
- It can write for a machine it is not running on (`export`). Android runs
RetroArch but cannot run Python, so the only way to serve it is to
render the tree here and copy it over; the same mechanism handles an SD
card that will be mounted elsewhere.
- It refuses to write while RetroArch is running, because RetroArch holds
its playlists in memory and writes them back on exit. The Batocera
engine defers the write instead; here there is no Ports menu launching
us, so refusing is both simpler and safer.
Decisions worth recording. One playlist per platform, because
default_core_path is a header field — that is what makes every entry start
without a core prompt; the entries themselves stay on DETECT so the file
survives being moved to a machine whose cores live elsewhere. A missing
core is a note, not an error, or the store would never run for anyone the
first time. The playlist name carries the store's name, so we never write
into RetroArch's own Commodore - 64.lpl and never collide with the
official thumbnail packs — and an entry the user added to our playlist
survives a rewrite. Thumbnails must be PNG and one of our covers is a
GIF, so the engine shells out to sips/magick/convert/ffmpeg, and simply
goes without the image if the machine has none of them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>