refactor(downloads): add readableStreamIterator for easier stream handling

- Introduced `readableStreamIterator` to convert ReadableStream into async iterable.
- Updated `LosslessAPI` to utilize `readableStreamIterator` for handling response body.
- Modified `ZipNeutralinoWriter` to use `readableStreamIterator` for reading chunks.
This commit is contained in:
Daniel 2026-03-17 19:50:29 -05:00
parent 61aebf7994
commit cd64239ba1
3 changed files with 34 additions and 13 deletions

View file

@ -21,6 +21,7 @@ import { triggerDownload, applyAudioPostProcessing } from './download-utils.ts';
import { isCustomFormat } from './ffmpegFormats.ts';
import { DownloadProgress } from './progressEvents.js';
import { resolveDownloadTotalBytes } from './downloadProgressUtils.js';
import { readableStreamIterator } from './readableStreamIterator.js';
export const DASH_MANIFEST_UNAVAILABLE_CODE = 'DASH_MANIFEST_UNAVAILABLE';
export { resolveDownloadTotalBytes };
@ -1431,19 +1432,13 @@ export class LosslessAPI {
let receivedBytes = 0;
if (response.body) {
const reader = response.body.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
for await (const chunk of readableStreamIterator(response.body)) {
chunks.push(chunk);
receivedBytes += chunk.byteLength;
if (value) {
chunks.push(value);
receivedBytes += value.byteLength;
onProgress?.(new DownloadProgress(receivedBytes, totalBytes || undefined));
}
onProgress?.(new DownloadProgress(receivedBytes, totalBytes || undefined));
}
const defaultMime = isVideo ? 'video/mp4' : 'audio/flac';

View file

@ -135,9 +135,7 @@ export class ZipNeutralinoWriter implements IBulkDownloadWriter {
const reader = response.body.getReader();
let receivedLength = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
for await (const value of readableStreamIterator(response.body)) {
const chunk = value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
await bridge.filesystem.appendBinaryFile(savePath, chunk);
receivedLength += value.length;

View file

@ -0,0 +1,28 @@
/**
* Converts a ReadableStream into an async iterable iterator.
* @template T The type of data chunks yielded from the stream.
* @param stream The ReadableStream to convert into an async iterable.
* @yields Chunks of data from the stream as they become available.
* @example
* ```typescript
* const response = await fetch('https://example.com/data');
* for await (const chunk of readableStreamIterator(response.body)) {
* console.log(chunk);
* }
* ```
*/
export async function* readableStreamIterator<T>(stream: ReadableStream<T>): AsyncIterableIterator<T> {
const reader = stream.getReader();
while (true) {
const { value, done } = await reader.read();
if (value) {
yield value;
}
if (done) {
break;
}
}
}