fix(playback): show the Up next card near the real end of an episode (#1768)

* fix(playback): show the Up next card near the real end of an episode

The card appeared a fixed 8 minutes before the end: most of a short
episode, and far into the story of a long one, with no way to hide it.

- Adaptive lead: 4% of the episode, clamped to 40 s … 3 min.
- A closing-credits chapter in the last third, when timeline segments
  carry one, brings the card forward to its start (capped at 5 min).
- Close button and Escape dismiss the card for the current next episode.
- After 10 s (not while hovered) the card collapses into a one-line pill.
- Seconds countdown in the last minute.
- New playback setting "Up next card" (default on) turns it off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(playback): address Up next card review feedback

- Offer the Up next card setting for Embedded MPV only under the
  frame-copy engine; native view never mounts the shared controls.
- Hovering pauses the collapse delay instead of restarting it.
- Document that the card stays visible when the controls auto-hide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(playback): restart the Up next collapse delay for a new episode

- A card that stays mounted while its next episode changes gives the new
  item the full delay instead of the previous item's leftover.
- The setting description no longer promises credit-based timing: no
  current series path supplies chapters yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 authored and GitHub committed 2026-09-30 21:56:48 +02:00
1 parent cb317bad4c
commit 525ca7bc44
44 files changed
+782 -106

No files matched your search

+23 -7
View File
@@ -405,10 +405,17 @@ bottom-right corner above the controls: the next episode's still (or its
watched, "Up next · in 7 min" and the title. The host supplies the item
through the optional `upNext` input (`PlayerUpNextItem { label, title,
thumbnailUrl, progressPercent }`); `ControlsUpNext` decides when it shows —
`seriesNavigation` capability, a finite duration with at
most `UP_NEXT_THRESHOLD_SECONDS` (8 min) left, not live, not `ended` (with
autoplay off nothing is scheduled, so no countdown), controls shown,
settings panel closed — and how many minutes remain (never below one). A
`seriesNavigation` capability, a finite duration, not live, not `ended`
(with autoplay off nothing is scheduled, so no countdown), controls shown,
settings panel closed, not dismissed — and when. The lead adapts to the
episode: `upNextThresholdSeconds` is 4% of the duration clamped to
40 s … 3 min (about 50 s for a 22-minute episode, 2.4 min for an hour). When
`timelineSegments` carry a closing-credits chapter in the last third
(`creditsStartSeconds`: "Credits", "Outro", "Ending", an anime `ED`, and a
few localized names), the card appears when it starts instead, at most
5 min before the end. No engine reports file chapters today, so in practice
the adaptive lead applies. The countdown shows whole minutes, and seconds
in the last minute. A
still that fails to load falls back to the label tile. A
click emits `nextEpisodeRequested` directly — not through the
transport's `canNextEpisode` guard, which is season-local — so the card
@@ -417,12 +424,21 @@ routes such a request through the Up Next rail selection
(`upNextEpisodeSelected`) whenever `seriesNavigation.canNext` is false, which
plays the next season's first episode; either path keeps fullscreen exactly
like the transport button.
The card is a glass surface that does not fade with the controls; the
compact dock uses a smaller variant without the trailing icon.
The card is a glass surface that stays visible when the controls auto-hide
(`showControls` is the host's input, not the idle state); the compact dock
uses a smaller variant without the trailing icon. After
`UP_NEXT_COLLAPSE_DELAY_MS` (10 s, paused while hovered) the card asks to
collapse and `ControlsUpNext.collapse()` turns it into a one-line pill
(label and countdown) for the rest of the episode. A corner close button
(`player-controls-up-next-close`) or Escape on the focused card calls
`dismiss()`, which hides it until the item it points to changes; Escape is
stopped at the card so it does not reach the player's own Escape handling.
The `playerUpNextCard` setting (default on) turns the card off: the
producer below then passes `null`.
Plumbing mirrors `mediaTitle`: `PortalInlinePlayerComponent.playerUpNext`
derives the item after the playing one from its `upNextEpisodes` input
(episodes only) → `WebPlayerViewComponent.upNext` → the four engine hosts →
(episodes only, and only while `playerUpNextCard` is not `false`) → `WebPlayerViewComponent.upNext` → the four engine hosts →
`app-player-controls`. Movie and live hosts pass nothing.
### Settings panel