90 lines
4.3 KiB
Markdown
90 lines
4.3 KiB
Markdown
|
|
# OpenGamepadUI-itch
|
||
|
|
|
||
|
|
An itch.io library plugin for [OpenGamepadUI](https://github.com/ShadowBlip/OpenGamepadUI),
|
||
|
|
built against itch's official [butlerd](https://itch.io/docs/butler/launcher-integration.html)
|
||
|
|
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](https://broth.itch.zone/) 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](https://itch.io/docs/butler/launcher-integration.html).
|
||
|
|
|
||
|
|
## Requirements
|
||
|
|
|
||
|
|
See the [OpenGamepadUI requirements](https://github.com/ShadowBlip/OpenGamepadUI#requirements).
|
||
|
|
This plugin additionally needs `unzip` on the host (used to unpack the
|
||
|
|
downloaded `butler` binary).
|
||
|
|
|
||
|
|
## Building
|
||
|
|
|
||
|
|
Same as any other OpenGamepadUI plugin:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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](https://pkg.go.dev/github.com/itchio/butler/butlerd)
|
||
|
|
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
|
||
|
|
```
|