From 7909fcd2cfde9a9a023d03a306628fe0aeeed395 Mon Sep 17 00:00:00 2001 From: sudacode Date: Mon, 12 Oct 2026 22:11:17 -0700 Subject: [PATCH] refactor(ipc): remove dead preload methods and the ASS line broadcast (#293) Drop 16 overlay preload methods with no caller (onSubtitleAss, getCurrentSubtitleAss, onVisibility, getOverlayVisibility, openYomitanSettings, quitApp, toggleOverlay, getMecabStatus, setMecabEnabled, getKeybindings, saveControllerPreference, getAnkiConnectStatus, setAnkiConnectEnabled, clearAnkiConnectHistory, cycleRuntimeOption, appendClipboardVideoToQueue) along with their IPC_CHANNELS keys, handlers, validators and dep plumbing. With both ASS consumers gone, stop observing sub-text/ass in mpv and remove the subtitle-ass-change event chain and appState.currentSubAssText. The main-process functions these wrapped stay; tray, CLI, shortcuts and session actions still use them. --- changes/remove-dead-ipc.md | 4 + src/core/services/anki-jimaku-ipc.test.ts | 13 -- src/core/services/anki-jimaku-ipc.ts | 11 - src/core/services/anki-jimaku.test.ts | 55 +---- src/core/services/anki-jimaku.ts | 87 +------ src/core/services/ipc.test.ts | 213 ------------------ src/core/services/ipc.ts | 124 ---------- src/core/services/mpv-properties.ts | 6 - src/core/services/mpv-protocol.test.ts | 23 -- src/core/services/mpv-protocol.ts | 6 - src/core/services/mpv.test.ts | 13 -- src/core/services/mpv.ts | 4 - src/core/services/runtime-options-ipc.test.ts | 19 -- src/core/services/runtime-options-ipc.ts | 16 -- src/main.ts | 50 ---- src/main/dependencies.ts | 63 +----- src/main/ipc-runtime.ts | 3 +- src/main/main-wiring.test.ts | 1 - .../composers/mpv-runtime-composer.test.ts | 1 - src/main/runtime/mpv-client-event-bindings.ts | 3 - src/main/runtime/mpv-main-event-actions.ts | 10 - .../runtime/mpv-main-event-bindings.test.ts | 2 - src/main/runtime/mpv-main-event-bindings.ts | 8 - .../runtime/mpv-main-event-main-deps.test.ts | 1 - src/main/runtime/mpv-main-event-main-deps.ts | 6 - src/main/state.ts | 2 - src/mecab-tokenizer.ts | 23 -- src/preload.ts | 59 ----- src/renderer/handlers/keyboard.test.ts | 1 - src/shared/ipc/contracts.ts | 21 -- src/shared/ipc/validators.ts | 15 -- src/types/runtime.ts | 21 -- 32 files changed, 8 insertions(+), 876 deletions(-) create mode 100644 changes/remove-dead-ipc.md diff --git a/changes/remove-dead-ipc.md b/changes/remove-dead-ipc.md new file mode 100644 index 00000000..5b8146e7 --- /dev/null +++ b/changes/remove-dead-ipc.md @@ -0,0 +1,4 @@ +type: internal +area: overlay + +- Removed 16 overlay preload/IPC methods that nothing called, plus their main-process handlers. SubMiner no longer observes mpv's `sub-text/ass` or sends every ASS line to overlay windows that never listened. diff --git a/src/core/services/anki-jimaku-ipc.test.ts b/src/core/services/anki-jimaku-ipc.test.ts index b189206d..0765ab4e 100644 --- a/src/core/services/anki-jimaku-ipc.test.ts +++ b/src/core/services/anki-jimaku-ipc.test.ts @@ -32,8 +32,6 @@ test('anki/jimaku IPC handlers reject malformed invoke payloads', async () => { let previewCalls = 0; registerAnkiJimakuIpcHandlers( { - setAnkiConnectEnabled: () => {}, - clearAnkiHistory: () => {}, refreshKnownWords: async () => {}, respondFieldGrouping: () => {}, buildKikuMergePreview: async () => { @@ -138,8 +136,6 @@ test('tsukihime downloads always route Japanese as primary', async () => { const secondaryLoads: string[] = []; registerAnkiJimakuIpcHandlers( { - setAnkiConnectEnabled: () => {}, - clearAnkiHistory: () => {}, refreshKnownWords: async () => {}, respondFieldGrouping: () => {}, buildKikuMergePreview: async () => ({ ok: true }), @@ -205,13 +201,8 @@ test('tsukihime downloads always route Japanese as primary', async () => { test('anki/jimaku IPC command handlers ignore malformed payloads', () => { const { registrar, onHandlers } = createFakeRegistrar(); const fieldGroupingChoices: unknown[] = []; - const enabledStates: boolean[] = []; registerAnkiJimakuIpcHandlers( { - setAnkiConnectEnabled: (enabled) => { - enabledStates.push(enabled); - }, - clearAnkiHistory: () => {}, refreshKnownWords: async () => {}, respondFieldGrouping: (choice) => { fieldGroupingChoices.push(choice); @@ -241,10 +232,6 @@ test('anki/jimaku IPC command handlers ignore malformed payloads', () => { registrar, ); - onHandlers.get(IPC_CHANNELS.command.setAnkiConnectEnabled)!({}, 'true'); - onHandlers.get(IPC_CHANNELS.command.setAnkiConnectEnabled)!({}, true); - assert.deepEqual(enabledStates, [true]); - onHandlers.get(IPC_CHANNELS.command.kikuFieldGroupingRespond)!({}, null); onHandlers.get(IPC_CHANNELS.command.kikuFieldGroupingRespond)!( {}, diff --git a/src/core/services/anki-jimaku-ipc.ts b/src/core/services/anki-jimaku-ipc.ts index d4270234..d409e33f 100644 --- a/src/core/services/anki-jimaku-ipc.ts +++ b/src/core/services/anki-jimaku-ipc.ts @@ -40,8 +40,6 @@ const { ipcMain } = electron; const logger = createLogger('main:anki-jimaku-ipc'); export interface AnkiJimakuIpcDeps { - setAnkiConnectEnabled: (enabled: boolean) => void; - clearAnkiHistory: () => void; refreshKnownWords: () => Promise | void; respondFieldGrouping: (choice: KikuFieldGroupingChoice) => void; buildKikuMergePreview: (request: KikuMergePreviewRequest) => Promise; @@ -77,15 +75,6 @@ export function registerAnkiJimakuIpcHandlers( deps: AnkiJimakuIpcDeps, ipc: IpcMainRegistrar = ipcMain, ): void { - ipc.on(IPC_CHANNELS.command.setAnkiConnectEnabled, (_event: unknown, enabled: unknown) => { - if (typeof enabled !== 'boolean') return; - deps.setAnkiConnectEnabled(enabled); - }); - - ipc.on(IPC_CHANNELS.command.clearAnkiConnectHistory, () => { - deps.clearAnkiHistory(); - }); - ipc.on(IPC_CHANNELS.command.refreshKnownWords, async () => { await deps.refreshKnownWords(); }); diff --git a/src/core/services/anki-jimaku.test.ts b/src/core/services/anki-jimaku.test.ts index c1bf42e0..800163d5 100644 --- a/src/core/services/anki-jimaku.test.ts +++ b/src/core/services/anki-jimaku.test.ts @@ -8,8 +8,6 @@ interface RuntimeHarness { state: { ankiIntegration: unknown; fieldGroupingResolver: ((choice: unknown) => void) | null; - patches: boolean[]; - broadcasts: number; fetchCalls: Array<{ endpoint: string; query?: Record }>; tsukihimeFetchCalls: Array<{ endpoint: string; query?: Record }>; sentCommands: Array<{ command: (string | number)[] }>; @@ -20,8 +18,6 @@ function createHarness(): RuntimeHarness { const state = { ankiIntegration: null as unknown, fieldGroupingResolver: null as ((choice: unknown) => void) | null, - patches: [] as boolean[], - broadcasts: 0, fetchCalls: [] as Array<{ endpoint: string; query?: Record; @@ -34,11 +30,7 @@ function createHarness(): RuntimeHarness { }; const options: AnkiJimakuIpcRuntimeOptions = { - patchAnkiConnectEnabled: (enabled) => { - state.patches.push(enabled); - }, getResolvedConfig: () => ({ tsukihime: { maxSearchResults: 2 } }), - getRuntimeOptionsManager: () => null, tsukihimeFetchJson: async (endpoint, query) => { state.tsukihimeFetchCalls.push({ endpoint, @@ -76,7 +68,6 @@ function createHarness(): RuntimeHarness { } as never, }; }, - getSubtitleTimingTracker: () => null, getMpvClient: () => ({ connected: true, send: (payload) => { @@ -99,20 +90,6 @@ function createHarness(): RuntimeHarness { }, }), getAnkiIntegration: () => state.ankiIntegration as never, - setAnkiIntegration: (integration) => { - state.ankiIntegration = integration; - }, - getKnownWordCacheStatePath: () => '/tmp/subminer-known-words-cache.json', - showDesktopNotification: () => {}, - createFieldGroupingCallback: () => async () => ({ - keepNoteId: 1, - deleteNoteId: 2, - deleteDuplicate: false, - cancelled: false, - }), - broadcastRuntimeOptionsChanged: () => { - state.broadcasts += 1; - }, getFieldGroupingResolver: () => state.fieldGroupingResolver as never, setFieldGroupingResolver: (resolver) => { state.fieldGroupingResolver = resolver as never; @@ -169,51 +146,21 @@ test('refreshKnownWords throws when integration is unavailable', async () => { ); }); -test('setAnkiConnectEnabled disables active integration and broadcasts changes', () => { +test('respondFieldGrouping resolves and clears the pending resolver', () => { const { registered, state } = createHarness(); - let destroyed = 0; - state.ankiIntegration = { - destroy: () => { - destroyed += 1; - }, - }; - - registered.setAnkiConnectEnabled!(false); - - assert.deepEqual(state.patches, [false]); - assert.equal(destroyed, 1); - assert.equal(state.ankiIntegration, null); - assert.equal(state.broadcasts, 1); -}); - -test('clearAnkiHistory and respondFieldGrouping execute runtime callbacks', () => { - const { registered, state, options } = createHarness(); - let cleaned = 0; let resolvedChoice: unknown = null; state.fieldGroupingResolver = (choice) => { resolvedChoice = choice; }; - const originalGetTracker = options.getSubtitleTimingTracker; - options.getSubtitleTimingTracker = () => - ({ - cleanup: () => { - cleaned += 1; - }, - }) as never; - const choice = { keepNoteId: 10, deleteNoteId: 11, deleteDuplicate: true, cancelled: false, }; - registered.clearAnkiHistory!(); registered.respondFieldGrouping!(choice); - options.getSubtitleTimingTracker = originalGetTracker; - - assert.equal(cleaned, 1); assert.deepEqual(resolvedChoice, choice); assert.equal(state.fieldGroupingResolver, null); }); diff --git a/src/core/services/anki-jimaku.ts b/src/core/services/anki-jimaku.ts index 8ac3e47b..2295d565 100644 --- a/src/core/services/anki-jimaku.ts +++ b/src/core/services/anki-jimaku.ts @@ -1,19 +1,14 @@ import * as fs from 'fs'; -import { AnkiIntegration } from '../../anki-integration'; -import { mergeAiConfig } from '../../ai/config'; +import type { AnkiIntegration } from '../../anki-integration'; import { - AiConfig, TsukihimeApiResponse, TsukihimeConfig, - AnkiConnectConfig, JimakuApiResponse, JimakuEntry, JimakuFileEntry, JimakuLanguagePreference, JimakuMediaInfo, KikuFieldGroupingChoice, - KikuFieldGroupingRequestData, - OverlayNotificationPayload, } from '../../types'; import { sortJimakuFiles } from '../../jimaku/utils'; import { @@ -35,41 +30,13 @@ interface MpvClientLike { request?: (command: unknown[]) => Promise<{ data?: unknown }>; } -interface RuntimeOptionsManagerLike { - getEffectiveAnkiConnectConfig: (config?: AnkiConnectConfig) => AnkiConnectConfig; -} - -interface SubtitleTimingTrackerLike { - cleanup: () => void; -} - export interface AnkiJimakuIpcRuntimeOptions { - patchAnkiConnectEnabled: (enabled: boolean) => void; getResolvedConfig: () => { - ankiConnect?: AnkiConnectConfig; - ai?: AiConfig; tsukihime?: TsukihimeConfig; secondarySub?: { secondarySubLanguages?: string[] }; }; - getRuntimeOptionsManager: () => RuntimeOptionsManagerLike | null; - getSubtitleTimingTracker: () => SubtitleTimingTrackerLike | null; getMpvClient: () => MpvClientLike | null; getAnkiIntegration: () => AnkiIntegration | null; - setAnkiIntegration: (integration: AnkiIntegration | null) => void; - getKnownWordCacheStatePath: () => string; - getCachedMediaPath?: ( - currentVideoPath: string, - kind: 'audio' | 'video', - ) => Promise; - shouldRequireRemoteMediaCache?: () => boolean; - getYoutubeMediaSourceUrl?: () => Promise | string | null | undefined; - showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; - showOverlayNotification?: (payload: OverlayNotificationPayload) => void; - dismissOverlayNotification?: (id: string) => void; - createFieldGroupingCallback: () => ( - data: KikuFieldGroupingRequestData, - ) => Promise; - broadcastRuntimeOptionsChanged: () => void; getFieldGroupingResolver: () => ((choice: KikuFieldGroupingChoice) => void) | null; setFieldGroupingResolver: (resolver: ((choice: KikuFieldGroupingChoice) => void) | null) => void; parseMediaInfo: (mediaPath: string | null) => JimakuMediaInfo; @@ -135,58 +102,6 @@ export function registerAnkiJimakuIpcRuntime( registerHandlers: RegisterAnkiJimakuIpcRuntimeHandler, ): void { registerHandlers({ - setAnkiConnectEnabled: (enabled) => { - options.patchAnkiConnectEnabled(enabled); - const config = options.getResolvedConfig(); - const subtitleTimingTracker = options.getSubtitleTimingTracker(); - const mpvClient = options.getMpvClient(); - const ankiIntegration = options.getAnkiIntegration(); - - if (enabled && !ankiIntegration && subtitleTimingTracker && mpvClient) { - const runtimeOptionsManager = options.getRuntimeOptionsManager(); - const effectiveAnkiConfig = runtimeOptionsManager - ? runtimeOptionsManager.getEffectiveAnkiConnectConfig(config.ankiConnect) - : config.ankiConnect; - const integration = new AnkiIntegration( - effectiveAnkiConfig as never, - subtitleTimingTracker as never, - mpvClient as never, - (text: string) => { - if (mpvClient) { - mpvClient.send({ - command: ['show-text', text, '3000'], - }); - } - }, - options.showDesktopNotification, - options.createFieldGroupingCallback(), - options.getKnownWordCacheStatePath(), - mergeAiConfig(config.ai, config.ankiConnect?.ai) as AiConfig, - undefined, - options.showOverlayNotification, - options.getCachedMediaPath, - options.shouldRequireRemoteMediaCache, - options.getYoutubeMediaSourceUrl, - options.dismissOverlayNotification, - ); - integration.start(); - options.setAnkiIntegration(integration); - logger.info('AnkiConnect integration enabled'); - } else if (!enabled && ankiIntegration) { - ankiIntegration.destroy(); - options.setAnkiIntegration(null); - logger.info('AnkiConnect integration disabled'); - } - - options.broadcastRuntimeOptionsChanged(); - }, - clearAnkiHistory: () => { - const subtitleTimingTracker = options.getSubtitleTimingTracker(); - if (subtitleTimingTracker) { - subtitleTimingTracker.cleanup(); - logger.info('AnkiConnect subtitle timing history cleared'); - } - }, refreshKnownWords: async () => { const integration = options.getAnkiIntegration(); if (!integration) { diff --git a/src/core/services/ipc.test.ts b/src/core/services/ipc.test.ts index c6e6e118..f6d8192e 100644 --- a/src/core/services/ipc.test.ts +++ b/src/core/services/ipc.test.ts @@ -114,23 +114,15 @@ function createSubtitleSidebarSnapshotFixture(): SubtitleSidebarSnapshot { function createRegisterIpcDeps(overrides: Partial = {}): IpcServiceDeps { return { onOverlayModalClosed: () => {}, - openYomitanSettings: () => {}, - quitApp: () => {}, toggleDevTools: () => {}, - getVisibleOverlayVisibility: () => false, - toggleVisibleOverlay: () => {}, tokenizeCurrentSubtitle: async () => null, getCurrentSubtitleRaw: () => '', - getCurrentSubtitleAss: () => '', getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), getPlaybackPaused: () => false, getSubtitlePosition: () => null, getSubtitleStyle: () => null, saveSubtitlePosition: () => {}, - getMecabStatus: () => ({ available: false, enabled: false, path: null }), - setMecabEnabled: () => {}, handleMpvCommand: () => {}, - getKeybindings: () => [], getSessionBindings: () => [], getConfiguredShortcuts: () => ({}), dispatchSessionAction: async () => {}, @@ -139,23 +131,19 @@ function createRegisterIpcDeps(overrides: Partial = {}): IpcServ getOverlayNotificationPosition: () => 'top-right', getControllerConfig: () => createControllerConfigFixture(), saveControllerConfig: async () => {}, - saveControllerPreference: async () => {}, getSecondarySubMode: () => 'hover', getCurrentSecondarySub: () => '', focusMainWindow: () => {}, activatePlaybackWindowForOverlayInteraction: () => false, runSubsyncManual: async () => ({ ok: true, message: 'ok' }), - getAnkiConnectStatus: () => false, getRuntimeOptions: () => [], setRuntimeOption: () => ({ ok: true }), - cycleRuntimeOption: () => ({ ok: true }), reportOverlayContentBounds: () => {}, getAnilistStatus: () => ({}), clearAnilistToken: () => {}, openAnilistSetup: () => {}, getAnilistQueueStatus: () => ({}), retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }), - appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }), getPlaylistBrowserSnapshot: async () => ({ directoryPath: null, directoryAvailable: false, @@ -312,26 +300,17 @@ test('registerIpcHandlers skips AniList update when manual mark watched has no a test('registerIpcHandlers rejects malformed runtime-option payloads', async () => { const { registrar, handlers } = createFakeIpcRegistrar(); const calls: Array<{ id: string; value: unknown }> = []; - const cycles: Array<{ id: string; direction: 1 | -1 }> = []; registerIpcHandlers( { onOverlayModalClosed: () => {}, - openYomitanSettings: () => {}, - quitApp: () => {}, toggleDevTools: () => {}, - getVisibleOverlayVisibility: () => false, - toggleVisibleOverlay: () => {}, tokenizeCurrentSubtitle: async () => null, getCurrentSubtitleRaw: () => '', - getCurrentSubtitleAss: () => '', getPlaybackPaused: () => null, getSubtitlePosition: () => null, getSubtitleStyle: () => null, saveSubtitlePosition: () => {}, - getMecabStatus: () => ({ available: false, enabled: false, path: null }), - setMecabEnabled: () => {}, handleMpvCommand: () => {}, - getKeybindings: () => [], getSessionBindings: () => [], getConfiguredShortcuts: () => ({}), dispatchSessionAction: async () => {}, @@ -340,21 +319,15 @@ test('registerIpcHandlers rejects malformed runtime-option payloads', async () = getOverlayNotificationPosition: () => 'top-right', getControllerConfig: () => createControllerConfigFixture(), saveControllerConfig: () => {}, - saveControllerPreference: () => {}, getSecondarySubMode: () => 'hover', getCurrentSecondarySub: () => '', focusMainWindow: () => {}, runSubsyncManual: async () => ({ ok: true, message: 'ok' }), - getAnkiConnectStatus: () => false, getRuntimeOptions: () => [], setRuntimeOption: (id, value) => { calls.push({ id, value }); return { ok: true }; }, - cycleRuntimeOption: (id, direction) => { - cycles.push({ id, direction }); - return { ok: true }; - }, getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), reportOverlayContentBounds: () => {}, getAnilistStatus: () => ({}), @@ -362,7 +335,6 @@ test('registerIpcHandlers rejects malformed runtime-option payloads', async () = openAnilistSetup: () => {}, getAnilistQueueStatus: () => ({}), retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }), - appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }), getPlaylistBrowserSnapshot: async () => ({ directoryPath: null, directoryAvailable: false, @@ -399,16 +371,6 @@ test('registerIpcHandlers rejects malformed runtime-option payloads', async () = { id: 'subtitle.annotation.jlpt', value: false }, ]); - const cycleHandler = handlers.handle.get(IPC_CHANNELS.request.cycleRuntimeOption); - assert.ok(cycleHandler); - const invalidDirection = await cycleHandler!({}, 'anki.kikuFieldGrouping', 2); - assert.deepEqual(invalidDirection, { - ok: false, - error: 'Invalid runtime option cycle direction', - }); - await cycleHandler!({}, 'anki.kikuFieldGrouping', -1); - assert.deepEqual(cycles, [{ id: 'anki.kikuFieldGrouping', direction: -1 }]); - const getPlaybackPausedHandler = handlers.handle.get(IPC_CHANNELS.request.getPlaybackPaused); assert.ok(getPlaybackPausedHandler); assert.equal(getPlaybackPausedHandler!({}), null); @@ -609,7 +571,6 @@ test('registerIpcHandlers records yomitan lookup when subtitle context recording test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => { const { registrar, handlers } = createFakeIpcRegistrar(); const saves: unknown[] = []; - const controllerSaves: unknown[] = []; const closedModals: unknown[] = []; const openedModals: unknown[] = []; registerIpcHandlers( @@ -620,14 +581,9 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => { onOverlayModalOpened: (modal) => { openedModals.push(modal); }, - openYomitanSettings: () => {}, - quitApp: () => {}, toggleDevTools: () => {}, - getVisibleOverlayVisibility: () => false, - toggleVisibleOverlay: () => {}, tokenizeCurrentSubtitle: async () => null, getCurrentSubtitleRaw: () => '', - getCurrentSubtitleAss: () => '', getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), getPlaybackPaused: () => false, getSubtitlePosition: () => null, @@ -635,10 +591,7 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => { saveSubtitlePosition: (position) => { saves.push(position); }, - getMecabStatus: () => ({ available: false, enabled: false, path: null }), - setMecabEnabled: () => {}, handleMpvCommand: () => {}, - getKeybindings: () => [], getSessionBindings: () => [], getConfiguredShortcuts: () => ({}), dispatchSessionAction: async () => {}, @@ -647,24 +600,18 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => { getOverlayNotificationPosition: () => 'top-right', getControllerConfig: () => createControllerConfigFixture(), saveControllerConfig: () => {}, - saveControllerPreference: (update) => { - controllerSaves.push(update); - }, getSecondarySubMode: () => 'hover', getCurrentSecondarySub: () => '', focusMainWindow: () => {}, runSubsyncManual: async () => ({ ok: true, message: 'ok' }), - getAnkiConnectStatus: () => false, getRuntimeOptions: () => [], setRuntimeOption: () => ({ ok: true }), - cycleRuntimeOption: () => ({ ok: true }), reportOverlayContentBounds: () => {}, getAnilistStatus: () => ({}), clearAnilistToken: () => {}, openAnilistSetup: () => {}, getAnilistQueueStatus: () => ({}), retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }), - appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }), getPlaylistBrowserSnapshot: async () => ({ directoryPath: null, directoryAvailable: false, @@ -698,96 +645,6 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => { assert.deepEqual(openedModals, ['subsync', 'runtime-options']); }); -test('registerIpcHandlers awaits saveControllerPreference through request-response IPC', async () => { - const { registrar, handlers } = createFakeIpcRegistrar(); - const controllerSaves: unknown[] = []; - registerIpcHandlers( - { - onOverlayModalClosed: () => {}, - openYomitanSettings: () => {}, - quitApp: () => {}, - toggleDevTools: () => {}, - getVisibleOverlayVisibility: () => false, - toggleVisibleOverlay: () => {}, - tokenizeCurrentSubtitle: async () => null, - getCurrentSubtitleRaw: () => '', - getCurrentSubtitleAss: () => '', - getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), - getPlaybackPaused: () => false, - getSubtitlePosition: () => null, - getSubtitleStyle: () => null, - saveSubtitlePosition: () => {}, - getMecabStatus: () => ({ available: false, enabled: false, path: null }), - setMecabEnabled: () => {}, - handleMpvCommand: () => {}, - getKeybindings: () => [], - getSessionBindings: () => [], - getConfiguredShortcuts: () => ({}), - dispatchSessionAction: async () => {}, - getStatsToggleKey: () => 'Backquote', - getMarkWatchedKey: () => 'KeyW', - getOverlayNotificationPosition: () => 'top-right', - getControllerConfig: () => createControllerConfigFixture(), - saveControllerConfig: async () => {}, - saveControllerPreference: async (update) => { - await Promise.resolve(); - controllerSaves.push(update); - }, - getSecondarySubMode: () => 'hover', - getCurrentSecondarySub: () => '', - focusMainWindow: () => {}, - runSubsyncManual: async () => ({ ok: true, message: 'ok' }), - getAnkiConnectStatus: () => false, - getRuntimeOptions: () => [], - setRuntimeOption: () => ({ ok: true }), - cycleRuntimeOption: () => ({ ok: true }), - reportOverlayContentBounds: () => {}, - getAnilistStatus: () => ({}), - clearAnilistToken: () => {}, - openAnilistSetup: () => {}, - getAnilistQueueStatus: () => ({}), - retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }), - appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }), - getPlaylistBrowserSnapshot: async () => ({ - directoryPath: null, - directoryAvailable: false, - directoryStatus: '', - directoryItems: [], - playlistItems: [], - playingIndex: null, - currentFilePath: null, - }), - appendPlaylistBrowserFile: async () => ({ ok: true, message: 'ok' }), - playPlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }), - removePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }), - movePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }), - onYoutubePickerResolve: async () => ({ ok: true, message: 'ok' }), - }, - registrar, - ); - - const saveHandler = handlers.handle.get(IPC_CHANNELS.command.saveControllerPreference); - assert.ok(saveHandler); - - await assert.rejects(async () => { - await saveHandler!({}, { preferredGamepadId: 12 }); - }, /Invalid controller preference payload/); - await saveHandler!( - {}, - { - preferredGamepadId: 'pad-1', - preferredGamepadLabel: 'Pad 1', - }, - ); - - assert.deepEqual(controllerSaves, [ - { - preferredGamepadId: 'pad-1', - preferredGamepadLabel: 'Pad 1', - }, - ]); -}); - test('registerIpcHandlers accepts per-controller profile config updates', async () => { const { registrar, handlers } = createFakeIpcRegistrar(); const controllerSaves: unknown[] = []; @@ -975,76 +832,6 @@ test('registerIpcHandlers forwards valid overlay notification actions', () => { ]); }); -test('registerIpcHandlers rejects malformed controller preference payloads', async () => { - const { registrar, handlers } = createFakeIpcRegistrar(); - registerIpcHandlers( - { - onOverlayModalClosed: () => {}, - openYomitanSettings: () => {}, - quitApp: () => {}, - toggleDevTools: () => {}, - getVisibleOverlayVisibility: () => false, - toggleVisibleOverlay: () => {}, - tokenizeCurrentSubtitle: async () => null, - getCurrentSubtitleRaw: () => '', - getCurrentSubtitleAss: () => '', - getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(), - getPlaybackPaused: () => false, - getSubtitlePosition: () => null, - getSubtitleStyle: () => null, - saveSubtitlePosition: () => {}, - getMecabStatus: () => ({ available: false, enabled: false, path: null }), - setMecabEnabled: () => {}, - handleMpvCommand: () => {}, - getKeybindings: () => [], - getSessionBindings: () => [], - getConfiguredShortcuts: () => ({}), - dispatchSessionAction: async () => {}, - getStatsToggleKey: () => 'Backquote', - getMarkWatchedKey: () => 'KeyW', - getOverlayNotificationPosition: () => 'top-right', - getControllerConfig: () => createControllerConfigFixture(), - saveControllerConfig: async () => {}, - saveControllerPreference: async () => {}, - getSecondarySubMode: () => 'hover', - getCurrentSecondarySub: () => '', - focusMainWindow: () => {}, - runSubsyncManual: async () => ({ ok: true, message: 'ok' }), - getAnkiConnectStatus: () => false, - getRuntimeOptions: () => [], - setRuntimeOption: () => ({ ok: true }), - cycleRuntimeOption: () => ({ ok: true }), - reportOverlayContentBounds: () => {}, - getAnilistStatus: () => ({}), - clearAnilistToken: () => {}, - openAnilistSetup: () => {}, - getAnilistQueueStatus: () => ({}), - retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }), - appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }), - getPlaylistBrowserSnapshot: async () => ({ - directoryPath: null, - directoryAvailable: false, - directoryStatus: '', - directoryItems: [], - playlistItems: [], - playingIndex: null, - currentFilePath: null, - }), - appendPlaylistBrowserFile: async () => ({ ok: true, message: 'ok' }), - playPlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }), - removePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }), - movePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }), - onYoutubePickerResolve: async () => ({ ok: true, message: 'ok' }), - }, - registrar, - ); - - const saveHandler = handlers.handle.get(IPC_CHANNELS.command.saveControllerPreference); - await assert.rejects(async () => { - await saveHandler!({}, { preferredGamepadId: 12 }); - }, /Invalid controller preference payload/); -}); - test('registerIpcHandlers exposes character dictionary selection handlers', async () => { const { registrar, handlers } = createFakeIpcRegistrar(); const calls: number[] = []; diff --git a/src/core/services/ipc.ts b/src/core/services/ipc.ts index 113ee6dc..ae9cc6f8 100644 --- a/src/core/services/ipc.ts +++ b/src/core/services/ipc.ts @@ -7,7 +7,6 @@ import type { ControllerConfigUpdate, PlaylistBrowserMutationResult, PlaylistBrowserSnapshot, - ControllerPreferenceUpdate, ResolvedControllerConfig, RuntimeOptionId, RuntimeOptionValue, @@ -34,10 +33,8 @@ import { IPC_CHANNELS, type OverlayHostedModal } from '../../shared/ipc/contract import { parseMpvCommand, parseControllerConfigUpdate, - parseControllerPreferenceUpdate, parseOptionalForwardingOptions, parseOverlayHostedModal, - parseRuntimeOptionDirection, parseRuntimeOptionId, parseRuntimeOptionValue, parseSessionActionDispatchRequest, @@ -71,14 +68,9 @@ export interface IpcServiceDeps { actionId: string, noteId?: number, ) => void | Promise; - openYomitanSettings: () => void; - quitApp: () => void; toggleDevTools: () => void; - getVisibleOverlayVisibility: () => boolean; - toggleVisibleOverlay: () => void; tokenizeCurrentSubtitle: () => Promise; getCurrentSubtitleRaw: () => string; - getCurrentSubtitleAss: () => string; getSubtitleSidebarSnapshot?: () => Promise; getSubtitleSidebarPlaybackState?: () => SubtitleSidebarPlaybackState; getSubtitleSidebarOpen?: () => boolean; @@ -86,14 +78,7 @@ export interface IpcServiceDeps { getSubtitlePosition: () => unknown; getSubtitleStyle: () => unknown; saveSubtitlePosition: (position: SubtitlePosition) => void; - getMecabStatus: () => { - available: boolean; - enabled: boolean; - path: string | null; - }; - setMecabEnabled: (enabled: boolean) => void; handleMpvCommand: (command: Array) => void; - getKeybindings: () => unknown; getMpvInputBindings?: () => Promise; getSessionBindings?: () => CompiledSessionBinding[] | Promise; getConfiguredShortcuts: () => unknown; @@ -103,7 +88,6 @@ export interface IpcServiceDeps { getOverlayNotificationPosition: () => string; getControllerConfig: () => ResolvedControllerConfig; saveControllerConfig: (update: ControllerConfigUpdate) => void | Promise; - saveControllerPreference: (update: ControllerPreferenceUpdate) => void | Promise; getSecondarySubMode: () => unknown; getCurrentSecondarySub: () => string; focusMainWindow: () => void; @@ -125,10 +109,8 @@ export interface IpcServiceDeps { resolveMediaTimingReview?: ( request: MediaTimingReviewResolveRequest, ) => MediaTimingReviewActionResult | Promise; - getAnkiConnectStatus: () => boolean; getRuntimeOptions: () => unknown; setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown; - cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => unknown; reportOverlayContentBounds: ( payload: unknown, senderWindow: ElectronBrowserWindow | null, @@ -149,7 +131,6 @@ export interface IpcServiceDeps { getCharacterDictionaryManagerSnapshot?: () => Promise; removeCharacterDictionaryManagedEntry?: (mediaId: number) => Promise; moveCharacterDictionaryManagedEntry?: (mediaId: number, direction: 1 | -1) => Promise; - appendClipboardVideoToQueue: () => { ok: boolean; message: string }; getChangelogSnapshot?: (options?: { refresh?: boolean }) => Promise; getPlaylistBrowserSnapshot: () => Promise; appendPlaylistBrowserFile: (filePath: string) => Promise; @@ -174,15 +155,6 @@ interface WindowLike { }; } -interface MecabTokenizerLike { - getStatus: () => { - available: boolean; - enabled: boolean; - path: string | null; - }; - setEnabled: (enabled: boolean) => void; -} - interface MpvClientLike { currentSecondarySubText?: string; } @@ -342,7 +314,6 @@ function parseMediaTimingReviewResolveRequest( export interface IpcDepsRuntimeOptions { getMainWindow: () => WindowLike | null; - getVisibleOverlayVisibility: () => boolean; onOverlayModalClosed: ( modal: OverlayHostedModal, senderWindow: ElectronBrowserWindow | null, @@ -364,12 +335,8 @@ export interface IpcDepsRuntimeOptions { actionId: string, noteId?: number, ) => void | Promise; - openYomitanSettings: () => void; - quitApp: () => void; - toggleVisibleOverlay: () => void; tokenizeCurrentSubtitle: () => Promise; getCurrentSubtitleRaw: () => string; - getCurrentSubtitleAss: () => string; getSubtitleSidebarSnapshot?: () => Promise; getSubtitleSidebarPlaybackState?: () => SubtitleSidebarPlaybackState; getSubtitleSidebarOpen?: () => boolean; @@ -377,9 +344,7 @@ export interface IpcDepsRuntimeOptions { getSubtitlePosition: () => unknown; getSubtitleStyle: () => unknown; saveSubtitlePosition: (position: SubtitlePosition) => void; - getMecabTokenizer: () => MecabTokenizerLike | null; handleMpvCommand: (command: Array) => void; - getKeybindings: () => unknown; getMpvInputBindings?: () => Promise; getSessionBindings?: () => CompiledSessionBinding[] | Promise; getConfiguredShortcuts: () => unknown; @@ -389,7 +354,6 @@ export interface IpcDepsRuntimeOptions { getOverlayNotificationPosition: () => string; getControllerConfig: () => ResolvedControllerConfig; saveControllerConfig: (update: ControllerConfigUpdate) => void | Promise; - saveControllerPreference: (update: ControllerPreferenceUpdate) => void | Promise; getSecondarySubMode: () => unknown; getMpvClient: () => MpvClientLike | null; focusMainWindow: () => void; @@ -403,10 +367,8 @@ export interface IpcDepsRuntimeOptions { getMediaTimingReviewWaveform?: IpcServiceDeps['getMediaTimingReviewWaveform']; stopMediaTimingReviewPreview?: IpcServiceDeps['stopMediaTimingReviewPreview']; resolveMediaTimingReview?: IpcServiceDeps['resolveMediaTimingReview']; - getAnkiConnectStatus: () => boolean; getRuntimeOptions: () => unknown; setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown; - cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => unknown; reportOverlayContentBounds: (payload: unknown) => void; getAnilistStatus: () => unknown; clearAnilistToken: () => void; @@ -424,7 +386,6 @@ export interface IpcDepsRuntimeOptions { getCharacterDictionaryManagerSnapshot?: () => Promise; removeCharacterDictionaryManagedEntry?: (mediaId: number) => Promise; moveCharacterDictionaryManagedEntry?: (mediaId: number, direction: 1 | -1) => Promise; - appendClipboardVideoToQueue: () => { ok: boolean; message: string }; getChangelogSnapshot?: (options?: { refresh?: boolean }) => Promise; getPlaylistBrowserSnapshot: () => Promise; appendPlaylistBrowserFile: (filePath: string) => Promise; @@ -444,19 +405,14 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService onOverlayMouseInteractionChanged: options.onOverlayMouseInteractionChanged, onOverlayInteractiveHint: options.onOverlayInteractiveHint, handleOverlayNotificationAction: options.handleOverlayNotificationAction, - openYomitanSettings: options.openYomitanSettings, recordSubtitleMiningContext: options.recordSubtitleMiningContext, - quitApp: options.quitApp, toggleDevTools: () => { const mainWindow = options.getMainWindow(); if (!mainWindow || mainWindow.isDestroyed()) return; mainWindow.webContents.toggleDevTools(); }, - getVisibleOverlayVisibility: options.getVisibleOverlayVisibility, - toggleVisibleOverlay: options.toggleVisibleOverlay, tokenizeCurrentSubtitle: options.tokenizeCurrentSubtitle, getCurrentSubtitleRaw: options.getCurrentSubtitleRaw, - getCurrentSubtitleAss: options.getCurrentSubtitleAss, getSubtitleSidebarSnapshot: options.getSubtitleSidebarSnapshot, getSubtitleSidebarPlaybackState: options.getSubtitleSidebarPlaybackState, getSubtitleSidebarOpen: options.getSubtitleSidebarOpen ?? (() => false), @@ -464,19 +420,7 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService getSubtitlePosition: options.getSubtitlePosition, getSubtitleStyle: options.getSubtitleStyle, saveSubtitlePosition: options.saveSubtitlePosition, - getMecabStatus: () => { - const mecabTokenizer = options.getMecabTokenizer(); - return mecabTokenizer - ? mecabTokenizer.getStatus() - : { available: false, enabled: false, path: null }; - }, - setMecabEnabled: (enabled) => { - const mecabTokenizer = options.getMecabTokenizer(); - if (!mecabTokenizer) return; - mecabTokenizer.setEnabled(enabled); - }, handleMpvCommand: options.handleMpvCommand, - getKeybindings: options.getKeybindings, getMpvInputBindings: options.getMpvInputBindings, getSessionBindings: options.getSessionBindings ?? (() => []), getConfiguredShortcuts: options.getConfiguredShortcuts, @@ -486,7 +430,6 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService getOverlayNotificationPosition: options.getOverlayNotificationPosition, getControllerConfig: options.getControllerConfig, saveControllerConfig: options.saveControllerConfig, - saveControllerPreference: options.saveControllerPreference, getSecondarySubMode: options.getSecondarySubMode, getCurrentSecondarySub: () => options.getMpvClient()?.currentSecondarySubText || '', focusMainWindow: () => { @@ -503,10 +446,8 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService getMediaTimingReviewWaveform: options.getMediaTimingReviewWaveform, stopMediaTimingReviewPreview: options.stopMediaTimingReviewPreview, resolveMediaTimingReview: options.resolveMediaTimingReview, - getAnkiConnectStatus: options.getAnkiConnectStatus, getRuntimeOptions: options.getRuntimeOptions, setRuntimeOption: options.setRuntimeOption, - cycleRuntimeOption: options.cycleRuntimeOption, reportOverlayContentBounds: (payload, senderWindow) => { const mainWindow = options.getMainWindow(); if (!mainWindow || mainWindow.isDestroyed()) return; @@ -553,7 +494,6 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService message: 'Character dictionary manager unavailable.', entries: [], })), - appendClipboardVideoToQueue: options.appendClipboardVideoToQueue, getChangelogSnapshot: options.getChangelogSnapshot, getPlaylistBrowserSnapshot: options.getPlaylistBrowserSnapshot, appendPlaylistBrowserFile: options.appendPlaylistBrowserFile, @@ -680,10 +620,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar }, ); - ipc.on(IPC_CHANNELS.command.openYomitanSettings, () => { - deps.openYomitanSettings(); - }); - ipc.on(IPC_CHANNELS.command.recordYomitanLookup, (_event: unknown, payload: unknown) => { try { deps.recordSubtitleMiningContext?.(parseSubtitleMiningContext(payload)); @@ -711,22 +647,10 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar return marked; }); - ipc.on(IPC_CHANNELS.command.quitApp, () => { - deps.quitApp(); - }); - ipc.on(IPC_CHANNELS.command.toggleDevTools, () => { deps.toggleDevTools(); }); - ipc.on(IPC_CHANNELS.command.toggleOverlay, () => { - deps.toggleVisibleOverlay(); - }); - - ipc.handle(IPC_CHANNELS.request.getVisibleOverlayVisibility, () => { - return deps.getVisibleOverlayVisibility(); - }); - ipc.handle(IPC_CHANNELS.request.getCurrentSubtitle, async () => { return await deps.tokenizeCurrentSubtitle(); }); @@ -735,10 +659,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar return deps.getCurrentSubtitleRaw(); }); - ipc.handle(IPC_CHANNELS.request.getCurrentSubtitleAss, () => { - return deps.getCurrentSubtitleAss(); - }); - ipc.handle(IPC_CHANNELS.request.getSubtitleSidebarSnapshot, async () => { if (!deps.getSubtitleSidebarSnapshot) { throw new Error('Subtitle sidebar snapshot is unavailable.'); @@ -775,17 +695,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar deps.saveSubtitlePosition(parsedPosition); }); - ipc.handle( - IPC_CHANNELS.command.saveControllerPreference, - async (_event: unknown, update: unknown) => { - const parsedUpdate = parseControllerPreferenceUpdate(update); - if (!parsedUpdate) { - throw new Error('Invalid controller preference payload'); - } - await deps.saveControllerPreference(parsedUpdate); - }, - ); - ipc.handle( IPC_CHANNELS.command.saveControllerConfig, async (_event: unknown, update: unknown) => { @@ -797,15 +706,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar }, ); - ipc.handle(IPC_CHANNELS.request.getMecabStatus, () => { - return deps.getMecabStatus(); - }); - - ipc.on(IPC_CHANNELS.command.setMecabEnabled, (_event: unknown, enabled: unknown) => { - if (typeof enabled !== 'boolean') return; - deps.setMecabEnabled(enabled); - }); - ipc.on(IPC_CHANNELS.command.mpvCommand, (_event: unknown, command: unknown) => { const parsedCommand = parseMpvCommand(command); if (!parsedCommand) return; @@ -823,10 +723,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar }, ); - ipc.handle(IPC_CHANNELS.request.getKeybindings, () => { - return deps.getKeybindings(); - }); - ipc.handle(IPC_CHANNELS.request.getMpvInputBindings, () => { return deps.getMpvInputBindings?.() ?? { keys: [], blockedKeys: [] }; }); @@ -879,10 +775,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar return await deps.runSubsyncManual(parsedRequest); }); - ipc.handle(IPC_CHANNELS.request.getAnkiConnectStatus, () => { - return deps.getAnkiConnectStatus(); - }); - ipc.handle(IPC_CHANNELS.request.getRuntimeOptions, () => { return deps.getRuntimeOptions(); }); @@ -899,18 +791,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar return deps.setRuntimeOption(parsedId, parsedValue); }); - ipc.handle(IPC_CHANNELS.request.cycleRuntimeOption, (_event, id: unknown, direction: unknown) => { - const parsedId = parseRuntimeOptionId(id); - if (!parsedId) { - return { ok: false, error: 'Invalid runtime option id' }; - } - const parsedDirection = parseRuntimeOptionDirection(direction); - if (!parsedDirection) { - return { ok: false, error: 'Invalid runtime option cycle direction' }; - } - return deps.cycleRuntimeOption(parsedId, parsedDirection); - }); - ipc.on(IPC_CHANNELS.command.reportOverlayContentBounds, (event: unknown, payload: unknown) => { const senderWindow = electron.BrowserWindow?.fromWebContents((event as IpcMainEvent).sender) ?? null; @@ -1020,10 +900,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar }, ); - ipc.handle(IPC_CHANNELS.request.appendClipboardVideoToQueue, () => { - return deps.appendClipboardVideoToQueue(); - }); - ipc.handle(IPC_CHANNELS.request.getChangelogSnapshot, async (_event, payload: unknown) => { const refresh = typeof payload === 'object' && payload !== null && 'refresh' in payload diff --git a/src/core/services/mpv-properties.ts b/src/core/services/mpv-properties.ts index 6891872e..158ffdc3 100644 --- a/src/core/services/mpv-properties.ts +++ b/src/core/services/mpv-properties.ts @@ -20,7 +20,6 @@ import { MPV_REQUEST_ID_SUB_SHADOW_OFFSET, MPV_REQUEST_ID_SUB_SPACING, MPV_REQUEST_ID_SUBTEXT, - MPV_REQUEST_ID_SUBTEXT_ASS, MPV_REQUEST_ID_SUB_USE_MARGINS, MPV_REQUEST_ID_PAUSE, } from './mpv-protocol'; @@ -54,7 +53,6 @@ const MPV_SUBTITLE_PROPERTY_OBSERVATIONS: string[] = [ 'sub-scale-by-window', 'osd-height', 'osd-dimensions', - 'sub-text/ass', 'sub-border-size', 'sub-shadow-offset', 'sub-ass-override', @@ -76,10 +74,6 @@ const MPV_INITIAL_PROPERTY_REQUESTS: Array = [ command: ['get_property', 'sub-text'], request_id: MPV_REQUEST_ID_SUBTEXT, }, - { - command: ['get_property', 'sub-text/ass'], - request_id: MPV_REQUEST_ID_SUBTEXT_ASS, - }, { command: ['get_property', 'path'], request_id: MPV_REQUEST_ID_PATH, diff --git a/src/core/services/mpv-protocol.test.ts b/src/core/services/mpv-protocol.test.ts index a1f0a791..6ca1b827 100644 --- a/src/core/services/mpv-protocol.test.ts +++ b/src/core/services/mpv-protocol.test.ts @@ -59,7 +59,6 @@ function createDeps(overrides: Partial = {}): { getSubtitleMetrics: () => metrics, isVisibleOverlayVisible: () => false, emitSubtitleChange: (payload) => state.events.push(payload), - emitSubtitleAssChange: (payload) => state.events.push(payload), emitSubtitleTiming: (payload) => state.events.push(payload), emitSecondarySubtitleChange: (payload) => state.events.push(payload), emitSubtitleTrackChange: (payload) => state.events.push(payload), @@ -132,28 +131,6 @@ test('dispatchMpvProtocolMessage emits subtitle text on property change', async assert.deepEqual(state.events, [{ text: '字幕', isOverlayVisible: false }]); }); -test('dispatchMpvProtocolMessage emits ASS subtitle text from the current mpv property', async () => { - const { deps, state } = createDeps(); - - await dispatchMpvProtocolMessage( - { event: 'property-change', name: 'sub-text/ass', data: '{\\b1}字幕' }, - deps, - ); - - assert.deepEqual(state.events, [{ text: '{\\b1}字幕' }]); -}); - -test('dispatchMpvProtocolMessage emits ASS subtitle text from the legacy mpv property', async () => { - const { deps, state } = createDeps(); - - await dispatchMpvProtocolMessage( - { event: 'property-change', name: 'sub-text-ass', data: '{\\b1}字幕' }, - deps, - ); - - assert.deepEqual(state.events, [{ text: '{\\b1}字幕' }]); -}); - test('dispatchMpvProtocolMessage emits subtitle track changes', async () => { const { deps, state } = createDeps({ emitSubtitleTrackChange: (payload) => state.events.push(payload), diff --git a/src/core/services/mpv-protocol.ts b/src/core/services/mpv-protocol.ts index da3b1c9a..0ea185dc 100644 --- a/src/core/services/mpv-protocol.ts +++ b/src/core/services/mpv-protocol.ts @@ -24,7 +24,6 @@ export const MPV_REQUEST_ID_SUB_FONT = 111; export const MPV_REQUEST_ID_SUB_SCALE_BY_WINDOW = 112; export const MPV_REQUEST_ID_OSD_HEIGHT = 113; export const MPV_REQUEST_ID_OSD_DIMENSIONS = 114; -export const MPV_REQUEST_ID_SUBTEXT_ASS = 115; export const MPV_REQUEST_ID_SUB_SPACING = 116; export const MPV_REQUEST_ID_SUB_BOLD = 117; export const MPV_REQUEST_ID_SUB_ITALIC = 118; @@ -52,7 +51,6 @@ export interface MpvProtocolHandleMessageDeps { getSubtitleMetrics: () => MpvSubtitleRenderMetrics; isVisibleOverlayVisible: () => boolean; emitSubtitleChange: (payload: { text: string; isOverlayVisible: boolean }) => void; - emitSubtitleAssChange: (payload: { text: string }) => void; emitSubtitleTiming: (payload: { text: string; start: number; end: number }) => void; emitSecondarySubtitleChange: (payload: { text: string }) => void; emitSubtitleTrackChange: (payload: { sid: number | null }) => void; @@ -253,8 +251,6 @@ export async function dispatchMpvProtocolMessage( isOverlayVisible: overlayVisible, }); deps.setCurrentSubText(nextSubText); - } else if (msg.name === 'sub-text/ass' || msg.name === 'sub-text-ass') { - deps.emitSubtitleAssChange({ text: (msg.data as string) || '' }); } else if (msg.name === 'sub-start') { deps.setCurrentSubStart((msg.data as number) || 0); deps.emitSubtitleTiming({ @@ -468,8 +464,6 @@ export async function dispatchMpvProtocolMessage( text: nextSubText, isOverlayVisible: deps.isVisibleOverlayVisible(), }); - } else if (msg.request_id === MPV_REQUEST_ID_SUBTEXT_ASS) { - deps.emitSubtitleAssChange({ text: (msg.data as string) || '' }); } else if (msg.request_id === MPV_REQUEST_ID_PATH) { deps.emitMediaPathChange({ path: (msg.data as string) || '' }); } else if (msg.request_id === MPV_REQUEST_ID_MEDIA_TITLE) { diff --git a/src/core/services/mpv.test.ts b/src/core/services/mpv.test.ts index 0072dbaa..734c6582 100644 --- a/src/core/services/mpv.test.ts +++ b/src/core/services/mpv.test.ts @@ -444,17 +444,6 @@ test('MpvIpcClient reconnect replays property subscriptions and initial state re (command as { command: unknown[] }).command[1] === 1 && (command as { command: unknown[] }).command[2] === 'sub-text', ); - const hasAssSubtitleSubscription = commands.some( - (command) => - Array.isArray((command as { command: unknown[] }).command) && - (command as { command: unknown[] }).command[0] === 'observe_property' && - (command as { command: unknown[] }).command[2] === 'sub-text/ass', - ); - const hasDeprecatedAssSubtitleProperty = commands.some( - (command) => - Array.isArray((command as { command: unknown[] }).command) && - (command as { command: unknown[] }).command.includes('sub-text-ass'), - ); const hasPathRequest = commands.some( (command) => Array.isArray((command as { command: unknown[] }).command) && @@ -464,8 +453,6 @@ test('MpvIpcClient reconnect replays property subscriptions and initial state re assert.equal(hasSecondaryVisibilityReset, true); assert.equal(hasTrackSubscription, true); - assert.equal(hasAssSubtitleSubscription, true); - assert.equal(hasDeprecatedAssSubtitleProperty, false); assert.equal(hasPathRequest, true); }); diff --git a/src/core/services/mpv.ts b/src/core/services/mpv.ts index 3345733d..5f3e46f7 100644 --- a/src/core/services/mpv.ts +++ b/src/core/services/mpv.ts @@ -123,7 +123,6 @@ export interface MpvIpcClientDeps extends MpvIpcClientProtocolDeps {} export interface MpvIpcClientEventMap { 'connection-change': { connected: boolean }; 'subtitle-change': { text: string; isOverlayVisible: boolean }; - 'subtitle-ass-change': { text: string }; 'subtitle-timing': { text: string; start: number; end: number }; 'time-pos-change': { time: number }; 'duration-change': { duration: number }; @@ -417,9 +416,6 @@ export class MpvIpcClient implements MpvClient { emitSubtitleChange: (payload) => { this.emit('subtitle-change', payload); }, - emitSubtitleAssChange: (payload) => { - this.emit('subtitle-ass-change', payload); - }, emitSubtitleTiming: (payload) => { this.emit('subtitle-timing', payload); }, diff --git a/src/core/services/runtime-options-ipc.test.ts b/src/core/services/runtime-options-ipc.test.ts index fa659cf9..6c74ea6b 100644 --- a/src/core/services/runtime-options-ipc.test.ts +++ b/src/core/services/runtime-options-ipc.test.ts @@ -2,7 +2,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { applyRuntimeOptionResultRuntime, - cycleRuntimeOptionFromIpcRuntime, setRuntimeOptionFromIpcRuntime, } from './runtime-options-ipc'; @@ -25,21 +24,3 @@ test('setRuntimeOptionFromIpcRuntime returns unavailable when manager missing', assert.equal(result.error, 'Runtime options manager unavailable'); assert.deepEqual(osd, []); }); - -test('cycleRuntimeOptionFromIpcRuntime reports errors once', () => { - const osd: string[] = []; - const result = cycleRuntimeOptionFromIpcRuntime( - { - setOptionValue: () => ({ ok: true }), - cycleOption: () => ({ ok: false, error: 'bad option' }), - }, - 'anki.kikuFieldGrouping', - 1, - (text) => { - osd.push(text); - }, - ); - assert.equal(result.ok, false); - assert.equal(result.error, 'bad option'); - assert.deepEqual(osd, ['bad option']); -}); diff --git a/src/core/services/runtime-options-ipc.ts b/src/core/services/runtime-options-ipc.ts index 71d32ef5..39509ff9 100644 --- a/src/core/services/runtime-options-ipc.ts +++ b/src/core/services/runtime-options-ipc.ts @@ -34,19 +34,3 @@ export function setRuntimeOptionFromIpcRuntime( } return result; } - -export function cycleRuntimeOptionFromIpcRuntime( - manager: RuntimeOptionsManagerLike | null, - id: RuntimeOptionId, - direction: 1 | -1, - showMpvOsd: (text: string) => void, -): RuntimeOptionApplyResult { - if (!manager) { - return { ok: false, error: 'Runtime options manager unavailable' }; - } - const result = applyRuntimeOptionResultRuntime(manager.cycleOption(id, direction), showMpvOsd); - if (!result.ok && result.error) { - showMpvOsd(result.error); - } - return result; -} diff --git a/src/main.ts b/src/main.ts index bbf544bc..3242d719 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4767,7 +4767,6 @@ const { autoplaySubtitlePrimingRuntime.resetAutoplaySubtitlePrime(); lastObservedTimePos = 0; appState.currentSubText = ''; - appState.currentSubAssText = ''; appState.currentSubtitleData = null; if (!preserveParsedSubtitleCues) { appState.activeParsedSubtitleCues = []; @@ -5723,7 +5722,6 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({ stopMediaTimingReviewPreview: (reviewId) => mediaTimingReviewRuntime.stopPreview(reviewId), resolveMediaTimingReview: (request) => mediaTimingReviewRuntime.resolveReview(request), getMainWindow: () => overlayManager.getMainWindow(), - getVisibleOverlayVisibility: () => overlayManager.getVisibleOverlayVisible(), focusMainWindow: () => { const mainWindow = overlayManager.getMainWindow(); if (!mainWindow || mainWindow.isDestroyed()) return; @@ -5837,14 +5835,11 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({ } }, onYoutubePickerResolve: (request) => youtubeFlowRuntime.resolveActivePicker(request), - openYomitanSettings: () => openYomitanSettings(), // Overlay lookups carry no cue context of their own; fall back to snapshotting the // live mpv sub timings at lookup time so media generation clips the mined line even // when extraction finishes long after playback has moved on. recordSubtitleMiningContext: (context) => recordSubtitleMiningContext(context ?? captureCurrentPrimarySubtitleMiningContext()), - quitApp: () => requestAppQuit(), - toggleVisibleOverlay: () => toggleVisibleOverlay(), tokenizeCurrentSubtitle: async () => { const tokenizeSubtitleForCurrent = tokenizeSubtitleDeferred; return resolveCurrentSubtitleForRenderer({ @@ -5862,7 +5857,6 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({ }); }, getCurrentSubtitleRaw: () => appState.currentSubText, - getCurrentSubtitleAss: () => appState.currentSubAssText, getSubtitleSidebarOpen: () => subtitleSidebarRequestedOpen, getSubtitleSidebarPlaybackState: () => getSubtitleSidebarPlaybackState(), // Full snapshot: resolves the active source over mpv IPC and re-parses it when it changed. @@ -5942,8 +5936,6 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({ return resolveSubtitleStyleForRenderer(resolvedConfig); }, saveSubtitlePosition: (position) => saveSubtitlePosition(position), - getMecabTokenizer: () => appState.mecabTokenizer, - getKeybindings: () => appState.keybindings, getMpvInputBindings: async () => { await refreshMpvSessionBindings(); return readMpvInputBindings({ @@ -5973,17 +5965,8 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({ controller: applyControllerConfigUpdate(currentRawConfig.controller, update), }); }, - saveControllerPreference: ({ preferredGamepadId, preferredGamepadLabel }) => { - configService.patchRawConfig({ - controller: { - preferredGamepadId, - preferredGamepadLabel, - }, - }); - }, getSecondarySubMode: () => appState.secondarySubMode, getMpvClient: () => appState.mpvClient, - getAnkiConnectStatus: () => appState.ankiIntegration !== null, getRuntimeOptions: () => getRuntimeOptionsStateHandler(), reportOverlayContentBounds: (payload: unknown) => { if (overlayContentMeasurementStore.report(payload)) { @@ -6071,47 +6054,14 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({ } return result; }, - appendClipboardVideoToQueue: () => appendClipboardVideoToQueueHandler(), getChangelogSnapshot: (options) => getChangelogSnapshot(options), ...playlistBrowserMainDeps, getImmersionTracker: () => appState.immersionTracker, }, ankiJimakuDeps: createAnkiJimakuIpcRuntimeServiceDeps({ - patchAnkiConnectEnabled: (enabled: boolean) => { - configService.patchRawConfig({ ankiConnect: { enabled } }); - }, getResolvedConfig: () => configService.getConfig(), - getRuntimeOptionsManager: () => appState.runtimeOptionsManager, - getSubtitleTimingTracker: () => appState.subtitleTimingTracker, getMpvClient: () => appState.mpvClient, getAnkiIntegration: () => appState.ankiIntegration, - setAnkiIntegration: (integration: AnkiIntegration | null) => { - appState.ankiIntegration = integration; - appState.ankiIntegration?.setRecordCardsMinedCallback(recordTrackedCardsMined); - appState.ankiIntegration?.setKnownWordCacheUpdatedCallback( - refreshCurrentSubtitleAnnotations, - ); - appState.ankiIntegration?.setSubtitleMiningContextConsumer( - consumePendingSubtitleMiningContext, - ); - appState.ankiIntegration?.setMediaTimingReviewCallback( - mediaTimingReviewRuntime.requestReview, - ); - appState.ankiIntegration?.setSentenceFuriganaGenerator(generateMiningSentenceFurigana); - }, - getKnownWordCacheStatePath: () => path.join(USER_DATA_PATH, 'known-words-cache.json'), - getCachedMediaPath: (currentVideoPath, kind) => - getCachedYoutubeMediaPathForCurrentPlayback(currentVideoPath, kind), - shouldRequireRemoteMediaCache: () => shouldRequireYoutubeMediaCacheForCurrentPlayback(), - getYoutubeMediaSourceUrl: () => getCurrentYoutubeMediaCacheSourceUrl(), - showDesktopNotification, - showOverlayNotification: (payload) => - overlayNotificationsRuntime.showOverlayNotification(payload), - dismissOverlayNotification: (id) => - overlayNotificationsRuntime.dismissOverlayNotification(id), - createFieldGroupingCallback: () => createFieldGroupingCallback(), - broadcastRuntimeOptionsChanged: () => - overlayVisibilityComposer.broadcastRuntimeOptionsChanged(), getFieldGroupingResolver: () => getFieldGroupingResolverHandler(), setFieldGroupingResolver: (resolver: ((choice: KikuFieldGroupingChoice) => void) | null) => setFieldGroupingResolverHandler(resolver), diff --git a/src/main/dependencies.ts b/src/main/dependencies.ts index da74e427..9aebcec8 100644 --- a/src/main/dependencies.ts +++ b/src/main/dependencies.ts @@ -1,15 +1,11 @@ import { RuntimeOptionId, RuntimeOptionValue, SubsyncManualPayload } from '../types'; -import type { OverlayNotificationPayload } from '../types/notification'; import { SubsyncResolvedConfig } from '../subsync/utils'; import type { SubsyncRuntimeDeps } from '../core/services/subsync-runner'; import type { IpcDepsRuntimeOptions } from '../core/services/ipc'; import type { AnkiJimakuIpcRuntimeOptions } from '../core/services/anki-jimaku'; import type { CliCommandDepsRuntimeOptions } from '../core/services/cli-command'; import type { HandleMpvCommandFromIpcOptions } from '../core/services/ipc-command'; -import { - cycleRuntimeOptionFromIpcRuntime, - setRuntimeOptionFromIpcRuntime, -} from '../core/services/runtime-options-ipc'; +import { setRuntimeOptionFromIpcRuntime } from '../core/services/runtime-options-ipc'; import { RuntimeOptionsManager } from '../runtime-options'; export interface RuntimeOptionsIpcDepsParams { @@ -28,17 +24,12 @@ export interface SubsyncRuntimeDepsParams { export function createRuntimeOptionsIpcDeps(params: RuntimeOptionsIpcDepsParams): { setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown; - cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => unknown; } { return { setRuntimeOption: (id, value) => setRuntimeOptionFromIpcRuntime(params.getRuntimeOptionsManager(), id, value, (text) => params.showMpvOsd(text), ), - cycleRuntimeOption: (id, direction) => - cycleRuntimeOptionFromIpcRuntime(params.getRuntimeOptionsManager(), id, direction, (text) => - params.showMpvOsd(text), - ), }; } @@ -55,7 +46,6 @@ export function createSubsyncRuntimeDeps(params: SubsyncRuntimeDepsParams): Subs export interface MainIpcRuntimeServiceDepsParams { getMainWindow: IpcDepsRuntimeOptions['getMainWindow']; - getVisibleOverlayVisibility: IpcDepsRuntimeOptions['getVisibleOverlayVisibility']; onOverlayModalClosed: IpcDepsRuntimeOptions['onOverlayModalClosed']; onOverlayModalOpened?: IpcDepsRuntimeOptions['onOverlayModalOpened']; onOverlayMouseInteractionChanged?: IpcDepsRuntimeOptions['onOverlayMouseInteractionChanged']; @@ -67,12 +57,8 @@ export interface MainIpcRuntimeServiceDepsParams { getMediaTimingReviewWaveform?: IpcDepsRuntimeOptions['getMediaTimingReviewWaveform']; stopMediaTimingReviewPreview?: IpcDepsRuntimeOptions['stopMediaTimingReviewPreview']; resolveMediaTimingReview?: IpcDepsRuntimeOptions['resolveMediaTimingReview']; - openYomitanSettings: IpcDepsRuntimeOptions['openYomitanSettings']; - quitApp: IpcDepsRuntimeOptions['quitApp']; - toggleVisibleOverlay: IpcDepsRuntimeOptions['toggleVisibleOverlay']; tokenizeCurrentSubtitle: IpcDepsRuntimeOptions['tokenizeCurrentSubtitle']; getCurrentSubtitleRaw: IpcDepsRuntimeOptions['getCurrentSubtitleRaw']; - getCurrentSubtitleAss: IpcDepsRuntimeOptions['getCurrentSubtitleAss']; getSubtitleSidebarSnapshot?: IpcDepsRuntimeOptions['getSubtitleSidebarSnapshot']; getSubtitleSidebarPlaybackState?: IpcDepsRuntimeOptions['getSubtitleSidebarPlaybackState']; getSubtitleSidebarOpen?: IpcDepsRuntimeOptions['getSubtitleSidebarOpen']; @@ -82,9 +68,7 @@ export interface MainIpcRuntimeServiceDepsParams { getSubtitlePosition: IpcDepsRuntimeOptions['getSubtitlePosition']; getSubtitleStyle: IpcDepsRuntimeOptions['getSubtitleStyle']; saveSubtitlePosition: IpcDepsRuntimeOptions['saveSubtitlePosition']; - getMecabTokenizer: IpcDepsRuntimeOptions['getMecabTokenizer']; handleMpvCommand: IpcDepsRuntimeOptions['handleMpvCommand']; - getKeybindings: IpcDepsRuntimeOptions['getKeybindings']; getMpvInputBindings?: IpcDepsRuntimeOptions['getMpvInputBindings']; getSessionBindings: IpcDepsRuntimeOptions['getSessionBindings']; getConfiguredShortcuts: IpcDepsRuntimeOptions['getConfiguredShortcuts']; @@ -94,14 +78,11 @@ export interface MainIpcRuntimeServiceDepsParams { getOverlayNotificationPosition: IpcDepsRuntimeOptions['getOverlayNotificationPosition']; getControllerConfig: IpcDepsRuntimeOptions['getControllerConfig']; saveControllerConfig: IpcDepsRuntimeOptions['saveControllerConfig']; - saveControllerPreference: IpcDepsRuntimeOptions['saveControllerPreference']; getSecondarySubMode: IpcDepsRuntimeOptions['getSecondarySubMode']; getMpvClient: IpcDepsRuntimeOptions['getMpvClient']; runSubsyncManual: IpcDepsRuntimeOptions['runSubsyncManual']; - getAnkiConnectStatus: IpcDepsRuntimeOptions['getAnkiConnectStatus']; getRuntimeOptions: IpcDepsRuntimeOptions['getRuntimeOptions']; setRuntimeOption: IpcDepsRuntimeOptions['setRuntimeOption']; - cycleRuntimeOption: IpcDepsRuntimeOptions['cycleRuntimeOption']; reportOverlayContentBounds: IpcDepsRuntimeOptions['reportOverlayContentBounds']; getAnilistStatus: IpcDepsRuntimeOptions['getAnilistStatus']; clearAnilistToken: IpcDepsRuntimeOptions['clearAnilistToken']; @@ -115,7 +96,6 @@ export interface MainIpcRuntimeServiceDepsParams { getCharacterDictionaryManagerSnapshot?: IpcDepsRuntimeOptions['getCharacterDictionaryManagerSnapshot']; removeCharacterDictionaryManagedEntry?: IpcDepsRuntimeOptions['removeCharacterDictionaryManagedEntry']; moveCharacterDictionaryManagedEntry?: IpcDepsRuntimeOptions['moveCharacterDictionaryManagedEntry']; - appendClipboardVideoToQueue: IpcDepsRuntimeOptions['appendClipboardVideoToQueue']; getChangelogSnapshot?: IpcDepsRuntimeOptions['getChangelogSnapshot']; getPlaylistBrowserSnapshot: IpcDepsRuntimeOptions['getPlaylistBrowserSnapshot']; appendPlaylistBrowserFile: IpcDepsRuntimeOptions['appendPlaylistBrowserFile']; @@ -126,22 +106,9 @@ export interface MainIpcRuntimeServiceDepsParams { } export interface AnkiJimakuIpcRuntimeServiceDepsParams { - patchAnkiConnectEnabled: AnkiJimakuIpcRuntimeOptions['patchAnkiConnectEnabled']; getResolvedConfig: AnkiJimakuIpcRuntimeOptions['getResolvedConfig']; - getRuntimeOptionsManager: AnkiJimakuIpcRuntimeOptions['getRuntimeOptionsManager']; - getSubtitleTimingTracker: AnkiJimakuIpcRuntimeOptions['getSubtitleTimingTracker']; getMpvClient: AnkiJimakuIpcRuntimeOptions['getMpvClient']; getAnkiIntegration: AnkiJimakuIpcRuntimeOptions['getAnkiIntegration']; - setAnkiIntegration: AnkiJimakuIpcRuntimeOptions['setAnkiIntegration']; - getKnownWordCacheStatePath: AnkiJimakuIpcRuntimeOptions['getKnownWordCacheStatePath']; - getCachedMediaPath?: AnkiJimakuIpcRuntimeOptions['getCachedMediaPath']; - shouldRequireRemoteMediaCache?: AnkiJimakuIpcRuntimeOptions['shouldRequireRemoteMediaCache']; - getYoutubeMediaSourceUrl?: AnkiJimakuIpcRuntimeOptions['getYoutubeMediaSourceUrl']; - showDesktopNotification: AnkiJimakuIpcRuntimeOptions['showDesktopNotification']; - showOverlayNotification?: (payload: OverlayNotificationPayload) => void; - dismissOverlayNotification?: (id: string) => void; - createFieldGroupingCallback: AnkiJimakuIpcRuntimeOptions['createFieldGroupingCallback']; - broadcastRuntimeOptionsChanged: AnkiJimakuIpcRuntimeOptions['broadcastRuntimeOptionsChanged']; getFieldGroupingResolver: AnkiJimakuIpcRuntimeOptions['getFieldGroupingResolver']; setFieldGroupingResolver: AnkiJimakuIpcRuntimeOptions['setFieldGroupingResolver']; parseMediaInfo: AnkiJimakuIpcRuntimeOptions['parseMediaInfo']; @@ -258,7 +225,6 @@ export function createMainIpcRuntimeServiceDeps( ): IpcDepsRuntimeOptions { return { getMainWindow: params.getMainWindow, - getVisibleOverlayVisibility: params.getVisibleOverlayVisibility, onOverlayModalClosed: params.onOverlayModalClosed, onOverlayModalOpened: params.onOverlayModalOpened, onOverlayMouseInteractionChanged: params.onOverlayMouseInteractionChanged, @@ -270,12 +236,8 @@ export function createMainIpcRuntimeServiceDeps( getMediaTimingReviewWaveform: params.getMediaTimingReviewWaveform, stopMediaTimingReviewPreview: params.stopMediaTimingReviewPreview, resolveMediaTimingReview: params.resolveMediaTimingReview, - openYomitanSettings: params.openYomitanSettings, - quitApp: params.quitApp, - toggleVisibleOverlay: params.toggleVisibleOverlay, tokenizeCurrentSubtitle: params.tokenizeCurrentSubtitle, getCurrentSubtitleRaw: params.getCurrentSubtitleRaw, - getCurrentSubtitleAss: params.getCurrentSubtitleAss, getSubtitleSidebarSnapshot: params.getSubtitleSidebarSnapshot, getSubtitleSidebarPlaybackState: params.getSubtitleSidebarPlaybackState, getSubtitleSidebarOpen: params.getSubtitleSidebarOpen, @@ -283,9 +245,7 @@ export function createMainIpcRuntimeServiceDeps( getSubtitlePosition: params.getSubtitlePosition, getSubtitleStyle: params.getSubtitleStyle, saveSubtitlePosition: params.saveSubtitlePosition, - getMecabTokenizer: params.getMecabTokenizer, handleMpvCommand: params.handleMpvCommand, - getKeybindings: params.getKeybindings, getMpvInputBindings: params.getMpvInputBindings, getSessionBindings: params.getSessionBindings, getConfiguredShortcuts: params.getConfiguredShortcuts, @@ -295,16 +255,13 @@ export function createMainIpcRuntimeServiceDeps( getOverlayNotificationPosition: params.getOverlayNotificationPosition, getControllerConfig: params.getControllerConfig, saveControllerConfig: params.saveControllerConfig, - saveControllerPreference: params.saveControllerPreference, focusMainWindow: params.focusMainWindow ?? (() => {}), activatePlaybackWindowForOverlayInteraction: params.activatePlaybackWindowForOverlayInteraction, getSecondarySubMode: params.getSecondarySubMode, getMpvClient: params.getMpvClient, runSubsyncManual: params.runSubsyncManual, - getAnkiConnectStatus: params.getAnkiConnectStatus, getRuntimeOptions: params.getRuntimeOptions, setRuntimeOption: params.setRuntimeOption, - cycleRuntimeOption: params.cycleRuntimeOption, reportOverlayContentBounds: params.reportOverlayContentBounds, getAnilistStatus: params.getAnilistStatus, clearAnilistToken: params.clearAnilistToken, @@ -318,7 +275,6 @@ export function createMainIpcRuntimeServiceDeps( getCharacterDictionaryManagerSnapshot: params.getCharacterDictionaryManagerSnapshot, removeCharacterDictionaryManagedEntry: params.removeCharacterDictionaryManagedEntry, moveCharacterDictionaryManagedEntry: params.moveCharacterDictionaryManagedEntry, - appendClipboardVideoToQueue: params.appendClipboardVideoToQueue, getChangelogSnapshot: params.getChangelogSnapshot, getPlaylistBrowserSnapshot: params.getPlaylistBrowserSnapshot, appendPlaylistBrowserFile: params.appendPlaylistBrowserFile, @@ -333,26 +289,9 @@ export function createAnkiJimakuIpcRuntimeServiceDeps( params: AnkiJimakuIpcRuntimeServiceDepsParams, ): AnkiJimakuIpcRuntimeOptions { return { - patchAnkiConnectEnabled: params.patchAnkiConnectEnabled, getResolvedConfig: params.getResolvedConfig, - getRuntimeOptionsManager: params.getRuntimeOptionsManager, - getSubtitleTimingTracker: params.getSubtitleTimingTracker, getMpvClient: params.getMpvClient, getAnkiIntegration: params.getAnkiIntegration, - setAnkiIntegration: params.setAnkiIntegration, - getKnownWordCacheStatePath: params.getKnownWordCacheStatePath, - ...(params.getCachedMediaPath ? { getCachedMediaPath: params.getCachedMediaPath } : {}), - ...(params.shouldRequireRemoteMediaCache - ? { shouldRequireRemoteMediaCache: params.shouldRequireRemoteMediaCache } - : {}), - ...(params.getYoutubeMediaSourceUrl - ? { getYoutubeMediaSourceUrl: params.getYoutubeMediaSourceUrl } - : {}), - showDesktopNotification: params.showDesktopNotification, - showOverlayNotification: params.showOverlayNotification, - dismissOverlayNotification: params.dismissOverlayNotification, - createFieldGroupingCallback: params.createFieldGroupingCallback, - broadcastRuntimeOptionsChanged: params.broadcastRuntimeOptionsChanged, getFieldGroupingResolver: params.getFieldGroupingResolver, setFieldGroupingResolver: params.setFieldGroupingResolver, parseMediaInfo: params.parseMediaInfo, diff --git a/src/main/ipc-runtime.ts b/src/main/ipc-runtime.ts index 4e5f7f6a..3ac27410 100644 --- a/src/main/ipc-runtime.ts +++ b/src/main/ipc-runtime.ts @@ -15,7 +15,7 @@ import { export interface RegisterIpcRuntimeServicesParams { runtimeOptions: RuntimeOptionsIpcDepsParams; - mainDeps: Omit; + mainDeps: Omit; ankiJimakuDeps: AnkiJimakuIpcRuntimeServiceDepsParams; } @@ -40,7 +40,6 @@ export function registerIpcRuntimeServices(params: RegisterIpcRuntimeServicesPar registerMainIpcRuntimeServices({ ...params.mainDeps, setRuntimeOption: runtimeOptionsIpcDeps.setRuntimeOption, - cycleRuntimeOption: runtimeOptionsIpcDeps.cycleRuntimeOption, }); registerAnkiJimakuIpcRuntimeServices(params.ankiJimakuDeps); } diff --git a/src/main/main-wiring.test.ts b/src/main/main-wiring.test.ts index 031db5ea..51953089 100644 --- a/src/main/main-wiring.test.ts +++ b/src/main/main-wiring.test.ts @@ -37,7 +37,6 @@ test('media path changes clear rendered subtitle state without clearing same-you assert.ok(actionBlock); assert.match(actionBlock, /appState\.currentSubText = '';/); - assert.match(actionBlock, /appState\.currentSubAssText = '';/); assert.match(actionBlock, /appState\.currentSubtitleData = null;/); assert.match(actionBlock, /isSameYoutubeMediaPath\(/); assert.match(actionBlock, /if \(!preserveParsedSubtitleCues\)/); diff --git a/src/main/runtime/composers/mpv-runtime-composer.test.ts b/src/main/runtime/composers/mpv-runtime-composer.test.ts index e83683cc..c42e9718 100644 --- a/src/main/runtime/composers/mpv-runtime-composer.test.ts +++ b/src/main/runtime/composers/mpv-runtime-composer.test.ts @@ -45,7 +45,6 @@ function createDefaultMpvFixture() { immersionTracker: null, subtitleTimingTracker: null, currentSubText: '', - currentSubAssText: '', playbackPaused: null, previousSecondarySubVisibility: null, }, diff --git a/src/main/runtime/mpv-client-event-bindings.ts b/src/main/runtime/mpv-client-event-bindings.ts index cb0d7c83..1b761028 100644 --- a/src/main/runtime/mpv-client-event-bindings.ts +++ b/src/main/runtime/mpv-client-event-bindings.ts @@ -1,7 +1,6 @@ type MpvBindingEventName = | 'connection-change' | 'subtitle-change' - | 'subtitle-ass-change' | 'secondary-subtitle-change' | 'subtitle-track-change' | 'secondary-subtitle-track-change' @@ -89,7 +88,6 @@ export function createHandleMpvSubtitleTimingHandler(deps: { export function createBindMpvClientEventHandlers(deps: { onConnectionChange: (payload: { connected: boolean }) => void; onSubtitleChange: (payload: { text: string }) => void; - onSubtitleAssChange: (payload: { text: string }) => void; onSecondarySubtitleChange: (payload: { text: string }) => void; onSubtitleTrackChange: (payload: { sid: number | null }) => void; onSecondarySubtitleTrackChange: (payload: { sid: number | null }) => void; @@ -108,7 +106,6 @@ export function createBindMpvClientEventHandlers(deps: { return (mpvClient: MpvEventClient): void => { mpvClient.on('connection-change', deps.onConnectionChange); mpvClient.on('subtitle-change', deps.onSubtitleChange); - mpvClient.on('subtitle-ass-change', deps.onSubtitleAssChange); mpvClient.on('secondary-subtitle-change', deps.onSecondarySubtitleChange); mpvClient.on('subtitle-track-change', deps.onSubtitleTrackChange); mpvClient.on('secondary-subtitle-track-change', deps.onSecondarySubtitleTrackChange); diff --git a/src/main/runtime/mpv-main-event-actions.ts b/src/main/runtime/mpv-main-event-actions.ts index ab0b4577..01100375 100644 --- a/src/main/runtime/mpv-main-event-actions.ts +++ b/src/main/runtime/mpv-main-event-actions.ts @@ -49,16 +49,6 @@ export function createHandleMpvSubtitleChangeHandler(deps: { }; } -export function createHandleMpvSubtitleAssChangeHandler(deps: { - setCurrentSubAssText: (text: string) => void; - broadcastSubtitleAss: (text: string) => void; -}) { - return ({ text }: { text: string }): void => { - deps.setCurrentSubAssText(text); - deps.broadcastSubtitleAss(text); - }; -} - export function createHandleMpvSecondarySubtitleChangeHandler(deps: { broadcastSecondarySubtitle: (text: string) => void; }) { diff --git a/src/main/runtime/mpv-main-event-bindings.test.ts b/src/main/runtime/mpv-main-event-bindings.test.ts index 2ab395e7..6ffa091d 100644 --- a/src/main/runtime/mpv-main-event-bindings.test.ts +++ b/src/main/runtime/mpv-main-event-bindings.test.ts @@ -29,8 +29,6 @@ function createDeps(overrides: Partial = {}): Deps { onSubtitleChange: () => {}, refreshDiscordPresence: () => {}, - setCurrentSubAssText: () => {}, - broadcastSubtitleAss: () => {}, broadcastSecondarySubtitle: () => {}, updateCurrentMediaPath: () => {}, diff --git a/src/main/runtime/mpv-main-event-bindings.ts b/src/main/runtime/mpv-main-event-bindings.ts index f4eee996..608adb28 100644 --- a/src/main/runtime/mpv-main-event-bindings.ts +++ b/src/main/runtime/mpv-main-event-bindings.ts @@ -10,7 +10,6 @@ import { createHandleMpvPauseChangeHandler, createHandleMpvSecondarySubtitleChangeHandler, createHandleMpvSecondarySubtitleVisibilityHandler, - createHandleMpvSubtitleAssChangeHandler, createHandleMpvSubtitleChangeHandler, createHandleMpvSubtitleMetricsChangeHandler, createHandleMpvTimePosChangeHandler, @@ -52,8 +51,6 @@ export function createBindMpvMainEventHandlersHandler(deps: { logSubtitleProcessingDebug?: (message: string) => void; refreshDiscordPresence: () => void; - setCurrentSubAssText: (text: string) => void; - broadcastSubtitleAss: (text: string) => void; broadcastSecondarySubtitle: (text: string) => void; onSubtitleTrackChange?: (sid: number | null) => void; onSecondarySubtitleTrackChange?: (sid: number | null) => void; @@ -135,10 +132,6 @@ export function createBindMpvMainEventHandlersHandler(deps: { : undefined, refreshDiscordPresence: () => deps.refreshDiscordPresence(), }); - const handleMpvSubtitleAssChange = createHandleMpvSubtitleAssChangeHandler({ - setCurrentSubAssText: (text) => deps.setCurrentSubAssText(text), - broadcastSubtitleAss: (text) => deps.broadcastSubtitleAss(text), - }); const handleMpvSecondarySubtitleChange = createHandleMpvSecondarySubtitleChangeHandler({ broadcastSecondarySubtitle: (text) => deps.broadcastSecondarySubtitle(text), }); @@ -200,7 +193,6 @@ export function createBindMpvMainEventHandlersHandler(deps: { createBindMpvClientEventHandlers({ onConnectionChange: handleMpvConnectionChangeWithSidebarReset, onSubtitleChange: handleMpvSubtitleChange, - onSubtitleAssChange: handleMpvSubtitleAssChange, onSecondarySubtitleChange: handleMpvSecondarySubtitleChange, onSubtitleTrackChange: ({ sid }) => deps.onSubtitleTrackChange?.(sid), onSecondarySubtitleTrackChange: ({ sid }) => deps.onSecondarySubtitleTrackChange?.(sid), diff --git a/src/main/runtime/mpv-main-event-main-deps.test.ts b/src/main/runtime/mpv-main-event-main-deps.test.ts index 0a15f19c..d46d4357 100644 --- a/src/main/runtime/mpv-main-event-main-deps.test.ts +++ b/src/main/runtime/mpv-main-event-main-deps.test.ts @@ -20,7 +20,6 @@ function buildMainDeps( immersionTracker: null, subtitleTimingTracker: null, currentSubText: '', - currentSubAssText: '', playbackPaused: null, previousSecondarySubVisibility: false, ...appStateOverrides, diff --git a/src/main/runtime/mpv-main-event-main-deps.ts b/src/main/runtime/mpv-main-event-main-deps.ts index a7bd5d6c..ac30fd73 100644 --- a/src/main/runtime/mpv-main-event-main-deps.ts +++ b/src/main/runtime/mpv-main-event-main-deps.ts @@ -46,7 +46,6 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: { activeParsedSubtitleSource?: string | null; currentMediaPath?: string | null; currentSubText: string; - currentSubAssText: string; currentSubtitleData?: SubtitleData | null; playbackPaused: boolean | null; previousSecondarySubVisibility: boolean | null; @@ -300,11 +299,6 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: { ? (trackList: unknown[] | null) => deps.onSubtitleTrackListChange!(trackList) : undefined, refreshDiscordPresence: () => deps.refreshDiscordPresence(), - setCurrentSubAssText: (text: string) => { - deps.appState.currentSubAssText = text; - }, - broadcastSubtitleAss: (text: string) => - deps.broadcastToOverlayWindows('subtitle-ass:set', text), broadcastSecondarySubtitle: (text: string) => { if (deps.onSecondarySubtitleChange) { deps.onSecondarySubtitleChange(text); diff --git a/src/main/state.ts b/src/main/state.ts index e9a963dd..c7af0e70 100644 --- a/src/main/state.ts +++ b/src/main/state.ts @@ -160,7 +160,6 @@ export interface AppState { discordPresenceService: ReturnType | null; reconnectTimer: ReturnType | null; currentSubText: string; - currentSubAssText: string; currentSubtitleData: SubtitleData | null; activeParsedSubtitleCues: SubtitleCue[]; activeParsedSubtitleSource: string | null; @@ -247,7 +246,6 @@ export function createAppState(values: AppStateInitialValues): AppState { discordPresenceService: null, reconnectTimer: null, currentSubText: '', - currentSubAssText: '', currentSubtitleData: null, activeParsedSubtitleCues: [], activeParsedSubtitleSource: null, diff --git a/src/mecab-tokenizer.ts b/src/mecab-tokenizer.ts index d2e1bdbc..db7bef3f 100644 --- a/src/mecab-tokenizer.ts +++ b/src/mecab-tokenizer.ts @@ -399,29 +399,6 @@ export class MecabTokenizer { path: this.mecabPath, }; } - - setEnabled(enabled: boolean): void { - this.enabled = enabled; - if (!enabled) { - const pending: MecabQueuedRequest[] = []; - if (this.activeRequest) { - pending.push({ - text: this.activeRequest.text, - retryCount: MecabTokenizer.MAX_RETRY_COUNT, - resolve: this.activeRequest.resolve, - }); - } - if (this.requestQueue.length > 0) { - pending.push(...this.requestQueue); - } - this.activeRequest = null; - this.requestQueue = []; - for (const request of pending) { - request.resolve(null); - } - this.stopPersistentProcess(); - } - } } export { mapMecabPos1ToPartOfSpeech as mapPartOfSpeech }; diff --git a/src/preload.ts b/src/preload.ts index dfcdae7f..22abbaa8 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -22,8 +22,6 @@ import { createIpcListenerFactories } from './preload-ipc-listeners'; import type { SubtitleData, SubtitlePosition, - MecabStatus, - Keybinding, ElectronAPI, SecondarySubMode, SubtitleStyleConfig, @@ -45,7 +43,6 @@ import type { SubsyncManualPayload, SubsyncManualRunRequest, SubsyncResult, - ClipboardAppendResult, PlaylistBrowserMutationResult, PlaylistBrowserSnapshot, KikuFieldGroupingRequestData, @@ -60,7 +57,6 @@ import type { ShortcutsConfig, ConfigHotReloadPayload, ControllerConfigUpdate, - ControllerPreferenceUpdate, ResolvedControllerConfig, SessionHelpOpenPayload, SessionNumericSelectionStartPayload, @@ -176,10 +172,6 @@ const onOverlayNotificationEvent = const onNotificationHistoryToggleEvent = createQueuedIpcListener( IPC_CHANNELS.event.notificationHistoryToggle, ); -const onSubtitleVisibilityEvent = createLatestValueIpcListenerWithPayload( - IPC_CHANNELS.event.subtitleVisibility, - (payload) => payload === true, -); const onSubtitlePositionSetEvent = createLatestValueIpcListenerWithPayload( IPC_CHANNELS.event.subtitlePositionSet, (payload) => payload as SubtitlePosition | null, @@ -236,22 +228,14 @@ const electronAPI: ElectronAPI = { }, onNotificationHistoryToggle: onNotificationHistoryToggleEvent, - onVisibility: (callback: (visible: boolean) => void) => { - onSubtitleVisibilityEvent(callback); - }, - onSubtitlePosition: (callback: (position: SubtitlePosition | null) => void) => { onSubtitlePositionSetEvent(callback); }, - getOverlayVisibility: (): Promise => - ipcRenderer.invoke(IPC_CHANNELS.request.getVisibleOverlayVisibility), getCurrentSubtitle: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitle), getCurrentSubtitleRaw: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitleRaw), - getCurrentSubtitleAss: (): Promise => - ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitleAss), getSubtitleSidebarOpen: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.getSubtitleSidebarOpen), getSubtitleSidebarSnapshot: () => @@ -264,14 +248,6 @@ const electronAPI: ElectronAPI = { }, getPlaybackPaused: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.getPlaybackPaused), - onSubtitleAss: (callback: (assText: string) => void) => { - ipcRenderer.on( - IPC_CHANNELS.event.subtitleAssSet, - (_event: IpcRendererEvent, assText: string) => { - callback(assText); - }, - ); - }, setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => { ipcRenderer.send(IPC_CHANNELS.command.setIgnoreMouseEvents, ignore, options); @@ -281,10 +257,6 @@ const electronAPI: ElectronAPI = { ipcRenderer.send(IPC_CHANNELS.command.reportOverlayInteractive, interactive); }, - openYomitanSettings: () => { - ipcRenderer.send(IPC_CHANNELS.command.openYomitanSettings); - }, - recordYomitanLookup: (context?: SubtitleMiningContext | null) => { ipcRenderer.send(IPC_CHANNELS.command.recordYomitanLookup, context ?? null); }, @@ -295,18 +267,10 @@ const electronAPI: ElectronAPI = { ipcRenderer.send(IPC_CHANNELS.command.saveSubtitlePosition, position); }, - getMecabStatus: (): Promise => - ipcRenderer.invoke(IPC_CHANNELS.request.getMecabStatus), - setMecabEnabled: (enabled: boolean) => { - ipcRenderer.send(IPC_CHANNELS.command.setMecabEnabled, enabled); - }, - sendMpvCommand: (command: (string | number)[]) => { ipcRenderer.send(IPC_CHANNELS.command.mpvCommand, command); }, - getKeybindings: (): Promise => - ipcRenderer.invoke(IPC_CHANNELS.request.getKeybindings), getMpvInputBindings: () => ipcRenderer.invoke(IPC_CHANNELS.request.getMpvInputBindings), getSessionBindings: () => ipcRenderer.invoke(IPC_CHANNELS.request.getSessionBindings), getConfiguredShortcuts: (): Promise> => @@ -325,8 +289,6 @@ const electronAPI: ElectronAPI = { ipcRenderer.invoke(IPC_CHANNELS.request.getControllerConfig), saveControllerConfig: (update: ControllerConfigUpdate): Promise => ipcRenderer.invoke(IPC_CHANNELS.command.saveControllerConfig, update), - saveControllerPreference: (update: ControllerPreferenceUpdate): Promise => - ipcRenderer.invoke(IPC_CHANNELS.command.saveControllerPreference, update), getJimakuMediaInfo: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.jimakuGetMediaInfo), @@ -350,31 +312,14 @@ const electronAPI: ElectronAPI = { tsukihimeGetSecondaryLanguages: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.tsukihimeGetSecondaryLanguages), - quitApp: () => { - ipcRenderer.send(IPC_CHANNELS.command.quitApp); - }, - toggleDevTools: () => { ipcRenderer.send(IPC_CHANNELS.command.toggleDevTools); }, - toggleOverlay: () => { - ipcRenderer.send(IPC_CHANNELS.command.toggleOverlay); - }, - toggleStatsOverlay: () => { ipcRenderer.send(IPC_CHANNELS.command.toggleStatsOverlay); }, - getAnkiConnectStatus: (): Promise => - ipcRenderer.invoke(IPC_CHANNELS.request.getAnkiConnectStatus), - setAnkiConnectEnabled: (enabled: boolean) => { - ipcRenderer.send(IPC_CHANNELS.command.setAnkiConnectEnabled, enabled); - }, - clearAnkiConnectHistory: () => { - ipcRenderer.send(IPC_CHANNELS.command.clearAnkiConnectHistory); - }, - onSecondarySub: (callback: (text: string) => void) => { onSecondarySubtitleSetEvent(callback); }, @@ -419,8 +364,6 @@ const electronAPI: ElectronAPI = { value: RuntimeOptionValue, ): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.setRuntimeOption, id, value), - cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1): Promise => - ipcRenderer.invoke(IPC_CHANNELS.request.cycleRuntimeOption, id, direction), onRuntimeOptionsChanged: (callback: (options: RuntimeOptionState[]) => void) => { ipcRenderer.on( IPC_CHANNELS.event.runtimeOptionsChanged, @@ -485,8 +428,6 @@ const electronAPI: ElectronAPI = { onSessionNumericSelectionStart: onSessionNumericSelectionStartEvent, onKeyboardModeToggleRequested: onKeyboardModeToggleRequestedEvent, onLookupWindowToggleRequested: onLookupWindowToggleRequestedEvent, - appendClipboardVideoToQueue: (): Promise => - ipcRenderer.invoke(IPC_CHANNELS.request.appendClipboardVideoToQueue), getPlaylistBrowserSnapshot: (): Promise => ipcRenderer.invoke(IPC_CHANNELS.request.getPlaylistBrowserSnapshot), appendPlaylistBrowserFile: (pathValue: string): Promise => diff --git a/src/renderer/handlers/keyboard.test.ts b/src/renderer/handlers/keyboard.test.ts index cca4b7c1..0dff8e0f 100644 --- a/src/renderer/handlers/keyboard.test.ts +++ b/src/renderer/handlers/keyboard.test.ts @@ -242,7 +242,6 @@ function installKeyboardTestGlobals() { windowFocusCalls += 1; }, electronAPI: { - getKeybindings: async () => [], getMpvInputBindings: () => getMpvInputBindings(), getSessionBindings: () => getSessionBindingsImpl(), getConfiguredShortcuts: async () => configuredShortcuts, diff --git a/src/shared/ipc/contracts.ts b/src/shared/ipc/contracts.ts index 9afd5831..c7e32116 100644 --- a/src/shared/ipc/contracts.ts +++ b/src/shared/ipc/contracts.ts @@ -25,22 +25,15 @@ export const IPC_CHANNELS = { command: { setIgnoreMouseEvents: 'set-ignore-mouse-events', overlayModalClosed: 'overlay:modal-closed', - openYomitanSettings: 'open-yomitan-settings', recordYomitanLookup: 'record-yomitan-lookup', - quitApp: 'quit-app', youtubePickerResolve: 'youtube:picker-resolve', toggleDevTools: 'toggle-dev-tools', - toggleOverlay: 'toggle-overlay', saveSubtitlePosition: 'save-subtitle-position', statsNativeConfirmDialog: 'stats:native-confirm-dialog', statsNativeDialogOpened: 'stats:native-dialog-opened', statsNativeDialogClosed: 'stats:native-dialog-closed', saveControllerConfig: 'save-controller-config', - saveControllerPreference: 'save-controller-preference', - setMecabEnabled: 'set-mecab-enabled', mpvCommand: 'mpv-command', - setAnkiConnectEnabled: 'set-anki-connect-enabled', - clearAnkiConnectHistory: 'clear-anki-connect-history', refreshKnownWords: 'anki:refresh-known-words', kikuFieldGroupingRespond: 'kiku:field-grouping-respond', reportOverlayContentBounds: 'overlay-content-bounds:report', @@ -63,18 +56,14 @@ export const IPC_CHANNELS = { downloadSubtitleGenerationVadModel: 'subtitle-generation:download-vad', setSubtitleGenerationVadEnabled: 'subtitle-generation:set-vad-enabled', cancelSubtitleGeneration: 'subtitle-generation:cancel', - getVisibleOverlayVisibility: 'get-visible-overlay-visibility', getCurrentSubtitle: 'get-current-subtitle', getCurrentSubtitleRaw: 'get-current-subtitle-raw', - getCurrentSubtitleAss: 'get-current-subtitle-ass', getSubtitleSidebarSnapshot: 'get-subtitle-sidebar-snapshot', getSubtitleSidebarPlaybackState: 'get-subtitle-sidebar-playback-state', getSubtitleSidebarOpen: 'get-subtitle-sidebar-open', getPlaybackPaused: 'get-playback-paused', getSubtitlePosition: 'get-subtitle-position', getSubtitleStyle: 'get-subtitle-style', - getMecabStatus: 'get-mecab-status', - getKeybindings: 'get-keybindings', getMpvInputBindings: 'get-mpv-input-bindings', getSessionBindings: 'get-session-bindings', getConfigShortcuts: 'get-config-shortcuts', @@ -88,10 +77,8 @@ export const IPC_CHANNELS = { focusMainWindow: 'focus-main-window', activatePlaybackWindowForOverlayInteraction: 'overlay:activate-playback-window', runSubsyncManual: 'subsync:run-manual', - getAnkiConnectStatus: 'get-anki-connect-status', getRuntimeOptions: 'runtime-options:get', setRuntimeOption: 'runtime-options:set', - cycleRuntimeOption: 'runtime-options:cycle', getAnilistStatus: 'anilist:get-status', clearAnilistToken: 'anilist:clear-token', openAnilistSetup: 'anilist:open-setup', @@ -103,7 +90,6 @@ export const IPC_CHANNELS = { getCharacterDictionaryManagerSnapshot: 'character-dictionary:get-manager-snapshot', removeCharacterDictionaryManagedEntry: 'character-dictionary:remove-managed-entry', moveCharacterDictionaryManagedEntry: 'character-dictionary:move-managed-entry', - appendClipboardVideoToQueue: 'clipboard:append-video-to-queue', getPlaylistBrowserSnapshot: 'playlist-browser:get-snapshot', appendPlaylistBrowserFile: 'playlist-browser:append-file', playPlaylistBrowserIndex: 'playlist-browser:play-index', @@ -153,9 +139,7 @@ export const IPC_CHANNELS = { subtitleGenerationProgress: 'subtitle-generation:progress', subtitleSet: 'subtitle:set', overlayPointerRecoveryRequest: 'overlay:pointer-recovery-request', - subtitleVisibility: 'mpv:subVisibility', subtitlePositionSet: 'subtitle-position:set', - subtitleAssSet: 'subtitle-ass:set', secondarySubtitleSet: 'secondary-subtitle:set', secondarySubtitleMode: 'secondary-subtitle:mode', subsyncOpenManual: 'subsync:open-manual', @@ -197,11 +181,6 @@ export type RuntimeOptionsSetRequest = { value: RuntimeOptionValue; }; -export type RuntimeOptionsCycleRequest = { - id: RuntimeOptionId; - direction: 1 | -1; -}; - export type OverlayContentBoundsReportRequest = { measurement: OverlayContentMeasurement; }; diff --git a/src/shared/ipc/validators.ts b/src/shared/ipc/validators.ts index 26dca4fb..be4b37cd 100644 --- a/src/shared/ipc/validators.ts +++ b/src/shared/ipc/validators.ts @@ -10,7 +10,6 @@ import type { } from '../../types/integrations'; import type { ControllerConfigUpdate, - ControllerPreferenceUpdate, SessionActionDispatchRequest, SubsyncManualRunRequest, } from '../../types/runtime'; @@ -131,16 +130,6 @@ export function parseSubtitlePosition(value: unknown): SubtitlePosition | null { }; } -export function parseControllerPreferenceUpdate(value: unknown): ControllerPreferenceUpdate | null { - if (!isObject(value)) return null; - if (typeof value.preferredGamepadId !== 'string') return null; - if (typeof value.preferredGamepadLabel !== 'string') return null; - return { - preferredGamepadId: value.preferredGamepadId, - preferredGamepadLabel: value.preferredGamepadLabel, - }; -} - function parseDiscreteBinding(value: unknown) { if (!isObject(value) || typeof value.kind !== 'string') return null; if (value.kind === 'none') { @@ -328,10 +317,6 @@ export function parseRuntimeOptionId(value: unknown): RuntimeOptionId | null { return RUNTIME_OPTION_IDS.includes(value as RuntimeOptionId) ? (value as RuntimeOptionId) : null; } -export function parseRuntimeOptionDirection(value: unknown): 1 | -1 | null { - return value === 1 || value === -1 ? value : null; -} - export function parseRuntimeOptionValue(value: unknown): RuntimeOptionValue | null { return typeof value === 'boolean' || typeof value === 'string' ? (value as RuntimeOptionValue) diff --git a/src/types/runtime.ts b/src/types/runtime.ts index 54bd36f5..6d9a7253 100644 --- a/src/types/runtime.ts +++ b/src/types/runtime.ts @@ -297,11 +297,6 @@ export interface ControllerConfig { profiles?: Record; } -export interface ControllerPreferenceUpdate { - preferredGamepadId: string; - preferredGamepadLabel: string; -} - export type ControllerConfigUpdate = ControllerConfig; export interface ControllerDeviceInfo { @@ -470,28 +465,20 @@ export interface ElectronAPI { options?: Pick, ) => void; onNotificationHistoryToggle: (callback: () => void) => void; - onVisibility: (callback: (visible: boolean) => void) => void; onSubtitlePosition: (callback: (position: SubtitlePosition | null) => void) => void; - getOverlayVisibility: () => Promise; getCurrentSubtitle: () => Promise; getCurrentSubtitleRaw: () => Promise; - getCurrentSubtitleAss: () => Promise; getSubtitleSidebarSnapshot: () => Promise; getSubtitleSidebarPlaybackState: () => Promise; copySubtitleSidebarSelection: (text: string) => Promise; getSubtitleSidebarOpen: () => Promise; getPlaybackPaused: () => Promise; - onSubtitleAss: (callback: (assText: string) => void) => void; setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => void; reportOverlayInteractive: (interactive: boolean) => void; - openYomitanSettings: () => void; recordYomitanLookup: (context?: SubtitleMiningContext | null) => void; getSubtitlePosition: () => Promise; saveSubtitlePosition: (position: SubtitlePosition) => void; - getMecabStatus: () => Promise; - setMecabEnabled: (enabled: boolean) => void; sendMpvCommand: (command: (string | number)[]) => void; - getKeybindings: () => Promise; getMpvInputBindings: () => Promise; getSessionBindings: () => Promise; getConfiguredShortcuts: () => Promise>; @@ -505,7 +492,6 @@ export interface ElectronAPI { markActiveVideoWatched: () => Promise; getControllerConfig: () => Promise; saveControllerConfig: (update: ControllerConfigUpdate) => Promise; - saveControllerPreference: (update: ControllerPreferenceUpdate) => Promise; getJimakuMediaInfo: () => Promise; jimakuSearchEntries: (query: JimakuSearchQuery) => Promise>; jimakuListFiles: (query: JimakuFilesQuery) => Promise>; @@ -518,13 +504,8 @@ export interface ElectronAPI { ) => Promise>; tsukihimeDownloadFile: (query: TsukihimeDownloadQuery) => Promise; tsukihimeGetSecondaryLanguages: () => Promise; - quitApp: () => void; toggleDevTools: () => void; - toggleOverlay: () => void; toggleStatsOverlay: () => void; - getAnkiConnectStatus: () => Promise; - setAnkiConnectEnabled: (enabled: boolean) => void; - clearAnkiConnectHistory: () => void; onSecondarySub: (callback: (text: string) => void) => void; onSecondarySubMode: (callback: (mode: SecondarySubMode) => void) => void; getSecondarySubMode: () => Promise; @@ -550,7 +531,6 @@ export interface ElectronAPI { id: RuntimeOptionId, value: RuntimeOptionValue, ) => Promise; - cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => Promise; onRuntimeOptionsChanged: (callback: (options: RuntimeOptionState[]) => void) => void; onOpenRuntimeOptions: (callback: () => void) => void; onOpenSessionHelp: (callback: (payload: SessionHelpOpenPayload) => void) => void; @@ -589,7 +569,6 @@ export interface ElectronAPI { ) => void; onKeyboardModeToggleRequested: (callback: () => void) => void; onLookupWindowToggleRequested: (callback: () => void) => void; - appendClipboardVideoToQueue: () => Promise; getPlaylistBrowserSnapshot: () => Promise; appendPlaylistBrowserFile: (path: string) => Promise; playPlaylistBrowserIndex: (index: number) => Promise;