mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-01 06:22:44 -08:00
fix: lazy initialize immersion tracker
This commit is contained in:
@@ -58,9 +58,12 @@ test('runAppReadyRuntime starts websocket in auto mode when plugin missing', asy
|
|||||||
await runAppReadyRuntime(deps);
|
await runAppReadyRuntime(deps);
|
||||||
assert.ok(calls.includes('startSubtitleWebsocket:9001'));
|
assert.ok(calls.includes('startSubtitleWebsocket:9001'));
|
||||||
assert.ok(calls.includes('initializeOverlayRuntime'));
|
assert.ok(calls.includes('initializeOverlayRuntime'));
|
||||||
assert.ok(calls.includes('createImmersionTracker'));
|
|
||||||
assert.ok(calls.includes('startBackgroundWarmups'));
|
assert.ok(calls.includes('startBackgroundWarmups'));
|
||||||
assert.ok(calls.includes('log:Runtime ready: invoking createImmersionTracker.'));
|
assert.ok(
|
||||||
|
calls.includes(
|
||||||
|
'log:Runtime ready: immersion tracker startup deferred until first media activity.',
|
||||||
|
),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('runAppReadyRuntime skips Jellyfin remote startup when dependency is not wired', async () => {
|
test('runAppReadyRuntime skips Jellyfin remote startup when dependency is not wired', async () => {
|
||||||
@@ -86,23 +89,7 @@ test('runAppReadyRuntime logs when createImmersionTracker dependency is missing'
|
|||||||
createImmersionTracker: undefined,
|
createImmersionTracker: undefined,
|
||||||
});
|
});
|
||||||
await runAppReadyRuntime(deps);
|
await runAppReadyRuntime(deps);
|
||||||
assert.ok(calls.includes('log:Runtime ready: createImmersionTracker dependency is missing.'));
|
assert.ok(calls.includes('log:Runtime ready: immersion tracker dependency is missing.'));
|
||||||
});
|
|
||||||
|
|
||||||
test('runAppReadyRuntime logs and continues when createImmersionTracker throws', async () => {
|
|
||||||
const { deps, calls } = makeDeps({
|
|
||||||
createImmersionTracker: () => {
|
|
||||||
calls.push('createImmersionTracker');
|
|
||||||
throw new Error('immersion init failed');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await runAppReadyRuntime(deps);
|
|
||||||
assert.ok(calls.includes('createImmersionTracker'));
|
|
||||||
assert.ok(
|
|
||||||
calls.includes('log:Runtime ready: createImmersionTracker failed: immersion init failed'),
|
|
||||||
);
|
|
||||||
assert.ok(calls.includes('initializeOverlayRuntime'));
|
|
||||||
assert.ok(calls.includes('handleInitialArgs'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('runAppReadyRuntime logs defer message when overlay not auto-started', async () => {
|
test('runAppReadyRuntime logs defer message when overlay not auto-started', async () => {
|
||||||
|
|||||||
@@ -203,14 +203,9 @@ export async function runAppReadyRuntime(deps: AppReadyRuntimeDeps): Promise<voi
|
|||||||
|
|
||||||
deps.createSubtitleTimingTracker();
|
deps.createSubtitleTimingTracker();
|
||||||
if (deps.createImmersionTracker) {
|
if (deps.createImmersionTracker) {
|
||||||
deps.log('Runtime ready: invoking createImmersionTracker.');
|
deps.log('Runtime ready: immersion tracker startup deferred until first media activity.');
|
||||||
try {
|
|
||||||
deps.createImmersionTracker();
|
|
||||||
} catch (error) {
|
|
||||||
deps.log(`Runtime ready: createImmersionTracker failed: ${(error as Error).message}`);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
deps.log('Runtime ready: createImmersionTracker dependency is missing.');
|
deps.log('Runtime ready: immersion tracker dependency is missing.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deps.texthookerOnlyMode) {
|
if (deps.texthookerOnlyMode) {
|
||||||
|
|||||||
99
src/main.ts
99
src/main.ts
@@ -365,6 +365,8 @@ import {
|
|||||||
triggerFieldGrouping as triggerFieldGroupingCore,
|
triggerFieldGrouping as triggerFieldGroupingCore,
|
||||||
updateLastCardFromClipboard as updateLastCardFromClipboardCore,
|
updateLastCardFromClipboard as updateLastCardFromClipboardCore,
|
||||||
} from './core/services';
|
} from './core/services';
|
||||||
|
import { createImmersionTrackerStartupHandler } from './main/runtime/immersion-startup';
|
||||||
|
import { createBuildImmersionTrackerStartupMainDepsHandler } from './main/runtime/immersion-startup-main-deps';
|
||||||
import { createAnilistUpdateQueue } from './core/services/anilist/anilist-update-queue';
|
import { createAnilistUpdateQueue } from './core/services/anilist/anilist-update-queue';
|
||||||
import {
|
import {
|
||||||
guessAnilistMediaInfo,
|
guessAnilistMediaInfo,
|
||||||
@@ -437,7 +439,9 @@ import { resolveConfigDir } from './config/path-resolution';
|
|||||||
|
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal');
|
app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal');
|
||||||
const passwordStore = normalizePasswordStoreArg(getPasswordStoreArg(process.argv) ?? getDefaultPasswordStore());
|
const passwordStore = normalizePasswordStoreArg(
|
||||||
|
getPasswordStoreArg(process.argv) ?? getDefaultPasswordStore(),
|
||||||
|
);
|
||||||
app.commandLine.appendSwitch('password-store', passwordStore);
|
app.commandLine.appendSwitch('password-store', passwordStore);
|
||||||
console.debug(`[main] Applied --password-store ${passwordStore}`);
|
console.debug(`[main] Applied --password-store ${passwordStore}`);
|
||||||
}
|
}
|
||||||
@@ -683,8 +687,13 @@ function refreshDiscordPresenceMediaDuration(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function publishDiscordPresence(): void {
|
function publishDiscordPresence(): void {
|
||||||
|
const discordPresenceService = appState.discordPresenceService;
|
||||||
|
if (!discordPresenceService || getResolvedConfig().discordPresence.enabled !== true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
refreshDiscordPresenceMediaDuration();
|
refreshDiscordPresenceMediaDuration();
|
||||||
appState.discordPresenceService?.publish({
|
discordPresenceService.publish({
|
||||||
mediaTitle: appState.currentMediaTitle,
|
mediaTitle: appState.currentMediaTitle,
|
||||||
mediaPath: appState.currentMediaPath,
|
mediaPath: appState.currentMediaPath,
|
||||||
subtitleText: appState.currentSubText,
|
subtitleText: appState.currentSubText,
|
||||||
@@ -718,6 +727,11 @@ function createDiscordRpcClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function initializeDiscordPresenceService(): Promise<void> {
|
async function initializeDiscordPresenceService(): Promise<void> {
|
||||||
|
if (getResolvedConfig().discordPresence.enabled !== true) {
|
||||||
|
appState.discordPresenceService = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
appState.discordPresenceService = createDiscordPresenceService({
|
appState.discordPresenceService = createDiscordPresenceService({
|
||||||
config: getResolvedConfig().discordPresence,
|
config: getResolvedConfig().discordPresence,
|
||||||
createClient: () => createDiscordRpcClient(),
|
createClient: () => createDiscordRpcClient(),
|
||||||
@@ -1802,6 +1816,15 @@ const {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function refreshAnilistClientSecretStateIfEnabled(options?: {
|
||||||
|
force?: boolean;
|
||||||
|
}): Promise<string | null> {
|
||||||
|
if (!isAnilistTrackingEnabled(getResolvedConfig())) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
return refreshAnilistClientSecretState(options);
|
||||||
|
}
|
||||||
|
|
||||||
const rememberAnilistAttemptedUpdate = (key: string): void => {
|
const rememberAnilistAttemptedUpdate = (key: string): void => {
|
||||||
rememberAnilistAttemptedUpdateKey(
|
rememberAnilistAttemptedUpdateKey(
|
||||||
anilistAttemptedUpdateKeys,
|
anilistAttemptedUpdateKeys,
|
||||||
@@ -1930,6 +1953,35 @@ const {
|
|||||||
});
|
});
|
||||||
registerProtocolUrlHandlersHandler();
|
registerProtocolUrlHandlersHandler();
|
||||||
|
|
||||||
|
const immersionTrackerStartupMainDeps: Parameters<
|
||||||
|
typeof createBuildImmersionTrackerStartupMainDepsHandler
|
||||||
|
>[0] = {
|
||||||
|
getResolvedConfig: () => getResolvedConfig(),
|
||||||
|
getConfiguredDbPath: () => immersionMediaRuntime.getConfiguredDbPath(),
|
||||||
|
createTrackerService: (params) => new ImmersionTrackerService(params),
|
||||||
|
setTracker: (tracker) => {
|
||||||
|
appState.immersionTracker = tracker as ImmersionTrackerService | null;
|
||||||
|
},
|
||||||
|
getMpvClient: () => appState.mpvClient,
|
||||||
|
seedTrackerFromCurrentMedia: () => {
|
||||||
|
void immersionMediaRuntime.seedFromCurrentMedia();
|
||||||
|
},
|
||||||
|
logInfo: (message) => logger.info(message),
|
||||||
|
logDebug: (message) => logger.debug(message),
|
||||||
|
logWarn: (message, details) => logger.warn(message, details),
|
||||||
|
};
|
||||||
|
const createImmersionTrackerStartup = createImmersionTrackerStartupHandler(
|
||||||
|
createBuildImmersionTrackerStartupMainDepsHandler(immersionTrackerStartupMainDeps)(),
|
||||||
|
);
|
||||||
|
let hasAttemptedImmersionTrackerStartup = false;
|
||||||
|
const ensureImmersionTrackerStarted = (): void => {
|
||||||
|
if (hasAttemptedImmersionTrackerStartup || appState.immersionTracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hasAttemptedImmersionTrackerStartup = true;
|
||||||
|
createImmersionTrackerStartup();
|
||||||
|
};
|
||||||
|
|
||||||
const { reloadConfig: reloadConfigHandler, appReadyRuntimeRunner } = composeAppReadyRuntime({
|
const { reloadConfig: reloadConfigHandler, appReadyRuntimeRunner } = composeAppReadyRuntime({
|
||||||
reloadConfigMainDeps: {
|
reloadConfigMainDeps: {
|
||||||
reloadConfigStrict: () => configService.reloadConfigStrict(),
|
reloadConfigStrict: () => configService.reloadConfigStrict(),
|
||||||
@@ -1937,7 +1989,7 @@ const { reloadConfig: reloadConfigHandler, appReadyRuntimeRunner } = composeAppR
|
|||||||
logWarning: (message) => appLogger.logWarning(message),
|
logWarning: (message) => appLogger.logWarning(message),
|
||||||
showDesktopNotification: (title, options) => showDesktopNotification(title, options),
|
showDesktopNotification: (title, options) => showDesktopNotification(title, options),
|
||||||
startConfigHotReload: () => configHotReloadRuntime.start(),
|
startConfigHotReload: () => configHotReloadRuntime.start(),
|
||||||
refreshAnilistClientSecretState: (options) => refreshAnilistClientSecretState(options),
|
refreshAnilistClientSecretState: (options) => refreshAnilistClientSecretStateIfEnabled(options),
|
||||||
failHandlers: {
|
failHandlers: {
|
||||||
logError: (details) => logger.error(details),
|
logError: (details) => logger.error(details),
|
||||||
showErrorBox: (title, details) => dialog.showErrorBox(title, details),
|
showErrorBox: (title, details) => dialog.showErrorBox(title, details),
|
||||||
@@ -2016,26 +2068,15 @@ const { reloadConfig: reloadConfigHandler, appReadyRuntimeRunner } = composeAppR
|
|||||||
: configDerivedRuntime.shouldAutoInitializeOverlayRuntimeFromConfig(),
|
: configDerivedRuntime.shouldAutoInitializeOverlayRuntimeFromConfig(),
|
||||||
initializeOverlayRuntime: () => initializeOverlayRuntime(),
|
initializeOverlayRuntime: () => initializeOverlayRuntime(),
|
||||||
handleInitialArgs: () => handleInitialArgs(),
|
handleInitialArgs: () => handleInitialArgs(),
|
||||||
|
createImmersionTracker: () => {
|
||||||
|
ensureImmersionTrackerStarted();
|
||||||
|
},
|
||||||
logDebug: (message: string) => {
|
logDebug: (message: string) => {
|
||||||
logger.debug(message);
|
logger.debug(message);
|
||||||
},
|
},
|
||||||
now: () => Date.now(),
|
now: () => Date.now(),
|
||||||
},
|
},
|
||||||
immersionTrackerStartupMainDeps: {
|
immersionTrackerStartupMainDeps,
|
||||||
getResolvedConfig: () => getResolvedConfig(),
|
|
||||||
getConfiguredDbPath: () => immersionMediaRuntime.getConfiguredDbPath(),
|
|
||||||
createTrackerService: (params) => new ImmersionTrackerService(params),
|
|
||||||
setTracker: (tracker) => {
|
|
||||||
appState.immersionTracker = tracker as ImmersionTrackerService | null;
|
|
||||||
},
|
|
||||||
getMpvClient: () => appState.mpvClient,
|
|
||||||
seedTrackerFromCurrentMedia: () => {
|
|
||||||
void immersionMediaRuntime.seedFromCurrentMedia();
|
|
||||||
},
|
|
||||||
logInfo: (message) => logger.info(message),
|
|
||||||
logDebug: (message) => logger.debug(message),
|
|
||||||
logWarn: (message, details) => logger.warn(message, details),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { appLifecycleRuntimeRunner, runAndApplyStartupState } =
|
const { appLifecycleRuntimeRunner, runAndApplyStartupState } =
|
||||||
@@ -2099,8 +2140,10 @@ const { appLifecycleRuntimeRunner, runAndApplyStartupState } =
|
|||||||
});
|
});
|
||||||
|
|
||||||
runAndApplyStartupState();
|
runAndApplyStartupState();
|
||||||
void refreshAnilistClientSecretState({ force: true });
|
if (isAnilistTrackingEnabled(getResolvedConfig())) {
|
||||||
anilistStateRuntime.refreshRetryQueueState();
|
void refreshAnilistClientSecretStateIfEnabled({ force: true });
|
||||||
|
anilistStateRuntime.refreshRetryQueueState();
|
||||||
|
}
|
||||||
void initializeDiscordPresenceService();
|
void initializeDiscordPresenceService();
|
||||||
|
|
||||||
const handleCliCommand = createCliCommandRuntimeHandler({
|
const handleCliCommand = createCliCommandRuntimeHandler({
|
||||||
@@ -2167,7 +2210,13 @@ const {
|
|||||||
refreshDiscordPresence: () => {
|
refreshDiscordPresence: () => {
|
||||||
publishDiscordPresence();
|
publishDiscordPresence();
|
||||||
},
|
},
|
||||||
|
ensureImmersionTrackerInitialized: () => {
|
||||||
|
ensureImmersionTrackerStarted();
|
||||||
|
},
|
||||||
updateCurrentMediaPath: (path) => {
|
updateCurrentMediaPath: (path) => {
|
||||||
|
if (path) {
|
||||||
|
ensureImmersionTrackerStarted();
|
||||||
|
}
|
||||||
mediaRuntime.updateCurrentMediaPath(path);
|
mediaRuntime.updateCurrentMediaPath(path);
|
||||||
},
|
},
|
||||||
restoreMpvSubVisibility: () => {
|
restoreMpvSubVisibility: () => {
|
||||||
@@ -2241,6 +2290,7 @@ const {
|
|||||||
},
|
},
|
||||||
isKnownWord: (text) => Boolean(appState.ankiIntegration?.isKnownWord(text)),
|
isKnownWord: (text) => Boolean(appState.ankiIntegration?.isKnownWord(text)),
|
||||||
recordLookup: (hit) => {
|
recordLookup: (hit) => {
|
||||||
|
ensureImmersionTrackerStarted();
|
||||||
appState.immersionTracker?.recordLookup(hit);
|
appState.immersionTracker?.recordLookup(hit);
|
||||||
},
|
},
|
||||||
getKnownWordMatchMode: () =>
|
getKnownWordMatchMode: () =>
|
||||||
@@ -2662,6 +2712,7 @@ const buildMineSentenceCardMainDepsHandler = createBuildMineSentenceCardMainDeps
|
|||||||
showMpvOsd: (text) => showMpvOsd(text),
|
showMpvOsd: (text) => showMpvOsd(text),
|
||||||
mineSentenceCardCore,
|
mineSentenceCardCore,
|
||||||
recordCardsMined: (count) => {
|
recordCardsMined: (count) => {
|
||||||
|
ensureImmersionTrackerStarted();
|
||||||
appState.immersionTracker?.recordCardsMined(count);
|
appState.immersionTracker?.recordCardsMined(count);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -2697,6 +2748,7 @@ const buildHandleMineSentenceDigitMainDepsHandler =
|
|||||||
logger.error(message, err);
|
logger.error(message, err);
|
||||||
},
|
},
|
||||||
onCardsMined: (cards) => {
|
onCardsMined: (cards) => {
|
||||||
|
ensureImmersionTrackerStarted();
|
||||||
appState.immersionTracker?.recordCardsMined(cards);
|
appState.immersionTracker?.recordCardsMined(cards);
|
||||||
},
|
},
|
||||||
handleMineSentenceDigitCore,
|
handleMineSentenceDigitCore,
|
||||||
@@ -2910,9 +2962,7 @@ const {
|
|||||||
onRuntimeOptionsChanged: () => broadcastRuntimeOptionsChanged(),
|
onRuntimeOptionsChanged: () => broadcastRuntimeOptionsChanged(),
|
||||||
setOverlayDebugVisualizationEnabled: (enabled) => setOverlayDebugVisualizationEnabled(enabled),
|
setOverlayDebugVisualizationEnabled: (enabled) => setOverlayDebugVisualizationEnabled(enabled),
|
||||||
isOverlayVisible: (windowKind) =>
|
isOverlayVisible: (windowKind) =>
|
||||||
windowKind === 'visible'
|
windowKind === 'visible' ? overlayManager.getVisibleOverlayVisible() : false,
|
||||||
? overlayManager.getVisibleOverlayVisible()
|
|
||||||
: false,
|
|
||||||
tryHandleOverlayShortcutLocalFallback: (input) =>
|
tryHandleOverlayShortcutLocalFallback: (input) =>
|
||||||
overlayShortcutsRuntime.tryHandleOverlayShortcutLocalFallback(input),
|
overlayShortcutsRuntime.tryHandleOverlayShortcutLocalFallback(input),
|
||||||
onWindowClosed: (windowKind) => {
|
onWindowClosed: (windowKind) => {
|
||||||
@@ -3013,7 +3063,8 @@ const { initializeOverlayRuntime: initializeOverlayRuntimeHandler } =
|
|||||||
},
|
},
|
||||||
createMainWindow: () => createMainWindow(),
|
createMainWindow: () => createMainWindow(),
|
||||||
registerGlobalShortcuts: () => registerGlobalShortcuts(),
|
registerGlobalShortcuts: () => registerGlobalShortcuts(),
|
||||||
updateVisibleOverlayBounds: (geometry: WindowGeometry) => updateVisibleOverlayBounds(geometry),
|
updateVisibleOverlayBounds: (geometry: WindowGeometry) =>
|
||||||
|
updateVisibleOverlayBounds(geometry),
|
||||||
getOverlayWindows: () => getOverlayWindows(),
|
getOverlayWindows: () => getOverlayWindows(),
|
||||||
getResolvedConfig: () => getResolvedConfig(),
|
getResolvedConfig: () => getResolvedConfig(),
|
||||||
showDesktopNotification,
|
showDesktopNotification,
|
||||||
|
|||||||
@@ -42,11 +42,13 @@ export function composeAppReadyRuntime(options: AppReadyComposerOptions): AppRea
|
|||||||
createBuildAppReadyRuntimeMainDepsHandler({
|
createBuildAppReadyRuntimeMainDepsHandler({
|
||||||
...options.appReadyRuntimeMainDeps,
|
...options.appReadyRuntimeMainDeps,
|
||||||
reloadConfig,
|
reloadConfig,
|
||||||
createImmersionTracker: createImmersionTrackerStartupHandler(
|
createImmersionTracker:
|
||||||
createBuildImmersionTrackerStartupMainDepsHandler(
|
options.appReadyRuntimeMainDeps.createImmersionTracker ??
|
||||||
options.immersionTrackerStartupMainDeps,
|
createImmersionTrackerStartupHandler(
|
||||||
)(),
|
createBuildImmersionTrackerStartupMainDepsHandler(
|
||||||
),
|
options.immersionTrackerStartupMainDeps,
|
||||||
|
)(),
|
||||||
|
),
|
||||||
onCriticalConfigErrors: criticalConfigError,
|
onCriticalConfigErrors: criticalConfigError,
|
||||||
})(),
|
})(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ test('composeMpvRuntimeHandlers returns callable handlers and forwards to inject
|
|||||||
broadcastToOverlayWindows: () => {},
|
broadcastToOverlayWindows: () => {},
|
||||||
onSubtitleChange: () => {},
|
onSubtitleChange: () => {},
|
||||||
refreshDiscordPresence: () => {},
|
refreshDiscordPresence: () => {},
|
||||||
|
ensureImmersionTrackerInitialized: () => {},
|
||||||
updateCurrentMediaPath: () => {},
|
updateCurrentMediaPath: () => {},
|
||||||
restoreMpvSubVisibility: () => {},
|
restoreMpvSubVisibility: () => {},
|
||||||
getCurrentAnilistMediaKey: () => null,
|
getCurrentAnilistMediaKey: () => null,
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ test('mpv main event main deps map app state updates and delegate callbacks', as
|
|||||||
broadcastToOverlayWindows: (channel, payload) =>
|
broadcastToOverlayWindows: (channel, payload) =>
|
||||||
calls.push(`broadcast:${channel}:${String(payload)}`),
|
calls.push(`broadcast:${channel}:${String(payload)}`),
|
||||||
onSubtitleChange: (text) => calls.push(`subtitle-change:${text}`),
|
onSubtitleChange: (text) => calls.push(`subtitle-change:${text}`),
|
||||||
|
ensureImmersionTrackerInitialized: () => calls.push('ensure-immersion'),
|
||||||
updateCurrentMediaPath: (path) => calls.push(`path:${path}`),
|
updateCurrentMediaPath: (path) => calls.push(`path:${path}`),
|
||||||
restoreMpvSubVisibility: () => calls.push('restore-mpv-sub'),
|
restoreMpvSubVisibility: () => calls.push('restore-mpv-sub'),
|
||||||
getCurrentAnilistMediaKey: () => 'media-key',
|
getCurrentAnilistMediaKey: () => 'media-key',
|
||||||
@@ -97,6 +98,7 @@ test('mpv main event main deps map app state updates and delegate callbacks', as
|
|||||||
assert.ok(calls.includes('remote-stopped'));
|
assert.ok(calls.includes('remote-stopped'));
|
||||||
assert.ok(calls.includes('sync-overlay-mpv-sub'));
|
assert.ok(calls.includes('sync-overlay-mpv-sub'));
|
||||||
assert.ok(calls.includes('anilist-post-watch'));
|
assert.ok(calls.includes('anilist-post-watch'));
|
||||||
|
assert.ok(calls.includes('ensure-immersion'));
|
||||||
assert.ok(calls.includes('sync-immersion'));
|
assert.ok(calls.includes('sync-immersion'));
|
||||||
assert.ok(calls.includes('metrics'));
|
assert.ok(calls.includes('metrics'));
|
||||||
assert.ok(calls.includes('presence-refresh'));
|
assert.ok(calls.includes('presence-refresh'));
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: {
|
|||||||
reportJellyfinRemoteProgress: (forceImmediate: boolean) => void;
|
reportJellyfinRemoteProgress: (forceImmediate: boolean) => void;
|
||||||
updateSubtitleRenderMetrics: (patch: Record<string, unknown>) => void;
|
updateSubtitleRenderMetrics: (patch: Record<string, unknown>) => void;
|
||||||
refreshDiscordPresence: () => void;
|
refreshDiscordPresence: () => void;
|
||||||
|
ensureImmersionTrackerInitialized: () => void;
|
||||||
}) {
|
}) {
|
||||||
return () => ({
|
return () => ({
|
||||||
reportJellyfinRemoteStopped: () => deps.reportJellyfinRemoteStopped(),
|
reportJellyfinRemoteStopped: () => deps.reportJellyfinRemoteStopped(),
|
||||||
@@ -48,8 +49,10 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: {
|
|||||||
scheduleQuitCheck: (callback: () => void) => deps.scheduleQuitCheck(callback),
|
scheduleQuitCheck: (callback: () => void) => deps.scheduleQuitCheck(callback),
|
||||||
isMpvConnected: () => Boolean(deps.appState.mpvClient?.connected),
|
isMpvConnected: () => Boolean(deps.appState.mpvClient?.connected),
|
||||||
quitApp: () => deps.quitApp(),
|
quitApp: () => deps.quitApp(),
|
||||||
recordImmersionSubtitleLine: (text: string, start: number, end: number) =>
|
recordImmersionSubtitleLine: (text: string, start: number, end: number) => {
|
||||||
deps.appState.immersionTracker?.recordSubtitleLine?.(text, start, end),
|
deps.ensureImmersionTrackerInitialized();
|
||||||
|
deps.appState.immersionTracker?.recordSubtitleLine?.(text, start, end);
|
||||||
|
},
|
||||||
hasSubtitleTimingTracker: () => Boolean(deps.appState.subtitleTimingTracker),
|
hasSubtitleTimingTracker: () => Boolean(deps.appState.subtitleTimingTracker),
|
||||||
recordSubtitleTiming: (text: string, start: number, end: number) =>
|
recordSubtitleTiming: (text: string, start: number, end: number) =>
|
||||||
deps.appState.subtitleTimingTracker?.recordSubtitle?.(text, start, end),
|
deps.appState.subtitleTimingTracker?.recordSubtitle?.(text, start, end),
|
||||||
@@ -71,8 +74,7 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: {
|
|||||||
broadcastSecondarySubtitle: (text: string) =>
|
broadcastSecondarySubtitle: (text: string) =>
|
||||||
deps.broadcastToOverlayWindows('secondary-subtitle:set', text),
|
deps.broadcastToOverlayWindows('secondary-subtitle:set', text),
|
||||||
updateCurrentMediaPath: (path: string) => deps.updateCurrentMediaPath(path),
|
updateCurrentMediaPath: (path: string) => deps.updateCurrentMediaPath(path),
|
||||||
restoreMpvSubVisibility: () =>
|
restoreMpvSubVisibility: () => deps.restoreMpvSubVisibility(),
|
||||||
deps.restoreMpvSubVisibility(),
|
|
||||||
getCurrentAnilistMediaKey: () => deps.getCurrentAnilistMediaKey(),
|
getCurrentAnilistMediaKey: () => deps.getCurrentAnilistMediaKey(),
|
||||||
resetAnilistMediaTracking: (mediaKey: string | null) =>
|
resetAnilistMediaTracking: (mediaKey: string | null) =>
|
||||||
deps.resetAnilistMediaTracking(mediaKey),
|
deps.resetAnilistMediaTracking(mediaKey),
|
||||||
@@ -81,14 +83,19 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: {
|
|||||||
syncImmersionMediaState: () => deps.syncImmersionMediaState(),
|
syncImmersionMediaState: () => deps.syncImmersionMediaState(),
|
||||||
updateCurrentMediaTitle: (title: string) => deps.updateCurrentMediaTitle(title),
|
updateCurrentMediaTitle: (title: string) => deps.updateCurrentMediaTitle(title),
|
||||||
resetAnilistMediaGuessState: () => deps.resetAnilistMediaGuessState(),
|
resetAnilistMediaGuessState: () => deps.resetAnilistMediaGuessState(),
|
||||||
notifyImmersionTitleUpdate: (title: string) =>
|
notifyImmersionTitleUpdate: (title: string) => {
|
||||||
deps.appState.immersionTracker?.handleMediaTitleUpdate?.(title),
|
deps.ensureImmersionTrackerInitialized();
|
||||||
recordPlaybackPosition: (time: number) =>
|
deps.appState.immersionTracker?.handleMediaTitleUpdate?.(title);
|
||||||
deps.appState.immersionTracker?.recordPlaybackPosition?.(time),
|
},
|
||||||
|
recordPlaybackPosition: (time: number) => {
|
||||||
|
deps.ensureImmersionTrackerInitialized();
|
||||||
|
deps.appState.immersionTracker?.recordPlaybackPosition?.(time);
|
||||||
|
},
|
||||||
reportJellyfinRemoteProgress: (forceImmediate: boolean) =>
|
reportJellyfinRemoteProgress: (forceImmediate: boolean) =>
|
||||||
deps.reportJellyfinRemoteProgress(forceImmediate),
|
deps.reportJellyfinRemoteProgress(forceImmediate),
|
||||||
recordPauseState: (paused: boolean) => {
|
recordPauseState: (paused: boolean) => {
|
||||||
deps.appState.playbackPaused = paused;
|
deps.appState.playbackPaused = paused;
|
||||||
|
deps.ensureImmersionTrackerInitialized();
|
||||||
deps.appState.immersionTracker?.recordPauseState?.(paused);
|
deps.appState.immersionTracker?.recordPauseState?.(paused);
|
||||||
},
|
},
|
||||||
updateSubtitleRenderMetrics: (patch: Record<string, unknown>) =>
|
updateSubtitleRenderMetrics: (patch: Record<string, unknown>) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user