diff --git a/backlog/completed/task-55 - Normalize-service-naming-conventions-across-core-services.md b/backlog/completed/task-55 - Normalize-service-naming-conventions-across-core-services.md new file mode 100644 index 0000000..4aafba5 --- /dev/null +++ b/backlog/completed/task-55 - Normalize-service-naming-conventions-across-core-services.md @@ -0,0 +1,64 @@ +--- +id: TASK-55 +title: Normalize service naming conventions across core/services +status: Done +assignee: [] +created_date: '2026-02-16 04:47' +updated_date: '2026-02-17 09:12' +labels: [] +dependencies: [] +references: + - /home/sudacode/projects/japanese/SubMiner/src/core/services/index.ts +priority: low +--- + +## Description + + +The core/services directory has inconsistent naming patterns that create confusion: +- Some files use `*Service.ts` suffix (e.g., `mpv-service.ts`, `tokenizer-service.ts`) +- Others use `*RuntimeService.ts` or just descriptive names (e.g., `overlay-visibility-service.ts` exports functions with 'Service' in name) +- Some functions in files have 'Service' suffix, others don't + +This inconsistency makes it hard to predict file/function names and creates cognitive overhead. + +Standardize on: +- File names: `kebab-case.ts` without 'service' suffix (e.g., `mpv.ts`, `tokenizer.ts`) +- Function names: descriptive verbs without 'Service' suffix (e.g., `createMpvClient()`, `tokenizeSubtitle()`) +- Barrel exports: clean, predictable names + +Files needing audit (47 services): +- All files in src/core/services/ need review + +Note: This is a large-scale refactor that should be done carefully to avoid breaking changes. + + +## Acceptance Criteria + +- [x] #1 Establish naming convention rules (document in code or docs) +- [x] #2 Audit all service files for naming inconsistencies +- [x] #3 Rename files to follow convention (kebab-case, no 'service' suffix) +- [x] #4 Rename exported functions to remove 'Service' suffix where present +- [x] #5 Update all imports across the entire codebase +- [x] #6 Update barrel exports +- [x] #7 Run full test suite +- [x] #8 Update any documentation referencing old names + + +## Implementation Notes + + +Starting implementation. Planning and executing a mechanical refactor: file names and exported symbols with Service suffix in `src/core/services`, then cascading import updates across `src/`. + +Implemented naming convention refactor across `src/core/services`: removed `-service` from service file names, renamed Service-suffixed exported symbols to non-Service names, and updated barrel exports in `src/core/services/index.ts`. + +Updated call sites across `src/main/**`, `src/core/services/**` tests, `scripts/**`, `package.json` test paths, and docs references (`docs/development.md`, `docs/architecture.md`, `docs/structure-roadmap.md`). + +Validation completed: `pnpm run build` and `pnpm run test:fast` both pass after refactor. + + +## Final Summary + + +Normalized `src/core/services` naming by removing `-service` from module filenames, dropping `Service` suffixes from exported service functions, and updating `src/core/services/index.ts` barrel exports to the new names. Updated all import/call sites across `src/main/**`, service tests, scripts, and docs/package test paths to match the new module and symbol names. Verified no behavior regressions with `pnpm run build` and `pnpm run test:fast` (all passing). + diff --git a/backlog/tasks/task-55 - Normalize-service-naming-conventions-across-core-services.md b/backlog/tasks/task-55 - Normalize-service-naming-conventions-across-core-services.md deleted file mode 100644 index 31d05b9..0000000 --- a/backlog/tasks/task-55 - Normalize-service-naming-conventions-across-core-services.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -id: TASK-55 -title: Normalize service naming conventions across core/services -status: To Do -assignee: [] -created_date: '2026-02-16 04:47' -labels: [] -dependencies: [] -references: - - /home/sudacode/projects/japanese/SubMiner/src/core/services/index.ts -priority: low ---- - -## Description - - -The core/services directory has inconsistent naming patterns that create confusion: -- Some files use `*Service.ts` suffix (e.g., `mpv-service.ts`, `tokenizer-service.ts`) -- Others use `*RuntimeService.ts` or just descriptive names (e.g., `overlay-visibility-service.ts` exports functions with 'Service' in name) -- Some functions in files have 'Service' suffix, others don't - -This inconsistency makes it hard to predict file/function names and creates cognitive overhead. - -Standardize on: -- File names: `kebab-case.ts` without 'service' suffix (e.g., `mpv.ts`, `tokenizer.ts`) -- Function names: descriptive verbs without 'Service' suffix (e.g., `createMpvClient()`, `tokenizeSubtitle()`) -- Barrel exports: clean, predictable names - -Files needing audit (47 services): -- All files in src/core/services/ need review - -Note: This is a large-scale refactor that should be done carefully to avoid breaking changes. - - -## Acceptance Criteria - -- [ ] #1 Establish naming convention rules (document in code or docs) -- [ ] #2 Audit all service files for naming inconsistencies -- [ ] #3 Rename files to follow convention (kebab-case, no 'service' suffix) -- [ ] #4 Rename exported functions to remove 'Service' suffix where present -- [ ] #5 Update all imports across the entire codebase -- [ ] #6 Update barrel exports -- [ ] #7 Run full test suite -- [ ] #8 Update any documentation referencing old names - diff --git a/docs/architecture.md b/docs/architecture.md index 5017f15..d0e5389 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -222,7 +222,7 @@ flowchart TD - **Better reviewability:** PRs can be scoped to one subsystem. - **Backward compatibility:** CLI flags and IPC channels can remain stable while internals evolve. - **Extracted composition root:** TASK-27 refactored `main.ts` into focused modules under `src/main/`, isolating startup, lifecycle, IPC, CLI, and domain-specific runtime wiring. -- **Split MPV service:** TASK-27.4 separated `mpv-service.ts` into transport (`mpv-transport.ts`), protocol (`mpv-protocol.ts`), state (`mpv-state.ts`), and properties (`mpv-properties.ts`) layers for improved maintainability. +- **Split MPV service:** TASK-27.4 separated `mpv.ts` into transport (`mpv-transport.ts`), protocol (`mpv-protocol.ts`), state (`mpv-state.ts`), and properties (`mpv-properties.ts`) layers for improved maintainability. ## Extension Rules diff --git a/docs/development.md b/docs/development.md index 615ef18..807ebc5 100644 --- a/docs/development.md +++ b/docs/development.md @@ -96,7 +96,7 @@ Run `make help` for a full list of targets. Key ones: ## Contributor Notes - To add or change a config option, update `src/config/definitions.ts` first. Defaults, runtime-option metadata, and generated `config.example.jsonc` are derived from this centralized source. -- Overlay window/visibility state is owned by `src/core/services/overlay-manager-service.ts`. +- Overlay window/visibility state is owned by `src/core/services/overlay-manager.ts`. - Main process composition is now split across `src/main/` modules (`startup.ts`, `app-lifecycle.ts`, `startup-lifecycle.ts`, `state.ts`, `ipc-runtime.ts`, `cli-runtime.ts`, `overlay-runtime.ts`, `subsync-runtime.ts`). - MPV service has been split into transport, protocol, state, and properties layers in `src/core/services/`. - Prefer direct inline deps objects in `src/main/` modules for simple pass-through wiring. diff --git a/docs/structure-roadmap.md b/docs/structure-roadmap.md index d2d08a1..e03cb94 100644 --- a/docs/structure-roadmap.md +++ b/docs/structure-roadmap.md @@ -8,8 +8,8 @@ Date: 2026-02-14 | --- | --- | --- | --- | | `src/main.ts` | Bootstrap / composition root / orchestration | Active | Main entrypoint owns startup, lifecycle orchestration, service construction, state mutation surfaces, and IPC bindings | | `src/anki-integration.ts` | Domain service orchestration / integrations | Active | 2.6k+ LOC, high cyclomatic coupling to mpv/subtitle timing and mining flows | -| `src/core/services/mpv-service.ts` | MPV protocol + app state bridge | Active | ~780 LOC, large protocol and behavior mix, 22-entry dep interface | -| `src/core/services/subsync-service.ts` | Subsync orchestration (ffsubsync/alass workflows) | Active | ~494 LOC, file IO + mpv command orchestration + result shaping | +| `src/core/services/mpv.ts` | MPV protocol + app state bridge | Active | ~780 LOC, large protocol and behavior mix, 22-entry dep interface | +| `src/core/services/subsync.ts` | Subsync orchestration (ffsubsync/alass workflows) | Active | ~494 LOC, file IO + mpv command orchestration + result shaping | | `src/renderer/positioning.ts` | Renderer positioning layout policy | Active (downstream of TASK-27.5) | 513 LOC, layout/rules + platform-specific behavior in one module | | `src/config/service.ts` | Config load/validation | Active support | ~601 LOC, central schema validation + mutation APIs | | `src/types.ts` | Shared contract surface | Active support | ~640 LOC, foundational type exports driving module boundaries | @@ -34,7 +34,7 @@ Date: 2026-02-14 - Electron event loop (`app.whenReady`, `process` signals) - startup/bootstrap services, service adapters in `src/core/services` -### `src/core/services/mpv-service.ts` (protocol + facade) +### `src/core/services/mpv.ts` (protocol + facade) - **Core exports**: `MpvIpcClient`, `MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY`, `MpvIpcClientDeps` - **Primary responsibilities / API**: @@ -45,9 +45,9 @@ Date: 2026-02-14 - state restoration (`restorePreviousSecondarySubVisibility`) - **Current caller set**: - `src/main.ts` (construction + lifecycle + service invocations) - - `src/core/services/mpv-control-service.ts` (runtime control API) - - `src/core/services/subsync-service.ts` (`requestProperty`, request ID usage) - - tests under `src/core/services/mpv-service.test.ts` + - `src/main/ipc-mpv-command.ts` (runtime control API) + - `src/core/services/subsync.ts` (`requestProperty`, request ID usage) + - tests under `src/core/services/mpv.test.ts` - **Observed coupling risk**: - `MpvIpcClientDeps` mixes protocol config with app-level side effects (subtitle broadcast, tokenizer, overlay updates, config reads) @@ -61,15 +61,15 @@ Date: 2026-02-14 - **State dependencies (constructor)**: - config, subtitle timing tracker, mpv client, OSD/notification callbacks - **Primary callers**: - - `src/core/services/overlay-runtime-init-service.ts` (initial integration creation) - - `src/core/services/anki-jimaku-service.ts` (enable/disable and field-grouping RPC) - - `src/core/services/mining-service.ts` (delegates mining actions) + - `src/core/services/overlay-runtime-init.ts` (initial integration creation) + - `src/core/services/anki-jimaku.ts` (enable/disable and field-grouping RPC) + - `src/core/services/mining.ts` (delegates mining actions) -### `src/core/services/subsync-service.ts` +### `src/core/services/subsync.ts` - **Exports**: `runSubsyncManualService`, `openSubsyncManualPickerService`, `triggerSubsyncFromConfigService` - **Caller set**: - - `src/core/services/subsync-runner-service.ts` (runtime wrappers) + - `src/core/services/subsync-runner.ts` (runtime wrappers) - `src/core/services/mpv-jimaku/`? (through runtime services and IPC command handlers) ### `src/config/service.ts` diff --git a/package.json b/package.json index 6a9baac..034d056 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "docs:build": "VITE_EXTRA_EXTENSIONS=jsonc vitepress build docs", "docs:preview": "VITE_EXTRA_EXTENSIONS=jsonc vitepress preview docs --host 0.0.0.0 --port 4173 --strictPort", "test:config:dist": "node --test dist/config/config.test.js", - "test:core:dist": "node --test dist/cli/args.test.js dist/cli/help.test.js dist/core/services/cli-command-service.test.js dist/core/services/field-grouping-overlay-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/overlay-content-measurement-service.test.js dist/core/services/mpv-control-service.test.js dist/core/services/mpv-service.test.js dist/core/services/runtime-options-ipc-service.test.js dist/core/services/runtime-config-service.test.js dist/core/services/tokenizer-service.test.js dist/core/services/subsync-service.test.js dist/core/services/overlay-bridge-service.test.js dist/core/services/overlay-manager-service.test.js dist/core/services/overlay-shortcut-handler.test.js dist/core/services/mining-service.test.js dist/core/services/anki-jimaku-service.test.js dist/core/services/immersion-tracker-service.test.js dist/core/services/app-ready-service.test.js dist/core/services/startup-bootstrap-service.test.js dist/subsync/utils.test.js dist/main/anilist-url-guard.test.js", + "test:core:dist": "node --test dist/cli/args.test.js dist/cli/help.test.js dist/core/services/cli-command.test.js dist/core/services/field-grouping-overlay.test.js dist/core/services/numeric-shortcut-session.test.js dist/core/services/secondary-subtitle.test.js dist/core/services/mpv-render-metrics.test.js dist/core/services/overlay-content-measurement.test.js dist/core/services/mpv-control.test.js dist/core/services/mpv.test.js dist/core/services/runtime-options-ipc.test.js dist/core/services/runtime-config.test.js dist/core/services/tokenizer.test.js dist/core/services/subsync.test.js dist/core/services/overlay-bridge.test.js dist/core/services/overlay-manager.test.js dist/core/services/overlay-shortcut-handler.test.js dist/core/services/mining.test.js dist/core/services/anki-jimaku.test.js dist/core/services/immersion-tracker-service.test.js dist/core/services/app-ready.test.js dist/core/services/startup-bootstrap.test.js dist/subsync/utils.test.js dist/main/anilist-url-guard.test.js", "test:subtitle:dist": "echo \"Subtitle tests are currently not configured\"", "test": "pnpm run test:config && pnpm run test:core", "test:config": "pnpm run build && pnpm run test:config:dist", diff --git a/scripts/get_frequency.ts b/scripts/get_frequency.ts index cd58192..89345a8 100644 --- a/scripts/get_frequency.ts +++ b/scripts/get_frequency.ts @@ -2,8 +2,8 @@ import fs from "node:fs"; import path from "node:path"; import process from "node:process"; -import { createTokenizerDepsRuntimeService, tokenizeSubtitleService } from "../src/core/services/tokenizer-service.js"; -import { createFrequencyDictionaryLookupService } from "../src/core/services/frequency-dictionary-service.js"; +import { createTokenizerDepsRuntime, tokenizeSubtitle } from "../src/core/services/tokenizer.js"; +import { createFrequencyDictionaryLookup } from "../src/core/services/index.js"; import { MecabTokenizer } from "../src/mecab-tokenizer.js"; import type { MergedToken, FrequencyDictionaryLookup } from "../src/types.js"; @@ -537,11 +537,11 @@ async function createYomitanRuntimeState( try { await electronImport.app.whenReady(); - const loadYomitanExtensionService = ( + const loadYomitanExtension = ( await import( - "../src/core/services/yomitan-extension-loader-service.js" + "../src/core/services/yomitan-extension-loader.js" ) - ).loadYomitanExtensionService as ( + ).loadYomitanExtension as ( options: { userDataPath: string; getYomitanParserWindow: () => unknown; @@ -552,7 +552,7 @@ async function createYomitanRuntimeState( }, ) => Promise; - const extension = await loadYomitanExtensionService({ + const extension = await loadYomitanExtension({ userDataPath, getYomitanParserWindow: () => state.parserWindow, setYomitanParserWindow: (window) => { @@ -623,7 +623,7 @@ async function createYomitanRuntimeStateWithSearch( } async function getFrequencyLookup(dictionaryPath: string): Promise { - return createFrequencyDictionaryLookupService({ + return createFrequencyDictionaryLookup({ searchPaths: [dictionaryPath], log: (message) => { // Keep script output pure JSON by default @@ -786,7 +786,7 @@ async function main(): Promise { : null; const hasYomitan = Boolean(yomitanState?.available && yomitanState?.yomitanExt); - const deps = createTokenizerDepsRuntimeService({ + const deps = createTokenizerDepsRuntime({ getYomitanExt: () => (hasYomitan ? yomitanState!.yomitanExt : null) as never, getYomitanParserWindow: () => @@ -823,7 +823,7 @@ async function main(): Promise { }), }); - const subtitleData = await tokenizeSubtitleService(args.input, deps); + const subtitleData = await tokenizeSubtitle(args.input, deps); const tokenCount = subtitleData.tokens?.length ?? 0; const mergedCount = subtitleData.tokens?.filter((token) => token.isMerged).length ?? 0; const tokens = diff --git a/scripts/test-yomitan-parser.ts b/scripts/test-yomitan-parser.ts index 9ea8157..ae6dce3 100644 --- a/scripts/test-yomitan-parser.ts +++ b/scripts/test-yomitan-parser.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import process from "node:process"; -import { createTokenizerDepsRuntimeService, tokenizeSubtitleService } from "../src/core/services/tokenizer-service.js"; +import { createTokenizerDepsRuntime, tokenizeSubtitle } from "../src/core/services/tokenizer.js"; import { MecabTokenizer } from "../src/mecab-tokenizer.js"; import type { MergedToken } from "../src/types.js"; @@ -563,7 +563,7 @@ async function main(): Promise { yomitan.parserReadyPromise = runtime.parserReadyPromise; yomitan.parserInitPromise = runtime.parserInitPromise; - const deps = createTokenizerDepsRuntimeService({ + const deps = createTokenizerDepsRuntime({ getYomitanExt: () => yomitan.extension, getYomitanParserWindow: () => yomitan.parserWindow, setYomitanParserWindow: (window) => { @@ -585,7 +585,7 @@ async function main(): Promise { }), }); - const subtitleData = await tokenizeSubtitleService(args.input, deps); + const subtitleData = await tokenizeSubtitle(args.input, deps); const tokenizeText = normalizeTokenizerText(args.input); let rawParseResults: unknown = null; if ( diff --git a/src/core/services/anki-jimaku-ipc-service.ts b/src/core/services/anki-jimaku-ipc.ts similarity index 100% rename from src/core/services/anki-jimaku-ipc-service.ts rename to src/core/services/anki-jimaku-ipc.ts diff --git a/src/core/services/anki-jimaku-service.test.ts b/src/core/services/anki-jimaku.test.ts similarity index 97% rename from src/core/services/anki-jimaku-service.test.ts rename to src/core/services/anki-jimaku.test.ts index d3e465c..eaf63fd 100644 --- a/src/core/services/anki-jimaku-service.test.ts +++ b/src/core/services/anki-jimaku.test.ts @@ -2,8 +2,8 @@ import test from "node:test"; import assert from "node:assert/strict"; import { AnkiJimakuIpcRuntimeOptions, - registerAnkiJimakuIpcRuntimeService, -} from "./anki-jimaku-service"; + registerAnkiJimakuIpcRuntime, +} from "./anki-jimaku"; interface RuntimeHarness { options: AnkiJimakuIpcRuntimeOptions; @@ -92,7 +92,7 @@ function createHarness(): RuntimeHarness { }; let registered: Record unknown> = {}; - registerAnkiJimakuIpcRuntimeService( + registerAnkiJimakuIpcRuntime( options, (deps) => { registered = deps as unknown as Record unknown>; @@ -102,7 +102,7 @@ function createHarness(): RuntimeHarness { return { options, registered, state }; } -test("registerAnkiJimakuIpcRuntimeService provides full handler surface", () => { +test("registerAnkiJimakuIpcRuntime provides full handler surface", () => { const { registered } = createHarness(); const expected = [ "setAnkiConnectEnabled", diff --git a/src/core/services/anki-jimaku-service.ts b/src/core/services/anki-jimaku.ts similarity index 98% rename from src/core/services/anki-jimaku-service.ts rename to src/core/services/anki-jimaku.ts index 97d506d..d4a5f7e 100644 --- a/src/core/services/anki-jimaku-service.ts +++ b/src/core/services/anki-jimaku.ts @@ -10,7 +10,7 @@ import { KikuFieldGroupingRequestData, } from "../../types"; import { sortJimakuFiles } from "../../jimaku/utils"; -import type { AnkiJimakuIpcDeps } from "./anki-jimaku-ipc-service"; +import type { AnkiJimakuIpcDeps } from "./anki-jimaku-ipc"; import { createLogger } from "../../logger"; export type RegisterAnkiJimakuIpcRuntimeHandler = ( @@ -65,7 +65,7 @@ export interface AnkiJimakuIpcRuntimeOptions { const logger = createLogger("main:anki-jimaku"); -export function registerAnkiJimakuIpcRuntimeService( +export function registerAnkiJimakuIpcRuntime( options: AnkiJimakuIpcRuntimeOptions, registerHandlers: RegisterAnkiJimakuIpcRuntimeHandler, ): void { diff --git a/src/core/services/app-lifecycle-service.ts b/src/core/services/app-lifecycle.ts similarity index 97% rename from src/core/services/app-lifecycle-service.ts rename to src/core/services/app-lifecycle.ts index ca2bb25..2e69871 100644 --- a/src/core/services/app-lifecycle-service.ts +++ b/src/core/services/app-lifecycle.ts @@ -44,7 +44,7 @@ export interface AppLifecycleDepsRuntimeOptions { restoreWindowsOnActivate: () => void; } -export function createAppLifecycleDepsRuntimeService( +export function createAppLifecycleDepsRuntime( options: AppLifecycleDepsRuntimeOptions, ): AppLifecycleServiceDeps { return { @@ -80,7 +80,7 @@ export function createAppLifecycleDepsRuntimeService( }; } -export function startAppLifecycleService( +export function startAppLifecycle( initialArgs: CliArgs, deps: AppLifecycleServiceDeps, ): void { diff --git a/src/core/services/app-ready-service.test.ts b/src/core/services/app-ready.test.ts similarity index 87% rename from src/core/services/app-ready-service.test.ts rename to src/core/services/app-ready.test.ts index 4287841..3fee8e1 100644 --- a/src/core/services/app-ready-service.test.ts +++ b/src/core/services/app-ready.test.ts @@ -1,6 +1,6 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { AppReadyRuntimeDeps, runAppReadyRuntimeService } from "./startup-service"; +import { AppReadyRuntimeDeps, runAppReadyRuntime } from "./startup"; function makeDeps(overrides: Partial = {}) { const calls: string[] = []; @@ -37,11 +37,11 @@ function makeDeps(overrides: Partial = {}) { return { deps, calls }; } -test("runAppReadyRuntimeService starts websocket in auto mode when plugin missing", async () => { +test("runAppReadyRuntime starts websocket in auto mode when plugin missing", async () => { const { deps, calls } = makeDeps({ hasMpvWebsocketPlugin: () => false, }); - await runAppReadyRuntimeService(deps); + await runAppReadyRuntime(deps); assert.ok(calls.includes("startSubtitleWebsocket:9001")); assert.ok(calls.includes("initializeOverlayRuntime")); assert.ok(calls.includes("createImmersionTracker")); @@ -80,11 +80,11 @@ test("runAppReadyRuntimeService logs and continues when createImmersionTracker t assert.ok(calls.includes("handleInitialArgs")); }); -test("runAppReadyRuntimeService logs defer message when overlay not auto-started", async () => { +test("runAppReadyRuntime logs defer message when overlay not auto-started", async () => { const { deps, calls } = makeDeps({ shouldAutoInitializeOverlayRuntimeFromConfig: () => false, }); - await runAppReadyRuntimeService(deps); + await runAppReadyRuntime(deps); assert.ok( calls.includes( "log:Overlay runtime deferred: waiting for explicit overlay command.", @@ -92,7 +92,7 @@ test("runAppReadyRuntimeService logs defer message when overlay not auto-started ); }); -test("runAppReadyRuntimeService applies config logging level during app-ready", async () => { +test("runAppReadyRuntime applies config logging level during app-ready", async () => { const { deps, calls } = makeDeps({ getResolvedConfig: () => ({ websocket: { enabled: "auto" }, @@ -100,6 +100,6 @@ test("runAppReadyRuntimeService applies config logging level during app-ready", logging: { level: "warn" }, }), }); - await runAppReadyRuntimeService(deps); + await runAppReadyRuntime(deps); assert.ok(calls.includes("setLogLevel:warn:config")); }); diff --git a/src/core/services/cli-command-service.test.ts b/src/core/services/cli-command.test.ts similarity index 82% rename from src/core/services/cli-command-service.test.ts rename to src/core/services/cli-command.test.ts index 9d4b007..46bb351 100644 --- a/src/core/services/cli-command-service.test.ts +++ b/src/core/services/cli-command.test.ts @@ -1,7 +1,7 @@ import test from "node:test"; import assert from "node:assert/strict"; import { CliArgs } from "../../cli/args"; -import { CliCommandServiceDeps, handleCliCommandService } from "./cli-command-service"; +import { CliCommandServiceDeps, handleCliCommand } from "./cli-command"; function makeArgs(overrides: Partial = {}): CliArgs { return { @@ -148,21 +148,21 @@ function createDeps(overrides: Partial = {}) { return { deps, calls, osd }; } -test("handleCliCommandService ignores --start for second-instance without actions", () => { +test("handleCliCommand ignores --start for second-instance without actions", () => { const { deps, calls } = createDeps(); const args = makeArgs({ start: true }); - handleCliCommandService(args, "second-instance", deps); + handleCliCommand(args, "second-instance", deps); assert.ok(calls.includes("log:Ignoring --start because SubMiner is already running.")); assert.equal(calls.some((value) => value.includes("connectMpvClient")), false); }); -test("handleCliCommandService runs texthooker flow with browser open", () => { +test("handleCliCommand runs texthooker flow with browser open", () => { const { deps, calls } = createDeps(); const args = makeArgs({ texthooker: true }); - handleCliCommandService(args, "initial", deps); + handleCliCommand(args, "initial", deps); assert.ok(calls.includes("ensureTexthookerRunning:5174")); assert.ok( @@ -170,24 +170,24 @@ test("handleCliCommandService runs texthooker flow with browser open", () => { ); }); -test("handleCliCommandService reports async mine errors to OSD", async () => { +test("handleCliCommand reports async mine errors to OSD", async () => { const { deps, calls, osd } = createDeps({ mineSentenceCard: async () => { throw new Error("boom"); }, }); - handleCliCommandService(makeArgs({ mineSentence: true }), "initial", deps); + handleCliCommand(makeArgs({ mineSentence: true }), "initial", deps); await new Promise((resolve) => setImmediate(resolve)); assert.ok(calls.some((value) => value.startsWith("error:mineSentenceCard failed:"))); assert.ok(osd.some((value) => value.includes("Mine sentence failed: boom"))); }); -test("handleCliCommandService applies socket path and connects on start", () => { +test("handleCliCommand applies socket path and connects on start", () => { const { deps, calls } = createDeps(); - handleCliCommandService( + handleCliCommand( makeArgs({ start: true, socketPath: "/tmp/custom.sock" }), "initial", deps, @@ -198,12 +198,12 @@ test("handleCliCommandService applies socket path and connects on start", () => assert.ok(calls.includes("connectMpvClient")); }); -test("handleCliCommandService warns when texthooker port override used while running", () => { +test("handleCliCommand warns when texthooker port override used while running", () => { const { deps, calls } = createDeps({ isTexthookerRunning: () => true, }); - handleCliCommandService( + handleCliCommand( makeArgs({ texthookerPort: 9999, texthooker: true }), "initial", deps, @@ -217,25 +217,25 @@ test("handleCliCommandService warns when texthooker port override used while run assert.equal(calls.some((value) => value === "setTexthookerPort:9999"), false); }); -test("handleCliCommandService prints help and stops app when no window exists", () => { +test("handleCliCommand prints help and stops app when no window exists", () => { const { deps, calls } = createDeps({ hasMainWindow: () => false, }); - handleCliCommandService(makeArgs({ help: true }), "initial", deps); + handleCliCommand(makeArgs({ help: true }), "initial", deps); assert.ok(calls.includes("printHelp")); assert.ok(calls.includes("stopApp")); }); -test("handleCliCommandService reports async trigger-subsync errors to OSD", async () => { +test("handleCliCommand reports async trigger-subsync errors to OSD", async () => { const { deps, calls, osd } = createDeps({ triggerSubsyncFromConfig: async () => { throw new Error("subsync boom"); }, }); - handleCliCommandService(makeArgs({ triggerSubsync: true }), "initial", deps); + handleCliCommand(makeArgs({ triggerSubsync: true }), "initial", deps); await new Promise((resolve) => setImmediate(resolve)); assert.ok( @@ -244,16 +244,16 @@ test("handleCliCommandService reports async trigger-subsync errors to OSD", asyn assert.ok(osd.some((value) => value.includes("Subsync failed: subsync boom"))); }); -test("handleCliCommandService stops app for --stop command", () => { +test("handleCliCommand stops app for --stop command", () => { const { deps, calls } = createDeps(); - handleCliCommandService(makeArgs({ stop: true }), "initial", deps); + handleCliCommand(makeArgs({ stop: true }), "initial", deps); assert.ok(calls.includes("log:Stopping SubMiner...")); assert.ok(calls.includes("stopApp")); }); -test("handleCliCommandService still runs non-start actions on second-instance", () => { +test("handleCliCommand still runs non-start actions on second-instance", () => { const { deps, calls } = createDeps(); - handleCliCommandService( + handleCliCommand( makeArgs({ start: true, toggleVisibleOverlay: true }), "second-instance", deps, @@ -262,7 +262,7 @@ test("handleCliCommandService still runs non-start actions on second-instance", assert.equal(calls.some((value) => value === "connectMpvClient"), true); }); -test("handleCliCommandService handles visibility and utility command dispatches", () => { +test("handleCliCommand handles visibility and utility command dispatches", () => { const cases: Array<{ args: Partial; expected: string; @@ -285,7 +285,7 @@ test("handleCliCommandService handles visibility and utility command dispatches" for (const entry of cases) { const { deps, calls } = createDeps(); - handleCliCommandService(makeArgs(entry.args), "initial", deps); + handleCliCommand(makeArgs(entry.args), "initial", deps); assert.ok( calls.includes(entry.expected), `expected call missing for args ${JSON.stringify(entry.args)}: ${entry.expected}`, @@ -293,22 +293,22 @@ test("handleCliCommandService handles visibility and utility command dispatches" } }); -test("handleCliCommandService runs refresh-known-words command", () => { +test("handleCliCommand runs refresh-known-words command", () => { const { deps, calls } = createDeps(); - handleCliCommandService(makeArgs({ refreshKnownWords: true }), "initial", deps); + handleCliCommand(makeArgs({ refreshKnownWords: true }), "initial", deps); assert.ok(calls.includes("refreshKnownWords")); }); -test("handleCliCommandService reports async refresh-known-words errors to OSD", async () => { +test("handleCliCommand reports async refresh-known-words errors to OSD", async () => { const { deps, calls, osd } = createDeps({ refreshKnownWords: async () => { throw new Error("refresh boom"); }, }); - handleCliCommandService(makeArgs({ refreshKnownWords: true }), "initial", deps); + handleCliCommand(makeArgs({ refreshKnownWords: true }), "initial", deps); await new Promise((resolve) => setImmediate(resolve)); assert.ok( diff --git a/src/core/services/cli-command-service.ts b/src/core/services/cli-command.ts similarity index 99% rename from src/core/services/cli-command-service.ts rename to src/core/services/cli-command.ts index 939114e..cd05d4e 100644 --- a/src/core/services/cli-command-service.ts +++ b/src/core/services/cli-command.ts @@ -116,7 +116,7 @@ export interface CliCommandDepsRuntimeOptions { error: (message: string, err: unknown) => void; } -export function createCliCommandDepsRuntimeService( +export function createCliCommandDepsRuntime( options: CliCommandDepsRuntimeOptions, ): CliCommandServiceDeps { return { @@ -189,7 +189,7 @@ function runAsyncWithOsd( }); } -export function handleCliCommandService( +export function handleCliCommand( args: CliArgs, source: CliCommandSource = "initial", deps: CliCommandServiceDeps, diff --git a/src/core/services/field-grouping-overlay-service.test.ts b/src/core/services/field-grouping-overlay.test.ts similarity index 82% rename from src/core/services/field-grouping-overlay-service.test.ts rename to src/core/services/field-grouping-overlay.test.ts index 37a1b42..0349215 100644 --- a/src/core/services/field-grouping-overlay-service.test.ts +++ b/src/core/services/field-grouping-overlay.test.ts @@ -1,15 +1,15 @@ import test from "node:test"; import assert from "node:assert/strict"; import { KikuFieldGroupingChoice } from "../../types"; -import { createFieldGroupingOverlayRuntimeService } from "./field-grouping-overlay-service"; +import { createFieldGroupingOverlayRuntime } from "./field-grouping-overlay"; -test("createFieldGroupingOverlayRuntimeService sends overlay messages and sets restore flag", () => { +test("createFieldGroupingOverlayRuntime sends overlay messages and sets restore flag", () => { const sent: unknown[][] = []; let visible = false; const restore = new Set<"runtime-options" | "subsync">(); const runtime = - createFieldGroupingOverlayRuntimeService<"runtime-options" | "subsync">({ + createFieldGroupingOverlayRuntime<"runtime-options" | "subsync">({ getMainWindow: () => ({ isDestroyed: () => false, webContents: { @@ -40,10 +40,10 @@ test("createFieldGroupingOverlayRuntimeService sends overlay messages and sets r assert.deepEqual(sent, [["runtime-options:open"]]); }); -test("createFieldGroupingOverlayRuntimeService callback cancels when send fails", async () => { +test("createFieldGroupingOverlayRuntime callback cancels when send fails", async () => { let resolver: ((choice: KikuFieldGroupingChoice) => void) | null = null; const runtime = - createFieldGroupingOverlayRuntimeService<"runtime-options" | "subsync">({ + createFieldGroupingOverlayRuntime<"runtime-options" | "subsync">({ getMainWindow: () => null, getVisibleOverlayVisible: () => false, getInvisibleOverlayVisible: () => false, diff --git a/src/core/services/field-grouping-overlay-service.ts b/src/core/services/field-grouping-overlay.ts similarity index 89% rename from src/core/services/field-grouping-overlay-service.ts rename to src/core/services/field-grouping-overlay.ts index c9224bc..c64808d 100644 --- a/src/core/services/field-grouping-overlay-service.ts +++ b/src/core/services/field-grouping-overlay.ts @@ -3,9 +3,9 @@ import { KikuFieldGroupingRequestData, } from "../../types"; import { - createFieldGroupingCallbackRuntimeService, - sendToVisibleOverlayRuntimeService, -} from "./overlay-bridge-service"; + createFieldGroupingCallbackRuntime, + sendToVisibleOverlayRuntime, +} from "./overlay-bridge"; interface WindowLike { isDestroyed: () => boolean; @@ -32,7 +32,7 @@ export interface FieldGroupingOverlayRuntimeOptions { ) => boolean; } -export function createFieldGroupingOverlayRuntimeService( +export function createFieldGroupingOverlayRuntime( options: FieldGroupingOverlayRuntimeOptions, ): { sendToVisibleOverlay: ( @@ -52,7 +52,7 @@ export function createFieldGroupingOverlayRuntimeService( if (options.sendToVisibleOverlay) { return options.sendToVisibleOverlay(channel, payload, runtimeOptions); } - return sendToVisibleOverlayRuntimeService({ + return sendToVisibleOverlayRuntime({ mainWindow: options.getMainWindow() as never, visibleOverlayVisible: options.getVisibleOverlayVisible(), setVisibleOverlayVisible: options.setVisibleOverlayVisible, @@ -67,7 +67,7 @@ export function createFieldGroupingOverlayRuntimeService( const createFieldGroupingCallback = (): (( data: KikuFieldGroupingRequestData, ) => Promise) => { - return createFieldGroupingCallbackRuntimeService({ + return createFieldGroupingCallbackRuntime({ getVisibleOverlayVisible: options.getVisibleOverlayVisible, getInvisibleOverlayVisible: options.getInvisibleOverlayVisible, setVisibleOverlayVisible: options.setVisibleOverlayVisible, diff --git a/src/core/services/field-grouping-service.ts b/src/core/services/field-grouping.ts similarity index 97% rename from src/core/services/field-grouping-service.ts rename to src/core/services/field-grouping.ts index 6c0fbe7..f88bc3f 100644 --- a/src/core/services/field-grouping-service.ts +++ b/src/core/services/field-grouping.ts @@ -3,7 +3,7 @@ import { KikuFieldGroupingRequestData, } from "../../types"; -export function createFieldGroupingCallbackService(options: { +export function createFieldGroupingCallback(options: { getVisibleOverlayVisible: () => boolean; getInvisibleOverlayVisible: () => boolean; setVisibleOverlayVisible: (visible: boolean) => void; diff --git a/src/core/services/frequency-dictionary-service.test.ts b/src/core/services/frequency-dictionary.test.ts similarity index 70% rename from src/core/services/frequency-dictionary-service.test.ts rename to src/core/services/frequency-dictionary.test.ts index 997c457..8f789d4 100644 --- a/src/core/services/frequency-dictionary-service.test.ts +++ b/src/core/services/frequency-dictionary.test.ts @@ -4,15 +4,15 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { createFrequencyDictionaryLookupService } from "./frequency-dictionary-service"; +import { createFrequencyDictionaryLookup } from "./frequency-dictionary"; -test("createFrequencyDictionaryLookupService logs parse errors and returns no-op for invalid dictionaries", async () => { +test("createFrequencyDictionaryLookup logs parse errors and returns no-op for invalid dictionaries", async () => { const logs: string[] = []; const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "subminer-frequency-dict-")); const bankPath = path.join(tempDir, "term_meta_bank_1.json"); fs.writeFileSync(bankPath, "{ invalid json"); - const lookup = await createFrequencyDictionaryLookupService({ + const lookup = await createFrequencyDictionaryLookup({ searchPaths: [tempDir], log: (message) => { logs.push(message); @@ -31,10 +31,10 @@ test("createFrequencyDictionaryLookupService logs parse errors and returns no-op ); }); -test("createFrequencyDictionaryLookupService continues with no-op lookup when search path is missing", async () => { +test("createFrequencyDictionaryLookup continues with no-op lookup when search path is missing", async () => { const logs: string[] = []; const missingPath = path.join(os.tmpdir(), "subminer-frequency-dict-missing-dir"); - const lookup = await createFrequencyDictionaryLookupService({ + const lookup = await createFrequencyDictionaryLookup({ searchPaths: [missingPath], log: (message) => { logs.push(message); diff --git a/src/core/services/frequency-dictionary-service.ts b/src/core/services/frequency-dictionary.ts similarity index 98% rename from src/core/services/frequency-dictionary-service.ts rename to src/core/services/frequency-dictionary.ts index 6523749..acedfac 100644 --- a/src/core/services/frequency-dictionary-service.ts +++ b/src/core/services/frequency-dictionary.ts @@ -145,7 +145,7 @@ function collectDictionaryFromPath( return terms; } -export async function createFrequencyDictionaryLookupService( +export async function createFrequencyDictionaryLookup( options: FrequencyDictionaryLookupOptions, ): Promise<(term: string) => number | null> { const attemptedPaths: string[] = []; diff --git a/src/core/services/index.ts b/src/core/services/index.ts index 56c328f..7581450 100644 --- a/src/core/services/index.ts +++ b/src/core/services/index.ts @@ -1,39 +1,39 @@ -export { TexthookerService } from "./texthooker-service"; -export { hasMpvWebsocketPlugin, SubtitleWebSocketService } from "./subtitle-ws-service"; -export { registerGlobalShortcutsService } from "./shortcut-service"; -export { createIpcDepsRuntimeService, registerIpcHandlersService } from "./ipc-service"; -export { shortcutMatchesInputForLocalFallback } from "./shortcut-fallback-service"; +export { Texthooker } from "./texthooker"; +export { hasMpvWebsocketPlugin, SubtitleWebSocket } from "./subtitle-ws"; +export { registerGlobalShortcuts } from "./shortcut"; +export { createIpcDepsRuntime, registerIpcHandlers } from "./ipc"; +export { shortcutMatchesInputForLocalFallback } from "./shortcut-fallback"; export { - refreshOverlayShortcutsRuntimeService, - registerOverlayShortcutsService, - syncOverlayShortcutsRuntimeService, - unregisterOverlayShortcutsRuntimeService, -} from "./overlay-shortcut-service"; + refreshOverlayShortcutsRuntime, + registerOverlayShortcuts, + syncOverlayShortcutsRuntime, + unregisterOverlayShortcutsRuntime, +} from "./overlay-shortcut"; export { createOverlayShortcutRuntimeHandlers } from "./overlay-shortcut-handler"; -export { createCliCommandDepsRuntimeService, handleCliCommandService } from "./cli-command-service"; +export { createCliCommandDepsRuntime, handleCliCommand } from "./cli-command"; export { - copyCurrentSubtitleService, - handleMineSentenceDigitService, - handleMultiCopyDigitService, - markLastCardAsAudioCardService, - mineSentenceCardService, - triggerFieldGroupingService, - updateLastCardFromClipboardService, -} from "./mining-service"; -export { createAppLifecycleDepsRuntimeService, startAppLifecycleService } from "./app-lifecycle-service"; + copyCurrentSubtitle, + handleMineSentenceDigit, + handleMultiCopyDigit, + markLastCardAsAudioCard, + mineSentenceCard, + triggerFieldGrouping, + updateLastCardFromClipboard, +} from "./mining"; +export { createAppLifecycleDepsRuntime, startAppLifecycle } from "./app-lifecycle"; export { - cycleSecondarySubModeService, -} from "./subtitle-position-service"; + cycleSecondarySubMode, +} from "./subtitle-position"; export { - getInitialInvisibleOverlayVisibilityService, - isAutoUpdateEnabledRuntimeService, - shouldAutoInitializeOverlayRuntimeFromConfigService, - shouldBindVisibleOverlayToMpvSubVisibilityService, -} from "./startup-service"; -export { openYomitanSettingsWindow } from "./yomitan-settings-service"; -export { createTokenizerDepsRuntimeService, tokenizeSubtitleService } from "./tokenizer-service"; -export { createFrequencyDictionaryLookupService } from "./frequency-dictionary-service"; -export { createJlptVocabularyLookupService } from "./jlpt-vocab-service"; + getInitialInvisibleOverlayVisibility, + isAutoUpdateEnabledRuntime, + shouldAutoInitializeOverlayRuntimeFromConfig, + shouldBindVisibleOverlayToMpvSubVisibility, +} from "./startup"; +export { openYomitanSettingsWindow } from "./yomitan-settings"; +export { createTokenizerDepsRuntime, tokenizeSubtitle } from "./tokenizer"; +export { createFrequencyDictionaryLookup } from "./frequency-dictionary"; +export { createJlptVocabularyLookup } from "./jlpt-vocab"; export { getIgnoredPos1Entries, JlptIgnoredPos1Entry, @@ -44,59 +44,59 @@ export { shouldIgnoreJlptByTerm, shouldIgnoreJlptForMecabPos1, } from "./jlpt-token-filter"; -export { loadYomitanExtensionService } from "./yomitan-extension-loader-service"; +export { loadYomitanExtension } from "./yomitan-extension-loader"; export { - getJimakuLanguagePreferenceService, - getJimakuMaxEntryResultsService, - jimakuFetchJsonService, - resolveJimakuApiKeyService, -} from "./jimaku-service"; + getJimakuLanguagePreference, + getJimakuMaxEntryResults, + jimakuFetchJson, + resolveJimakuApiKey, +} from "./jimaku"; export { - loadSubtitlePositionService, - saveSubtitlePositionService, - updateCurrentMediaPathService, -} from "./subtitle-position-service"; + loadSubtitlePosition, + saveSubtitlePosition, + updateCurrentMediaPath, +} from "./subtitle-position"; export { - createOverlayWindowService, - enforceOverlayLayerOrderService, - ensureOverlayWindowLevelService, - updateOverlayWindowBoundsService, -} from "./overlay-window-service"; -export { initializeOverlayRuntimeService } from "./overlay-runtime-init-service"; + createOverlayWindow, + enforceOverlayLayerOrder, + ensureOverlayWindowLevel, + updateOverlayWindowBounds, +} from "./overlay-window"; +export { initializeOverlayRuntime } from "./overlay-runtime-init"; export { - setInvisibleOverlayVisibleService, - setVisibleOverlayVisibleService, - syncInvisibleOverlayMousePassthroughService, - updateInvisibleOverlayVisibilityService, - updateVisibleOverlayVisibilityService, -} from "./overlay-visibility-service"; + setInvisibleOverlayVisible, + setVisibleOverlayVisible, + syncInvisibleOverlayMousePassthrough, + updateInvisibleOverlayVisibility, + updateVisibleOverlayVisibility, +} from "./overlay-visibility"; export { MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY, MpvIpcClient, MpvRuntimeClientLike, MpvTrackProperty, - playNextSubtitleRuntimeService, - replayCurrentSubtitleRuntimeService, + playNextSubtitleRuntime, + replayCurrentSubtitleRuntime, resolveCurrentAudioStreamIndex, - sendMpvCommandRuntimeService, - setMpvSubVisibilityRuntimeService, - showMpvOsdRuntimeService, -} from "./mpv-service"; + sendMpvCommandRuntime, + setMpvSubVisibilityRuntime, + showMpvOsdRuntime, +} from "./mpv"; export { - applyMpvSubtitleRenderMetricsPatchService, + applyMpvSubtitleRenderMetricsPatch, DEFAULT_MPV_SUBTITLE_RENDER_METRICS, sanitizeMpvSubtitleRenderMetrics, -} from "./mpv-render-metrics-service"; -export { createOverlayContentMeasurementStoreService } from "./overlay-content-measurement-service"; -export { handleMpvCommandFromIpcService } from "./ipc-command-service"; +} from "./mpv-render-metrics"; +export { createOverlayContentMeasurementStore } from "./overlay-content-measurement"; +export { handleMpvCommandFromIpc } from "./ipc-command"; +export { createFieldGroupingOverlayRuntime } from "./field-grouping-overlay"; +export { createNumericShortcutRuntime } from "./numeric-shortcut"; +export { runStartupBootstrapRuntime } from "./startup"; +export { runSubsyncManualFromIpcRuntime, triggerSubsyncFromConfigRuntime } from "./subsync-runner"; +export { registerAnkiJimakuIpcRuntime } from "./anki-jimaku"; export { ImmersionTrackerService } from "./immersion-tracker-service"; -export { createFieldGroupingOverlayRuntimeService } from "./field-grouping-overlay-service"; -export { createNumericShortcutRuntimeService } from "./numeric-shortcut-service"; -export { runStartupBootstrapRuntimeService } from "./startup-service"; -export { runSubsyncManualFromIpcRuntimeService, triggerSubsyncFromConfigRuntimeService } from "./subsync-runner-service"; -export { registerAnkiJimakuIpcRuntimeService } from "./anki-jimaku-service"; export { - broadcastRuntimeOptionsChangedRuntimeService, - createOverlayManagerService, - setOverlayDebugVisualizationEnabledRuntimeService, -} from "./overlay-manager-service"; + broadcastRuntimeOptionsChangedRuntime, + createOverlayManager, + setOverlayDebugVisualizationEnabledRuntime, +} from "./overlay-manager"; diff --git a/src/core/services/ipc-command-service.ts b/src/core/services/ipc-command.ts similarity index 96% rename from src/core/services/ipc-command-service.ts rename to src/core/services/ipc-command.ts index d5defe6..1c7b637 100644 --- a/src/core/services/ipc-command-service.ts +++ b/src/core/services/ipc-command.ts @@ -28,7 +28,7 @@ export interface HandleMpvCommandFromIpcOptions { hasRuntimeOptionsManager: () => boolean; } -export function handleMpvCommandFromIpcService( +export function handleMpvCommandFromIpc( command: (string | number)[], options: HandleMpvCommandFromIpcOptions, ): void { @@ -66,7 +66,7 @@ export function handleMpvCommandFromIpcService( } } -export async function runSubsyncManualFromIpcService( +export async function runSubsyncManualFromIpc( request: SubsyncManualRunRequest, options: { isSubsyncInProgress: () => boolean; diff --git a/src/core/services/ipc-service.ts b/src/core/services/ipc.ts similarity index 98% rename from src/core/services/ipc-service.ts rename to src/core/services/ipc.ts index 9aaff25..ce8309b 100644 --- a/src/core/services/ipc-service.ts +++ b/src/core/services/ipc.ts @@ -84,7 +84,7 @@ export interface IpcDepsRuntimeOptions { reportOverlayContentBounds: (payload: unknown) => void; } -export function createIpcDepsRuntimeService( +export function createIpcDepsRuntime( options: IpcDepsRuntimeOptions, ): IpcServiceDeps { return { @@ -143,7 +143,7 @@ export function createIpcDepsRuntimeService( }; } -export function registerIpcHandlersService(deps: IpcServiceDeps): void { +export function registerIpcHandlers(deps: IpcServiceDeps): void { ipcMain.on( "set-ignore-mouse-events", ( diff --git a/src/core/services/jimaku-service.ts b/src/core/services/jimaku.ts similarity index 72% rename from src/core/services/jimaku-service.ts rename to src/core/services/jimaku.ts index 55769d3..ce5797c 100644 --- a/src/core/services/jimaku-service.ts +++ b/src/core/services/jimaku.ts @@ -8,34 +8,34 @@ import { resolveJimakuApiKey as resolveJimakuApiKeyFromConfig, } from "../../jimaku/utils"; -export function getJimakuConfigService( +export function getJimakuConfig( getResolvedConfig: () => { jimaku?: JimakuConfig }, ): JimakuConfig { const config = getResolvedConfig(); return config.jimaku ?? {}; } -export function getJimakuBaseUrlService( +export function getJimakuBaseUrl( getResolvedConfig: () => { jimaku?: JimakuConfig }, defaultBaseUrl: string, ): string { - const config = getJimakuConfigService(getResolvedConfig); + const config = getJimakuConfig(getResolvedConfig); return config.apiBaseUrl || defaultBaseUrl; } -export function getJimakuLanguagePreferenceService( +export function getJimakuLanguagePreference( getResolvedConfig: () => { jimaku?: JimakuConfig }, defaultPreference: JimakuLanguagePreference, ): JimakuLanguagePreference { - const config = getJimakuConfigService(getResolvedConfig); + const config = getJimakuConfig(getResolvedConfig); return config.languagePreference || defaultPreference; } -export function getJimakuMaxEntryResultsService( +export function getJimakuMaxEntryResults( getResolvedConfig: () => { jimaku?: JimakuConfig }, defaultValue: number, ): number { - const config = getJimakuConfigService(getResolvedConfig); + const config = getJimakuConfig(getResolvedConfig); const value = config.maxEntryResults; if (typeof value === "number" && Number.isFinite(value) && value > 0) { return Math.floor(value); @@ -43,13 +43,13 @@ export function getJimakuMaxEntryResultsService( return defaultValue; } -export async function resolveJimakuApiKeyService( +export async function resolveJimakuApiKey( getResolvedConfig: () => { jimaku?: JimakuConfig }, ): Promise { - return resolveJimakuApiKeyFromConfig(getJimakuConfigService(getResolvedConfig)); + return resolveJimakuApiKeyFromConfig(getJimakuConfig(getResolvedConfig)); } -export async function jimakuFetchJsonService( +export async function jimakuFetchJson( endpoint: string, query: Record = {}, options: { @@ -59,7 +59,7 @@ export async function jimakuFetchJsonService( defaultLanguagePreference: JimakuLanguagePreference; }, ): Promise> { - const apiKey = await resolveJimakuApiKeyService(options.getResolvedConfig); + const apiKey = await resolveJimakuApiKey(options.getResolvedConfig); if (!apiKey) { return { ok: false, @@ -72,7 +72,7 @@ export async function jimakuFetchJsonService( } return jimakuFetchJsonRequest(endpoint, query, { - baseUrl: getJimakuBaseUrlService( + baseUrl: getJimakuBaseUrl( options.getResolvedConfig, options.defaultBaseUrl, ), diff --git a/src/core/services/jlpt-vocab-service.ts b/src/core/services/jlpt-vocab.ts similarity index 98% rename from src/core/services/jlpt-vocab-service.ts rename to src/core/services/jlpt-vocab.ts index 00aa99e..52626c7 100644 --- a/src/core/services/jlpt-vocab-service.ts +++ b/src/core/services/jlpt-vocab.ts @@ -134,7 +134,7 @@ function collectDictionaryFromPath( return terms; } -export async function createJlptVocabularyLookupService( +export async function createJlptVocabularyLookup( options: JlptVocabLookupOptions, ): Promise<(term: string) => JlptLevel | null> { const attemptedPaths: string[] = []; diff --git a/src/core/services/mining-service.test.ts b/src/core/services/mining.test.ts similarity index 83% rename from src/core/services/mining-service.test.ts rename to src/core/services/mining.test.ts index 34bf4bf..8a00dca 100644 --- a/src/core/services/mining-service.test.ts +++ b/src/core/services/mining.test.ts @@ -1,24 +1,24 @@ import test from "node:test"; import assert from "node:assert/strict"; import { - copyCurrentSubtitleService, - handleMineSentenceDigitService, - handleMultiCopyDigitService, - mineSentenceCardService, -} from "./mining-service"; + copyCurrentSubtitle, + handleMineSentenceDigit, + handleMultiCopyDigit, + mineSentenceCard, +} from "./mining"; -test("copyCurrentSubtitleService reports tracker and subtitle guards", () => { +test("copyCurrentSubtitle reports tracker and subtitle guards", () => { const osd: string[] = []; const copied: string[] = []; - copyCurrentSubtitleService({ + copyCurrentSubtitle({ subtitleTimingTracker: null, writeClipboardText: (text) => copied.push(text), showMpvOsd: (text) => osd.push(text), }); assert.equal(osd.at(-1), "Subtitle tracker not available"); - copyCurrentSubtitleService({ + copyCurrentSubtitle({ subtitleTimingTracker: { getRecentBlocks: () => [], getCurrentSubtitle: () => null, @@ -31,11 +31,11 @@ test("copyCurrentSubtitleService reports tracker and subtitle guards", () => { assert.deepEqual(copied, []); }); -test("copyCurrentSubtitleService copies current subtitle text", () => { +test("copyCurrentSubtitle copies current subtitle text", () => { const osd: string[] = []; const copied: string[] = []; - copyCurrentSubtitleService({ + copyCurrentSubtitle({ subtitleTimingTracker: { getRecentBlocks: () => [], getCurrentSubtitle: () => "hello world", @@ -49,11 +49,11 @@ test("copyCurrentSubtitleService copies current subtitle text", () => { assert.equal(osd.at(-1), "Copied subtitle"); }); -test("mineSentenceCardService handles missing integration and disconnected mpv", async () => { +test("mineSentenceCard handles missing integration and disconnected mpv", async () => { const osd: string[] = []; assert.equal( - await mineSentenceCardService({ + await mineSentenceCard({ ankiIntegration: null, mpvClient: null, showMpvOsd: (text) => osd.push(text), @@ -62,8 +62,8 @@ test("mineSentenceCardService handles missing integration and disconnected mpv", ); assert.equal(osd.at(-1), "AnkiConnect integration not enabled"); - assert.equal( - await mineSentenceCardService({ + assert.equal( + await mineSentenceCard({ ankiIntegration: { updateLastAddedFromClipboard: async () => {}, triggerFieldGroupingForLastAddedCard: async () => {}, @@ -84,7 +84,7 @@ test("mineSentenceCardService handles missing integration and disconnected mpv", assert.equal(osd.at(-1), "MPV not connected"); }); -test("mineSentenceCardService creates sentence card from mpv subtitle state", async () => { +test("mineSentenceCard creates sentence card from mpv subtitle state", async () => { const created: Array<{ sentence: string; startTime: number; @@ -92,7 +92,7 @@ test("mineSentenceCardService creates sentence card from mpv subtitle state", as secondarySub?: string; }> = []; - const createdCard = await mineSentenceCardService({ + const createdCard = await mineSentenceCard({ ankiIntegration: { updateLastAddedFromClipboard: async () => {}, triggerFieldGroupingForLastAddedCard: async () => {}, @@ -123,11 +123,11 @@ test("mineSentenceCardService creates sentence card from mpv subtitle state", as ]); }); -test("handleMultiCopyDigitService copies available history and reports truncation", () => { +test("handleMultiCopyDigit copies available history and reports truncation", () => { const osd: string[] = []; const copied: string[] = []; - handleMultiCopyDigitService(5, { + handleMultiCopyDigit(5, { subtitleTimingTracker: { getRecentBlocks: (count) => ["a", "b"].slice(0, count), getCurrentSubtitle: () => null, @@ -141,12 +141,12 @@ test("handleMultiCopyDigitService copies available history and reports truncatio assert.equal(osd.at(-1), "Only 2 lines available, copied 2"); }); -test("handleMineSentenceDigitService reports async create failures", async () => { +test("handleMineSentenceDigit reports async create failures", async () => { const osd: string[] = []; const logs: Array<{ message: string; err: unknown }> = []; let cardsMined = 0; - handleMineSentenceDigitService(2, { + handleMineSentenceDigit(2, { subtitleTimingTracker: { getRecentBlocks: () => ["one", "two"], getCurrentSubtitle: () => null, @@ -184,7 +184,7 @@ test("handleMineSentenceDigitService increments successful card count", async () const osd: string[] = []; let cardsMined = 0; - handleMineSentenceDigitService(2, { + handleMineSentenceDigit(2, { subtitleTimingTracker: { getRecentBlocks: () => ["one", "two"], getCurrentSubtitle: () => null, diff --git a/src/core/services/mining-service.ts b/src/core/services/mining.ts similarity index 93% rename from src/core/services/mining-service.ts rename to src/core/services/mining.ts index afb266d..137e698 100644 --- a/src/core/services/mining-service.ts +++ b/src/core/services/mining.ts @@ -24,7 +24,7 @@ interface MpvClientLike { currentSecondarySubText?: string; } -export function handleMultiCopyDigitService( +export function handleMultiCopyDigit( count: number, deps: { subtitleTimingTracker: SubtitleTimingTrackerLike | null; @@ -50,7 +50,7 @@ export function handleMultiCopyDigitService( } } -export function copyCurrentSubtitleService(deps: { +export function copyCurrentSubtitle(deps: { subtitleTimingTracker: SubtitleTimingTrackerLike | null; writeClipboardText: (text: string) => void; showMpvOsd: (text: string) => void; @@ -79,7 +79,7 @@ function requireAnkiIntegration( return ankiIntegration; } -export async function updateLastCardFromClipboardService(deps: { +export async function updateLastCardFromClipboard(deps: { ankiIntegration: AnkiIntegrationLike | null; readClipboardText: () => string; showMpvOsd: (text: string) => void; @@ -89,7 +89,7 @@ export async function updateLastCardFromClipboardService(deps: { await anki.updateLastAddedFromClipboard(deps.readClipboardText()); } -export async function triggerFieldGroupingService(deps: { +export async function triggerFieldGrouping(deps: { ankiIntegration: AnkiIntegrationLike | null; showMpvOsd: (text: string) => void; }): Promise { @@ -98,7 +98,7 @@ export async function triggerFieldGroupingService(deps: { await anki.triggerFieldGroupingForLastAddedCard(); } -export async function markLastCardAsAudioCardService(deps: { +export async function markLastCardAsAudioCard(deps: { ankiIntegration: AnkiIntegrationLike | null; showMpvOsd: (text: string) => void; }): Promise { @@ -107,7 +107,7 @@ export async function markLastCardAsAudioCardService(deps: { await anki.markLastCardAsAudioCard(); } -export async function mineSentenceCardService(deps: { +export async function mineSentenceCard(deps: { ankiIntegration: AnkiIntegrationLike | null; mpvClient: MpvClientLike | null; showMpvOsd: (text: string) => void; @@ -133,7 +133,7 @@ export async function mineSentenceCardService(deps: { ); } -export function handleMineSentenceDigitService( +export function handleMineSentenceDigit( count: number, deps: { subtitleTimingTracker: SubtitleTimingTrackerLike | null; diff --git a/src/core/services/mpv-control-service.test.ts b/src/core/services/mpv-control.test.ts similarity index 65% rename from src/core/services/mpv-control-service.test.ts rename to src/core/services/mpv-control.test.ts index 4f69ed1..6f75822 100644 --- a/src/core/services/mpv-control-service.test.ts +++ b/src/core/services/mpv-control.test.ts @@ -1,16 +1,16 @@ import test from "node:test"; import assert from "node:assert/strict"; import { - playNextSubtitleRuntimeService, - replayCurrentSubtitleRuntimeService, - sendMpvCommandRuntimeService, - setMpvSubVisibilityRuntimeService, - showMpvOsdRuntimeService, -} from "./mpv-service"; + playNextSubtitleRuntime, + replayCurrentSubtitleRuntime, + sendMpvCommandRuntime, + setMpvSubVisibilityRuntime, + showMpvOsdRuntime, +} from "./mpv"; -test("showMpvOsdRuntimeService sends show-text when connected", () => { +test("showMpvOsdRuntime sends show-text when connected", () => { const commands: (string | number)[][] = []; - showMpvOsdRuntimeService( + showMpvOsdRuntime( { connected: true, send: ({ command }) => { @@ -22,9 +22,9 @@ test("showMpvOsdRuntimeService sends show-text when connected", () => { assert.deepEqual(commands, [["show-text", "hello", "3000"]]); }); -test("showMpvOsdRuntimeService logs fallback when disconnected", () => { +test("showMpvOsdRuntime logs fallback when disconnected", () => { const logs: string[] = []; - showMpvOsdRuntimeService( + showMpvOsdRuntime( { connected: false, send: () => {}, @@ -55,10 +55,10 @@ test("mpv runtime command wrappers call expected client methods", () => { }, }; - replayCurrentSubtitleRuntimeService(client); - playNextSubtitleRuntimeService(client); - sendMpvCommandRuntimeService(client, ["script-message", "x"]); - setMpvSubVisibilityRuntimeService(client, false); + replayCurrentSubtitleRuntime(client); + playNextSubtitleRuntime(client); + sendMpvCommandRuntime(client, ["script-message", "x"]); + setMpvSubVisibilityRuntime(client, false); assert.deepEqual(calls, [ "replay", diff --git a/src/core/services/mpv-render-metrics-service.test.ts b/src/core/services/mpv-render-metrics-service.test.ts deleted file mode 100644 index 9bd005d..0000000 --- a/src/core/services/mpv-render-metrics-service.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { MpvSubtitleRenderMetrics } from "../../types"; -import { - applyMpvSubtitleRenderMetricsPatchService, - DEFAULT_MPV_SUBTITLE_RENDER_METRICS, -} from "./mpv-render-metrics-service"; - -const BASE: MpvSubtitleRenderMetrics = { - ...DEFAULT_MPV_SUBTITLE_RENDER_METRICS, -}; - -test("applyMpvSubtitleRenderMetricsPatchService returns unchanged on empty patch", () => { - const { next, changed } = applyMpvSubtitleRenderMetricsPatchService(BASE, {}); - assert.equal(changed, false); - assert.deepEqual(next, BASE); -}); - -test("applyMpvSubtitleRenderMetricsPatchService reports changed when patch modifies value", () => { - const { next, changed } = applyMpvSubtitleRenderMetricsPatchService(BASE, { - subPos: 95, - }); - assert.equal(changed, true); - assert.equal(next.subPos, 95); -}); diff --git a/src/core/services/mpv-render-metrics.test.ts b/src/core/services/mpv-render-metrics.test.ts new file mode 100644 index 0000000..cbd9bc6 --- /dev/null +++ b/src/core/services/mpv-render-metrics.test.ts @@ -0,0 +1,25 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { MpvSubtitleRenderMetrics } from "../../types"; +import { + applyMpvSubtitleRenderMetricsPatch, + DEFAULT_MPV_SUBTITLE_RENDER_METRICS, +} from "./mpv-render-metrics"; + +const BASE: MpvSubtitleRenderMetrics = { + ...DEFAULT_MPV_SUBTITLE_RENDER_METRICS, +}; + +test("applyMpvSubtitleRenderMetricsPatch returns unchanged on empty patch", () => { + const { next, changed } = applyMpvSubtitleRenderMetricsPatch(BASE, {}); + assert.equal(changed, false); + assert.deepEqual(next, BASE); +}); + +test("applyMpvSubtitleRenderMetricsPatch reports changed when patch modifies value", () => { + const { next, changed } = applyMpvSubtitleRenderMetricsPatch(BASE, { + subPos: 95, + }); + assert.equal(changed, true); + assert.equal(next.subPos, 95); +}); diff --git a/src/core/services/mpv-render-metrics-service.ts b/src/core/services/mpv-render-metrics.ts similarity index 93% rename from src/core/services/mpv-render-metrics-service.ts rename to src/core/services/mpv-render-metrics.ts index 564f761..784880a 100644 --- a/src/core/services/mpv-render-metrics-service.ts +++ b/src/core/services/mpv-render-metrics.ts @@ -25,10 +25,10 @@ export function sanitizeMpvSubtitleRenderMetrics( patch: Partial | null | undefined, ): MpvSubtitleRenderMetrics { if (!patch) return current; - return updateMpvSubtitleRenderMetricsService(current, patch); + return updateMpvSubtitleRenderMetrics(current, patch); } -export function updateMpvSubtitleRenderMetricsService( +export function updateMpvSubtitleRenderMetrics( current: MpvSubtitleRenderMetrics, patch: Partial, ): MpvSubtitleRenderMetrics { @@ -83,11 +83,11 @@ export function updateMpvSubtitleRenderMetricsService( }; } -export function applyMpvSubtitleRenderMetricsPatchService( +export function applyMpvSubtitleRenderMetricsPatch( current: MpvSubtitleRenderMetrics, patch: Partial, ): { next: MpvSubtitleRenderMetrics; changed: boolean } { - const next = updateMpvSubtitleRenderMetricsService(current, patch); + const next = updateMpvSubtitleRenderMetrics(current, patch); const changed = next.subPos !== current.subPos || next.subFontSize !== current.subFontSize || diff --git a/src/core/services/mpv-state.test.ts b/src/core/services/mpv-state.test.ts index 14bc89c..508108b 100644 --- a/src/core/services/mpv-state.test.ts +++ b/src/core/services/mpv-state.test.ts @@ -1,6 +1,6 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { resolveCurrentAudioStreamIndex } from "./mpv-service"; +import { resolveCurrentAudioStreamIndex } from "./mpv"; test("resolveCurrentAudioStreamIndex returns selected ff-index when no current track id", () => { assert.equal( diff --git a/src/core/services/mpv-service.test.ts b/src/core/services/mpv.test.ts similarity index 99% rename from src/core/services/mpv-service.test.ts rename to src/core/services/mpv.test.ts index ce10026..f854cc4 100644 --- a/src/core/services/mpv-service.test.ts +++ b/src/core/services/mpv.test.ts @@ -5,7 +5,7 @@ import { MpvIpcClientDeps, MpvIpcClientProtocolDeps, MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY, -} from "./mpv-service"; +} from "./mpv"; import { MPV_REQUEST_ID_TRACK_LIST_AUDIO } from "./mpv-protocol"; function makeDeps( diff --git a/src/core/services/mpv-service.ts b/src/core/services/mpv.ts similarity index 98% rename from src/core/services/mpv-service.ts rename to src/core/services/mpv.ts index a808767..c99c4d9 100644 --- a/src/core/services/mpv-service.ts +++ b/src/core/services/mpv.ts @@ -55,7 +55,7 @@ export interface MpvRuntimeClientLike { setSubVisibility?: (visible: boolean) => void; } -export function showMpvOsdRuntimeService( +export function showMpvOsdRuntime( mpvClient: MpvRuntimeClientLike | null, text: string, fallbackLog: (text: string) => void = (line) => logger.info(line), @@ -67,21 +67,21 @@ export function showMpvOsdRuntimeService( fallbackLog(`OSD (MPV not connected): ${text}`); } -export function replayCurrentSubtitleRuntimeService( +export function replayCurrentSubtitleRuntime( mpvClient: MpvRuntimeClientLike | null, ): void { if (!mpvClient?.replayCurrentSubtitle) return; mpvClient.replayCurrentSubtitle(); } -export function playNextSubtitleRuntimeService( +export function playNextSubtitleRuntime( mpvClient: MpvRuntimeClientLike | null, ): void { if (!mpvClient?.playNextSubtitle) return; mpvClient.playNextSubtitle(); } -export function sendMpvCommandRuntimeService( +export function sendMpvCommandRuntime( mpvClient: MpvRuntimeClientLike | null, command: (string | number)[], ): void { @@ -89,7 +89,7 @@ export function sendMpvCommandRuntimeService( mpvClient.send({ command }); } -export function setMpvSubVisibilityRuntimeService( +export function setMpvSubVisibilityRuntime( mpvClient: MpvRuntimeClientLike | null, visible: boolean, ): void { diff --git a/src/core/services/numeric-shortcut-session-service.test.ts b/src/core/services/numeric-shortcut-session.test.ts similarity index 89% rename from src/core/services/numeric-shortcut-session-service.test.ts rename to src/core/services/numeric-shortcut-session.test.ts index c5d699a..d7a2cd1 100644 --- a/src/core/services/numeric-shortcut-session-service.test.ts +++ b/src/core/services/numeric-shortcut-session.test.ts @@ -1,17 +1,17 @@ import test from "node:test"; import assert from "node:assert/strict"; import { - createNumericShortcutRuntimeService, - createNumericShortcutSessionService, -} from "./numeric-shortcut-service"; + createNumericShortcutRuntime, + createNumericShortcutSession, +} from "./numeric-shortcut"; -test("createNumericShortcutRuntimeService creates sessions wired to globalShortcut", () => { +test("createNumericShortcutRuntime creates sessions wired to globalShortcut", () => { const registered: string[] = []; const unregistered: string[] = []; const osd: string[] = []; const handlers = new Map void>(); - const runtime = createNumericShortcutRuntimeService({ + const runtime = createNumericShortcutRuntime({ globalShortcut: { register: (accelerator, callback) => { registered.push(accelerator); @@ -54,7 +54,7 @@ test("numeric shortcut session handles digit selection and unregisters shortcuts const handlers = new Map void>(); const unregistered: string[] = []; const osd: string[] = []; - const session = createNumericShortcutSessionService({ + const session = createNumericShortcutSession({ registerShortcut: (accelerator, handler) => { handlers.set(accelerator, handler); return true; @@ -96,7 +96,7 @@ test("numeric shortcut session handles digit selection and unregisters shortcuts test("numeric shortcut session emits timeout message", () => { const osd: string[] = []; - const session = createNumericShortcutSessionService({ + const session = createNumericShortcutSession({ registerShortcut: () => true, unregisterShortcut: () => {}, setTimer: (handler) => { @@ -126,7 +126,7 @@ test("numeric shortcut session emits timeout message", () => { test("numeric shortcut session handles escape cancellation", () => { const handlers = new Map void>(); const osd: string[] = []; - const session = createNumericShortcutSessionService({ + const session = createNumericShortcutSession({ registerShortcut: (accelerator, handler) => { handlers.set(accelerator, handler); return true; diff --git a/src/core/services/numeric-shortcut-service.ts b/src/core/services/numeric-shortcut.ts similarity index 95% rename from src/core/services/numeric-shortcut-service.ts rename to src/core/services/numeric-shortcut.ts index c6fd1ea..2607f64 100644 --- a/src/core/services/numeric-shortcut-service.ts +++ b/src/core/services/numeric-shortcut.ts @@ -13,11 +13,11 @@ export interface NumericShortcutRuntimeOptions { clearTimer: (timer: ReturnType) => void; } -export function createNumericShortcutRuntimeService( +export function createNumericShortcutRuntime( options: NumericShortcutRuntimeOptions, ) { const createSession = () => - createNumericShortcutSessionService({ + createNumericShortcutSession({ registerShortcut: (accelerator, handler) => options.globalShortcut.register(accelerator, handler), unregisterShortcut: (accelerator) => @@ -52,7 +52,7 @@ export interface NumericShortcutSessionStartParams { messages: NumericShortcutSessionMessages; } -export function createNumericShortcutSessionService( +export function createNumericShortcutSession( deps: NumericShortcutSessionDeps, ) { let active = false; diff --git a/src/core/services/overlay-bridge-service.test.ts b/src/core/services/overlay-bridge.test.ts similarity index 80% rename from src/core/services/overlay-bridge-service.test.ts rename to src/core/services/overlay-bridge.test.ts index 17d5942..c24ebeb 100644 --- a/src/core/services/overlay-bridge-service.test.ts +++ b/src/core/services/overlay-bridge.test.ts @@ -2,16 +2,16 @@ import test from "node:test"; import assert from "node:assert/strict"; import { KikuFieldGroupingChoice } from "../../types"; import { - createFieldGroupingCallbackRuntimeService, - sendToVisibleOverlayRuntimeService, -} from "./overlay-bridge-service"; + createFieldGroupingCallbackRuntime, + sendToVisibleOverlayRuntime, +} from "./overlay-bridge"; -test("sendToVisibleOverlayRuntimeService restores visibility flag when opening hidden overlay modal", () => { +test("sendToVisibleOverlayRuntime restores visibility flag when opening hidden overlay modal", () => { const sent: unknown[][] = []; const restoreSet = new Set<"runtime-options" | "subsync">(); let visibleOverlayVisible = false; - const ok = sendToVisibleOverlayRuntimeService({ + const ok = sendToVisibleOverlayRuntime({ mainWindow: { isDestroyed: () => false, webContents: { @@ -36,9 +36,9 @@ test("sendToVisibleOverlayRuntimeService restores visibility flag when opening h assert.deepEqual(sent, [["runtime-options:open"]]); }); -test("createFieldGroupingCallbackRuntimeService cancels when overlay request cannot be sent", async () => { +test("createFieldGroupingCallbackRuntime cancels when overlay request cannot be sent", async () => { let resolver: ((choice: KikuFieldGroupingChoice) => void) | null = null; - const callback = createFieldGroupingCallbackRuntimeService< + const callback = createFieldGroupingCallbackRuntime< "runtime-options" | "subsync" >({ getVisibleOverlayVisible: () => false, diff --git a/src/core/services/overlay-bridge-service.ts b/src/core/services/overlay-bridge.ts similarity index 89% rename from src/core/services/overlay-bridge-service.ts rename to src/core/services/overlay-bridge.ts index ad31ec6..c6be82c 100644 --- a/src/core/services/overlay-bridge-service.ts +++ b/src/core/services/overlay-bridge.ts @@ -2,10 +2,10 @@ import { KikuFieldGroupingChoice, KikuFieldGroupingRequestData, } from "../../types"; -import { createFieldGroupingCallbackService } from "./field-grouping-service"; +import { createFieldGroupingCallback } from "./field-grouping"; import { BrowserWindow } from "electron"; -export function sendToVisibleOverlayRuntimeService(options: { +export function sendToVisibleOverlayRuntime(options: { mainWindow: BrowserWindow | null; visibleOverlayVisible: boolean; setVisibleOverlayVisible: (visible: boolean) => void; @@ -45,7 +45,7 @@ export function sendToVisibleOverlayRuntimeService(options: { return true; } -export function createFieldGroupingCallbackRuntimeService( +export function createFieldGroupingCallbackRuntime( options: { getVisibleOverlayVisible: () => boolean; getInvisibleOverlayVisible: () => boolean; @@ -62,7 +62,7 @@ export function createFieldGroupingCallbackRuntimeService( ) => boolean; }, ): (data: KikuFieldGroupingRequestData) => Promise { - return createFieldGroupingCallbackService({ + return createFieldGroupingCallback({ getVisibleOverlayVisible: options.getVisibleOverlayVisible, getInvisibleOverlayVisible: options.getInvisibleOverlayVisible, setVisibleOverlayVisible: options.setVisibleOverlayVisible, diff --git a/src/core/services/overlay-content-measurement-service.test.ts b/src/core/services/overlay-content-measurement.test.ts similarity index 90% rename from src/core/services/overlay-content-measurement-service.test.ts rename to src/core/services/overlay-content-measurement.test.ts index 47dbb99..149783d 100644 --- a/src/core/services/overlay-content-measurement-service.test.ts +++ b/src/core/services/overlay-content-measurement.test.ts @@ -2,9 +2,9 @@ import test from "node:test"; import assert from "node:assert/strict"; import { - createOverlayContentMeasurementStoreService, + createOverlayContentMeasurementStore, sanitizeOverlayContentMeasurement, -} from "./overlay-content-measurement-service"; +} from "./overlay-content-measurement"; test("sanitizeOverlayContentMeasurement accepts valid payload with null rect", () => { const measurement = sanitizeOverlayContentMeasurement( @@ -40,7 +40,7 @@ test("sanitizeOverlayContentMeasurement rejects invalid ranges", () => { }); test("overlay measurement store keeps latest payload per layer", () => { - const store = createOverlayContentMeasurementStoreService({ + const store = createOverlayContentMeasurementStore({ now: () => 1000, warn: () => { // noop @@ -69,7 +69,7 @@ test("overlay measurement store keeps latest payload per layer", () => { test("overlay measurement store rate-limits invalid payload warnings", () => { let now = 1_000; const warnings: string[] = []; - const store = createOverlayContentMeasurementStoreService({ + const store = createOverlayContentMeasurementStore({ now: () => now, warn: (message) => { warnings.push(message); diff --git a/src/core/services/overlay-content-measurement-service.ts b/src/core/services/overlay-content-measurement.ts similarity index 98% rename from src/core/services/overlay-content-measurement-service.ts rename to src/core/services/overlay-content-measurement.ts index 214549e..265a047 100644 --- a/src/core/services/overlay-content-measurement-service.ts +++ b/src/core/services/overlay-content-measurement.ts @@ -105,7 +105,7 @@ function readFiniteInRange( return value; } -export function createOverlayContentMeasurementStoreService(options?: { +export function createOverlayContentMeasurementStore(options?: { now?: () => number; warn?: (message: string) => void; }) { diff --git a/src/core/services/overlay-manager-service.test.ts b/src/core/services/overlay-manager.test.ts similarity index 87% rename from src/core/services/overlay-manager-service.test.ts rename to src/core/services/overlay-manager.test.ts index c1b11e5..10fe978 100644 --- a/src/core/services/overlay-manager-service.test.ts +++ b/src/core/services/overlay-manager.test.ts @@ -1,13 +1,13 @@ import test from "node:test"; import assert from "node:assert/strict"; import { - broadcastRuntimeOptionsChangedRuntimeService, - createOverlayManagerService, - setOverlayDebugVisualizationEnabledRuntimeService, -} from "./overlay-manager-service"; + broadcastRuntimeOptionsChangedRuntime, + createOverlayManager, + setOverlayDebugVisualizationEnabledRuntime, +} from "./overlay-manager"; test("overlay manager initializes with empty windows and hidden overlays", () => { - const manager = createOverlayManagerService(); + const manager = createOverlayManager(); assert.equal(manager.getMainWindow(), null); assert.equal(manager.getInvisibleWindow(), null); assert.equal(manager.getVisibleOverlayVisible(), false); @@ -16,7 +16,7 @@ test("overlay manager initializes with empty windows and hidden overlays", () => }); test("overlay manager stores window references and returns stable window order", () => { - const manager = createOverlayManagerService(); + const manager = createOverlayManager(); const visibleWindow = { isDestroyed: () => false } as unknown as Electron.BrowserWindow; const invisibleWindow = { isDestroyed: () => false } as unknown as Electron.BrowserWindow; @@ -31,7 +31,7 @@ test("overlay manager stores window references and returns stable window order", }); test("overlay manager excludes destroyed windows", () => { - const manager = createOverlayManagerService(); + const manager = createOverlayManager(); manager.setMainWindow({ isDestroyed: () => true } as unknown as Electron.BrowserWindow); manager.setInvisibleWindow({ isDestroyed: () => false } as unknown as Electron.BrowserWindow); @@ -39,7 +39,7 @@ test("overlay manager excludes destroyed windows", () => { }); test("overlay manager stores visibility state", () => { - const manager = createOverlayManagerService(); + const manager = createOverlayManager(); manager.setVisibleOverlayVisible(true); manager.setInvisibleOverlayVisible(true); @@ -48,7 +48,7 @@ test("overlay manager stores visibility state", () => { }); test("overlay manager broadcasts to non-destroyed windows", () => { - const manager = createOverlayManagerService(); + const manager = createOverlayManager(); const calls: unknown[][] = []; const aliveWindow = { isDestroyed: () => false, @@ -73,7 +73,7 @@ test("overlay manager broadcasts to non-destroyed windows", () => { }); test("overlay manager applies bounds by layer", () => { - const manager = createOverlayManagerService(); + const manager = createOverlayManager(); const visibleCalls: Electron.Rectangle[] = []; const invisibleCalls: Electron.Rectangle[] = []; const visibleWindow = { @@ -110,14 +110,14 @@ test("overlay manager applies bounds by layer", () => { test("runtime-option and debug broadcasts use expected channels", () => { const broadcasts: unknown[][] = []; - broadcastRuntimeOptionsChangedRuntimeService( + broadcastRuntimeOptionsChangedRuntime( () => [], (channel, ...args) => { broadcasts.push([channel, ...args]); }, ); let state = false; - const changed = setOverlayDebugVisualizationEnabledRuntimeService( + const changed = setOverlayDebugVisualizationEnabledRuntime( state, true, (enabled) => { diff --git a/src/core/services/overlay-manager-service.ts b/src/core/services/overlay-manager.ts similarity index 89% rename from src/core/services/overlay-manager-service.ts rename to src/core/services/overlay-manager.ts index 00c251d..d17c090 100644 --- a/src/core/services/overlay-manager-service.ts +++ b/src/core/services/overlay-manager.ts @@ -1,10 +1,10 @@ import { BrowserWindow } from "electron"; import { RuntimeOptionState, WindowGeometry } from "../../types"; -import { updateOverlayWindowBoundsService } from "./overlay-window-service"; +import { updateOverlayWindowBounds } from "./overlay-window"; type OverlayLayer = "visible" | "invisible"; -export interface OverlayManagerService { +export interface OverlayManager { getMainWindow: () => BrowserWindow | null; setMainWindow: (window: BrowserWindow | null) => void; getInvisibleWindow: () => BrowserWindow | null; @@ -19,7 +19,7 @@ export interface OverlayManagerService { broadcastToOverlayWindows: (channel: string, ...args: unknown[]) => void; } -export function createOverlayManagerService(): OverlayManagerService { +export function createOverlayManager(): OverlayManager { let mainWindow: BrowserWindow | null = null; let invisibleWindow: BrowserWindow | null = null; let visibleOverlayVisible = false; @@ -37,7 +37,7 @@ export function createOverlayManagerService(): OverlayManagerService { getOverlayWindow: (layer) => layer === "visible" ? mainWindow : invisibleWindow, setOverlayWindowBounds: (layer, geometry) => { - updateOverlayWindowBoundsService( + updateOverlayWindowBounds( geometry, layer === "visible" ? mainWindow : invisibleWindow, ); @@ -75,14 +75,14 @@ export function createOverlayManagerService(): OverlayManagerService { }; } -export function broadcastRuntimeOptionsChangedRuntimeService( +export function broadcastRuntimeOptionsChangedRuntime( getRuntimeOptionsState: () => RuntimeOptionState[], broadcastToOverlayWindows: (channel: string, ...args: unknown[]) => void, ): void { broadcastToOverlayWindows("runtime-options:changed", getRuntimeOptionsState()); } -export function setOverlayDebugVisualizationEnabledRuntimeService( +export function setOverlayDebugVisualizationEnabledRuntime( currentEnabled: boolean, nextEnabled: boolean, setState: (enabled: boolean) => void, diff --git a/src/core/services/overlay-runtime-init-service.ts b/src/core/services/overlay-runtime-init.ts similarity index 98% rename from src/core/services/overlay-runtime-init-service.ts rename to src/core/services/overlay-runtime-init.ts index 5b629ad..a6085b4 100644 --- a/src/core/services/overlay-runtime-init-service.ts +++ b/src/core/services/overlay-runtime-init.ts @@ -8,7 +8,7 @@ import { WindowGeometry, } from "../../types"; -export function initializeOverlayRuntimeService(options: { +export function initializeOverlayRuntime(options: { backendOverride: string | null; getInitialInvisibleOverlayVisibility: () => boolean; createMainWindow: () => void; diff --git a/src/core/services/overlay-shortcut-handler.ts b/src/core/services/overlay-shortcut-handler.ts index 721f67f..98106fa 100644 --- a/src/core/services/overlay-shortcut-handler.ts +++ b/src/core/services/overlay-shortcut-handler.ts @@ -1,5 +1,5 @@ import { ConfiguredShortcuts } from "../utils/shortcut-config"; -import { OverlayShortcutHandlers } from "./overlay-shortcut-service"; +import { OverlayShortcutHandlers } from "./overlay-shortcut"; import { createLogger } from "../../logger"; const logger = createLogger("main:overlay-shortcut-handler"); diff --git a/src/core/services/overlay-shortcut-service.ts b/src/core/services/overlay-shortcut.ts similarity index 88% rename from src/core/services/overlay-shortcut-service.ts rename to src/core/services/overlay-shortcut.ts index ca0b289..85338c6 100644 --- a/src/core/services/overlay-shortcut-service.ts +++ b/src/core/services/overlay-shortcut.ts @@ -1,6 +1,6 @@ import { globalShortcut } from "electron"; import { ConfiguredShortcuts } from "../utils/shortcut-config"; -import { isGlobalShortcutRegisteredSafe } from "./shortcut-fallback-service"; +import { isGlobalShortcutRegisteredSafe } from "./shortcut-fallback"; import { createLogger } from "../../logger"; const logger = createLogger("main:overlay-shortcut-service"); @@ -26,7 +26,7 @@ export interface OverlayShortcutLifecycleDeps { cancelPendingMineSentenceMultiple: () => void; } -export function registerOverlayShortcutsService( +export function registerOverlayShortcuts( shortcuts: ConfiguredShortcuts, handlers: OverlayShortcutHandlers, ): boolean { @@ -140,7 +140,7 @@ export function registerOverlayShortcutsService( return registeredAny; } -export function unregisterOverlayShortcutsService( +export function unregisterOverlayShortcuts( shortcuts: ConfiguredShortcuts, ): void { if (shortcuts.copySubtitle) { @@ -178,45 +178,45 @@ export function unregisterOverlayShortcutsService( } } -export function registerOverlayShortcutsRuntimeService( +export function registerOverlayShortcutsRuntime( deps: OverlayShortcutLifecycleDeps, ): boolean { - return registerOverlayShortcutsService( + return registerOverlayShortcuts( deps.getConfiguredShortcuts(), deps.getOverlayHandlers(), ); } -export function unregisterOverlayShortcutsRuntimeService( +export function unregisterOverlayShortcutsRuntime( shortcutsRegistered: boolean, deps: OverlayShortcutLifecycleDeps, ): boolean { if (!shortcutsRegistered) return shortcutsRegistered; deps.cancelPendingMultiCopy(); deps.cancelPendingMineSentenceMultiple(); - unregisterOverlayShortcutsService(deps.getConfiguredShortcuts()); + unregisterOverlayShortcuts(deps.getConfiguredShortcuts()); return false; } -export function syncOverlayShortcutsRuntimeService( +export function syncOverlayShortcutsRuntime( shouldBeActive: boolean, shortcutsRegistered: boolean, deps: OverlayShortcutLifecycleDeps, ): boolean { if (shouldBeActive) { - return registerOverlayShortcutsRuntimeService(deps); + return registerOverlayShortcutsRuntime(deps); } - return unregisterOverlayShortcutsRuntimeService(shortcutsRegistered, deps); + return unregisterOverlayShortcutsRuntime(shortcutsRegistered, deps); } -export function refreshOverlayShortcutsRuntimeService( +export function refreshOverlayShortcutsRuntime( shouldBeActive: boolean, shortcutsRegistered: boolean, deps: OverlayShortcutLifecycleDeps, ): boolean { - const cleared = unregisterOverlayShortcutsRuntimeService( + const cleared = unregisterOverlayShortcutsRuntime( shortcutsRegistered, deps, ); - return syncOverlayShortcutsRuntimeService(shouldBeActive, cleared, deps); + return syncOverlayShortcutsRuntime(shouldBeActive, cleared, deps); } diff --git a/src/core/services/overlay-visibility-service.ts b/src/core/services/overlay-visibility.ts similarity index 94% rename from src/core/services/overlay-visibility-service.ts rename to src/core/services/overlay-visibility.ts index 4074ea5..fea2b1b 100644 --- a/src/core/services/overlay-visibility-service.ts +++ b/src/core/services/overlay-visibility.ts @@ -2,7 +2,7 @@ import { BrowserWindow, screen } from "electron"; import { BaseWindowTracker } from "../../window-trackers"; import { WindowGeometry } from "../../types"; -export function updateVisibleOverlayVisibilityService(args: { +export function updateVisibleOverlayVisibility(args: { visibleOverlayVisible: boolean; mainWindow: BrowserWindow | null; windowTracker: BaseWindowTracker | null; @@ -66,7 +66,7 @@ export function updateVisibleOverlayVisibilityService(args: { args.syncOverlayShortcuts(); } -export function updateInvisibleOverlayVisibilityService(args: { +export function updateInvisibleOverlayVisibility(args: { invisibleWindow: BrowserWindow | null; visibleOverlayVisible: boolean; invisibleOverlayVisible: boolean; @@ -131,7 +131,7 @@ export function updateInvisibleOverlayVisibilityService(args: { args.syncOverlayShortcuts(); } -export function syncInvisibleOverlayMousePassthroughService(options: { +export function syncInvisibleOverlayMousePassthrough(options: { hasInvisibleWindow: () => boolean; setIgnoreMouseEvents: (ignore: boolean, extra?: { forward: boolean }) => void; visibleOverlayVisible: boolean; @@ -145,7 +145,7 @@ export function syncInvisibleOverlayMousePassthroughService(options: { } } -export function setVisibleOverlayVisibleService(options: { +export function setVisibleOverlayVisible(options: { visible: boolean; setVisibleOverlayVisibleState: (visible: boolean) => void; updateVisibleOverlayVisibility: () => void; @@ -167,7 +167,7 @@ export function setVisibleOverlayVisibleService(options: { } } -export function setInvisibleOverlayVisibleService(options: { +export function setInvisibleOverlayVisible(options: { visible: boolean; setInvisibleOverlayVisibleState: (visible: boolean) => void; updateInvisibleOverlayVisibility: () => void; diff --git a/src/core/services/overlay-window-service.ts b/src/core/services/overlay-window.ts similarity index 94% rename from src/core/services/overlay-window-service.ts rename to src/core/services/overlay-window.ts index 5c2aec8..2bb8470 100644 --- a/src/core/services/overlay-window-service.ts +++ b/src/core/services/overlay-window.ts @@ -7,7 +7,7 @@ const logger = createLogger("main:overlay-window"); export type OverlayWindowKind = "visible" | "invisible"; -export function updateOverlayWindowBoundsService( +export function updateOverlayWindowBounds( geometry: WindowGeometry, window: BrowserWindow | null, ): void { @@ -20,7 +20,7 @@ export function updateOverlayWindowBoundsService( }); } -export function ensureOverlayWindowLevelService(window: BrowserWindow): void { +export function ensureOverlayWindowLevel(window: BrowserWindow): void { if (process.platform === "darwin") { window.setAlwaysOnTop(true, "screen-saver", 1); window.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true }); @@ -30,7 +30,7 @@ export function ensureOverlayWindowLevelService(window: BrowserWindow): void { window.setAlwaysOnTop(true); } -export function enforceOverlayLayerOrderService(options: { +export function enforceOverlayLayerOrder(options: { visibleOverlayVisible: boolean; invisibleOverlayVisible: boolean; mainWindow: BrowserWindow | null; @@ -45,7 +45,7 @@ export function enforceOverlayLayerOrderService(options: { options.mainWindow.moveTop(); } -export function createOverlayWindowService( +export function createOverlayWindow( kind: OverlayWindowKind, options: { isDev: boolean; diff --git a/src/core/services/runtime-config-service.test.ts b/src/core/services/runtime-config-service.test.ts deleted file mode 100644 index c935dc4..0000000 --- a/src/core/services/runtime-config-service.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { - getInitialInvisibleOverlayVisibilityService, - isAutoUpdateEnabledRuntimeService, - shouldAutoInitializeOverlayRuntimeFromConfigService, - shouldBindVisibleOverlayToMpvSubVisibilityService, -} from "./startup-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); -}); diff --git a/src/core/services/runtime-config.test.ts b/src/core/services/runtime-config.test.ts new file mode 100644 index 0000000..8ba3bd7 --- /dev/null +++ b/src/core/services/runtime-config.test.ts @@ -0,0 +1,98 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { + getInitialInvisibleOverlayVisibility, + isAutoUpdateEnabledRuntime, + shouldAutoInitializeOverlayRuntimeFromConfig, + shouldBindVisibleOverlayToMpvSubVisibility, +} from "./startup"; + +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("getInitialInvisibleOverlayVisibility handles visibility + platform", () => { + assert.equal( + getInitialInvisibleOverlayVisibility( + { ...BASE_CONFIG, invisibleOverlay: { startupVisibility: "visible" } }, + "linux", + ), + true, + ); + assert.equal( + getInitialInvisibleOverlayVisibility( + { ...BASE_CONFIG, invisibleOverlay: { startupVisibility: "hidden" } }, + "darwin", + ), + false, + ); + assert.equal( + getInitialInvisibleOverlayVisibility(BASE_CONFIG, "linux"), + false, + ); + assert.equal( + getInitialInvisibleOverlayVisibility(BASE_CONFIG, "darwin"), + true, + ); +}); + +test("shouldAutoInitializeOverlayRuntimeFromConfig respects auto start and visible startup", () => { + assert.equal( + shouldAutoInitializeOverlayRuntimeFromConfig(BASE_CONFIG), + false, + ); + assert.equal( + shouldAutoInitializeOverlayRuntimeFromConfig({ + ...BASE_CONFIG, + auto_start_overlay: true, + }), + true, + ); + assert.equal( + shouldAutoInitializeOverlayRuntimeFromConfig({ + ...BASE_CONFIG, + invisibleOverlay: { startupVisibility: "visible" }, + }), + true, + ); +}); + +test("shouldBindVisibleOverlayToMpvSubVisibility returns config value", () => { + assert.equal(shouldBindVisibleOverlayToMpvSubVisibility(BASE_CONFIG), true); + assert.equal( + shouldBindVisibleOverlayToMpvSubVisibility({ + ...BASE_CONFIG, + bind_visible_overlay_to_mpv_sub_visibility: false, + }), + false, + ); +}); + +test("isAutoUpdateEnabledRuntime prefers runtime option and falls back to config", () => { + assert.equal( + isAutoUpdateEnabledRuntime(BASE_CONFIG, { + getOptionValue: () => false, + }), + false, + ); + assert.equal( + isAutoUpdateEnabledRuntime( + { + ...BASE_CONFIG, + ankiConnect: { behavior: { autoUpdateNewCards: false } }, + }, + null, + ), + false, + ); + assert.equal(isAutoUpdateEnabledRuntime(BASE_CONFIG, null), true); +}); diff --git a/src/core/services/runtime-options-ipc-service.test.ts b/src/core/services/runtime-options-ipc.test.ts similarity index 60% rename from src/core/services/runtime-options-ipc-service.test.ts rename to src/core/services/runtime-options-ipc.test.ts index 5d53634..ce73b92 100644 --- a/src/core/services/runtime-options-ipc-service.test.ts +++ b/src/core/services/runtime-options-ipc.test.ts @@ -1,14 +1,14 @@ import test from "node:test"; import assert from "node:assert/strict"; import { - applyRuntimeOptionResultRuntimeService, - cycleRuntimeOptionFromIpcRuntimeService, - setRuntimeOptionFromIpcRuntimeService, -} from "./runtime-options-ipc-service"; + applyRuntimeOptionResultRuntime, + cycleRuntimeOptionFromIpcRuntime, + setRuntimeOptionFromIpcRuntime, +} from "./runtime-options-ipc"; -test("applyRuntimeOptionResultRuntimeService emits success OSD message", () => { +test("applyRuntimeOptionResultRuntime emits success OSD message", () => { const osd: string[] = []; - const result = applyRuntimeOptionResultRuntimeService( + const result = applyRuntimeOptionResultRuntime( { ok: true, osdMessage: "Updated" }, (text) => { osd.push(text); @@ -19,9 +19,9 @@ test("applyRuntimeOptionResultRuntimeService emits success OSD message", () => { assert.deepEqual(osd, ["Updated"]); }); -test("setRuntimeOptionFromIpcRuntimeService returns unavailable when manager missing", () => { +test("setRuntimeOptionFromIpcRuntime returns unavailable when manager missing", () => { const osd: string[] = []; - const result = setRuntimeOptionFromIpcRuntimeService( + const result = setRuntimeOptionFromIpcRuntime( null, "anki.autoUpdateNewCards", true, @@ -34,9 +34,9 @@ test("setRuntimeOptionFromIpcRuntimeService returns unavailable when manager mis assert.deepEqual(osd, []); }); -test("cycleRuntimeOptionFromIpcRuntimeService reports errors once", () => { +test("cycleRuntimeOptionFromIpcRuntime reports errors once", () => { const osd: string[] = []; - const result = cycleRuntimeOptionFromIpcRuntimeService( + const result = cycleRuntimeOptionFromIpcRuntime( { setOptionValue: () => ({ ok: true }), cycleOption: () => ({ ok: false, error: "bad option" }), diff --git a/src/core/services/runtime-options-ipc-service.ts b/src/core/services/runtime-options-ipc.ts similarity index 82% rename from src/core/services/runtime-options-ipc-service.ts rename to src/core/services/runtime-options-ipc.ts index 339ac27..d997410 100644 --- a/src/core/services/runtime-options-ipc-service.ts +++ b/src/core/services/runtime-options-ipc.ts @@ -15,7 +15,7 @@ export interface RuntimeOptionsManagerLike { ) => RuntimeOptionApplyResult; } -export function applyRuntimeOptionResultRuntimeService( +export function applyRuntimeOptionResultRuntime( result: RuntimeOptionApplyResult, showMpvOsd: (text: string) => void, ): RuntimeOptionApplyResult { @@ -25,7 +25,7 @@ export function applyRuntimeOptionResultRuntimeService( return result; } -export function setRuntimeOptionFromIpcRuntimeService( +export function setRuntimeOptionFromIpcRuntime( manager: RuntimeOptionsManagerLike | null, id: RuntimeOptionId, value: RuntimeOptionValue, @@ -34,7 +34,7 @@ export function setRuntimeOptionFromIpcRuntimeService( if (!manager) { return { ok: false, error: "Runtime options manager unavailable" }; } - const result = applyRuntimeOptionResultRuntimeService( + const result = applyRuntimeOptionResultRuntime( manager.setOptionValue(id, value), showMpvOsd, ); @@ -44,7 +44,7 @@ export function setRuntimeOptionFromIpcRuntimeService( return result; } -export function cycleRuntimeOptionFromIpcRuntimeService( +export function cycleRuntimeOptionFromIpcRuntime( manager: RuntimeOptionsManagerLike | null, id: RuntimeOptionId, direction: 1 | -1, @@ -53,7 +53,7 @@ export function cycleRuntimeOptionFromIpcRuntimeService( if (!manager) { return { ok: false, error: "Runtime options manager unavailable" }; } - const result = applyRuntimeOptionResultRuntimeService( + const result = applyRuntimeOptionResultRuntime( manager.cycleOption(id, direction), showMpvOsd, ); diff --git a/src/core/services/secondary-subtitle-service.test.ts b/src/core/services/secondary-subtitle.test.ts similarity index 83% rename from src/core/services/secondary-subtitle-service.test.ts rename to src/core/services/secondary-subtitle.test.ts index 8e88801..8b1c990 100644 --- a/src/core/services/secondary-subtitle-service.test.ts +++ b/src/core/services/secondary-subtitle.test.ts @@ -1,15 +1,15 @@ import test from "node:test"; import assert from "node:assert/strict"; import { SecondarySubMode } from "../../types"; -import { cycleSecondarySubModeService } from "./subtitle-position-service"; +import { cycleSecondarySubMode } from "./subtitle-position"; -test("cycleSecondarySubModeService cycles and emits broadcast + OSD", () => { +test("cycleSecondarySubMode cycles and emits broadcast + OSD", () => { let mode: SecondarySubMode = "hover"; let lastToggleAt = 0; const broadcasts: SecondarySubMode[] = []; const osd: string[] = []; - cycleSecondarySubModeService({ + cycleSecondarySubMode({ getSecondarySubMode: () => mode, setSecondarySubMode: (next) => { mode = next; @@ -33,13 +33,13 @@ test("cycleSecondarySubModeService cycles and emits broadcast + OSD", () => { assert.equal(lastToggleAt, 1000); }); -test("cycleSecondarySubModeService obeys debounce window", () => { +test("cycleSecondarySubMode obeys debounce window", () => { let mode: SecondarySubMode = "visible"; let lastToggleAt = 950; let broadcasted = false; let osdShown = false; - cycleSecondarySubModeService({ + cycleSecondarySubMode({ getSecondarySubMode: () => mode, setSecondarySubMode: (next) => { mode = next; diff --git a/src/core/services/shortcut-fallback-service.ts b/src/core/services/shortcut-fallback.ts similarity index 100% rename from src/core/services/shortcut-fallback-service.ts rename to src/core/services/shortcut-fallback.ts diff --git a/src/core/services/shortcut-service.ts b/src/core/services/shortcut.ts similarity index 98% rename from src/core/services/shortcut-service.ts rename to src/core/services/shortcut.ts index fee6660..36ac022 100644 --- a/src/core/services/shortcut-service.ts +++ b/src/core/services/shortcut.ts @@ -19,7 +19,7 @@ export interface RegisterGlobalShortcutsServiceOptions { getMainWindow: () => BrowserWindow | null; } -export function registerGlobalShortcutsService( +export function registerGlobalShortcuts( options: RegisterGlobalShortcutsServiceOptions, ): void { const visibleShortcut = options.shortcuts.toggleVisibleOverlayGlobal; diff --git a/src/core/services/startup-bootstrap-service.test.ts b/src/core/services/startup-bootstrap.test.ts similarity index 86% rename from src/core/services/startup-bootstrap-service.test.ts rename to src/core/services/startup-bootstrap.test.ts index e0afbbb..25d08b3 100644 --- a/src/core/services/startup-bootstrap-service.test.ts +++ b/src/core/services/startup-bootstrap.test.ts @@ -1,8 +1,8 @@ import test from "node:test"; import assert from "node:assert/strict"; import { - runStartupBootstrapRuntimeService, -} from "./startup-service"; + runStartupBootstrapRuntime, +} from "./startup"; import { CliArgs } from "../../cli/args"; function makeArgs(overrides: Partial = {}): CliArgs { @@ -40,7 +40,7 @@ function makeArgs(overrides: Partial = {}): CliArgs { }; } -test("runStartupBootstrapRuntimeService configures startup state and starts lifecycle", () => { +test("runStartupBootstrapRuntime configures startup state and starts lifecycle", () => { const calls: string[] = []; const args = makeArgs({ logLevel: "debug", @@ -51,7 +51,7 @@ test("runStartupBootstrapRuntimeService configures startup state and starts life texthooker: true, }); - const result = runStartupBootstrapRuntimeService({ + const result = runStartupBootstrapRuntime({ argv: ["node", "main.ts", "--log-level", "debug"], parseArgs: () => args, setLogLevel: (level, source) => calls.push(`setLog:${level}:${source}`), @@ -77,13 +77,13 @@ test("runStartupBootstrapRuntimeService configures startup state and starts life ]); }); -test("runStartupBootstrapRuntimeService keeps log-level precedence for repeated calls", () => { +test("runStartupBootstrapRuntime keeps log-level precedence for repeated calls", () => { const calls: string[] = []; const args = makeArgs({ logLevel: "warn", }); - runStartupBootstrapRuntimeService({ + runStartupBootstrapRuntime({ argv: ["node", "main.ts", "--log-level", "warn"], parseArgs: () => args, setLogLevel: (level, source) => calls.push(`setLog:${level}:${source}`), @@ -102,13 +102,13 @@ test("runStartupBootstrapRuntimeService keeps log-level precedence for repeated ]); }); -test("runStartupBootstrapRuntimeService keeps --debug separate from log verbosity", () => { +test("runStartupBootstrapRuntime keeps --debug separate from log verbosity", () => { const calls: string[] = []; const args = makeArgs({ debug: true, }); - runStartupBootstrapRuntimeService({ + runStartupBootstrapRuntime({ argv: ["node", "main.ts", "--debug"], parseArgs: () => args, setLogLevel: (level, source) => calls.push(`setLog:${level}:${source}`), @@ -123,11 +123,11 @@ test("runStartupBootstrapRuntimeService keeps --debug separate from log verbosit assert.deepEqual(calls, ["forceX11", "enforceWayland", "startLifecycle"]); }); -test("runStartupBootstrapRuntimeService skips lifecycle when generate-config flow handled", () => { +test("runStartupBootstrapRuntime skips lifecycle when generate-config flow handled", () => { const calls: string[] = []; const args = makeArgs({ generateConfig: true, logLevel: "warn" }); - const result = runStartupBootstrapRuntimeService({ + const result = runStartupBootstrapRuntime({ argv: ["node", "main.ts", "--generate-config"], parseArgs: () => args, setLogLevel: (level, source) => calls.push(`setLog:${level}:${source}`), diff --git a/src/core/services/startup-service.ts b/src/core/services/startup.ts similarity index 94% rename from src/core/services/startup-service.ts rename to src/core/services/startup.ts index 3e11b86..bc1916f 100644 --- a/src/core/services/startup-service.ts +++ b/src/core/services/startup.ts @@ -40,7 +40,7 @@ export interface StartupBootstrapRuntimeDeps { startAppLifecycle: (args: CliArgs) => void; } -export function runStartupBootstrapRuntimeService( +export function runStartupBootstrapRuntime( deps: StartupBootstrapRuntimeDeps, ): StartupBootstrapRuntimeState { const initialArgs = deps.parseArgs(deps.argv); @@ -107,7 +107,7 @@ export interface AppReadyRuntimeDeps { handleInitialArgs: () => void; } -export function getInitialInvisibleOverlayVisibilityService( +export function getInitialInvisibleOverlayVisibility( config: RuntimeConfigLike, platform: NodeJS.Platform, ): boolean { @@ -118,7 +118,7 @@ export function getInitialInvisibleOverlayVisibilityService( return true; } -export function shouldAutoInitializeOverlayRuntimeFromConfigService( +export function shouldAutoInitializeOverlayRuntimeFromConfig( config: RuntimeConfigLike, ): boolean { if (config.auto_start_overlay === true) return true; @@ -126,13 +126,13 @@ export function shouldAutoInitializeOverlayRuntimeFromConfigService( return false; } -export function shouldBindVisibleOverlayToMpvSubVisibilityService( +export function shouldBindVisibleOverlayToMpvSubVisibility( config: RuntimeConfigLike, ): boolean { return config.bind_visible_overlay_to_mpv_sub_visibility; } -export function isAutoUpdateEnabledRuntimeService( +export function isAutoUpdateEnabledRuntime( config: ResolvedConfig | RuntimeConfigLike, runtimeOptionsManager: RuntimeAutoUpdateOptionManagerLike | null, ): boolean { @@ -141,7 +141,7 @@ export function isAutoUpdateEnabledRuntimeService( return (config as ResolvedConfig).ankiConnect?.behavior?.autoUpdateNewCards !== false; } -export async function runAppReadyRuntimeService( +export async function runAppReadyRuntime( deps: AppReadyRuntimeDeps, ): Promise { deps.loadSubtitlePosition(); diff --git a/src/core/services/subsync-runner-service.ts b/src/core/services/subsync-runner.ts similarity index 82% rename from src/core/services/subsync-runner-service.ts rename to src/core/services/subsync-runner.ts index 554f7eb..af2b2c3 100644 --- a/src/core/services/subsync-runner-service.ts +++ b/src/core/services/subsync-runner.ts @@ -4,12 +4,12 @@ import { SubsyncResult, } from "../../types"; import { SubsyncResolvedConfig } from "../../subsync/utils"; -import { runSubsyncManualFromIpcService } from "./ipc-command-service"; +import { runSubsyncManualFromIpc } from "./ipc-command"; import { TriggerSubsyncFromConfigDeps, - runSubsyncManualService, - triggerSubsyncFromConfigService, -} from "./subsync-service"; + runSubsyncManual, + triggerSubsyncFromConfig, +} from "./subsync"; const AUTOSUBSYNC_SPINNER_FRAMES = ["|", "/", "-", "\\"]; @@ -62,24 +62,24 @@ function buildTriggerSubsyncDeps( }; } -export async function triggerSubsyncFromConfigRuntimeService( +export async function triggerSubsyncFromConfigRuntime( deps: SubsyncRuntimeDeps, ): Promise { - await triggerSubsyncFromConfigService(buildTriggerSubsyncDeps(deps)); + await triggerSubsyncFromConfig(buildTriggerSubsyncDeps(deps)); } -export async function runSubsyncManualFromIpcRuntimeService( +export async function runSubsyncManualFromIpcRuntime( request: SubsyncManualRunRequest, deps: SubsyncRuntimeDeps, ): Promise { const triggerDeps = buildTriggerSubsyncDeps(deps); - return runSubsyncManualFromIpcService(request, { + return runSubsyncManualFromIpc(request, { isSubsyncInProgress: triggerDeps.isSubsyncInProgress, setSubsyncInProgress: triggerDeps.setSubsyncInProgress, showMpvOsd: triggerDeps.showMpvOsd, runWithSpinner: (task) => triggerDeps.runWithSubsyncSpinner(() => task()), runSubsyncManual: (subsyncRequest) => - runSubsyncManualService(subsyncRequest, triggerDeps), + runSubsyncManual(subsyncRequest, triggerDeps), }); } diff --git a/src/core/services/subsync-service.test.ts b/src/core/services/subsync.test.ts similarity index 89% rename from src/core/services/subsync-service.test.ts rename to src/core/services/subsync.test.ts index 21fad19..43f070a 100644 --- a/src/core/services/subsync-service.test.ts +++ b/src/core/services/subsync.test.ts @@ -5,9 +5,9 @@ import * as os from "os"; import * as path from "path"; import { TriggerSubsyncFromConfigDeps, - runSubsyncManualService, - triggerSubsyncFromConfigService, -} from "./subsync-service"; + runSubsyncManual, + triggerSubsyncFromConfig, +} from "./subsync"; function makeDeps( overrides: Partial = {}, @@ -55,9 +55,9 @@ function makeDeps( }; } -test("triggerSubsyncFromConfigService returns early when already in progress", async () => { +test("triggerSubsyncFromConfig returns early when already in progress", async () => { const osd: string[] = []; - await triggerSubsyncFromConfigService( + await triggerSubsyncFromConfig( makeDeps({ isSubsyncInProgress: () => true, showMpvOsd: (text) => { @@ -68,12 +68,12 @@ test("triggerSubsyncFromConfigService returns early when already in progress", a assert.deepEqual(osd, ["Subsync already running"]); }); -test("triggerSubsyncFromConfigService opens manual picker in manual mode", async () => { +test("triggerSubsyncFromConfig opens manual picker in manual mode", async () => { const osd: string[] = []; let payloadTrackCount = 0; let inProgressState: boolean | null = null; - await triggerSubsyncFromConfigService( + await triggerSubsyncFromConfig( makeDeps({ openManualPicker: (payload) => { payloadTrackCount = payload.sourceTracks.length; @@ -92,9 +92,9 @@ test("triggerSubsyncFromConfigService opens manual picker in manual mode", async assert.equal(inProgressState, false); }); -test("triggerSubsyncFromConfigService reports failures to OSD", async () => { +test("triggerSubsyncFromConfig reports failures to OSD", async () => { const osd: string[] = []; - await triggerSubsyncFromConfigService( + await triggerSubsyncFromConfig( makeDeps({ getMpvClient: () => null, showMpvOsd: (text) => { @@ -106,8 +106,8 @@ test("triggerSubsyncFromConfigService reports failures to OSD", async () => { assert.ok(osd.some((line) => line.startsWith("Subsync failed: MPV not connected"))); }); -test("runSubsyncManualService requires a source track for alass", async () => { - const result = await runSubsyncManualService( +test("runSubsyncManual requires a source track for alass", async () => { + const result = await runSubsyncManual( { engine: "alass", sourceTrackId: null }, makeDeps(), ); @@ -118,11 +118,11 @@ test("runSubsyncManualService requires a source track for alass", async () => { }); }); -test("triggerSubsyncFromConfigService reports path validation failures", async () => { +test("triggerSubsyncFromConfig reports path validation failures", async () => { const osd: string[] = []; const inProgress: boolean[] = []; - await triggerSubsyncFromConfigService( + await triggerSubsyncFromConfig( makeDeps({ getResolvedConfig: () => ({ defaultMode: "auto", @@ -152,7 +152,7 @@ function writeExecutableScript(filePath: string, content: string): void { fs.chmodSync(filePath, 0o755); } -test("runSubsyncManualService constructs ffsubsync command and returns success", async () => { +test("runSubsyncManual constructs ffsubsync command and returns success", async () => { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "subsync-ffsubsync-")); const ffsubsyncLogPath = path.join(tmpDir, "ffsubsync-args.log"); const ffsubsyncPath = path.join(tmpDir, "ffsubsync.sh"); @@ -210,7 +210,7 @@ test("runSubsyncManualService constructs ffsubsync command and returns success", }), }); - const result = await runSubsyncManualService( + const result = await runSubsyncManual( { engine: "ffsubsync", sourceTrackId: null }, deps, ); @@ -227,7 +227,7 @@ test("runSubsyncManualService constructs ffsubsync command and returns success", assert.deepEqual(sentCommands[1], ["set_property", "sub-delay", 0]); }); -test("runSubsyncManualService constructs alass command and returns failure on non-zero exit", async () => { +test("runSubsyncManual constructs alass command and returns failure on non-zero exit", async () => { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "subsync-alass-")); const alassLogPath = path.join(tmpDir, "alass-args.log"); const alassPath = path.join(tmpDir, "alass.sh"); @@ -285,7 +285,7 @@ test("runSubsyncManualService constructs alass command and returns failure on no }), }); - const result = await runSubsyncManualService( + const result = await runSubsyncManual( { engine: "alass", sourceTrackId: 2 }, deps, ); @@ -298,7 +298,7 @@ test("runSubsyncManualService constructs alass command and returns failure on no assert.equal(alassArgs[1], primaryPath); }); -test("runSubsyncManualService resolves string sid values from mpv stream properties", async () => { +test("runSubsyncManual resolves string sid values from mpv stream properties", async () => { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "subsync-stream-sid-")); const ffsubsyncPath = path.join(tmpDir, "ffsubsync.sh"); const ffsubsyncLogPath = path.join(tmpDir, "ffsubsync-args.log"); @@ -347,7 +347,7 @@ test("runSubsyncManualService resolves string sid values from mpv stream propert }), }); - const result = await runSubsyncManualService( + const result = await runSubsyncManual( { engine: "ffsubsync", sourceTrackId: null }, deps, ); diff --git a/src/core/services/subsync-service.ts b/src/core/services/subsync.ts similarity index 98% rename from src/core/services/subsync-service.ts rename to src/core/services/subsync.ts index a89f996..d4d3056 100644 --- a/src/core/services/subsync-service.ts +++ b/src/core/services/subsync.ts @@ -399,7 +399,7 @@ async function runSubsyncAutoInternal( ); } -export async function runSubsyncManualService( +export async function runSubsyncManual( request: SubsyncManualRunRequest, deps: SubsyncCoreDeps, ): Promise { @@ -452,7 +452,7 @@ export async function runSubsyncManualService( } } -export async function openSubsyncManualPickerService( +export async function openSubsyncManualPicker( deps: TriggerSubsyncFromConfigDeps, ): Promise { const client = getMpvClientForSubsync(deps); @@ -468,7 +468,7 @@ export async function openSubsyncManualPickerService( deps.openManualPicker(payload); } -export async function triggerSubsyncFromConfigService( +export async function triggerSubsyncFromConfig( deps: TriggerSubsyncFromConfigDeps, ): Promise { if (deps.isSubsyncInProgress()) { @@ -479,7 +479,7 @@ export async function triggerSubsyncFromConfigService( const resolved = deps.getResolvedConfig(); try { if (resolved.defaultMode === "manual") { - await openSubsyncManualPickerService(deps); + await openSubsyncManualPicker(deps); deps.showMpvOsd("Subsync: choose engine and source"); return; } diff --git a/src/core/services/subtitle-position-service.ts b/src/core/services/subtitle-position.ts similarity index 96% rename from src/core/services/subtitle-position-service.ts rename to src/core/services/subtitle-position.ts index c9374c0..3725c69 100644 --- a/src/core/services/subtitle-position-service.ts +++ b/src/core/services/subtitle-position.ts @@ -19,7 +19,7 @@ export interface CycleSecondarySubModeDeps { const SECONDARY_SUB_CYCLE: SecondarySubMode[] = ["hidden", "visible", "hover"]; const SECONDARY_SUB_TOGGLE_DEBOUNCE_MS = 120; -export function cycleSecondarySubModeService( +export function cycleSecondarySubMode( deps: CycleSecondarySubModeDeps, ): void { const now = deps.now ? deps.now() : Date.now(); @@ -89,7 +89,7 @@ function persistSubtitlePosition( fs.writeFileSync(positionPath, JSON.stringify(position, null, 2)); } -export function loadSubtitlePositionService(options: { +export function loadSubtitlePosition(options: { currentMediaPath: string | null; fallbackPosition: SubtitlePosition; } & { subtitlePositionsDir: string }): SubtitlePosition | null { @@ -135,7 +135,7 @@ export function loadSubtitlePositionService(options: { } } -export function saveSubtitlePositionService(options: { +export function saveSubtitlePosition(options: { position: SubtitlePosition; currentMediaPath: string | null; subtitlePositionsDir: string; @@ -160,7 +160,7 @@ export function saveSubtitlePositionService(options: { } } -export function updateCurrentMediaPathService(options: { +export function updateCurrentMediaPath(options: { mediaPath: unknown; currentMediaPath: string | null; pendingSubtitlePosition: SubtitlePosition | null; diff --git a/src/core/services/subtitle-ws-service.ts b/src/core/services/subtitle-ws.ts similarity index 97% rename from src/core/services/subtitle-ws-service.ts rename to src/core/services/subtitle-ws.ts index fe1606e..c240147 100644 --- a/src/core/services/subtitle-ws-service.ts +++ b/src/core/services/subtitle-ws.ts @@ -16,7 +16,7 @@ export function hasMpvWebsocketPlugin(): boolean { return fs.existsSync(mpvWebsocketPath); } -export class SubtitleWebSocketService { +export class SubtitleWebSocket { private server: WebSocket.Server | null = null; public isRunning(): boolean { diff --git a/src/core/services/texthooker-service.ts b/src/core/services/texthooker.ts similarity index 98% rename from src/core/services/texthooker-service.ts rename to src/core/services/texthooker.ts index fc43be8..f4d0a7c 100644 --- a/src/core/services/texthooker-service.ts +++ b/src/core/services/texthooker.ts @@ -5,7 +5,7 @@ import { createLogger } from "../../logger"; const logger = createLogger("main:texthooker"); -export class TexthookerService { +export class Texthooker { private server: http.Server | null = null; public isRunning(): boolean { diff --git a/src/core/services/tokenizer-service.test.ts b/src/core/services/tokenizer.test.ts similarity index 87% rename from src/core/services/tokenizer-service.test.ts rename to src/core/services/tokenizer.test.ts index 0845cb0..81f5ee3 100644 --- a/src/core/services/tokenizer-service.test.ts +++ b/src/core/services/tokenizer.test.ts @@ -2,11 +2,11 @@ import test from "node:test"; import assert from "node:assert/strict"; import { PartOfSpeech } from "../../types"; import { - createTokenizerDepsRuntimeService, + createTokenizerDepsRuntime, TokenizerServiceDeps, TokenizerDepsRuntimeOptions, - tokenizeSubtitleService, -} from "./tokenizer-service"; + tokenizeSubtitle, +} from "./tokenizer"; function makeDeps( overrides: Partial = {}, @@ -31,7 +31,7 @@ function makeDepsFromMecabTokenizer( tokenize: (text: string) => Promise, overrides: Partial = {}, ): TokenizerServiceDeps { - return createTokenizerDepsRuntimeService({ + return createTokenizerDepsRuntime({ getYomitanExt: () => null, getYomitanParserWindow: () => null, setYomitanParserWindow: () => {}, @@ -49,8 +49,8 @@ function makeDepsFromMecabTokenizer( }); } -test("tokenizeSubtitleService assigns JLPT level to parsed Yomitan tokens", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle assigns JLPT level to parsed Yomitan tokens", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -88,9 +88,9 @@ test("tokenizeSubtitleService assigns JLPT level to parsed Yomitan tokens", asyn assert.equal(result.tokens?.[0]?.jlptLevel, "N5"); }); -test("tokenizeSubtitleService caches JLPT lookups across repeated tokens", async () => { +test("tokenizeSubtitle caches JLPT lookups across repeated tokens", async () => { let lookupCalls = 0; - const result = await tokenizeSubtitleService( + const result = await tokenizeSubtitle( "猫猫", makeDepsFromMecabTokenizer(async () => [ { @@ -133,8 +133,8 @@ test("tokenizeSubtitleService caches JLPT lookups across repeated tokens", async assert.equal(result.tokens?.[1]?.jlptLevel, "N5"); }); -test("tokenizeSubtitleService leaves JLPT unset for non-matching tokens", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle leaves JLPT unset for non-matching tokens", async () => { + const result = await tokenizeSubtitle( "猫", makeDepsFromMecabTokenizer(async () => [ { @@ -159,9 +159,9 @@ test("tokenizeSubtitleService leaves JLPT unset for non-matching tokens", async assert.equal(result.tokens?.[0]?.jlptLevel, undefined); }); -test("tokenizeSubtitleService skips JLPT lookups when disabled", async () => { +test("tokenizeSubtitle skips JLPT lookups when disabled", async () => { let lookupCalls = 0; - const result = await tokenizeSubtitleService( + const result = await tokenizeSubtitle( "猫です", makeDeps({ tokenizeWithMecab: async () => [ @@ -190,8 +190,8 @@ test("tokenizeSubtitleService skips JLPT lookups when disabled", async () => { assert.equal(lookupCalls, 0); }); -test("tokenizeSubtitleService applies frequency dictionary ranks", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle applies frequency dictionary ranks", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -228,8 +228,8 @@ test("tokenizeSubtitleService applies frequency dictionary ranks", async () => { assert.equal(result.tokens?.[1]?.frequencyRank, 1200); }); -test("tokenizeSubtitleService uses only selected Yomitan headword for frequency lookup", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle uses only selected Yomitan headword for frequency lookup", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -265,8 +265,8 @@ test("tokenizeSubtitleService uses only selected Yomitan headword for frequency assert.equal(result.tokens?.[0]?.frequencyRank, 1200); }); -test("tokenizeSubtitleService keeps furigana-split Yomitan segments as one token", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle keeps furigana-split Yomitan segments as one token", async () => { + const result = await tokenizeSubtitle( "友達と話した", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -324,8 +324,8 @@ test("tokenizeSubtitleService keeps furigana-split Yomitan segments as one token assert.equal(result.tokens?.[2]?.frequencyRank, 90); }); -test("tokenizeSubtitleService prefers exact headword frequency over surface/reading when available", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle prefers exact headword frequency over surface/reading when available", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -358,8 +358,8 @@ test("tokenizeSubtitleService prefers exact headword frequency over surface/read assert.equal(result.tokens?.[0]?.frequencyRank, 8); }); -test("tokenizeSubtitleService keeps no frequency when only reading matches and headword misses", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle keeps no frequency when only reading matches and headword misses", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -392,8 +392,8 @@ test("tokenizeSubtitleService keeps no frequency when only reading matches and h assert.equal(result.tokens?.[0]?.frequencyRank, undefined); }); -test("tokenizeSubtitleService ignores invalid frequency rank on selected headword", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle ignores invalid frequency rank on selected headword", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -429,8 +429,8 @@ test("tokenizeSubtitleService ignores invalid frequency rank on selected headwor assert.equal(result.tokens?.[0]?.frequencyRank, undefined); }); -test("tokenizeSubtitleService handles real-word frequency candidates and prefers most frequent term", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle handles real-word frequency candidates and prefers most frequent term", async () => { + const result = await tokenizeSubtitle( "昨日", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -466,8 +466,8 @@ test("tokenizeSubtitleService handles real-word frequency candidates and prefers assert.equal(result.tokens?.[0]?.frequencyRank, 40); }); -test("tokenizeSubtitleService ignores candidates with no dictionary rank when higher-frequency candidate exists", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle ignores candidates with no dictionary rank when higher-frequency candidate exists", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -504,8 +504,8 @@ test("tokenizeSubtitleService ignores candidates with no dictionary rank when hi assert.equal(result.tokens?.[0]?.frequencyRank, 88); }); -test("tokenizeSubtitleService ignores frequency lookup failures", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle ignores frequency lookup failures", async () => { + const result = await tokenizeSubtitle( "猫", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -531,8 +531,8 @@ test("tokenizeSubtitleService ignores frequency lookup failures", async () => { assert.equal(result.tokens?.[0]?.frequencyRank, undefined); }); -test("tokenizeSubtitleService skips frequency rank when Yomitan token is enriched as particle by mecab pos1", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle skips frequency rank when Yomitan token is enriched as particle by mecab pos1", async () => { + const result = await tokenizeSubtitle( "は", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -580,8 +580,8 @@ test("tokenizeSubtitleService skips frequency rank when Yomitan token is enriche assert.equal(result.tokens?.[0]?.frequencyRank, undefined); }); -test("tokenizeSubtitleService ignores invalid frequency ranks", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle ignores invalid frequency ranks", async () => { + const result = await tokenizeSubtitle( "猫", makeDeps({ getFrequencyDictionaryEnabled: () => true, @@ -622,9 +622,9 @@ test("tokenizeSubtitleService ignores invalid frequency ranks", async () => { assert.equal(result.tokens?.[1]?.frequencyRank, undefined); }); -test("tokenizeSubtitleService skips frequency lookups when disabled", async () => { +test("tokenizeSubtitle skips frequency lookups when disabled", async () => { let frequencyCalls = 0; - const result = await tokenizeSubtitleService( + const result = await tokenizeSubtitle( "猫", makeDeps({ getFrequencyDictionaryEnabled: () => false, @@ -653,8 +653,8 @@ test("tokenizeSubtitleService skips frequency lookups when disabled", async () = assert.equal(frequencyCalls, 0); }); -test("tokenizeSubtitleService skips JLPT level for excluded demonstratives", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle skips JLPT level for excluded demonstratives", async () => { + const result = await tokenizeSubtitle( "この", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -687,8 +687,8 @@ test("tokenizeSubtitleService skips JLPT level for excluded demonstratives", asy assert.equal(result.tokens?.[0]?.jlptLevel, undefined); }); -test("tokenizeSubtitleService skips JLPT level for repeated kana SFX", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle skips JLPT level for repeated kana SFX", async () => { + const result = await tokenizeSubtitle( "ああ", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -721,8 +721,8 @@ test("tokenizeSubtitleService skips JLPT level for repeated kana SFX", async () assert.equal(result.tokens?.[0]?.jlptLevel, undefined); }); -test("tokenizeSubtitleService assigns JLPT level to mecab tokens", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle assigns JLPT level to mecab tokens", async () => { + const result = await tokenizeSubtitle( "猫です", makeDepsFromMecabTokenizer(async () => [ { @@ -747,8 +747,8 @@ test("tokenizeSubtitleService assigns JLPT level to mecab tokens", async () => { assert.equal(result.tokens?.[0]?.jlptLevel, "N4"); }); -test("tokenizeSubtitleService skips JLPT level for mecab tokens marked as ineligible", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle skips JLPT level for mecab tokens marked as ineligible", async () => { + const result = await tokenizeSubtitle( "は", makeDepsFromMecabTokenizer(async () => [ { @@ -774,14 +774,14 @@ test("tokenizeSubtitleService skips JLPT level for mecab tokens marked as inelig assert.equal(result.tokens?.[0]?.jlptLevel, undefined); }); -test("tokenizeSubtitleService returns null tokens for empty normalized text", async () => { - const result = await tokenizeSubtitleService(" \\n ", makeDeps()); +test("tokenizeSubtitle returns null tokens for empty normalized text", async () => { + const result = await tokenizeSubtitle(" \\n ", makeDeps()); assert.deepEqual(result, { text: " \\n ", tokens: null }); }); -test("tokenizeSubtitleService normalizes newlines before mecab fallback", async () => { +test("tokenizeSubtitle normalizes newlines before mecab fallback", async () => { let tokenizeInput = ""; - const result = await tokenizeSubtitleService( + const result = await tokenizeSubtitle( "猫\\Nです\nね", makeDeps({ tokenizeWithMecab: async (text) => { @@ -808,8 +808,8 @@ test("tokenizeSubtitleService normalizes newlines before mecab fallback", async assert.equal(result.tokens?.[0]?.surface, "猫ですね"); }); -test("tokenizeSubtitleService falls back to mecab tokens when available", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle falls back to mecab tokens when available", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ tokenizeWithMecab: async () => [ @@ -833,8 +833,8 @@ test("tokenizeSubtitleService falls back to mecab tokens when available", async assert.equal(result.tokens?.[0]?.surface, "猫"); }); -test("tokenizeSubtitleService returns null tokens when mecab throws", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle returns null tokens when mecab throws", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ tokenizeWithMecab: async () => { @@ -846,7 +846,7 @@ test("tokenizeSubtitleService returns null tokens when mecab throws", async () = assert.deepEqual(result, { text: "猫です", tokens: null }); }); -test("tokenizeSubtitleService uses Yomitan parser result when available", async () => { +test("tokenizeSubtitle uses Yomitan parser result when available", async () => { const parserWindow = { isDestroyed: () => false, webContents: { @@ -874,7 +874,7 @@ test("tokenizeSubtitleService uses Yomitan parser result when available", async }, } as unknown as Electron.BrowserWindow; - const result = await tokenizeSubtitleService( + const result = await tokenizeSubtitle( "猫です", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -893,7 +893,7 @@ test("tokenizeSubtitleService uses Yomitan parser result when available", async assert.equal(result.tokens?.[1]?.isKnown, false); }); -test("tokenizeSubtitleService logs selected Yomitan groups when debug toggle is enabled", async () => { +test("tokenizeSubtitle logs selected Yomitan groups when debug toggle is enabled", async () => { const infoLogs: string[] = []; const originalInfo = console.info; console.info = (...args: unknown[]) => { @@ -901,7 +901,7 @@ test("tokenizeSubtitleService logs selected Yomitan groups when debug toggle is }; try { - await tokenizeSubtitleService( + await tokenizeSubtitle( "友達と話した", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -949,7 +949,7 @@ test("tokenizeSubtitleService logs selected Yomitan groups when debug toggle is ); }); -test("tokenizeSubtitleService does not log Yomitan groups when debug toggle is disabled", async () => { +test("tokenizeSubtitle does not log Yomitan groups when debug toggle is disabled", async () => { const infoLogs: string[] = []; const originalInfo = console.info; console.info = (...args: unknown[]) => { @@ -957,7 +957,7 @@ test("tokenizeSubtitleService does not log Yomitan groups when debug toggle is d }; try { - await tokenizeSubtitleService( + await tokenizeSubtitle( "友達と話した", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -999,7 +999,7 @@ test("tokenizeSubtitleService does not log Yomitan groups when debug toggle is d ); }); -test("tokenizeSubtitleService preserves segmented Yomitan line as one token", async () => { +test("tokenizeSubtitle preserves segmented Yomitan line as one token", async () => { const parserWindow = { isDestroyed: () => false, webContents: { @@ -1025,7 +1025,7 @@ test("tokenizeSubtitleService preserves segmented Yomitan line as one token", as }, } as unknown as Electron.BrowserWindow; - const result = await tokenizeSubtitleService( + const result = await tokenizeSubtitle( "猫です", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -1042,8 +1042,8 @@ test("tokenizeSubtitleService preserves segmented Yomitan line as one token", as assert.equal(result.tokens?.[0]?.isKnown, false); }); -test("tokenizeSubtitleService prefers mecab parser tokens when scanning parser returns one token", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle prefers mecab parser tokens when scanning parser returns one token", async () => { + const result = await tokenizeSubtitle( "俺は小園にいきたい", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -1091,8 +1091,8 @@ test("tokenizeSubtitleService prefers mecab parser tokens when scanning parser r assert.equal(result.tokens?.[2]?.frequencyRank, 25); }); -test("tokenizeSubtitleService keeps scanning parser tokens when they are already split", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle keeps scanning parser tokens when they are already split", async () => { + const result = await tokenizeSubtitle( "小園に行きたい", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -1139,8 +1139,8 @@ test("tokenizeSubtitleService keeps scanning parser tokens when they are already assert.equal(result.tokens?.[2]?.frequencyRank, undefined); }); -test("tokenizeSubtitleService prefers parse candidates with fewer fragment-only kana tokens when source priority is equal", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle prefers parse candidates with fewer fragment-only kana tokens when source priority is equal", async () => { + const result = await tokenizeSubtitle( "俺は公園にいきたい", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -1192,8 +1192,8 @@ test("tokenizeSubtitleService prefers parse candidates with fewer fragment-only assert.equal(result.tokens?.[4]?.frequencyRank, 1500); }); -test("tokenizeSubtitleService still assigns frequency to non-known Yomitan tokens", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle still assigns frequency to non-known Yomitan tokens", async () => { + const result = await tokenizeSubtitle( "小園に", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -1229,8 +1229,8 @@ test("tokenizeSubtitleService still assigns frequency to non-known Yomitan token assert.equal(result.tokens?.[1]?.frequencyRank, 3000); }); -test("tokenizeSubtitleService marks tokens as known using callback", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle marks tokens as known using callback", async () => { + const result = await tokenizeSubtitle( "猫です", makeDepsFromMecabTokenizer(async () => [ { @@ -1255,8 +1255,8 @@ test("tokenizeSubtitleService marks tokens as known using callback", async () => assert.equal(result.tokens?.[0]?.isKnown, true); }); -test("tokenizeSubtitleService still assigns frequency rank to non-known tokens", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle still assigns frequency rank to non-known tokens", async () => { + const result = await tokenizeSubtitle( "既知未知", makeDeps({ tokenizeWithMecab: async () => [ @@ -1312,8 +1312,8 @@ test("tokenizeSubtitleService still assigns frequency rank to non-known tokens", assert.equal(result.tokens?.[1]?.frequencyRank, 30); }); -test("tokenizeSubtitleService selects one N+1 target token", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle selects one N+1 target token", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ tokenizeWithMecab: async () => [ @@ -1349,8 +1349,8 @@ test("tokenizeSubtitleService selects one N+1 target token", async () => { assert.equal(targets[0]?.surface, "犬"); }); -test("tokenizeSubtitleService does not mark target when sentence has multiple candidates", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle does not mark target when sentence has multiple candidates", async () => { + const result = await tokenizeSubtitle( "猫犬", makeDeps({ tokenizeWithMecab: async () => [ @@ -1386,7 +1386,7 @@ test("tokenizeSubtitleService does not mark target when sentence has multiple ca ); }); -test("tokenizeSubtitleService applies N+1 target marking to Yomitan results", async () => { +test("tokenizeSubtitle applies N+1 target marking to Yomitan results", async () => { const parserWindow = { isDestroyed: () => false, webContents: { @@ -1415,7 +1415,7 @@ test("tokenizeSubtitleService applies N+1 target marking to Yomitan results", as }, } as unknown as Electron.BrowserWindow; - const result = await tokenizeSubtitleService( + const result = await tokenizeSubtitle( "猫です", makeDeps({ getYomitanExt: () => ({ id: "dummy-ext" } as any), @@ -1433,8 +1433,8 @@ test("tokenizeSubtitleService applies N+1 target marking to Yomitan results", as assert.equal(result.tokens?.[1]?.isNPlusOneTarget, false); }); -test("tokenizeSubtitleService does not color 1-2 word sentences by default", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle does not color 1-2 word sentences by default", async () => { + const result = await tokenizeSubtitle( "猫です", makeDeps({ tokenizeWithMecab: async () => [ @@ -1470,8 +1470,8 @@ test("tokenizeSubtitleService does not color 1-2 word sentences by default", asy ); }); -test("tokenizeSubtitleService checks known words by headword, not surface", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle checks known words by headword, not surface", async () => { + const result = await tokenizeSubtitle( "猫です", makeDepsFromMecabTokenizer(async () => [ { @@ -1496,8 +1496,8 @@ test("tokenizeSubtitleService checks known words by headword, not surface", asyn assert.equal(result.tokens?.[0]?.isKnown, true); }); -test("tokenizeSubtitleService checks known words by surface when configured", async () => { - const result = await tokenizeSubtitleService( +test("tokenizeSubtitle checks known words by surface when configured", async () => { + const result = await tokenizeSubtitle( "猫です", makeDepsFromMecabTokenizer(async () => [ { diff --git a/src/core/services/tokenizer-service.ts b/src/core/services/tokenizer.ts similarity index 99% rename from src/core/services/tokenizer-service.ts rename to src/core/services/tokenizer.ts index 76c4dbd..325c729 100644 --- a/src/core/services/tokenizer-service.ts +++ b/src/core/services/tokenizer.ts @@ -182,7 +182,7 @@ function getCachedFrequencyRank( return rank; } -export function createTokenizerDepsRuntimeService( +export function createTokenizerDepsRuntime( options: TokenizerDepsRuntimeOptions, ): TokenizerServiceDeps { return { @@ -983,7 +983,7 @@ async function parseWithYomitanInternalParser( } } -export async function tokenizeSubtitleService( +export async function tokenizeSubtitle( text: string, deps: TokenizerServiceDeps, ): Promise { diff --git a/src/core/services/yomitan-extension-loader-service.ts b/src/core/services/yomitan-extension-loader.ts similarity index 98% rename from src/core/services/yomitan-extension-loader-service.ts rename to src/core/services/yomitan-extension-loader.ts index 946e4d6..33bc175 100644 --- a/src/core/services/yomitan-extension-loader-service.ts +++ b/src/core/services/yomitan-extension-loader.ts @@ -58,7 +58,7 @@ function ensureExtensionCopy(sourceDir: string, userDataPath: string): string { return targetDir; } -export async function loadYomitanExtensionService( +export async function loadYomitanExtension( deps: YomitanExtensionLoaderDeps, ): Promise { const searchPaths = [ diff --git a/src/core/services/yomitan-settings-service.ts b/src/core/services/yomitan-settings.ts similarity index 100% rename from src/core/services/yomitan-settings-service.ts rename to src/core/services/yomitan-settings.ts diff --git a/src/main.ts b/src/main.ts index 4e1d5b8..ace7b73 100644 --- a/src/main.ts +++ b/src/main.ts @@ -85,53 +85,53 @@ import { } from "./core/utils"; import { MpvIpcClient, - SubtitleWebSocketService, - TexthookerService, - applyMpvSubtitleRenderMetricsPatchService, - broadcastRuntimeOptionsChangedRuntimeService, - copyCurrentSubtitleService, - createOverlayManagerService, - createFieldGroupingOverlayRuntimeService, - createNumericShortcutRuntimeService, - createOverlayContentMeasurementStoreService, - createOverlayWindowService, - createTokenizerDepsRuntimeService, - cycleSecondarySubModeService, - enforceOverlayLayerOrderService, - ensureOverlayWindowLevelService, - getInitialInvisibleOverlayVisibilityService, - getJimakuLanguagePreferenceService, - getJimakuMaxEntryResultsService, - handleMineSentenceDigitService, - handleMultiCopyDigitService, + SubtitleWebSocket, + Texthooker, + applyMpvSubtitleRenderMetricsPatch, + broadcastRuntimeOptionsChangedRuntime, + copyCurrentSubtitle as copyCurrentSubtitleCore, + createOverlayManager, + createFieldGroupingOverlayRuntime, + createNumericShortcutRuntime, + createOverlayContentMeasurementStore, + createOverlayWindow as createOverlayWindowCore, + createTokenizerDepsRuntime, + cycleSecondarySubMode as cycleSecondarySubModeCore, + enforceOverlayLayerOrder as enforceOverlayLayerOrderCore, + ensureOverlayWindowLevel as ensureOverlayWindowLevelCore, + getInitialInvisibleOverlayVisibility as getInitialInvisibleOverlayVisibilityCore, + getJimakuLanguagePreference as getJimakuLanguagePreferenceCore, + getJimakuMaxEntryResults as getJimakuMaxEntryResultsCore, + handleMineSentenceDigit as handleMineSentenceDigitCore, + handleMultiCopyDigit as handleMultiCopyDigitCore, hasMpvWebsocketPlugin, - initializeOverlayRuntimeService, - isAutoUpdateEnabledRuntimeService, - jimakuFetchJsonService, - loadSubtitlePositionService, - loadYomitanExtensionService, - markLastCardAsAudioCardService, + initializeOverlayRuntime as initializeOverlayRuntimeCore, + isAutoUpdateEnabledRuntime as isAutoUpdateEnabledRuntimeCore, + jimakuFetchJson as jimakuFetchJsonCore, + loadSubtitlePosition as loadSubtitlePositionCore, + loadYomitanExtension as loadYomitanExtensionCore, + markLastCardAsAudioCard as markLastCardAsAudioCardCore, DEFAULT_MPV_SUBTITLE_RENDER_METRICS, - mineSentenceCardService, + mineSentenceCard as mineSentenceCardCore, ImmersionTrackerService, openYomitanSettingsWindow, - playNextSubtitleRuntimeService, - registerGlobalShortcutsService, - replayCurrentSubtitleRuntimeService, - resolveJimakuApiKeyService, - runStartupBootstrapRuntimeService, - saveSubtitlePositionService, - sendMpvCommandRuntimeService, - setInvisibleOverlayVisibleService, - setMpvSubVisibilityRuntimeService, - setOverlayDebugVisualizationEnabledRuntimeService, - setVisibleOverlayVisibleService, - shouldAutoInitializeOverlayRuntimeFromConfigService, - shouldBindVisibleOverlayToMpvSubVisibilityService, - showMpvOsdRuntimeService, - tokenizeSubtitleService, - triggerFieldGroupingService, - updateLastCardFromClipboardService, + playNextSubtitleRuntime, + registerGlobalShortcuts as registerGlobalShortcutsCore, + replayCurrentSubtitleRuntime, + resolveJimakuApiKey as resolveJimakuApiKeyCore, + runStartupBootstrapRuntime, + saveSubtitlePosition as saveSubtitlePositionCore, + sendMpvCommandRuntime, + setInvisibleOverlayVisible as setInvisibleOverlayVisibleCore, + setMpvSubVisibilityRuntime, + setOverlayDebugVisualizationEnabledRuntime, + setVisibleOverlayVisible as setVisibleOverlayVisibleCore, + shouldAutoInitializeOverlayRuntimeFromConfig as shouldAutoInitializeOverlayRuntimeFromConfigCore, + shouldBindVisibleOverlayToMpvSubVisibility as shouldBindVisibleOverlayToMpvSubVisibilityCore, + showMpvOsdRuntime, + tokenizeSubtitle as tokenizeSubtitleCore, + triggerFieldGrouping as triggerFieldGroupingCore, + updateLastCardFromClipboard as updateLastCardFromClipboardCore, } from "./core/services"; import { guessAnilistMediaInfo, @@ -140,7 +140,7 @@ import { } from "./core/services/anilist/anilist-updater"; import { createAnilistTokenStore } from "./core/services/anilist/anilist-token-store"; import { createAnilistUpdateQueue } from "./core/services/anilist/anilist-update-queue"; -import { applyRuntimeOptionResultRuntimeService } from "./core/services/runtime-options-ipc-service"; +import { applyRuntimeOptionResultRuntime } from "./core/services/runtime-options-ipc"; import { createAppReadyRuntimeRunner, } from "./main/app-lifecycle"; @@ -283,8 +283,8 @@ const anilistUpdateQueue = createAnilistUpdateQueue( ); const isDev = process.argv.includes("--dev") || process.argv.includes("--debug"); -const texthookerService = new TexthookerService(); -const subtitleWsService = new SubtitleWebSocketService(); +const texthookerService = new Texthooker(); +const subtitleWsService = new SubtitleWebSocket(); const logger = createLogger("main"); const appLogger = { logInfo: (message: string) => { @@ -330,8 +330,8 @@ process.on("SIGTERM", () => { app.quit(); }); -const overlayManager = createOverlayManagerService(); -const overlayContentMeasurementStore = createOverlayContentMeasurementStoreService({ +const overlayManager = createOverlayManager(); +const overlayContentMeasurementStore = createOverlayContentMeasurementStore({ now: () => Date.now(), warn: (message: string) => logger.warn(message), }); @@ -460,7 +460,7 @@ function setFieldGroupingResolver( appState.fieldGroupingResolver = wrappedResolver; } -const fieldGroupingOverlayRuntime = createFieldGroupingOverlayRuntimeService({ +const fieldGroupingOverlayRuntime = createFieldGroupingOverlayRuntime({ getMainWindow: () => overlayManager.getMainWindow(), getVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(), getInvisibleOverlayVisible: () => overlayManager.getInvisibleOverlayVisible(), @@ -548,7 +548,7 @@ function broadcastToOverlayWindows(channel: string, ...args: unknown[]): void { } function broadcastRuntimeOptionsChanged(): void { - broadcastRuntimeOptionsChangedRuntimeService( + broadcastRuntimeOptionsChangedRuntime( () => getRuntimeOptionsState(), (channel, ...args) => broadcastToOverlayWindows(channel, ...args), ); @@ -567,7 +567,7 @@ function sendToActiveOverlayWindow( } function setOverlayDebugVisualizationEnabled(enabled: boolean): void { - setOverlayDebugVisualizationEnabledRuntimeService( + setOverlayDebugVisualizationEnabledRuntime( appState.overlayDebugVisualizationEnabled, enabled, (next) => { @@ -646,32 +646,32 @@ async function getCurrentMpvMediaStateForTracker(): Promise } function getInitialInvisibleOverlayVisibility(): boolean { - return getInitialInvisibleOverlayVisibilityService( + return getInitialInvisibleOverlayVisibilityCore( getResolvedConfig(), process.platform, ); } function shouldAutoInitializeOverlayRuntimeFromConfig(): boolean { - return shouldAutoInitializeOverlayRuntimeFromConfigService(getResolvedConfig()); + return shouldAutoInitializeOverlayRuntimeFromConfigCore(getResolvedConfig()); } function shouldBindVisibleOverlayToMpvSubVisibility(): boolean { - return shouldBindVisibleOverlayToMpvSubVisibilityService(getResolvedConfig()); + return shouldBindVisibleOverlayToMpvSubVisibilityCore(getResolvedConfig()); } function isAutoUpdateEnabledRuntime(): boolean { - return isAutoUpdateEnabledRuntimeService( + return isAutoUpdateEnabledRuntimeCore( getResolvedConfig(), appState.runtimeOptionsManager, ); } -function getJimakuLanguagePreference(): JimakuLanguagePreference { return getJimakuLanguagePreferenceService(() => getResolvedConfig(), DEFAULT_CONFIG.jimaku.languagePreference); } +function getJimakuLanguagePreference(): JimakuLanguagePreference { return getJimakuLanguagePreferenceCore(() => getResolvedConfig(), DEFAULT_CONFIG.jimaku.languagePreference); } -function getJimakuMaxEntryResults(): number { return getJimakuMaxEntryResultsService(() => getResolvedConfig(), DEFAULT_CONFIG.jimaku.maxEntryResults); } +function getJimakuMaxEntryResults(): number { return getJimakuMaxEntryResultsCore(() => getResolvedConfig(), DEFAULT_CONFIG.jimaku.maxEntryResults); } -async function resolveJimakuApiKey(): Promise { return resolveJimakuApiKeyService(() => getResolvedConfig()); } +async function resolveJimakuApiKey(): Promise { return resolveJimakuApiKeyCore(() => getResolvedConfig()); } function seedImmersionTrackerFromCurrentMedia(): void { const tracker = appState.immersionTracker; @@ -754,7 +754,7 @@ async function jimakuFetchJson( endpoint: string, query: Record = {}, ): Promise> { - return jimakuFetchJsonService(endpoint, query, { + return jimakuFetchJsonCore(endpoint, query, { getResolvedConfig: () => getResolvedConfig(), defaultBaseUrl: DEFAULT_CONFIG.jimaku.apiBaseUrl, defaultMaxEntryResults: DEFAULT_CONFIG.jimaku.maxEntryResults, @@ -1193,7 +1193,7 @@ async function maybeRunAnilistPostWatchUpdate(): Promise { } function loadSubtitlePosition(): SubtitlePosition | null { - appState.subtitlePosition = loadSubtitlePositionService({ + appState.subtitlePosition = loadSubtitlePositionCore({ currentMediaPath: appState.currentMediaPath, fallbackPosition: getResolvedConfig().subtitlePosition, subtitlePositionsDir: SUBTITLE_POSITIONS_DIR, @@ -1203,7 +1203,7 @@ function loadSubtitlePosition(): SubtitlePosition | null { function saveSubtitlePosition(position: SubtitlePosition): void { appState.subtitlePosition = position; - saveSubtitlePositionService({ + saveSubtitlePositionCore({ position, currentMediaPath: appState.currentMediaPath, subtitlePositionsDir: SUBTITLE_POSITIONS_DIR, @@ -1216,7 +1216,7 @@ function saveSubtitlePosition(position: SubtitlePosition): void { }); } -const startupState = runStartupBootstrapRuntimeService( +const startupState = runStartupBootstrapRuntime( createStartupBootstrapRuntimeDeps({ argv: process.argv, parseArgs: (argv: string[]) => parseArgs(argv), @@ -1558,7 +1558,7 @@ function createMpvClientRuntimeService(): MpvIpcClient { function updateMpvSubtitleRenderMetrics( patch: Partial, ): void { - const { next, changed } = applyMpvSubtitleRenderMetricsPatchService( + const { next, changed } = applyMpvSubtitleRenderMetricsPatch( appState.mpvSubtitleRenderMetrics, patch, ); @@ -1573,9 +1573,9 @@ function updateMpvSubtitleRenderMetrics( async function tokenizeSubtitle(text: string): Promise { await jlptDictionaryRuntime.ensureJlptDictionaryLookup(); await frequencyDictionaryRuntime.ensureFrequencyDictionaryLookup(); - return tokenizeSubtitleService( + return tokenizeSubtitleCore( text, - createTokenizerDepsRuntimeService({ + createTokenizerDepsRuntime({ getYomitanExt: () => appState.yomitanExt, getYomitanParserWindow: () => appState.yomitanParserWindow, setYomitanParserWindow: (window) => { @@ -1621,11 +1621,11 @@ function updateInvisibleOverlayBounds(geometry: WindowGeometry): void { } function ensureOverlayWindowLevel(window: BrowserWindow): void { - ensureOverlayWindowLevelService(window); + ensureOverlayWindowLevelCore(window); } function enforceOverlayLayerOrder(): void { - enforceOverlayLayerOrderService({ + enforceOverlayLayerOrderCore({ visibleOverlayVisible: overlayManager.getVisibleOverlayVisible(), invisibleOverlayVisible: overlayManager.getInvisibleOverlayVisible(), mainWindow: overlayManager.getMainWindow(), @@ -1635,7 +1635,7 @@ function enforceOverlayLayerOrder(): void { } async function loadYomitanExtension(): Promise { - return loadYomitanExtensionService({ + return loadYomitanExtensionCore({ userDataPath: USER_DATA_PATH, getYomitanParserWindow: () => appState.yomitanParserWindow, setYomitanParserWindow: (window) => { @@ -1654,7 +1654,7 @@ async function loadYomitanExtension(): Promise { } function createOverlayWindow(kind: "visible" | "invisible"): BrowserWindow { - return createOverlayWindowService( + return createOverlayWindowCore( kind, { isDev, @@ -1695,7 +1695,7 @@ function initializeOverlayRuntime(): void { if (appState.overlayRuntimeInitialized) { return; } - const result = initializeOverlayRuntimeService( + const result = initializeOverlayRuntimeCore( { backendOverride: appState.backendOverride, getInitialInvisibleOverlayVisibility: () => @@ -1759,7 +1759,7 @@ function openYomitanSettings(): void { ); } function registerGlobalShortcuts(): void { - registerGlobalShortcutsService( + registerGlobalShortcutsCore( { shortcuts: getConfiguredShortcuts(), onToggleVisibleOverlay: () => toggleVisibleOverlay(), @@ -1774,7 +1774,7 @@ function registerGlobalShortcuts(): void { function getConfiguredShortcuts() { return resolveConfiguredShortcuts(getResolvedConfig(), DEFAULT_CONFIG); } function cycleSecondarySubMode(): void { - cycleSecondarySubModeService( + cycleSecondarySubModeCore( { getSecondarySubMode: () => appState.secondarySubMode, setSecondarySubMode: (mode: SecondarySubMode) => { @@ -1794,7 +1794,7 @@ function cycleSecondarySubMode(): void { function showMpvOsd(text: string): void { appendToMpvLog(`[OSD] ${text}`); - showMpvOsdRuntimeService( + showMpvOsdRuntime( appState.mpvClient, text, (line) => { @@ -1816,7 +1816,7 @@ function appendToMpvLog(message: string): void { } } -const numericShortcutRuntime = createNumericShortcutRuntimeService({ +const numericShortcutRuntime = createNumericShortcutRuntime({ globalShortcut, showMpvOsd: (text) => showMpvOsd(text), setTimer: (handler, timeoutMs) => setTimeout(handler, timeoutMs), @@ -1863,7 +1863,7 @@ function startPendingMultiCopy(timeoutMs: number): void { } function handleMultiCopyDigit(count: number): void { - handleMultiCopyDigitService( + handleMultiCopyDigitCore( count, { subtitleTimingTracker: appState.subtitleTimingTracker, @@ -1874,7 +1874,7 @@ function handleMultiCopyDigit(count: number): void { } function copyCurrentSubtitle(): void { - copyCurrentSubtitleService( + copyCurrentSubtitleCore( { subtitleTimingTracker: appState.subtitleTimingTracker, writeClipboardText: (text) => clipboard.writeText(text), @@ -1884,7 +1884,7 @@ function copyCurrentSubtitle(): void { } async function updateLastCardFromClipboard(): Promise { - await updateLastCardFromClipboardService( + await updateLastCardFromClipboardCore( { ankiIntegration: appState.ankiIntegration, readClipboardText: () => clipboard.readText(), @@ -1902,7 +1902,7 @@ async function refreshKnownWordCache(): Promise { } async function triggerFieldGrouping(): Promise { - await triggerFieldGroupingService( + await triggerFieldGroupingCore( { ankiIntegration: appState.ankiIntegration, showMpvOsd: (text) => showMpvOsd(text), @@ -1911,7 +1911,7 @@ async function triggerFieldGrouping(): Promise { } async function markLastCardAsAudioCard(): Promise { - await markLastCardAsAudioCardService( + await markLastCardAsAudioCardCore( { ankiIntegration: appState.ankiIntegration, showMpvOsd: (text) => showMpvOsd(text), @@ -1920,7 +1920,7 @@ async function markLastCardAsAudioCard(): Promise { } async function mineSentenceCard(): Promise { - const created = await mineSentenceCardService( + const created = await mineSentenceCardCore( { ankiIntegration: appState.ankiIntegration, mpvClient: appState.mpvClient, @@ -1949,7 +1949,7 @@ function startPendingMineSentenceMultiple(timeoutMs: number): void { } function handleMineSentenceDigit(count: number): void { - handleMineSentenceDigitService( + handleMineSentenceDigitCore( count, { subtitleTimingTracker: appState.subtitleTimingTracker, @@ -1983,7 +1983,7 @@ function refreshOverlayShortcuts(): void { } function setVisibleOverlayVisible(visible: boolean): void { - setVisibleOverlayVisibleService({ + setVisibleOverlayVisibleCore({ visible, setVisibleOverlayVisibleState: (nextVisible) => { overlayManager.setVisibleOverlayVisible(nextVisible); @@ -1998,13 +1998,13 @@ function setVisibleOverlayVisible(visible: boolean): void { shouldBindVisibleOverlayToMpvSubVisibility(), isMpvConnected: () => Boolean(appState.mpvClient && appState.mpvClient.connected), setMpvSubVisibility: (mpvSubVisible) => { - setMpvSubVisibilityRuntimeService(appState.mpvClient, mpvSubVisible); + setMpvSubVisibilityRuntime(appState.mpvClient, mpvSubVisible); }, }); } function setInvisibleOverlayVisible(visible: boolean): void { - setInvisibleOverlayVisibleService({ + setInvisibleOverlayVisibleCore({ visible, setInvisibleOverlayVisibleState: (nextVisible) => { overlayManager.setInvisibleOverlayVisible(nextVisible); @@ -2036,16 +2036,16 @@ function handleMpvCommandFromIpc(command: (string | number)[]): void { if (!appState.runtimeOptionsManager) { return { ok: false, error: "Runtime options manager unavailable" }; } - return applyRuntimeOptionResultRuntimeService( + return applyRuntimeOptionResultRuntime( appState.runtimeOptionsManager.cycleOption(id, direction), (text) => showMpvOsd(text), ); }, showMpvOsd: (text: string) => showMpvOsd(text), - replayCurrentSubtitle: () => replayCurrentSubtitleRuntimeService(appState.mpvClient), - playNextSubtitle: () => playNextSubtitleRuntimeService(appState.mpvClient), + replayCurrentSubtitle: () => replayCurrentSubtitleRuntime(appState.mpvClient), + playNextSubtitle: () => playNextSubtitleRuntime(appState.mpvClient), sendMpvCommand: (rawCommand: (string | number)[]) => - sendMpvCommandRuntimeService(appState.mpvClient, rawCommand), + sendMpvCommandRuntime(appState.mpvClient, rawCommand), isMpvConnected: () => Boolean(appState.mpvClient && appState.mpvClient.connected), hasRuntimeOptionsManager: () => appState.runtimeOptionsManager !== null, }); diff --git a/src/main/app-lifecycle.ts b/src/main/app-lifecycle.ts index c25f645..47ca562 100644 --- a/src/main/app-lifecycle.ts +++ b/src/main/app-lifecycle.ts @@ -1,7 +1,7 @@ import type { CliArgs, CliCommandSource } from "../cli/args"; -import { runAppReadyRuntimeService } from "../core/services/startup-service"; -import type { AppReadyRuntimeDeps } from "../core/services/startup-service"; -import type { AppLifecycleDepsRuntimeOptions } from "../core/services/app-lifecycle-service"; +import { runAppReadyRuntime } from "../core/services/startup"; +import type { AppReadyRuntimeDeps } from "../core/services/startup"; +import type { AppLifecycleDepsRuntimeOptions } from "../core/services/app-lifecycle"; export interface AppLifecycleRuntimeDepsFactoryInput { app: AppLifecycleDepsRuntimeOptions["app"]; @@ -96,6 +96,6 @@ export function createAppReadyRuntimeRunner( params: AppReadyRuntimeDepsFactoryInput, ): () => Promise { return async () => { - await runAppReadyRuntimeService(createAppReadyRuntimeDeps(params)); + await runAppReadyRuntime(createAppReadyRuntimeDeps(params)); }; } diff --git a/src/main/cli-runtime.ts b/src/main/cli-runtime.ts index df7de43..e55a361 100644 --- a/src/main/cli-runtime.ts +++ b/src/main/cli-runtime.ts @@ -1,4 +1,4 @@ -import { handleCliCommandService, createCliCommandDepsRuntimeService } from "../core/services"; +import { handleCliCommand, createCliCommandDepsRuntime } from "../core/services"; import type { CliArgs, CliCommandSource } from "../cli/args"; import { createCliCommandRuntimeServiceDeps, CliCommandRuntimeServiceDepsParams } from "./dependencies"; @@ -102,10 +102,10 @@ export function handleCliCommandRuntimeService( source: CliCommandSource, params: CliCommandRuntimeServiceDepsParams, ): void { - const deps = createCliCommandDepsRuntimeService( + const deps = createCliCommandDepsRuntime( createCliCommandRuntimeServiceDeps(params), ); - handleCliCommandService(args, source, deps); + handleCliCommand(args, source, deps); } export function handleCliCommandRuntimeServiceWithContext( diff --git a/src/main/dependencies.ts b/src/main/dependencies.ts index 38f0e56..144bd90 100644 --- a/src/main/dependencies.ts +++ b/src/main/dependencies.ts @@ -4,15 +4,15 @@ import { SubsyncManualPayload, } from "../types"; import { SubsyncResolvedConfig } from "../subsync/utils"; -import type { SubsyncRuntimeDeps } from "../core/services/subsync-runner-service"; -import type { IpcDepsRuntimeOptions } from "../core/services/ipc-service"; -import type { AnkiJimakuIpcRuntimeOptions } from "../core/services/anki-jimaku-service"; -import type { CliCommandDepsRuntimeOptions } from "../core/services/cli-command-service"; -import type { HandleMpvCommandFromIpcOptions } from "../core/services/ipc-command-service"; +import type { SubsyncRuntimeDeps } from "../core/services/subsync-runner"; +import type { IpcDepsRuntimeOptions } from "../core/services/ipc"; +import type { AnkiJimakuIpcRuntimeOptions } from "../core/services/anki-jimaku"; +import type { CliCommandDepsRuntimeOptions } from "../core/services/cli-command"; +import type { HandleMpvCommandFromIpcOptions } from "../core/services/ipc-command"; import { - cycleRuntimeOptionFromIpcRuntimeService, - setRuntimeOptionFromIpcRuntimeService, -} from "../core/services/runtime-options-ipc-service"; + cycleRuntimeOptionFromIpcRuntime, + setRuntimeOptionFromIpcRuntime, +} from "../core/services/runtime-options-ipc"; import { RuntimeOptionsManager } from "../runtime-options"; export interface RuntimeOptionsIpcDepsParams { @@ -35,14 +35,14 @@ export function createRuntimeOptionsIpcDeps(params: RuntimeOptionsIpcDepsParams) } { return { setRuntimeOption: (id, value) => - setRuntimeOptionFromIpcRuntimeService( + setRuntimeOptionFromIpcRuntime( params.getRuntimeOptionsManager(), id as RuntimeOptionId, value as RuntimeOptionValue, (text) => params.showMpvOsd(text), ), cycleRuntimeOption: (id, direction) => - cycleRuntimeOptionFromIpcRuntimeService( + cycleRuntimeOptionFromIpcRuntime( params.getRuntimeOptionsManager(), id as RuntimeOptionId, direction, diff --git a/src/main/frequency-dictionary-runtime.ts b/src/main/frequency-dictionary-runtime.ts index 00f1a19..4ea4585 100644 --- a/src/main/frequency-dictionary-runtime.ts +++ b/src/main/frequency-dictionary-runtime.ts @@ -1,6 +1,6 @@ import * as path from "path"; import type { FrequencyDictionaryLookup } from "../types"; -import { createFrequencyDictionaryLookupService } from "../core/services"; +import { createFrequencyDictionaryLookup } from "../core/services"; export interface FrequencyDictionarySearchPathDeps { getDictionaryRoots: () => string[]; @@ -47,7 +47,7 @@ export function getFrequencyDictionarySearchPaths( export async function initializeFrequencyDictionaryLookup( deps: FrequencyDictionaryRuntimeDeps, ): Promise { - const lookup = await createFrequencyDictionaryLookupService({ + const lookup = await createFrequencyDictionaryLookup({ searchPaths: deps.getSearchPaths(), log: deps.log, }); diff --git a/src/main/ipc-mpv-command.ts b/src/main/ipc-mpv-command.ts index 716296c..c8b7dd0 100644 --- a/src/main/ipc-mpv-command.ts +++ b/src/main/ipc-mpv-command.ts @@ -1,5 +1,5 @@ import type { RuntimeOptionApplyResult, RuntimeOptionId } from "../types"; -import { handleMpvCommandFromIpcService } from "../core/services"; +import { handleMpvCommandFromIpc } from "../core/services"; import { createMpvCommandRuntimeServiceDeps } from "./dependencies"; import { SPECIAL_COMMANDS } from "../config"; @@ -22,7 +22,7 @@ export function handleMpvCommandFromIpcRuntime( command: (string | number)[], deps: MpvCommandFromIpcRuntimeDeps, ): void { - handleMpvCommandFromIpcService( + handleMpvCommandFromIpc( command, createMpvCommandRuntimeServiceDeps({ specialCommands: SPECIAL_COMMANDS, diff --git a/src/main/ipc-runtime.ts b/src/main/ipc-runtime.ts index 8a2a9db..e7500d9 100644 --- a/src/main/ipc-runtime.ts +++ b/src/main/ipc-runtime.ts @@ -1,9 +1,9 @@ import { - createIpcDepsRuntimeService, - registerAnkiJimakuIpcRuntimeService, - registerIpcHandlersService, + createIpcDepsRuntime, + registerAnkiJimakuIpcRuntime, + registerIpcHandlers, } from "../core/services"; -import { registerAnkiJimakuIpcHandlers } from "../core/services/anki-jimaku-ipc-service"; +import { registerAnkiJimakuIpcHandlers } from "../core/services/anki-jimaku-ipc"; import { createAnkiJimakuIpcRuntimeServiceDeps, AnkiJimakuIpcRuntimeServiceDepsParams, @@ -25,15 +25,15 @@ export interface RegisterIpcRuntimeServicesParams { export function registerMainIpcRuntimeServices( params: MainIpcRuntimeServiceDepsParams, ): void { - registerIpcHandlersService( - createIpcDepsRuntimeService(createMainIpcRuntimeServiceDeps(params)), + registerIpcHandlers( + createIpcDepsRuntime(createMainIpcRuntimeServiceDeps(params)), ); } export function registerAnkiJimakuIpcRuntimeServices( params: AnkiJimakuIpcRuntimeServiceDepsParams, ): void { - registerAnkiJimakuIpcRuntimeService( + registerAnkiJimakuIpcRuntime( createAnkiJimakuIpcRuntimeServiceDeps(params), registerAnkiJimakuIpcHandlers, ); diff --git a/src/main/jlpt-runtime.ts b/src/main/jlpt-runtime.ts index a48558d..4c6b4fa 100644 --- a/src/main/jlpt-runtime.ts +++ b/src/main/jlpt-runtime.ts @@ -1,7 +1,7 @@ import * as path from "path"; import type { JlptLevel } from "../types"; -import { createJlptVocabularyLookupService } from "../core/services"; +import { createJlptVocabularyLookup } from "../core/services"; export interface JlptDictionarySearchPathDeps { getDictionaryRoots: () => string[]; @@ -39,7 +39,7 @@ export async function initializeJlptDictionaryLookup( deps: JlptDictionaryRuntimeDeps, ): Promise { deps.setJlptLevelLookup( - await createJlptVocabularyLookupService({ + await createJlptVocabularyLookup({ searchPaths: deps.getSearchPaths(), log: deps.log, }), diff --git a/src/main/media-runtime.ts b/src/main/media-runtime.ts index dedc556..d7585ef 100644 --- a/src/main/media-runtime.ts +++ b/src/main/media-runtime.ts @@ -1,4 +1,4 @@ -import { updateCurrentMediaPathService } from "../core/services"; +import { updateCurrentMediaPath } from "../core/services"; import type { SubtitlePosition } from "../types"; @@ -31,7 +31,7 @@ export function createMediaRuntimeService( deps.setCurrentMediaTitle(null); } - updateCurrentMediaPathService({ + updateCurrentMediaPath({ mediaPath, currentMediaPath: deps.getCurrentMediaPath(), pendingSubtitlePosition: deps.getPendingSubtitlePosition(), diff --git a/src/main/overlay-shortcuts-runtime.ts b/src/main/overlay-shortcuts-runtime.ts index 7f9b1df..284ceb2 100644 --- a/src/main/overlay-shortcuts-runtime.ts +++ b/src/main/overlay-shortcuts-runtime.ts @@ -4,10 +4,10 @@ import { shortcutMatchesInputForLocalFallback, } from "../core/services"; import { - refreshOverlayShortcutsRuntimeService, - registerOverlayShortcutsService, - syncOverlayShortcutsRuntimeService, - unregisterOverlayShortcutsRuntimeService, + refreshOverlayShortcutsRuntime, + registerOverlayShortcuts, + syncOverlayShortcutsRuntime, + unregisterOverlayShortcutsRuntime, } from "../core/services"; import { runOverlayShortcutLocalFallback } from "../core/services/overlay-shortcut-handler"; @@ -102,7 +102,7 @@ export function createOverlayShortcutsRuntimeService( ), registerOverlayShortcuts: () => { input.setShortcutsRegistered( - registerOverlayShortcutsService( + registerOverlayShortcuts( input.getConfiguredShortcuts(), handlers.overlayHandlers, ), @@ -110,7 +110,7 @@ export function createOverlayShortcutsRuntimeService( }, unregisterOverlayShortcuts: () => { input.setShortcutsRegistered( - unregisterOverlayShortcutsRuntimeService( + unregisterOverlayShortcutsRuntime( input.getShortcutsRegistered(), getShortcutLifecycleDeps(), ), @@ -118,7 +118,7 @@ export function createOverlayShortcutsRuntimeService( }, syncOverlayShortcuts: () => { input.setShortcutsRegistered( - syncOverlayShortcutsRuntimeService( + syncOverlayShortcutsRuntime( shouldOverlayShortcutsBeActive(), input.getShortcutsRegistered(), getShortcutLifecycleDeps(), @@ -127,7 +127,7 @@ export function createOverlayShortcutsRuntimeService( }, refreshOverlayShortcuts: () => { input.setShortcutsRegistered( - refreshOverlayShortcutsRuntimeService( + refreshOverlayShortcutsRuntime( shouldOverlayShortcutsBeActive(), input.getShortcutsRegistered(), getShortcutLifecycleDeps(), diff --git a/src/main/overlay-visibility-runtime.ts b/src/main/overlay-visibility-runtime.ts index 17999ff..5b61c86 100644 --- a/src/main/overlay-visibility-runtime.ts +++ b/src/main/overlay-visibility-runtime.ts @@ -3,9 +3,9 @@ import type { BrowserWindow } from "electron"; import type { BaseWindowTracker } from "../window-trackers"; import type { WindowGeometry } from "../types"; import { - syncInvisibleOverlayMousePassthroughService, - updateInvisibleOverlayVisibilityService, - updateVisibleOverlayVisibilityService, + syncInvisibleOverlayMousePassthrough, + updateInvisibleOverlayVisibility, + updateVisibleOverlayVisibility, } from "../core/services"; export interface OverlayVisibilityRuntimeDeps { @@ -48,7 +48,7 @@ export function createOverlayVisibilityRuntimeService( return { updateVisibleOverlayVisibility(): void { - updateVisibleOverlayVisibilityService({ + updateVisibleOverlayVisibility({ visibleOverlayVisible: deps.getVisibleOverlayVisible(), mainWindow: deps.getMainWindow(), windowTracker: deps.getWindowTracker(), @@ -66,7 +66,7 @@ export function createOverlayVisibilityRuntimeService( }, updateInvisibleOverlayVisibility(): void { - updateInvisibleOverlayVisibilityService({ + updateInvisibleOverlayVisibility({ invisibleWindow: deps.getInvisibleWindow(), visibleOverlayVisible: deps.getVisibleOverlayVisible(), invisibleOverlayVisible: deps.getInvisibleOverlayVisible(), @@ -81,7 +81,7 @@ export function createOverlayVisibilityRuntimeService( }, syncInvisibleOverlayMousePassthrough(): void { - syncInvisibleOverlayMousePassthroughService({ + syncInvisibleOverlayMousePassthrough({ hasInvisibleWindow, setIgnoreMouseEvents, visibleOverlayVisible: deps.getVisibleOverlayVisible(), diff --git a/src/main/startup-lifecycle.ts b/src/main/startup-lifecycle.ts index ac5a744..cde9800 100644 --- a/src/main/startup-lifecycle.ts +++ b/src/main/startup-lifecycle.ts @@ -1,7 +1,7 @@ import { CliArgs, CliCommandSource } from "../cli/args"; -import { createAppLifecycleDepsRuntimeService } from "../core/services"; -import { startAppLifecycleService } from "../core/services/app-lifecycle-service"; -import type { AppLifecycleDepsRuntimeOptions } from "../core/services/app-lifecycle-service"; +import { createAppLifecycleDepsRuntime } from "../core/services"; +import { startAppLifecycle } from "../core/services/app-lifecycle"; +import type { AppLifecycleDepsRuntimeOptions } from "../core/services/app-lifecycle"; import { createAppLifecycleRuntimeDeps } from "./app-lifecycle"; export interface AppLifecycleRuntimeRunnerParams { @@ -22,9 +22,9 @@ export function createAppLifecycleRuntimeRunner( params: AppLifecycleRuntimeRunnerParams, ): (args: CliArgs) => void { return (args: CliArgs): void => { - startAppLifecycleService( + startAppLifecycle( args, - createAppLifecycleDepsRuntimeService( + createAppLifecycleDepsRuntime( createAppLifecycleRuntimeDeps({ app: params.app, platform: params.platform, diff --git a/src/main/startup.ts b/src/main/startup.ts index 17b8fad..970b31e 100644 --- a/src/main/startup.ts +++ b/src/main/startup.ts @@ -1,6 +1,6 @@ import { CliArgs } from "../cli/args"; import type { ResolvedConfig } from "../types"; -import type { StartupBootstrapRuntimeDeps } from "../core/services/startup-service"; +import type { StartupBootstrapRuntimeDeps } from "../core/services/startup"; import type { LogLevelSource } from "../logger"; export interface StartupBootstrapRuntimeFactoryDeps { diff --git a/src/main/subsync-runtime.ts b/src/main/subsync-runtime.ts index 4163e26..92128bb 100644 --- a/src/main/subsync-runtime.ts +++ b/src/main/subsync-runtime.ts @@ -1,8 +1,11 @@ import { SubsyncResolvedConfig } from "../subsync/utils"; import type { SubsyncManualPayload, SubsyncManualRunRequest, SubsyncResult } from "../types"; -import type { SubsyncRuntimeDeps } from "../core/services/subsync-runner-service"; +import type { SubsyncRuntimeDeps } from "../core/services/subsync-runner"; import { createSubsyncRuntimeDeps } from "./dependencies"; -import { runSubsyncManualFromIpcRuntimeService, triggerSubsyncFromConfigRuntimeService } from "../core/services"; +import { + runSubsyncManualFromIpcRuntime as runSubsyncManualFromIpcRuntimeCore, + triggerSubsyncFromConfigRuntime as triggerSubsyncFromConfigRuntimeCore, +} from "../core/services"; export interface SubsyncRuntimeServiceInput { getMpvClient: SubsyncRuntimeDeps["getMpvClient"]; @@ -51,14 +54,14 @@ export function createSubsyncRuntimeServiceDeps( export function triggerSubsyncFromConfigRuntime( params: SubsyncRuntimeServiceInput, ): Promise { - return triggerSubsyncFromConfigRuntimeService(createSubsyncRuntimeServiceDeps(params)); + return triggerSubsyncFromConfigRuntimeCore(createSubsyncRuntimeServiceDeps(params)); } export async function runSubsyncManualFromIpcRuntime( request: SubsyncManualRunRequest, params: SubsyncRuntimeServiceInput, ): Promise { - return runSubsyncManualFromIpcRuntimeService( + return runSubsyncManualFromIpcRuntimeCore( request, createSubsyncRuntimeServiceDeps(params), );