mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -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,
|
createSubtitleTimingTrackerRuntimeService,
|
||||||
} from "./core/services/startup-resource-runtime-service";
|
} from "./core/services/startup-resource-runtime-service";
|
||||||
import { runGenerateConfigFlowRuntimeService } from "./core/services/config-generation-runtime-service";
|
import { runGenerateConfigFlowRuntimeService } from "./core/services/config-generation-runtime-service";
|
||||||
|
import { runStartupBootstrapRuntimeService } from "./core/services/startup-bootstrap-runtime-service";
|
||||||
import {
|
import {
|
||||||
runSubsyncManualFromIpcRuntimeService,
|
runSubsyncManualFromIpcRuntimeService,
|
||||||
triggerSubsyncFromConfigRuntimeService,
|
triggerSubsyncFromConfigRuntimeService,
|
||||||
@@ -479,218 +480,227 @@ function updateCurrentMediaPath(mediaPath: unknown): void {
|
|||||||
|
|
||||||
let subsyncInProgress = false;
|
let subsyncInProgress = false;
|
||||||
|
|
||||||
const initialArgs = parseArgs(process.argv);
|
const startupState = runStartupBootstrapRuntimeService({
|
||||||
if (initialArgs.logLevel) {
|
argv: process.argv,
|
||||||
process.env.SUBMINER_LOG_LEVEL = initialArgs.logLevel;
|
parseArgs: (argv) => parseArgs(argv),
|
||||||
} else if (initialArgs.verbose) {
|
setLogLevelEnv: (level) => {
|
||||||
process.env.SUBMINER_LOG_LEVEL = "debug";
|
process.env.SUBMINER_LOG_LEVEL = level;
|
||||||
}
|
},
|
||||||
|
enableVerboseLogging: () => {
|
||||||
forceX11Backend(initialArgs);
|
process.env.SUBMINER_LOG_LEVEL = "debug";
|
||||||
enforceUnsupportedWaylandMode(initialArgs);
|
},
|
||||||
|
forceX11Backend: (args) => {
|
||||||
let mpvSocketPath = initialArgs.socketPath ?? getDefaultSocketPath();
|
forceX11Backend(args);
|
||||||
let texthookerPort = initialArgs.texthookerPort ?? DEFAULT_TEXTHOOKER_PORT;
|
},
|
||||||
const backendOverride = initialArgs.backend ?? null;
|
enforceUnsupportedWaylandMode: (args) => {
|
||||||
const autoStartOverlay = initialArgs.autoStartOverlay;
|
enforceUnsupportedWaylandMode(args);
|
||||||
const texthookerOnlyMode = initialArgs.texthooker;
|
},
|
||||||
|
getDefaultSocketPath: () => getDefaultSocketPath(),
|
||||||
if (
|
defaultTexthookerPort: DEFAULT_TEXTHOOKER_PORT,
|
||||||
!runGenerateConfigFlowRuntimeService(initialArgs, {
|
runGenerateConfigFlow: (args) =>
|
||||||
shouldStartApp: (args) => shouldStartApp(args),
|
runGenerateConfigFlowRuntimeService(args, {
|
||||||
generateConfig: async (args) =>
|
shouldStartApp: (nextArgs) => shouldStartApp(nextArgs),
|
||||||
generateDefaultConfigFile(args, {
|
generateConfig: async (nextArgs) =>
|
||||||
configDir: CONFIG_DIR,
|
generateDefaultConfigFile(nextArgs, {
|
||||||
defaultConfig: DEFAULT_CONFIG,
|
configDir: CONFIG_DIR,
|
||||||
generateTemplate: (config) => generateConfigTemplate(config as never),
|
defaultConfig: DEFAULT_CONFIG,
|
||||||
}),
|
generateTemplate: (config) => generateConfigTemplate(config as never),
|
||||||
onSuccess: (exitCode) => {
|
}),
|
||||||
process.exitCode = exitCode;
|
onSuccess: (exitCode) => {
|
||||||
app.quit();
|
process.exitCode = exitCode;
|
||||||
},
|
app.quit();
|
||||||
onError: (error) => {
|
},
|
||||||
console.error(`Failed to generate config: ${error.message}`);
|
onError: (error) => {
|
||||||
process.exitCode = 1;
|
console.error(`Failed to generate config: ${error.message}`);
|
||||||
app.quit();
|
process.exitCode = 1;
|
||||||
},
|
app.quit();
|
||||||
})
|
},
|
||||||
) {
|
}),
|
||||||
startAppLifecycleService(initialArgs, createAppLifecycleDepsRuntimeService({
|
startAppLifecycle: (args) => {
|
||||||
app,
|
startAppLifecycleService(args, createAppLifecycleDepsRuntimeService({
|
||||||
platform: process.platform,
|
app,
|
||||||
shouldStartApp: (args) => shouldStartApp(args),
|
platform: process.platform,
|
||||||
parseArgs: (argv) => parseArgs(argv),
|
shouldStartApp: (nextArgs) => shouldStartApp(nextArgs),
|
||||||
handleCliCommand: (args, source) => handleCliCommand(args, source),
|
parseArgs: (argv) => parseArgs(argv),
|
||||||
printHelp: () => printHelp(DEFAULT_TEXTHOOKER_PORT),
|
handleCliCommand: (nextArgs, source) => handleCliCommand(nextArgs, source),
|
||||||
logNoRunningInstance: () => appLogger.logNoRunningInstance(),
|
printHelp: () => printHelp(DEFAULT_TEXTHOOKER_PORT),
|
||||||
onReady: async () => {
|
logNoRunningInstance: () => appLogger.logNoRunningInstance(),
|
||||||
await runAppReadyRuntimeService(
|
onReady: async () => {
|
||||||
createStartupAppReadyDepsRuntimeService({
|
await runAppReadyRuntimeService(
|
||||||
loadSubtitlePosition: () => loadSubtitlePosition(),
|
createStartupAppReadyDepsRuntimeService({
|
||||||
resolveKeybindings: () => {
|
loadSubtitlePosition: () => loadSubtitlePosition(),
|
||||||
keybindings = resolveKeybindings(getResolvedConfig(), DEFAULT_KEYBINDINGS);
|
resolveKeybindings: () => {
|
||||||
},
|
keybindings = resolveKeybindings(getResolvedConfig(), DEFAULT_KEYBINDINGS);
|
||||||
createMpvClient: () => {
|
},
|
||||||
mpvClient = new MpvIpcClient(
|
createMpvClient: () => {
|
||||||
mpvSocketPath,
|
mpvClient = new MpvIpcClient(
|
||||||
createMpvIpcClientDepsRuntimeService({
|
mpvSocketPath,
|
||||||
getResolvedConfig: () => getResolvedConfig(),
|
createMpvIpcClientDepsRuntimeService({
|
||||||
autoStartOverlay,
|
getResolvedConfig: () => getResolvedConfig(),
|
||||||
setOverlayVisible: (visible) => setOverlayVisible(visible),
|
autoStartOverlay,
|
||||||
shouldBindVisibleOverlayToMpvSubVisibility: () =>
|
setOverlayVisible: (visible) => setOverlayVisible(visible),
|
||||||
shouldBindVisibleOverlayToMpvSubVisibility(),
|
shouldBindVisibleOverlayToMpvSubVisibility: () =>
|
||||||
isVisibleOverlayVisible: () => visibleOverlayVisible,
|
shouldBindVisibleOverlayToMpvSubVisibility(),
|
||||||
getReconnectTimer: () => reconnectTimer,
|
isVisibleOverlayVisible: () => visibleOverlayVisible,
|
||||||
setReconnectTimer: (timer) => {
|
getReconnectTimer: () => reconnectTimer,
|
||||||
reconnectTimer = timer;
|
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,
|
onOptionsChanged: () => {
|
||||||
setCurrentSubText: (text) => {
|
broadcastRuntimeOptionsChanged();
|
||||||
currentSubText = text;
|
refreshOverlayShortcuts();
|
||||||
},
|
},
|
||||||
setCurrentSubAssText: (text) => {
|
});
|
||||||
currentSubAssText = text;
|
},
|
||||||
},
|
setSecondarySubMode: (mode) => {
|
||||||
getSubtitleTimingTracker: () => subtitleTimingTracker,
|
secondarySubMode = mode;
|
||||||
subtitleWsBroadcast: (text) => {
|
},
|
||||||
subtitleWsService.broadcast(text);
|
defaultSecondarySubMode: "hover",
|
||||||
},
|
defaultWebsocketPort: DEFAULT_CONFIG.websocket.port,
|
||||||
getOverlayWindowsCount: () => getOverlayWindows().length,
|
hasMpvWebsocketPlugin: () => hasMpvWebsocketPlugin(),
|
||||||
tokenizeSubtitle: (text) => tokenizeSubtitle(text),
|
startSubtitleWebsocket: (port) => {
|
||||||
broadcastToOverlayWindows: (channel, ...args) => {
|
subtitleWsService.start(port, () => currentSubText);
|
||||||
broadcastToOverlayWindows(channel, ...args);
|
},
|
||||||
},
|
log: (message) => appLogger.logInfo(message),
|
||||||
updateCurrentMediaPath: (mediaPath) => {
|
createMecabTokenizerAndCheck: async () =>
|
||||||
updateCurrentMediaPath(mediaPath);
|
createMecabTokenizerAndCheckRuntimeService({
|
||||||
},
|
createMecabTokenizer: () => new MecabTokenizer(),
|
||||||
updateMpvSubtitleRenderMetrics: (patch) => {
|
setMecabTokenizer: (tokenizer) => {
|
||||||
updateMpvSubtitleRenderMetrics(patch);
|
mecabTokenizer = tokenizer;
|
||||||
},
|
|
||||||
getMpvSubtitleRenderMetrics: () => mpvSubtitleRenderMetrics,
|
|
||||||
setPreviousSecondarySubVisibility: (value) => {
|
|
||||||
previousSecondarySubVisibility = value;
|
|
||||||
},
|
|
||||||
showMpvOsd: (text) => {
|
|
||||||
showMpvOsd(text);
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
createSubtitleTimingTracker: () =>
|
||||||
},
|
createSubtitleTimingTrackerRuntimeService({
|
||||||
reloadConfig: () => {
|
createSubtitleTimingTracker: () => new SubtitleTimingTracker(),
|
||||||
configService.reloadConfig();
|
setSubtitleTimingTracker: (tracker) => {
|
||||||
},
|
subtitleTimingTracker = tracker;
|
||||||
getResolvedConfig: () => getResolvedConfig(),
|
},
|
||||||
getConfigWarnings: () => configService.getWarnings(),
|
}),
|
||||||
logConfigWarning: (warning) => appLogger.logConfigWarning(warning),
|
loadYomitanExtension: async () => {
|
||||||
initRuntimeOptionsManager: () => {
|
await loadYomitanExtension();
|
||||||
runtimeOptionsManager = createRuntimeOptionsManagerRuntimeService({
|
},
|
||||||
getAnkiConfig: () => configService.getConfig().ankiConnect,
|
texthookerOnlyMode,
|
||||||
applyAnkiPatch: (patch) => {
|
shouldAutoInitializeOverlayRuntimeFromConfig: () =>
|
||||||
if (ankiIntegration) {
|
shouldAutoInitializeOverlayRuntimeFromConfig(),
|
||||||
ankiIntegration.applyRuntimeConfigPatch(patch);
|
initializeOverlayRuntime: () => initializeOverlayRuntime(),
|
||||||
}
|
handleInitialArgs: () => handleInitialArgs(),
|
||||||
},
|
}),
|
||||||
onOptionsChanged: () => {
|
);
|
||||||
broadcastRuntimeOptionsChanged();
|
},
|
||||||
refreshOverlayShortcuts();
|
onWillQuitCleanup: () => {
|
||||||
},
|
runAppShutdownRuntimeService(
|
||||||
});
|
createStartupAppShutdownDepsRuntimeService({
|
||||||
},
|
unregisterAllGlobalShortcuts: () => {
|
||||||
setSecondarySubMode: (mode) => {
|
globalShortcut.unregisterAll();
|
||||||
secondarySubMode = mode;
|
},
|
||||||
},
|
stopSubtitleWebsocket: () => {
|
||||||
defaultSecondarySubMode: "hover",
|
subtitleWsService.stop();
|
||||||
defaultWebsocketPort: DEFAULT_CONFIG.websocket.port,
|
},
|
||||||
hasMpvWebsocketPlugin: () => hasMpvWebsocketPlugin(),
|
stopTexthookerService: () => {
|
||||||
startSubtitleWebsocket: (port) => {
|
texthookerService.stop();
|
||||||
subtitleWsService.start(port, () => currentSubText);
|
},
|
||||||
},
|
destroyYomitanParserWindow: () => {
|
||||||
log: (message) => appLogger.logInfo(message),
|
if (yomitanParserWindow && !yomitanParserWindow.isDestroyed()) {
|
||||||
createMecabTokenizerAndCheck: async () =>
|
yomitanParserWindow.destroy();
|
||||||
createMecabTokenizerAndCheckRuntimeService({
|
}
|
||||||
createMecabTokenizer: () => new MecabTokenizer(),
|
yomitanParserWindow = null;
|
||||||
setMecabTokenizer: (tokenizer) => {
|
},
|
||||||
mecabTokenizer = tokenizer;
|
clearYomitanParserPromises: () => {
|
||||||
},
|
yomitanParserReadyPromise = null;
|
||||||
}),
|
yomitanParserInitPromise = null;
|
||||||
createSubtitleTimingTracker: () =>
|
},
|
||||||
createSubtitleTimingTrackerRuntimeService({
|
stopWindowTracker: () => {
|
||||||
createSubtitleTimingTracker: () => new SubtitleTimingTracker(),
|
if (windowTracker) {
|
||||||
setSubtitleTimingTracker: (tracker) => {
|
windowTracker.stop();
|
||||||
subtitleTimingTracker = tracker;
|
}
|
||||||
},
|
},
|
||||||
}),
|
destroyMpvSocket: () => {
|
||||||
loadYomitanExtension: async () => {
|
if (mpvClient && mpvClient.socket) {
|
||||||
await loadYomitanExtension();
|
mpvClient.socket.destroy();
|
||||||
},
|
}
|
||||||
texthookerOnlyMode,
|
},
|
||||||
shouldAutoInitializeOverlayRuntimeFromConfig: () =>
|
clearReconnectTimer: () => {
|
||||||
shouldAutoInitializeOverlayRuntimeFromConfig(),
|
if (reconnectTimer) {
|
||||||
initializeOverlayRuntime: () => initializeOverlayRuntime(),
|
clearTimeout(reconnectTimer);
|
||||||
handleInitialArgs: () => handleInitialArgs(),
|
}
|
||||||
}),
|
},
|
||||||
);
|
destroySubtitleTimingTracker: () => {
|
||||||
},
|
if (subtitleTimingTracker) {
|
||||||
onWillQuitCleanup: () => {
|
subtitleTimingTracker.destroy();
|
||||||
runAppShutdownRuntimeService(
|
}
|
||||||
createStartupAppShutdownDepsRuntimeService({
|
},
|
||||||
unregisterAllGlobalShortcuts: () => {
|
destroyAnkiIntegration: () => {
|
||||||
globalShortcut.unregisterAll();
|
if (ankiIntegration) {
|
||||||
},
|
ankiIntegration.destroy();
|
||||||
stopSubtitleWebsocket: () => {
|
}
|
||||||
subtitleWsService.stop();
|
},
|
||||||
},
|
}),
|
||||||
stopTexthookerService: () => {
|
);
|
||||||
texthookerService.stop();
|
},
|
||||||
},
|
shouldRestoreWindowsOnActivate: () =>
|
||||||
destroyYomitanParserWindow: () => {
|
overlayRuntimeInitialized && BrowserWindow.getAllWindows().length === 0,
|
||||||
if (yomitanParserWindow && !yomitanParserWindow.isDestroyed()) {
|
restoreWindowsOnActivate: () => {
|
||||||
yomitanParserWindow.destroy();
|
createMainWindow();
|
||||||
}
|
createInvisibleWindow();
|
||||||
yomitanParserWindow = null;
|
updateVisibleOverlayVisibility();
|
||||||
},
|
updateInvisibleOverlayVisibility();
|
||||||
clearYomitanParserPromises: () => {
|
},
|
||||||
yomitanParserReadyPromise = null;
|
}));
|
||||||
yomitanParserInitPromise = null;
|
},
|
||||||
},
|
});
|
||||||
stopWindowTracker: () => {
|
|
||||||
if (windowTracker) {
|
const initialArgs = startupState.initialArgs;
|
||||||
windowTracker.stop();
|
let mpvSocketPath = startupState.mpvSocketPath;
|
||||||
}
|
let texthookerPort = startupState.texthookerPort;
|
||||||
},
|
const backendOverride = startupState.backendOverride;
|
||||||
destroyMpvSocket: () => {
|
const autoStartOverlay = startupState.autoStartOverlay;
|
||||||
if (mpvClient && mpvClient.socket) {
|
const texthookerOnlyMode = startupState.texthookerOnlyMode;
|
||||||
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();
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCliCommand(
|
function handleCliCommand(
|
||||||
args: CliArgs,
|
args: CliArgs,
|
||||||
|
|||||||
Reference in New Issue
Block a user