diff --git a/package.json b/package.json index c740579..c8696af 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "docs:build": "VITE_EXTRA_EXTENSIONS=jsonc vitepress build docs", "docs:preview": "VITE_EXTRA_EXTENSIONS=jsonc 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/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/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/overlay-deps-runtime-service.test.js dist/core/services/startup-lifecycle-hooks-runtime-service.test.js dist/core/services/shortcut-ui-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/overlay-manager-service.test.js dist/core/services/app-ready-runtime-service.test.js dist/core/services/app-shutdown-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/field-grouping-overlay-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/tokenizer-deps-runtime-service.test.js dist/core/services/shortcut-ui-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-broadcast-runtime-service.test.js dist/core/services/overlay-manager-service.test.js dist/core/services/app-ready-runtime-service.test.js dist/core/services/app-shutdown-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/index.ts b/src/core/services/index.ts index 097866c..c0be5b7 100644 --- a/src/core/services/index.ts +++ b/src/core/services/index.ts @@ -61,12 +61,6 @@ export { setVisibleOverlayVisibleService, syncInvisibleOverlayMousePassthroughService, } from "./overlay-visibility-runtime-service"; -export { - setInvisibleOverlayVisibleRuntimeFacadeService, - setVisibleOverlayVisibleRuntimeFacadeService, - toggleInvisibleOverlayRuntimeFacadeService, - toggleVisibleOverlayRuntimeFacadeService, -} from "./overlay-visibility-facade-service"; export { MpvIpcClient, MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY } from "./mpv-service"; export { applyMpvSubtitleRenderMetricsPatchService } from "./mpv-render-metrics-service"; export { handleMpvCommandFromIpcService } from "./ipc-command-service"; @@ -81,19 +75,9 @@ export { createAppLifecycleDepsRuntimeService } from "./app-lifecycle-deps-runti export { createCliCommandDepsRuntimeService } from "./cli-command-deps-runtime-service"; export { createIpcDepsRuntimeService } from "./ipc-deps-runtime-service"; export { createFieldGroupingOverlayRuntimeService } from "./field-grouping-overlay-runtime-service"; -export { createSubsyncRuntimeDepsService } from "./subsync-deps-runtime-service"; export { createNumericShortcutRuntimeService } from "./numeric-shortcut-runtime-service"; -export { createMpvCommandIpcDepsRuntimeService } from "./mpv-command-ipc-deps-runtime-service"; -export { createRuntimeOptionsIpcDepsRuntimeService } from "./runtime-options-ipc-deps-runtime-service"; export { createTokenizerDepsRuntimeService } from "./tokenizer-deps-runtime-service"; -export { - createInitializeOverlayRuntimeDepsService, - createInvisibleOverlayVisibilityDepsRuntimeService, - createOverlayWindowRuntimeDepsService, - createVisibleOverlayVisibilityDepsRuntimeService, -} from "./overlay-deps-runtime-service"; export { runOverlayShortcutLocalFallbackRuntimeService } from "./shortcut-ui-deps-runtime-service"; -export { createStartupLifecycleHooksRuntimeService } from "./startup-lifecycle-hooks-runtime-service"; export { createRuntimeOptionsManagerRuntimeService } from "./runtime-options-manager-runtime-service"; export { createAppLoggingRuntimeService } from "./app-logging-runtime-service"; export { 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 deleted file mode 100644 index 1e5438b..0000000 --- a/src/core/services/mpv-command-ipc-deps-runtime-service.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index f117e56..0000000 --- a/src/core/services/mpv-command-ipc-deps-runtime-service.ts +++ /dev/null @@ -1,53 +0,0 @@ -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/overlay-deps-runtime-service.test.ts b/src/core/services/overlay-deps-runtime-service.test.ts deleted file mode 100644 index 57672bb..0000000 --- a/src/core/services/overlay-deps-runtime-service.test.ts +++ /dev/null @@ -1,105 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { - createInitializeOverlayRuntimeDepsService, - createInvisibleOverlayVisibilityDepsRuntimeService, - createOverlayWindowRuntimeDepsService, - createVisibleOverlayVisibilityDepsRuntimeService, -} from "./overlay-deps-runtime-service"; - -test("createOverlayWindowRuntimeDepsService maps runtime state providers", () => { - let visible = true; - let invisible = false; - const deps = createOverlayWindowRuntimeDepsService({ - isDev: false, - getOverlayDebugVisualizationEnabled: () => true, - ensureOverlayWindowLevel: () => {}, - onRuntimeOptionsChanged: () => {}, - setOverlayDebugVisualizationEnabled: () => {}, - getVisibleOverlayVisible: () => visible, - getInvisibleOverlayVisible: () => invisible, - tryHandleOverlayShortcutLocalFallback: () => false, - onWindowClosed: () => {}, - }); - - assert.equal(deps.isOverlayVisible("visible"), true); - assert.equal(deps.isOverlayVisible("invisible"), false); - visible = false; - invisible = true; - assert.equal(deps.isOverlayVisible("visible"), false); - assert.equal(deps.isOverlayVisible("invisible"), true); -}); - -test("createInitializeOverlayRuntimeDepsService passes through overlay init deps", () => { - const windows: any[] = []; - const deps = createInitializeOverlayRuntimeDepsService({ - backendOverride: null, - getInitialInvisibleOverlayVisibility: () => true, - createMainWindow: () => {}, - createInvisibleWindow: () => {}, - registerGlobalShortcuts: () => {}, - updateOverlayBounds: () => {}, - isVisibleOverlayVisible: () => false, - isInvisibleOverlayVisible: () => true, - updateVisibleOverlayVisibility: () => {}, - updateInvisibleOverlayVisibility: () => {}, - getOverlayWindows: () => windows as never, - syncOverlayShortcuts: () => {}, - setWindowTracker: () => {}, - getResolvedConfig: () => ({ ankiConnect: undefined }), - getSubtitleTimingTracker: () => null, - getMpvClient: () => null, - getRuntimeOptionsManager: () => null, - setAnkiIntegration: () => {}, - showDesktopNotification: () => {}, - createFieldGroupingCallback: () => async () => ({ - keepNoteId: 0, - deleteNoteId: 0, - deleteDuplicate: true, - cancelled: true, - }), - }); - - assert.equal(deps.getInitialInvisibleOverlayVisibility(), true); - assert.equal(deps.getOverlayWindows().length, 0); -}); - -test("createVisibleOverlayVisibilityDepsRuntimeService snapshots runtime values", () => { - const deps = createVisibleOverlayVisibilityDepsRuntimeService({ - getVisibleOverlayVisible: () => true, - getMainWindow: () => null, - getWindowTracker: () => null, - getTrackerNotReadyWarningShown: () => false, - setTrackerNotReadyWarningShown: () => {}, - shouldBindVisibleOverlayToMpvSubVisibility: () => true, - getPreviousSecondarySubVisibility: () => null, - setPreviousSecondarySubVisibility: () => {}, - isMpvConnected: () => false, - mpvSend: () => {}, - secondarySubVisibilityRequestId: 123, - updateOverlayBounds: () => {}, - ensureOverlayWindowLevel: () => {}, - enforceOverlayLayerOrder: () => {}, - syncOverlayShortcuts: () => {}, - }); - - assert.equal(deps.visibleOverlayVisible, true); - assert.equal(deps.secondarySubVisibilityRequestId, 123); - assert.equal(deps.mpvConnected, false); -}); - -test("createInvisibleOverlayVisibilityDepsRuntimeService snapshots runtime values", () => { - const deps = createInvisibleOverlayVisibilityDepsRuntimeService({ - getInvisibleWindow: () => null, - getVisibleOverlayVisible: () => true, - getInvisibleOverlayVisible: () => false, - getWindowTracker: () => null, - updateOverlayBounds: () => {}, - ensureOverlayWindowLevel: () => {}, - enforceOverlayLayerOrder: () => {}, - syncOverlayShortcuts: () => {}, - }); - - assert.equal(deps.visibleOverlayVisible, true); - assert.equal(deps.invisibleOverlayVisible, false); -}); diff --git a/src/core/services/overlay-deps-runtime-service.ts b/src/core/services/overlay-deps-runtime-service.ts deleted file mode 100644 index d04716b..0000000 --- a/src/core/services/overlay-deps-runtime-service.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { BrowserWindow } from "electron"; -import { BaseWindowTracker } from "../../window-trackers"; -import { - AnkiConnectConfig, - KikuFieldGroupingChoice, - KikuFieldGroupingRequestData, - WindowGeometry, -} from "../../types"; -import { createOverlayWindowService } from "./overlay-window-service"; -import { initializeOverlayRuntimeService } from "./overlay-runtime-init-service"; -import { - updateInvisibleOverlayVisibilityService, - updateVisibleOverlayVisibilityService, -} from "./overlay-visibility-service"; - -interface MpvCommandSender { - command: Array; - request_id?: number; -} - -export interface OverlayWindowRuntimeDepsOptions { - isDev: boolean; - getOverlayDebugVisualizationEnabled: () => boolean; - ensureOverlayWindowLevel: (window: BrowserWindow) => void; - onRuntimeOptionsChanged: () => void; - setOverlayDebugVisualizationEnabled: (enabled: boolean) => void; - getVisibleOverlayVisible: () => boolean; - getInvisibleOverlayVisible: () => boolean; - tryHandleOverlayShortcutLocalFallback: (input: Electron.Input) => boolean; - onWindowClosed: (kind: "visible" | "invisible") => void; -} - -export interface InitializeOverlayRuntimeDepsOptions { - backendOverride: string | null; - getInitialInvisibleOverlayVisibility: () => boolean; - createMainWindow: () => void; - createInvisibleWindow: () => void; - registerGlobalShortcuts: () => void; - updateOverlayBounds: (geometry: WindowGeometry) => void; - isVisibleOverlayVisible: () => boolean; - isInvisibleOverlayVisible: () => boolean; - updateVisibleOverlayVisibility: () => void; - updateInvisibleOverlayVisibility: () => void; - getOverlayWindows: () => BrowserWindow[]; - syncOverlayShortcuts: () => void; - setWindowTracker: (tracker: BaseWindowTracker | null) => void; - getResolvedConfig: () => { ankiConnect?: AnkiConnectConfig }; - getSubtitleTimingTracker: () => unknown | null; - getMpvClient: () => { send?: (payload: { command: string[] }) => void } | null; - getRuntimeOptionsManager: () => { - getEffectiveAnkiConnectConfig: (config?: AnkiConnectConfig) => AnkiConnectConfig; - } | null; - setAnkiIntegration: (integration: unknown | null) => void; - showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; - createFieldGroupingCallback: () => ( - data: KikuFieldGroupingRequestData, - ) => Promise; -} - -export interface VisibleOverlayVisibilityDepsRuntimeOptions { - getVisibleOverlayVisible: () => boolean; - getMainWindow: () => BrowserWindow | null; - getWindowTracker: () => BaseWindowTracker | null; - getTrackerNotReadyWarningShown: () => boolean; - setTrackerNotReadyWarningShown: (shown: boolean) => void; - shouldBindVisibleOverlayToMpvSubVisibility: () => boolean; - getPreviousSecondarySubVisibility: () => boolean | null; - setPreviousSecondarySubVisibility: (value: boolean | null) => void; - isMpvConnected: () => boolean; - mpvSend: (payload: MpvCommandSender) => void; - secondarySubVisibilityRequestId: number; - updateOverlayBounds: (geometry: WindowGeometry) => void; - ensureOverlayWindowLevel: (window: BrowserWindow) => void; - enforceOverlayLayerOrder: () => void; - syncOverlayShortcuts: () => void; -} - -export interface InvisibleOverlayVisibilityDepsRuntimeOptions { - getInvisibleWindow: () => BrowserWindow | null; - getVisibleOverlayVisible: () => boolean; - getInvisibleOverlayVisible: () => boolean; - getWindowTracker: () => BaseWindowTracker | null; - updateOverlayBounds: (geometry: WindowGeometry) => void; - ensureOverlayWindowLevel: (window: BrowserWindow) => void; - enforceOverlayLayerOrder: () => void; - syncOverlayShortcuts: () => void; -} - -export function createOverlayWindowRuntimeDepsService( - options: OverlayWindowRuntimeDepsOptions, -): Parameters[1] { - return { - isDev: options.isDev, - overlayDebugVisualizationEnabled: - options.getOverlayDebugVisualizationEnabled(), - ensureOverlayWindowLevel: options.ensureOverlayWindowLevel, - onRuntimeOptionsChanged: options.onRuntimeOptionsChanged, - setOverlayDebugVisualizationEnabled: - options.setOverlayDebugVisualizationEnabled, - isOverlayVisible: (kind) => - kind === "visible" - ? options.getVisibleOverlayVisible() - : options.getInvisibleOverlayVisible(), - tryHandleOverlayShortcutLocalFallback: - options.tryHandleOverlayShortcutLocalFallback, - onWindowClosed: options.onWindowClosed, - }; -} - -export function createInitializeOverlayRuntimeDepsService( - options: InitializeOverlayRuntimeDepsOptions, -): Parameters[0] { - return { - backendOverride: options.backendOverride, - getInitialInvisibleOverlayVisibility: - options.getInitialInvisibleOverlayVisibility, - createMainWindow: options.createMainWindow, - createInvisibleWindow: options.createInvisibleWindow, - registerGlobalShortcuts: options.registerGlobalShortcuts, - updateOverlayBounds: options.updateOverlayBounds, - isVisibleOverlayVisible: options.isVisibleOverlayVisible, - isInvisibleOverlayVisible: options.isInvisibleOverlayVisible, - updateVisibleOverlayVisibility: options.updateVisibleOverlayVisibility, - updateInvisibleOverlayVisibility: options.updateInvisibleOverlayVisibility, - getOverlayWindows: options.getOverlayWindows, - syncOverlayShortcuts: options.syncOverlayShortcuts, - setWindowTracker: options.setWindowTracker, - getResolvedConfig: options.getResolvedConfig, - getSubtitleTimingTracker: options.getSubtitleTimingTracker, - getMpvClient: options.getMpvClient, - getRuntimeOptionsManager: options.getRuntimeOptionsManager, - setAnkiIntegration: options.setAnkiIntegration, - showDesktopNotification: options.showDesktopNotification, - createFieldGroupingCallback: options.createFieldGroupingCallback, - }; -} - -export function createVisibleOverlayVisibilityDepsRuntimeService( - options: VisibleOverlayVisibilityDepsRuntimeOptions, -): Parameters[0] { - return { - visibleOverlayVisible: options.getVisibleOverlayVisible(), - mainWindow: options.getMainWindow(), - windowTracker: options.getWindowTracker(), - trackerNotReadyWarningShown: options.getTrackerNotReadyWarningShown(), - setTrackerNotReadyWarningShown: options.setTrackerNotReadyWarningShown, - shouldBindVisibleOverlayToMpvSubVisibility: - options.shouldBindVisibleOverlayToMpvSubVisibility(), - previousSecondarySubVisibility: options.getPreviousSecondarySubVisibility(), - setPreviousSecondarySubVisibility: options.setPreviousSecondarySubVisibility, - mpvConnected: options.isMpvConnected(), - mpvSend: options.mpvSend, - secondarySubVisibilityRequestId: options.secondarySubVisibilityRequestId, - updateOverlayBounds: options.updateOverlayBounds, - ensureOverlayWindowLevel: options.ensureOverlayWindowLevel, - enforceOverlayLayerOrder: options.enforceOverlayLayerOrder, - syncOverlayShortcuts: options.syncOverlayShortcuts, - }; -} - -export function createInvisibleOverlayVisibilityDepsRuntimeService( - options: InvisibleOverlayVisibilityDepsRuntimeOptions, -): Parameters[0] { - return { - invisibleWindow: options.getInvisibleWindow(), - visibleOverlayVisible: options.getVisibleOverlayVisible(), - invisibleOverlayVisible: options.getInvisibleOverlayVisible(), - windowTracker: options.getWindowTracker(), - updateOverlayBounds: options.updateOverlayBounds, - ensureOverlayWindowLevel: options.ensureOverlayWindowLevel, - enforceOverlayLayerOrder: options.enforceOverlayLayerOrder, - syncOverlayShortcuts: options.syncOverlayShortcuts, - }; -} diff --git a/src/core/services/overlay-visibility-facade-service.test.ts b/src/core/services/overlay-visibility-facade-service.test.ts deleted file mode 100644 index e234d2b..0000000 --- a/src/core/services/overlay-visibility-facade-service.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { - OverlayVisibilityFacadeDeps, - setVisibleOverlayVisibleRuntimeFacadeService, - toggleInvisibleOverlayRuntimeFacadeService, - toggleVisibleOverlayRuntimeFacadeService, -} from "./overlay-visibility-facade-service"; - -function makeDeps(initialVisible = false, initialInvisible = false): { - deps: OverlayVisibilityFacadeDeps; - getState: () => { visible: boolean; invisible: boolean; mpvSubVisible: boolean | null }; -} { - let visible = initialVisible; - let invisible = initialInvisible; - let mpvSubVisible: boolean | null = null; - - const deps: OverlayVisibilityFacadeDeps = { - getVisibleOverlayVisible: () => visible, - getInvisibleOverlayVisible: () => invisible, - setVisibleOverlayVisibleState: (value) => { - visible = value; - }, - setInvisibleOverlayVisibleState: (value) => { - invisible = value; - }, - updateVisibleOverlayVisibility: () => {}, - updateInvisibleOverlayVisibility: () => {}, - syncInvisibleOverlayMousePassthrough: () => {}, - shouldBindVisibleOverlayToMpvSubVisibility: () => true, - isMpvConnected: () => true, - setMpvSubVisibility: (value) => { - mpvSubVisible = value; - }, - }; - - return { - deps, - getState: () => ({ visible, invisible, mpvSubVisible }), - }; -} - -test("setVisibleOverlayVisibleRuntimeFacadeService updates visible state and mpv subtitle visibility", () => { - const { deps, getState } = makeDeps(false, true); - setVisibleOverlayVisibleRuntimeFacadeService(true, deps); - assert.deepEqual(getState(), { - visible: true, - invisible: true, - mpvSubVisible: false, - }); -}); - -test("toggleVisibleOverlayRuntimeFacadeService flips visible overlay state", () => { - const { deps, getState } = makeDeps(false, false); - toggleVisibleOverlayRuntimeFacadeService(deps); - assert.equal(getState().visible, true); -}); - -test("toggleInvisibleOverlayRuntimeFacadeService flips invisible overlay state", () => { - const { deps, getState } = makeDeps(false, false); - toggleInvisibleOverlayRuntimeFacadeService(deps); - assert.equal(getState().invisible, true); -}); diff --git a/src/core/services/overlay-visibility-facade-service.ts b/src/core/services/overlay-visibility-facade-service.ts deleted file mode 100644 index 309d7e2..0000000 --- a/src/core/services/overlay-visibility-facade-service.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { - setInvisibleOverlayVisibleService, - setVisibleOverlayVisibleService, -} from "./overlay-visibility-runtime-service"; - -export interface OverlayVisibilityFacadeDeps { - getVisibleOverlayVisible: () => boolean; - getInvisibleOverlayVisible: () => boolean; - setVisibleOverlayVisibleState: (visible: boolean) => void; - setInvisibleOverlayVisibleState: (visible: boolean) => void; - updateVisibleOverlayVisibility: () => void; - updateInvisibleOverlayVisibility: () => void; - syncInvisibleOverlayMousePassthrough: () => void; - shouldBindVisibleOverlayToMpvSubVisibility: () => boolean; - isMpvConnected: () => boolean; - setMpvSubVisibility: (visible: boolean) => void; -} - -export function setVisibleOverlayVisibleRuntimeFacadeService( - visible: boolean, - deps: OverlayVisibilityFacadeDeps, -): void { - setVisibleOverlayVisibleService({ - visible, - setVisibleOverlayVisibleState: deps.setVisibleOverlayVisibleState, - updateVisibleOverlayVisibility: deps.updateVisibleOverlayVisibility, - updateInvisibleOverlayVisibility: deps.updateInvisibleOverlayVisibility, - syncInvisibleOverlayMousePassthrough: deps.syncInvisibleOverlayMousePassthrough, - shouldBindVisibleOverlayToMpvSubVisibility: - deps.shouldBindVisibleOverlayToMpvSubVisibility, - isMpvConnected: deps.isMpvConnected, - setMpvSubVisibility: deps.setMpvSubVisibility, - }); -} - -export function setInvisibleOverlayVisibleRuntimeFacadeService( - visible: boolean, - deps: OverlayVisibilityFacadeDeps, -): void { - setInvisibleOverlayVisibleService({ - visible, - setInvisibleOverlayVisibleState: deps.setInvisibleOverlayVisibleState, - updateInvisibleOverlayVisibility: deps.updateInvisibleOverlayVisibility, - syncInvisibleOverlayMousePassthrough: deps.syncInvisibleOverlayMousePassthrough, - }); -} - -export function toggleVisibleOverlayRuntimeFacadeService( - deps: OverlayVisibilityFacadeDeps, -): void { - setVisibleOverlayVisibleRuntimeFacadeService( - !deps.getVisibleOverlayVisible(), - deps, - ); -} - -export function toggleInvisibleOverlayRuntimeFacadeService( - deps: OverlayVisibilityFacadeDeps, -): void { - setInvisibleOverlayVisibleRuntimeFacadeService( - !deps.getInvisibleOverlayVisible(), - deps, - ); -} 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 deleted file mode 100644 index 77d6aa2..0000000 --- a/src/core/services/runtime-options-ipc-deps-runtime-service.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index 55777cf..0000000 --- a/src/core/services/runtime-options-ipc-deps-runtime-service.ts +++ /dev/null @@ -1,38 +0,0 @@ -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/startup-lifecycle-hooks-runtime-service.test.ts b/src/core/services/startup-lifecycle-hooks-runtime-service.test.ts deleted file mode 100644 index 8911532..0000000 --- a/src/core/services/startup-lifecycle-hooks-runtime-service.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { createStartupLifecycleHooksRuntimeService } from "./startup-lifecycle-hooks-runtime-service"; - -test("createStartupLifecycleHooksRuntimeService wires app-ready and app-shutdown handlers", async () => { - const calls: string[] = []; - const hooks = createStartupLifecycleHooksRuntimeService({ - appReadyDeps: { - loadSubtitlePosition: () => calls.push("loadSubtitlePosition"), - resolveKeybindings: () => calls.push("resolveKeybindings"), - createMpvClient: () => calls.push("createMpvClient"), - reloadConfig: () => calls.push("reloadConfig"), - getResolvedConfig: () => ({ - secondarySub: { defaultMode: "hover" }, - websocket: { enabled: "auto", port: 1234 }, - }), - getConfigWarnings: () => [], - logConfigWarning: () => calls.push("logConfigWarning"), - initRuntimeOptionsManager: () => calls.push("initRuntimeOptionsManager"), - setSecondarySubMode: () => calls.push("setSecondarySubMode"), - defaultSecondarySubMode: "hover", - defaultWebsocketPort: 8765, - hasMpvWebsocketPlugin: () => true, - startSubtitleWebsocket: () => calls.push("startSubtitleWebsocket"), - log: () => calls.push("log"), - createMecabTokenizerAndCheck: async () => { - calls.push("createMecabTokenizerAndCheck"); - }, - createSubtitleTimingTracker: () => calls.push("createSubtitleTimingTracker"), - loadYomitanExtension: async () => { - calls.push("loadYomitanExtension"); - }, - texthookerOnlyMode: false, - shouldAutoInitializeOverlayRuntimeFromConfig: () => false, - initializeOverlayRuntime: () => calls.push("initializeOverlayRuntime"), - handleInitialArgs: () => calls.push("handleInitialArgs"), - }, - appShutdownDeps: { - unregisterAllGlobalShortcuts: () => calls.push("unregisterAllGlobalShortcuts"), - stopSubtitleWebsocket: () => calls.push("stopSubtitleWebsocket"), - stopTexthookerService: () => calls.push("stopTexthookerService"), - destroyYomitanParserWindow: () => calls.push("destroyYomitanParserWindow"), - clearYomitanParserPromises: () => calls.push("clearYomitanParserPromises"), - stopWindowTracker: () => calls.push("stopWindowTracker"), - destroyMpvSocket: () => calls.push("destroyMpvSocket"), - clearReconnectTimer: () => calls.push("clearReconnectTimer"), - destroySubtitleTimingTracker: () => calls.push("destroySubtitleTimingTracker"), - destroyAnkiIntegration: () => calls.push("destroyAnkiIntegration"), - }, - shouldRestoreWindowsOnActivate: () => true, - restoreWindowsOnActivate: () => calls.push("restoreWindowsOnActivate"), - }); - - await hooks.onReady(); - hooks.onWillQuitCleanup(); - assert.equal(hooks.shouldRestoreWindowsOnActivate(), true); - hooks.restoreWindowsOnActivate(); - - assert.ok(calls.includes("loadSubtitlePosition")); - assert.ok(calls.includes("handleInitialArgs")); - assert.ok(calls.includes("destroyAnkiIntegration")); - assert.ok(calls.includes("restoreWindowsOnActivate")); -}); diff --git a/src/core/services/startup-lifecycle-hooks-runtime-service.ts b/src/core/services/startup-lifecycle-hooks-runtime-service.ts deleted file mode 100644 index 3a38b41..0000000 --- a/src/core/services/startup-lifecycle-hooks-runtime-service.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { AppLifecycleDepsRuntimeOptions } from "./app-lifecycle-deps-runtime-service"; -import { - AppReadyRuntimeDeps, - runAppReadyRuntimeService, -} from "./app-ready-runtime-service"; -import { - AppShutdownRuntimeDeps, - runAppShutdownRuntimeService, -} from "./app-shutdown-runtime-service"; - -type StartupLifecycleHookDeps = Pick< - AppLifecycleDepsRuntimeOptions, - "onReady" | "onWillQuitCleanup" | "shouldRestoreWindowsOnActivate" | "restoreWindowsOnActivate" ->; - -export interface StartupLifecycleHooksRuntimeOptions { - appReadyDeps: AppReadyRuntimeDeps; - appShutdownDeps: AppShutdownRuntimeDeps; - shouldRestoreWindowsOnActivate: () => boolean; - restoreWindowsOnActivate: () => void; -} - -export function createStartupLifecycleHooksRuntimeService( - options: StartupLifecycleHooksRuntimeOptions, -): StartupLifecycleHookDeps { - return { - onReady: async () => { - await runAppReadyRuntimeService(options.appReadyDeps); - }, - onWillQuitCleanup: () => { - runAppShutdownRuntimeService(options.appShutdownDeps); - }, - shouldRestoreWindowsOnActivate: options.shouldRestoreWindowsOnActivate, - restoreWindowsOnActivate: options.restoreWindowsOnActivate, - }; -} diff --git a/src/core/services/subsync-deps-runtime-service.test.ts b/src/core/services/subsync-deps-runtime-service.test.ts deleted file mode 100644 index d0c9200..0000000 --- a/src/core/services/subsync-deps-runtime-service.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { createSubsyncRuntimeDepsService } from "./subsync-deps-runtime-service"; - -test("createSubsyncRuntimeDepsService opens manual picker via visible overlay", () => { - let inProgress = false; - const calls: Array<{ channel: string; payload?: unknown; restore?: string }> = []; - - const deps = createSubsyncRuntimeDepsService({ - getMpvClient: () => null, - getResolvedSubsyncConfig: () => ({ - defaultMode: "auto", - ffsubsyncPath: "/usr/bin/ffsubsync", - alassPath: "/usr/bin/alass", - ffmpegPath: "/usr/bin/ffmpeg", - }), - isSubsyncInProgress: () => inProgress, - setSubsyncInProgress: (next) => { - inProgress = next; - }, - showMpvOsd: () => {}, - sendToVisibleOverlay: (channel, payload, options) => { - calls.push({ channel, payload, restore: options?.restoreOnModalClose }); - return true; - }, - }); - - deps.setSubsyncInProgress(true); - deps.openManualPicker({ - sourceTracks: [{ id: 1, label: "Japanese Track" }], - }); - - assert.equal(deps.isSubsyncInProgress(), true); - assert.equal(calls.length, 1); - assert.equal(calls[0]?.channel, "subsync:open-manual"); - assert.equal(calls[0]?.restore, "subsync"); -}); diff --git a/src/core/services/subsync-deps-runtime-service.ts b/src/core/services/subsync-deps-runtime-service.ts deleted file mode 100644 index b9b171e..0000000 --- a/src/core/services/subsync-deps-runtime-service.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { - SubsyncManualPayload, -} from "../../types"; -import { - SubsyncRuntimeDeps, -} from "./subsync-runtime-service"; -import { SubsyncResolvedConfig } from "../../subsync/utils"; - -interface MpvClientLike { - connected: boolean; - currentAudioStreamIndex: number | null; - send: (payload: { command: (string | number)[] }) => void; - requestProperty: (name: string) => Promise; -} - -export interface SubsyncDepsRuntimeOptions { - getMpvClient: () => MpvClientLike | null; - getResolvedSubsyncConfig: () => SubsyncResolvedConfig; - isSubsyncInProgress: () => boolean; - setSubsyncInProgress: (inProgress: boolean) => void; - showMpvOsd: (text: string) => void; - sendToVisibleOverlay: ( - channel: string, - payload?: unknown, - options?: { restoreOnModalClose?: "runtime-options" | "subsync" }, - ) => boolean; -} - -export function createSubsyncRuntimeDepsService( - options: SubsyncDepsRuntimeOptions, -): SubsyncRuntimeDeps { - return { - getMpvClient: options.getMpvClient, - getResolvedSubsyncConfig: options.getResolvedSubsyncConfig, - isSubsyncInProgress: options.isSubsyncInProgress, - setSubsyncInProgress: options.setSubsyncInProgress, - showMpvOsd: options.showMpvOsd, - openManualPicker: (payload: SubsyncManualPayload) => { - options.sendToVisibleOverlay("subsync:open-manual", payload, { - restoreOnModalClose: "subsync", - }); - }, - }; -}