diff --git a/frontend/src/lib/resume.dom.test.ts b/frontend/src/lib/resume.dom.test.ts index 29053ec7..aa071ace 100644 --- a/frontend/src/lib/resume.dom.test.ts +++ b/frontend/src/lib/resume.dom.test.ts @@ -94,6 +94,18 @@ describe("useResume", () => { expect(save).toHaveBeenLastCalledWith(42, 600, true); }); + it("counts an element already playing when it subscribes as played", () => { + // A cached file started from 0 autoplays before the effect runs: its one `playing` is gone. + const m = fakeMedia(); + m.metadata(); + m.play(); + const save = vi.fn(); + renderHook(() => useResume(m.el, "7", 0, save)); + m.at(42); + m.pause(); + expect(save).toHaveBeenLastCalledWith(42, 600, false); + }); + it("checkpoints while it plays, at most once per interval", () => { vi.useFakeTimers(); const m = fakeMedia(); diff --git a/frontend/src/lib/resume.ts b/frontend/src/lib/resume.ts index 396d4d44..c0f49428 100644 --- a/frontend/src/lib/resume.ts +++ b/frontend/src/lib/resume.ts @@ -48,7 +48,9 @@ export function useResume( const report = useEffectEvent(save); useEffect(() => { if (!media || itemKey == null) return; - let played = false; + // Already playing counts as played: a cached file that autoplays from the start can fire its + // one `playing` before this effect subscribes, and would then never report at all. + let played = !media.paused; let lastAt = 0; const duration = () => (Number.isFinite(media.duration) ? media.duration : 0); const put = (leaving: boolean) => {