crabidy/plan/seek.md

3.3 KiB
Raw Blame History

Plan — seek

Executes architecture/seek.md against quality/seek.md. One commit: the change is a single thin path from key to sink, and half-wiring it would leave a dead RPC.

A — The engine (where the only real logic is)

  • A1 — PlayerEngine::seek_target — a pure function of (current position, delta millis, known duration) returning the absolute target: saturating on both ends, 0 as the floor, duration - 1 s as the ceiling when the duration is known, no ceiling when it is 0. Extracted as a free function so the arithmetic is testable without an audio device. Verifies: G1, G5, G6, G7.
  • A2 — Rewrite PlayerEngine::seek_to to route through the same helper, dropping the clamp(1s, duration) that panics whenever the duration is unknown or under a second. Verifies: G1.
  • A3 — PlayerEngine::seek_by — reads sink.get_pos(), applies A1, calls try_seek, and on success notifies PlayerMessage::Elapsed with the new position so a paused seek is visible. Refuses when stopped. Verifies: G4, G8, G9.
  • A4 — PlayerEngineCommand::SeekBy + Player::seek_by on the existing bounded reply pattern. Verifies: G3.
  • A5 — Engine tests: extremes (i64::MIN/MAX), zero duration, short track, composition, near-end saturation. Verifies: G1, G4G7.

B — Wire and server

  • B1 — Proto: rpc Seek(SeekRequest) returns (SeekResponse) with sint32 delta_millis, documented with the clamping contract. Verifies: G10.
  • B2 — PlaybackCommand::Seek { delta_millis } + its name() arm, and the playback handler that forwards to player.seek_by and warns on failure. No state. Verifies: G2, G12.
  • B3 — RpcService::seek following the change_volume shape (record the field, send, return empty). Verifies: G10.
  • B4 — Server test that the command reaches the player with the delta unchanged. Verifies: G11.

C — Clients

  • C1 — TUI: Action::SeekForward/SeekBackward, Ctrl-f/Ctrl-b bindings in Scope::Global with help text, MessageFromUi::Seek(i64), the lib.rs arm, rpc.rs wrapper, SEEK_STEP constant, dispatch tests. Verifies: G13, G14, G15.
  • C2 — Web: the same two actions in keymap.rs (global, with HELP rows), Rpc::seek, the app.rs dispatch arms, and / buttons in the transport bar. Verifies: G13, G14, G15.
  • C3 — CLI: GlobalCmd::Seek { seconds: i32 } with allow_negative_numbers, and its executor arm. Verifies: G14.

D — Docs and gates

  • D1 — Docs: key tables (docs/src/clients/tui.md, docs/src/clients/web.md), the CLI page's global list, and the within-track/end-of-track/HLS sentences in docs/src/queue.md. Verifies: G16.
  • D2 — Gates: workspace tests, check-features, cargo fmt, a wasm build of cbd-web, and the book build. Verifies: G17.
  • D3 — plan/summary.md entry, then commit.

Deferred (recorded, not dropped)

  • Absolute seek + click-to-seek on the web progress gauge (the gauge is already rendered; needs one proto field and a click handler).
  • Configurable step size, and a larger step on </>.
  • Chapter-aware seek for podcasts/audiobooks — no provider exposes chapter marks through the library model.