From 6dfc6b259a6b6898ad76f7c6d8a41faad3ef570c Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 16 Aug 2026 23:54:43 +0200 Subject: [PATCH] fix(player): lockscreen skip scrubs instead of advancing in background audio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit onSkipToNext/onSkipToPrevious forwarded a bare next/previous to Rust, which always advanced the queue. Correct for music, wrong for a video whose audio is running through a background-audio handoff (UR-040): pressing skip to re-hear a line jumped to the next episode instead of scrubbing. resolve_skip_action in player/seek.rs maps the command to Advance or SeekTo, and is_background_audio_active() is the whole test — the handoff exists only for video, and an episode played through it reports MediaType::Audio, so media type cannot distinguish the case. Forward 30s, back 10s, both clamped to [0, duration] so a skip near either end cannot seek negative or read as EOF and advance. Routed through the same spawn-then-seek_absolute path as the scrubber, because a handoff seek re-opens the stream and must not run under the blocking lock (DR-159). Kotlin keeps sending the opaque command; it only gains FAST_FORWARD/ REWIND in the PlaybackStateCompat so the system stops drawing skip arrows for a control that scrubs. The remote-volume action block is deliberately untouched: the handoff never applies to cast sessions, where skip really does mean advance. Tests written first and watched fail (left: Advance, right: SeekTo). 706 Rust tests pass, clippy 0, coverage 90%. --- docs/requirements.md | 10 +- scripts/extract-traces.test.ts | 7 +- .../player/JellyTauPlaybackService.kt | 23 +++ src-tauri/src/lib.rs | 49 +++++- src-tauri/src/player/seek.rs | 139 ++++++++++++++++++ 5 files changed, 221 insertions(+), 7 deletions(-) diff --git a/docs/requirements.md b/docs/requirements.md index e289980d..eac38138 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -374,6 +374,7 @@ Internal architecture, components, and application logic. | DR-196 | Returning from background audio brings the picture back on the **native** path, because the return now restarts the renderer that is actually on screen. The two paths resume by different means: the webview `