removed electron

This commit is contained in:
2026-04-07 23:08:27 -06:00
parent d80ff847d8
commit e25f8a9b63
20 changed files with 96 additions and 363 deletions

View File

@ -22,7 +22,7 @@ import {
VolumeX,
} from 'lucide-react';
const IS_ELECTRON = !!window.electronAPI;
const IS_DESKTOP = !!window.desktopAPI;
type Panel = 'ai' | 'settings' | 'export' | 'silence' | null;
@ -66,8 +66,8 @@ export default function App() {
}, []);
useEffect(() => {
if (IS_ELECTRON) {
window.electronAPI!.getBackendUrl().then(setBackendUrl);
if (IS_DESKTOP) {
window.desktopAPI!.getBackendUrl().then(setBackendUrl);
}
// In Tauri on Linux/WebKit2GTK the ipc:// custom protocol is blocked by
// WebKit internals; postMessage fallback works but logs noisy warnings.
@ -75,11 +75,11 @@ export default function App() {
}, [setBackendUrl]);
const handleLoadProject = async () => {
if (!IS_ELECTRON) return;
if (!IS_DESKTOP) return;
try {
const projectPath = await window.electronAPI!.openProject();
const projectPath = await window.desktopAPI!.openProject();
if (!projectPath) return;
const content = await window.electronAPI!.readFile(projectPath);
const content = await window.desktopAPI!.readFile(projectPath);
const data = JSON.parse(content);
useEditorStore.getState().loadProject(data);
} catch (err) {
@ -89,13 +89,13 @@ export default function App() {
};
const handleSaveProject = async () => {
if (!IS_ELECTRON) return;
if (!IS_DESKTOP) return;
try {
const savePath = await window.electronAPI!.saveProject();
const savePath = await window.desktopAPI!.saveProject();
if (!savePath) return;
const data = useEditorStore.getState().saveProject();
const path = savePath.endsWith('.aive') ? savePath : `${savePath}.aive`;
await window.electronAPI!.writeFile(path, JSON.stringify(data, null, 2));
await window.desktopAPI!.writeFile(path, JSON.stringify(data, null, 2));
} catch (err) {
console.error('Failed to save project:', err);
alert(`Failed to save project: ${err}`);
@ -103,8 +103,8 @@ export default function App() {
};
const handleOpenFile = async () => {
if (IS_ELECTRON) {
const path = await window.electronAPI!.openFile();
if (IS_DESKTOP) {
const path = await window.desktopAPI!.openFile();
if (path) {
loadVideo(path);
await transcribeVideo(path);
@ -130,7 +130,7 @@ export default function App() {
const transcribeVideo = async (path: string) => {
setTranscribing(true, 0, 'Checking model...');
try {
if (!window.electronAPI?.transcribe) {
if (!window.desktopAPI?.transcribe) {
throw new Error('Transcription not available');
}
// Step 1: ensure model is downloaded (may take a while on first run)
@ -153,11 +153,11 @@ export default function App() {
};
const modelLabel = MODEL_SIZES[whisperModel] ?? 'unknown size';
setTranscribing(true, 5, `Downloading ${whisperModel} model (${modelLabel})...`);
await window.electronAPI.ensureModel(whisperModel);
await window.desktopAPI.ensureModel(whisperModel);
// Step 2: run transcription
setTranscribing(true, 20, 'Transcribing audio...');
const data = await window.electronAPI.transcribe(path, whisperModel);
const data = await window.desktopAPI.transcribe(path, whisperModel);
setTranscription(data);
} catch (err) {
console.error('Transcription error:', err);
@ -243,7 +243,7 @@ export default function App() {
English-only models are ~10% faster and more accurate for English content.
</p>
{IS_ELECTRON ? (
{IS_DESKTOP ? (
<div className="flex flex-col items-center gap-3">
<button
onClick={handleOpenFile}
@ -313,9 +313,9 @@ export default function App() {
<ToolbarButton
icon={<FolderOpen className="w-4 h-4" />}
label="Open"
onClick={IS_ELECTRON ? handleOpenFile : () => useEditorStore.getState().reset()}
onClick={IS_DESKTOP ? handleOpenFile : () => useEditorStore.getState().reset()}
/>
{IS_ELECTRON && (
{IS_DESKTOP && (
<ToolbarButton
icon={<Save className="w-4 h-4" />}
label="Save"
@ -323,7 +323,7 @@ export default function App() {
disabled={words.length === 0}
/>
)}
{IS_ELECTRON && (
{IS_DESKTOP && (
<ToolbarButton
icon={<FileInput className="w-4 h-4" />}
label="Load"

View File

@ -20,7 +20,7 @@ export default function ExportDialog() {
const handleExport = useCallback(async () => {
if (!videoPath) return;
const outputPath = await window.electronAPI?.saveFile({
const outputPath = await window.desktopAPI?.saveFile({
defaultPath: videoPath.replace(/\.[^.]+$/, '_edited.mp4'),
filters: [
{ name: 'MP4', extensions: ['mp4'] },

View File

@ -167,14 +167,14 @@ async function saveProject() {
modifiedAt: new Date().toISOString(),
};
const outputPath = await window.electronAPI?.saveFile({
const outputPath = await window.desktopAPI?.saveFile({
defaultPath: state.videoPath.replace(/\.[^.]+$/, '.aive'),
filters: [{ name: 'TalkEdit Project', extensions: ['aive'] }],
});
if (outputPath) {
if (window.electronAPI?.writeFile) {
await window.electronAPI.writeFile(outputPath, JSON.stringify(projectData, null, 2));
if (window.desktopAPI?.writeFile) {
await window.desktopAPI.writeFile(outputPath, JSON.stringify(projectData, null, 2));
} else {
const blob = new Blob([JSON.stringify(projectData, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);

View File

@ -1,8 +1,8 @@
/**
* tauri-bridge.ts
*
* Polyfills window.electronAPI with Tauri equivalents so all existing
* call-sites in App.tsx, hooks, and stores continue to work unchanged.
* Exposes window.desktopAPI using Tauri equivalents so UI code can stay
* desktop-runtime agnostic.
*
* Imported once at the top of main.tsx.
*/
@ -25,7 +25,10 @@ const EXPORT_FILTERS = [
{ name: 'Project Files', extensions: ['aive'] },
];
window.electronAPI = {
const BACKEND_PORT = import.meta.env.VITE_BACKEND_PORT || '8000';
const BACKEND_URL = `http://127.0.0.1:${BACKEND_PORT}`;
window.desktopAPI = {
openFile: async (_options?: Record<string, unknown>): Promise<string | null> => {
const result = await open({
multiple: false,
@ -53,8 +56,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');
// Use env-driven backend URL and avoid invoke() to bypass ipc:// noise on Linux/WebKit2GTK.
return Promise.resolve(BACKEND_URL);
},
encryptString: (data: string): Promise<string> => {

View File

@ -2,7 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
// Forward console.error/warn/log to backend in dev mode so we can tail webview.log
import './lib/dev-logger';
// Must be imported before App so window.electronAPI is patched before any component runs.
// Must be imported before App so window.desktopAPI is patched before any component runs.
import './lib/tauri-bridge';
import App from './App';
import './index.css';

View File

@ -30,8 +30,8 @@ async function encryptAndStore(key: string, value: string): Promise<void> {
localStorage.removeItem(ENCRYPTED_KEY_PREFIX + key);
return;
}
if (window.electronAPI) {
const encrypted = await window.electronAPI.encryptString(value);
if (window.desktopAPI) {
const encrypted = await window.desktopAPI.encryptString(value);
localStorage.setItem(ENCRYPTED_KEY_PREFIX + key, encrypted);
} else {
localStorage.setItem(ENCRYPTED_KEY_PREFIX + key, btoa(value));
@ -41,9 +41,9 @@ async function encryptAndStore(key: string, value: string): Promise<void> {
async function loadAndDecrypt(key: string): Promise<string> {
const stored = localStorage.getItem(ENCRYPTED_KEY_PREFIX + key);
if (!stored) return '';
if (window.electronAPI) {
if (window.desktopAPI) {
try {
return await window.electronAPI.decryptString(stored);
return await window.desktopAPI.decryptString(stored);
} catch {
return '';
}

View File

@ -1,6 +1,10 @@
/// <reference types="vite/client" />
interface ElectronAPI {
interface ImportMetaEnv {
readonly VITE_BACKEND_PORT?: string;
}
interface DesktopAPI {
openFile: (options?: Record<string, unknown>) => Promise<string | null>;
saveFile: (options?: Record<string, unknown>) => Promise<string | null>;
openProject: () => Promise<string | null>;
@ -15,5 +19,5 @@ interface ElectronAPI {
}
interface Window {
electronAPI?: ElectronAPI;
desktopAPI?: DesktopAPI;
}