Move to the store's own EmulationStation menu entry

Engine 4.0 gives a store its own carousel entry instead of scattering the
games across the box's systems, so this config switches to it: the games
land in /userdata/roms/teletypegames/ with a folder per platform, and the
sync is started from *Teletype Games -> Store -> "Update Teletype Games"*.

That makes the Ports entry redundant, so the installer stops asking for
one — the engine takes the old *Ports -> Teletype Games Store* script away
on the first sync after the upgrade, along with the old ROM folders. The
games are downloaded again into the new place rather than moved; today's
catalog is six cartridges and one native build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-23 12:57:45 +02:00
co-authored by Claude Opus 5
parent 5062e0da63
commit 049f09d0c0
3 changed files with 91 additions and 49 deletions
+79 -42
View File
@@ -1,8 +1,9 @@
# ttg-batocera-store — the Teletype Games store for Batocera # ttg-batocera-store — the Teletype Games store for Batocera
Puts the <https://teletypegames.org> catalog into a Batocera box's ROM folders, Puts the <https://teletypegames.org> catalog on a Batocera box, with
with EmulationStation metadata and box art. Triggered from the **Ports** menu on EmulationStation metadata and box art, under **its own menu entry**: *Teletype
the device, or from the CLI over SSH. Games*, next to the box's own systems. Started from there on the device, or from
the CLI over SSH.
This repository is only the store definition — `config.json` plus the two wrapper This repository is only the store definition — `config.json` plus the two wrapper
scripts. All the logic lives in the shared engine, scripts. All the logic lives in the shared engine,
@@ -30,15 +31,29 @@ ssh root@batocera /tmp/ttg-batocera-store/install.sh
``` ```
The installer fetches the engine, drops it and this config in The installer fetches the engine, drops it and this config in
`/userdata/system/batocera-store/ttg/`, writes the `ttg-store` launcher and the `/userdata/system/batocera-store/ttg/`, writes the `ttg-store` launcher, and runs
*Teletype Games Store* Ports entry, and runs the first sync. Restart the first sync — which downloads the games and writes the menu entry. Restart
EmulationStation (`batocera-es-swissknife --restart`) to see the games. EmulationStation (`batocera-es-swissknife --restart`) to see it.
## Use ## Use
**On the device.** *Ports ▸ Teletype Games Store*. It downloads anything new, **On the device.** *Teletype Games Store ▸ "Update Teletype Games"*. It
then restarts EmulationStation. Ports scripts get no console in Batocera, so the downloads anything new, then restarts EmulationStation. ES gives a launched
output goes to `/userdata/system/batocera-store/ttg/store.log`. script no console, so the output goes to
`/userdata/system/batocera-store/ttg/store.log`.
```
main carousel: … ▸ Teletype Games ▸ ┌ Commodore 64
├ TIC-80
├ Ports the native builds
└ Store → "Update Teletype Games"
```
Only the platforms that have something installed show up as folders, so the entry
never has a dead end in it. The games are launched exactly as the box would
launch them — the engine copies the launch command and the emulator list off the
box's own `c64`, `tic80` and `ports` systems, so whatever you configured for the
C64 applies to our C64 games too.
**Over SSH.** **Over SSH.**
@@ -46,15 +61,33 @@ output goes to `/userdata/system/batocera-store/ttg/store.log`.
S=/userdata/system/batocera-store/ttg-store S=/userdata/system/batocera-store/ttg-store
$S list # compatible catalog entries; * installed, ^ update available $S list # compatible catalog entries; * installed, ^ update available
$S sync # download everything new, refresh gamelists $S sync # download everything new, refresh gamelists and the menu
$S sync blessingofra # just one title (never prunes) $S sync blessingofra # just one title (never prunes)
$S -n sync # dry run $S -n sync # dry run
$S remove c64demo # uninstall $S remove c64demo # uninstall
$S config # effective configuration $S config # effective configuration, and where the menu entry lives
``` ```
Global flags go before the subcommand: `$S --roms-root /tmp/roms sync`. Global flags go before the subcommand: `$S --roms-root /tmp/roms sync`.
## Upgrading from a pre-4.0 install
Older versions installed into the box's own systems — `c64/teletypegames/`,
`tic80/teletypegames/`, `ports/teletypegames/` — and ran the sync from *Ports ▸
Teletype Games Store*. The first sync after the upgrade moves all of that into
`/userdata/roms/teletypegames/`, the store's own folder, by taking the old
install off the box and downloading again. It also removes the old Ports entry:
the updater now lives inside the menu entry.
Nothing of yours goes with it: our nodes come out of your gamelists and the rest
— your own games, their play counts and favourites — is written back untouched,
and the `gamelist.xml.ttg-backup` copies are listed and left alone. Today's
catalog is six cartridges and one native build, so the re-download is minutes.
`-n sync` shows the whole thing without doing any of it. To stay on the old
layout, set `emulationstation.menu.mode` to `merge` in
`/userdata/system/batocera-store/ttg/config.json` before syncing.
## Uninstall ## Uninstall
```sh ```sh
@@ -62,47 +95,43 @@ curl -fsSL https://git.teletypegames.org/stores/ttg-batocera-store/raw/branch/ma
``` ```
Or `/tmp/ttg-batocera-store/uninstall.sh` from a checkout on the box. It takes Or `/tmp/ttg-batocera-store/uninstall.sh` from a checkout on the box. It takes
out the games — including any unpacked Ports payload — our gamelist entries, the out the games — including any unpacked port payload — our gamelists, the menu
*Teletype Games* Ports entry, the launcher and the store home, and restarts entry, the launcher and the store home, and restarts EmulationStation.
EmulationStation.
```sh ```sh
DRY_RUN=1 ./uninstall.sh # show what would go, remove nothing DRY_RUN=1 ./uninstall.sh # show what would go, remove nothing
KEEP_HOME=1 ./uninstall.sh # keep state.json and the log, for a reinstall KEEP_HOME=1 ./uninstall.sh # keep state.json and the log, for a reinstall
``` ```
Nothing of yours goes with it: your own ROMs keep their folders, and your Since everything the store installs lives in one folder of its own, an uninstall
gamelists are rewritten without our nodes rather than deleted — play counts and leaves the box exactly as it was: your own ROM folders are never touched.
favourites survive. The `gamelist.xml.ttg-backup` copies are listed and left
alone.
## What this store installs ## What this store installs
Cartridges go to their emulator's ROM folder, native builds to **Ports**: Cartridges go to the folder of the system that boots them, native builds to a
`ports` folder — all of them inside the store's own tree:
| Catalog platform | Asset kind | Batocera system | Extension | | Catalog platform | Asset kind | Folder in the menu | Extension |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `c64` | `cartridge` | `c64` (VICE) | `.prg` | | `c64` | `cartridge` | Commodore 64 (VICE) | `.prg` |
| `tic80` | `cartridge` | `tic80` | `.tic` | | `tic80` | `cartridge` | TIC-80 | `.tic` |
| `ebitengine` | `linux_x64` / `linux_arm64` | `ports` | `.zip` | | `ebitengine` | `linux_x64` / `linux_arm64` | Ports | `.zip` |
| `bevy` | `linux_x64` / `linux_arm64` | `ports` | `.zip` | | `bevy` | `linux_x64` / `linux_arm64` | Ports | `.zip` |
| `godot` | `linux_x64` | `ports` | `.zip` | | `godot` | `linux_x64` | Ports | `.zip` |
| `love` | `linux_x64` | `ports` | `.zip` | | `love` | `linux_x64` | Ports | `.zip` |
Statuses `released` and `archived`, whole catalog, no owner filter. Everything Statuses `released` and `archived`, whole catalog, no owner filter. To change any
lands under the `teletypegames/` subfolder of each system, so a prune can never of it, edit `/userdata/system/batocera-store/ttg/config.json` on the box — the
reach ROMs you put there yourself. To change any of it, edit full key reference is in the engine's README.
`/userdata/system/batocera-store/ttg/config.json` on the box — the full key
reference is in the engine's README.
## Native games as Ports ## Native games as Ports
Cartridges are a little under half the catalog; the rest of our games are native Cartridges are a little under half the catalog; the rest of our games are native
Linux builds, and no emulator boots those. Batocera runs Linux, so they are Linux builds, and no emulator boots those. Batocera runs Linux, so they are
installed through its **Ports** system instead: the zip is unpacked under installed the way its **Ports** system does it: the zip is unpacked under
`ports/.data/teletypegames/`, and the launcher EmulationStation lists is `teletypegames/ports/.data/`, and the launcher EmulationStation lists is
`ports/teletypegames/<name>.sh`, which `cd`s into the program's directory before `teletypegames/ports/<name>.sh`, which `cd`s into the program's directory before
running it. They appear under *Ports ▸ Teletype Games*, and `remove` takes the running it. They appear under *Teletype Games ▸ Ports*, and `remove` takes the
unpacked program with it. unpacked program with it.
Each one is a 30100 MB download rather than the few kilobytes of a cartridge. Each one is a 30100 MB download rather than the few kilobytes of a cartridge.
@@ -138,12 +167,20 @@ native game that currently installs is `rabbitroller`. Add `"demo"` to
├── store.py, warpstore.py, config.json ├── store.py, warpstore.py, config.json
└── state.json, catalog.json, store.log └── state.json, catalog.json, store.log
/userdata/roms/c64/teletypegames/ blessingofra-2.0.0.prg, rabbit-1.0.0.prg, … /userdata/system/configs/emulationstation/es_systems_ttg.cfg the menu entry
/userdata/roms/c64/teletypegames/images/ blessingofra.png, …
/userdata/roms/c64/gamelist.xml our entries merged in
/userdata/roms/ports/Teletype Games Store.sh the store itself /userdata/roms/teletypegames/ the store's own ROM folder
/userdata/roms/ports/teletypegames/ rabbitroller.sh, … ├── c64/
/userdata/roms/ports/teletypegames/images/ rabbitroller.png, … │ ├── blessingofra-2.0.0.prg, rabbit-1.0.0.prg, …
/userdata/roms/ports/.data/teletypegames/ the unpacked programs │ ├── images/blessingofra.png, …
│ └── gamelist.xml
├── tic80/
│ └── …
├── ports/
│ ├── rabbitroller.sh, images/rabbitroller.png
│ ├── .data/rabbitroller/ the unpacked program
│ └── gamelist.xml
└── store/
├── update.sh the sync, as the menu starts it
└── gamelist.xml
``` ```
+5 -1
View File
@@ -15,7 +15,11 @@
}, },
"emulationstation": { "emulationstation": {
"folder_name": "Teletype Games", "menu": {
"mode": "system",
"theme": "ports",
"updater": true
},
"restart": true "restart": true
}, },
+7 -6
View File
@@ -25,14 +25,15 @@ else
fi fi
export STORE_CONFIG ENGINE_RAW_BASE export STORE_CONFIG ENGINE_RAW_BASE
# Keep the Ports entry the box already has, so an upgrade replaces it in place. # No Ports entry any more: the store has its own EmulationStation menu entry,
BATOCERA_PORT_NAME="${BATOCERA_PORT_NAME:-Teletype Games Store}" # with the updater inside it. The engine takes the old Ports entry away on the
export BATOCERA_PORT_NAME # first sync after the upgrade.
# --- migrate the pre-split ttg-store layout ------------------------------- # --- migrate the pre-split ttg-store layout -------------------------------
# Up to engine 1.x everything lived in /userdata/system/ttg-store. The ROMs # Up to engine 1.x everything lived in /userdata/system/ttg-store. Carrying
# themselves do not move (the subfolder is still `teletypegames`), so carrying # state.json across is what lets the engine recognise what is installed — from
# state.json across is enough to avoid a full re-download. # engine 4.0 on it uses that to take the old layout off the box before filling
# /userdata/roms/teletypegames, the store's own folder.
LEGACY_HOME="${LEGACY_STORE_HOME:-/userdata/system/ttg-store}" LEGACY_HOME="${LEGACY_STORE_HOME:-/userdata/system/ttg-store}"
NEW_HOME="${BATOCERA_STORE_ROOT:-/userdata/system/batocera-store}/ttg" NEW_HOME="${BATOCERA_STORE_ROOT:-/userdata/system/batocera-store}/ttg"