removed electron

This commit is contained in:
2026-04-15 17:40:27 -06:00
parent 48d761c713
commit 84edddded8
11 changed files with 73 additions and 512 deletions

View File

@ -1,4 +1,4 @@
import { useEffect, useState, useRef, useMemo } from 'react';
import { useEffect, useState, useMemo } from 'react';
import { useEditorStore } from './store/editorStore';
import VideoPlayer from './components/VideoPlayer';
import TranscriptEditor from './components/TranscriptEditor';
@ -16,7 +16,6 @@ import {
Settings,
Sparkles,
Download,
FolderSearch,
FileInput,
Save,
Scissors,
@ -27,7 +26,6 @@ import {
RefreshCw,
} from 'lucide-react';
const IS_ELECTRON = !!window.electronAPI;
const LAST_MEDIA_PATH_KEY = 'talkedit:lastMediaPath';
type Panel = 'ai' | 'settings' | 'export' | 'silence' | 'volume' | null;
@ -60,7 +58,6 @@ export default function App() {
} = useEditorStore();
const [activePanel, setActivePanel] = useState<Panel>(null);
const [manualPath, setManualPath] = useState('');
const [whisperModel, setWhisperModel] = useState('base');
const [cutMode, setCutMode] = useState(false);
const [muteMode, setMuteMode] = useState(false);
@ -70,7 +67,6 @@ export default function App() {
const [showUnsavedPrompt, setShowUnsavedPrompt] = useState(false);
const [pendingProceedAction, setPendingProceedAction] = useState<(() => Promise<void>) | null>(null);
const [lastSavedSignature, setLastSavedSignature] = useState<string | null>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const projectSignature = useMemo(() => {
if (!videoPath) return null;
@ -125,7 +121,7 @@ export default function App() {
};
const runGuarded = async (action: () => Promise<void>) => {
if (!IS_ELECTRON || !hasUnsavedChanges) {
if (!hasUnsavedChanges) {
await action();
return;
}
@ -150,16 +146,11 @@ export default function App() {
}, []);
useEffect(() => {
if (IS_ELECTRON) {
window.electronAPI!.getBackendUrl().then(setBackendUrl);
}
// In Tauri on Linux/WebKit2GTK the ipc:// custom protocol is blocked by
// WebKit internals; postMessage fallback works but logs noisy warnings.
// The backend URL is fixed at 127.0.0.1:8000 so we rely on the store default.
window.electronAPI!.getBackendUrl().then(setBackendUrl);
}, [setBackendUrl]);
useEffect(() => {
if (!IS_ELECTRON || videoPath) return;
if (videoPath) return;
const savedPath = sessionStorage.getItem(LAST_MEDIA_PATH_KEY);
if (savedPath) {
loadVideo(savedPath);
@ -167,7 +158,6 @@ export default function App() {
}, [videoPath, loadVideo]);
useEffect(() => {
if (!IS_ELECTRON) return;
if (videoPath) {
sessionStorage.setItem(LAST_MEDIA_PATH_KEY, videoPath);
return;
@ -176,7 +166,6 @@ export default function App() {
}, [videoPath]);
const handleLoadProject = async () => {
if (!IS_ELECTRON) return;
await runGuarded(async () => {
try {
const projectPath = await window.electronAPI!.openProject();
@ -192,7 +181,6 @@ export default function App() {
};
const handleSaveProject = async (): Promise<boolean> => {
if (!IS_ELECTRON) return false;
try {
const savePath = await window.electronAPI!.saveProject();
if (!savePath) return false;
@ -208,25 +196,15 @@ export default function App() {
alert(`Failed to save project: ${err}`);
return false;
}
return false;
};
const handleOpenFile = async () => {
await runGuarded(async () => {
if (IS_ELECTRON) {
const path = await window.electronAPI!.openFile();
if (path) {
setLastSavedSignature(null);
loadVideo(path);
await transcribeVideo(path);
}
} else {
// Browser: use the manual path input
const path = manualPath.trim();
if (path) {
loadVideo(path);
await transcribeVideo(path);
}
const path = await window.electronAPI!.openFile();
if (path) {
setLastSavedSignature(null);
loadVideo(path);
await transcribeVideo(path);
}
});
};
@ -236,27 +214,15 @@ export default function App() {
useEditorStore.getState().reset();
setLastSavedSignature(null);
setActivePanel(null);
setManualPath('');
setCutMode(false);
setMuteMode(false);
setGainMode(false);
});
};
const handleManualSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const path = manualPath.trim();
if (!path) return;
loadVideo(path);
await transcribeVideo(path);
};
const transcribeVideo = async (path: string) => {
setTranscribing(true, 0, 'Checking model...');
try {
if (!window.electronAPI?.transcribe) {
throw new Error('Transcription not available');
}
// Step 1: ensure model is downloaded (may take a while on first run)
const MODEL_SIZES: Record<string, string> = {
'tiny': '~75 MB',
@ -294,10 +260,6 @@ export default function App() {
const handleReprocessProject = async () => {
if (!videoPath) return;
if (!window.electronAPI?.transcribe) {
alert('Reprocessing is only available in desktop mode.');
return;
}
await runGuarded(async () => {
setShowReprocessConfirm(true);
@ -428,58 +390,22 @@ export default function App() {
English-only models are ~10% faster and more accurate for English content.
</p>
{IS_ELECTRON ? (
<div className="flex flex-col items-center gap-3">
<button
onClick={handleOpenFile}
className="flex items-center gap-2 px-6 py-3 bg-editor-accent hover:bg-editor-accent-hover rounded-lg text-white font-medium transition-colors"
>
<FolderOpen className="w-5 h-5" />
Open Video File
</button>
<button
onClick={handleLoadProject}
className="flex items-center gap-2 px-4 py-2 text-sm text-editor-text-muted hover:text-editor-text hover:bg-editor-surface rounded-lg transition-colors"
>
<FileInput className="w-4 h-4" />
Load Project (.aive)
</button>
</div>
) : (
/* Browser: manual path input */
<div className="w-full max-w-lg space-y-3">
<div className="flex items-center gap-2 px-3 py-1.5 bg-editor-warning/10 border border-editor-warning/30 rounded-lg">
<span className="text-editor-warning text-xs">
Running in browser paste the full path to your video file below.
</span>
</div>
<form onSubmit={handleManualSubmit} className="flex gap-2">
<div className="flex-1 relative">
<FolderSearch className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-editor-text-muted pointer-events-none" />
<input
ref={fileInputRef}
type="text"
value={manualPath}
onChange={(e) => setManualPath(e.target.value)}
placeholder="C:\Videos\my-video.mp4"
className="w-full pl-9 pr-3 py-2.5 bg-editor-surface border border-editor-border rounded-lg text-sm text-editor-text placeholder:text-editor-text-muted/40 focus:outline-none focus:border-editor-accent"
autoFocus
/>
</div>
<button
type="submit"
disabled={!manualPath.trim()}
className="flex items-center gap-2 px-5 py-2.5 bg-editor-accent hover:bg-editor-accent-hover disabled:opacity-40 rounded-lg text-sm text-white font-medium transition-colors whitespace-nowrap"
>
<Film className="w-4 h-4" />
Load &amp; Transcribe
</button>
</form>
<p className="text-[11px] text-editor-text-muted text-center">
Supported: MP4, AVI, MOV, MKV, WebM, M4A
</p>
</div>
)}
<div className="flex flex-col items-center gap-3">
<button
onClick={handleOpenFile}
className="flex items-center gap-2 px-6 py-3 bg-editor-accent hover:bg-editor-accent-hover rounded-lg text-white font-medium transition-colors"
>
<FolderOpen className="w-5 h-5" />
Open Video File
</button>
<button
onClick={handleLoadProject}
className="flex items-center gap-2 px-4 py-2 text-sm text-editor-text-muted hover:text-editor-text hover:bg-editor-surface rounded-lg transition-colors"
>
<FileInput className="w-4 h-4" />
Load Project (.aive)
</button>
</div>
</div>
);
}
@ -508,23 +434,19 @@ export default function App() {
<ToolbarButton
icon={<FolderOpen className="w-4 h-4" />}
label="Open"
onClick={IS_ELECTRON ? handleOpenFile : () => useEditorStore.getState().reset()}
onClick={handleOpenFile}
/>
<ToolbarButton
icon={<Save className="w-4 h-4" />}
label="Save"
onClick={handleSaveProject}
disabled={words.length === 0}
/>
<ToolbarButton
icon={<FileInput className="w-4 h-4" />}
label="Load"
onClick={handleLoadProject}
/>
{IS_ELECTRON && (
<ToolbarButton
icon={<Save className="w-4 h-4" />}
label="Save"
onClick={handleSaveProject}
disabled={words.length === 0}
/>
)}
{IS_ELECTRON && (
<ToolbarButton
icon={<FileInput className="w-4 h-4" />}
label="Load"
onClick={handleLoadProject}
/>
)}
<ToolbarButton
icon={<Scissors className="w-4 h-4" />}
label="Cut"