perf(download): stream response body straight to file

Bun.file().writer() per chunk replaces the in-memory chunk array +
final concat copy: no more whole-episode buffering.
This commit is contained in:
2026-09-06 18:46:42 -04:00
parent 8a173a5180
commit a3641d100e

View File

@@ -124,17 +124,17 @@ export async function downloadEpisode(
} }
} }
const reader = body.getReader() const fileWriter = Bun.file(filePath).writer()
const chunks: Uint8Array[] = []
let bytesDownloaded = 0 let bytesDownloaded = 0
let lastProgressTime = Date.now() let lastProgressTime = Date.now()
let lastProgressBytes = 0 let lastProgressBytes = 0
const reader = body.getReader()
while (true) { while (true) {
const { done, value } = await reader.read() const { done, value } = await reader.read()
if (done) break if (done) break
chunks.push(value) fileWriter.write(value)
bytesDownloaded += value.length bytesDownloaded += value.length
// Report progress roughly every 250ms // Report progress roughly every 250ms
@@ -152,22 +152,14 @@ export async function downloadEpisode(
} }
} }
// Concatenate chunks and write to file // Finalize the streamed file
const totalSize = bytesDownloaded await fileWriter.end()
const buffer = new Uint8Array(totalSize)
let offset = 0
for (const chunk of chunks) {
buffer.set(chunk, offset)
offset += chunk.length
}
await Bun.write(filePath, buffer)
// Final progress report // Final progress report
if (onProgress) { if (onProgress) {
onProgress({ onProgress({
bytesDownloaded: totalSize, bytesDownloaded,
totalBytes: contentLength || totalSize, totalBytes: contentLength || bytesDownloaded,
percent: 100, percent: 100,
speed: 0, speed: 0,
}) })
@@ -176,7 +168,7 @@ export async function downloadEpisode(
return { return {
success: true, success: true,
filePath, filePath,
fileSize: totalSize, fileSize: bytesDownloaded,
} }
} catch (err: unknown) { } catch (err: unknown) {
if (err instanceof DOMException && err.name === "AbortError") { if (err instanceof DOMException && err.name === "AbortError") {