No description
Find a file
Jose Falanga bbc9b248bb
Some checks failed
Build plugin / build (push) Failing after 10s
Fix install of bought games and launch of games with spaces in paths
Three bugs, all seen on Bubble Tower (itch.io game 4845491):

- Installs of bought games failed with "you must buy this game to download".
  butlerd only learns itch.io download keys from Fetch.ProfileOwnedKeys,
  which the library skips when "show_purchases" is off (the listing then
  comes from collections, so owned games still show up). butlerd queued
  the install without credentials and itch.io rejected the build request.
  Install.Queue is now retried once after a fresh owned-keys sync when
  itch.io answers with that error.

- The install-options upload dropdown never applied the user's pick: it
  offers "<name>  (<size>)" while _pick_upload compared against the bare
  displayName/filename, so every multi-upload game silently fell back to
  the default upload. The label format is now shared through
  UPLOAD_SIZE_SEPARATOR and the name prefix counts as a match.

- Games whose receipt carries no launch block were resolved by scanning
  for the largest executable and splitting "size path" on a space, which
  truncated the path of any file with a space in its name (Unity's
  "unity default resources") and pointed the launch at a file that does
  not exist. Sizes and paths are now tab-separated, and Unity's data
  files are skipped.
2026-10-15 11:25:05 -03:00
.forgejo/workflows Fix CI: remove upload-artifact (not supported on Forgejo) 2026-08-16 16:04:43 -03:00
assets Initial commit 2026-08-05 17:27:43 -03:00
core Fix install of bought games and launch of games with spaces in paths 2026-10-15 11:25:05 -03:00
.gitignore Enriched metadata, per-layout boxart, install failure UI, and modal focus fix (v0.1.31) 2026-08-16 15:33:36 -03:00
export_presets.cfg Initial commit 2026-08-05 17:27:43 -03:00
LICENSE Initial commit 2026-08-05 17:27:43 -03:00
Makefile Install games to persistent user://butler/games and reconcile orphaned caves 2026-08-07 22:48:17 -03:00
plugin.gd Replace cookie HTTP verification with butlerd's Profile.List + UseSavedLogin 2026-08-17 02:19:22 -03:00
plugin.json Fix install of bought games and launch of games with spaces in paths 2026-10-15 11:25:05 -03:00
README.md Initial commit 2026-08-05 17:27:43 -03:00

OpenGamepadUI-itch

An itch.io library plugin for OpenGamepadUI, built against itch's official butlerd JSON-RPC launcher daemon (the same integration path the official itch.io app uses under the hood) rather than screen-scraping the itch desktop app.

Owned games, install state, install/update/uninstall, and launching are all driven through butlerd. This plugin spawns butler daemon --json ... itself, so the itch.io desktop app doesn't need to be installed at all — only a butler binary, which this plugin downloads automatically on first run from itch's own broth distribution channel.

Setup

  1. Build and install the plugin (see below).
  2. Generate an API key at https://itch.io/user/settings/api-keys.
  3. Open the plugin's settings screen in OpenGamepadUI and paste it in.

API key login was chosen over the OAuth + PKCE flow butlerd also supports, because OAuth requires registering a redirect URI / custom URL scheme with itch.io for a specific app, which doesn't make sense for a self-built, unpublished plugin. If you're distributing this plugin publicly, switching to OAuth is worth doing — see Profile.LoginWithOAuthCode in the butlerd launcher guide.

Requirements

See the OpenGamepadUI requirements. This plugin additionally needs unzip on the host (used to unpack the downloaded butler binary).

Building

Same as any other OpenGamepadUI plugin:

make help
make build
make install

Known limitations / good next steps

This was put together from butlerd's public spec rather than against a running instance, so a few corners are simplifications rather than the "real" solution. If you pick this up:

  • Launch target discovery. butlerd's Launch call is the "correct" way to start a game (it handles prerequisites, manifest actions, sandboxing, etc.), but OpenGamepadUI's library items launch via a plain command + args OS exec, not an RPC call. This plugin currently side-steps that by scanning each installed game's folder for an executable file and pointing command directly at it (library_itch.gd::_find_executable). That works for straightforward native builds but skips prerequisite installation and manifest-declared launch actions. Parsing .itch/receipt.json.gz in the install folder would give the authoritative answer.
  • Field names. The JSON-RPC field names used in itch_client.gd follow butlerd's documented camelCase convention, cross-checked against the butlerd Go package docs for the calls that matter most (Install.Queue/Install.Perform, Uninstall.Perform). A couple of the less-central ones (Launch, Profile.LoginWithAPIKey, Fetch.ProfileOwnedKeys) were written from the documented naming convention rather than a byte-for-byte spec check — worth diffing against your butler's actual behavior (run with --log to see the raw JSON-RPC traffic) if a call comes back with an unexpected error shape.
  • Install location picker. _ensure_install_location() silently picks the first existing install location, or creates one under the plugin's own data directory. No UI for choosing/managing install locations yet.
  • Settings screen. Uses plain Godot Control nodes rather than OpenGamepadUI's themed widget set (the one the built-in Steam plugin's settings scene uses), since this was written without editor access to those theme resources.
  • has_update() always returns false — wiring up CheckUpdate (and periodic background polling) is a natural next step.
  • No progress→UI wiring. install_progressed is re-emitted from raw butlerd notifications but not yet mapped back to a LibraryLaunchItem through LibraryManager (see the TODO in library_itch.gd).

How it fits together

plugin.gd            entrypoint; wires client + library + settings menu
core/itch_client.gd   spawns butlerd, speaks JSON-RPC 2.0 over TCP to it
core/library_itch.gd  extends Library; turns butlerd data into LibraryLaunchItems
core/itch_settings.*  API key entry screen