From 16e2b24c312c72fa9ea71022b80e87f8e4282ed9 Mon Sep 17 00:00:00 2001 From: Jonathan Sykes Date: Sat, 3 Oct 2026 00:49:24 +0800 Subject: [PATCH] Resumable saves: prepare reports the mp4's real size, not the cache row's mp4+m4a total The media_cache row's size counts the audio sidecar too, so a device asked for bytes past the end of the file and could never finish a ranged save. --- server/server.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/server.js b/server/server.js index f28b21b..50e6d3a 100644 --- a/server/server.js +++ b/server/server.js @@ -1576,7 +1576,13 @@ app.get('/api/download/:videoId/prepare', async (c) => { if (ready) { if (!servableTo(ready, hevcOk)) return c.json({ ok: true, state: 'legacy', reason: 'hevc' }, 200, nocache); media.touch(videoId); - return c.json({ ok: true, state: 'ready', gen: ready.gen, size: ready.size, sha256: ready.sha256 || null, + // The row's size can differ from the mp4 on disk (it is not the file the + // device fetches byte-for-byte), so report the file's real length. + const path = await media.filePath(videoId, ready.gen); + let size = 0; + try { size = path ? Bun.file(path).size : 0; } catch { /* vanished */ } + if (!size) return c.json({ ok: true, state: 'legacy', reason: 'cached file unavailable' }, 200, nocache); + return c.json({ ok: true, state: 'ready', gen: ready.gen, size, sha256: ready.sha256 || null, etag: `"${videoId}.${ready.gen}"`, ext: 'mp4' }, 200, nocache); } // A job refused moments ago (too long for the cache, cache offline…) would