From 9dca83acd9dd494f87eb02e66b259cb77c4d1ba1 Mon Sep 17 00:00:00 2001 From: sudacode Date: Wed, 25 Mar 2026 20:36:50 -0700 Subject: [PATCH] fix: delay youtube overlay bootstrap until yomitan loads --- changes/fix-youtube-yomitan-bootstrap.md | 4 ++ src/cli/args.test.ts | 7 ++++ src/cli/args.ts | 7 +++- src/core/services/cli-command.test.ts | 10 +---- src/main.ts | 15 ++++++- .../cli-command-prechecks-main-deps.test.ts | 4 +- .../cli-command-prechecks-main-deps.ts | 5 ++- .../runtime/cli-command-prechecks.test.ts | 28 +++++++++++-- src/main/runtime/cli-command-prechecks.ts | 4 +- .../cli-command-runtime-handler.test.ts | 29 +++++++++++++- .../runtime/cli-command-runtime-handler.ts | 2 +- src/main/runtime/initial-args-handler.test.ts | 39 +++++++++++++++++++ src/main/runtime/initial-args-handler.ts | 5 ++- .../runtime/initial-args-main-deps.test.ts | 2 + src/main/runtime/initial-args-main-deps.ts | 3 ++ .../initial-args-runtime-handler.test.ts | 3 ++ 16 files changed, 143 insertions(+), 24 deletions(-) create mode 100644 changes/fix-youtube-yomitan-bootstrap.md diff --git a/changes/fix-youtube-yomitan-bootstrap.md b/changes/fix-youtube-yomitan-bootstrap.md new file mode 100644 index 0000000..0dcc4de --- /dev/null +++ b/changes/fix-youtube-yomitan-bootstrap.md @@ -0,0 +1,4 @@ +type: fixed +area: overlay + +- Fixed `subminer ` on Linux so the YouTube playback flow waits for Yomitan to load before creating the overlay window, avoiding the broken lookup popup state that previously required a manual overlay refresh. diff --git a/src/cli/args.test.ts b/src/cli/args.test.ts index 1e24531..a766480 100644 --- a/src/cli/args.test.ts +++ b/src/cli/args.test.ts @@ -1,6 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { + commandNeedsOverlayRuntime, hasExplicitCommand, isHeadlessInitialCommand, parseArgs, @@ -70,6 +71,12 @@ test('parseArgs captures youtube startup forwarding flags', () => { assert.equal(shouldStartApp(args), true); }); +test('youtube playback does not use generic overlay-runtime bootstrap classification', () => { + const args = parseArgs(['--youtube-play', 'https://youtube.com/watch?v=abc']); + + assert.equal(commandNeedsOverlayRuntime(args), false); +}); + test('parseArgs handles jellyfin item listing controls', () => { const args = parseArgs([ '--jellyfin-items', diff --git a/src/cli/args.ts b/src/cli/args.ts index d9dd468..75cb3ce 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -499,7 +499,10 @@ export function commandNeedsOverlayRuntime(args: CliArgs): boolean { args.triggerFieldGrouping || args.triggerSubsync || args.markAudioCard || - args.openRuntimeOptions || - Boolean(args.youtubePlay) + args.openRuntimeOptions ); } + +export function commandNeedsOverlayStartupPrereqs(args: CliArgs): boolean { + return commandNeedsOverlayRuntime(args) || Boolean(args.youtubePlay); +} diff --git a/src/core/services/cli-command.test.ts b/src/core/services/cli-command.test.ts index 2020bc9..6b370c0 100644 --- a/src/core/services/cli-command.test.ts +++ b/src/core/services/cli-command.test.ts @@ -225,10 +225,7 @@ test('handleCliCommand starts youtube playback flow on initial launch', () => { deps, ); - assert.deepEqual(calls, [ - 'initializeOverlayRuntime', - 'youtube:https://youtube.com/watch?v=abc:generate', - ]); + assert.deepEqual(calls, ['youtube:https://youtube.com/watch?v=abc:generate']); }); test('handleCliCommand defaults youtube mode to download when omitted', () => { @@ -240,10 +237,7 @@ test('handleCliCommand defaults youtube mode to download when omitted', () => { handleCliCommand(makeArgs({ youtubePlay: 'https://youtube.com/watch?v=abc' }), 'initial', deps); - assert.deepEqual(calls, [ - 'initializeOverlayRuntime', - 'youtube:https://youtube.com/watch?v=abc:download', - ]); + assert.deepEqual(calls, ['youtube:https://youtube.com/watch?v=abc:download']); }); test('handleCliCommand reuses initialized overlay runtime for second-instance youtube playback', () => { diff --git a/src/main.ts b/src/main.ts index 7626239..6ceb813 100644 --- a/src/main.ts +++ b/src/main.ts @@ -105,6 +105,7 @@ import { createLogger, setLogLevel, type LogLevelSource } from './logger'; import { resolveDefaultLogFilePath } from './logger'; import { createWindowTracker as createWindowTrackerCore } from './window-trackers'; import { + commandNeedsOverlayStartupPrereqs, commandNeedsOverlayRuntime, isHeadlessInitialCommand, parseArgs, @@ -990,6 +991,7 @@ async function runYoutubePlaybackFlowMain(request: { try { clearYoutubePlayQuitOnDisconnectArmTimer(); youtubePlayQuitOnDisconnectArmed = false; + await ensureYoutubePlaybackRuntimeReady(); let playbackUrl = request.url; let launchedWindowsMpv = false; if (process.platform === 'win32') { @@ -3528,7 +3530,7 @@ const handleCliCommand = createCliCommandRuntimeHandler({ setTexthookerOnlyMode: (enabled) => { appState.texthookerOnlyMode = enabled; }, - commandNeedsOverlayRuntime: (inputArgs) => commandNeedsOverlayRuntime(inputArgs), + commandNeedsOverlayStartupPrereqs: (inputArgs) => commandNeedsOverlayStartupPrereqs(inputArgs), startBackgroundWarmups: () => startBackgroundWarmups(), logInfo: (message: string) => logger.info(message), }, @@ -3571,6 +3573,16 @@ function ensureOverlayStartupPrereqs(): void { } } +async function ensureYoutubePlaybackRuntimeReady(): Promise { + ensureOverlayStartupPrereqs(); + await ensureYomitanExtensionLoaded(); + if (!appState.overlayRuntimeInitialized) { + initializeOverlayRuntime(); + return; + } + ensureOverlayWindowsReadyForVisibilityActions(); +} + const handleInitialArgsRuntimeHandler = createInitialArgsRuntimeHandler({ getInitialArgs: () => appState.initialArgs, isBackgroundMode: () => appState.backgroundMode, @@ -3581,6 +3593,7 @@ const handleInitialArgsRuntimeHandler = createInitialArgsRuntimeHandler({ isTexthookerOnlyMode: () => appState.texthookerOnlyMode, hasImmersionTracker: () => Boolean(appState.immersionTracker), getMpvClient: () => appState.mpvClient, + commandNeedsOverlayStartupPrereqs: (args) => commandNeedsOverlayStartupPrereqs(args), commandNeedsOverlayRuntime: (args) => commandNeedsOverlayRuntime(args), ensureOverlayStartupPrereqs: () => ensureOverlayStartupPrereqs(), isOverlayRuntimeInitialized: () => appState.overlayRuntimeInitialized, diff --git a/src/main/runtime/cli-command-prechecks-main-deps.test.ts b/src/main/runtime/cli-command-prechecks-main-deps.test.ts index 084eae2..cf0a1f3 100644 --- a/src/main/runtime/cli-command-prechecks-main-deps.test.ts +++ b/src/main/runtime/cli-command-prechecks-main-deps.test.ts @@ -7,14 +7,14 @@ test('cli prechecks main deps builder maps transition handlers', () => { const deps = createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler({ isTexthookerOnlyMode: () => true, setTexthookerOnlyMode: (enabled) => calls.push(`set:${enabled}`), - commandNeedsOverlayRuntime: () => true, + commandNeedsOverlayStartupPrereqs: () => true, ensureOverlayStartupPrereqs: () => calls.push('prereqs'), startBackgroundWarmups: () => calls.push('warmups'), logInfo: (message) => calls.push(`info:${message}`), })(); assert.equal(deps.isTexthookerOnlyMode(), true); - assert.equal(deps.commandNeedsOverlayRuntime({} as never), true); + assert.equal(deps.commandNeedsOverlayStartupPrereqs({} as never), true); deps.setTexthookerOnlyMode(false); deps.ensureOverlayStartupPrereqs(); deps.startBackgroundWarmups(); diff --git a/src/main/runtime/cli-command-prechecks-main-deps.ts b/src/main/runtime/cli-command-prechecks-main-deps.ts index 8541df3..c8cabce 100644 --- a/src/main/runtime/cli-command-prechecks-main-deps.ts +++ b/src/main/runtime/cli-command-prechecks-main-deps.ts @@ -3,7 +3,7 @@ import type { CliArgs } from '../../cli/args'; export function createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler(deps: { isTexthookerOnlyMode: () => boolean; setTexthookerOnlyMode: (enabled: boolean) => void; - commandNeedsOverlayRuntime: (args: CliArgs) => boolean; + commandNeedsOverlayStartupPrereqs: (args: CliArgs) => boolean; ensureOverlayStartupPrereqs: () => void; startBackgroundWarmups: () => void; logInfo: (message: string) => void; @@ -11,7 +11,8 @@ export function createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler(dep return () => ({ isTexthookerOnlyMode: () => deps.isTexthookerOnlyMode(), setTexthookerOnlyMode: (enabled: boolean) => deps.setTexthookerOnlyMode(enabled), - commandNeedsOverlayRuntime: (args: CliArgs) => deps.commandNeedsOverlayRuntime(args), + commandNeedsOverlayStartupPrereqs: (args: CliArgs) => + deps.commandNeedsOverlayStartupPrereqs(args), ensureOverlayStartupPrereqs: () => deps.ensureOverlayStartupPrereqs(), startBackgroundWarmups: () => deps.startBackgroundWarmups(), logInfo: (message: string) => deps.logInfo(message), diff --git a/src/main/runtime/cli-command-prechecks.test.ts b/src/main/runtime/cli-command-prechecks.test.ts index 5d8532f..c985533 100644 --- a/src/main/runtime/cli-command-prechecks.test.ts +++ b/src/main/runtime/cli-command-prechecks.test.ts @@ -7,7 +7,7 @@ test('texthooker precheck no-ops when mode is disabled', () => { const handlePrecheck = createHandleTexthookerOnlyModeTransitionHandler({ isTexthookerOnlyMode: () => false, setTexthookerOnlyMode: () => {}, - commandNeedsOverlayRuntime: () => true, + commandNeedsOverlayStartupPrereqs: () => true, ensureOverlayStartupPrereqs: () => {}, startBackgroundWarmups: () => { warmups += 1; @@ -29,7 +29,7 @@ test('texthooker precheck disables mode and warms up on start command', () => { setTexthookerOnlyMode: (enabled) => { mode = enabled; }, - commandNeedsOverlayRuntime: () => false, + commandNeedsOverlayStartupPrereqs: () => false, ensureOverlayStartupPrereqs: () => { prereqs += 1; }, @@ -55,7 +55,7 @@ test('texthooker precheck no-ops for texthooker command', () => { setTexthookerOnlyMode: (enabled) => { mode = enabled; }, - commandNeedsOverlayRuntime: () => true, + commandNeedsOverlayStartupPrereqs: () => true, ensureOverlayStartupPrereqs: () => {}, startBackgroundWarmups: () => {}, logInfo: () => {}, @@ -64,3 +64,25 @@ test('texthooker precheck no-ops for texthooker command', () => { handlePrecheck({ start: true, texthooker: true } as never); assert.equal(mode, true); }); + +test('texthooker precheck transitions for youtube playback startup prereqs', () => { + let mode = true; + let prereqs = 0; + const handlePrecheck = createHandleTexthookerOnlyModeTransitionHandler({ + isTexthookerOnlyMode: () => mode, + setTexthookerOnlyMode: (enabled) => { + mode = enabled; + }, + commandNeedsOverlayStartupPrereqs: () => true, + ensureOverlayStartupPrereqs: () => { + prereqs += 1; + }, + startBackgroundWarmups: () => {}, + logInfo: () => {}, + }); + + handlePrecheck({ youtubePlay: 'https://youtube.com/watch?v=abc', texthooker: false } as never); + + assert.equal(mode, false); + assert.equal(prereqs, 1); +}); diff --git a/src/main/runtime/cli-command-prechecks.ts b/src/main/runtime/cli-command-prechecks.ts index 91ed8f6..01eb265 100644 --- a/src/main/runtime/cli-command-prechecks.ts +++ b/src/main/runtime/cli-command-prechecks.ts @@ -3,7 +3,7 @@ import type { CliArgs } from '../../cli/args'; export function createHandleTexthookerOnlyModeTransitionHandler(deps: { isTexthookerOnlyMode: () => boolean; setTexthookerOnlyMode: (enabled: boolean) => void; - commandNeedsOverlayRuntime: (args: CliArgs) => boolean; + commandNeedsOverlayStartupPrereqs: (args: CliArgs) => boolean; ensureOverlayStartupPrereqs: () => void; startBackgroundWarmups: () => void; logInfo: (message: string) => void; @@ -12,7 +12,7 @@ export function createHandleTexthookerOnlyModeTransitionHandler(deps: { if ( deps.isTexthookerOnlyMode() && !args.texthooker && - (args.start || deps.commandNeedsOverlayRuntime(args)) + (args.start || deps.commandNeedsOverlayStartupPrereqs(args)) ) { deps.ensureOverlayStartupPrereqs(); deps.setTexthookerOnlyMode(false); diff --git a/src/main/runtime/cli-command-runtime-handler.test.ts b/src/main/runtime/cli-command-runtime-handler.test.ts index 6b51e41..960446b 100644 --- a/src/main/runtime/cli-command-runtime-handler.test.ts +++ b/src/main/runtime/cli-command-runtime-handler.test.ts @@ -8,7 +8,7 @@ test('cli command runtime handler applies precheck and forwards command with con handleTexthookerOnlyModeTransitionMainDeps: { isTexthookerOnlyMode: () => true, setTexthookerOnlyMode: () => calls.push('set-mode'), - commandNeedsOverlayRuntime: () => true, + commandNeedsOverlayStartupPrereqs: () => true, ensureOverlayStartupPrereqs: () => calls.push('prereqs'), startBackgroundWarmups: () => calls.push('warmups'), logInfo: (message) => calls.push(`log:${message}`), @@ -40,7 +40,7 @@ test('cli command runtime handler prepares overlay prerequisites before overlay handleTexthookerOnlyModeTransitionMainDeps: { isTexthookerOnlyMode: () => false, setTexthookerOnlyMode: () => calls.push('set-mode'), - commandNeedsOverlayRuntime: () => true, + commandNeedsOverlayStartupPrereqs: () => true, ensureOverlayStartupPrereqs: () => calls.push('prereqs'), startBackgroundWarmups: () => calls.push('warmups'), logInfo: (message) => calls.push(`log:${message}`), @@ -58,3 +58,28 @@ test('cli command runtime handler prepares overlay prerequisites before overlay assert.deepEqual(calls, ['prereqs', 'context', 'cli:initial:ctx']); }); + +test('cli command runtime handler skips generic overlay prerequisites for youtube playback', () => { + const calls: string[] = []; + const handler = createCliCommandRuntimeHandler({ + handleTexthookerOnlyModeTransitionMainDeps: { + isTexthookerOnlyMode: () => false, + setTexthookerOnlyMode: () => calls.push('set-mode'), + commandNeedsOverlayStartupPrereqs: () => false, + ensureOverlayStartupPrereqs: () => calls.push('prereqs'), + startBackgroundWarmups: () => calls.push('warmups'), + logInfo: (message) => calls.push(`log:${message}`), + }, + createCliCommandContext: () => { + calls.push('context'); + return { id: 'ctx' }; + }, + handleCliCommandRuntimeServiceWithContext: (_args, source, context) => { + calls.push(`cli:${source}:${context.id}`); + }, + }); + + handler({ youtubePlay: 'https://youtube.com/watch?v=abc' } as never); + + assert.deepEqual(calls, ['context', 'cli:initial:ctx']); +}); diff --git a/src/main/runtime/cli-command-runtime-handler.ts b/src/main/runtime/cli-command-runtime-handler.ts index e57c3a4..8aa403f 100644 --- a/src/main/runtime/cli-command-runtime-handler.ts +++ b/src/main/runtime/cli-command-runtime-handler.ts @@ -25,7 +25,7 @@ export function createCliCommandRuntimeHandler(deps: { handleTexthookerOnlyModeTransitionHandler(args); if ( !deps.handleTexthookerOnlyModeTransitionMainDeps.isTexthookerOnlyMode() && - deps.handleTexthookerOnlyModeTransitionMainDeps.commandNeedsOverlayRuntime(args) + deps.handleTexthookerOnlyModeTransitionMainDeps.commandNeedsOverlayStartupPrereqs(args) ) { deps.handleTexthookerOnlyModeTransitionMainDeps.ensureOverlayStartupPrereqs(); } diff --git a/src/main/runtime/initial-args-handler.test.ts b/src/main/runtime/initial-args-handler.test.ts index b9da6bc..751e1f3 100644 --- a/src/main/runtime/initial-args-handler.test.ts +++ b/src/main/runtime/initial-args-handler.test.ts @@ -13,6 +13,7 @@ test('initial args handler no-ops without initial args', () => { isTexthookerOnlyMode: () => false, hasImmersionTracker: () => false, getMpvClient: () => null, + commandNeedsOverlayStartupPrereqs: () => false, commandNeedsOverlayRuntime: () => false, ensureOverlayStartupPrereqs: () => {}, isOverlayRuntimeInitialized: () => false, @@ -40,6 +41,7 @@ test('initial args handler ensures tray in background mode', () => { isTexthookerOnlyMode: () => true, hasImmersionTracker: () => false, getMpvClient: () => null, + commandNeedsOverlayStartupPrereqs: () => false, commandNeedsOverlayRuntime: () => false, ensureOverlayStartupPrereqs: () => {}, isOverlayRuntimeInitialized: () => false, @@ -69,6 +71,7 @@ test('initial args handler auto-connects mpv when needed', () => { connectCalls += 1; }, }), + commandNeedsOverlayStartupPrereqs: () => false, commandNeedsOverlayRuntime: () => false, ensureOverlayStartupPrereqs: () => {}, isOverlayRuntimeInitialized: () => false, @@ -95,6 +98,7 @@ test('initial args handler forwards args to cli handler', () => { isTexthookerOnlyMode: () => false, hasImmersionTracker: () => false, getMpvClient: () => null, + commandNeedsOverlayStartupPrereqs: () => false, commandNeedsOverlayRuntime: () => false, ensureOverlayStartupPrereqs: () => { seenSources.push('prereqs'); @@ -125,6 +129,7 @@ test('initial args handler bootstraps overlay before initial overlay-runtime com isTexthookerOnlyMode: () => false, hasImmersionTracker: () => false, getMpvClient: () => null, + commandNeedsOverlayStartupPrereqs: (inputArgs) => inputArgs === args, commandNeedsOverlayRuntime: (inputArgs) => inputArgs === args, ensureOverlayStartupPrereqs: () => { calls.push('prereqs'); @@ -144,6 +149,38 @@ test('initial args handler bootstraps overlay before initial overlay-runtime com assert.deepEqual(calls, ['prereqs', 'init-overlay', 'cli:initial']); }); +test('initial args handler prepares prereqs but skips eager overlay bootstrap for youtube playback', () => { + const calls: string[] = []; + const args = { youtubePlay: 'https://youtube.com/watch?v=abc' } as never; + const handleInitialArgs = createHandleInitialArgsHandler({ + getInitialArgs: () => args, + isBackgroundMode: () => false, + shouldEnsureTrayOnStartup: () => false, + shouldRunHeadlessInitialCommand: () => false, + ensureTray: () => {}, + isTexthookerOnlyMode: () => false, + hasImmersionTracker: () => false, + getMpvClient: () => null, + commandNeedsOverlayStartupPrereqs: () => true, + commandNeedsOverlayRuntime: () => false, + ensureOverlayStartupPrereqs: () => { + calls.push('prereqs'); + }, + isOverlayRuntimeInitialized: () => false, + initializeOverlayRuntime: () => { + calls.push('init-overlay'); + }, + logInfo: () => {}, + handleCliCommand: (_args, source) => { + calls.push(`cli:${source}`); + }, + }); + + handleInitialArgs(); + + assert.deepEqual(calls, ['prereqs', 'cli:initial']); +}); + test('initial args handler can ensure tray outside background mode when requested', () => { let ensuredTray = false; const handleInitialArgs = createHandleInitialArgsHandler({ @@ -157,6 +194,7 @@ test('initial args handler can ensure tray outside background mode when requeste isTexthookerOnlyMode: () => true, hasImmersionTracker: () => false, getMpvClient: () => null, + commandNeedsOverlayStartupPrereqs: () => false, commandNeedsOverlayRuntime: () => false, ensureOverlayStartupPrereqs: () => {}, isOverlayRuntimeInitialized: () => false, @@ -188,6 +226,7 @@ test('initial args handler skips tray and mpv auto-connect for headless refresh' connectCalls += 1; }, }), + commandNeedsOverlayStartupPrereqs: () => true, commandNeedsOverlayRuntime: () => true, ensureOverlayStartupPrereqs: () => {}, isOverlayRuntimeInitialized: () => false, diff --git a/src/main/runtime/initial-args-handler.ts b/src/main/runtime/initial-args-handler.ts index acfe021..7d28603 100644 --- a/src/main/runtime/initial-args-handler.ts +++ b/src/main/runtime/initial-args-handler.ts @@ -14,6 +14,7 @@ export function createHandleInitialArgsHandler(deps: { isTexthookerOnlyMode: () => boolean; hasImmersionTracker: () => boolean; getMpvClient: () => MpvClientLike | null; + commandNeedsOverlayStartupPrereqs: (args: CliArgs) => boolean; commandNeedsOverlayRuntime: (args: CliArgs) => boolean; ensureOverlayStartupPrereqs: () => void; isOverlayRuntimeInitialized: () => boolean; @@ -43,8 +44,10 @@ export function createHandleInitialArgsHandler(deps: { mpvClient.connect(); } - if (!runHeadless && deps.commandNeedsOverlayRuntime(initialArgs)) { + if (!runHeadless && deps.commandNeedsOverlayStartupPrereqs(initialArgs)) { deps.ensureOverlayStartupPrereqs(); + } + if (!runHeadless && deps.commandNeedsOverlayRuntime(initialArgs)) { if (!deps.isOverlayRuntimeInitialized()) { deps.initializeOverlayRuntime(); } diff --git a/src/main/runtime/initial-args-main-deps.test.ts b/src/main/runtime/initial-args-main-deps.test.ts index bf5eee5..df0ef8e 100644 --- a/src/main/runtime/initial-args-main-deps.test.ts +++ b/src/main/runtime/initial-args-main-deps.test.ts @@ -15,6 +15,7 @@ test('initial args main deps builder maps runtime callbacks and state readers', isTexthookerOnlyMode: () => false, hasImmersionTracker: () => true, getMpvClient: () => mpvClient, + commandNeedsOverlayStartupPrereqs: () => true, commandNeedsOverlayRuntime: () => true, ensureOverlayStartupPrereqs: () => calls.push('prereqs'), isOverlayRuntimeInitialized: () => false, @@ -30,6 +31,7 @@ test('initial args main deps builder maps runtime callbacks and state readers', assert.equal(deps.isTexthookerOnlyMode(), false); assert.equal(deps.hasImmersionTracker(), true); assert.equal(deps.getMpvClient(), mpvClient); + assert.equal(deps.commandNeedsOverlayStartupPrereqs(args), true); assert.equal(deps.commandNeedsOverlayRuntime(args), true); assert.equal(deps.isOverlayRuntimeInitialized(), false); diff --git a/src/main/runtime/initial-args-main-deps.ts b/src/main/runtime/initial-args-main-deps.ts index bdae28f..9da01e5 100644 --- a/src/main/runtime/initial-args-main-deps.ts +++ b/src/main/runtime/initial-args-main-deps.ts @@ -9,6 +9,7 @@ export function createBuildHandleInitialArgsMainDepsHandler(deps: { isTexthookerOnlyMode: () => boolean; hasImmersionTracker: () => boolean; getMpvClient: () => { connected: boolean; connect: () => void } | null; + commandNeedsOverlayStartupPrereqs: (args: CliArgs) => boolean; commandNeedsOverlayRuntime: (args: CliArgs) => boolean; ensureOverlayStartupPrereqs: () => void; isOverlayRuntimeInitialized: () => boolean; @@ -25,6 +26,8 @@ export function createBuildHandleInitialArgsMainDepsHandler(deps: { isTexthookerOnlyMode: () => deps.isTexthookerOnlyMode(), hasImmersionTracker: () => deps.hasImmersionTracker(), getMpvClient: () => deps.getMpvClient(), + commandNeedsOverlayStartupPrereqs: (args: CliArgs) => + deps.commandNeedsOverlayStartupPrereqs(args), commandNeedsOverlayRuntime: (args: CliArgs) => deps.commandNeedsOverlayRuntime(args), ensureOverlayStartupPrereqs: () => deps.ensureOverlayStartupPrereqs(), isOverlayRuntimeInitialized: () => deps.isOverlayRuntimeInitialized(), diff --git a/src/main/runtime/initial-args-runtime-handler.test.ts b/src/main/runtime/initial-args-runtime-handler.test.ts index ac0fade..b9e7aae 100644 --- a/src/main/runtime/initial-args-runtime-handler.test.ts +++ b/src/main/runtime/initial-args-runtime-handler.test.ts @@ -16,6 +16,7 @@ test('initial args runtime handler composes main deps and runs initial command f connected: false, connect: () => calls.push('connect'), }), + commandNeedsOverlayStartupPrereqs: () => false, commandNeedsOverlayRuntime: () => false, ensureOverlayStartupPrereqs: () => calls.push('prereqs'), isOverlayRuntimeInitialized: () => false, @@ -48,6 +49,7 @@ test('initial args runtime handler skips mpv auto-connect for stats mode', () => connected: false, connect: () => calls.push('connect'), }), + commandNeedsOverlayStartupPrereqs: () => false, commandNeedsOverlayRuntime: () => false, ensureOverlayStartupPrereqs: () => calls.push('prereqs'), isOverlayRuntimeInitialized: () => false, @@ -75,6 +77,7 @@ test('initial args runtime handler skips tray and mpv auto-connect for headless connected: false, connect: () => calls.push('connect'), }), + commandNeedsOverlayStartupPrereqs: () => true, commandNeedsOverlayRuntime: () => true, ensureOverlayStartupPrereqs: () => calls.push('prereqs'), isOverlayRuntimeInitialized: () => false,