fix: propagate Content-Type from fetch through loadFileAsArrayBuffer

Change return type to { data, contentType } so the fetched Content-Type
header is available to callers. loadSourceFile uses it to set the Blob
MIME type for https:/blob: URLs instead of always falling back to
application/octet-stream. useAudioPeaks destructures only { data }.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Davide Mendolia
2026-05-24 11:30:06 +02:00
co-authored by Claude Sonnet 4.6
parent 928cabc68d
commit d06bf37471
2 changed files with 11 additions and 5 deletions
+1 -1
View File
@@ -94,7 +94,7 @@ export function useAudioPeaks(videoUrl?: string): Float32Array | null {
(async () => {
try {
const arrayBuffer = await loadFileAsArrayBuffer(videoUrl);
const { data: arrayBuffer } = await loadFileAsArrayBuffer(videoUrl);
if (cancelled) return;
const audioBuffer = await getAudioCtx().decodeAudioData(arrayBuffer);
if (cancelled) return;
+10 -4
View File
@@ -140,9 +140,13 @@ export function shouldFailDecodeEndedEarly({
/**
* Loads a video file as an ArrayBuffer, using the Electron IPC bridge for
* local paths and falling back to `fetch` for remote / blob / data URLs.
* Also returns the `contentType` from the response headers (empty string for
* local IPC reads where no Content-Type is available).
* This is the single canonical place for reading raw video bytes in the renderer.
*/
export async function loadFileAsArrayBuffer(videoUrl: string): Promise<ArrayBuffer> {
export async function loadFileAsArrayBuffer(
videoUrl: string,
): Promise<{ data: ArrayBuffer; contentType: string }> {
const isRemoteUrl = /^(https?:|blob:|data:)/i.test(videoUrl);
if (!isRemoteUrl && window.electronAPI?.readBinaryFile) {
@@ -150,14 +154,15 @@ export async function loadFileAsArrayBuffer(videoUrl: string): Promise<ArrayBuff
if (!result.success || !result.data) {
throw new Error(result.message ?? result.error ?? "Failed to read video file");
}
return result.data;
return { data: result.data, contentType: "" };
}
const response = await fetch(videoUrl);
if (!response.ok) {
throw new Error(`Failed to fetch video file: ${response.status} ${response.statusText}`);
}
return response.arrayBuffer();
const contentType = response.headers.get("content-type")?.split(";")[0].trim() ?? "";
return { data: await response.arrayBuffer(), contentType };
}
/** Caller must close the VideoFrame after use. */
@@ -182,7 +187,7 @@ export class StreamingVideoDecoder {
/** Loads the video file and returns it as both a Blob and a File for WebDemuxer. */
private async loadSourceFile(videoUrl: string): Promise<{ file: File; blob: Blob }> {
const buffer = await this.withTimeout(
const { data: buffer, contentType } = await this.withTimeout(
loadFileAsArrayBuffer(videoUrl),
SOURCE_LOAD_TIMEOUT_MS,
"Timed out while loading the source video.",
@@ -198,6 +203,7 @@ export class StreamingVideoDecoder {
const ext = mime.split("/")[1]?.replace(/[^a-z0-9]/gi, "") ?? "";
filename = ext ? `video.${ext}` : "video";
} else {
mime = contentType;
filename = videoUrl.split(/[\\/]/).pop() || "video";
}