Do not offer transport a client cannot accept #20

Closed
opened 2026-08-10 14:04:38 +00:00 by aiko · 1 comment
Owner

Parent

#1

What to build

The transport controls (#16) send commands a client may never act on. Jellyfin already knows which clients can be driven — every session carries SupportsRemoteControl — and we do not look at it, so the app promises a control it has no reason to believe will work.

Observed on a real deploy: a Moonfin client on a Google TV. The endpoints answer, the command is accepted, and the picture does not move. From the sofa a refused command and a working one are indistinguishable, because #16 deliberately does not report command failures in the footer.

Surface the capability. Add SupportsRemoteControl to what the Sessions endpoint reports about a Playback Session.

Be honest about it on screen. When the followed session cannot be driven, the transport is disabled rather than dead — the footer never changes shape (DESIGN.md), so the controls stay put and go inert. The here control on the frozen strip needs the same treatment, since it is a seek. live does not: it moves the phone, not the show.

Say why once, where it can be read. A disabled control with no explanation is worse than no control. Where that explanation goes is a design decision, not a free choice — it may not live in the footer, and it must not become a state the footer changes shape for.

Stop swallowing the outcome. A refused or failed command currently disappears: drive catches and re-polls. That was right for keeping the footer stable and wrong for diagnosing this. Log the outcome server-side so a silent failure is recoverable from the Jellyfin log rather than only from a person noticing the television did not move.

Acceptance criteria

  • The Sessions endpoint reports whether a Playback Session accepts remote control
  • Transport is disabled, not absent, when the followed session cannot be driven
  • The frozen strip's here control is disabled on the same condition; live stays enabled
  • The reason is legible somewhere a reader will find it, without the footer changing shape
  • Switching to a controllable session re-enables everything without a reload
  • A refused or failed command leaves a server-side trace
  • The capability's effect on control state is covered by tests

Blocked by

## Parent #1 ## What to build The transport controls (#16) send commands a client may never act on. Jellyfin already knows which clients can be driven — every session carries `SupportsRemoteControl` — and we do not look at it, so the app promises a control it has no reason to believe will work. Observed on a real deploy: a Moonfin client on a Google TV. The endpoints answer, the command is accepted, and the picture does not move. From the sofa a refused command and a working one are indistinguishable, because #16 deliberately does not report command failures in the footer. **Surface the capability.** Add `SupportsRemoteControl` to what the Sessions endpoint reports about a Playback Session. **Be honest about it on screen.** When the followed session cannot be driven, the transport is disabled rather than dead — the footer never changes shape (`DESIGN.md`), so the controls stay put and go inert. The `here` control on the frozen strip needs the same treatment, since it is a seek. `live` does not: it moves the phone, not the show. **Say why once, where it can be read.** A disabled control with no explanation is worse than no control. Where that explanation goes is a design decision, not a free choice — it may not live in the footer, and it must not become a state the footer changes shape for. **Stop swallowing the outcome.** A refused or failed command currently disappears: `drive` catches and re-polls. That was right for keeping the footer stable and wrong for diagnosing this. Log the outcome server-side so a silent failure is recoverable from the Jellyfin log rather than only from a person noticing the television did not move. ## Acceptance criteria - [ ] The Sessions endpoint reports whether a Playback Session accepts remote control - [ ] Transport is disabled, not absent, when the followed session cannot be driven - [ ] The frozen strip's `here` control is disabled on the same condition; `live` stays enabled - [ ] The reason is legible somewhere a reader will find it, without the footer changing shape - [ ] Switching to a controllable session re-enables everything without a reload - [ ] A refused or failed command leaves a server-side trace - [ ] The capability's effect on control state is covered by tests ## Blocked by - #16
Author
Owner

This was generated by AI during triage.

Merged to main in af73452. Suites at merge: 79 C#, 335 phone.

Jellyfin knows which clients accept remote control and we were not asking. Confirmed in the field: Moonfin takes the command and does nothing, and Jellyfin's own UI cannot drive it either.

Transport is now disabled rather than dead on a client that cannot be driven, the reason is said in the status header, and auto-pause and follow are gated at the decision rather than swallowed at the send. A resume the app already owes bypasses the gate — otherwise a session that stopped accepting commands mid-Lookup would be left paused by us with every control that could undo it disabled.

SupportsRemoteControl turned out to be computed, not stored: the capability flag alone yields false, Jellyfin also requires a live session controller. The fixture sets both.

> *This was generated by AI during triage.* Merged to `main` in af73452. Suites at merge: 79 C#, 335 phone. Jellyfin knows which clients accept remote control and we were not asking. Confirmed in the field: Moonfin takes the command and does nothing, and Jellyfin's own UI cannot drive it either. Transport is now disabled rather than dead on a client that cannot be driven, the reason is said in the status header, and auto-pause and follow are gated at the decision rather than swallowed at the send. A resume the app already owes bypasses the gate — otherwise a session that stopped accepting commands mid-Lookup would be left paused by us with every control that could undo it disabled. `SupportsRemoteControl` turned out to be computed, not stored: the capability flag alone yields false, Jellyfin also requires a live session controller. The fixture sets both.
aiko closed this issue 2026-08-10 16:21:27 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
mobrule/kurageyomi#20
No description provided.