refactor: extract runtime config access helpers

This commit is contained in:
2026-02-09 23:31:30 -08:00
parent 3be0258286
commit 53c2e6353a
4 changed files with 170 additions and 9 deletions

View File

@@ -16,7 +16,7 @@
"docs:build": "vitepress build docs", "docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs --host 0.0.0.0 --port 4173 --strictPort", "docs:preview": "vitepress preview docs --host 0.0.0.0 --port 4173 --strictPort",
"test:config": "pnpm run build && node --test dist/config/config.test.js", "test:config": "pnpm run build && node --test dist/config/config.test.js",
"test:core": "pnpm run build && node --test dist/cli/args.test.js dist/cli/help.test.js dist/core/services/cli-command-service.test.js dist/core/services/numeric-shortcut-session-service.test.js dist/core/services/secondary-subtitle-service.test.js dist/core/services/mpv-render-metrics-service.test.js dist/core/services/mpv-runtime-service.test.js dist/core/services/runtime-options-runtime-service.test.js dist/core/services/overlay-modal-restore-service.test.js", "test:core": "pnpm run build && node --test dist/cli/args.test.js dist/cli/help.test.js dist/core/services/cli-command-service.test.js dist/core/services/numeric-shortcut-session-service.test.js dist/core/services/secondary-subtitle-service.test.js dist/core/services/mpv-render-metrics-service.test.js dist/core/services/mpv-runtime-service.test.js dist/core/services/runtime-options-runtime-service.test.js dist/core/services/overlay-modal-restore-service.test.js dist/core/services/runtime-config-service.test.js",
"test:subtitle": "pnpm run build && node --test dist/subtitle/stages.test.js dist/subtitle/pipeline.test.js", "test:subtitle": "pnpm run build && node --test dist/subtitle/stages.test.js dist/subtitle/pipeline.test.js",
"generate:config-example": "pnpm run build && node dist/generate-config-example.js", "generate:config-example": "pnpm run build && node dist/generate-config-example.js",
"start": "pnpm run build && electron . --start", "start": "pnpm run build && electron . --start",

View File

@@ -0,0 +1,98 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
getInitialInvisibleOverlayVisibilityService,
isAutoUpdateEnabledRuntimeService,
shouldAutoInitializeOverlayRuntimeFromConfigService,
shouldBindVisibleOverlayToMpvSubVisibilityService,
} from "./runtime-config-service";
const BASE_CONFIG = {
auto_start_overlay: false,
bind_visible_overlay_to_mpv_sub_visibility: true,
invisibleOverlay: {
startupVisibility: "platform-default" as const,
},
ankiConnect: {
behavior: {
autoUpdateNewCards: true,
},
},
};
test("getInitialInvisibleOverlayVisibilityService handles visibility + platform", () => {
assert.equal(
getInitialInvisibleOverlayVisibilityService(
{ ...BASE_CONFIG, invisibleOverlay: { startupVisibility: "visible" } },
"linux",
),
true,
);
assert.equal(
getInitialInvisibleOverlayVisibilityService(
{ ...BASE_CONFIG, invisibleOverlay: { startupVisibility: "hidden" } },
"darwin",
),
false,
);
assert.equal(
getInitialInvisibleOverlayVisibilityService(BASE_CONFIG, "linux"),
false,
);
assert.equal(
getInitialInvisibleOverlayVisibilityService(BASE_CONFIG, "darwin"),
true,
);
});
test("shouldAutoInitializeOverlayRuntimeFromConfigService respects auto start and visible startup", () => {
assert.equal(
shouldAutoInitializeOverlayRuntimeFromConfigService(BASE_CONFIG),
false,
);
assert.equal(
shouldAutoInitializeOverlayRuntimeFromConfigService({
...BASE_CONFIG,
auto_start_overlay: true,
}),
true,
);
assert.equal(
shouldAutoInitializeOverlayRuntimeFromConfigService({
...BASE_CONFIG,
invisibleOverlay: { startupVisibility: "visible" },
}),
true,
);
});
test("shouldBindVisibleOverlayToMpvSubVisibilityService returns config value", () => {
assert.equal(shouldBindVisibleOverlayToMpvSubVisibilityService(BASE_CONFIG), true);
assert.equal(
shouldBindVisibleOverlayToMpvSubVisibilityService({
...BASE_CONFIG,
bind_visible_overlay_to_mpv_sub_visibility: false,
}),
false,
);
});
test("isAutoUpdateEnabledRuntimeService prefers runtime option and falls back to config", () => {
assert.equal(
isAutoUpdateEnabledRuntimeService(BASE_CONFIG, {
getOptionValue: () => false,
}),
false,
);
assert.equal(
isAutoUpdateEnabledRuntimeService(
{
...BASE_CONFIG,
ankiConnect: { behavior: { autoUpdateNewCards: false } },
},
null,
),
false,
);
assert.equal(isAutoUpdateEnabledRuntimeService(BASE_CONFIG, null), true);
});

View File

@@ -0,0 +1,50 @@
interface RuntimeAutoUpdateOptionManagerLike {
getOptionValue: (id: "anki.autoUpdateNewCards") => unknown;
}
interface RuntimeConfigLike {
auto_start_overlay?: boolean;
bind_visible_overlay_to_mpv_sub_visibility: boolean;
invisibleOverlay: {
startupVisibility: "visible" | "hidden" | "platform-default";
};
ankiConnect?: {
behavior?: {
autoUpdateNewCards?: boolean;
};
};
}
export function getInitialInvisibleOverlayVisibilityService(
config: RuntimeConfigLike,
platform: NodeJS.Platform,
): boolean {
const visibility = config.invisibleOverlay.startupVisibility;
if (visibility === "visible") return true;
if (visibility === "hidden") return false;
if (platform === "linux") return false;
return true;
}
export function shouldAutoInitializeOverlayRuntimeFromConfigService(
config: RuntimeConfigLike,
): boolean {
if (config.auto_start_overlay === true) return true;
if (config.invisibleOverlay.startupVisibility === "visible") return true;
return false;
}
export function shouldBindVisibleOverlayToMpvSubVisibilityService(
config: RuntimeConfigLike,
): boolean {
return config.bind_visible_overlay_to_mpv_sub_visibility;
}
export function isAutoUpdateEnabledRuntimeService(
config: RuntimeConfigLike,
runtimeOptionsManager: RuntimeAutoUpdateOptionManagerLike | null,
): boolean {
const value = runtimeOptionsManager?.getOptionValue("anki.autoUpdateNewCards");
if (typeof value === "boolean") return value;
return config.ankiConnect?.behavior?.autoUpdateNewCards !== false;
}

View File

@@ -143,6 +143,12 @@ import {
cycleRuntimeOptionFromIpcRuntimeService, cycleRuntimeOptionFromIpcRuntimeService,
setRuntimeOptionFromIpcRuntimeService, setRuntimeOptionFromIpcRuntimeService,
} from "./core/services/runtime-options-runtime-service"; } from "./core/services/runtime-options-runtime-service";
import {
getInitialInvisibleOverlayVisibilityService,
isAutoUpdateEnabledRuntimeService,
shouldAutoInitializeOverlayRuntimeFromConfigService,
shouldBindVisibleOverlayToMpvSubVisibilityService,
} from "./core/services/runtime-config-service";
import { showDesktopNotification } from "./core/utils/notification"; import { showDesktopNotification } from "./core/utils/notification";
import { openYomitanSettingsWindow } from "./core/services/yomitan-settings-service"; import { openYomitanSettingsWindow } from "./core/services/yomitan-settings-service";
import { tokenizeSubtitleService } from "./core/services/tokenizer-service"; import { tokenizeSubtitleService } from "./core/services/tokenizer-service";
@@ -318,19 +324,26 @@ function openRuntimeOptionsPalette(): void { sendToVisibleOverlay("runtime-optio
function getResolvedConfig() { return configService.getConfig(); } function getResolvedConfig() { return configService.getConfig(); }
function getInitialInvisibleOverlayVisibility(): boolean { const visibility = getResolvedConfig().invisibleOverlay.startupVisibility; if (visibility === "visible") return true; if (visibility === "hidden") return false; if (process.platform === "linux") return false; return true; } function getInitialInvisibleOverlayVisibility(): boolean {
return getInitialInvisibleOverlayVisibilityService(
getResolvedConfig(),
process.platform,
);
}
function shouldAutoInitializeOverlayRuntimeFromConfig(): boolean { const config = getResolvedConfig(); if (config.auto_start_overlay === true) return true; if (config.invisibleOverlay.startupVisibility === "visible") return true; return false; } function shouldAutoInitializeOverlayRuntimeFromConfig(): boolean {
return shouldAutoInitializeOverlayRuntimeFromConfigService(getResolvedConfig());
}
function shouldBindVisibleOverlayToMpvSubVisibility(): boolean { return getResolvedConfig().bind_visible_overlay_to_mpv_sub_visibility; } function shouldBindVisibleOverlayToMpvSubVisibility(): boolean {
return shouldBindVisibleOverlayToMpvSubVisibilityService(getResolvedConfig());
}
function isAutoUpdateEnabledRuntime(): boolean { function isAutoUpdateEnabledRuntime(): boolean {
const value = runtimeOptionsManager?.getOptionValue( return isAutoUpdateEnabledRuntimeService(
"anki.autoUpdateNewCards", getResolvedConfig(),
runtimeOptionsManager,
); );
if (typeof value === "boolean") return value;
const config = getResolvedConfig();
return config.ankiConnect?.behavior?.autoUpdateNewCards !== false;
} }
function getJimakuLanguagePreference(): JimakuLanguagePreference { return getJimakuLanguagePreferenceService(() => getResolvedConfig(), DEFAULT_CONFIG.jimaku.languagePreference); } function getJimakuLanguagePreference(): JimakuLanguagePreference { return getJimakuLanguagePreferenceService(() => getResolvedConfig(), DEFAULT_CONFIG.jimaku.languagePreference); }