mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
refactor: normalize remaining main runtime dependency setup
This commit is contained in:
@@ -390,3 +390,20 @@
|
|||||||
- [2026-02-20T08:56:46Z] progress: extracted MPV IPC command dependency assembly into `src/main/runtime/ipc-mpv-command-main-deps.ts` and rewired `main.ts` IPC bridge setup to compose through `buildMpvCommandFromIpcRuntimeMainDepsHandler`.
|
- [2026-02-20T08:56:46Z] progress: extracted MPV IPC command dependency assembly into `src/main/runtime/ipc-mpv-command-main-deps.ts` and rewired `main.ts` IPC bridge setup to compose through `buildMpvCommandFromIpcRuntimeMainDepsHandler`.
|
||||||
- [2026-02-20T08:56:46Z] progress: added `src/main/runtime/ipc-mpv-command-main-deps.test.ts` mapping coverage.
|
- [2026-02-20T08:56:46Z] progress: added `src/main/runtime/ipc-mpv-command-main-deps.test.ts` mapping coverage.
|
||||||
- [2026-02-20T08:56:46Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + `node --test dist/main/runtime/ipc-mpv-command-main-deps.test.js dist/main/runtime/ipc-bridge-actions-main-deps.test.js dist/main/runtime/ipc-bridge-actions.test.js` pass.
|
- [2026-02-20T08:56:46Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + `node --test dist/main/runtime/ipc-mpv-command-main-deps.test.js dist/main/runtime/ipc-bridge-actions-main-deps.test.js dist/main/runtime/ipc-bridge-actions.test.js` pass.
|
||||||
|
- [2026-02-20T09:00:14Z] progress: post-push slice extracted `playJellyfinItemInMpv` dependency assembly into `src/main/runtime/jellyfin-playback-launch-main-deps.ts` and rewired `main.ts` playback handler construction.
|
||||||
|
- [2026-02-20T09:00:14Z] progress: added `src/main/runtime/jellyfin-playback-launch-main-deps.test.ts` mapping coverage.
|
||||||
|
- [2026-02-20T09:00:14Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + `node --test dist/main/runtime/jellyfin-playback-launch-main-deps.test.js dist/main/runtime/jellyfin-playback-launch.test.js` pass.
|
||||||
|
- [2026-02-20T09:10:53Z] progress: extracted config hot-reload message/watcher dependency assembly into builders in `config-hot-reload-main-deps.ts` (`createBuildConfigHotReloadMessageMainDepsHandler`, `createBuildWatchConfigPathMainDepsHandler`) and rewired `main.ts`.
|
||||||
|
- [2026-02-20T09:10:53Z] progress: extracted MPV subtitle render metrics dependency assembly into `mpv-subtitle-render-metrics-main-deps.ts` and rewired `main.ts` update runtime setup.
|
||||||
|
- [2026-02-20T09:10:53Z] progress: added mapping tests `config-hot-reload-main-deps.test.ts` (new cases) and `mpv-subtitle-render-metrics-main-deps.test.ts`.
|
||||||
|
- [2026-02-20T09:10:53Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + `node --test dist/main/runtime/config-hot-reload-main-deps.test.js dist/main/runtime/mpv-subtitle-render-metrics-main-deps.test.js dist/main/runtime/mpv-subtitle-render-metrics.test.js dist/main/runtime/config-hot-reload-handlers.test.js` pass.
|
||||||
|
- [2026-02-20T09:14:06Z] progress: extracted numeric shortcut runtime option assembly into `src/main/runtime/numeric-shortcut-runtime-main-deps.ts` and rewired `createNumericShortcutRuntime` setup in `main.ts`.
|
||||||
|
- [2026-02-20T09:14:06Z] progress: added `src/main/runtime/numeric-shortcut-runtime-main-deps.test.ts` mapping coverage.
|
||||||
|
- [2026-02-20T09:14:06Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + `node --test dist/main/runtime/numeric-shortcut-runtime-main-deps.test.js dist/core/services/numeric-shortcut-session.test.js` pass.
|
||||||
|
- [2026-02-20T09:16:42Z] progress: extracted immersion tracker startup dependency assembly into `src/main/runtime/immersion-startup-main-deps.ts` and rewired app-ready startup wiring in `main.ts`.
|
||||||
|
- [2026-02-20T09:16:42Z] progress: extracted config hot-reload watcher/message and MPV subtitle metrics dependency assembly into dedicated builder usage in `main.ts`; added `mpv-subtitle-render-metrics-main-deps.ts`.
|
||||||
|
- [2026-02-20T09:16:42Z] progress: normalized `handleInitialArgs` setup to prebuilt builder-backed handler (`buildHandleInitialArgsMainDepsHandler` + `handleInitialArgsRuntimeHandler`) to reduce repeated construction.
|
||||||
|
- [2026-02-20T09:16:42Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + targeted suites pass: `immersion-startup*`, `config-hot-reload-main-deps*`, `mpv-subtitle-render-metrics*`, `numeric-shortcut-runtime-main-deps*`, `initial-args*`.
|
||||||
|
- [2026-02-20T09:30:02Z] progress: applied 5-block safe normalization in `main.ts` by prebuilding deps handlers for global shortcuts (`getConfiguredShortcuts`, `registerGlobalShortcuts`, `refreshGlobalAndOverlayShortcuts`) and MPV logging/OSD (`appendToMpvLog`, `showMpvOsd`).
|
||||||
|
- [2026-02-20T09:30:02Z] progress: earlier in this batch also extracted `jellyfin-playback-launch-main-deps`, `immersion-startup-main-deps`, `numeric-shortcut-runtime-main-deps`, and `mpv-subtitle-render-metrics-main-deps`; extended `config-hot-reload-main-deps` with watcher/message builders.
|
||||||
|
- [2026-02-20T09:30:02Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + targeted suites pass for `global-shortcuts*`, `mpv-osd-log*`, `jellyfin-playback-launch*`, `immersion-startup*`, `config-hot-reload-main-deps*`, `mpv-subtitle-render-metrics*`, `numeric-shortcut-runtime-main-deps*`, `initial-args*`.
|
||||||
|
|||||||
166
src/main.ts
166
src/main.ts
@@ -74,6 +74,7 @@ import {
|
|||||||
} from './main/runtime/startup-config';
|
} from './main/runtime/startup-config';
|
||||||
import { buildConfigWarningNotificationBody } from './main/config-validation';
|
import { buildConfigWarningNotificationBody } from './main/config-validation';
|
||||||
import { createImmersionTrackerStartupHandler } from './main/runtime/immersion-startup';
|
import { createImmersionTrackerStartupHandler } from './main/runtime/immersion-startup';
|
||||||
|
import { createBuildImmersionTrackerStartupMainDepsHandler } from './main/runtime/immersion-startup-main-deps';
|
||||||
import { createImmersionMediaRuntime } from './main/runtime/immersion-media';
|
import { createImmersionMediaRuntime } from './main/runtime/immersion-media';
|
||||||
import { createAnilistStateRuntime } from './main/runtime/anilist-state';
|
import { createAnilistStateRuntime } from './main/runtime/anilist-state';
|
||||||
import { createConfigDerivedRuntime } from './main/runtime/config-derived';
|
import { createConfigDerivedRuntime } from './main/runtime/config-derived';
|
||||||
@@ -230,6 +231,7 @@ import {
|
|||||||
createBuildJlptDictionaryRuntimeMainDepsHandler,
|
createBuildJlptDictionaryRuntimeMainDepsHandler,
|
||||||
} from './main/runtime/dictionary-runtime-main-deps';
|
} from './main/runtime/dictionary-runtime-main-deps';
|
||||||
import { createPlayJellyfinItemInMpvHandler } from './main/runtime/jellyfin-playback-launch';
|
import { createPlayJellyfinItemInMpvHandler } from './main/runtime/jellyfin-playback-launch';
|
||||||
|
import { createBuildPlayJellyfinItemInMpvMainDepsHandler } from './main/runtime/jellyfin-playback-launch-main-deps';
|
||||||
import { createPreloadJellyfinExternalSubtitlesHandler } from './main/runtime/jellyfin-subtitle-preload';
|
import { createPreloadJellyfinExternalSubtitlesHandler } from './main/runtime/jellyfin-subtitle-preload';
|
||||||
import { createBuildPreloadJellyfinExternalSubtitlesMainDepsHandler } from './main/runtime/jellyfin-subtitle-preload-main-deps';
|
import { createBuildPreloadJellyfinExternalSubtitlesMainDepsHandler } from './main/runtime/jellyfin-subtitle-preload-main-deps';
|
||||||
import {
|
import {
|
||||||
@@ -259,6 +261,7 @@ import { createBuildBindMpvMainEventHandlersMainDepsHandler } from './main/runti
|
|||||||
import { createBuildMpvClientRuntimeServiceFactoryDepsHandler } from './main/runtime/mpv-client-runtime-service-main-deps';
|
import { createBuildMpvClientRuntimeServiceFactoryDepsHandler } from './main/runtime/mpv-client-runtime-service-main-deps';
|
||||||
import { createMpvClientRuntimeServiceFactory } from './main/runtime/mpv-client-runtime-service';
|
import { createMpvClientRuntimeServiceFactory } from './main/runtime/mpv-client-runtime-service';
|
||||||
import { createUpdateMpvSubtitleRenderMetricsHandler } from './main/runtime/mpv-subtitle-render-metrics';
|
import { createUpdateMpvSubtitleRenderMetricsHandler } from './main/runtime/mpv-subtitle-render-metrics';
|
||||||
|
import { createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler } from './main/runtime/mpv-subtitle-render-metrics-main-deps';
|
||||||
import {
|
import {
|
||||||
createBuildTokenizerDepsMainHandler,
|
createBuildTokenizerDepsMainHandler,
|
||||||
createCreateMecabTokenizerAndCheckMainHandler,
|
createCreateMecabTokenizerAndCheckMainHandler,
|
||||||
@@ -312,6 +315,7 @@ import {
|
|||||||
createBuildCancelNumericShortcutSessionMainDepsHandler,
|
createBuildCancelNumericShortcutSessionMainDepsHandler,
|
||||||
createBuildStartNumericShortcutSessionMainDepsHandler,
|
createBuildStartNumericShortcutSessionMainDepsHandler,
|
||||||
} from './main/runtime/numeric-shortcut-session-main-deps';
|
} from './main/runtime/numeric-shortcut-session-main-deps';
|
||||||
|
import { createBuildNumericShortcutRuntimeMainDepsHandler } from './main/runtime/numeric-shortcut-runtime-main-deps';
|
||||||
import {
|
import {
|
||||||
createRefreshOverlayShortcutsHandler,
|
createRefreshOverlayShortcutsHandler,
|
||||||
createRegisterOverlayShortcutsHandler,
|
createRegisterOverlayShortcutsHandler,
|
||||||
@@ -453,8 +457,10 @@ import {
|
|||||||
resolveSubtitleStyleForRenderer,
|
resolveSubtitleStyleForRenderer,
|
||||||
} from './main/runtime/config-hot-reload-handlers';
|
} from './main/runtime/config-hot-reload-handlers';
|
||||||
import {
|
import {
|
||||||
|
createBuildConfigHotReloadMessageMainDepsHandler,
|
||||||
createBuildConfigHotReloadAppliedMainDepsHandler,
|
createBuildConfigHotReloadAppliedMainDepsHandler,
|
||||||
createBuildConfigHotReloadRuntimeMainDepsHandler,
|
createBuildConfigHotReloadRuntimeMainDepsHandler,
|
||||||
|
createBuildWatchConfigPathMainDepsHandler,
|
||||||
createWatchConfigPathHandler,
|
createWatchConfigPathHandler,
|
||||||
} from './main/runtime/config-hot-reload-main-deps';
|
} from './main/runtime/config-hot-reload-main-deps';
|
||||||
import {
|
import {
|
||||||
@@ -849,15 +855,19 @@ const overlayShortcutsRuntime = createOverlayShortcutsRuntimeService(
|
|||||||
})(),
|
})(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const notifyConfigHotReloadMessage = createConfigHotReloadMessageHandler({
|
const buildConfigHotReloadMessageMainDepsHandler = createBuildConfigHotReloadMessageMainDepsHandler({
|
||||||
showMpvOsd: (message) => showMpvOsd(message),
|
showMpvOsd: (message) => showMpvOsd(message),
|
||||||
showDesktopNotification: (title, options) => showDesktopNotification(title, options),
|
showDesktopNotification: (title, options) => showDesktopNotification(title, options),
|
||||||
});
|
});
|
||||||
const watchConfigPathHandler = createWatchConfigPathHandler({
|
const notifyConfigHotReloadMessage = createConfigHotReloadMessageHandler(
|
||||||
|
buildConfigHotReloadMessageMainDepsHandler(),
|
||||||
|
);
|
||||||
|
const buildWatchConfigPathMainDepsHandler = createBuildWatchConfigPathMainDepsHandler({
|
||||||
fileExists: (targetPath) => fs.existsSync(targetPath),
|
fileExists: (targetPath) => fs.existsSync(targetPath),
|
||||||
dirname: (targetPath) => path.dirname(targetPath),
|
dirname: (targetPath) => path.dirname(targetPath),
|
||||||
watchPath: (targetPath, listener) => fs.watch(targetPath, listener),
|
watchPath: (targetPath, listener) => fs.watch(targetPath, listener),
|
||||||
});
|
});
|
||||||
|
const watchConfigPathHandler = createWatchConfigPathHandler(buildWatchConfigPathMainDepsHandler());
|
||||||
const buildConfigHotReloadAppliedMainDepsHandler = createBuildConfigHotReloadAppliedMainDepsHandler({
|
const buildConfigHotReloadAppliedMainDepsHandler = createBuildConfigHotReloadAppliedMainDepsHandler({
|
||||||
setKeybindings: (keybindings) => {
|
setKeybindings: (keybindings) => {
|
||||||
appState.keybindings = keybindings as never;
|
appState.keybindings = keybindings as never;
|
||||||
@@ -1305,7 +1315,7 @@ const preloadJellyfinExternalSubtitles = createPreloadJellyfinExternalSubtitlesH
|
|||||||
buildPreloadJellyfinExternalSubtitlesMainDepsHandler(),
|
buildPreloadJellyfinExternalSubtitlesMainDepsHandler(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const playJellyfinItemInMpv = createPlayJellyfinItemInMpvHandler({
|
const buildPlayJellyfinItemInMpvMainDepsHandler = createBuildPlayJellyfinItemInMpvMainDepsHandler({
|
||||||
ensureMpvConnectedForPlayback: () => ensureMpvConnectedForJellyfinPlayback(),
|
ensureMpvConnectedForPlayback: () => ensureMpvConnectedForJellyfinPlayback(),
|
||||||
getMpvClient: () => appState.mpvClient,
|
getMpvClient: () => appState.mpvClient,
|
||||||
resolvePlaybackPlan: (params) =>
|
resolvePlaybackPlan: (params) =>
|
||||||
@@ -1348,6 +1358,9 @@ const playJellyfinItemInMpv = createPlayJellyfinItemInMpvHandler({
|
|||||||
showMpvOsd(text);
|
showMpvOsd(text);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const playJellyfinItemInMpv = createPlayJellyfinItemInMpvHandler(
|
||||||
|
buildPlayJellyfinItemInMpvMainDepsHandler(),
|
||||||
|
);
|
||||||
|
|
||||||
const buildHandleJellyfinAuthCommandsMainDepsHandler =
|
const buildHandleJellyfinAuthCommandsMainDepsHandler =
|
||||||
createBuildHandleJellyfinAuthCommandsMainDepsHandler({
|
createBuildHandleJellyfinAuthCommandsMainDepsHandler({
|
||||||
@@ -1985,8 +1998,7 @@ const criticalConfigErrorHandler = createCriticalConfigErrorHandler(
|
|||||||
})(),
|
})(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const appReadyRuntimeRunner = createAppReadyRuntimeRunner(
|
const buildAppReadyRuntimeMainDepsHandler = createBuildAppReadyRuntimeMainDepsHandler({
|
||||||
createBuildAppReadyRuntimeMainDepsHandler({
|
|
||||||
loadSubtitlePosition: () => loadSubtitlePosition(),
|
loadSubtitlePosition: () => loadSubtitlePosition(),
|
||||||
resolveKeybindings: () => {
|
resolveKeybindings: () => {
|
||||||
appState.keybindings = resolveKeybindings(getResolvedConfig(), DEFAULT_KEYBINDINGS);
|
appState.keybindings = resolveKeybindings(getResolvedConfig(), DEFAULT_KEYBINDINGS);
|
||||||
@@ -2032,21 +2044,23 @@ const appReadyRuntimeRunner = createAppReadyRuntimeRunner(
|
|||||||
const tracker = new SubtitleTimingTracker();
|
const tracker = new SubtitleTimingTracker();
|
||||||
appState.subtitleTimingTracker = tracker;
|
appState.subtitleTimingTracker = tracker;
|
||||||
},
|
},
|
||||||
createImmersionTracker: createImmersionTrackerStartupHandler({
|
createImmersionTracker: createImmersionTrackerStartupHandler(
|
||||||
getResolvedConfig: () => getResolvedConfig(),
|
createBuildImmersionTrackerStartupMainDepsHandler({
|
||||||
getConfiguredDbPath: () => immersionMediaRuntime.getConfiguredDbPath(),
|
getResolvedConfig: () => getResolvedConfig(),
|
||||||
createTrackerService: (params) => new ImmersionTrackerService(params),
|
getConfiguredDbPath: () => immersionMediaRuntime.getConfiguredDbPath(),
|
||||||
setTracker: (tracker) => {
|
createTrackerService: (params) => new ImmersionTrackerService(params),
|
||||||
appState.immersionTracker = tracker as ImmersionTrackerService | null;
|
setTracker: (tracker) => {
|
||||||
},
|
appState.immersionTracker = tracker as ImmersionTrackerService | null;
|
||||||
getMpvClient: () => appState.mpvClient,
|
},
|
||||||
seedTrackerFromCurrentMedia: () => {
|
getMpvClient: () => appState.mpvClient,
|
||||||
void immersionMediaRuntime.seedFromCurrentMedia();
|
seedTrackerFromCurrentMedia: () => {
|
||||||
},
|
void immersionMediaRuntime.seedFromCurrentMedia();
|
||||||
logInfo: (message) => logger.info(message),
|
},
|
||||||
logDebug: (message) => logger.debug(message),
|
logInfo: (message) => logger.info(message),
|
||||||
logWarn: (message, details) => logger.warn(message, details),
|
logDebug: (message) => logger.debug(message),
|
||||||
}),
|
logWarn: (message, details) => logger.warn(message, details),
|
||||||
|
})(),
|
||||||
|
),
|
||||||
loadYomitanExtension: async () => {
|
loadYomitanExtension: async () => {
|
||||||
await loadYomitanExtension();
|
await loadYomitanExtension();
|
||||||
},
|
},
|
||||||
@@ -2071,10 +2085,10 @@ const appReadyRuntimeRunner = createAppReadyRuntimeRunner(
|
|||||||
logger.debug(message);
|
logger.debug(message);
|
||||||
},
|
},
|
||||||
now: () => Date.now(),
|
now: () => Date.now(),
|
||||||
})(),
|
});
|
||||||
);
|
const appReadyRuntimeRunner = createAppReadyRuntimeRunner(buildAppReadyRuntimeMainDepsHandler());
|
||||||
|
|
||||||
const appLifecycleRuntimeRunner = createAppLifecycleRuntimeRunner(
|
const buildAppLifecycleRuntimeRunnerMainDepsHandler =
|
||||||
createBuildAppLifecycleRuntimeRunnerMainDepsHandler({
|
createBuildAppLifecycleRuntimeRunnerMainDepsHandler({
|
||||||
app,
|
app,
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
@@ -2089,12 +2103,12 @@ const appLifecycleRuntimeRunner = createAppLifecycleRuntimeRunner(
|
|||||||
shouldRestoreWindowsOnActivate: () => shouldRestoreWindowsOnActivateHandler(),
|
shouldRestoreWindowsOnActivate: () => shouldRestoreWindowsOnActivateHandler(),
|
||||||
restoreWindowsOnActivate: () => restoreWindowsOnActivateHandler(),
|
restoreWindowsOnActivate: () => restoreWindowsOnActivateHandler(),
|
||||||
shouldQuitOnWindowAllClosed: () => !appState.backgroundMode,
|
shouldQuitOnWindowAllClosed: () => !appState.backgroundMode,
|
||||||
})(),
|
});
|
||||||
|
const appLifecycleRuntimeRunner = createAppLifecycleRuntimeRunner(
|
||||||
|
buildAppLifecycleRuntimeRunnerMainDepsHandler(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const buildStartupBootstrapRuntimeFactoryDepsHandler =
|
const buildStartupBootstrapMainDepsHandler = createBuildStartupBootstrapMainDepsHandler({
|
||||||
createBuildStartupBootstrapRuntimeFactoryDepsHandler(
|
|
||||||
createBuildStartupBootstrapMainDepsHandler({
|
|
||||||
argv: process.argv,
|
argv: process.argv,
|
||||||
parseArgs: (argv: string[]) => parseArgs(argv),
|
parseArgs: (argv: string[]) => parseArgs(argv),
|
||||||
setLogLevel: (level: string, source: LogLevelSource) => {
|
setLogLevel: (level: string, source: LogLevelSource) => {
|
||||||
@@ -2126,8 +2140,9 @@ const buildStartupBootstrapRuntimeFactoryDepsHandler =
|
|||||||
quitApp: () => app.quit(),
|
quitApp: () => app.quit(),
|
||||||
logGenerateConfigError: (message) => logger.error(message),
|
logGenerateConfigError: (message) => logger.error(message),
|
||||||
startAppLifecycle: appLifecycleRuntimeRunner,
|
startAppLifecycle: appLifecycleRuntimeRunner,
|
||||||
})(),
|
});
|
||||||
);
|
const buildStartupBootstrapRuntimeFactoryDepsHandler =
|
||||||
|
createBuildStartupBootstrapRuntimeFactoryDepsHandler(buildStartupBootstrapMainDepsHandler());
|
||||||
|
|
||||||
const startupState = runStartupBootstrapRuntime(
|
const startupState = runStartupBootstrapRuntime(
|
||||||
createStartupBootstrapRuntimeDeps(buildStartupBootstrapRuntimeFactoryDepsHandler()),
|
createStartupBootstrapRuntimeDeps(buildStartupBootstrapRuntimeFactoryDepsHandler()),
|
||||||
@@ -2156,19 +2171,22 @@ function handleCliCommand(args: CliArgs, source: CliCommandSource = 'initial'):
|
|||||||
handleCliCommandRuntimeServiceWithContext(args, source, cliContext);
|
handleCliCommandRuntimeServiceWithContext(args, source, cliContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buildHandleInitialArgsMainDepsHandler = createBuildHandleInitialArgsMainDepsHandler({
|
||||||
|
getInitialArgs: () => appState.initialArgs,
|
||||||
|
isBackgroundMode: () => appState.backgroundMode,
|
||||||
|
ensureTray: () => ensureTray(),
|
||||||
|
isTexthookerOnlyMode: () => appState.texthookerOnlyMode,
|
||||||
|
hasImmersionTracker: () => Boolean(appState.immersionTracker),
|
||||||
|
getMpvClient: () => appState.mpvClient,
|
||||||
|
logInfo: (message) => logger.info(message),
|
||||||
|
handleCliCommand: (args, source) => handleCliCommand(args, source),
|
||||||
|
});
|
||||||
|
const handleInitialArgsRuntimeHandler = createHandleInitialArgsHandler(
|
||||||
|
buildHandleInitialArgsMainDepsHandler(),
|
||||||
|
);
|
||||||
|
|
||||||
function handleInitialArgs(): void {
|
function handleInitialArgs(): void {
|
||||||
createHandleInitialArgsHandler(
|
handleInitialArgsRuntimeHandler();
|
||||||
createBuildHandleInitialArgsMainDepsHandler({
|
|
||||||
getInitialArgs: () => appState.initialArgs,
|
|
||||||
isBackgroundMode: () => appState.backgroundMode,
|
|
||||||
ensureTray: () => ensureTray(),
|
|
||||||
isTexthookerOnlyMode: () => appState.texthookerOnlyMode,
|
|
||||||
hasImmersionTracker: () => Boolean(appState.immersionTracker),
|
|
||||||
getMpvClient: () => appState.mpvClient,
|
|
||||||
logInfo: (message) => logger.info(message),
|
|
||||||
handleCliCommand: (args, source) => handleCliCommand(args, source),
|
|
||||||
})(),
|
|
||||||
)();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bindMpvClientEventHandlers = createBindMpvMainEventHandlersHandler(
|
const bindMpvClientEventHandlers = createBindMpvMainEventHandlersHandler(
|
||||||
@@ -2241,7 +2259,8 @@ function createMpvClientRuntimeService(): MpvIpcClient {
|
|||||||
)();
|
)();
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateMpvSubtitleRenderMetricsRuntime = createUpdateMpvSubtitleRenderMetricsHandler({
|
const buildUpdateMpvSubtitleRenderMetricsMainDepsHandler =
|
||||||
|
createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler({
|
||||||
getCurrentMetrics: () => appState.mpvSubtitleRenderMetrics,
|
getCurrentMetrics: () => appState.mpvSubtitleRenderMetrics,
|
||||||
setCurrentMetrics: (metrics) => {
|
setCurrentMetrics: (metrics) => {
|
||||||
appState.mpvSubtitleRenderMetrics = metrics;
|
appState.mpvSubtitleRenderMetrics = metrics;
|
||||||
@@ -2251,6 +2270,9 @@ const updateMpvSubtitleRenderMetricsRuntime = createUpdateMpvSubtitleRenderMetri
|
|||||||
broadcastToOverlayWindows('mpv-subtitle-render-metrics:set', metrics);
|
broadcastToOverlayWindows('mpv-subtitle-render-metrics:set', metrics);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const updateMpvSubtitleRenderMetricsRuntime = createUpdateMpvSubtitleRenderMetricsHandler(
|
||||||
|
buildUpdateMpvSubtitleRenderMetricsMainDepsHandler(),
|
||||||
|
);
|
||||||
|
|
||||||
function updateMpvSubtitleRenderMetrics(patch: Partial<MpvSubtitleRenderMetrics>): void {
|
function updateMpvSubtitleRenderMetrics(patch: Partial<MpvSubtitleRenderMetrics>): void {
|
||||||
updateMpvSubtitleRenderMetricsRuntime(patch);
|
updateMpvSubtitleRenderMetricsRuntime(patch);
|
||||||
@@ -2430,16 +2452,19 @@ function openYomitanSettings(): void {
|
|||||||
openYomitanSettingsHandler();
|
openYomitanSettingsHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
const getConfiguredShortcutsHandler = createGetConfiguredShortcutsHandler({
|
const buildGetConfiguredShortcutsMainDepsHandler = createBuildGetConfiguredShortcutsMainDepsHandler(
|
||||||
...createBuildGetConfiguredShortcutsMainDepsHandler({
|
{
|
||||||
getResolvedConfig: () => getResolvedConfig(),
|
getResolvedConfig: () => getResolvedConfig(),
|
||||||
defaultConfig: DEFAULT_CONFIG,
|
defaultConfig: DEFAULT_CONFIG,
|
||||||
resolveConfiguredShortcuts,
|
resolveConfiguredShortcuts,
|
||||||
})(),
|
},
|
||||||
|
);
|
||||||
|
const getConfiguredShortcutsHandler = createGetConfiguredShortcutsHandler({
|
||||||
|
...buildGetConfiguredShortcutsMainDepsHandler(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const registerGlobalShortcutsHandler = createRegisterGlobalShortcutsHandler({
|
const buildRegisterGlobalShortcutsMainDepsHandler =
|
||||||
...createBuildRegisterGlobalShortcutsMainDepsHandler({
|
createBuildRegisterGlobalShortcutsMainDepsHandler({
|
||||||
getConfiguredShortcuts: () => getConfiguredShortcuts(),
|
getConfiguredShortcuts: () => getConfiguredShortcuts(),
|
||||||
registerGlobalShortcutsCore,
|
registerGlobalShortcutsCore,
|
||||||
toggleVisibleOverlay: () => toggleVisibleOverlay(),
|
toggleVisibleOverlay: () => toggleVisibleOverlay(),
|
||||||
@@ -2447,15 +2472,19 @@ const registerGlobalShortcutsHandler = createRegisterGlobalShortcutsHandler({
|
|||||||
openYomitanSettings: () => openYomitanSettings(),
|
openYomitanSettings: () => openYomitanSettings(),
|
||||||
isDev,
|
isDev,
|
||||||
getMainWindow: () => overlayManager.getMainWindow(),
|
getMainWindow: () => overlayManager.getMainWindow(),
|
||||||
})(),
|
});
|
||||||
|
const registerGlobalShortcutsHandler = createRegisterGlobalShortcutsHandler({
|
||||||
|
...buildRegisterGlobalShortcutsMainDepsHandler(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const refreshGlobalAndOverlayShortcutsHandler = createRefreshGlobalAndOverlayShortcutsHandler({
|
const buildRefreshGlobalAndOverlayShortcutsMainDepsHandler =
|
||||||
...createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler({
|
createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler({
|
||||||
unregisterAllGlobalShortcuts: () => globalShortcut.unregisterAll(),
|
unregisterAllGlobalShortcuts: () => globalShortcut.unregisterAll(),
|
||||||
registerGlobalShortcuts: () => registerGlobalShortcuts(),
|
registerGlobalShortcuts: () => registerGlobalShortcuts(),
|
||||||
syncOverlayShortcuts: () => syncOverlayShortcuts(),
|
syncOverlayShortcuts: () => syncOverlayShortcuts(),
|
||||||
})(),
|
});
|
||||||
|
const refreshGlobalAndOverlayShortcutsHandler = createRefreshGlobalAndOverlayShortcutsHandler({
|
||||||
|
...buildRefreshGlobalAndOverlayShortcutsMainDepsHandler(),
|
||||||
});
|
});
|
||||||
|
|
||||||
function registerGlobalShortcuts(): void {
|
function registerGlobalShortcuts(): void {
|
||||||
@@ -2489,24 +2518,26 @@ function cycleSecondarySubMode(): void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buildAppendToMpvLogMainDepsHandler = createBuildAppendToMpvLogMainDepsHandler({
|
||||||
|
logPath: DEFAULT_MPV_LOG_PATH,
|
||||||
|
dirname: (targetPath) => path.dirname(targetPath),
|
||||||
|
mkdirSync: (targetPath, options) => fs.mkdirSync(targetPath, options),
|
||||||
|
appendFileSync: (targetPath, data, options) => fs.appendFileSync(targetPath, data, options),
|
||||||
|
now: () => new Date(),
|
||||||
|
});
|
||||||
const appendToMpvLogHandler = createAppendToMpvLogHandler({
|
const appendToMpvLogHandler = createAppendToMpvLogHandler({
|
||||||
...createBuildAppendToMpvLogMainDepsHandler({
|
...buildAppendToMpvLogMainDepsHandler(),
|
||||||
logPath: DEFAULT_MPV_LOG_PATH,
|
|
||||||
dirname: (targetPath) => path.dirname(targetPath),
|
|
||||||
mkdirSync: (targetPath, options) => fs.mkdirSync(targetPath, options),
|
|
||||||
appendFileSync: (targetPath, data, options) => fs.appendFileSync(targetPath, data, options),
|
|
||||||
now: () => new Date(),
|
|
||||||
})(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const buildShowMpvOsdMainDepsHandler = createBuildShowMpvOsdMainDepsHandler({
|
||||||
|
appendToMpvLog: (message) => appendToMpvLog(message),
|
||||||
|
showMpvOsdRuntime: (mpvClient, text, fallbackLog) =>
|
||||||
|
showMpvOsdRuntime(mpvClient as never, text, fallbackLog),
|
||||||
|
getMpvClient: () => appState.mpvClient,
|
||||||
|
logInfo: (line) => logger.info(line),
|
||||||
|
});
|
||||||
const showMpvOsdHandler = createShowMpvOsdHandler({
|
const showMpvOsdHandler = createShowMpvOsdHandler({
|
||||||
...createBuildShowMpvOsdMainDepsHandler({
|
...buildShowMpvOsdMainDepsHandler(),
|
||||||
appendToMpvLog: (message) => appendToMpvLog(message),
|
|
||||||
showMpvOsdRuntime: (mpvClient, text, fallbackLog) =>
|
|
||||||
showMpvOsdRuntime(mpvClient as never, text, fallbackLog),
|
|
||||||
getMpvClient: () => appState.mpvClient,
|
|
||||||
logInfo: (line) => logger.info(line),
|
|
||||||
})(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function showMpvOsd(text: string): void {
|
function showMpvOsd(text: string): void {
|
||||||
@@ -2517,12 +2548,15 @@ function appendToMpvLog(message: string): void {
|
|||||||
appendToMpvLogHandler(message);
|
appendToMpvLogHandler(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
const numericShortcutRuntime = createNumericShortcutRuntime({
|
const buildNumericShortcutRuntimeMainDepsHandler = createBuildNumericShortcutRuntimeMainDepsHandler({
|
||||||
globalShortcut,
|
globalShortcut,
|
||||||
showMpvOsd: (text) => showMpvOsd(text),
|
showMpvOsd: (text) => showMpvOsd(text),
|
||||||
setTimer: (handler, timeoutMs) => setTimeout(handler, timeoutMs),
|
setTimer: (handler, timeoutMs) => setTimeout(handler, timeoutMs),
|
||||||
clearTimer: (timer) => clearTimeout(timer),
|
clearTimer: (timer) => clearTimeout(timer),
|
||||||
});
|
});
|
||||||
|
const numericShortcutRuntime = createNumericShortcutRuntime(
|
||||||
|
buildNumericShortcutRuntimeMainDepsHandler(),
|
||||||
|
);
|
||||||
const multiCopySession = numericShortcutRuntime.createSession();
|
const multiCopySession = numericShortcutRuntime.createSession();
|
||||||
const mineSentenceSession = numericShortcutRuntime.createSession();
|
const mineSentenceSession = numericShortcutRuntime.createSession();
|
||||||
const buildCancelPendingMultiCopyMainDepsHandler =
|
const buildCancelPendingMultiCopyMainDepsHandler =
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import test from 'node:test';
|
|||||||
import type { ReloadConfigStrictResult } from '../../config';
|
import type { ReloadConfigStrictResult } from '../../config';
|
||||||
import type { ResolvedConfig } from '../../types';
|
import type { ResolvedConfig } from '../../types';
|
||||||
import {
|
import {
|
||||||
|
createBuildConfigHotReloadMessageMainDepsHandler,
|
||||||
createBuildConfigHotReloadAppliedMainDepsHandler,
|
createBuildConfigHotReloadAppliedMainDepsHandler,
|
||||||
createBuildConfigHotReloadRuntimeMainDepsHandler,
|
createBuildConfigHotReloadRuntimeMainDepsHandler,
|
||||||
|
createBuildWatchConfigPathMainDepsHandler,
|
||||||
createWatchConfigPathHandler,
|
createWatchConfigPathHandler,
|
||||||
} from './config-hot-reload-main-deps';
|
} from './config-hot-reload-main-deps';
|
||||||
|
|
||||||
@@ -43,6 +45,45 @@ test('watch config path handler filters directory events to config files only',
|
|||||||
assert.deepEqual(calls, ['change', 'change', 'change']);
|
assert.deepEqual(calls, ['change', 'change', 'change']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('watch config path main deps builder maps filesystem callbacks', () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
const deps = createBuildWatchConfigPathMainDepsHandler({
|
||||||
|
fileExists: () => true,
|
||||||
|
dirname: (targetPath) => {
|
||||||
|
calls.push(`dirname:${targetPath}`);
|
||||||
|
return '/tmp';
|
||||||
|
},
|
||||||
|
watchPath: (targetPath, listener) => {
|
||||||
|
calls.push(`watch:${targetPath}`);
|
||||||
|
listener('change', 'config.jsonc');
|
||||||
|
return { close: () => calls.push('close') };
|
||||||
|
},
|
||||||
|
})();
|
||||||
|
|
||||||
|
assert.equal(deps.fileExists('/tmp/config.jsonc'), true);
|
||||||
|
assert.equal(deps.dirname('/tmp/config.jsonc'), '/tmp');
|
||||||
|
const watcher = deps.watchPath('/tmp/config.jsonc', () => calls.push('listener'));
|
||||||
|
watcher.close();
|
||||||
|
assert.deepEqual(calls, [
|
||||||
|
'dirname:/tmp/config.jsonc',
|
||||||
|
'watch:/tmp/config.jsonc',
|
||||||
|
'listener',
|
||||||
|
'close',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('config hot reload message main deps builder maps notifications', () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
const deps = createBuildConfigHotReloadMessageMainDepsHandler({
|
||||||
|
showMpvOsd: (message) => calls.push(`osd:${message}`),
|
||||||
|
showDesktopNotification: (title) => calls.push(`notify:${title}`),
|
||||||
|
})();
|
||||||
|
|
||||||
|
deps.showMpvOsd('updated');
|
||||||
|
deps.showDesktopNotification('SubMiner', { body: 'updated' });
|
||||||
|
assert.deepEqual(calls, ['osd:updated', 'notify:SubMiner']);
|
||||||
|
});
|
||||||
|
|
||||||
test('config hot reload applied main deps builder maps callbacks', () => {
|
test('config hot reload applied main deps builder maps callbacks', () => {
|
||||||
const calls: string[] = [];
|
const calls: string[] = [];
|
||||||
const deps = createBuildConfigHotReloadAppliedMainDepsHandler({
|
const deps = createBuildConfigHotReloadAppliedMainDepsHandler({
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type {
|
|||||||
} from '../../core/services/config-hot-reload';
|
} from '../../core/services/config-hot-reload';
|
||||||
import type { ReloadConfigStrictResult } from '../../config';
|
import type { ReloadConfigStrictResult } from '../../config';
|
||||||
import type { ConfigHotReloadPayload, ConfigValidationWarning, ResolvedConfig, SecondarySubMode } from '../../types';
|
import type { ConfigHotReloadPayload, ConfigValidationWarning, ResolvedConfig, SecondarySubMode } from '../../types';
|
||||||
|
import type { createConfigHotReloadMessageHandler } from './config-hot-reload-handlers';
|
||||||
|
|
||||||
type ConfigWatchListener = (eventType: string, filename: string | null) => void;
|
type ConfigWatchListener = (eventType: string, filename: string | null) => void;
|
||||||
|
|
||||||
@@ -32,6 +33,28 @@ export function createWatchConfigPathHandler(deps: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WatchConfigPathMainDeps = Parameters<typeof createWatchConfigPathHandler>[0];
|
||||||
|
type ConfigHotReloadMessageMainDeps = Parameters<typeof createConfigHotReloadMessageHandler>[0];
|
||||||
|
|
||||||
|
export function createBuildWatchConfigPathMainDepsHandler(deps: WatchConfigPathMainDeps) {
|
||||||
|
return (): WatchConfigPathMainDeps => ({
|
||||||
|
fileExists: (targetPath: string) => deps.fileExists(targetPath),
|
||||||
|
dirname: (targetPath: string) => deps.dirname(targetPath),
|
||||||
|
watchPath: (targetPath: string, listener: ConfigWatchListener) =>
|
||||||
|
deps.watchPath(targetPath, listener),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createBuildConfigHotReloadMessageMainDepsHandler(
|
||||||
|
deps: ConfigHotReloadMessageMainDeps,
|
||||||
|
) {
|
||||||
|
return (): ConfigHotReloadMessageMainDeps => ({
|
||||||
|
showMpvOsd: (message: string) => deps.showMpvOsd(message),
|
||||||
|
showDesktopNotification: (title: string, options: { body: string }) =>
|
||||||
|
deps.showDesktopNotification(title, options),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function createBuildConfigHotReloadAppliedMainDepsHandler(deps: {
|
export function createBuildConfigHotReloadAppliedMainDepsHandler(deps: {
|
||||||
setKeybindings: (keybindings: ConfigHotReloadPayload['keybindings']) => void;
|
setKeybindings: (keybindings: ConfigHotReloadPayload['keybindings']) => void;
|
||||||
refreshGlobalAndOverlayShortcuts: () => void;
|
refreshGlobalAndOverlayShortcuts: () => void;
|
||||||
|
|||||||
35
src/main/runtime/immersion-startup-main-deps.test.ts
Normal file
35
src/main/runtime/immersion-startup-main-deps.test.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
import { createBuildImmersionTrackerStartupMainDepsHandler } from './immersion-startup-main-deps';
|
||||||
|
|
||||||
|
test('immersion tracker startup main deps builder maps callbacks', () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
const deps = createBuildImmersionTrackerStartupMainDepsHandler({
|
||||||
|
getResolvedConfig: () => ({ immersionTracking: { enabled: true } } as never),
|
||||||
|
getConfiguredDbPath: () => '/tmp/immersion.db',
|
||||||
|
createTrackerService: () => {
|
||||||
|
calls.push('create');
|
||||||
|
return { id: 'tracker' };
|
||||||
|
},
|
||||||
|
setTracker: () => calls.push('set'),
|
||||||
|
getMpvClient: () => ({ connected: true, connect: () => {} }),
|
||||||
|
seedTrackerFromCurrentMedia: () => calls.push('seed'),
|
||||||
|
logInfo: (message) => calls.push(`info:${message}`),
|
||||||
|
logDebug: (message) => calls.push(`debug:${message}`),
|
||||||
|
logWarn: (message) => calls.push(`warn:${message}`),
|
||||||
|
})();
|
||||||
|
|
||||||
|
assert.deepEqual(deps.getResolvedConfig(), { immersionTracking: { enabled: true } });
|
||||||
|
assert.equal(deps.getConfiguredDbPath(), '/tmp/immersion.db');
|
||||||
|
assert.deepEqual(deps.createTrackerService({ dbPath: '/tmp/immersion.db', policy: {} as never }), {
|
||||||
|
id: 'tracker',
|
||||||
|
});
|
||||||
|
deps.setTracker(null);
|
||||||
|
assert.equal(deps.getMpvClient()?.connected, true);
|
||||||
|
deps.seedTrackerFromCurrentMedia();
|
||||||
|
deps.logInfo('i');
|
||||||
|
deps.logDebug('d');
|
||||||
|
deps.logWarn('w', null);
|
||||||
|
|
||||||
|
assert.deepEqual(calls, ['create', 'set', 'seed', 'info:i', 'debug:d', 'warn:w']);
|
||||||
|
});
|
||||||
22
src/main/runtime/immersion-startup-main-deps.ts
Normal file
22
src/main/runtime/immersion-startup-main-deps.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import type {
|
||||||
|
ImmersionTrackerStartupDeps,
|
||||||
|
createImmersionTrackerStartupHandler,
|
||||||
|
} from './immersion-startup';
|
||||||
|
|
||||||
|
type ImmersionTrackerStartupMainDeps = Parameters<typeof createImmersionTrackerStartupHandler>[0];
|
||||||
|
|
||||||
|
export function createBuildImmersionTrackerStartupMainDepsHandler(
|
||||||
|
deps: ImmersionTrackerStartupMainDeps,
|
||||||
|
) {
|
||||||
|
return (): ImmersionTrackerStartupDeps => ({
|
||||||
|
getResolvedConfig: () => deps.getResolvedConfig(),
|
||||||
|
getConfiguredDbPath: () => deps.getConfiguredDbPath(),
|
||||||
|
createTrackerService: (params) => deps.createTrackerService(params),
|
||||||
|
setTracker: (tracker) => deps.setTracker(tracker),
|
||||||
|
getMpvClient: () => deps.getMpvClient(),
|
||||||
|
seedTrackerFromCurrentMedia: () => deps.seedTrackerFromCurrentMedia(),
|
||||||
|
logInfo: (message: string) => deps.logInfo(message),
|
||||||
|
logDebug: (message: string) => deps.logDebug(message),
|
||||||
|
logWarn: (message: string, details: unknown) => deps.logWarn(message, details),
|
||||||
|
});
|
||||||
|
}
|
||||||
56
src/main/runtime/jellyfin-playback-launch-main-deps.test.ts
Normal file
56
src/main/runtime/jellyfin-playback-launch-main-deps.test.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
import { createBuildPlayJellyfinItemInMpvMainDepsHandler } from './jellyfin-playback-launch-main-deps';
|
||||||
|
|
||||||
|
test('play jellyfin item in mpv main deps builder maps callbacks', async () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
const deps = createBuildPlayJellyfinItemInMpvMainDepsHandler({
|
||||||
|
ensureMpvConnectedForPlayback: async () => true,
|
||||||
|
getMpvClient: () => ({ connected: true }),
|
||||||
|
resolvePlaybackPlan: async () => ({
|
||||||
|
url: 'u',
|
||||||
|
mode: 'direct',
|
||||||
|
title: 't',
|
||||||
|
startTimeTicks: 0,
|
||||||
|
}),
|
||||||
|
applyJellyfinMpvDefaults: () => calls.push('defaults'),
|
||||||
|
sendMpvCommand: (command) => calls.push(`cmd:${command[0]}`),
|
||||||
|
armQuitOnDisconnect: () => calls.push('arm'),
|
||||||
|
schedule: (_callback, delayMs) => calls.push(`schedule:${delayMs}`),
|
||||||
|
convertTicksToSeconds: (ticks) => ticks / 10_000_000,
|
||||||
|
preloadExternalSubtitles: () => calls.push('preload'),
|
||||||
|
setActivePlayback: () => calls.push('active'),
|
||||||
|
setLastProgressAtMs: () => calls.push('progress'),
|
||||||
|
reportPlaying: () => calls.push('report'),
|
||||||
|
showMpvOsd: (text) => calls.push(`osd:${text}`),
|
||||||
|
})();
|
||||||
|
|
||||||
|
assert.equal(await deps.ensureMpvConnectedForPlayback(), true);
|
||||||
|
assert.equal(typeof deps.getMpvClient(), 'object');
|
||||||
|
assert.deepEqual(
|
||||||
|
await deps.resolvePlaybackPlan({ session: {} as never, clientInfo: {} as never, jellyfinConfig: {}, itemId: 'i' }),
|
||||||
|
{ url: 'u', mode: 'direct', title: 't', startTimeTicks: 0 },
|
||||||
|
);
|
||||||
|
deps.applyJellyfinMpvDefaults({});
|
||||||
|
deps.sendMpvCommand(['show-text', 'x']);
|
||||||
|
deps.armQuitOnDisconnect();
|
||||||
|
deps.schedule(() => {}, 500);
|
||||||
|
assert.equal(deps.convertTicksToSeconds(20_000_000), 2);
|
||||||
|
deps.preloadExternalSubtitles({ session: {} as never, clientInfo: {} as never, itemId: 'i' });
|
||||||
|
deps.setActivePlayback({ itemId: 'i', mediaSourceId: undefined, playMethod: 'DirectPlay' });
|
||||||
|
deps.setLastProgressAtMs(0);
|
||||||
|
deps.reportPlaying({ itemId: 'i', mediaSourceId: undefined, playMethod: 'DirectPlay', eventName: 'start' });
|
||||||
|
deps.showMpvOsd('ok');
|
||||||
|
|
||||||
|
assert.deepEqual(calls, [
|
||||||
|
'defaults',
|
||||||
|
'cmd:show-text',
|
||||||
|
'arm',
|
||||||
|
'schedule:500',
|
||||||
|
'preload',
|
||||||
|
'active',
|
||||||
|
'progress',
|
||||||
|
'report',
|
||||||
|
'osd:ok',
|
||||||
|
]);
|
||||||
|
});
|
||||||
21
src/main/runtime/jellyfin-playback-launch-main-deps.ts
Normal file
21
src/main/runtime/jellyfin-playback-launch-main-deps.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { createPlayJellyfinItemInMpvHandler } from './jellyfin-playback-launch';
|
||||||
|
|
||||||
|
type PlayJellyfinItemInMpvMainDeps = Parameters<typeof createPlayJellyfinItemInMpvHandler>[0];
|
||||||
|
|
||||||
|
export function createBuildPlayJellyfinItemInMpvMainDepsHandler(deps: PlayJellyfinItemInMpvMainDeps) {
|
||||||
|
return (): PlayJellyfinItemInMpvMainDeps => ({
|
||||||
|
ensureMpvConnectedForPlayback: () => deps.ensureMpvConnectedForPlayback(),
|
||||||
|
getMpvClient: () => deps.getMpvClient(),
|
||||||
|
resolvePlaybackPlan: (params) => deps.resolvePlaybackPlan(params),
|
||||||
|
applyJellyfinMpvDefaults: (mpvClient) => deps.applyJellyfinMpvDefaults(mpvClient),
|
||||||
|
sendMpvCommand: (command: Array<string | number>) => deps.sendMpvCommand(command),
|
||||||
|
armQuitOnDisconnect: () => deps.armQuitOnDisconnect(),
|
||||||
|
schedule: (callback: () => void, delayMs: number) => deps.schedule(callback, delayMs),
|
||||||
|
convertTicksToSeconds: (ticks: number) => deps.convertTicksToSeconds(ticks),
|
||||||
|
preloadExternalSubtitles: (params) => deps.preloadExternalSubtitles(params),
|
||||||
|
setActivePlayback: (state) => deps.setActivePlayback(state),
|
||||||
|
setLastProgressAtMs: (value: number) => deps.setLastProgressAtMs(value),
|
||||||
|
reportPlaying: (payload) => deps.reportPlaying(payload),
|
||||||
|
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
import type { MpvSubtitleRenderMetrics } from '../../types';
|
||||||
|
import { createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler } from './mpv-subtitle-render-metrics-main-deps';
|
||||||
|
|
||||||
|
const BASE_METRICS: MpvSubtitleRenderMetrics = {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
test('mpv subtitle render metrics main deps builder maps callbacks', () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
const deps = createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler({
|
||||||
|
getCurrentMetrics: () => BASE_METRICS,
|
||||||
|
setCurrentMetrics: () => calls.push('set'),
|
||||||
|
applyPatch: (current, patch) => {
|
||||||
|
calls.push('apply');
|
||||||
|
return { next: { ...current, ...patch }, changed: true };
|
||||||
|
},
|
||||||
|
broadcastMetrics: () => calls.push('broadcast'),
|
||||||
|
})();
|
||||||
|
|
||||||
|
assert.equal(deps.getCurrentMetrics().subPos, 100);
|
||||||
|
deps.setCurrentMetrics(BASE_METRICS);
|
||||||
|
const patched = deps.applyPatch(BASE_METRICS, { subPos: 90 });
|
||||||
|
deps.broadcastMetrics(BASE_METRICS);
|
||||||
|
|
||||||
|
assert.equal(patched.changed, true);
|
||||||
|
assert.equal(patched.next.subPos, 90);
|
||||||
|
assert.deepEqual(calls, ['set', 'apply', 'broadcast']);
|
||||||
|
});
|
||||||
14
src/main/runtime/mpv-subtitle-render-metrics-main-deps.ts
Normal file
14
src/main/runtime/mpv-subtitle-render-metrics-main-deps.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import type { createUpdateMpvSubtitleRenderMetricsHandler } from './mpv-subtitle-render-metrics';
|
||||||
|
|
||||||
|
type UpdateMpvSubtitleRenderMetricsMainDeps = Parameters<typeof createUpdateMpvSubtitleRenderMetricsHandler>[0];
|
||||||
|
|
||||||
|
export function createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler(
|
||||||
|
deps: UpdateMpvSubtitleRenderMetricsMainDeps,
|
||||||
|
) {
|
||||||
|
return (): UpdateMpvSubtitleRenderMetricsMainDeps => ({
|
||||||
|
getCurrentMetrics: () => deps.getCurrentMetrics(),
|
||||||
|
setCurrentMetrics: (metrics) => deps.setCurrentMetrics(metrics),
|
||||||
|
applyPatch: (current, patch) => deps.applyPatch(current, patch),
|
||||||
|
broadcastMetrics: (metrics) => deps.broadcastMetrics(metrics),
|
||||||
|
});
|
||||||
|
}
|
||||||
32
src/main/runtime/numeric-shortcut-runtime-main-deps.test.ts
Normal file
32
src/main/runtime/numeric-shortcut-runtime-main-deps.test.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
import { createBuildNumericShortcutRuntimeMainDepsHandler } from './numeric-shortcut-runtime-main-deps';
|
||||||
|
|
||||||
|
test('numeric shortcut runtime main deps builder maps callbacks', () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
const deps = createBuildNumericShortcutRuntimeMainDepsHandler({
|
||||||
|
globalShortcut: {
|
||||||
|
register: () => true,
|
||||||
|
unregister: () => {
|
||||||
|
calls.push('unregister');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
showMpvOsd: (text) => calls.push(`osd:${text}`),
|
||||||
|
setTimer: (handler) => {
|
||||||
|
calls.push('timer');
|
||||||
|
handler();
|
||||||
|
return 1 as never;
|
||||||
|
},
|
||||||
|
clearTimer: () => {
|
||||||
|
calls.push('clear');
|
||||||
|
},
|
||||||
|
})();
|
||||||
|
|
||||||
|
assert.equal(deps.globalShortcut.register('1', () => {}), true);
|
||||||
|
deps.globalShortcut.unregister('1');
|
||||||
|
deps.showMpvOsd('x');
|
||||||
|
deps.setTimer(() => calls.push('tick'), 1000);
|
||||||
|
deps.clearTimer(1 as never);
|
||||||
|
|
||||||
|
assert.deepEqual(calls, ['unregister', 'osd:x', 'timer', 'tick', 'clear']);
|
||||||
|
});
|
||||||
10
src/main/runtime/numeric-shortcut-runtime-main-deps.ts
Normal file
10
src/main/runtime/numeric-shortcut-runtime-main-deps.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import type { NumericShortcutRuntimeOptions } from '../../core/services/numeric-shortcut';
|
||||||
|
|
||||||
|
export function createBuildNumericShortcutRuntimeMainDepsHandler(deps: NumericShortcutRuntimeOptions) {
|
||||||
|
return (): NumericShortcutRuntimeOptions => ({
|
||||||
|
globalShortcut: deps.globalShortcut,
|
||||||
|
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||||
|
setTimer: (handler: () => void, timeoutMs: number) => deps.setTimer(handler, timeoutMs),
|
||||||
|
clearTimer: (timer: ReturnType<typeof setTimeout>) => deps.clearTimer(timer),
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user