|
Some checks failed
Build plugin / build (push) Failing after 10s
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. |
||
|---|---|---|
| .forgejo/workflows | ||
| assets | ||
| core | ||
| .gitignore | ||
| export_presets.cfg | ||
| LICENSE | ||
| Makefile | ||
| plugin.gd | ||
| plugin.json | ||
| README.md | ||
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
- Build and install the plugin (see below).
- Generate an API key at https://itch.io/user/settings/api-keys.
- 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
Launchcall is the "correct" way to start a game (it handles prerequisites, manifest actions, sandboxing, etc.), but OpenGamepadUI's library items launch via a plaincommand+argsOS exec, not an RPC call. This plugin currently side-steps that by scanning each installed game's folder for an executable file and pointingcommanddirectly 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.gzin the install folder would give the authoritative answer. - Field names. The JSON-RPC field names used in
itch_client.gdfollow 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 yourbutler's actual behavior (run with--logto 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
Controlnodes 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 returnsfalse— wiring upCheckUpdate(and periodic background polling) is a natural next step.- No progress→UI wiring.
install_progressedis re-emitted from raw butlerd notifications but not yet mapped back to aLibraryLaunchItemthroughLibraryManager(see the TODO inlibrary_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