Merge pull request #222 from EtienneLescot/fix/export-local-file-loading
fix: read local export sources through electron IPC
This commit is contained in:
Vendored
+7
@@ -51,6 +51,13 @@ interface Window {
|
||||
openVideoFilePicker: () => Promise<{ success: boolean; path?: string; canceled?: boolean }>;
|
||||
setCurrentVideoPath: (path: string) => Promise<{ success: boolean }>;
|
||||
getCurrentVideoPath: () => Promise<{ success: boolean; path?: string }>;
|
||||
readBinaryFile: (filePath: string) => Promise<{
|
||||
success: boolean;
|
||||
data?: ArrayBuffer;
|
||||
path?: string;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}>;
|
||||
clearCurrentVideoPath: () => Promise<{ success: boolean }>;
|
||||
saveProjectFile: (
|
||||
projectData: unknown,
|
||||
|
||||
@@ -200,6 +200,29 @@ export function registerIpcHandlers(
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle("read-binary-file", async (_, inputPath: string) => {
|
||||
try {
|
||||
const normalizedPath = normalizeVideoSourcePath(inputPath);
|
||||
if (!normalizedPath) {
|
||||
return { success: false, message: "Invalid file path" };
|
||||
}
|
||||
|
||||
const data = await fs.readFile(normalizedPath);
|
||||
return {
|
||||
success: true,
|
||||
data: data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength),
|
||||
path: normalizedPath,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Failed to read binary file:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed to read binary file",
|
||||
error: String(error),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle("set-recording-state", (_, recording: boolean) => {
|
||||
if (recording) {
|
||||
stopCursorCapture();
|
||||
|
||||
@@ -60,6 +60,9 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
||||
getCurrentVideoPath: () => {
|
||||
return ipcRenderer.invoke("get-current-video-path");
|
||||
},
|
||||
readBinaryFile: (filePath: string) => {
|
||||
return ipcRenderer.invoke("read-binary-file", filePath);
|
||||
},
|
||||
clearCurrentVideoPath: () => {
|
||||
return ipcRenderer.invoke("clear-current-video-path");
|
||||
},
|
||||
|
||||
@@ -32,11 +32,37 @@ export class StreamingVideoDecoder {
|
||||
private cancelled = false;
|
||||
private metadata: DecodedVideoInfo | null = null;
|
||||
|
||||
async loadMetadata(videoUrl: string): Promise<DecodedVideoInfo> {
|
||||
private async loadSourceFile(videoUrl: string): Promise<{ file: File; blob: Blob }> {
|
||||
const isRemoteUrl = /^(https?:|blob:|data:)/i.test(videoUrl);
|
||||
|
||||
if (!isRemoteUrl && window.electronAPI?.readBinaryFile) {
|
||||
const result = await window.electronAPI.readBinaryFile(videoUrl);
|
||||
if (!result.success || !result.data) {
|
||||
throw new Error(result.message || result.error || "Failed to read source video");
|
||||
}
|
||||
|
||||
const filename = (result.path || videoUrl).split(/[\\/]/).pop() || "video";
|
||||
const blob = new Blob([result.data]);
|
||||
return {
|
||||
blob,
|
||||
file: new File([blob], filename, { type: blob.type || "application/octet-stream" }),
|
||||
};
|
||||
}
|
||||
|
||||
const response = await fetch(videoUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch source video: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const blob = await response.blob();
|
||||
const filename = videoUrl.split("/").pop() || "video";
|
||||
const file = new File([blob], filename, { type: blob.type });
|
||||
return {
|
||||
blob,
|
||||
file: new File([blob], filename, { type: blob.type }),
|
||||
};
|
||||
}
|
||||
|
||||
async loadMetadata(videoUrl: string): Promise<DecodedVideoInfo> {
|
||||
const { file } = await this.loadSourceFile(videoUrl);
|
||||
|
||||
// Relative URL so it resolves correctly in both dev (http) and packaged (file://) builds
|
||||
const wasmUrl = new URL("./wasm/web-demuxer.wasm", window.location.href).href;
|
||||
|
||||
Reference in New Issue
Block a user