/* * SubMiner - All-in-one sentence mining overlay * Copyright (C) 2024 sudacode * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import { contextBridge, ipcRenderer, IpcRendererEvent } from "electron"; import type { SubtitleData, SubtitlePosition, MecabStatus, Keybinding, ElectronAPI, SecondarySubMode, SubtitleStyleConfig, JimakuMediaInfo, JimakuSearchQuery, JimakuFilesQuery, JimakuDownloadQuery, JimakuEntry, JimakuFileEntry, JimakuApiResponse, JimakuDownloadResult, SubsyncManualPayload, SubsyncManualRunRequest, SubsyncResult, KikuFieldGroupingRequestData, KikuFieldGroupingChoice, KikuMergePreviewRequest, KikuMergePreviewResponse, RuntimeOptionApplyResult, RuntimeOptionId, RuntimeOptionState, RuntimeOptionValue, MpvSubtitleRenderMetrics, OverlayContentMeasurement, ShortcutsConfig, } from "./types"; const overlayLayerArg = process.argv.find((arg) => arg.startsWith("--overlay-layer="), ); const overlayLayerFromArg = overlayLayerArg?.slice("--overlay-layer=".length); const overlayLayer = overlayLayerFromArg === "visible" || overlayLayerFromArg === "invisible" ? overlayLayerFromArg : null; const electronAPI: ElectronAPI = { getOverlayLayer: () => overlayLayer, onSubtitle: (callback: (data: SubtitleData) => void) => { ipcRenderer.on( "subtitle:set", (_event: IpcRendererEvent, data: SubtitleData) => callback(data), ); }, onVisibility: (callback: (visible: boolean) => void) => { ipcRenderer.on( "mpv:subVisibility", (_event: IpcRendererEvent, visible: boolean) => callback(visible), ); }, onSubtitlePosition: ( callback: (position: SubtitlePosition | null) => void, ) => { ipcRenderer.on( "subtitle-position:set", (_event: IpcRendererEvent, position: SubtitlePosition | null) => { callback(position); }, ); }, getOverlayVisibility: (): Promise => ipcRenderer.invoke("get-overlay-visibility"), getCurrentSubtitle: (): Promise => ipcRenderer.invoke("get-current-subtitle"), getCurrentSubtitleAss: (): Promise => ipcRenderer.invoke("get-current-subtitle-ass"), getMpvSubtitleRenderMetrics: () => ipcRenderer.invoke("get-mpv-subtitle-render-metrics"), onMpvSubtitleRenderMetrics: ( callback: (metrics: MpvSubtitleRenderMetrics) => void, ) => { ipcRenderer.on( "mpv-subtitle-render-metrics:set", (_event: IpcRendererEvent, metrics: MpvSubtitleRenderMetrics) => { callback(metrics); }, ); }, onSubtitleAss: (callback: (assText: string) => void) => { ipcRenderer.on( "subtitle-ass:set", (_event: IpcRendererEvent, assText: string) => { callback(assText); }, ); }, onOverlayDebugVisualization: (callback: (enabled: boolean) => void) => { ipcRenderer.on( "overlay-debug-visualization:set", (_event: IpcRendererEvent, enabled: boolean) => { callback(enabled); }, ); }, setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => { ipcRenderer.send("set-ignore-mouse-events", ignore, options); }, openYomitanSettings: () => { ipcRenderer.send("open-yomitan-settings"); }, getSubtitlePosition: (): Promise => ipcRenderer.invoke("get-subtitle-position"), saveSubtitlePosition: (position: SubtitlePosition) => { ipcRenderer.send("save-subtitle-position", position); }, getMecabStatus: (): Promise => ipcRenderer.invoke("get-mecab-status"), setMecabEnabled: (enabled: boolean) => { ipcRenderer.send("set-mecab-enabled", enabled); }, sendMpvCommand: (command: (string | number)[]) => { ipcRenderer.send("mpv-command", command); }, getKeybindings: (): Promise => ipcRenderer.invoke("get-keybindings"), getConfiguredShortcuts: (): Promise> => ipcRenderer.invoke("get-config-shortcuts"), getJimakuMediaInfo: (): Promise => ipcRenderer.invoke("jimaku:get-media-info"), jimakuSearchEntries: ( query: JimakuSearchQuery, ): Promise> => ipcRenderer.invoke("jimaku:search-entries", query), jimakuListFiles: ( query: JimakuFilesQuery, ): Promise> => ipcRenderer.invoke("jimaku:list-files", query), jimakuDownloadFile: ( query: JimakuDownloadQuery, ): Promise => ipcRenderer.invoke("jimaku:download-file", query), quitApp: () => { ipcRenderer.send("quit-app"); }, toggleDevTools: () => { ipcRenderer.send("toggle-dev-tools"); }, toggleOverlay: () => { ipcRenderer.send("toggle-overlay"); }, getAnkiConnectStatus: (): Promise => ipcRenderer.invoke("get-anki-connect-status"), setAnkiConnectEnabled: (enabled: boolean) => { ipcRenderer.send("set-anki-connect-enabled", enabled); }, clearAnkiConnectHistory: () => { ipcRenderer.send("clear-anki-connect-history"); }, onSecondarySub: (callback: (text: string) => void) => { ipcRenderer.on( "secondary-subtitle:set", (_event: IpcRendererEvent, text: string) => callback(text), ); }, onSecondarySubMode: (callback: (mode: SecondarySubMode) => void) => { ipcRenderer.on( "secondary-subtitle:mode", (_event: IpcRendererEvent, mode: SecondarySubMode) => callback(mode), ); }, getSecondarySubMode: (): Promise => ipcRenderer.invoke("get-secondary-sub-mode"), getCurrentSecondarySub: (): Promise => ipcRenderer.invoke("get-current-secondary-sub"), focusMainWindow: () => ipcRenderer.invoke("focus-main-window") as Promise, getSubtitleStyle: (): Promise => ipcRenderer.invoke("get-subtitle-style"), onSubsyncManualOpen: (callback: (payload: SubsyncManualPayload) => void) => { ipcRenderer.on( "subsync:open-manual", (_event: IpcRendererEvent, payload: SubsyncManualPayload) => { callback(payload); }, ); }, runSubsyncManual: ( request: SubsyncManualRunRequest, ): Promise => ipcRenderer.invoke("subsync:run-manual", request), onKikuFieldGroupingRequest: ( callback: (data: KikuFieldGroupingRequestData) => void, ) => { ipcRenderer.on( "kiku:field-grouping-request", (_event: IpcRendererEvent, data: KikuFieldGroupingRequestData) => callback(data), ); }, kikuBuildMergePreview: ( request: KikuMergePreviewRequest, ): Promise => ipcRenderer.invoke("kiku:build-merge-preview", request), kikuFieldGroupingRespond: (choice: KikuFieldGroupingChoice) => { ipcRenderer.send("kiku:field-grouping-respond", choice); }, getRuntimeOptions: (): Promise => ipcRenderer.invoke("runtime-options:get"), setRuntimeOptionValue: ( id: RuntimeOptionId, value: RuntimeOptionValue, ): Promise => ipcRenderer.invoke("runtime-options:set", id, value), cycleRuntimeOption: ( id: RuntimeOptionId, direction: 1 | -1, ): Promise => ipcRenderer.invoke("runtime-options:cycle", id, direction), onRuntimeOptionsChanged: ( callback: (options: RuntimeOptionState[]) => void, ) => { ipcRenderer.on( "runtime-options:changed", (_event: IpcRendererEvent, options: RuntimeOptionState[]) => { callback(options); }, ); }, onOpenRuntimeOptions: (callback: () => void) => { ipcRenderer.on("runtime-options:open", () => { callback(); }); }, onOpenJimaku: (callback: () => void) => { ipcRenderer.on("jimaku:open", () => { callback(); }); }, notifyOverlayModalClosed: (modal: "runtime-options" | "subsync" | "jimaku") => { ipcRenderer.send("overlay:modal-closed", modal); }, reportOverlayContentBounds: (measurement: OverlayContentMeasurement) => { ipcRenderer.send("overlay-content-bounds:report", measurement); }, }; contextBridge.exposeInMainWorld("electronAPI", electronAPI);