diff --git a/src/main/boot/handlers.test.ts b/src/main/boot/handlers.test.ts deleted file mode 100644 index 3b26a59..0000000 --- a/src/main/boot/handlers.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; -import { createMainBootHandlers } from './handlers'; - -test('createMainBootHandlers returns grouped handler bundles', () => { - const handlers = createMainBootHandlers({ - startupLifecycleDeps: { - registerProtocolUrlHandlersMainDeps: {} as never, - onWillQuitCleanupMainDeps: {} as never, - shouldRestoreWindowsOnActivateMainDeps: {} as never, - restoreWindowsOnActivateMainDeps: {} as never, - }, - ipcRuntimeDeps: { - mpvCommandMainDeps: {} as never, - handleMpvCommandFromIpcRuntime: () => ({ ok: true }) as never, - runSubsyncManualFromIpc: () => Promise.resolve({ ok: true }) as never, - registration: { - runtimeOptions: {} as never, - mainDeps: {} as never, - ankiJimakuDeps: {} as never, - registerIpcRuntimeServices: () => {}, - }, - }, - cliStartupDeps: { - cliCommandContextMainDeps: {} as never, - cliCommandRuntimeHandlerMainDeps: {} as never, - initialArgsRuntimeHandlerMainDeps: {} as never, - }, - headlessStartupDeps: { - startupRuntimeHandlersDeps: { - appLifecycleRuntimeRunnerMainDeps: { - app: { on: () => {} } as never, - platform: 'darwin', - shouldStartApp: () => true, - parseArgs: () => ({}) as never, - handleCliCommand: () => {}, - printHelp: () => {}, - logNoRunningInstance: () => {}, - onReady: async () => {}, - onWillQuitCleanup: () => {}, - shouldRestoreWindowsOnActivate: () => false, - restoreWindowsOnActivate: () => {}, - shouldQuitOnWindowAllClosed: () => false, - }, - createAppLifecycleRuntimeRunner: () => () => {}, - buildStartupBootstrapMainDeps: (startAppLifecycle) => ({ - argv: ['node', 'main.js'], - parseArgs: () => ({ command: 'start' }) as never, - setLogLevel: () => {}, - forceX11Backend: () => {}, - enforceUnsupportedWaylandMode: () => {}, - shouldStartApp: () => true, - getDefaultSocketPath: () => '/tmp/mpv.sock', - defaultTexthookerPort: 5174, - configDir: '/tmp/config', - defaultConfig: {} as never, - generateConfigTemplate: () => 'template', - generateDefaultConfigFile: async () => 0, - setExitCode: () => {}, - quitApp: () => {}, - logGenerateConfigError: () => {}, - startAppLifecycle: (args) => startAppLifecycle(args as never), - }), - createStartupBootstrapRuntimeDeps: (deps) => ({ - startAppLifecycle: deps.startAppLifecycle, - }), - runStartupBootstrapRuntime: () => ({ mode: 'started' } as never), - applyStartupState: () => {}, - }, - }, - overlayWindowDeps: { - createOverlayWindowDeps: { - createOverlayWindowCore: (kind) => ({ kind }), - isDev: false, - ensureOverlayWindowLevel: () => {}, - onRuntimeOptionsChanged: () => {}, - setOverlayDebugVisualizationEnabled: () => {}, - isOverlayVisible: () => false, - tryHandleOverlayShortcutLocalFallback: () => false, - forwardTabToMpv: () => {}, - onWindowClosed: () => {}, - getYomitanSession: () => null, - }, - setMainWindow: () => {}, - setModalWindow: () => {}, - }, - }); - - assert.equal(typeof handlers.startupLifecycle.registerProtocolUrlHandlers, 'function'); - assert.equal(typeof handlers.ipcRuntime.registerIpcRuntimeHandlers, 'function'); - assert.equal(typeof handlers.cliStartup.handleCliCommand, 'function'); - assert.equal(typeof handlers.headlessStartup.runAndApplyStartupState, 'function'); - assert.equal(typeof handlers.overlayWindow.createMainWindow, 'function'); -}); diff --git a/src/main/boot/handlers.ts b/src/main/boot/handlers.ts index 135abbf..2b4bc3e 100644 --- a/src/main/boot/handlers.ts +++ b/src/main/boot/handlers.ts @@ -6,33 +6,6 @@ import { composeStartupLifecycleHandlers, } from '../runtime/composers'; -export interface MainBootHandlersParams { - startupLifecycleDeps: Parameters[0]; - ipcRuntimeDeps: Parameters[0]; - cliStartupDeps: Parameters[0]; - headlessStartupDeps: Parameters< - typeof composeHeadlessStartupHandlers - >[0]; - overlayWindowDeps: Parameters>[0]; -} - -export function createMainBootHandlers< - TBrowserWindow, - TCliArgs, - TStartupState, - TBootstrapDeps, ->(params: MainBootHandlersParams) { - return { - startupLifecycle: composeStartupLifecycleHandlers(params.startupLifecycleDeps), - ipcRuntime: composeIpcRuntimeHandlers(params.ipcRuntimeDeps), - cliStartup: composeCliStartupHandlers(params.cliStartupDeps), - headlessStartup: composeHeadlessStartupHandlers( - params.headlessStartupDeps, - ), - overlayWindow: composeOverlayWindowHandlers(params.overlayWindowDeps), - }; -} - export const composeBootStartupLifecycleHandlers = composeStartupLifecycleHandlers; export const composeBootIpcRuntimeHandlers = composeIpcRuntimeHandlers; export const composeBootCliStartupHandlers = composeCliStartupHandlers; diff --git a/src/main/boot/runtimes.test.ts b/src/main/boot/runtimes.test.ts deleted file mode 100644 index c66d2e8..0000000 --- a/src/main/boot/runtimes.test.ts +++ /dev/null @@ -1,339 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; -import { createMainBootRuntimes } from './runtimes'; - -test('createMainBootRuntimes returns grouped runtime bundles', () => { - const runtimes = createMainBootRuntimes({ - overlayVisibilityRuntimeDeps: { - overlayVisibilityRuntime: {} as never, - restorePreviousSecondarySubVisibilityMainDeps: {} as never, - broadcastRuntimeOptionsChangedMainDeps: {} as never, - sendToActiveOverlayWindowMainDeps: {} as never, - setOverlayDebugVisualizationEnabledMainDeps: {} as never, - openRuntimeOptionsPaletteMainDeps: {} as never, - }, - jellyfinRuntimeHandlerDeps: { - getResolvedJellyfinConfigMainDeps: {} as never, - getJellyfinClientInfoMainDeps: {} as never, - waitForMpvConnectedMainDeps: {} as never, - launchMpvIdleForJellyfinPlaybackMainDeps: {} as never, - ensureMpvConnectedForJellyfinPlaybackMainDeps: {} as never, - preloadJellyfinExternalSubtitlesMainDeps: {} as never, - playJellyfinItemInMpvMainDeps: {} as never, - remoteComposerOptions: {} as never, - handleJellyfinAuthCommandsMainDeps: {} as never, - handleJellyfinListCommandsMainDeps: {} as never, - handleJellyfinPlayCommandMainDeps: {} as never, - handleJellyfinRemoteAnnounceCommandMainDeps: {} as never, - startJellyfinRemoteSessionMainDeps: {} as never, - stopJellyfinRemoteSessionMainDeps: {} as never, - runJellyfinCommandMainDeps: {} as never, - maybeFocusExistingJellyfinSetupWindowMainDeps: {} as never, - openJellyfinSetupWindowMainDeps: {} as never, - }, - anilistSetupDeps: { - notifyDeps: {} as never, - consumeTokenDeps: {} as never, - handleProtocolDeps: {} as never, - registerProtocolClientDeps: {} as never, - }, - buildOpenAnilistSetupWindowMainDeps: { - maybeFocusExistingSetupWindow: () => false, - createSetupWindow: () => null as never, - buildAuthorizeUrl: () => 'https://example.test', - consumeCallbackUrl: () => false, - openSetupInBrowser: () => {}, - loadManualTokenEntry: () => Promise.resolve(), - redirectUri: 'https://example.test/callback', - developerSettingsUrl: 'https://example.test/dev', - isAllowedExternalUrl: () => true, - isAllowedNavigationUrl: () => true, - logWarn: () => {}, - logError: () => {}, - clearSetupWindow: () => {}, - setSetupPageOpened: () => {}, - setSetupWindow: () => {}, - openExternal: () => {}, - }, - anilistTrackingDeps: { - refreshClientSecretMainDeps: {} as never, - getCurrentMediaKeyMainDeps: {} as never, - resetMediaTrackingMainDeps: {} as never, - getMediaGuessRuntimeStateMainDeps: {} as never, - setMediaGuessRuntimeStateMainDeps: {} as never, - resetMediaGuessStateMainDeps: {} as never, - maybeProbeDurationMainDeps: {} as never, - ensureMediaGuessMainDeps: {} as never, - processNextRetryUpdateMainDeps: {} as never, - maybeRunPostWatchUpdateMainDeps: {} as never, - }, - statsStartupRuntimeDeps: { - ensureStatsServerStarted: () => '', - ensureBackgroundStatsServerStarted: () => ({ url: '', runningInCurrentProcess: false }), - stopBackgroundStatsServer: async () => ({ ok: true, stale: false }), - ensureImmersionTrackerStarted: () => {}, - }, - runStatsCliCommandDeps: { - getResolvedConfig: () => ({}) as never, - ensureImmersionTrackerStarted: () => {}, - ensureVocabularyCleanupTokenizerReady: async () => {}, - getImmersionTracker: () => null, - ensureStatsServerStarted: () => '', - ensureBackgroundStatsServerStarted: () => ({ url: '', runningInCurrentProcess: false }), - stopBackgroundStatsServer: async () => ({ ok: true, stale: false }), - openExternal: () => Promise.resolve(), - writeResponse: () => {}, - exitAppWithCode: () => {}, - logInfo: () => {}, - logWarn: () => {}, - logError: () => {}, - }, - appReadyRuntimeDeps: { - reloadConfigMainDeps: { - reloadConfigStrict: () => ({ ok: true, path: '/tmp/config.jsonc', warnings: [] }), - logInfo: () => {}, - logWarning: () => {}, - showDesktopNotification: () => {}, - startConfigHotReload: () => {}, - refreshAnilistClientSecretState: async () => {}, - failHandlers: { - logError: () => {}, - showErrorBox: () => {}, - quit: () => {}, - }, - }, - criticalConfigErrorMainDeps: { - getConfigPath: () => '/tmp/config.jsonc', - failHandlers: { - logError: () => {}, - showErrorBox: () => {}, - quit: () => {}, - }, - }, - appReadyRuntimeMainDeps: { - ensureDefaultConfigBootstrap: () => {}, - loadSubtitlePosition: () => {}, - resolveKeybindings: () => {}, - createMpvClient: () => {}, - getResolvedConfig: () => ({}) as never, - getConfigWarnings: () => [], - logConfigWarning: () => {}, - setLogLevel: () => {}, - initRuntimeOptionsManager: () => {}, - setSecondarySubMode: () => {}, - defaultSecondarySubMode: 'hover', - defaultWebsocketPort: 5174, - defaultAnnotationWebsocketPort: 6678, - defaultTexthookerPort: 5174, - hasMpvWebsocketPlugin: () => false, - startSubtitleWebsocket: () => {}, - startAnnotationWebsocket: () => {}, - startTexthooker: () => {}, - log: () => {}, - createMecabTokenizerAndCheck: async () => {}, - createSubtitleTimingTracker: () => {}, - loadYomitanExtension: async () => {}, - handleFirstRunSetup: async () => {}, - startJellyfinRemoteSession: async () => {}, - prewarmSubtitleDictionaries: async () => {}, - startBackgroundWarmups: () => {}, - texthookerOnlyMode: false, - shouldAutoInitializeOverlayRuntimeFromConfig: () => false, - setVisibleOverlayVisible: () => {}, - initializeOverlayRuntime: () => {}, - handleInitialArgs: () => {}, - logDebug: () => {}, - now: () => Date.now(), - }, - immersionTrackerStartupMainDeps: { - getResolvedConfig: () => ({}) as never, - getConfiguredDbPath: () => '/tmp/immersion.sqlite', - createTrackerService: () => - ({ - startSession: () => {}, - }) as never, - setTracker: () => {}, - getMpvClient: () => null, - seedTrackerFromCurrentMedia: () => {}, - logInfo: () => {}, - logDebug: () => {}, - logWarn: () => {}, - }, - }, - mpvRuntimeDeps: { - bindMpvMainEventHandlersMainDeps: { - appState: { - initialArgs: null, - overlayRuntimeInitialized: true, - mpvClient: null, - immersionTracker: null, - subtitleTimingTracker: null, - currentSubText: '', - currentSubAssText: '', - playbackPaused: null, - previousSecondarySubVisibility: null, - }, - getQuitOnDisconnectArmed: () => false, - scheduleQuitCheck: () => {}, - quitApp: () => {}, - reportJellyfinRemoteStopped: () => {}, - syncOverlayMpvSubtitleSuppression: () => {}, - maybeRunAnilistPostWatchUpdate: async () => {}, - logSubtitleTimingError: () => {}, - broadcastToOverlayWindows: () => {}, - onSubtitleChange: () => {}, - refreshDiscordPresence: () => {}, - ensureImmersionTrackerInitialized: () => {}, - updateCurrentMediaPath: () => {}, - restoreMpvSubVisibility: () => {}, - getCurrentAnilistMediaKey: () => null, - resetAnilistMediaTracking: () => {}, - maybeProbeAnilistDuration: () => {}, - ensureAnilistMediaGuess: () => {}, - syncImmersionMediaState: () => {}, - updateCurrentMediaTitle: () => {}, - resetAnilistMediaGuessState: () => {}, - reportJellyfinRemoteProgress: () => {}, - updateSubtitleRenderMetrics: () => {}, - }, - mpvClientRuntimeServiceFactoryMainDeps: { - createClient: class FakeMpvClient { - connected = true; - on(): void {} - connect(): void {} - } as never, - getSocketPath: () => '/tmp/mpv.sock', - getResolvedConfig: () => ({ auto_start_overlay: false }), - isAutoStartOverlayEnabled: () => true, - setOverlayVisible: () => {}, - isVisibleOverlayVisible: () => false, - getReconnectTimer: () => null, - setReconnectTimer: () => {}, - }, - updateMpvSubtitleRenderMetricsMainDeps: { - getCurrentMetrics: () => ({ - subPos: 100, - subFontSize: 36, - subScale: 1, - subMarginY: 0, - subMarginX: 0, - subFont: '', - subSpacing: 0, - subBold: false, - subItalic: false, - subBorderSize: 0, - subShadowOffset: 0, - subAssOverride: 'yes', - subScaleByWindow: true, - subUseMargins: true, - osdHeight: 0, - osdDimensions: null, - }), - setCurrentMetrics: () => {}, - applyPatch: (current: any) => ({ next: current, changed: false }), - broadcastMetrics: () => {}, - }, - tokenizer: { - buildTokenizerDepsMainDeps: { - getYomitanExt: () => null, - getYomitanParserWindow: () => null, - setYomitanParserWindow: () => {}, - getYomitanParserReadyPromise: () => null, - setYomitanParserReadyPromise: () => {}, - getYomitanParserInitPromise: () => null, - setYomitanParserInitPromise: () => {}, - isKnownWord: () => false, - recordLookup: () => {}, - getKnownWordMatchMode: () => 'headword', - getMinSentenceWordsForNPlusOne: () => 3, - getJlptLevel: () => null, - getJlptEnabled: () => false, - getFrequencyDictionaryEnabled: () => false, - getFrequencyDictionaryMatchMode: () => 'headword', - getFrequencyRank: () => null, - getYomitanGroupDebugEnabled: () => false, - getMecabTokenizer: () => null, - }, - createTokenizerRuntimeDeps: () => ({}), - tokenizeSubtitle: async () => ({ text: '' }), - createMecabTokenizerAndCheckMainDeps: { - getMecabTokenizer: () => null, - setMecabTokenizer: () => {}, - createMecabTokenizer: () => ({}) as never, - checkAvailability: async () => {}, - }, - prewarmSubtitleDictionariesMainDeps: { - ensureJlptDictionaryLookup: async () => {}, - ensureFrequencyDictionaryLookup: async () => {}, - }, - }, - warmups: { - launchBackgroundWarmupTaskMainDeps: { - now: () => 0, - logDebug: () => {}, - logWarn: () => {}, - }, - startBackgroundWarmupsMainDeps: { - getStarted: () => false, - setStarted: () => {}, - isTexthookerOnlyMode: () => false, - ensureYomitanExtensionLoaded: async () => {}, - shouldWarmupMecab: () => false, - shouldWarmupYomitanExtension: () => false, - shouldWarmupSubtitleDictionaries: () => false, - shouldWarmupJellyfinRemoteSession: () => false, - shouldAutoConnectJellyfinRemote: () => false, - startJellyfinRemoteSession: async () => {}, - }, - }, - }, - trayRuntimeDeps: { - resolveTrayIconPathDeps: {} as never, - buildTrayMenuTemplateDeps: {} as never, - ensureTrayDeps: {} as never, - destroyTrayDeps: {} as never, - buildMenuFromTemplate: () => ({}) as never, - }, - yomitanProfilePolicyDeps: { - externalProfilePath: '', - logInfo: () => {}, - }, - yomitanExtensionRuntimeDeps: { - loadYomitanExtensionCore: async () => null, - userDataPath: '/tmp', - externalProfilePath: '', - getYomitanParserWindow: () => null, - setYomitanParserWindow: () => {}, - setYomitanParserReadyPromise: () => {}, - setYomitanParserInitPromise: () => {}, - setYomitanExtension: () => {}, - setYomitanSession: () => {}, - getYomitanExtension: () => null, - getLoadInFlight: () => null, - setLoadInFlight: () => {}, - }, - yomitanSettingsRuntimeDeps: { - ensureYomitanExtensionLoaded: async () => {}, - getYomitanSession: () => null, - openYomitanSettingsWindow: () => {}, - getExistingWindow: () => null, - setWindow: () => {}, - logWarn: () => {}, - logError: () => {}, - }, - createOverlayRuntimeBootstrapHandlers: () => ({ - initializeOverlayRuntime: () => {}, - }), - initializeOverlayRuntimeMainDeps: {}, - initializeOverlayRuntimeBootstrapDeps: {}, - }); - - assert.equal(typeof runtimes.overlayVisibilityComposer.sendToActiveOverlayWindow, 'function'); - assert.equal(typeof runtimes.jellyfinRuntimeHandlers.runJellyfinCommand, 'function'); - assert.equal(typeof runtimes.anilistSetupHandlers.notifyAnilistSetup, 'function'); - assert.equal(typeof runtimes.openAnilistSetupWindow, 'function'); - assert.equal(typeof runtimes.anilistTrackingHandlers.maybeRunAnilistPostWatchUpdate, 'function'); - assert.equal(typeof runtimes.runStatsCliCommand, 'function'); - assert.equal(typeof runtimes.appReadyRuntime.appReadyRuntimeRunner, 'function'); - assert.equal(typeof runtimes.initializeOverlayRuntime, 'function'); -}); diff --git a/src/main/boot/runtimes.ts b/src/main/boot/runtimes.ts index 77e35f0..d52465e 100644 --- a/src/main/boot/runtimes.ts +++ b/src/main/boot/runtimes.ts @@ -1,4 +1,3 @@ -import { createOpenFirstRunSetupWindowHandler } from '../runtime/first-run-setup-window'; import { createRunStatsCliCommandHandler } from '../runtime/stats-cli-command'; import { createYomitanProfilePolicy } from '../runtime/yomitan-profile-policy'; import { @@ -21,93 +20,6 @@ import { composeStatsStartupRuntime, } from '../runtime/composers'; -export interface MainBootRuntimesParams { - overlayVisibilityRuntimeDeps: Parameters[0]; - jellyfinRuntimeHandlerDeps: Parameters[0]; - anilistSetupDeps: Parameters[0]; - buildOpenAnilistSetupWindowMainDeps: Parameters< - typeof createBuildOpenAnilistSetupWindowMainDepsHandler - >[0]; - anilistTrackingDeps: Parameters[0]; - statsStartupRuntimeDeps: Parameters[0]; - runStatsCliCommandDeps: Parameters[0]; - appReadyRuntimeDeps: Parameters[0]; - mpvRuntimeDeps: any; - trayRuntimeDeps: Parameters[0]; - yomitanProfilePolicyDeps: Parameters[0]; - yomitanExtensionRuntimeDeps: Parameters[0]; - yomitanSettingsRuntimeDeps: Parameters[0]; - createOverlayRuntimeBootstrapHandlers: (params: { - initializeOverlayRuntimeMainDeps: unknown; - initializeOverlayRuntimeBootstrapDeps: unknown; - }) => { - initializeOverlayRuntime: () => void; - }; - initializeOverlayRuntimeMainDeps: unknown; - initializeOverlayRuntimeBootstrapDeps: unknown; -} - -export function createMainBootRuntimes< - TBrowserWindow, - TMpvClient, - TTokenizerDeps, - TSubtitleData, ->( - params: MainBootRuntimesParams, -) { - const overlayVisibilityComposer = composeOverlayVisibilityRuntime( - params.overlayVisibilityRuntimeDeps, - ); - const jellyfinRuntimeHandlers = composeJellyfinRuntimeHandlers( - params.jellyfinRuntimeHandlerDeps, - ); - const anilistSetupHandlers = composeAnilistSetupHandlers(params.anilistSetupDeps); - const buildOpenAnilistSetupWindowMainDepsHandler = - createBuildOpenAnilistSetupWindowMainDepsHandler(params.buildOpenAnilistSetupWindowMainDeps); - const maybeFocusExistingAnilistSetupWindow = - params.buildOpenAnilistSetupWindowMainDeps.maybeFocusExistingSetupWindow; - const anilistTrackingHandlers = composeAnilistTrackingHandlers(params.anilistTrackingDeps); - const statsStartupRuntime = composeStatsStartupRuntime(params.statsStartupRuntimeDeps); - const runStatsCliCommand = createRunStatsCliCommandHandler(params.runStatsCliCommandDeps); - const appReadyRuntime = composeAppReadyRuntime(params.appReadyRuntimeDeps); - const mpvRuntimeHandlers = composeMpvRuntimeHandlers( - params.mpvRuntimeDeps as any, - ); - const trayRuntimeHandlers = createTrayRuntimeHandlers(params.trayRuntimeDeps); - const yomitanProfilePolicy = createYomitanProfilePolicy(params.yomitanProfilePolicyDeps); - const yomitanExtensionRuntime = createYomitanExtensionRuntime( - params.yomitanExtensionRuntimeDeps, - ); - const yomitanSettingsRuntime = createYomitanSettingsRuntime( - params.yomitanSettingsRuntimeDeps, - ); - const overlayRuntimeBootstrapHandlers = params.createOverlayRuntimeBootstrapHandlers({ - initializeOverlayRuntimeMainDeps: params.initializeOverlayRuntimeMainDeps, - initializeOverlayRuntimeBootstrapDeps: params.initializeOverlayRuntimeBootstrapDeps, - }); - - return { - overlayVisibilityComposer, - jellyfinRuntimeHandlers, - anilistSetupHandlers, - maybeFocusExistingAnilistSetupWindow, - buildOpenAnilistSetupWindowMainDepsHandler, - openAnilistSetupWindow: () => - createOpenAnilistSetupWindowHandler(buildOpenAnilistSetupWindowMainDepsHandler())(), - anilistTrackingHandlers, - statsStartupRuntime, - runStatsCliCommand, - appReadyRuntime, - mpvRuntimeHandlers, - trayRuntimeHandlers, - yomitanProfilePolicy, - yomitanExtensionRuntime, - yomitanSettingsRuntime, - initializeOverlayRuntime: overlayRuntimeBootstrapHandlers.initializeOverlayRuntime, - openFirstRunSetupWindowHandler: createOpenFirstRunSetupWindowHandler, - }; -} - export const composeBootOverlayVisibilityRuntime = composeOverlayVisibilityRuntime; export const composeBootJellyfinRuntimeHandlers = composeJellyfinRuntimeHandlers; export const composeBootAnilistSetupHandlers = composeAnilistSetupHandlers;