refactor(player): E.11 — extract two playback-coordination helpers (#574)

Two small file-private helpers move into dedicated modules under
src/store/:

- `waveformRefreshGen.ts` — the per-track generation counter that
  guards against applying a stale waveform read after the cache was
  invalidated. Exposes `bumpWaveformRefreshGen` (existing) +
  `getWaveformRefreshGen` (new accessor that replaces the two direct
  reads at `refreshWaveformForTrack`).
- `hotCacheTouch.ts` — `touchHotCacheOnPlayback` with its empty-id
  guards, called from every `audio_play` entry point.

Both file-private; no caller-side changes outside playerStore's own
imports. 8 focused tests pin the generation-increment + isolation
contract and the touch helper's empty-id guards.

playerStore 3302 → 3291 LOC.
This commit is contained in:
Frank Stellmacher
2026-05-12 14:14:50 +02:00
committed by GitHub
parent 86b13dd4d0
commit ddead24678
5 changed files with 129 additions and 18 deletions
+32
View File
@@ -0,0 +1,32 @@
/**
* Last-write-wins generation counter per track. Avoids applying a stale
* empty waveform read when `analysis:waveform-updated` bumps the gen after
* SQLite commit while an older `analysis_get_waveform_for_track` is still
* in flight. Gen is bumped only on explicit invalidation (waveform-updated,
* analysis storage), not on every `refreshWaveformForTrack` call —
* otherwise bursts (Lucky Mix, queue) cancel each other.
*
* Typical usage:
*
* const gen = getWaveformRefreshGen(trackId);
* const row = await invoke('analysis_get_waveform_for_track', { trackId });
* if (getWaveformRefreshGen(trackId) !== gen) return; // stale result
*/
const waveformRefreshGenByTrackId: Record<string, number> = {};
export function bumpWaveformRefreshGen(trackId: string): void {
if (!trackId) return;
waveformRefreshGenByTrackId[trackId] = (waveformRefreshGenByTrackId[trackId] ?? 0) + 1;
}
export function getWaveformRefreshGen(trackId: string): number {
return waveformRefreshGenByTrackId[trackId] ?? 0;
}
/** Test-only: wipe the per-track generations so each spec starts fresh. */
export function _resetWaveformRefreshGenForTest(): void {
for (const k of Object.keys(waveformRefreshGenByTrackId)) {
delete waveformRefreshGenByTrackId[k];
}
}