const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('electron', { createView: (name, url, imageUrl, zoom, useProxy) => ipcRenderer.send('create-view', name, url, imageUrl, zoom, useProxy), confirm: (text, funcName) => ipcRenderer.send('confirm', text, funcName), removeView: (name) => ipcRenderer.send('remove-view', name), hideView: () => ipcRenderer.send('hide-view'), showView: (name) => ipcRenderer.send('show-view', name), adjustView: (expanded) => ipcRenderer.send('adjust-view', expanded), on: (channel, func) => { const listener = (_event, ...args) => func(...args); ipcRenderer.on(channel, listener); return () => ipcRenderer.removeListener(channel, listener); }, handleAction: (action) => ipcRenderer.send('action', action), setProxy: (host, port) => ipcRenderer.send('set-proxy', host, port), expandWithHeader: () => ipcRenderer.send('expandWithHeader'), collapseWithHeader: () => ipcRenderer.send('collapseWithHeader'), backwardPage: () => ipcRenderer.send('backwardPage'), forwardPage: () => ipcRenderer.send('forwardPage'), refreshPage: () => ipcRenderer.send('refreshPage'), getCurrentPage: () => ipcRenderer.invoke('get-current-page'), getPageMeta: () => ipcRenderer.invoke('get-page-meta'), installUpdate: () => ipcRenderer.invoke('install-update'), checkUpdateNow: () => ipcRenderer.invoke('check-update-now'), readConfig: () => ipcRenderer.invoke('read-config'), writeConfig: (data) => ipcRenderer.send('write-config', data), // Streaming: возвращает unsubscribe(). onResult({ source, results }) вызывается по мере прихода // ответов от каждого сайта; onDone() — когда все сайты ответили. // Слушатели снимаются автоматически после onDone (или вручную через возвращённую функцию). searchMoviesStream: (query, sites, onResult, onDone) => { const searchId = `s_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; let active = true; const cleanup = () => { if (!active) return; active = false; ipcRenderer.removeListener('search-movies-result', resultListener); ipcRenderer.removeListener('search-movies-done', doneListener); }; const resultListener = (_event, payload) => { if (active && payload.searchId === searchId) onResult({ source: payload.source, results: payload.results }); }; const doneListener = (_event, payload) => { if (active && payload.searchId === searchId) { try { onDone(); } finally { cleanup(); } } }; ipcRenderer.on('search-movies-result', resultListener); ipcRenderer.on('search-movies-done', doneListener); ipcRenderer.send('search-movies-start', searchId, query, sites); return cleanup; }, searchTmdb: (query, apiKey) => ipcRenderer.invoke('search-tmdb', query, apiKey), discoverTmdb: (params) => ipcRenderer.invoke('discover-tmdb', params), detectLogo: (siteUrl) => ipcRenderer.invoke('detect-logo', siteUrl), toggleKiosk: () => ipcRenderer.invoke('toggle-kiosk'), isKiosk: () => ipcRenderer.invoke('is-kiosk'), });