From dec9320b3486a6753f7b2ee25906ba3a55020220 Mon Sep 17 00:00:00 2001 From: sudacode Date: Tue, 10 Feb 2026 01:22:13 -0800 Subject: [PATCH] refactor: extract ipc mpv and tokenizer runtime deps --- package.json | 2 +- src/core/services/ipc-command-service.ts | 41 ++++--- ...v-command-ipc-deps-runtime-service.test.ts | 28 +++++ .../mpv-command-ipc-deps-runtime-service.ts | 53 +++++++++ ...e-options-ipc-deps-runtime-service.test.ts | 28 +++++ ...untime-options-ipc-deps-runtime-service.ts | 38 ++++++ .../tokenizer-deps-runtime-service.test.ts | 48 ++++++++ .../tokenizer-deps-runtime-service.ts | 45 +++++++ src/main.ts | 112 +++++++----------- 9 files changed, 308 insertions(+), 87 deletions(-) create mode 100644 src/core/services/mpv-command-ipc-deps-runtime-service.test.ts create mode 100644 src/core/services/mpv-command-ipc-deps-runtime-service.ts create mode 100644 src/core/services/runtime-options-ipc-deps-runtime-service.test.ts create mode 100644 src/core/services/runtime-options-ipc-deps-runtime-service.ts create mode 100644 src/core/services/tokenizer-deps-runtime-service.test.ts create mode 100644 src/core/services/tokenizer-deps-runtime-service.ts diff --git a/package.json b/package.json index b94c7cd..c4bd3a6 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "docs:build": "vitepress build docs", "docs:preview": "vitepress preview docs --host 0.0.0.0 --port 4173 --strictPort", "test:config": "pnpm run build && node --test dist/config/config.test.js", - "test:core": "pnpm run build && node --test dist/cli/args.test.js dist/cli/help.test.js dist/core/services/cli-command-service.test.js dist/core/services/cli-command-deps-runtime-service.test.js dist/core/services/ipc-deps-runtime-service.test.js dist/core/services/anki-jimaku-ipc-deps-runtime-service.test.js dist/core/services/field-grouping-overlay-runtime-service.test.js dist/core/services/subsync-deps-runtime-service.test.js dist/core/services/numeric-shortcut-runtime-service.test.js dist/core/services/numeric-shortcut-session-service.test.js dist/core/services/overlay-visibility-facade-deps-runtime-service.test.js dist/core/services/secondary-subtitle-service.test.js dist/core/services/mpv-render-metrics-service.test.js dist/core/services/mpv-runtime-service.test.js dist/core/services/runtime-options-runtime-service.test.js dist/core/services/overlay-modal-restore-service.test.js dist/core/services/runtime-config-service.test.js dist/core/services/overlay-bridge-runtime-service.test.js dist/core/services/overlay-visibility-facade-service.test.js dist/core/services/overlay-broadcast-runtime-service.test.js dist/core/services/app-ready-runtime-service.test.js dist/core/services/app-shutdown-runtime-service.test.js dist/core/services/mpv-client-deps-runtime-service.test.js dist/core/services/app-lifecycle-deps-runtime-service.test.js dist/core/services/runtime-options-manager-runtime-service.test.js dist/core/services/config-warning-runtime-service.test.js dist/core/services/app-logging-runtime-service.test.js dist/core/services/startup-resource-runtime-service.test.js dist/core/services/config-generation-runtime-service.test.js", + "test:core": "pnpm run build && node --test dist/cli/args.test.js dist/cli/help.test.js dist/core/services/cli-command-service.test.js dist/core/services/cli-command-deps-runtime-service.test.js dist/core/services/ipc-deps-runtime-service.test.js dist/core/services/anki-jimaku-ipc-deps-runtime-service.test.js dist/core/services/field-grouping-overlay-runtime-service.test.js dist/core/services/subsync-deps-runtime-service.test.js dist/core/services/numeric-shortcut-runtime-service.test.js dist/core/services/numeric-shortcut-session-service.test.js dist/core/services/overlay-visibility-facade-deps-runtime-service.test.js dist/core/services/mpv-command-ipc-deps-runtime-service.test.js dist/core/services/runtime-options-ipc-deps-runtime-service.test.js dist/core/services/tokenizer-deps-runtime-service.test.js dist/core/services/secondary-subtitle-service.test.js dist/core/services/mpv-render-metrics-service.test.js dist/core/services/mpv-runtime-service.test.js dist/core/services/runtime-options-runtime-service.test.js dist/core/services/overlay-modal-restore-service.test.js dist/core/services/runtime-config-service.test.js dist/core/services/overlay-bridge-runtime-service.test.js dist/core/services/overlay-visibility-facade-service.test.js dist/core/services/overlay-broadcast-runtime-service.test.js dist/core/services/app-ready-runtime-service.test.js dist/core/services/app-shutdown-runtime-service.test.js dist/core/services/mpv-client-deps-runtime-service.test.js dist/core/services/app-lifecycle-deps-runtime-service.test.js dist/core/services/runtime-options-manager-runtime-service.test.js dist/core/services/config-warning-runtime-service.test.js dist/core/services/app-logging-runtime-service.test.js dist/core/services/startup-resource-runtime-service.test.js dist/core/services/config-generation-runtime-service.test.js", "test:subtitle": "pnpm run build && node --test dist/subtitle/stages.test.js dist/subtitle/pipeline.test.js", "generate:config-example": "pnpm run build && node dist/generate-config-example.js", "start": "pnpm run build && electron . --start", diff --git a/src/core/services/ipc-command-service.ts b/src/core/services/ipc-command-service.ts index 93cdbd2..d5defe6 100644 --- a/src/core/services/ipc-command-service.ts +++ b/src/core/services/ipc-command-service.ts @@ -6,26 +6,31 @@ import { SubsyncResult, } from "../../types"; +export interface HandleMpvCommandFromIpcOptions { + specialCommands: { + SUBSYNC_TRIGGER: string; + RUNTIME_OPTIONS_OPEN: string; + RUNTIME_OPTION_CYCLE_PREFIX: string; + REPLAY_SUBTITLE: string; + PLAY_NEXT_SUBTITLE: string; + }; + triggerSubsyncFromConfig: () => void; + openRuntimeOptionsPalette: () => void; + runtimeOptionsCycle: ( + id: RuntimeOptionId, + direction: 1 | -1, + ) => RuntimeOptionApplyResult; + showMpvOsd: (text: string) => void; + mpvReplaySubtitle: () => void; + mpvPlayNextSubtitle: () => void; + mpvSendCommand: (command: (string | number)[]) => void; + isMpvConnected: () => boolean; + hasRuntimeOptionsManager: () => boolean; +} + export function handleMpvCommandFromIpcService( command: (string | number)[], - options: { - specialCommands: { - SUBSYNC_TRIGGER: string; - RUNTIME_OPTIONS_OPEN: string; - RUNTIME_OPTION_CYCLE_PREFIX: string; - REPLAY_SUBTITLE: string; - PLAY_NEXT_SUBTITLE: string; - }; - triggerSubsyncFromConfig: () => void; - openRuntimeOptionsPalette: () => void; - runtimeOptionsCycle: (id: RuntimeOptionId, direction: 1 | -1) => RuntimeOptionApplyResult; - showMpvOsd: (text: string) => void; - mpvReplaySubtitle: () => void; - mpvPlayNextSubtitle: () => void; - mpvSendCommand: (command: (string | number)[]) => void; - isMpvConnected: () => boolean; - hasRuntimeOptionsManager: () => boolean; - }, + options: HandleMpvCommandFromIpcOptions, ): void { const first = typeof command[0] === "string" ? command[0] : ""; if (first === options.specialCommands.SUBSYNC_TRIGGER) { diff --git a/src/core/services/mpv-command-ipc-deps-runtime-service.test.ts b/src/core/services/mpv-command-ipc-deps-runtime-service.test.ts new file mode 100644 index 0000000..1e5438b --- /dev/null +++ b/src/core/services/mpv-command-ipc-deps-runtime-service.test.ts @@ -0,0 +1,28 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { SPECIAL_COMMANDS } from "../../config"; +import { createMpvCommandIpcDepsRuntimeService } from "./mpv-command-ipc-deps-runtime-service"; + +test("createMpvCommandIpcDepsRuntimeService wires runtime-options cycle and manager availability", () => { + const osd: string[] = []; + const deps = createMpvCommandIpcDepsRuntimeService({ + specialCommands: SPECIAL_COMMANDS, + triggerSubsyncFromConfig: () => {}, + openRuntimeOptionsPalette: () => {}, + getRuntimeOptionsManager: () => ({ + cycleOption: () => ({ ok: true, osdMessage: "cycled" }), + }), + showMpvOsd: (text) => { + osd.push(text); + }, + mpvReplaySubtitle: () => {}, + mpvPlayNextSubtitle: () => {}, + mpvSendCommand: () => {}, + isMpvConnected: () => true, + }); + + const result = deps.runtimeOptionsCycle("subtitles.secondaryMode" as never, 1); + assert.equal(result.ok, true); + assert.equal(deps.hasRuntimeOptionsManager(), true); + assert.ok(osd.includes("cycled")); +}); diff --git a/src/core/services/mpv-command-ipc-deps-runtime-service.ts b/src/core/services/mpv-command-ipc-deps-runtime-service.ts new file mode 100644 index 0000000..f117e56 --- /dev/null +++ b/src/core/services/mpv-command-ipc-deps-runtime-service.ts @@ -0,0 +1,53 @@ +import { + RuntimeOptionApplyResult, + RuntimeOptionId, +} from "../../types"; +import { + HandleMpvCommandFromIpcOptions, +} from "./ipc-command-service"; +import { applyRuntimeOptionResultRuntimeService } from "./runtime-options-runtime-service"; + +interface RuntimeOptionsManagerLike { + cycleOption: ( + id: RuntimeOptionId, + direction: 1 | -1, + ) => RuntimeOptionApplyResult; +} + +export interface MpvCommandIpcDepsRuntimeOptions { + specialCommands: HandleMpvCommandFromIpcOptions["specialCommands"]; + triggerSubsyncFromConfig: () => void; + openRuntimeOptionsPalette: () => void; + getRuntimeOptionsManager: () => RuntimeOptionsManagerLike | null; + showMpvOsd: (text: string) => void; + mpvReplaySubtitle: () => void; + mpvPlayNextSubtitle: () => void; + mpvSendCommand: (command: (string | number)[]) => void; + isMpvConnected: () => boolean; +} + +export function createMpvCommandIpcDepsRuntimeService( + options: MpvCommandIpcDepsRuntimeOptions, +): HandleMpvCommandFromIpcOptions { + return { + specialCommands: options.specialCommands, + triggerSubsyncFromConfig: options.triggerSubsyncFromConfig, + openRuntimeOptionsPalette: options.openRuntimeOptionsPalette, + runtimeOptionsCycle: (id, direction) => { + const manager = options.getRuntimeOptionsManager(); + if (!manager) { + return { ok: false, error: "Runtime options manager unavailable" }; + } + return applyRuntimeOptionResultRuntimeService( + manager.cycleOption(id, direction), + options.showMpvOsd, + ); + }, + showMpvOsd: options.showMpvOsd, + mpvReplaySubtitle: options.mpvReplaySubtitle, + mpvPlayNextSubtitle: options.mpvPlayNextSubtitle, + mpvSendCommand: options.mpvSendCommand, + isMpvConnected: options.isMpvConnected, + hasRuntimeOptionsManager: () => options.getRuntimeOptionsManager() !== null, + }; +} diff --git a/src/core/services/runtime-options-ipc-deps-runtime-service.test.ts b/src/core/services/runtime-options-ipc-deps-runtime-service.test.ts new file mode 100644 index 0000000..77d6aa2 --- /dev/null +++ b/src/core/services/runtime-options-ipc-deps-runtime-service.test.ts @@ -0,0 +1,28 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { createRuntimeOptionsIpcDepsRuntimeService } from "./runtime-options-ipc-deps-runtime-service"; + +test("createRuntimeOptionsIpcDepsRuntimeService delegates set/cycle with osd", () => { + const osd: string[] = []; + const deps = createRuntimeOptionsIpcDepsRuntimeService({ + getRuntimeOptionsManager: () => ({ + setOptionValue: () => ({ ok: true, osdMessage: "set ok" }), + cycleOption: () => ({ ok: true, osdMessage: "cycle ok" }), + }), + showMpvOsd: (text) => { + osd.push(text); + }, + }); + + const setResult = deps.setRuntimeOption("subtitles.secondaryMode", "hidden") as { + ok: boolean; + }; + const cycleResult = deps.cycleRuntimeOption("subtitles.secondaryMode", 1) as { + ok: boolean; + }; + + assert.equal(setResult.ok, true); + assert.equal(cycleResult.ok, true); + assert.ok(osd.includes("set ok")); + assert.ok(osd.includes("cycle ok")); +}); diff --git a/src/core/services/runtime-options-ipc-deps-runtime-service.ts b/src/core/services/runtime-options-ipc-deps-runtime-service.ts new file mode 100644 index 0000000..55777cf --- /dev/null +++ b/src/core/services/runtime-options-ipc-deps-runtime-service.ts @@ -0,0 +1,38 @@ +import { + RuntimeOptionId, + RuntimeOptionValue, +} from "../../types"; +import { + cycleRuntimeOptionFromIpcRuntimeService, + RuntimeOptionsManagerLike, + setRuntimeOptionFromIpcRuntimeService, +} from "./runtime-options-runtime-service"; + +export interface RuntimeOptionsIpcDepsRuntimeOptions { + getRuntimeOptionsManager: () => RuntimeOptionsManagerLike | null; + showMpvOsd: (text: string) => void; +} + +export function createRuntimeOptionsIpcDepsRuntimeService( + options: RuntimeOptionsIpcDepsRuntimeOptions, +): { + setRuntimeOption: (id: string, value: unknown) => unknown; + cycleRuntimeOption: (id: string, direction: 1 | -1) => unknown; +} { + return { + setRuntimeOption: (id, value) => + setRuntimeOptionFromIpcRuntimeService( + options.getRuntimeOptionsManager(), + id as RuntimeOptionId, + value as RuntimeOptionValue, + options.showMpvOsd, + ), + cycleRuntimeOption: (id, direction) => + cycleRuntimeOptionFromIpcRuntimeService( + options.getRuntimeOptionsManager(), + id as RuntimeOptionId, + direction, + options.showMpvOsd, + ), + }; +} diff --git a/src/core/services/tokenizer-deps-runtime-service.test.ts b/src/core/services/tokenizer-deps-runtime-service.test.ts new file mode 100644 index 0000000..298fd62 --- /dev/null +++ b/src/core/services/tokenizer-deps-runtime-service.test.ts @@ -0,0 +1,48 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { PartOfSpeech } from "../../types"; +import { createTokenizerDepsRuntimeService } from "./tokenizer-deps-runtime-service"; + +test("createTokenizerDepsRuntimeService tokenizes with mecab and merge", async () => { + let parserWindow: any = null; + let readyPromise: Promise | null = null; + let initPromise: Promise | null = null; + + const deps = createTokenizerDepsRuntimeService({ + getYomitanExt: () => null, + getYomitanParserWindow: () => parserWindow, + setYomitanParserWindow: (window) => { + parserWindow = window; + }, + getYomitanParserReadyPromise: () => readyPromise, + setYomitanParserReadyPromise: (promise) => { + readyPromise = promise; + }, + getYomitanParserInitPromise: () => initPromise, + setYomitanParserInitPromise: (promise) => { + initPromise = promise; + }, + getMecabTokenizer: () => ({ + tokenize: async () => [ + { + word: "猫", + partOfSpeech: PartOfSpeech.noun, + pos1: "名詞", + pos2: "一般", + pos3: "", + pos4: "", + inflectionType: "", + inflectionForm: "", + headword: "猫", + katakanaReading: "ネコ", + pronunciation: "ネコ", + }, + ], + }), + }); + + const merged = await deps.tokenizeWithMecab("猫"); + assert.ok(Array.isArray(merged)); + assert.equal(merged?.length, 1); + assert.equal(merged?.[0]?.surface, "猫"); +}); diff --git a/src/core/services/tokenizer-deps-runtime-service.ts b/src/core/services/tokenizer-deps-runtime-service.ts new file mode 100644 index 0000000..337a519 --- /dev/null +++ b/src/core/services/tokenizer-deps-runtime-service.ts @@ -0,0 +1,45 @@ +import { BrowserWindow, Extension } from "electron"; +import { mergeTokens } from "../../token-merger"; +import { TokenizerServiceDeps } from "./tokenizer-service"; + +interface RawTokenLike {} + +interface MecabTokenizerLike { + tokenize: (text: string) => Promise; +} + +export interface TokenizerDepsRuntimeOptions { + getYomitanExt: () => Extension | null; + getYomitanParserWindow: () => BrowserWindow | null; + setYomitanParserWindow: (window: BrowserWindow | null) => void; + getYomitanParserReadyPromise: () => Promise | null; + setYomitanParserReadyPromise: (promise: Promise | null) => void; + getYomitanParserInitPromise: () => Promise | null; + setYomitanParserInitPromise: (promise: Promise | null) => void; + getMecabTokenizer: () => MecabTokenizerLike | null; +} + +export function createTokenizerDepsRuntimeService( + options: TokenizerDepsRuntimeOptions, +): TokenizerServiceDeps { + return { + getYomitanExt: options.getYomitanExt, + getYomitanParserWindow: options.getYomitanParserWindow, + setYomitanParserWindow: options.setYomitanParserWindow, + getYomitanParserReadyPromise: options.getYomitanParserReadyPromise, + setYomitanParserReadyPromise: options.setYomitanParserReadyPromise, + getYomitanParserInitPromise: options.getYomitanParserInitPromise, + setYomitanParserInitPromise: options.setYomitanParserInitPromise, + tokenizeWithMecab: async (text) => { + const mecabTokenizer = options.getMecabTokenizer(); + if (!mecabTokenizer) { + return null; + } + const rawTokens = await mecabTokenizer.tokenize(text); + if (!rawTokens || rawTokens.length === 0) { + return null; + } + return mergeTokens(rawTokens as never); + }, + }; +} diff --git a/src/main.ts b/src/main.ts index 4e69d79..9db5abc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -46,7 +46,6 @@ import * as os from "os"; import * as fs from "fs"; import * as crypto from "crypto"; import { MecabTokenizer } from "./mecab-tokenizer"; -import { mergeTokens } from "./token-merger"; import { BaseWindowTracker } from "./window-trackers"; import { JimakuApiResponse, @@ -64,9 +63,7 @@ import { KikuFieldGroupingChoice, KikuMergePreviewRequest, KikuMergePreviewResponse, - RuntimeOptionId, RuntimeOptionState, - RuntimeOptionValue, MpvSubtitleRenderMetrics, } from "./types"; import { SubtitleTimingTracker } from "./subtitle-timing-tracker"; @@ -136,11 +133,6 @@ import { setMpvSubVisibilityRuntimeService, showMpvOsdRuntimeService, } from "./core/services/mpv-runtime-service"; -import { - applyRuntimeOptionResultRuntimeService, - cycleRuntimeOptionFromIpcRuntimeService, - setRuntimeOptionFromIpcRuntimeService, -} from "./core/services/runtime-options-runtime-service"; import { getInitialInvisibleOverlayVisibilityService, isAutoUpdateEnabledRuntimeService, @@ -206,6 +198,9 @@ import { createFieldGroupingOverlayRuntimeService } from "./core/services/field- import { createSubsyncRuntimeDepsService } from "./core/services/subsync-deps-runtime-service"; import { createNumericShortcutRuntimeService } from "./core/services/numeric-shortcut-runtime-service"; import { createOverlayVisibilityFacadeDepsRuntimeService } from "./core/services/overlay-visibility-facade-deps-runtime-service"; +import { createMpvCommandIpcDepsRuntimeService } from "./core/services/mpv-command-ipc-deps-runtime-service"; +import { createRuntimeOptionsIpcDepsRuntimeService } from "./core/services/runtime-options-ipc-deps-runtime-service"; +import { createTokenizerDepsRuntimeService } from "./core/services/tokenizer-deps-runtime-service"; import { createRuntimeOptionsManagerRuntimeService } from "./core/services/runtime-options-manager-runtime-service"; import { createAppLoggingRuntimeService } from "./core/services/app-logging-runtime-service"; import { @@ -753,31 +748,25 @@ function updateMpvSubtitleRenderMetrics( } async function tokenizeSubtitle(text: string): Promise { - return tokenizeSubtitleService(text, { - getYomitanExt: () => yomitanExt, - getYomitanParserWindow: () => yomitanParserWindow, - setYomitanParserWindow: (window) => { - yomitanParserWindow = window; - }, - getYomitanParserReadyPromise: () => yomitanParserReadyPromise, - setYomitanParserReadyPromise: (promise) => { - yomitanParserReadyPromise = promise; - }, - getYomitanParserInitPromise: () => yomitanParserInitPromise, - setYomitanParserInitPromise: (promise) => { - yomitanParserInitPromise = promise; - }, - tokenizeWithMecab: async (tokenizeText) => { - if (!mecabTokenizer) { - return null; - } - const rawTokens = await mecabTokenizer.tokenize(tokenizeText); - if (!rawTokens || rawTokens.length === 0) { - return null; - } - return mergeTokens(rawTokens); - }, - }); + return tokenizeSubtitleService( + text, + createTokenizerDepsRuntimeService({ + getYomitanExt: () => yomitanExt, + getYomitanParserWindow: () => yomitanParserWindow, + setYomitanParserWindow: (window) => { + yomitanParserWindow = window; + }, + getYomitanParserReadyPromise: () => yomitanParserReadyPromise, + setYomitanParserReadyPromise: (promise) => { + yomitanParserReadyPromise = promise; + }, + getYomitanParserInitPromise: () => yomitanParserInitPromise, + setYomitanParserInitPromise: (promise) => { + yomitanParserInitPromise = promise; + }, + getMecabTokenizer: () => mecabTokenizer, + }), + ); } function updateOverlayBounds(geometry: WindowGeometry): void { @@ -1218,27 +1207,21 @@ function handleOverlayModalClosed(modal: OverlayHostedModal): void { } function handleMpvCommandFromIpc(command: (string | number)[]): void { - handleMpvCommandFromIpcService(command, { - specialCommands: SPECIAL_COMMANDS, - triggerSubsyncFromConfig: () => triggerSubsyncFromConfig(), - openRuntimeOptionsPalette: () => openRuntimeOptionsPalette(), - runtimeOptionsCycle: (id, direction) => { - if (!runtimeOptionsManager) { - return { ok: false, error: "Runtime options manager unavailable" }; - } - return applyRuntimeOptionResultRuntimeService( - runtimeOptionsManager.cycleOption(id, direction), - (text) => showMpvOsd(text), - ); - }, - showMpvOsd: (text) => showMpvOsd(text), - mpvReplaySubtitle: () => replayCurrentSubtitleRuntimeService(mpvClient), - mpvPlayNextSubtitle: () => playNextSubtitleRuntimeService(mpvClient), - mpvSendCommand: (rawCommand) => - sendMpvCommandRuntimeService(mpvClient, rawCommand), - isMpvConnected: () => Boolean(mpvClient && mpvClient.connected), - hasRuntimeOptionsManager: () => runtimeOptionsManager !== null, - }); + handleMpvCommandFromIpcService( + command, + createMpvCommandIpcDepsRuntimeService({ + specialCommands: SPECIAL_COMMANDS, + triggerSubsyncFromConfig: () => triggerSubsyncFromConfig(), + openRuntimeOptionsPalette: () => openRuntimeOptionsPalette(), + getRuntimeOptionsManager: () => runtimeOptionsManager, + showMpvOsd: (text) => showMpvOsd(text), + mpvReplaySubtitle: () => replayCurrentSubtitleRuntimeService(mpvClient), + mpvPlayNextSubtitle: () => playNextSubtitleRuntimeService(mpvClient), + mpvSendCommand: (rawCommand) => + sendMpvCommandRuntimeService(mpvClient, rawCommand), + isMpvConnected: () => Boolean(mpvClient && mpvClient.connected), + }), + ); } async function runSubsyncManualFromIpc( @@ -1247,6 +1230,11 @@ async function runSubsyncManualFromIpc( return runSubsyncManualFromIpcRuntimeService(request, getSubsyncRuntimeDeps()); } +const runtimeOptionsIpcDeps = createRuntimeOptionsIpcDepsRuntimeService({ + getRuntimeOptionsManager: () => runtimeOptionsManager, + showMpvOsd: (text) => showMpvOsd(text), +}); + registerIpcHandlersService( createIpcDepsRuntimeService({ getInvisibleWindow: () => invisibleWindow, @@ -1274,20 +1262,8 @@ registerIpcHandlersService( runSubsyncManualFromIpc(request as SubsyncManualRunRequest), getAnkiConnectStatus: () => ankiIntegration !== null, getRuntimeOptions: () => getRuntimeOptionsState(), - setRuntimeOption: (id, value) => - setRuntimeOptionFromIpcRuntimeService( - runtimeOptionsManager, - id as RuntimeOptionId, - value as RuntimeOptionValue, - (text) => showMpvOsd(text), - ), - cycleRuntimeOption: (id, direction) => - cycleRuntimeOptionFromIpcRuntimeService( - runtimeOptionsManager, - id as RuntimeOptionId, - direction, - (text) => showMpvOsd(text), - ), + setRuntimeOption: runtimeOptionsIpcDeps.setRuntimeOption, + cycleRuntimeOption: runtimeOptionsIpcDeps.cycleRuntimeOption, }), );