Skip to content

fix(seek): debounce seeks that restart a decoder - #331

Open
coryshaw1 wants to merge 1 commit into
bjarneo:mainfrom
coryshaw1:fix/debounce-stream-seek
Open

fix(seek): debounce seeks that restart a decoder#331
coryshaw1 wants to merge 1 commit into
bjarneo:mainfrom
coryshaw1:fix/debounce-stream-seek

Conversation

@coryshaw1

@coryshaw1 coryshaw1 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Holding or tapping the seek keys on a buffered network stream freezes the UI. Each press runs Player.Seek inline on the UI goroutine, and for these streams a seek kills ffmpeg and restarts it with -ss, then waits for PCM — so three quick presses serialise three restarts and the interface stops responding until they finish.

seekRelative already had the fix for yt-dlp: presses accumulate into seek.targetPos and one seek fires ~800ms after the last, from a command goroutine. This routes decoder-restarting stream seeks through that same path rather than adding a second mechanism.

needsDebouncedSeek gates it on track.Stream && Seekable(), which covers the providers sharing the nav/ffmpeg pipeline — Navidrome, Plex, Jellyfin, Emby, Qobuz, Audiobookshelf. Local files, radio (not seekable), Spotify (Stream: false, and its decoder repositions in place), and NetEase keep seeking inline.

Worth noting this mitigates rather than removes the cost: ffmpeg reads these streams through pipe:0, so it cannot seek and has to restart, even though navBuffer already has the bytes on disk. Feeding it the temp file instead would make seeks cheap and this debounce unnecessary — a larger change, and one I would rather raise separately than bundle here.

How to test

  1. Play an Audiobookshelf (or Navidrome/Plex/Jellyfin/Emby/Qobuz) track and tap the right arrow three or four times quickly. The UI should stay responsive, and one seek should land ~800ms after the last press at the summed offset.
  2. Try shift+arrow for the larger step, and the left arrow to confirm backward seeks sum the same way.
  3. Seek a local file and confirm it still moves immediately, with no added delay.
  4. Seek a yt-dlp source (cliamp "https://www.youtube.com/watch?v=<id>") and confirm its existing debounce still works — this PR renames the functions it uses.
  5. Play a radio stream and confirm the arrow keys behave as before.

Checklist

  • make check passes
  • docs/ and site/index.html updated for user-facing changes

No docs change: nothing in docs/ or site/index.html describes seek timing, so there is no stale claim to correct.

I tested Audiobookshelf, yt-dlp, Spotify, radio and local files by hand. Navidrome, Plex, Jellyfin, Emby and Qobuz share the same decoder and predicate so should behave identically, but I have no server for those and have not verified them directly.

Summary by CodeRabbit

  • Bug Fixes
    • Improved seeking responsiveness by debouncing seeks for supported streams.
    • Preserved immediate seeking during active playback where appropriate.
    • Improved handling of rapid, timer-triggered, and absolute seek actions.
    • Reduced unnecessary decoder restarts when multiple seek requests occur in quick succession.

Seeking a buffered network stream ran Player.Seek inline on the UI
goroutine, and each seek restarts ffmpeg and waits for PCM -- so a burst of
arrow presses froze the UI while they ran one after another.

Route them through the accumulate-and-debounce path yt-dlp already used, so
presses sum into one seek fired from a command goroutine. Affects the
providers sharing that pipeline (Navidrome, Plex, Jellyfin, Emby, Qobuz,
Audiobookshelf); local files and non-seekable streams are unchanged.
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: eb0f9019-3dbd-49f9-b548-5f727e0d01d9

📥 Commits

Reviewing files that changed from the base of the PR and between 23685fc and fb079f8.

📒 Files selected for processing (1)
  • ui/model/seek.go

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

Seeking now debounces yt-dlp decoder-restart seeks and seekable stream seeks. Shared pending targets handle relative, absolute, and timer-triggered seeks. Immediate seeking remains for non-debounced playback.

Changes

Seek debouncing and dispatch

Layer / File(s) Summary
Shared debounced seek dispatch
ui/model/seek.go
The model identifies seek types that require debouncing, queues shared targets, cancels active yt-dlp seeks when needed, and commits through SeekYTDL or regular Seek.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to fb079

The change debounces decoder-restarting stream seeks while preserving immediate seeking for other sources. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: bjarneo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: debouncing seeks that restart a decoder.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant