Opus max-effort audit on vc=53-vc=61 diff caught four interlocked
playback bugs. Cobb's 'video bugs are back' likely lived in the
intersection of #1+#2 — stale auto-resume seek + no recovery path.
BUG-1: setPlayingFrom clamps auto-resume against entry.durationMs.
YouTube can replace a video at the same videoId with a shorter cut
(live->VOD trim, premiere edit). Without the clamp, setMediaItem
seeks past the new end, ExoPlayer fires onPlayerError, NowPlaying
clears, surface locks at thumbnail+spinner. Clamp at lookup uses
the recorded duration with a 5s safety margin; falls back to 0
when out of range.
BUG-2: InlinePlayer adds a Retry button on the playback-error
branch. Tapping it nulls playbackError + bumps a retryVersion that
re-keys the setPlayingFrom LaunchedEffect. Previously the screen
locked into the error message forever (no UI affordance to
re-attempt; LaunchedEffect's keys never changed). Bonus protection:
the manual retry path avoids the infinite-error-loop risk a
NowPlaying-keyed auto-retry would have created.
BUG-4: captureResumePosition now gates strictly on STATE_READY.
STATE_BUFFERING during a fresh setMediaItem reports the PREVIOUS
item's position via currentPosition — the 5s poll was happily
writing A's tail position under B's videoId in that window. Next
auto-resume would drop the user mid-A on a fresh open of B.
BUG-5: onMediaItemTransition falls back to MediaItem.mediaMetadata
when Queue.at(idx) is null. Without the fallback, a Queue/controller
desync would leave NowPlaying stuck on the previous item forever,
freezing controllerOnThisVideo at false and locking the inline
player into thumbnail+spinner on the next screen.