feat: add waveform seekbar with composite PK cache and singleflight (#90)#106
feat: add waveform seekbar with composite PK cache and singleflight (#90)#106thedavidweng wants to merge 3 commits into
Conversation
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat/crossfade-playback-89 #106 +/- ##
============================================================
+ Coverage 78.2% 78.6% +0.3%
============================================================
Files 131 132 +1
Lines 6804 6940 +136
Branches 2112 2142 +30
============================================================
+ Hits 5325 5457 +132
- Misses 1435 1439 +4
Partials 44 44
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Greptile SummaryThis PR adds a waveform-backed seekbar with cached backend waveform generation. The main changes are:
Confidence Score: 5/5This PR appears safe to merge. No blocking correctness or security issues were identified. The waveform path clamps and validates bucket counts, sanitizes cache contents and errors, avoids holding playback locks during computation, and uses frontend generation guards for stale async responses. No files require special attention.
What T-Rex did
Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant SeekBar
participant LRU as Waveform LRU
participant IPC as get_waveform IPC
participant SF as WaveformSingleflight
participant Worker as Blocking waveform task
participant DB as SQLite waveforms cache
participant Audio as Audio decode/peaks
SeekBar->>SeekBar: "derive buckets from rail width * DPR"
SeekBar->>LRU: get(songHash, buckets)
alt cache hit
LRU-->>SeekBar: peaks
else cache miss
SeekBar->>IPC: get_waveform(hash, buckets)
IPC->>DB: lookup song and skip remote sources
IPC->>SF: register(songHash, buckets)
alt first waiter
SF->>Worker: spawn shared computation
Worker->>DB: read cached waveform
alt DB cache miss
Worker->>Audio: decode song and compute peaks
Worker->>DB: save peaks blob
end
Worker-->>SF: fan out result to waiters
else existing computation
SF-->>IPC: await shared waiter
end
IPC-->>SeekBar: peaks[]
SeekBar->>LRU: store non-empty peaks
end
SeekBar->>SeekBar: draw DPR-aware canvas behind seek progress
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant SeekBar
participant LRU as Waveform LRU
participant IPC as get_waveform IPC
participant SF as WaveformSingleflight
participant Worker as Blocking waveform task
participant DB as SQLite waveforms cache
participant Audio as Audio decode/peaks
SeekBar->>SeekBar: "derive buckets from rail width * DPR"
SeekBar->>LRU: get(songHash, buckets)
alt cache hit
LRU-->>SeekBar: peaks
else cache miss
SeekBar->>IPC: get_waveform(hash, buckets)
IPC->>DB: lookup song and skip remote sources
IPC->>SF: register(songHash, buckets)
alt first waiter
SF->>Worker: spawn shared computation
Worker->>DB: read cached waveform
alt DB cache miss
Worker->>Audio: decode song and compute peaks
Worker->>DB: save peaks blob
end
Worker-->>SF: fan out result to waiters
else existing computation
SF-->>IPC: await shared waiter
end
IPC-->>SeekBar: peaks[]
SeekBar->>LRU: store non-empty peaks
end
SeekBar->>SeekBar: draw DPR-aware canvas behind seek progress
Reviews (2): Last reviewed commit: "style: remove extra blank line in tauri-..." | Re-trigger Greptile |
Maintainer acceptance — merge slot 10, strictly after #104BLOCKED — changes required. Missing #90 frontend contract
Implement the required client cache and width/DPR bucket selection, refetch safely on relevant resize, and add the specified stale-generation/LRU/bucket tests. Branch/scope blockerThis PR targets old |
26945ad to
f4d6503
Compare
Re-review: waveform implementation and stack cleanup requiredThe current source at this head still has a fixed Do the following:
Add tests for width/DPR-driven bucket selection, resize refresh, 96-entry LRU promotion/eviction, stale deferred-response rejection, unmount cleanup, and unchanged seek interactions. Then, after #104 is final, rebase onto the merged |
d148599 to
b0f7c76
Compare
b0f7c76 to
ff4aeff
Compare
1f6007d to
d1d5abf
Compare
9b05bd0 to
51a261d
Compare
d1d5abf to
cf0947a
Compare
899f3f8 to
685aed2
Compare
dbe353c to
049d783
Compare
685aed2 to
414cbe1
Compare
Re-review — still blocked: waveform request identity is not DPR-awareReviewed at Implement the issue contract exactly:
The current comment explicitly describes width as “DPR-independent CSS”; that contradicts the #90 acceptance contract. |
049d783 to
a96c2f7
Compare
414cbe1 to
ca2befd
Compare
a96c2f7 to
5a85bb7
Compare
ca2befd to
56a5c96
Compare
56a5c96 to
ff9db59
Compare
Re-review — blocked: a quantized DPR-only migration leaves the canvas at the old pixel scaleReviewed at For example, at 299 CSS px a 2x → 2.005x migration retains bucket 199 and correctly does not refetch, but it also never repaints at the new DPR. Please make DPR itself invalidate the canvas draw (for example, depend on Extend the existing quantized-no-op test to assert both:
|
Re-review — DPR fix and regression test verified; held only by stack integrationReviewed at GitHub currently reports the PR unmergeable and it is two commits behind its |
4392601 to
3f1091f
Compare
f77c995 to
5e0369a
Compare
Re-review — DPR fix remains correct, but this head is not CI-cleanReviewed at CI run 29525679883 fails before the test suite because Run: pnpm format:write src/lib/tauri/tauri-wrappers.test.ts
pnpm formatCommit only the formatter output and rerun CI. The missing coverage/Codecov messages are downstream of the format step skipping tests; they are not a separate product failure. No LGTM until a fresh CI run is green. |
|
@greptile review |
|
Stack status update: the code-format blocker on head After #104 is conflict-free, green, and accepted, update/retarget #106 onto the accepted #104 head and run fresh full CI. Final LGTM remains gated on manual waveform rendering/seek interaction/DPR acceptance. |
7bb62b7 to
53ae363
Compare
b334c09 to
71329dc
Compare
79c8d05 to
067862e
Compare
f5de12e to
1711c22
Compare
067862e to
bc756ec
Compare
bc756ec to
db309ce
Compare
a15384a to
5046ec5
Compare
5ddbd3c to
d691ca1
Compare
5046ec5 to
ce496d5
Compare
d691ca1 to
e828019
Compare
c0f1ce4 to
81464a3
Compare
… feat/90-waveform-seekbar
Summary
(song_hash, bucket_count)once across concurrent WebViews via cancellation-safe singleflightCloses #90.
Test plan
pnpm format,pnpm lint,pnpm check:i18n,pnpm knip,pnpm build,pnpm test,pnpm test:coverage,pnpm check:patch-coveragepasscargo fmt --check,cargo test -qpass