trying to fix export issue and waveform load
This commit is contained in:
@ -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 — no quality loss, exports in seconds.
|
||||
|
||||
@ -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}]`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -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> => {
|
||||
|
||||
8
frontend/src/vite-env.d.ts
vendored
8
frontend/src/vite-env.d.ts
vendored
@ -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>;
|
||||
|
||||
Reference in New Issue
Block a user