feat(library/providers): let a provider say how to recognize its games
A plugin's titles launch through the provider's own client, which hands off and exits — so the host had nothing left to watch, and both lifetime behaviors went quiet for exactly the entries a provider contributes. A `ProviderEntry` (and a manual custom entry) may now carry an optional `detect` hint: install dir, exe, or process name. It is deliberately a subset of what the host tracks internally. A Steam appid or a launcher's environment marker are things the host discovers for itself and would be meaningless — or dangerous — to take on someone's word; where a title is installed is something only the provider knows. The host's own findings win where both exist, so a stale export can never redirect the matcher, and a blank field is treated as absent rather than as "match everything" — an empty install dir would otherwise prefix-match every process on the box, and this feature can end processes. `process_name` is the weakest of the three and the only one typed by hand, so it is matched case-insensitively against the image's file name and nothing else: `retroarch` finds RetroArch, not a helper whose name merely starts the same way, and not a script that happens to live in a `retroarch/` directory. The never-adopt-a-pre-existing-process rule still bounds it. Also: the tray summary gains the running-game row (with the closing-in countdown for a game whose client is gone — visible at the machine without opening the console), the SDK mirrors the `game.*` events, and its generated client catches up with the endpoints Phase 1 added. Gates on .21: check + clippy --all-targets clean, 299 tests, fmt CI-parity, openapi regenerated (GameEntry still carries no `detect` outbound); SDK tsc + 54 tests green.
This commit is contained in:
@@ -4022,6 +4022,10 @@
|
||||
"art": {
|
||||
"$ref": "#/components/schemas/Artwork"
|
||||
},
|
||||
"detect": {
|
||||
"$ref": "#/components/schemas/DetectHint",
|
||||
"description": "How to recognize this title's process once it is running (design §9) — the one thing a\nprovider knows that the host cannot work out for itself.\n\nOptional: without it the entry is still tracked by the child the host spawns for it, which\ncovers every command that stays in the foreground. It earns its keep for a command that hands\noff and exits — a launcher script, a `flatpak run`, a front-end that starts an emulator — where\nthe host would otherwise lose the game the moment the shim returns."
|
||||
},
|
||||
"external_id": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -4072,6 +4076,10 @@
|
||||
"art": {
|
||||
"$ref": "#/components/schemas/Artwork"
|
||||
},
|
||||
"detect": {
|
||||
"$ref": "#/components/schemas/DetectHint",
|
||||
"description": "How to recognize this title's process — see [`CustomEntry::detect`]."
|
||||
},
|
||||
"launch": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -4140,6 +4148,33 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"DetectHint": {
|
||||
"type": "object",
|
||||
"description": "What an operator (or a provider plugin) can tell the host about recognizing a title — the wire\nhalf of [`DetectSpec`], and the only part of it that is ever accepted from outside.\n\nDeliberately a **subset**: the store-derived signals (a Steam appid, a launcher's environment\nmarker) are things the host discovers for itself and would be meaningless — or dangerous — to take\non someone's word. What is left is what a provider genuinely knows and the host cannot guess: where\nthe title is installed, which executable is the game, what the process is called. All three are\noptional; supplying none is the same as supplying no hint at all.\n\nNever returned by the catalog API — see the module docs on why detect data does not cross the wire\noutbound.",
|
||||
"properties": {
|
||||
"exe": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "The game's own executable, as an absolute path."
|
||||
},
|
||||
"install_dir": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "Where the title is installed. Any process running from under this directory is part of the\ngame — the universal recipe, and the one worth supplying if you supply only one."
|
||||
},
|
||||
"process_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "The executable's file name (`Hades.exe`), when its location isn't fixed. Weakest of the three\n— see [`DetectSpec::process_name`]."
|
||||
}
|
||||
}
|
||||
},
|
||||
"DeviceRef": {
|
||||
"type": "object",
|
||||
"description": "A device in the pairing flow.",
|
||||
@@ -5449,6 +5484,13 @@
|
||||
},
|
||||
"description": "Other Moonlight-compatible hosts (Sunshine/Apollo/…) detected on this machine at startup —\nrunning one alongside Punktfunk is unsupported. Compact labels (e.g. `Sunshine (running)`);\nthe tray/console surface them so the clash is visible before pairing silently fails."
|
||||
},
|
||||
"games": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Launched games the host is tracking, as compact labels (`Hades`, `Hades (closing in 4:12)`).\n\nThe countdown form is the one that matters: it means the game's client is gone and the host\nwill end the game when the window closes — something a user at the machine should be able to\nsee (and stop) without opening the console. Empty when nothing was launched."
|
||||
},
|
||||
"kept_displays": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
@@ -5971,6 +6013,10 @@
|
||||
"art": {
|
||||
"$ref": "#/components/schemas/Artwork"
|
||||
},
|
||||
"detect": {
|
||||
"$ref": "#/components/schemas/DetectHint",
|
||||
"description": "How to recognize this title's process — see [`CustomEntry::detect`]. A provider that knows its\ntitles' install directories (Playnite does) should send them: it is what lets a game launched\nthrough the provider's own client still end its session when the player quits."
|
||||
},
|
||||
"external_id": {
|
||||
"type": "string",
|
||||
"description": "The provider's stable id for this title (the reconcile diff key)."
|
||||
|
||||
Reference in New Issue
Block a user