feat(serve): relay approval messages to jobs and proxy remote downloads

A REST job shows a wait_for_approval message as its notice field. search, list-titles and list-tracks fail at once on a login that needs the user. A remote client downloads through the --proxy it sends.
This commit is contained in:
imSp4rky
2026-10-07 11:15:16 -06:00
parent 5b0369e63a
commit 09cae2ec3f
16 changed files with 233 additions and 28 deletions
+13 -1
View File
@@ -197,6 +197,13 @@ Get the list of titles behind a title ID, for example episodes or a movie, witho
You can also pass service-specific CLI options as additional keys.
#### Logins that need the user
`search`, `list-titles` and `list-tracks` have no channel to the user. A login that asks for
input or waits for an approval on another device fails at once with `AUTH_FAILED` on these
endpoints. Complete that login in a download job or a remote session, then send the saved
login with the request.
#### Client cache on a remote-only server
A `--remote-only` server keeps nothing that a client sends. When the request
@@ -556,7 +563,8 @@ Show download jobs, with optional filtering and sorting.
"segments_total": 300,
"speed": "5.2 MB/s",
"skipped_subtitles": [],
"input_prompt": null
"input_prompt": null,
"notice": null
}
]
}
@@ -721,6 +729,10 @@ example an OTP code, a PIN, or a device-code confirmation. The job then shows th
`input_prompt` field and in its `progress` events. Show the prompt to the user and send the
answer here.
A job that waits for an approval on another device, such as a pair code login, shows the
message in its `notice` field instead. A notice needs no answer: show it to the user and keep
polling.
=== "Request"
```json
+3
View File
@@ -163,6 +163,7 @@ full detail:
| `speed` | string | Transfer speed of the track in progress, e.g. `4.20 MB/s`. |
| `skipped_subtitles` | list | Subtitles that were skipped as non-fatal failures (when `skip_subtitle_errors` is set). |
| `input_prompt` | string or `null` | The prompt the service waits on. Answer it with `POST /api/download/jobs/{job_id}/input`. |
| `notice` | string or `null` | A message the service shows while it waits for an approval on another device, such as a pair code. It needs no answer. |
The full detail adds `started_time`, `completed_time`, `output_files`, the redacted
`parameters`, and, for failed jobs, `error_message`, `error_details`, and `error_code`.
@@ -368,6 +369,8 @@ Three temporary files bridge the parent and the job worker:
The job worker has no terminal. When a service asks the user for input, the job worker writes
the prompt to `progress.json` as `input_prompt` and waits. The answer from
`POST /api/download/jobs/{job_id}/input` goes to the job worker on its stdin.
When a service waits for an approval on another device, the job worker writes the message as
`notice` and sets it back to `null` when the wait ends.
Running each download out-of-process isolates the server from crashes, memory growth,
and blocking work inside the download engine, and makes hard cancellation (killing the
+3
View File
@@ -127,6 +127,9 @@ hood the client walks a remote session through its lifecycle.
URI and runs its own forwarder for it. A bare region skips Control D, because its
proxy is a forwarder on the client. See
[Control D](../../guide/proxies-and-vpn.md#control-d)
The client also downloads playlists and segments through the same proxy,
as a local run does. `--no-proxy-download` and `--proxy-download` change
that for downloads only.
- Track-selection hints (`range_`, `vcodec`, `quality`, `best_available`) so
the server fetches the right manifests
- Your language and audio codec selection (`-l`, `-vl`, `-al`, `-a`, `-fs`)