EN /HU | Login

TTG Batocera Store

ttg-batocera-store puts our catalog on Batocera. It pulls games from the WarpEngine catalog on https://teletypegames.org onto the box, writes EmulationStation metadata and box art, and gives the store its own menu entryTeletype Games — from which it can be re-run for new releases.

This repository is only the store definition: a config.json and two wrapper scripts. The logic is in the shared engine, warp-engine-batocera-store — this is the Teletype Games configuration of it.

For RetroArch instead of a Batocera box — desktop, Android, Steam Deck, handheld — use the TTG RetroArch Store.

What you get

  • Its own menu entryTeletype Games in the main carousel, with a folder per platform inside it and an Update Teletype Games entry that downloads everything new in one click.
  • CLI over SSHlist, sync, remove, config, with dry-run, per-title sync and overrides.
  • Your library is left alone — the games live in /userdata/roms/teletypegames/, not in the box's own systems, so nothing of yours can be touched by a sync or a prune. Favourites and play counts on our games survive a rewrite.
  • Box art and metadata — title, description, author and image are merged into gamelist.xml, so the games look scraped.
  • Zero dependencies — Python 3 standard library only.
  • Idempotent syncs — existing files are left alone, a release bump replaces the old asset, and downloads go through /api/download so they count in the statistics.

Overview

TXT
Teletype Games ▸ "Update Teletype Games"
        ├─ GET /api/software                        the whole catalog
        ├─ keep platforms this box can run          c64 → c64, tic80 → tic80
        ├─ pick the newest non-dev release          that carries the right asset
        ├─ GET /api/download?path=<asset>           .prg / .tic into the store's folder
        ├─ GET <software.imageUrl>                  box art
        ├─ write gamelist.xml                       title, desc, author, image
        └─ write es_systems_ttg.cfg                 the menu entry

Repository: https://git.teletypegames.org/stores/ttg-batocera-store Engine: warp-engine-batocera-store RetroArch equivalent: TTG RetroArch Store Batocera: https://batocera.org Catalog side: WarpEngine (libs/ruby/warp_engine in the teletypegames repo)


Install

Over SSH on the Batocera box:

SH
curl -fsSL https://git.teletypegames.org/stores/ttg-batocera-store/raw/branch/master/install.sh | sh

Or from a checkout:

SH
scp -r ttg-batocera-store root@batocera:/tmp/
ssh root@batocera /tmp/ttg-batocera-store/install.sh

The installer fetches the engine, puts it and this config in /userdata/system/batocera-store/ttg/, writes the ttg-store launcher, and runs the first sync — which downloads the games and writes the menu entry. Restart EmulationStation to see it:

SH
batocera-es-swissknife --restart

Re-running the installer is the upgrade path: it refreshes the engine and the config (keeping the old one as config.json.bak) and leaves state.json alone.

Coming from a pre-4.0 install, that first sync also changes the layout: the games move out of c64/teletypegames/, tic80/teletypegames/ and ports/teletypegames/ into /userdata/roms/teletypegames/, and the old Ports ▸ Teletype Games Store entry goes away — the updater is inside the menu entry now. The move is a removal plus a fresh download rather than a file shuffle, which for today's catalog is minutes. Your gamelists are rewritten without our nodes, never deleted, and the gamelist.xml.ttg-backup copies are listed and left alone. -n sync shows all of it first; emulationstation.menu.mode: "merge" in config.json keeps the old layout.


Use

On the device. Teletype Games ▸ "Update Teletype Games". It downloads anything new, then restarts EmulationStation. A script launched by ES gets no console, so the output goes to /userdata/system/batocera-store/ttg/store.log.

TXT
main carousel:  …  ▸  Teletype Games  ▸  ┌ Commodore 64
                                         ├ TIC-80
                                         ├ Ports                    the native builds
                                         └ Update Teletype Games    the sync

The entry carries our own TTG logo, shipped in the store repository (logo.png, plus a vector logo.svg for themes that only look for an SVG) and installed by the engine into the logo folder of every theme on the box. A theme it cannot reach shows TELETYPE GAMES as text instead. Themes that came with the Batocera image live on the read-only system, so their copy is in the RAM overlay and goes after a reboot — the next update puts it back, batocera-save-overlay makes it permanent.

Only the platforms that have something installed show up, and 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. How that is put together is on the engine page.

Over SSH, through the launcher:

SH
S=/userdata/system/batocera-store/ttg-store

$S list                 # compatible catalog entries; * installed, ^ update available
$S sync                 # download everything new, refresh gamelists and the menu
$S sync blessingofra    # just one title (never prunes)
$S -n sync              # dry run
$S remove c64demo       # uninstall (c64:c64demo works too)
$S config               # effective configuration, and where the menu entry lives

Global flags go before the subcommand: $S --roms-root /tmp/roms sync.

Flag Meaning
--config <path> store config file (default /userdata/system/batocera-store/ttg/config.json)
--base-url <url> override the catalog base URL
--roms-root <path> override the ROMs root
-n, --dry-run report actions, change nothing
-v, --verbose verbose logging
--version print version

Two subcommands are for the machine, not the user: sync-from-es is what the menu entry calls, and apply-gamelists --wait-pid <pid> is the detached child it spawns.


Where things land

TXT
/userdata/system/batocera-store/
├── ttg-store                            launcher
└── ttg/
    ├── store.py, warpstore.py           the engine and its shared core
    ├── config.json                      the store that selected it
    └── state.json, catalog.json, store.log

/userdata/system/configs/emulationstation/es_systems_ttg.cfg   the menu entry

/userdata/roms/teletypegames/            the store's own ROM folder
├── c64/
│   ├── blessingofra-2.0.0.prg, rabbit-1.0.0.prg, …
│   ├── images/blessingofra.png, …
│   └── gamelist.xml
├── tic80/  …
├── ports/
│   ├── rabbitroller.sh, images/rabbitroller.png
│   ├── .data/rabbitroller/              the unpacked program
│   └── gamelist.xml
└── store/                               the menu entry itself
    ├── update.sh                        the sync, as the menu starts it
    └── gamelist.xml

The box's own system folders are not touched at all: a prune cannot reach your ROMs because they are not in the same tree, and inside our folder only what state.json records is ever deleted — a ROM you drop in there yourself keeps its file and its gamelist entry.


Configuration

/userdata/system/batocera-store/ttg/config.json, shipped by this repository:

JSON
{
  "store": {
    "id": "ttg",
    "name": "Teletype Games",
    "base_url": "https://teletypegames.org",
    "api": { "catalog": "/api/software", "download": "/api/download" }
  },
  "paths": { "roms_root": "/userdata/roms", "subfolder": "teletypegames" },
  "emulationstation": { "menu": { "mode": "system", "theme": "ports", "updater": true }, "restart": true },
  "catalog": { "statuses": ["released", "archived"], "owner_id": null, "only": [], "exclude": [] },
  "platforms": {
    "c64": { "system": "c64", "kind": "cartridge", "ext": ".prg", "enabled": true },
    "tic80": { "system": "tic80", "kind": "cartridge", "ext": ".tic", "enabled": true }
  },
  "behavior": { "prune": true, "timeout": 30, "insecure": false }
}

The full key reference is on the engine page. Edits on the box survive until the next install, which keeps the old file as config.json.bak. Anything permanent belongs in the repository.

Platform mapping

A platform is installable when its release asset is a file a system this box has can boot directly — "has" meaning declared in the box's own es_systems.cfg, which is an emulator that got built into this image:

Catalog platform Asset kind Batocera system Extension
c64 cartridge c64 (VICE) .prg
tic80 cartridge tic80 .tic

ebitengine, bevy, godot and love ship native Linux builds, and are installed the way Batocera's Ports system does it — a .sh launcher next to the unpacked program, under Teletype Games ▸ Ports. phaser ships only a web build, so it is not mapped. Adding a mapping is a config edit:

JSON
"platforms": { "godot": { "system": "godot", "kind": "linux_x64", "ext": ".zip", "enabled": true } }

A platform is skipped when the box does not have its system; list reports skipped <name>: this box has no '<system>' system.


Uninstall

SH
curl -fsSL https://git.teletypegames.org/stores/ttg-batocera-store/raw/branch/master/uninstall.sh | sh

It removes the games (including any unpacked port payload), our gamelists, the menu entry, the launcher and the store home, then restarts EmulationStation. DRY_RUN=1 shows what would go; KEEP_HOME=1 keeps state.json and the log for a reinstall.

Nothing of yours goes with it: everything the store installed is in one folder of its own, so an uninstall leaves the box exactly as it was. On a box that still uses the old layout, your gamelists are rewritten without our nodes rather than deleted, so play counts and favourites survive, and the gamelist.xml.ttg-backup copies are listed and left alone.


Troubleshooting

Symptom What to check
Nothing appears after an update /userdata/system/batocera-store/ttg/store.log, then batocera-es-swissknife --restart
skipped <name>: this box has no '<system>' system that emulator is not in this Batocera image
The Teletype Games entry is missing the sync writes /userdata/system/configs/emulationstation/es_systems_ttg.cfg; check the log, then restart ES
TLS errors against a test instance set behavior.insecure to true in config.json
A title should never be installed add its catalog name to catalog.exclude in config.json
Gamelist looks wrong ours is at /userdata/roms/teletypegames/<system>/gamelist.xml; a pre-4.0 original is at <system>/gamelist.xml.ttg-backup
Games vanished after a sync a missing ROMs mount aborts the sync by design; check /userdata/roms is mounted