mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-22 17:16:19 -07:00
fix(anime): scope preferences, paginate sources, harden installs
- Preference store keys entries by extension package + bridge source id; legacy unscoped entries are discarded once instead of being handed to whichever extension asks first - Source picker's "Load more" appends the next page without duplicating streamed results - Repository index fetches and subtitle/APK downloads now time out and are size-bounded instead of hanging or growing unbounded - APK installs are staged to a temp file and renamed into place - Stream metadata lookup matches the requested path, not only the currently playing one - Reworked animeui into browse-state/detail-panel/panels.css modules - Reverted premature CHANGELOG unreleased entries; refreshed anime-browser docs
This commit is contained in:
@@ -58,6 +58,7 @@ export interface SubtitleCacheResult {
|
||||
interface FetchResponseLike {
|
||||
ok: boolean;
|
||||
status: number;
|
||||
body?: ReadableStream<Uint8Array> | null;
|
||||
arrayBuffer: () => Promise<ArrayBuffer>;
|
||||
}
|
||||
|
||||
@@ -150,7 +151,7 @@ async function downloadTrack(
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
bytes = new Uint8Array(await response.arrayBuffer());
|
||||
bytes = await readBounded(response, MAX_SUBTITLE_BYTES);
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
@@ -171,6 +172,40 @@ async function downloadTrack(
|
||||
return filePath;
|
||||
}
|
||||
|
||||
async function readBounded(response: FetchResponseLike, maxBytes: number): Promise<Uint8Array> {
|
||||
const reader = response.body?.getReader();
|
||||
if (!reader) {
|
||||
const bytes = new Uint8Array(await response.arrayBuffer());
|
||||
if (bytes.byteLength > maxBytes) {
|
||||
throw new Error(`response too large (${bytes.byteLength} bytes)`);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const chunks: Uint8Array[] = [];
|
||||
let total = 0;
|
||||
for (;;) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
total += value.byteLength;
|
||||
if (total > maxBytes) {
|
||||
try {
|
||||
await reader.cancel();
|
||||
} catch {}
|
||||
throw new Error(`response too large (${total} bytes)`);
|
||||
}
|
||||
chunks.push(value);
|
||||
}
|
||||
|
||||
const bytes = new Uint8Array(total);
|
||||
let offset = 0;
|
||||
for (const chunk of chunks) {
|
||||
bytes.set(chunk, offset);
|
||||
offset += chunk.byteLength;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download every subtitle track to a fresh temp directory.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user