trying to fix export issue and waveform load

This commit is contained in:
2026-04-15 21:51:05 -06:00
parent 168676a9e9
commit 0c7a4c94c2
6 changed files with 157 additions and 45 deletions

View File

@ -16,6 +16,7 @@ export default function ExportDialog() {
enhanceAudio: false,
captions: 'none',
});
const [exportError, setExportError] = useState<string | null>(null);
const handleExport = useCallback(async () => {
if (!videoPath) return;
@ -31,6 +32,7 @@ export default function ExportDialog() {
if (!outputPath) return;
setExporting(true, 0);
setExportError(null);
try {
const keepSegments = getKeepSegments();
@ -58,10 +60,20 @@ export default function ExportDialog() {
...options,
}),
});
if (!res.ok) throw new Error(`Export failed: ${res.statusText}`);
if (!res.ok) {
let detail = res.statusText;
try {
const body = await res.json();
if (body?.detail) detail = String(body.detail);
} catch {
// Keep statusText fallback when response body is not JSON.
}
throw new Error(`Export failed: ${detail}`);
}
setExporting(false, 100);
} catch (err) {
console.error('Export error:', err);
setExportError(err instanceof Error ? err.message : 'Export failed');
setExporting(false);
}
}, [videoPath, options, backendUrl, setExporting, getKeepSegments, cutRanges, muteRanges, gainRanges, speedRanges, globalGainDb, words]);
@ -159,6 +171,12 @@ export default function ExportDialog() {
)}
</button>
{exportError && (
<div className="rounded border border-red-500/40 bg-red-500/10 px-3 py-2 text-xs text-red-300">
{exportError}
</div>
)}
{options.mode === 'fast' && !hasCuts && (
<p className="text-[10px] text-editor-text-muted text-center">
Fast mode uses stream copy &mdash; no quality loss, exports in seconds.

View File

@ -354,7 +354,11 @@ export default function WaveformTimeline({
encodedPath: encodeURIComponent(videoPath ?? ''),
});
const waveformUrl2 = `${backendUrl}/audio/waveform?path=${encodeURIComponent(videoPath ?? '')}`;
setAudioError(`Waveform unavailable — ${err instanceof Error ? err.message : 'audio could not be decoded'} [URL: ${waveformUrl2}]`);
const errMessage = err instanceof Error ? err.message : 'audio could not be decoded';
const userMessage = errMessage === 'Load failed'
? `Cannot reach backend at ${backendUrl}. Start the backend server and reload the project.`
: errMessage;
setAudioError(`Waveform unavailable — ${userMessage} [URL: ${waveformUrl2}]`);
}
};

View File

@ -11,6 +11,9 @@ import { invoke } from '@tauri-apps/api/core';
import { open, save } from '@tauri-apps/plugin-dialog';
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
const backendPort = import.meta.env.VITE_BACKEND_PORT || '8642';
const backendUrl = `http://127.0.0.1:${backendPort}`;
const VIDEO_FILTERS = [
{ name: 'Audio and Video Files', extensions: ['mp4', 'avi', 'mov', 'mkv', 'webm', 'm4a', 'wav', 'mp3', 'flac'] },
{ name: 'All Files', extensions: ['*'] },
@ -35,9 +38,13 @@ window.electronAPI = {
return typeof result === 'string' ? result : null;
},
saveFile: async (_options?: Record<string, unknown>): Promise<string | null> => {
void _options;
const result = await save({ filters: EXPORT_FILTERS });
saveFile: async (options?: Record<string, unknown>): Promise<string | null> => {
const result = await save({
defaultPath: typeof options?.defaultPath === 'string' ? options.defaultPath : undefined,
filters: Array.isArray(options?.filters)
? (options.filters as Array<{ name: string; extensions: string[] }>)
: EXPORT_FILTERS,
});
return result ?? null;
},
@ -61,8 +68,8 @@ window.electronAPI = {
},
getBackendUrl: (): Promise<string> => {
// Backend URL is fixed; avoid invoke() which triggers ipc:// CSP errors on Linux/WebKit2GTK
return Promise.resolve('http://127.0.0.1:8000');
// Avoid invoke() here because Linux/WebKit2GTK can log noisy ipc:// CSP warnings.
return Promise.resolve(backendUrl);
},
encryptString: (data: string): Promise<string> => {

View File

@ -1,5 +1,13 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_BACKEND_PORT?: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
interface DesktopAPI {
openFile: (options?: Record<string, unknown>) => Promise<string | null>;
saveFile: (options?: Record<string, unknown>) => Promise<string | null>;