mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-28 06:22:45 -08:00
refactor: extract startup bootstrap runtime orchestration
This commit is contained in:
105
src/core/services/startup-bootstrap-runtime-service.test.ts
Normal file
105
src/core/services/startup-bootstrap-runtime-service.test.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
runStartupBootstrapRuntimeService,
|
||||
} from "./startup-bootstrap-runtime-service";
|
||||
import { CliArgs } from "../../cli/args";
|
||||
|
||||
function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
|
||||
return {
|
||||
start: false,
|
||||
stop: false,
|
||||
toggle: false,
|
||||
toggleVisibleOverlay: false,
|
||||
toggleInvisibleOverlay: false,
|
||||
settings: false,
|
||||
show: false,
|
||||
hide: false,
|
||||
showVisibleOverlay: false,
|
||||
hideVisibleOverlay: false,
|
||||
showInvisibleOverlay: false,
|
||||
hideInvisibleOverlay: false,
|
||||
copySubtitle: false,
|
||||
copySubtitleMultiple: false,
|
||||
mineSentence: false,
|
||||
mineSentenceMultiple: false,
|
||||
updateLastCardFromClipboard: false,
|
||||
toggleSecondarySub: false,
|
||||
triggerFieldGrouping: false,
|
||||
triggerSubsync: false,
|
||||
markAudioCard: false,
|
||||
openRuntimeOptions: false,
|
||||
texthooker: false,
|
||||
help: false,
|
||||
autoStartOverlay: false,
|
||||
generateConfig: false,
|
||||
backupOverwrite: false,
|
||||
verbose: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
test("runStartupBootstrapRuntimeService configures startup state and starts lifecycle", () => {
|
||||
const calls: string[] = [];
|
||||
const args = makeArgs({
|
||||
verbose: true,
|
||||
socketPath: "/tmp/custom.sock",
|
||||
texthookerPort: 9001,
|
||||
backend: "x11",
|
||||
autoStartOverlay: true,
|
||||
texthooker: true,
|
||||
});
|
||||
|
||||
const result = runStartupBootstrapRuntimeService({
|
||||
argv: ["node", "main.ts", "--verbose"],
|
||||
parseArgs: () => args,
|
||||
setLogLevelEnv: (level) => calls.push(`setLog:${level}`),
|
||||
enableVerboseLogging: () => calls.push("enableVerbose"),
|
||||
forceX11Backend: () => calls.push("forceX11"),
|
||||
enforceUnsupportedWaylandMode: () => calls.push("enforceWayland"),
|
||||
getDefaultSocketPath: () => "/tmp/default.sock",
|
||||
defaultTexthookerPort: 5174,
|
||||
runGenerateConfigFlow: () => false,
|
||||
startAppLifecycle: () => calls.push("startLifecycle"),
|
||||
});
|
||||
|
||||
assert.equal(result.initialArgs, args);
|
||||
assert.equal(result.mpvSocketPath, "/tmp/custom.sock");
|
||||
assert.equal(result.texthookerPort, 9001);
|
||||
assert.equal(result.backendOverride, "x11");
|
||||
assert.equal(result.autoStartOverlay, true);
|
||||
assert.equal(result.texthookerOnlyMode, true);
|
||||
assert.deepEqual(calls, [
|
||||
"enableVerbose",
|
||||
"forceX11",
|
||||
"enforceWayland",
|
||||
"startLifecycle",
|
||||
]);
|
||||
});
|
||||
|
||||
test("runStartupBootstrapRuntimeService skips lifecycle when generate-config flow handled", () => {
|
||||
const calls: string[] = [];
|
||||
const args = makeArgs({ generateConfig: true, logLevel: "warn" });
|
||||
|
||||
const result = runStartupBootstrapRuntimeService({
|
||||
argv: ["node", "main.ts", "--generate-config"],
|
||||
parseArgs: () => args,
|
||||
setLogLevelEnv: (level) => calls.push(`setLog:${level}`),
|
||||
enableVerboseLogging: () => calls.push("enableVerbose"),
|
||||
forceX11Backend: () => calls.push("forceX11"),
|
||||
enforceUnsupportedWaylandMode: () => calls.push("enforceWayland"),
|
||||
getDefaultSocketPath: () => "/tmp/default.sock",
|
||||
defaultTexthookerPort: 5174,
|
||||
runGenerateConfigFlow: () => true,
|
||||
startAppLifecycle: () => calls.push("startLifecycle"),
|
||||
});
|
||||
|
||||
assert.equal(result.mpvSocketPath, "/tmp/default.sock");
|
||||
assert.equal(result.texthookerPort, 5174);
|
||||
assert.equal(result.backendOverride, null);
|
||||
assert.deepEqual(calls, [
|
||||
"setLog:warn",
|
||||
"forceX11",
|
||||
"enforceWayland",
|
||||
]);
|
||||
});
|
||||
53
src/core/services/startup-bootstrap-runtime-service.ts
Normal file
53
src/core/services/startup-bootstrap-runtime-service.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { CliArgs } from "../../cli/args";
|
||||
|
||||
export interface StartupBootstrapRuntimeState {
|
||||
initialArgs: CliArgs;
|
||||
mpvSocketPath: string;
|
||||
texthookerPort: number;
|
||||
backendOverride: string | null;
|
||||
autoStartOverlay: boolean;
|
||||
texthookerOnlyMode: boolean;
|
||||
}
|
||||
|
||||
export interface StartupBootstrapRuntimeDeps {
|
||||
argv: string[];
|
||||
parseArgs: (argv: string[]) => CliArgs;
|
||||
setLogLevelEnv: (level: string) => void;
|
||||
enableVerboseLogging: () => void;
|
||||
forceX11Backend: (args: CliArgs) => void;
|
||||
enforceUnsupportedWaylandMode: (args: CliArgs) => void;
|
||||
getDefaultSocketPath: () => string;
|
||||
defaultTexthookerPort: number;
|
||||
runGenerateConfigFlow: (args: CliArgs) => boolean;
|
||||
startAppLifecycle: (args: CliArgs) => void;
|
||||
}
|
||||
|
||||
export function runStartupBootstrapRuntimeService(
|
||||
deps: StartupBootstrapRuntimeDeps,
|
||||
): StartupBootstrapRuntimeState {
|
||||
const initialArgs = deps.parseArgs(deps.argv);
|
||||
|
||||
if (initialArgs.logLevel) {
|
||||
deps.setLogLevelEnv(initialArgs.logLevel);
|
||||
} else if (initialArgs.verbose) {
|
||||
deps.enableVerboseLogging();
|
||||
}
|
||||
|
||||
deps.forceX11Backend(initialArgs);
|
||||
deps.enforceUnsupportedWaylandMode(initialArgs);
|
||||
|
||||
const state: StartupBootstrapRuntimeState = {
|
||||
initialArgs,
|
||||
mpvSocketPath: initialArgs.socketPath ?? deps.getDefaultSocketPath(),
|
||||
texthookerPort: initialArgs.texthookerPort ?? deps.defaultTexthookerPort,
|
||||
backendOverride: initialArgs.backend ?? null,
|
||||
autoStartOverlay: initialArgs.autoStartOverlay,
|
||||
texthookerOnlyMode: initialArgs.texthooker,
|
||||
};
|
||||
|
||||
if (!deps.runGenerateConfigFlow(initialArgs)) {
|
||||
deps.startAppLifecycle(initialArgs);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
426
src/main.ts
426
src/main.ts
@@ -236,6 +236,7 @@ import {
|
||||
createSubtitleTimingTrackerRuntimeService,
|
||||
} from "./core/services/startup-resource-runtime-service";
|
||||
import { runGenerateConfigFlowRuntimeService } from "./core/services/config-generation-runtime-service";
|
||||
import { runStartupBootstrapRuntimeService } from "./core/services/startup-bootstrap-runtime-service";
|
||||
import {
|
||||
runSubsyncManualFromIpcRuntimeService,
|
||||
triggerSubsyncFromConfigRuntimeService,
|
||||
@@ -479,218 +480,227 @@ function updateCurrentMediaPath(mediaPath: unknown): void {
|
||||
|
||||
let subsyncInProgress = false;
|
||||
|
||||
const initialArgs = parseArgs(process.argv);
|
||||
if (initialArgs.logLevel) {
|
||||
process.env.SUBMINER_LOG_LEVEL = initialArgs.logLevel;
|
||||
} else if (initialArgs.verbose) {
|
||||
process.env.SUBMINER_LOG_LEVEL = "debug";
|
||||
}
|
||||
|
||||
forceX11Backend(initialArgs);
|
||||
enforceUnsupportedWaylandMode(initialArgs);
|
||||
|
||||
let mpvSocketPath = initialArgs.socketPath ?? getDefaultSocketPath();
|
||||
let texthookerPort = initialArgs.texthookerPort ?? DEFAULT_TEXTHOOKER_PORT;
|
||||
const backendOverride = initialArgs.backend ?? null;
|
||||
const autoStartOverlay = initialArgs.autoStartOverlay;
|
||||
const texthookerOnlyMode = initialArgs.texthooker;
|
||||
|
||||
if (
|
||||
!runGenerateConfigFlowRuntimeService(initialArgs, {
|
||||
shouldStartApp: (args) => shouldStartApp(args),
|
||||
generateConfig: async (args) =>
|
||||
generateDefaultConfigFile(args, {
|
||||
configDir: CONFIG_DIR,
|
||||
defaultConfig: DEFAULT_CONFIG,
|
||||
generateTemplate: (config) => generateConfigTemplate(config as never),
|
||||
}),
|
||||
onSuccess: (exitCode) => {
|
||||
process.exitCode = exitCode;
|
||||
app.quit();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(`Failed to generate config: ${error.message}`);
|
||||
process.exitCode = 1;
|
||||
app.quit();
|
||||
},
|
||||
})
|
||||
) {
|
||||
startAppLifecycleService(initialArgs, createAppLifecycleDepsRuntimeService({
|
||||
app,
|
||||
platform: process.platform,
|
||||
shouldStartApp: (args) => shouldStartApp(args),
|
||||
parseArgs: (argv) => parseArgs(argv),
|
||||
handleCliCommand: (args, source) => handleCliCommand(args, source),
|
||||
printHelp: () => printHelp(DEFAULT_TEXTHOOKER_PORT),
|
||||
logNoRunningInstance: () => appLogger.logNoRunningInstance(),
|
||||
onReady: async () => {
|
||||
await runAppReadyRuntimeService(
|
||||
createStartupAppReadyDepsRuntimeService({
|
||||
loadSubtitlePosition: () => loadSubtitlePosition(),
|
||||
resolveKeybindings: () => {
|
||||
keybindings = resolveKeybindings(getResolvedConfig(), DEFAULT_KEYBINDINGS);
|
||||
},
|
||||
createMpvClient: () => {
|
||||
mpvClient = new MpvIpcClient(
|
||||
mpvSocketPath,
|
||||
createMpvIpcClientDepsRuntimeService({
|
||||
getResolvedConfig: () => getResolvedConfig(),
|
||||
autoStartOverlay,
|
||||
setOverlayVisible: (visible) => setOverlayVisible(visible),
|
||||
shouldBindVisibleOverlayToMpvSubVisibility: () =>
|
||||
shouldBindVisibleOverlayToMpvSubVisibility(),
|
||||
isVisibleOverlayVisible: () => visibleOverlayVisible,
|
||||
getReconnectTimer: () => reconnectTimer,
|
||||
setReconnectTimer: (timer) => {
|
||||
reconnectTimer = timer;
|
||||
const startupState = runStartupBootstrapRuntimeService({
|
||||
argv: process.argv,
|
||||
parseArgs: (argv) => parseArgs(argv),
|
||||
setLogLevelEnv: (level) => {
|
||||
process.env.SUBMINER_LOG_LEVEL = level;
|
||||
},
|
||||
enableVerboseLogging: () => {
|
||||
process.env.SUBMINER_LOG_LEVEL = "debug";
|
||||
},
|
||||
forceX11Backend: (args) => {
|
||||
forceX11Backend(args);
|
||||
},
|
||||
enforceUnsupportedWaylandMode: (args) => {
|
||||
enforceUnsupportedWaylandMode(args);
|
||||
},
|
||||
getDefaultSocketPath: () => getDefaultSocketPath(),
|
||||
defaultTexthookerPort: DEFAULT_TEXTHOOKER_PORT,
|
||||
runGenerateConfigFlow: (args) =>
|
||||
runGenerateConfigFlowRuntimeService(args, {
|
||||
shouldStartApp: (nextArgs) => shouldStartApp(nextArgs),
|
||||
generateConfig: async (nextArgs) =>
|
||||
generateDefaultConfigFile(nextArgs, {
|
||||
configDir: CONFIG_DIR,
|
||||
defaultConfig: DEFAULT_CONFIG,
|
||||
generateTemplate: (config) => generateConfigTemplate(config as never),
|
||||
}),
|
||||
onSuccess: (exitCode) => {
|
||||
process.exitCode = exitCode;
|
||||
app.quit();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(`Failed to generate config: ${error.message}`);
|
||||
process.exitCode = 1;
|
||||
app.quit();
|
||||
},
|
||||
}),
|
||||
startAppLifecycle: (args) => {
|
||||
startAppLifecycleService(args, createAppLifecycleDepsRuntimeService({
|
||||
app,
|
||||
platform: process.platform,
|
||||
shouldStartApp: (nextArgs) => shouldStartApp(nextArgs),
|
||||
parseArgs: (argv) => parseArgs(argv),
|
||||
handleCliCommand: (nextArgs, source) => handleCliCommand(nextArgs, source),
|
||||
printHelp: () => printHelp(DEFAULT_TEXTHOOKER_PORT),
|
||||
logNoRunningInstance: () => appLogger.logNoRunningInstance(),
|
||||
onReady: async () => {
|
||||
await runAppReadyRuntimeService(
|
||||
createStartupAppReadyDepsRuntimeService({
|
||||
loadSubtitlePosition: () => loadSubtitlePosition(),
|
||||
resolveKeybindings: () => {
|
||||
keybindings = resolveKeybindings(getResolvedConfig(), DEFAULT_KEYBINDINGS);
|
||||
},
|
||||
createMpvClient: () => {
|
||||
mpvClient = new MpvIpcClient(
|
||||
mpvSocketPath,
|
||||
createMpvIpcClientDepsRuntimeService({
|
||||
getResolvedConfig: () => getResolvedConfig(),
|
||||
autoStartOverlay,
|
||||
setOverlayVisible: (visible) => setOverlayVisible(visible),
|
||||
shouldBindVisibleOverlayToMpvSubVisibility: () =>
|
||||
shouldBindVisibleOverlayToMpvSubVisibility(),
|
||||
isVisibleOverlayVisible: () => visibleOverlayVisible,
|
||||
getReconnectTimer: () => reconnectTimer,
|
||||
setReconnectTimer: (timer) => {
|
||||
reconnectTimer = timer;
|
||||
},
|
||||
getCurrentSubText: () => currentSubText,
|
||||
setCurrentSubText: (text) => {
|
||||
currentSubText = text;
|
||||
},
|
||||
setCurrentSubAssText: (text) => {
|
||||
currentSubAssText = text;
|
||||
},
|
||||
getSubtitleTimingTracker: () => subtitleTimingTracker,
|
||||
subtitleWsBroadcast: (text) => {
|
||||
subtitleWsService.broadcast(text);
|
||||
},
|
||||
getOverlayWindowsCount: () => getOverlayWindows().length,
|
||||
tokenizeSubtitle: (text) => tokenizeSubtitle(text),
|
||||
broadcastToOverlayWindows: (channel, ...channelArgs) => {
|
||||
broadcastToOverlayWindows(channel, ...channelArgs);
|
||||
},
|
||||
updateCurrentMediaPath: (mediaPath) => {
|
||||
updateCurrentMediaPath(mediaPath);
|
||||
},
|
||||
updateMpvSubtitleRenderMetrics: (patch) => {
|
||||
updateMpvSubtitleRenderMetrics(patch);
|
||||
},
|
||||
getMpvSubtitleRenderMetrics: () => mpvSubtitleRenderMetrics,
|
||||
setPreviousSecondarySubVisibility: (value) => {
|
||||
previousSecondarySubVisibility = value;
|
||||
},
|
||||
showMpvOsd: (text) => {
|
||||
showMpvOsd(text);
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
reloadConfig: () => {
|
||||
configService.reloadConfig();
|
||||
},
|
||||
getResolvedConfig: () => getResolvedConfig(),
|
||||
getConfigWarnings: () => configService.getWarnings(),
|
||||
logConfigWarning: (warning) => appLogger.logConfigWarning(warning),
|
||||
initRuntimeOptionsManager: () => {
|
||||
runtimeOptionsManager = createRuntimeOptionsManagerRuntimeService({
|
||||
getAnkiConfig: () => configService.getConfig().ankiConnect,
|
||||
applyAnkiPatch: (patch) => {
|
||||
if (ankiIntegration) {
|
||||
ankiIntegration.applyRuntimeConfigPatch(patch);
|
||||
}
|
||||
},
|
||||
getCurrentSubText: () => currentSubText,
|
||||
setCurrentSubText: (text) => {
|
||||
currentSubText = text;
|
||||
onOptionsChanged: () => {
|
||||
broadcastRuntimeOptionsChanged();
|
||||
refreshOverlayShortcuts();
|
||||
},
|
||||
setCurrentSubAssText: (text) => {
|
||||
currentSubAssText = text;
|
||||
},
|
||||
getSubtitleTimingTracker: () => subtitleTimingTracker,
|
||||
subtitleWsBroadcast: (text) => {
|
||||
subtitleWsService.broadcast(text);
|
||||
},
|
||||
getOverlayWindowsCount: () => getOverlayWindows().length,
|
||||
tokenizeSubtitle: (text) => tokenizeSubtitle(text),
|
||||
broadcastToOverlayWindows: (channel, ...args) => {
|
||||
broadcastToOverlayWindows(channel, ...args);
|
||||
},
|
||||
updateCurrentMediaPath: (mediaPath) => {
|
||||
updateCurrentMediaPath(mediaPath);
|
||||
},
|
||||
updateMpvSubtitleRenderMetrics: (patch) => {
|
||||
updateMpvSubtitleRenderMetrics(patch);
|
||||
},
|
||||
getMpvSubtitleRenderMetrics: () => mpvSubtitleRenderMetrics,
|
||||
setPreviousSecondarySubVisibility: (value) => {
|
||||
previousSecondarySubVisibility = value;
|
||||
},
|
||||
showMpvOsd: (text) => {
|
||||
showMpvOsd(text);
|
||||
});
|
||||
},
|
||||
setSecondarySubMode: (mode) => {
|
||||
secondarySubMode = mode;
|
||||
},
|
||||
defaultSecondarySubMode: "hover",
|
||||
defaultWebsocketPort: DEFAULT_CONFIG.websocket.port,
|
||||
hasMpvWebsocketPlugin: () => hasMpvWebsocketPlugin(),
|
||||
startSubtitleWebsocket: (port) => {
|
||||
subtitleWsService.start(port, () => currentSubText);
|
||||
},
|
||||
log: (message) => appLogger.logInfo(message),
|
||||
createMecabTokenizerAndCheck: async () =>
|
||||
createMecabTokenizerAndCheckRuntimeService({
|
||||
createMecabTokenizer: () => new MecabTokenizer(),
|
||||
setMecabTokenizer: (tokenizer) => {
|
||||
mecabTokenizer = tokenizer;
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
reloadConfig: () => {
|
||||
configService.reloadConfig();
|
||||
},
|
||||
getResolvedConfig: () => getResolvedConfig(),
|
||||
getConfigWarnings: () => configService.getWarnings(),
|
||||
logConfigWarning: (warning) => appLogger.logConfigWarning(warning),
|
||||
initRuntimeOptionsManager: () => {
|
||||
runtimeOptionsManager = createRuntimeOptionsManagerRuntimeService({
|
||||
getAnkiConfig: () => configService.getConfig().ankiConnect,
|
||||
applyAnkiPatch: (patch) => {
|
||||
if (ankiIntegration) {
|
||||
ankiIntegration.applyRuntimeConfigPatch(patch);
|
||||
}
|
||||
},
|
||||
onOptionsChanged: () => {
|
||||
broadcastRuntimeOptionsChanged();
|
||||
refreshOverlayShortcuts();
|
||||
},
|
||||
});
|
||||
},
|
||||
setSecondarySubMode: (mode) => {
|
||||
secondarySubMode = mode;
|
||||
},
|
||||
defaultSecondarySubMode: "hover",
|
||||
defaultWebsocketPort: DEFAULT_CONFIG.websocket.port,
|
||||
hasMpvWebsocketPlugin: () => hasMpvWebsocketPlugin(),
|
||||
startSubtitleWebsocket: (port) => {
|
||||
subtitleWsService.start(port, () => currentSubText);
|
||||
},
|
||||
log: (message) => appLogger.logInfo(message),
|
||||
createMecabTokenizerAndCheck: async () =>
|
||||
createMecabTokenizerAndCheckRuntimeService({
|
||||
createMecabTokenizer: () => new MecabTokenizer(),
|
||||
setMecabTokenizer: (tokenizer) => {
|
||||
mecabTokenizer = tokenizer;
|
||||
},
|
||||
}),
|
||||
createSubtitleTimingTracker: () =>
|
||||
createSubtitleTimingTrackerRuntimeService({
|
||||
createSubtitleTimingTracker: () => new SubtitleTimingTracker(),
|
||||
setSubtitleTimingTracker: (tracker) => {
|
||||
subtitleTimingTracker = tracker;
|
||||
},
|
||||
}),
|
||||
loadYomitanExtension: async () => {
|
||||
await loadYomitanExtension();
|
||||
},
|
||||
texthookerOnlyMode,
|
||||
shouldAutoInitializeOverlayRuntimeFromConfig: () =>
|
||||
shouldAutoInitializeOverlayRuntimeFromConfig(),
|
||||
initializeOverlayRuntime: () => initializeOverlayRuntime(),
|
||||
handleInitialArgs: () => handleInitialArgs(),
|
||||
}),
|
||||
);
|
||||
},
|
||||
onWillQuitCleanup: () => {
|
||||
runAppShutdownRuntimeService(
|
||||
createStartupAppShutdownDepsRuntimeService({
|
||||
unregisterAllGlobalShortcuts: () => {
|
||||
globalShortcut.unregisterAll();
|
||||
},
|
||||
stopSubtitleWebsocket: () => {
|
||||
subtitleWsService.stop();
|
||||
},
|
||||
stopTexthookerService: () => {
|
||||
texthookerService.stop();
|
||||
},
|
||||
destroyYomitanParserWindow: () => {
|
||||
if (yomitanParserWindow && !yomitanParserWindow.isDestroyed()) {
|
||||
yomitanParserWindow.destroy();
|
||||
}
|
||||
yomitanParserWindow = null;
|
||||
},
|
||||
clearYomitanParserPromises: () => {
|
||||
yomitanParserReadyPromise = null;
|
||||
yomitanParserInitPromise = null;
|
||||
},
|
||||
stopWindowTracker: () => {
|
||||
if (windowTracker) {
|
||||
windowTracker.stop();
|
||||
}
|
||||
},
|
||||
destroyMpvSocket: () => {
|
||||
if (mpvClient && mpvClient.socket) {
|
||||
mpvClient.socket.destroy();
|
||||
}
|
||||
},
|
||||
clearReconnectTimer: () => {
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
}
|
||||
},
|
||||
destroySubtitleTimingTracker: () => {
|
||||
if (subtitleTimingTracker) {
|
||||
subtitleTimingTracker.destroy();
|
||||
}
|
||||
},
|
||||
destroyAnkiIntegration: () => {
|
||||
if (ankiIntegration) {
|
||||
ankiIntegration.destroy();
|
||||
}
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
shouldRestoreWindowsOnActivate: () =>
|
||||
overlayRuntimeInitialized && BrowserWindow.getAllWindows().length === 0,
|
||||
restoreWindowsOnActivate: () => {
|
||||
createMainWindow();
|
||||
createInvisibleWindow();
|
||||
updateVisibleOverlayVisibility();
|
||||
updateInvisibleOverlayVisibility();
|
||||
},
|
||||
}));
|
||||
}
|
||||
createSubtitleTimingTracker: () =>
|
||||
createSubtitleTimingTrackerRuntimeService({
|
||||
createSubtitleTimingTracker: () => new SubtitleTimingTracker(),
|
||||
setSubtitleTimingTracker: (tracker) => {
|
||||
subtitleTimingTracker = tracker;
|
||||
},
|
||||
}),
|
||||
loadYomitanExtension: async () => {
|
||||
await loadYomitanExtension();
|
||||
},
|
||||
texthookerOnlyMode,
|
||||
shouldAutoInitializeOverlayRuntimeFromConfig: () =>
|
||||
shouldAutoInitializeOverlayRuntimeFromConfig(),
|
||||
initializeOverlayRuntime: () => initializeOverlayRuntime(),
|
||||
handleInitialArgs: () => handleInitialArgs(),
|
||||
}),
|
||||
);
|
||||
},
|
||||
onWillQuitCleanup: () => {
|
||||
runAppShutdownRuntimeService(
|
||||
createStartupAppShutdownDepsRuntimeService({
|
||||
unregisterAllGlobalShortcuts: () => {
|
||||
globalShortcut.unregisterAll();
|
||||
},
|
||||
stopSubtitleWebsocket: () => {
|
||||
subtitleWsService.stop();
|
||||
},
|
||||
stopTexthookerService: () => {
|
||||
texthookerService.stop();
|
||||
},
|
||||
destroyYomitanParserWindow: () => {
|
||||
if (yomitanParserWindow && !yomitanParserWindow.isDestroyed()) {
|
||||
yomitanParserWindow.destroy();
|
||||
}
|
||||
yomitanParserWindow = null;
|
||||
},
|
||||
clearYomitanParserPromises: () => {
|
||||
yomitanParserReadyPromise = null;
|
||||
yomitanParserInitPromise = null;
|
||||
},
|
||||
stopWindowTracker: () => {
|
||||
if (windowTracker) {
|
||||
windowTracker.stop();
|
||||
}
|
||||
},
|
||||
destroyMpvSocket: () => {
|
||||
if (mpvClient && mpvClient.socket) {
|
||||
mpvClient.socket.destroy();
|
||||
}
|
||||
},
|
||||
clearReconnectTimer: () => {
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
}
|
||||
},
|
||||
destroySubtitleTimingTracker: () => {
|
||||
if (subtitleTimingTracker) {
|
||||
subtitleTimingTracker.destroy();
|
||||
}
|
||||
},
|
||||
destroyAnkiIntegration: () => {
|
||||
if (ankiIntegration) {
|
||||
ankiIntegration.destroy();
|
||||
}
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
shouldRestoreWindowsOnActivate: () =>
|
||||
overlayRuntimeInitialized && BrowserWindow.getAllWindows().length === 0,
|
||||
restoreWindowsOnActivate: () => {
|
||||
createMainWindow();
|
||||
createInvisibleWindow();
|
||||
updateVisibleOverlayVisibility();
|
||||
updateInvisibleOverlayVisibility();
|
||||
},
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
const initialArgs = startupState.initialArgs;
|
||||
let mpvSocketPath = startupState.mpvSocketPath;
|
||||
let texthookerPort = startupState.texthookerPort;
|
||||
const backendOverride = startupState.backendOverride;
|
||||
const autoStartOverlay = startupState.autoStartOverlay;
|
||||
const texthookerOnlyMode = startupState.texthookerOnlyMode;
|
||||
|
||||
function handleCliCommand(
|
||||
args: CliArgs,
|
||||
|
||||
Reference in New Issue
Block a user