Files
church-translate/app/preload.js
T
christianandClaude Opus 5 c9eef0672c Church Translate, as it runs at the campuses
Live sermon translation into 100+ languages, running entirely on one Mac per
campus: audio in, voice detection, Whisper on the GPU, NLLB-200 in its own
process, and a built-in web server the congregation reads from on their
phones. No audio leaves the building.

This is the source only. What used to sit beside it — 14 GB of speech and
translation models, 8 GB of voice bundles, 6 GB of natural voices, the Electron
caches, and the app data holding the operator PIN and every service transcript
— is machine state and downloaded assets, and stays in the NAS backup where it
belongs. The vendored node, cloudflared and Windows ffmpeg binaries are out too
(533 MB, re-fetched for packaging); the browser-side runtime beside them is
kept, so a checkout still serves the congregation page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 15:41:21 -04:00

58 lines
3.2 KiB
JavaScript

/*
* preload.js — the only bridge between the renderer and Node.
* Nothing here takes a path or a command from the page; every call is a fixed
* verb with no free-form arguments beyond a config patch.
*/
'use strict';
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('engineHost', {
getConfig: () => ipcRenderer.invoke('config:get'),
setConfig: (patch) => ipcRenderer.invoke('config:set', patch),
micStatus: () => ipcRenderer.invoke('mic:status'),
askMic: () => ipcRenderer.invoke('mic:ask'),
openPrivacy: () => ipcRenderer.invoke('app:openPrivacy'),
cacheInfo: () => ipcRenderer.invoke('app:cacheInfo'),
revealCache: () => ipcRenderer.invoke('app:revealCache'),
copyText: (text) => ipcRenderer.invoke('app:copy', text),
setLive: (live) => ipcRenderer.send('engine:live', !!live),
logLine: (line) => ipcRenderer.send('log:line', String(line || '')),
/* Translation lives in the main process; these are its only two verbs. */
mtEnsure: () => ipcRenderer.invoke('mt:ensure'),
settingsExport: () => ipcRenderer.invoke('settings:export'),
settingsImport: () => ipcRenderer.invoke('settings:import'),
audioDevices: () => ipcRenderer.invoke('audio:devices'),
modelsCached: (id) => ipcRenderer.invoke('models:cached', id),
mtTranslate: (req) => ipcRenderer.invoke('mt:translate', req),
mtTranslateMulti: (req) => ipcRenderer.invoke('mt:translateMulti', req),
onMtProgress: (fn) => ipcRenderer.on('mt:progress', (_e, p) => fn(p)),
onMtDown: (fn) => ipcRenderer.on('mt:down', (_e, info) => fn(info)),
/* The congregation server runs inside this app; these describe it. */
localInfo: () => ipcRenderer.invoke('local:info'),
onServerUp: (fn) => ipcRenderer.on('server:up', (_e, info) => fn(info)),
onServerDown: (fn) => ipcRenderer.on('server:down', () => fn()),
/* Share to the internet: a Cloudflare quick tunnel for livestream viewers. */
tunnelStart: () => ipcRenderer.invoke('tunnel:start'),
tunnelStop: () => ipcRenderer.invoke('tunnel:stop'),
tunnelStatus: () => ipcRenderer.invoke('tunnel:status'),
onTunnel: (fn) => ipcRenderer.on('tunnel:status', (_e, s) => fn(s)),
/* Built-in voices: this Mac speaks, and the phones play what it sends. */
ttsInfo: () => ipcRenderer.invoke('tts:info'),
ttsSpeak: (req) => ipcRenderer.invoke('tts:speak', req),
ttsPreload: (langs) => ipcRenderer.invoke('tts:preload', langs),
/* Audition one specific voice, and save the per-language choices. */
ttsAudition: (req) => ipcRenderer.invoke('tts:audition', req),
ttsSetVoices: (c) => ipcRenderer.invoke('tts:setVoices', c),
ttsSetListenerVoices: (m) => ipcRenderer.invoke('tts:setListenerVoices', m),
onTtsReady: (fn) => ipcRenderer.on('tts:ready', (_e, i) => fn(i)),
onTtsProgress: (fn) => ipcRenderer.on('tts:progress', (_e, p) => fn(p)),
onTtsCloud: (fn) => ipcRenderer.on('tts:cloud', (_e, s) => fn(s)),
onLocalVoices: (fn) => ipcRenderer.on('localvoices:status', (_e, s) => fn(s)),
localVoicesStatus: () => ipcRenderer.invoke('localvoices:status')
});