mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
refactor(main): extract jellyfin and anilist runtime composers
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
id: TASK-71
|
id: TASK-71
|
||||||
title: Split main.ts into domain runtime modules round 2
|
title: Split main.ts into domain runtime modules round 2
|
||||||
status: To Do
|
status: In Progress
|
||||||
assignee: []
|
assignee: []
|
||||||
created_date: '2026-02-18 11:35'
|
created_date: '2026-02-18 11:35'
|
||||||
updated_date: '2026-02-18 11:35'
|
updated_date: '2026-02-21 03:40'
|
||||||
labels:
|
labels:
|
||||||
- architecture
|
- architecture
|
||||||
- refactor
|
- refactor
|
||||||
@@ -19,6 +19,15 @@ priority: high
|
|||||||
`src/main.ts` remains >3k LOC and still mixes composition, runtime state mutation, domain workflows (Jellyfin, AniList), tray/UI setup, and IPC wiring. This creates high cognitive load and broad change blast radius.
|
`src/main.ts` remains >3k LOC and still mixes composition, runtime state mutation, domain workflows (Jellyfin, AniList), tray/UI setup, and IPC wiring. This creates high cognitive load and broad change blast radius.
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Progress Notes
|
||||||
|
|
||||||
|
- Added runtime domain barrels under `src/main/runtime/domains/*` and composed registry entrypoint at `src/main/runtime/registry.ts`.
|
||||||
|
- Migrated `src/main.ts` runtime imports from per-file runtime modules to domain barrel import paths.
|
||||||
|
- Added `scripts/check-main-runtime-fanin.ts` guardrail and package scripts (`check:main-fanin`, `check:main-fanin:strict`).
|
||||||
|
- 2026-02-21: extracted jellyfin/anilist deps-builder clusters into composer modules (`src/main/runtime/composers/jellyfin-remote-composer.ts`, `src/main/runtime/composers/anilist-setup-composer.ts`) and replaced inline `main.ts` orchestration with composer invocations.
|
||||||
|
- 2026-02-21: tightened fan-in guard defaults to `import lines <= 110` and `unique runtime paths <= 11`; strict mode passing.
|
||||||
|
- Remaining TASK-71 scope: finish startup/overlay/ipc/shortcuts composer extraction to fully thin `src/main.ts`.
|
||||||
|
|
||||||
## Action Steps
|
## Action Steps
|
||||||
|
|
||||||
<!-- SECTION:PLAN:BEGIN -->
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
@@ -47,4 +56,3 @@ priority: high
|
|||||||
- [ ] #1 `bun run test:fast` passes
|
- [ ] #1 `bun run test:fast` passes
|
||||||
- [ ] #2 Architecture docs updated
|
- [ ] #2 Architecture docs updated
|
||||||
<!-- DOD:END -->
|
<!-- DOD:END -->
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
id: TASK-94
|
||||||
|
title: Reduce main.ts to thin composition root
|
||||||
|
status: In Progress
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-02-20 12:06'
|
||||||
|
updated_date: '2026-02-21 03:40'
|
||||||
|
labels:
|
||||||
|
- architecture
|
||||||
|
- refactor
|
||||||
|
- maintainability
|
||||||
|
dependencies:
|
||||||
|
- TASK-71
|
||||||
|
- TASK-85
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
`src/main.ts` still contains heavy deps-builder orchestration and high import concentration. Complete the composition-root refactor so `main.ts` owns boot wiring only and domain assembly moves behind registry/domain composer modules.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Action Steps
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Baseline current `main.ts` fan-in (`check:main-fanin`, `check:file-budgets`, `wc -l src/main.ts`).
|
||||||
|
2. Introduce domain composer modules for repeated build-handler clusters (startup, overlay, jellyfin, anilist, ipc/shortcuts).
|
||||||
|
3. Move `createBuild*MainDepsHandler` call clusters out of `main.ts` into domain composer modules with narrow typed inputs.
|
||||||
|
4. Replace inline assembly in `main.ts` with single-call composer invocations per domain.
|
||||||
|
5. Add/adjust unit tests for new composer modules to lock shape and wiring.
|
||||||
|
6. Tighten `check:main-fanin` thresholds after refactor to prevent regression.
|
||||||
|
7. Re-run full config/core test gates and update `TASK-71` progress.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Progress Notes
|
||||||
|
|
||||||
|
- 2026-02-21 baseline: `src/main.ts` = 3129 LOC; `check:main-fanin` = 105 import lines / 9 unique runtime paths.
|
||||||
|
- 2026-02-21 extraction slice: added composer modules `src/main/runtime/composers/jellyfin-remote-composer.ts` and `src/main/runtime/composers/anilist-setup-composer.ts`; moved corresponding `createBuild*MainDepsHandler` orchestration out of `main.ts`.
|
||||||
|
- 2026-02-21 tests: added focused composer shape tests at `src/main/runtime/composers/jellyfin-remote-composer.test.ts` and `src/main/runtime/composers/anilist-setup-composer.test.ts`.
|
||||||
|
- 2026-02-21 guardrail tighten: `scripts/check-main-runtime-fanin.ts` defaults tightened to `import lines <= 110` and `unique runtime paths <= 11`.
|
||||||
|
- 2026-02-21 post-slice metrics: `src/main.ts` = 3042 LOC; `check:main-fanin --strict` = 103 import lines / 11 unique runtime paths.
|
||||||
|
- Remaining gap: startup/overlay/ipc/shortcuts composer extraction still required to fully meet thin composition-root target.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 `src/main.ts` is composition-focused (boot/runtime wiring only; no broad deps-builder clusters).
|
||||||
|
- [x] #2 Runtime import paths in `src/main.ts` stay domain-registry oriented (no relapse to per-leaf runtime imports).
|
||||||
|
- [x] #3 `check:main-fanin` passes under updated threshold.
|
||||||
|
- [x] #4 `bun run test:core:dist` passes with no CLI/IPC behavior regressions.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Definition of Done
|
||||||
|
<!-- DOD:BEGIN -->
|
||||||
|
- [x] #1 `src/main.ts` LOC and fan-in metrics improve from pre-task baseline and are recorded in task notes.
|
||||||
|
- [x] #2 New composer modules are covered by focused tests.
|
||||||
|
- [x] #3 `TASK-71` and `TASK-85` progress notes reflect completed slice and remaining gap.
|
||||||
|
<!-- DOD:END -->
|
||||||
@@ -13,9 +13,13 @@ Purpose: keep large modules from becoming maintenance bottlenecks.
|
|||||||
- Warning mode (non-blocking): `bun run check:file-budgets`
|
- Warning mode (non-blocking): `bun run check:file-budgets`
|
||||||
- Strict mode (CI/local gate): `bun run check:file-budgets:strict`
|
- Strict mode (CI/local gate): `bun run check:file-budgets:strict`
|
||||||
- Custom limit: `bun run scripts/check-file-budgets.ts --limit 650`
|
- Custom limit: `bun run scripts/check-file-budgets.ts --limit 650`
|
||||||
|
- Main runtime fan-in (warning): `bun run check:main-fanin`
|
||||||
|
- Main runtime fan-in (strict): `bun run check:main-fanin:strict`
|
||||||
|
- Default main fan-in thresholds: `import lines <= 110`, `unique runtime paths <= 11`
|
||||||
|
|
||||||
## Policy
|
## Policy
|
||||||
|
|
||||||
- If file exceeds budget, prefer extracting domain module(s) first.
|
- If file exceeds budget, prefer extracting domain module(s) first.
|
||||||
- Keep composition/orchestration files focused on wiring.
|
- Keep composition/orchestration files focused on wiring.
|
||||||
- Do not hand-edit generated artifacts; refactor source modules.
|
- Do not hand-edit generated artifacts; refactor source modules.
|
||||||
|
- Keep `src/main.ts` runtime import fan-in low by routing domain imports through `src/main/runtime/domains/*` and `src/main/runtime/registry.ts`.
|
||||||
|
|||||||
@@ -2,31 +2,31 @@
|
|||||||
|
|
||||||
Read first. Keep concise.
|
Read first. Keep concise.
|
||||||
|
|
||||||
| agent_id | alias | mission | status | file | last_update_utc |
|
| agent_id | alias | mission | status | file | last_update_utc |
|
||||||
| ------------ | -------------- | ---------------------------------------------------- | --------- | ------------------------------------- | ---------------------- |
|
| --------------------------------------------------------- | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------- | ---------------------------------------------------------------------------------- | ---------------------- |
|
||||||
| `codex-generate-minecard-image-20260220T112900Z-vsxr` | `codex-generate-minecard-image` | `Generate media fallbacks (GIF) from assets/minecard.webm and wire README/docs fallback markup` | `done` | `docs/subagents/agents/codex-generate-minecard-image-20260220T112900Z-vsxr.md` | `2026-02-20T11:35:30Z` |
|
| `codex-generate-minecard-image-20260220T112900Z-vsxr` | `codex-generate-minecard-image` | `Generate media fallbacks (GIF) from assets/minecard.webm and wire README/docs fallback markup` | `done` | `docs/subagents/agents/codex-generate-minecard-image-20260220T112900Z-vsxr.md` | `2026-02-20T11:35:30Z` |
|
||||||
| `codex-frequency-dup-log-20260221T042815Z-r4k1` | `codex-frequency-dup-log` | `Reduce frequency dictionary duplicate-term startup log spam` | `completed` | `docs/subagents/agents/codex-frequency-dup-log-20260221T042815Z-r4k1.md` | `2026-02-21T04:32:40Z` |
|
| `codex-main` | `planner-exec` | `Fix frequency/N+1 regression in plugin --start flow` | `in_progress` | `docs/subagents/agents/codex-main.md` | `2026-02-19T19:36:46Z` |
|
||||||
| `codex-main` | `planner-exec` | `Fix frequency/N+1 regression in plugin --start flow` | `in_progress` | `docs/subagents/agents/codex-main.md` | `2026-02-19T19:36:46Z` |
|
| `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T11:42:39Z` |
|
||||||
| `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T11:42:39Z` |
|
| `codex-config-validation-20260219T172015Z-iiyf` | `codex-config-validation` | `Find root cause of config validation error for ~/.config/SubMiner/config.jsonc` | `completed` | `docs/subagents/agents/codex-config-validation-20260219T172015Z-iiyf.md` | `2026-02-19T17:26:17Z` |
|
||||||
| `codex-config-validation-20260219T172015Z-iiyf` | `codex-config-validation` | `Find root cause of config validation error for ~/.config/SubMiner/config.jsonc` | `completed` | `docs/subagents/agents/codex-config-validation-20260219T172015Z-iiyf.md` | `2026-02-19T17:26:17Z` |
|
| `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T02:56:34Z` |
|
||||||
| `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T02:56:34Z` |
|
| `codex-anilist-deeplink-20260219T233926Z` | `anilist-deeplink` | `Fix external subminer:// AniList callback handling from browser` | `done` | `docs/subagents/agents/codex-anilist-deeplink-20260219T233926Z.md` | `2026-02-19T23:59:21Z` |
|
||||||
| `codex-anilist-deeplink-20260219T233926Z` | `anilist-deeplink` | `Fix external subminer:// AniList callback handling from browser` | `done` | `docs/subagents/agents/codex-anilist-deeplink-20260219T233926Z.md` | `2026-02-19T23:59:21Z` |
|
| `codex-texthooker-highlights-20260220T002354Z-927c` | `codex-texthooker-highlights` | `Add optional texthooker highlight toggles for known/n+1/frequency/JLPT` | `completed` | `docs/subagents/agents/codex-texthooker-highlights-20260220T002354Z-927c.md` | `2026-02-20T00:30:49Z` |
|
||||||
| `codex-texthooker-highlights-20260220T002354Z-927c` | `codex-texthooker-highlights` | `Add optional texthooker highlight toggles for known/n+1/frequency/JLPT` | `completed` | `docs/subagents/agents/codex-texthooker-highlights-20260220T002354Z-927c.md` | `2026-02-20T00:30:49Z` |
|
| `codex-texthooker-ui-playwright-20260220T003827Z-k3p9` | `codex-texthooker-ui-playwright` | `Run Playwright MCP smoke/regression checks for texthooker-ui changes` | `completed` | `docs/subagents/agents/codex-texthooker-ui-playwright-20260220T003827Z-k3p9.md` | `2026-02-20T00:42:09Z` |
|
||||||
| `codex-texthooker-ui-playwright-20260220T003827Z-k3p9` | `codex-texthooker-ui-playwright` | `Run Playwright MCP smoke/regression checks for texthooker-ui changes` | `completed` | `docs/subagents/agents/codex-texthooker-ui-playwright-20260220T003827Z-k3p9.md` | `2026-02-20T00:42:09Z` |
|
| `codex-texthooker-color-ws-20260220T005844Z-r7m2` | `codex-texthooker-color-ws` | `Fix texthooker websocket payload so token highlight colors render` | `completed` | `docs/subagents/agents/codex-texthooker-color-ws-20260220T005844Z-r7m2.md` | `2026-02-20T01:01:00Z` |
|
||||||
| `codex-texthooker-color-ws-20260220T005844Z-r7m2` | `codex-texthooker-color-ws` | `Fix texthooker websocket payload so token highlight colors render` | `completed` | `docs/subagents/agents/codex-texthooker-color-ws-20260220T005844Z-r7m2.md` | `2026-02-20T01:01:00Z` |
|
| `codex-nplusone-pos1-20260220T012300Z-c5he` | `codex-nplusone-pos1` | `Fix N+1 false-negative when Yomitan functional tokens inflate unknown candidate count` | `completed` | `docs/subagents/agents/codex-nplusone-pos1-20260220T012300Z-c5he.md` | `2026-02-20T01:28:20Z` |
|
||||||
| `codex-nplusone-pos1-20260220T012300Z-c5he` | `codex-nplusone-pos1` | `Fix N+1 false-negative when Yomitan functional tokens inflate unknown candidate count` | `completed` | `docs/subagents/agents/codex-nplusone-pos1-20260220T012300Z-c5he.md` | `2026-02-20T01:28:20Z` |
|
| `codex-subtitle-bg-20260220T054247Z-h9cu` | `codex-subtitle-bg` | `Update default subtitle background color to requested RGBA value` | `completed` | `docs/subagents/agents/codex-subtitle-bg-20260220T054247Z-h9cu.md` | `2026-02-20T05:44:45Z` |
|
||||||
| `codex-subtitle-bg-20260220T054247Z-h9cu` | `codex-subtitle-bg` | `Update default subtitle background color to requested RGBA value` | `completed` | `docs/subagents/agents/codex-subtitle-bg-20260220T054247Z-h9cu.md` | `2026-02-20T05:44:45Z` |
|
| `codex-narrow-space-tokenizer-20260220T061716Z-p97s` | `codex-narrow-space-tokenizer` | `Fix tokenization when subtitle line contains narrow/invisible Unicode spacing between segments` | `completed` | `docs/subagents/agents/codex-narrow-space-tokenizer-20260220T061716Z-p97s.md` | `2026-02-20T06:20:07Z` |
|
||||||
| `codex-narrow-space-tokenizer-20260220T061716Z-p97s` | `codex-narrow-space-tokenizer` | `Fix tokenization when subtitle line contains narrow/invisible Unicode spacing between segments` | `completed` | `docs/subagents/agents/codex-narrow-space-tokenizer-20260220T061716Z-p97s.md` | `2026-02-20T06:20:07Z` |
|
| `codex-preserve-linebreaks-20260220T063538Z-s4nd` | `codex-preserve-linebreaks` | `Add config option to preserve subtitle line breaks in visible overlay rendering` | `completed` | `docs/subagents/agents/codex-preserve-linebreaks-20260220T063538Z-s4nd.md` | `2026-02-20T06:42:51Z` |
|
||||||
| `codex-preserve-linebreaks-20260220T063538Z-s4nd` | `codex-preserve-linebreaks` | `Add config option to preserve subtitle line breaks in visible overlay rendering` | `completed` | `docs/subagents/agents/codex-preserve-linebreaks-20260220T063538Z-s4nd.md` | `2026-02-20T06:42:51Z` |
|
| `codex-release-mpv-plugin-20260220T035757Z-d4yf` | `codex-release-mpv-plugin` | `Package optional release assets bundle (mpv plugin + rofi theme), move theme to assets/themes, update install/docs` | `completed` | `docs/subagents/agents/codex-release-mpv-plugin-20260220T035757Z-d4yf.md` | `2026-02-20T04:02:26Z` |
|
||||||
| `codex-release-mpv-plugin-20260220T035757Z-d4yf` | `codex-release-mpv-plugin` | `Package optional release assets bundle (mpv plugin + rofi theme), move theme to assets/themes, update install/docs` | `completed` | `docs/subagents/agents/codex-release-mpv-plugin-20260220T035757Z-d4yf.md` | `2026-02-20T04:02:26Z` |
|
| `codex-bundle-config-example-20260220T092408Z-a1b2` | `codex-bundle-config-example` | `Bundle config.example.jsonc in release assets tarball and align install docs` | `completed` | `docs/subagents/agents/codex-bundle-config-example-20260220T092408Z-a1b2.md` | `2026-02-20T09:26:24Z` |
|
||||||
| `codex-bundle-config-example-20260220T092408Z-a1b2` | `codex-bundle-config-example` | `Bundle config.example.jsonc in release assets tarball and align install docs` | `completed` | `docs/subagents/agents/codex-bundle-config-example-20260220T092408Z-a1b2.md` | `2026-02-20T09:26:24Z` |
|
| `codex-tsconfig-modernize-20260220T093035Z-68qb` | `codex-tsconfig-modernize` | `Enable noUncheckedIndexedAccess + isolatedModules in root tsconfig and fix resulting compile errors` | `completed` | `docs/subagents/agents/codex-tsconfig-modernize-20260220T093035Z-68qb.md` | `2026-02-20T09:46:26Z` |
|
||||||
| `codex-tsconfig-modernize-20260220T093035Z-68qb` | `codex-tsconfig-modernize` | `Enable noUncheckedIndexedAccess + isolatedModules in root tsconfig and fix resulting compile errors` | `completed` | `docs/subagents/agents/codex-tsconfig-modernize-20260220T093035Z-68qb.md` | `2026-02-20T09:46:26Z` |
|
| `codex-jellyfin-secret-store-20260220T101428Z-om4z` | `codex-jellyfin-secret-store` | `Verify whether Jellyfin token can use same secret-store path as AniList token` | `completed` | `docs/subagents/agents/codex-jellyfin-secret-store-20260220T101428Z-om4z.md` | `2026-02-20T10:22:45Z` |
|
||||||
| `codex-jellyfin-secret-store-20260220T101428Z-om4z` | `codex-jellyfin-secret-store` | `Move Jellyfin token/userId out of config into env override + stored session payload` | `completed` | `docs/subagents/agents/codex-jellyfin-secret-store-20260220T101428Z-om4z.md` | `2026-02-21T04:27:24Z` |
|
| `codex-vitepress-subagents-ignore-20260220T101755Z-k2m9` | `codex-vitepress-subagents-ignore` | `Exclude docs/subagents from VitePress build` | `completed` | `docs/subagents/agents/codex-vitepress-subagents-ignore-20260220T101755Z-k2m9.md` | `2026-02-20T10:18:30Z` |
|
||||||
| `codex-vitepress-subagents-ignore-20260220T101755Z-k2m9` | `codex-vitepress-subagents-ignore` | `Exclude docs/subagents from VitePress build` | `completed` | `docs/subagents/agents/codex-vitepress-subagents-ignore-20260220T101755Z-k2m9.md` | `2026-02-20T10:18:30Z` |
|
| `codex-preserve-linebreak-display-20260220T110436Z-r8f1` | `codex-preserve-linebreak-display` | `Fix visible overlay display artifact when subtitleStyle.preserveLineBreaks is disabled` | `completed` | `docs/subagents/agents/codex-preserve-linebreak-display-20260220T110436Z-r8f1.md` | `2026-02-20T11:10:51Z` |
|
||||||
| `codex-preserve-linebreak-display-20260220T110436Z-r8f1` | `codex-preserve-linebreak-display` | `Fix visible overlay display artifact when subtitleStyle.preserveLineBreaks is disabled` | `completed` | `docs/subagents/agents/codex-preserve-linebreak-display-20260220T110436Z-r8f1.md` | `2026-02-20T11:10:51Z` |
|
| `codex-review-refactor-cleanup-20260220T113818Z-i2ov` | `codex-review-refactor-cleanup` | `Review recent TASK-85 refactor effort and identify remaining cleanup work` | `handoff` | `docs/subagents/agents/codex-review-refactor-cleanup-20260220T113818Z-i2ov.md` | `2026-02-21T02:04:12Z` |
|
||||||
| `codex-review-refactor-cleanup-20260220T113818Z-i2ov` | `codex-review-refactor-cleanup` | `Review recent TASK-85 refactor effort and identify remaining cleanup work` | `handoff` | `docs/subagents/agents/codex-review-refactor-cleanup-20260220T113818Z-i2ov.md` | `2026-02-20T11:48:28Z` |
|
| `codex-commit-unstaged-20260220T115057Z-k7q2` | `codex-commit-unstaged` | `Commit all current unstaged repository changes with content-derived conventional message` | `in_progress` | `docs/subagents/agents/codex-commit-unstaged-20260220T115057Z-k7q2.md` | `2026-02-20T11:51:18Z` |
|
||||||
| `codex-commit-unstaged-20260220T115057Z-k7q2` | `codex-commit-unstaged` | `Commit all current unstaged repository changes with content-derived conventional message` | `in_progress` | `docs/subagents/agents/codex-commit-unstaged-20260220T115057Z-k7q2.md` | `2026-02-20T11:51:18Z` |
|
| `codex-task95-hotspots-20260221T031420Z-x7k2` | `codex-task95-hotspots` | `Execute TASK-95 decompose oversized core hotspots end-to-end` | `done` | `docs/subagents/agents/codex-task95-hotspots-20260221T031420Z-x7k2.md` | `2026-02-21T03:29:23Z` |
|
||||||
| `codex-overlay-whitespace-newline-20260221T040705Z-aw2j` | `codex-overlay-whitespace-newline` | `Fix visible overlay whitespace/newline token rendering bug with TDD regression coverage` | `completed` | `docs/subagents/agents/codex-overlay-whitespace-newline-20260221T040705Z-aw2j.md` | `2026-02-21T04:18:16Z` |
|
| `codex-task94-thin-root-20260221T031320Z-q3n7` | `codex-task94-thin-root` | `Execute TASK-94 by extracting main.ts deps-builder clusters into runtime composers` | `handoff` | `docs/subagents/agents/codex-task94-thin-root-20260221T031320Z-q3n7.md` | `2026-02-21T03:41:10Z` |
|
||||||
| `codex-duplicate-kiku-20260221T043006Z-5vkz` | `codex-duplicate-kiku` | `Fix Kiku duplicate-card detection/grouping regression for Yomitan duplicate-marked + N+1-highlighted cards` | `completed` | `docs/subagents/agents/codex-duplicate-kiku-20260221T043006Z-5vkz.md` | `2026-02-21T10:07:58Z` |
|
| `opencode-task95-immersion-tracker-20260221T031846Z-p4k9` | `opencode-task95-immersion-tracker` | `Implement TASK-95 immersion-tracker extraction into focused collaborators and seam tests` | `handoff` | `docs/subagents/agents/opencode-task95-immersion-tracker-20260221T031846Z-p4k9.md` | `2026-02-21T03:26:51Z` |
|
||||||
| `codex-mpv-connect-log-20260221T043748Z-q7m1` | `codex-mpv-connect-log` | `Suppress repetitive MPV IPC connect-request INFO logs during startup` | `completed` | `docs/subagents/agents/codex-mpv-connect-log-20260221T043748Z-q7m1.md` | `2026-02-21T04:41:15Z` |
|
| `opencode-task95-config-20260221T031843Z-m4k9` | `opencode-task95-config` | `Implement TASK-95 config extraction for src/config/service.ts` | `done` | `docs/subagents/agents/opencode-task95-config-20260221T031843Z-m4k9.md` | `2026-02-21T03:26:57Z` |
|
||||||
| `codex-add-backlog-tasks-20260221T044104Z-m3n8` | `codex-add-backlog-tasks` | `Add two unrelated backlog tasks: secondary subtitle decoupling and intro skip` | `done` | `docs/subagents/agents/codex-add-backlog-tasks-20260221T044104Z-m3n8.md` | `2026-02-21T04:44:12Z` |
|
| `codex-task95-anki-20260221T031836Z-6f3e` | `codex-task95-anki` | `Implement TASK-95 anki-integration extraction for field-grouping merge collaborator` | `done` | `docs/subagents/agents/codex-task95-anki-20260221T031836Z-6f3e.md` | `2026-02-21T03:26:55Z` |
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Agent: codex-task94-thin-root-20260221T031320Z-q3n7
|
||||||
|
|
||||||
|
- alias: codex-task94-thin-root
|
||||||
|
- mission: Execute TASK-94 end-to-end by moving main deps-builder clusters into runtime composer modules and shrinking main.ts fan-in
|
||||||
|
- status: handoff
|
||||||
|
- branch: main
|
||||||
|
- started_at: 2026-02-21T03:13:20Z
|
||||||
|
- heartbeat_minutes: 5
|
||||||
|
|
||||||
|
## Current Work (newest first)
|
||||||
|
- [2026-02-21T03:41:10Z] handoff: completed TASK-94 slice extraction for jellyfin/anilist composer modules; `main.ts` now consumes `composeJellyfinRemoteHandlers` + `composeAnilistSetupHandlers`; added composer tests; tightened fan-in guard to `<=110` import lines and `<=11` unique runtime paths.
|
||||||
|
- [2026-02-21T03:41:10Z] test: `bun run build`, `node --test dist/main/runtime/composers/anilist-setup-composer.test.js dist/main/runtime/composers/jellyfin-remote-composer.test.js`, `bun run test:config:dist`, `bun run test:core:dist`, `bun run check:main-fanin`, `bun run check:main-fanin:strict`, `bun run check:file-budgets`.
|
||||||
|
- [2026-02-21T03:24:30Z] intent: execute TASK-94 with batch extraction (startup, overlay, jellyfin/anilist, ipc/shortcuts), tests, fan-in threshold tighten, backlog updates.
|
||||||
|
- [2026-02-21T03:24:30Z] planned files: `src/main.ts`, `src/main/runtime/composers/*`, `src/main/runtime/registry.ts`, `src/main/runtime/*composer*.test.ts`, `scripts/check-main-runtime-fanin.ts`, `backlog/tasks/task-94 - Reduce-main.ts-to-thin-composition-root.md`, `backlog/tasks/task-71 - Split-main.ts-into-domain-runtime-modules-round-2.md`.
|
||||||
|
- [2026-02-21T03:24:30Z] assumptions: prior TASK-71 domain barrels + registry already landed in working tree; continue from current dirty state without reverting unrelated edits.
|
||||||
|
|
||||||
|
## Files Touched
|
||||||
|
- `docs/subagents/agents/codex-task94-thin-root-20260221T031320Z-q3n7.md`
|
||||||
|
- `docs/subagents/INDEX.md`
|
||||||
|
- `docs/subagents/collaboration.md`
|
||||||
|
- `src/main.ts`
|
||||||
|
- `src/main/runtime/composers/jellyfin-remote-composer.ts`
|
||||||
|
- `src/main/runtime/composers/anilist-setup-composer.ts`
|
||||||
|
- `src/main/runtime/composers/jellyfin-remote-composer.test.ts`
|
||||||
|
- `src/main/runtime/composers/anilist-setup-composer.test.ts`
|
||||||
|
- `scripts/check-main-runtime-fanin.ts`
|
||||||
|
- `docs/file-size-budgets.md`
|
||||||
|
- `backlog/tasks/task-94 - Reduce-main.ts-to-thin-composition-root.md`
|
||||||
|
- `backlog/tasks/task-71 - Split-main.ts-into-domain-runtime-modules-round-2.md`
|
||||||
|
- `backlog/tasks/task-85 - Refactor-large-files-for-maintainability-and-readability.md`
|
||||||
|
|
||||||
|
## Assumptions
|
||||||
|
- `TASK-94` scope is single-ticket execution from existing branch state; no new worktree requested by user.
|
||||||
|
- Existing uncommitted edits are intentional and should remain.
|
||||||
|
|
||||||
|
## Open Questions / Blockers
|
||||||
|
- none
|
||||||
|
|
||||||
|
## Next Step
|
||||||
|
- Continue TASK-94 by extracting startup/overlay/ipc/shortcuts deps-builder clusters into composer modules to finish thin composition-root target.
|
||||||
@@ -16,20 +16,13 @@ Shared notes. Append-only.
|
|||||||
- [2026-02-20T11:04:36Z] [codex-preserve-linebreak-display-20260220T110436Z-r8f1|codex-preserve-linebreak-display] overlap note: touching `src/renderer/subtitle-render.ts` + renderer tests to fix preserve-linebreaks disabled display artifact while preserving TASK-91 behavior.
|
- [2026-02-20T11:04:36Z] [codex-preserve-linebreak-display-20260220T110436Z-r8f1|codex-preserve-linebreak-display] overlap note: touching `src/renderer/subtitle-render.ts` + renderer tests to fix preserve-linebreaks disabled display artifact while preserving TASK-91 behavior.
|
||||||
- [2026-02-20T11:07:29Z] [codex-preserve-linebreak-display-20260220T110436Z-r8f1|codex-preserve-linebreak-display] completed follow-up for TASK-91: non-preserve mode now flattens token CR/LF to spaces instead of emitting `<br>` from token surfaces; regression test added.
|
- [2026-02-20T11:07:29Z] [codex-preserve-linebreak-display-20260220T110436Z-r8f1|codex-preserve-linebreak-display] completed follow-up for TASK-91: non-preserve mode now flattens token CR/LF to spaces instead of emitting `<br>` from token surfaces; regression test added.
|
||||||
- [2026-02-20T11:10:51Z] [codex-preserve-linebreak-display-20260220T110436Z-r8f1|codex-preserve-linebreak-display] second follow-up: handle overlap token streams by aligning non-preserve rendering to normalized source text and skipping unmatched tail tokens (prevents duplicated second-line phrase).
|
- [2026-02-20T11:10:51Z] [codex-preserve-linebreak-display-20260220T110436Z-r8f1|codex-preserve-linebreak-display] second follow-up: handle overlap token streams by aligning non-preserve rendering to normalized source text and skipping unmatched tail tokens (prevents duplicated second-line phrase).
|
||||||
- [2026-02-21T04:07:05Z] [codex-overlay-whitespace-newline-20260221T040705Z-aw2j|codex-overlay-whitespace-newline] overlap note: touching `src/renderer/subtitle-render.ts` + renderer tests for whitespace/newline display/token hover regression around `preserveLineBreaks`.
|
- [2026-02-21T03:24:45Z] [codex-task94-thin-root-20260221T031320Z-q3n7|codex-task94-thin-root] overlap note: starting TASK-94 extraction in `src/main.ts` + new `src/main/runtime/composers/*`; coordinating around existing in-progress rows (`codex-main`, `codex-task85`) that may also touch main-runtime wiring.
|
||||||
- [2026-02-21T04:09:02Z] [codex-overlay-whitespace-newline-20260221T040705Z-aw2j|codex-overlay-whitespace-newline] completed: whitespace-only token surfaces no longer become token segments; non-preserve mode now flattens token newlines to spaces and renders whitespace as text nodes; added regression test in renderer suite.
|
- [2026-02-21T03:41:10Z] [codex-task94-thin-root-20260221T031320Z-q3n7|codex-task94-thin-root] shipped TASK-94 slice: moved jellyfin/anilist deps-builder clusters behind composer modules, tightened fan-in guard, added composer tests, updated backlog task notes with before/after metrics and remaining scope (startup/overlay/ipc/shortcuts extraction).
|
||||||
- [2026-02-21T04:14:30Z] [codex-overlay-whitespace-newline-20260221T040705Z-aw2j|codex-overlay-whitespace-newline] preserve-line-breaks follow-up: when token surface mismatches source (e.g., `1` vs `1`), alignment now skips unmatched token instead of appending both source tail + token; fixes duplicated no-break line artifact.
|
- [2026-02-21T03:14:29Z] [codex-task95-hotspots-20260221T031420Z-x7k2|codex-task95-hotspots] starting TASK-95 execution: load backlog context, write plan with writing-plans skill, execute with executing-plans (no commit).
|
||||||
- [2026-02-21T04:18:16Z] [codex-overlay-whitespace-newline-20260221T040705Z-aw2j|codex-overlay-whitespace-newline] follow-up fix: non-token fallback now honors preserveLineBreaks flag by collapsing line breaks when disabled; prevents visible multi-line -> single-line transition while tokenized payload arrives.
|
- [2026-02-21T03:29:23Z] [codex-task95-hotspots-20260221T031420Z-x7k2|codex-task95-hotspots] completed TASK-95 with parallel subagents (anki/config/immersion), full gates green, TASK-95 set Done and TASK-85 evidence updated.
|
||||||
- [2026-02-21T04:18:58Z] [codex-jellyfin-secret-store-20260220T101428Z-om4z|codex-jellyfin-secret-store] overlap note: follow-up Jellyfin auth refactor touching `src/main.ts`, `src/main/runtime/jellyfin-*`, and config/docs to remove config token/userId fields in favor of env+stored session payload.
|
- [2026-02-21T03:18:36Z] [codex-task95-anki-20260221T031836Z-6f3e|codex-task95-anki] starting TASK-95 Anki portion: extract field-grouping/merge collaborator from `src/anki-integration.ts` into `src/anki-integration/*`; add seam tests; run `bun run build && node --test dist/anki-integration.test.js`.
|
||||||
- [2026-02-21T04:27:24Z] [codex-jellyfin-secret-store-20260220T101428Z-om4z|codex-jellyfin-secret-store] completed TASK-93: removed Jellyfin accessToken/userId config fields; resolver now uses env-first (`SUBMINER_JELLYFIN_ACCESS_TOKEN` + optional `SUBMINER_JELLYFIN_USER_ID`) then stored encrypted session payload; login/setup save session and logout clears session.
|
- [2026-02-21T03:26:55Z] [codex-task95-anki-20260221T031836Z-6f3e|codex-task95-anki] completed Anki extraction; collaborator now in `src/anki-integration/field-grouping-merge.ts`; `AnkiIntegration` rewired via collaborator seam; targeted build + `dist/anki-integration.test.js` passing.
|
||||||
- [2026-02-21T04:30:06Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] investigating Kiku duplicate grouping regression; expecting touches in `src/anki-integration/duplicate.ts` and duplicate-detection tests only.
|
- [2026-02-21T03:18:43Z] [opencode-task95-config-20260221T031843Z-m4k9|opencode-task95-config] starting TASK-95 config slice; scope `src/config/service.ts`, new `src/config/*` collaborators, and config seam tests only; no backlog-file edits.
|
||||||
- [2026-02-21T04:33:17Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] completed TASK-94: duplicate check now resolves `word`/`expression` alias fields when validating candidate notes; added regression test `src/anki-integration/duplicate.test.ts`; targeted build + duplicate/anki-integration tests passed.
|
- [2026-02-21T03:18:46Z] [opencode-task95-immersion-tracker-20260221T031846Z-p4k9|opencode-task95-immersion-tracker] overlap note: implementing TASK-95 immersion-tracker slice in `src/core/services/immersion-tracker-service.ts` + new `src/core/services/immersion-tracker/*` + seam tests; avoiding backlog file edits.
|
||||||
- [2026-02-21T04:38:25Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] follow-up repro fixed: duplicate search now queries both alias fields (`word` + `expression`) and unions note ids before exact compare; added second regression test for alias-query fallback.
|
- [2026-02-21T03:26:51Z] [opencode-task95-immersion-tracker-20260221T031846Z-p4k9|opencode-task95-immersion-tracker] completed immersion-tracker slice: extracted reducer/query/maintenance/queue/types collaborators, kept public API stable, added seam tests, and verified via `bun run build && node --test dist/core/services/immersion-tracker-service.test.js`.
|
||||||
- [2026-02-21T04:48:50Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] second follow-up fix: when source note has both `Expression` and `Word`, duplicate detection now uses both source values (not just first field by order); added regression for mixed-field source candidate scenario.
|
- [2026-02-21T03:26:57Z] [opencode-task95-config-20260221T031843Z-m4k9|opencode-task95-config] completed config slice: extracted `load/parse/warnings/resolve` collaborators, reduced `src/config/service.ts` to facade, added loader precedence + strict non-mutation + warning determinism seam tests, build+config tests green.
|
||||||
- [2026-02-21T07:23:56Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] third follow-up fix: add collection-wide fallback query pass when deck-scoped duplicate search returns no candidates; added regression for deck-scope miss case.
|
|
||||||
- [2026-02-21T09:25:53Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] fourth follow-up fix: add plain-text query fallback when field-scoped queries miss; keep exact value verification on candidate notes to avoid false positives.
|
|
||||||
- [2026-02-21T09:40:33Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] instrumentation pass: add duplicate-detection debug logs (`[duplicate] query/hits/candidates/exact-match`) to isolate remaining live repro mismatches.
|
|
||||||
- [2026-02-21T09:54:29Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] logging-path update: default persistent logs now target `~/.config/SubMiner/logs/SubMiner-YYYY-MM-DD.log` (launcher + app mpv log default).
|
|
||||||
- [2026-02-21T10:07:58Z] [codex-duplicate-kiku-20260221T043006Z-5vkz|codex-duplicate-kiku] observability fix: app logger now also appends to daily log file, so runtime duplicate traces are available even when overlay stdout is not surfaced in launcher terminal.
|
|
||||||
- [2026-02-21T04:37:48Z] [codex-mpv-connect-log-20260221T043748Z-q7m1|codex-mpv-connect-log] overlap note: touching `src/core/services/mpv.ts` + mpv service tests for startup connection-request log level gating; coordinating with historical TASK-33 behavior (same symptom, new logger path).
|
|
||||||
- [2026-02-21T04:41:15Z] [codex-mpv-connect-log-20260221T043748Z-q7m1|codex-mpv-connect-log] completed TASK-95: changed `MpvIpcClient.connect()` connect-request line to `logger.debug`, added regression tests for info/debug level log behavior in `src/core/services/mpv.test.ts`; verified via `bun run build && node dist/core/services/mpv.test.js` (pass).
|
|
||||||
|
|||||||
103
scripts/check-main-runtime-fanin.ts
Normal file
103
scripts/check-main-runtime-fanin.ts
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
type ParsedArgs = {
|
||||||
|
strict: boolean;
|
||||||
|
uniquePathLimit: number;
|
||||||
|
importLineLimit: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_UNIQUE_PATH_LIMIT = 11;
|
||||||
|
const DEFAULT_IMPORT_LINE_LIMIT = 110;
|
||||||
|
const MAIN_PATH = path.join(process.cwd(), 'src', 'main.ts');
|
||||||
|
|
||||||
|
function parseArgs(argv: string[]): ParsedArgs {
|
||||||
|
let strict = false;
|
||||||
|
let uniquePathLimit = DEFAULT_UNIQUE_PATH_LIMIT;
|
||||||
|
let importLineLimit = DEFAULT_IMPORT_LINE_LIMIT;
|
||||||
|
|
||||||
|
for (let i = 0; i < argv.length; i += 1) {
|
||||||
|
const arg = argv[i];
|
||||||
|
if (arg === '--strict') {
|
||||||
|
strict = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg === '--unique-path-limit') {
|
||||||
|
const raw = argv[i + 1];
|
||||||
|
const parsed = Number.parseInt(raw ?? '', 10);
|
||||||
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
||||||
|
throw new Error(`Invalid --unique-path-limit value: ${raw ?? '<missing>'}`);
|
||||||
|
}
|
||||||
|
uniquePathLimit = parsed;
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg === '--import-line-limit') {
|
||||||
|
const raw = argv[i + 1];
|
||||||
|
const parsed = Number.parseInt(raw ?? '', 10);
|
||||||
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
||||||
|
throw new Error(`Invalid --import-line-limit value: ${raw ?? '<missing>'}`);
|
||||||
|
}
|
||||||
|
importLineLimit = parsed;
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { strict, uniquePathLimit, importLineLimit };
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectRuntimeImportStats(source: string): {
|
||||||
|
importLines: number;
|
||||||
|
uniquePaths: string[];
|
||||||
|
} {
|
||||||
|
const pathMatches = Array.from(source.matchAll(/from '(\.\/main\/runtime[^']*)';/g)).map(
|
||||||
|
(match) => match[1],
|
||||||
|
);
|
||||||
|
const uniquePaths = new Set<string>();
|
||||||
|
|
||||||
|
for (const runtimeImportPath of pathMatches) {
|
||||||
|
uniquePaths.add(runtimeImportPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
importLines: pathMatches.length,
|
||||||
|
uniquePaths: Array.from(uniquePaths).sort(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(): void {
|
||||||
|
const { strict, uniquePathLimit, importLineLimit } = parseArgs(process.argv.slice(2));
|
||||||
|
const source = fs.readFileSync(MAIN_PATH, 'utf8');
|
||||||
|
const { importLines, uniquePaths } = collectRuntimeImportStats(source);
|
||||||
|
const overUniquePathLimit = uniquePaths.length > uniquePathLimit;
|
||||||
|
const overImportLineLimit = importLines > importLineLimit;
|
||||||
|
const hasFailure = overUniquePathLimit || overImportLineLimit;
|
||||||
|
const mode = strict ? 'strict' : 'warning';
|
||||||
|
|
||||||
|
if (!hasFailure) {
|
||||||
|
console.log(
|
||||||
|
`[OK] main runtime fan-in (${mode}) — ${importLines} import lines, ${uniquePaths.length} unique runtime paths`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const heading = strict ? '[FAIL]' : '[WARN]';
|
||||||
|
console.log(
|
||||||
|
`${heading} main runtime fan-in (${mode}) — ${importLines} import lines, ${uniquePaths.length} unique runtime paths`,
|
||||||
|
);
|
||||||
|
console.log(` limits: import lines <= ${importLineLimit}, unique paths <= ${uniquePathLimit}`);
|
||||||
|
console.log(' runtime import paths:');
|
||||||
|
for (const runtimeImportPath of uniquePaths) {
|
||||||
|
console.log(` - ${runtimeImportPath}`);
|
||||||
|
}
|
||||||
|
console.log(
|
||||||
|
' Hint: keep main.ts focused on boot wiring; move domain imports behind domain barrels/registries.',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (strict) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
354
src/main.ts
354
src/main.ts
@@ -71,15 +71,15 @@ import { printHelp } from './cli/help';
|
|||||||
import {
|
import {
|
||||||
createCriticalConfigErrorHandler,
|
createCriticalConfigErrorHandler,
|
||||||
createReloadConfigHandler,
|
createReloadConfigHandler,
|
||||||
} from './main/runtime/startup-config';
|
} from './main/runtime/domains/startup';
|
||||||
import { buildConfigWarningNotificationBody } from './main/config-validation';
|
import { buildConfigWarningNotificationBody } from './main/config-validation';
|
||||||
import { createImmersionTrackerStartupHandler } from './main/runtime/immersion-startup';
|
import { createImmersionTrackerStartupHandler } from './main/runtime/domains/startup';
|
||||||
import { createBuildImmersionTrackerStartupMainDepsHandler } from './main/runtime/immersion-startup-main-deps';
|
import { createBuildImmersionTrackerStartupMainDepsHandler } from './main/runtime/domains/startup';
|
||||||
import { createImmersionMediaRuntime } from './main/runtime/immersion-media';
|
import { createImmersionMediaRuntime } from './main/runtime/domains/startup';
|
||||||
import { createAnilistStateRuntime } from './main/runtime/anilist-state';
|
import { createAnilistStateRuntime } from './main/runtime/domains/anilist';
|
||||||
import { createConfigDerivedRuntime } from './main/runtime/config-derived';
|
import { createConfigDerivedRuntime } from './main/runtime/domains/startup';
|
||||||
import { appendClipboardVideoToQueueRuntime } from './main/runtime/clipboard-queue';
|
import { appendClipboardVideoToQueueRuntime } from './main/runtime/domains/startup';
|
||||||
import { createMainSubsyncRuntime } from './main/runtime/subsync-runtime';
|
import { createMainSubsyncRuntime } from './main/runtime/domains/startup';
|
||||||
import {
|
import {
|
||||||
buildAnilistSetupUrl,
|
buildAnilistSetupUrl,
|
||||||
consumeAnilistSetupCallbackUrl,
|
consumeAnilistSetupCallbackUrl,
|
||||||
@@ -88,246 +88,220 @@ import {
|
|||||||
loadAnilistManualTokenEntry,
|
loadAnilistManualTokenEntry,
|
||||||
loadAnilistSetupFallback,
|
loadAnilistSetupFallback,
|
||||||
openAnilistSetupInBrowser,
|
openAnilistSetupInBrowser,
|
||||||
} from './main/runtime/anilist-setup';
|
} from './main/runtime/domains/anilist';
|
||||||
|
import { createRefreshAnilistClientSecretStateHandler } from './main/runtime/domains/anilist';
|
||||||
|
import { createBuildRefreshAnilistClientSecretStateMainDepsHandler } from './main/runtime/domains/anilist';
|
||||||
import {
|
import {
|
||||||
createConsumeAnilistSetupTokenFromUrlHandler,
|
|
||||||
createHandleAnilistSetupProtocolUrlHandler,
|
|
||||||
createNotifyAnilistSetupHandler,
|
|
||||||
createRegisterSubminerProtocolClientHandler,
|
|
||||||
} from './main/runtime/anilist-setup-protocol';
|
|
||||||
import {
|
|
||||||
createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler,
|
|
||||||
createBuildHandleAnilistSetupProtocolUrlMainDepsHandler,
|
|
||||||
createBuildNotifyAnilistSetupMainDepsHandler,
|
|
||||||
createBuildRegisterSubminerProtocolClientMainDepsHandler,
|
|
||||||
} from './main/runtime/anilist-setup-protocol-main-deps';
|
|
||||||
import { createRefreshAnilistClientSecretStateHandler } from './main/runtime/anilist-token-refresh';
|
|
||||||
import { createBuildRefreshAnilistClientSecretStateMainDepsHandler } from './main/runtime/anilist-token-refresh-main-deps';
|
|
||||||
import {
|
|
||||||
createHandleJellyfinRemoteGeneralCommand,
|
|
||||||
createHandleJellyfinRemotePlay,
|
|
||||||
createHandleJellyfinRemotePlaystate,
|
|
||||||
getConfiguredJellyfinSession,
|
getConfiguredJellyfinSession,
|
||||||
type ActiveJellyfinRemotePlaybackState,
|
type ActiveJellyfinRemotePlaybackState,
|
||||||
} from './main/runtime/jellyfin-remote-commands';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import { createBuildSubtitleProcessingControllerMainDepsHandler } from './main/runtime/domains/startup';
|
||||||
createReportJellyfinRemoteProgressHandler,
|
|
||||||
createReportJellyfinRemoteStoppedHandler,
|
|
||||||
} from './main/runtime/jellyfin-remote-playback';
|
|
||||||
import {
|
|
||||||
createBuildHandleJellyfinRemoteGeneralCommandMainDepsHandler,
|
|
||||||
createBuildHandleJellyfinRemotePlayMainDepsHandler,
|
|
||||||
createBuildHandleJellyfinRemotePlaystateMainDepsHandler,
|
|
||||||
createBuildReportJellyfinRemoteProgressMainDepsHandler,
|
|
||||||
createBuildReportJellyfinRemoteStoppedMainDepsHandler,
|
|
||||||
} from './main/runtime/jellyfin-remote-main-deps';
|
|
||||||
import { createBuildSubtitleProcessingControllerMainDepsHandler } from './main/runtime/subtitle-processing-main-deps';
|
|
||||||
import {
|
import {
|
||||||
createBuildAnilistStateRuntimeMainDepsHandler,
|
createBuildAnilistStateRuntimeMainDepsHandler,
|
||||||
createBuildConfigDerivedRuntimeMainDepsHandler,
|
createBuildConfigDerivedRuntimeMainDepsHandler,
|
||||||
createBuildImmersionMediaRuntimeMainDepsHandler,
|
createBuildImmersionMediaRuntimeMainDepsHandler,
|
||||||
createBuildMainSubsyncRuntimeMainDepsHandler,
|
createBuildMainSubsyncRuntimeMainDepsHandler,
|
||||||
} from './main/runtime/runtime-bootstrap-main-deps';
|
} from './main/runtime/domains/startup';
|
||||||
import {
|
import {
|
||||||
createBuildOverlayContentMeasurementStoreMainDepsHandler,
|
createBuildOverlayContentMeasurementStoreMainDepsHandler,
|
||||||
createBuildOverlayModalRuntimeMainDepsHandler,
|
createBuildOverlayModalRuntimeMainDepsHandler,
|
||||||
} from './main/runtime/overlay-bootstrap-main-deps';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createEnsureMpvConnectedForJellyfinPlaybackHandler,
|
createEnsureMpvConnectedForJellyfinPlaybackHandler,
|
||||||
createLaunchMpvIdleForJellyfinPlaybackHandler,
|
createLaunchMpvIdleForJellyfinPlaybackHandler,
|
||||||
createWaitForMpvConnectedHandler,
|
createWaitForMpvConnectedHandler,
|
||||||
} from './main/runtime/jellyfin-remote-connection';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createBuildEnsureMpvConnectedForJellyfinPlaybackMainDepsHandler,
|
createBuildEnsureMpvConnectedForJellyfinPlaybackMainDepsHandler,
|
||||||
createBuildLaunchMpvIdleForJellyfinPlaybackMainDepsHandler,
|
createBuildLaunchMpvIdleForJellyfinPlaybackMainDepsHandler,
|
||||||
createBuildWaitForMpvConnectedMainDepsHandler,
|
createBuildWaitForMpvConnectedMainDepsHandler,
|
||||||
} from './main/runtime/jellyfin-remote-connection-main-deps';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
buildJellyfinSetupFormHtml,
|
buildJellyfinSetupFormHtml,
|
||||||
createOpenJellyfinSetupWindowHandler,
|
createOpenJellyfinSetupWindowHandler,
|
||||||
createMaybeFocusExistingJellyfinSetupWindowHandler,
|
createMaybeFocusExistingJellyfinSetupWindowHandler,
|
||||||
parseJellyfinSetupSubmissionUrl,
|
parseJellyfinSetupSubmissionUrl,
|
||||||
} from './main/runtime/jellyfin-setup-window';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import { createBuildOpenJellyfinSetupWindowMainDepsHandler } from './main/runtime/jellyfin-setup-window-main-deps';
|
import { createBuildOpenJellyfinSetupWindowMainDepsHandler } from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createMaybeFocusExistingAnilistSetupWindowHandler,
|
createMaybeFocusExistingAnilistSetupWindowHandler,
|
||||||
createOpenAnilistSetupWindowHandler,
|
createOpenAnilistSetupWindowHandler,
|
||||||
} from './main/runtime/anilist-setup-window';
|
} from './main/runtime/domains/anilist';
|
||||||
import { createBuildOpenAnilistSetupWindowMainDepsHandler } from './main/runtime/anilist-setup-window-main-deps';
|
import { createBuildOpenAnilistSetupWindowMainDepsHandler } from './main/runtime/domains/anilist';
|
||||||
import {
|
import {
|
||||||
createEnsureAnilistMediaGuessHandler,
|
createEnsureAnilistMediaGuessHandler,
|
||||||
createMaybeProbeAnilistDurationHandler,
|
createMaybeProbeAnilistDurationHandler,
|
||||||
} from './main/runtime/anilist-media-guess';
|
} from './main/runtime/domains/anilist';
|
||||||
import {
|
import {
|
||||||
createBuildEnsureAnilistMediaGuessMainDepsHandler,
|
createBuildEnsureAnilistMediaGuessMainDepsHandler,
|
||||||
createBuildMaybeProbeAnilistDurationMainDepsHandler,
|
createBuildMaybeProbeAnilistDurationMainDepsHandler,
|
||||||
} from './main/runtime/anilist-media-guess-main-deps';
|
} from './main/runtime/domains/anilist';
|
||||||
import {
|
import {
|
||||||
createGetAnilistMediaGuessRuntimeStateHandler,
|
createGetAnilistMediaGuessRuntimeStateHandler,
|
||||||
createGetCurrentAnilistMediaKeyHandler,
|
createGetCurrentAnilistMediaKeyHandler,
|
||||||
createResetAnilistMediaGuessStateHandler,
|
createResetAnilistMediaGuessStateHandler,
|
||||||
createResetAnilistMediaTrackingHandler,
|
createResetAnilistMediaTrackingHandler,
|
||||||
createSetAnilistMediaGuessRuntimeStateHandler,
|
createSetAnilistMediaGuessRuntimeStateHandler,
|
||||||
} from './main/runtime/anilist-media-state';
|
} from './main/runtime/domains/anilist';
|
||||||
import {
|
import {
|
||||||
createBuildGetAnilistMediaGuessRuntimeStateMainDepsHandler,
|
createBuildGetAnilistMediaGuessRuntimeStateMainDepsHandler,
|
||||||
createBuildGetCurrentAnilistMediaKeyMainDepsHandler,
|
createBuildGetCurrentAnilistMediaKeyMainDepsHandler,
|
||||||
createBuildResetAnilistMediaGuessStateMainDepsHandler,
|
createBuildResetAnilistMediaGuessStateMainDepsHandler,
|
||||||
createBuildResetAnilistMediaTrackingMainDepsHandler,
|
createBuildResetAnilistMediaTrackingMainDepsHandler,
|
||||||
createBuildSetAnilistMediaGuessRuntimeStateMainDepsHandler,
|
createBuildSetAnilistMediaGuessRuntimeStateMainDepsHandler,
|
||||||
} from './main/runtime/anilist-media-state-main-deps';
|
} from './main/runtime/domains/anilist';
|
||||||
import {
|
import {
|
||||||
buildAnilistAttemptKey,
|
buildAnilistAttemptKey,
|
||||||
createMaybeRunAnilistPostWatchUpdateHandler,
|
createMaybeRunAnilistPostWatchUpdateHandler,
|
||||||
createProcessNextAnilistRetryUpdateHandler,
|
createProcessNextAnilistRetryUpdateHandler,
|
||||||
rememberAnilistAttemptedUpdateKey,
|
rememberAnilistAttemptedUpdateKey,
|
||||||
} from './main/runtime/anilist-post-watch';
|
} from './main/runtime/domains/anilist';
|
||||||
import {
|
import {
|
||||||
createBuildMaybeRunAnilistPostWatchUpdateMainDepsHandler,
|
createBuildMaybeRunAnilistPostWatchUpdateMainDepsHandler,
|
||||||
createBuildProcessNextAnilistRetryUpdateMainDepsHandler,
|
createBuildProcessNextAnilistRetryUpdateMainDepsHandler,
|
||||||
} from './main/runtime/anilist-post-watch-main-deps';
|
} from './main/runtime/domains/anilist';
|
||||||
import {
|
import {
|
||||||
createLoadSubtitlePositionHandler,
|
createLoadSubtitlePositionHandler,
|
||||||
createSaveSubtitlePositionHandler,
|
createSaveSubtitlePositionHandler,
|
||||||
} from './main/runtime/subtitle-position';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createBuildLoadSubtitlePositionMainDepsHandler,
|
createBuildLoadSubtitlePositionMainDepsHandler,
|
||||||
createBuildSaveSubtitlePositionMainDepsHandler,
|
createBuildSaveSubtitlePositionMainDepsHandler,
|
||||||
} from './main/runtime/subtitle-position-main-deps';
|
} from './main/runtime/domains/overlay';
|
||||||
import { registerProtocolUrlHandlers } from './main/runtime/protocol-url-handlers';
|
import { registerProtocolUrlHandlers } from './main/runtime/domains/anilist';
|
||||||
import { createBuildRegisterProtocolUrlHandlersMainDepsHandler } from './main/runtime/protocol-url-handlers-main-deps';
|
import { createBuildRegisterProtocolUrlHandlersMainDepsHandler } from './main/runtime/domains/anilist';
|
||||||
import { createHandleJellyfinAuthCommands } from './main/runtime/jellyfin-cli-auth';
|
import { createHandleJellyfinAuthCommands } from './main/runtime/domains/jellyfin';
|
||||||
import { createRunJellyfinCommandHandler } from './main/runtime/jellyfin-command-dispatch';
|
import { createRunJellyfinCommandHandler } from './main/runtime/domains/jellyfin';
|
||||||
import { createBuildRunJellyfinCommandMainDepsHandler } from './main/runtime/jellyfin-command-dispatch-main-deps';
|
import { createBuildRunJellyfinCommandMainDepsHandler } from './main/runtime/domains/jellyfin';
|
||||||
import { createHandleJellyfinListCommands } from './main/runtime/jellyfin-cli-list';
|
import { createHandleJellyfinListCommands } from './main/runtime/domains/jellyfin';
|
||||||
import { createHandleJellyfinPlayCommand } from './main/runtime/jellyfin-cli-play';
|
import { createHandleJellyfinPlayCommand } from './main/runtime/domains/jellyfin';
|
||||||
import { createHandleJellyfinRemoteAnnounceCommand } from './main/runtime/jellyfin-cli-remote-announce';
|
import { createHandleJellyfinRemoteAnnounceCommand } from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createBuildHandleJellyfinAuthCommandsMainDepsHandler,
|
createBuildHandleJellyfinAuthCommandsMainDepsHandler,
|
||||||
createBuildHandleJellyfinListCommandsMainDepsHandler,
|
createBuildHandleJellyfinListCommandsMainDepsHandler,
|
||||||
createBuildHandleJellyfinPlayCommandMainDepsHandler,
|
createBuildHandleJellyfinPlayCommandMainDepsHandler,
|
||||||
createBuildHandleJellyfinRemoteAnnounceCommandMainDepsHandler,
|
createBuildHandleJellyfinRemoteAnnounceCommandMainDepsHandler,
|
||||||
} from './main/runtime/jellyfin-cli-main-deps';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createGetJellyfinClientInfoHandler,
|
createGetJellyfinClientInfoHandler,
|
||||||
createGetResolvedJellyfinConfigHandler,
|
createGetResolvedJellyfinConfigHandler,
|
||||||
} from './main/runtime/jellyfin-client-info';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createBuildGetJellyfinClientInfoMainDepsHandler,
|
createBuildGetJellyfinClientInfoMainDepsHandler,
|
||||||
createBuildGetResolvedJellyfinConfigMainDepsHandler,
|
createBuildGetResolvedJellyfinConfigMainDepsHandler,
|
||||||
} from './main/runtime/jellyfin-client-info-main-deps';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createApplyJellyfinMpvDefaultsHandler,
|
createApplyJellyfinMpvDefaultsHandler,
|
||||||
createGetDefaultSocketPathHandler,
|
createGetDefaultSocketPathHandler,
|
||||||
} from './main/runtime/mpv-jellyfin-defaults';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createBuildApplyJellyfinMpvDefaultsMainDepsHandler,
|
createBuildApplyJellyfinMpvDefaultsMainDepsHandler,
|
||||||
createBuildGetDefaultSocketPathMainDepsHandler,
|
createBuildGetDefaultSocketPathMainDepsHandler,
|
||||||
} from './main/runtime/mpv-jellyfin-defaults-main-deps';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import { createBuildMediaRuntimeMainDepsHandler } from './main/runtime/media-runtime-main-deps';
|
import { createBuildMediaRuntimeMainDepsHandler } from './main/runtime/domains/startup';
|
||||||
import {
|
import {
|
||||||
createBuildDictionaryRootsMainHandler,
|
createBuildDictionaryRootsMainHandler,
|
||||||
createBuildFrequencyDictionaryRootsMainHandler,
|
createBuildFrequencyDictionaryRootsMainHandler,
|
||||||
createBuildFrequencyDictionaryRuntimeMainDepsHandler,
|
createBuildFrequencyDictionaryRuntimeMainDepsHandler,
|
||||||
createBuildJlptDictionaryRuntimeMainDepsHandler,
|
createBuildJlptDictionaryRuntimeMainDepsHandler,
|
||||||
} from './main/runtime/dictionary-runtime-main-deps';
|
} from './main/runtime/domains/startup';
|
||||||
import { createPlayJellyfinItemInMpvHandler } from './main/runtime/jellyfin-playback-launch';
|
import { createPlayJellyfinItemInMpvHandler } from './main/runtime/domains/jellyfin';
|
||||||
import { createBuildPlayJellyfinItemInMpvMainDepsHandler } from './main/runtime/jellyfin-playback-launch-main-deps';
|
import { createBuildPlayJellyfinItemInMpvMainDepsHandler } from './main/runtime/domains/jellyfin';
|
||||||
import { createPreloadJellyfinExternalSubtitlesHandler } from './main/runtime/jellyfin-subtitle-preload';
|
import { createPreloadJellyfinExternalSubtitlesHandler } from './main/runtime/domains/jellyfin';
|
||||||
import { createBuildPreloadJellyfinExternalSubtitlesMainDepsHandler } from './main/runtime/jellyfin-subtitle-preload-main-deps';
|
import { createBuildPreloadJellyfinExternalSubtitlesMainDepsHandler } from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createStartJellyfinRemoteSessionHandler,
|
createStartJellyfinRemoteSessionHandler,
|
||||||
createStopJellyfinRemoteSessionHandler,
|
createStopJellyfinRemoteSessionHandler,
|
||||||
} from './main/runtime/jellyfin-remote-session-lifecycle';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import {
|
import {
|
||||||
createBuildStartJellyfinRemoteSessionMainDepsHandler,
|
createBuildStartJellyfinRemoteSessionMainDepsHandler,
|
||||||
createBuildStopJellyfinRemoteSessionMainDepsHandler,
|
createBuildStopJellyfinRemoteSessionMainDepsHandler,
|
||||||
} from './main/runtime/jellyfin-remote-session-main-deps';
|
} from './main/runtime/domains/jellyfin';
|
||||||
import { createCliCommandRuntimeHandler } from './main/runtime/cli-command-runtime-handler';
|
import { createCliCommandRuntimeHandler } from './main/runtime/domains/ipc';
|
||||||
import { createInitialArgsRuntimeHandler } from './main/runtime/initial-args-runtime-handler';
|
import { createInitialArgsRuntimeHandler } from './main/runtime/domains/ipc';
|
||||||
import {
|
import {
|
||||||
createGetFieldGroupingResolverHandler,
|
createGetFieldGroupingResolverHandler,
|
||||||
createSetFieldGroupingResolverHandler,
|
createSetFieldGroupingResolverHandler,
|
||||||
} from './main/runtime/field-grouping-resolver';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createBuildGetFieldGroupingResolverMainDepsHandler,
|
createBuildGetFieldGroupingResolverMainDepsHandler,
|
||||||
createBuildSetFieldGroupingResolverMainDepsHandler,
|
createBuildSetFieldGroupingResolverMainDepsHandler,
|
||||||
} from './main/runtime/field-grouping-resolver-main-deps';
|
} from './main/runtime/domains/overlay';
|
||||||
import { createBuildFieldGroupingOverlayMainDepsHandler } from './main/runtime/field-grouping-overlay-main-deps';
|
import { createBuildFieldGroupingOverlayMainDepsHandler } from './main/runtime/domains/overlay';
|
||||||
import { createCliCommandContextFactory } from './main/runtime/cli-command-context-factory';
|
import { createCliCommandContextFactory } from './main/runtime/domains/ipc';
|
||||||
import { createBindMpvMainEventHandlersHandler } from './main/runtime/mpv-main-event-bindings';
|
import { createBindMpvMainEventHandlersHandler } from './main/runtime/domains/mpv';
|
||||||
import { createBuildBindMpvMainEventHandlersMainDepsHandler } from './main/runtime/mpv-main-event-main-deps';
|
import { createBuildBindMpvMainEventHandlersMainDepsHandler } from './main/runtime/domains/mpv';
|
||||||
import { createBuildMpvClientRuntimeServiceFactoryDepsHandler } from './main/runtime/mpv-client-runtime-service-main-deps';
|
import { createBuildMpvClientRuntimeServiceFactoryDepsHandler } from './main/runtime/domains/mpv';
|
||||||
import { createMpvClientRuntimeServiceFactory } from './main/runtime/mpv-client-runtime-service';
|
import { createMpvClientRuntimeServiceFactory } from './main/runtime/domains/mpv';
|
||||||
import { createUpdateMpvSubtitleRenderMetricsHandler } from './main/runtime/mpv-subtitle-render-metrics';
|
import { createUpdateMpvSubtitleRenderMetricsHandler } from './main/runtime/domains/mpv';
|
||||||
import { createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler } from './main/runtime/mpv-subtitle-render-metrics-main-deps';
|
import { createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler } from './main/runtime/domains/mpv';
|
||||||
import {
|
import {
|
||||||
createBuildTokenizerDepsMainHandler,
|
createBuildTokenizerDepsMainHandler,
|
||||||
createCreateMecabTokenizerAndCheckMainHandler,
|
createCreateMecabTokenizerAndCheckMainHandler,
|
||||||
createPrewarmSubtitleDictionariesMainHandler,
|
createPrewarmSubtitleDictionariesMainHandler,
|
||||||
} from './main/runtime/subtitle-tokenization-main-deps';
|
} from './main/runtime/domains/mpv';
|
||||||
import {
|
import {
|
||||||
createLaunchBackgroundWarmupTaskHandler,
|
createLaunchBackgroundWarmupTaskHandler,
|
||||||
createStartBackgroundWarmupsHandler,
|
createStartBackgroundWarmupsHandler,
|
||||||
} from './main/runtime/startup-warmups';
|
} from './main/runtime/domains/startup';
|
||||||
import {
|
import {
|
||||||
createBuildLaunchBackgroundWarmupTaskMainDepsHandler,
|
createBuildLaunchBackgroundWarmupTaskMainDepsHandler,
|
||||||
createBuildStartBackgroundWarmupsMainDepsHandler,
|
createBuildStartBackgroundWarmupsMainDepsHandler,
|
||||||
} from './main/runtime/startup-warmups-main-deps';
|
} from './main/runtime/domains/startup';
|
||||||
import {
|
import {
|
||||||
createEnforceOverlayLayerOrderHandler,
|
createEnforceOverlayLayerOrderHandler,
|
||||||
createEnsureOverlayWindowLevelHandler,
|
createEnsureOverlayWindowLevelHandler,
|
||||||
createUpdateInvisibleOverlayBoundsHandler,
|
createUpdateInvisibleOverlayBoundsHandler,
|
||||||
createUpdateVisibleOverlayBoundsHandler,
|
createUpdateVisibleOverlayBoundsHandler,
|
||||||
} from './main/runtime/overlay-window-layout';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createBuildEnforceOverlayLayerOrderMainDepsHandler,
|
createBuildEnforceOverlayLayerOrderMainDepsHandler,
|
||||||
createBuildEnsureOverlayWindowLevelMainDepsHandler,
|
createBuildEnsureOverlayWindowLevelMainDepsHandler,
|
||||||
createBuildUpdateInvisibleOverlayBoundsMainDepsHandler,
|
createBuildUpdateInvisibleOverlayBoundsMainDepsHandler,
|
||||||
createBuildUpdateVisibleOverlayBoundsMainDepsHandler,
|
createBuildUpdateVisibleOverlayBoundsMainDepsHandler,
|
||||||
} from './main/runtime/overlay-window-layout-main-deps';
|
} from './main/runtime/domains/overlay';
|
||||||
import { buildTrayMenuTemplateRuntime, resolveTrayIconPathRuntime } from './main/runtime/tray-runtime';
|
import { buildTrayMenuTemplateRuntime, resolveTrayIconPathRuntime } from './main/runtime/domains/overlay';
|
||||||
import { createGlobalShortcutsRuntimeHandlers } from './main/runtime/global-shortcuts-runtime-handlers';
|
import { createGlobalShortcutsRuntimeHandlers } from './main/runtime/domains/shortcuts';
|
||||||
import { createMpvOsdRuntimeHandlers } from './main/runtime/mpv-osd-runtime-handlers';
|
import { createMpvOsdRuntimeHandlers } from './main/runtime/domains/mpv';
|
||||||
import { createCycleSecondarySubModeRuntimeHandler } from './main/runtime/secondary-sub-mode-runtime-handler';
|
import { createCycleSecondarySubModeRuntimeHandler } from './main/runtime/domains/mpv';
|
||||||
import { createNumericShortcutSessionRuntimeHandlers } from './main/runtime/numeric-shortcut-session-runtime-handlers';
|
import { createNumericShortcutSessionRuntimeHandlers } from './main/runtime/domains/shortcuts';
|
||||||
import { createBuildNumericShortcutRuntimeMainDepsHandler } from './main/runtime/numeric-shortcut-runtime-main-deps';
|
import { createBuildNumericShortcutRuntimeMainDepsHandler } from './main/runtime/domains/shortcuts';
|
||||||
import { createOverlayShortcutsRuntimeHandlers } from './main/runtime/overlay-shortcuts-runtime-handlers';
|
import { createOverlayShortcutsRuntimeHandlers } from './main/runtime/domains/shortcuts';
|
||||||
import { createBuildOverlayShortcutsRuntimeMainDepsHandler } from './main/runtime/overlay-shortcuts-runtime-main-deps';
|
import { createBuildOverlayShortcutsRuntimeMainDepsHandler } from './main/runtime/domains/shortcuts';
|
||||||
import {
|
import {
|
||||||
createMarkLastCardAsAudioCardHandler,
|
createMarkLastCardAsAudioCardHandler,
|
||||||
createMineSentenceCardHandler,
|
createMineSentenceCardHandler,
|
||||||
createRefreshKnownWordCacheHandler,
|
createRefreshKnownWordCacheHandler,
|
||||||
createTriggerFieldGroupingHandler,
|
createTriggerFieldGroupingHandler,
|
||||||
createUpdateLastCardFromClipboardHandler,
|
createUpdateLastCardFromClipboardHandler,
|
||||||
} from './main/runtime/anki-actions';
|
} from './main/runtime/domains/mining';
|
||||||
import {
|
import {
|
||||||
createBuildMarkLastCardAsAudioCardMainDepsHandler,
|
createBuildMarkLastCardAsAudioCardMainDepsHandler,
|
||||||
createBuildMineSentenceCardMainDepsHandler,
|
createBuildMineSentenceCardMainDepsHandler,
|
||||||
createBuildRefreshKnownWordCacheMainDepsHandler,
|
createBuildRefreshKnownWordCacheMainDepsHandler,
|
||||||
createBuildTriggerFieldGroupingMainDepsHandler,
|
createBuildTriggerFieldGroupingMainDepsHandler,
|
||||||
createBuildUpdateLastCardFromClipboardMainDepsHandler,
|
createBuildUpdateLastCardFromClipboardMainDepsHandler,
|
||||||
} from './main/runtime/anki-actions-main-deps';
|
} from './main/runtime/domains/mining';
|
||||||
import {
|
import {
|
||||||
createCopyCurrentSubtitleHandler,
|
createCopyCurrentSubtitleHandler,
|
||||||
createHandleMineSentenceDigitHandler,
|
createHandleMineSentenceDigitHandler,
|
||||||
createHandleMultiCopyDigitHandler,
|
createHandleMultiCopyDigitHandler,
|
||||||
} from './main/runtime/mining-actions';
|
} from './main/runtime/domains/mining';
|
||||||
import {
|
import {
|
||||||
createBuildCopyCurrentSubtitleMainDepsHandler,
|
createBuildCopyCurrentSubtitleMainDepsHandler,
|
||||||
createBuildHandleMineSentenceDigitMainDepsHandler,
|
createBuildHandleMineSentenceDigitMainDepsHandler,
|
||||||
createBuildHandleMultiCopyDigitMainDepsHandler,
|
createBuildHandleMultiCopyDigitMainDepsHandler,
|
||||||
} from './main/runtime/mining-actions-main-deps';
|
} from './main/runtime/domains/mining';
|
||||||
import { createBuildOverlayVisibilityRuntimeMainDepsHandler } from './main/runtime/overlay-visibility-runtime-main-deps';
|
import { createBuildOverlayVisibilityRuntimeMainDepsHandler } from './main/runtime/domains/overlay';
|
||||||
import { createOverlayVisibilityRuntime } from './main/runtime/overlay-visibility-runtime';
|
import { createOverlayVisibilityRuntime } from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createAppendClipboardVideoToQueueHandler,
|
createAppendClipboardVideoToQueueHandler,
|
||||||
createHandleOverlayModalClosedHandler,
|
createHandleOverlayModalClosedHandler,
|
||||||
} from './main/runtime/overlay-main-actions';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createBuildAppendClipboardVideoToQueueMainDepsHandler,
|
createBuildAppendClipboardVideoToQueueMainDepsHandler,
|
||||||
createBuildHandleOverlayModalClosedMainDepsHandler,
|
createBuildHandleOverlayModalClosedMainDepsHandler,
|
||||||
} from './main/runtime/overlay-main-actions-main-deps';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createBroadcastRuntimeOptionsChangedHandler,
|
createBroadcastRuntimeOptionsChangedHandler,
|
||||||
createGetRuntimeOptionsStateHandler,
|
createGetRuntimeOptionsStateHandler,
|
||||||
@@ -335,7 +309,7 @@ import {
|
|||||||
createRestorePreviousSecondarySubVisibilityHandler,
|
createRestorePreviousSecondarySubVisibilityHandler,
|
||||||
createSendToActiveOverlayWindowHandler,
|
createSendToActiveOverlayWindowHandler,
|
||||||
createSetOverlayDebugVisualizationEnabledHandler,
|
createSetOverlayDebugVisualizationEnabledHandler,
|
||||||
} from './main/runtime/overlay-runtime-main-actions';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createBuildBroadcastRuntimeOptionsChangedMainDepsHandler,
|
createBuildBroadcastRuntimeOptionsChangedMainDepsHandler,
|
||||||
createBuildGetRuntimeOptionsStateMainDepsHandler,
|
createBuildGetRuntimeOptionsStateMainDepsHandler,
|
||||||
@@ -343,43 +317,43 @@ import {
|
|||||||
createBuildRestorePreviousSecondarySubVisibilityMainDepsHandler,
|
createBuildRestorePreviousSecondarySubVisibilityMainDepsHandler,
|
||||||
createBuildSendToActiveOverlayWindowMainDepsHandler,
|
createBuildSendToActiveOverlayWindowMainDepsHandler,
|
||||||
createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler,
|
createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler,
|
||||||
} from './main/runtime/overlay-runtime-main-actions-main-deps';
|
} from './main/runtime/domains/overlay';
|
||||||
import { createIpcRuntimeHandlers } from './main/runtime/ipc-runtime-handlers';
|
import { createIpcRuntimeHandlers } from './main/runtime/domains/ipc';
|
||||||
import { createBuildMpvCommandFromIpcRuntimeMainDepsHandler } from './main/runtime/ipc-mpv-command-main-deps';
|
import { createBuildMpvCommandFromIpcRuntimeMainDepsHandler } from './main/runtime/domains/ipc';
|
||||||
import { createOverlayWindowRuntimeHandlers } from './main/runtime/overlay-window-runtime-handlers';
|
import { createOverlayWindowRuntimeHandlers } from './main/runtime/domains/overlay';
|
||||||
import { createOverlayRuntimeBootstrapHandlers } from './main/runtime/overlay-runtime-bootstrap-handlers';
|
import { createOverlayRuntimeBootstrapHandlers } from './main/runtime/domains/overlay';
|
||||||
import { createTrayRuntimeHandlers } from './main/runtime/tray-runtime-handlers';
|
import { createTrayRuntimeHandlers } from './main/runtime/domains/overlay';
|
||||||
import { createYomitanExtensionRuntime } from './main/runtime/yomitan-extension-runtime';
|
import { createYomitanExtensionRuntime } from './main/runtime/domains/overlay';
|
||||||
import { createYomitanSettingsRuntime } from './main/runtime/yomitan-settings-runtime';
|
import { createYomitanSettingsRuntime } from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createOnWillQuitCleanupHandler,
|
createOnWillQuitCleanupHandler,
|
||||||
createRestoreWindowsOnActivateHandler,
|
createRestoreWindowsOnActivateHandler,
|
||||||
createShouldRestoreWindowsOnActivateHandler,
|
createShouldRestoreWindowsOnActivateHandler,
|
||||||
} from './main/runtime/app-lifecycle-actions';
|
} from './main/runtime/domains/startup';
|
||||||
import { createBuildOnWillQuitCleanupDepsHandler } from './main/runtime/app-lifecycle-main-cleanup';
|
import { createBuildOnWillQuitCleanupDepsHandler } from './main/runtime/domains/startup';
|
||||||
import {
|
import {
|
||||||
createBuildRestoreWindowsOnActivateMainDepsHandler,
|
createBuildRestoreWindowsOnActivateMainDepsHandler,
|
||||||
createBuildShouldRestoreWindowsOnActivateMainDepsHandler,
|
createBuildShouldRestoreWindowsOnActivateMainDepsHandler,
|
||||||
} from './main/runtime/app-lifecycle-main-activate';
|
} from './main/runtime/domains/startup';
|
||||||
import {
|
import {
|
||||||
buildRestartRequiredConfigMessage,
|
buildRestartRequiredConfigMessage,
|
||||||
createConfigHotReloadAppliedHandler,
|
createConfigHotReloadAppliedHandler,
|
||||||
createConfigHotReloadMessageHandler,
|
createConfigHotReloadMessageHandler,
|
||||||
resolveSubtitleStyleForRenderer,
|
resolveSubtitleStyleForRenderer,
|
||||||
} from './main/runtime/config-hot-reload-handlers';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createBuildConfigHotReloadMessageMainDepsHandler,
|
createBuildConfigHotReloadMessageMainDepsHandler,
|
||||||
createBuildConfigHotReloadAppliedMainDepsHandler,
|
createBuildConfigHotReloadAppliedMainDepsHandler,
|
||||||
createBuildConfigHotReloadRuntimeMainDepsHandler,
|
createBuildConfigHotReloadRuntimeMainDepsHandler,
|
||||||
createBuildWatchConfigPathMainDepsHandler,
|
createBuildWatchConfigPathMainDepsHandler,
|
||||||
createWatchConfigPathHandler,
|
createWatchConfigPathHandler,
|
||||||
} from './main/runtime/config-hot-reload-main-deps';
|
} from './main/runtime/domains/overlay';
|
||||||
import {
|
import {
|
||||||
createBuildCriticalConfigErrorMainDepsHandler,
|
createBuildCriticalConfigErrorMainDepsHandler,
|
||||||
createBuildReloadConfigMainDepsHandler,
|
createBuildReloadConfigMainDepsHandler,
|
||||||
} from './main/runtime/startup-config-main-deps';
|
} from './main/runtime/domains/startup';
|
||||||
import { createBuildAppReadyRuntimeMainDepsHandler } from './main/runtime/app-ready-main-deps';
|
import { createBuildAppReadyRuntimeMainDepsHandler } from './main/runtime/domains/startup';
|
||||||
import { createStartupRuntimeHandlers } from './main/runtime/startup-runtime-handlers';
|
import { createStartupRuntimeHandlers } from './main/runtime/domains/startup';
|
||||||
import {
|
import {
|
||||||
enforceUnsupportedWaylandMode,
|
enforceUnsupportedWaylandMode,
|
||||||
forceX11Backend,
|
forceX11Backend,
|
||||||
@@ -479,6 +453,9 @@ import {
|
|||||||
generateConfigTemplate,
|
generateConfigTemplate,
|
||||||
} from './config';
|
} from './config';
|
||||||
import { resolveConfigDir } from './config/path-resolution';
|
import { resolveConfigDir } from './config/path-resolution';
|
||||||
|
import { createMainRuntimeRegistry } from './main/runtime/registry';
|
||||||
|
import { composeAnilistSetupHandlers } from './main/runtime/composers/anilist-setup-composer';
|
||||||
|
import { composeJellyfinRemoteHandlers } from './main/runtime/composers/jellyfin-remote-composer';
|
||||||
|
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal');
|
app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal');
|
||||||
@@ -613,6 +590,7 @@ const appLogger = {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const runtimeRegistry = createMainRuntimeRegistry();
|
||||||
|
|
||||||
const buildGetDefaultSocketPathMainDepsHandler = createBuildGetDefaultSocketPathMainDepsHandler({
|
const buildGetDefaultSocketPathMainDepsHandler = createBuildGetDefaultSocketPathMainDepsHandler({
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
@@ -826,39 +804,27 @@ const buildConfigHotReloadRuntimeMainDepsHandler = createBuildConfigHotReloadRun
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const buildHandleJellyfinRemotePlayMainDepsHandler =
|
const {
|
||||||
createBuildHandleJellyfinRemotePlayMainDepsHandler({
|
reportJellyfinRemoteProgress,
|
||||||
|
reportJellyfinRemoteStopped,
|
||||||
|
handleJellyfinRemotePlay,
|
||||||
|
handleJellyfinRemotePlaystate,
|
||||||
|
handleJellyfinRemoteGeneralCommand,
|
||||||
|
} = composeJellyfinRemoteHandlers({
|
||||||
getConfiguredSession: () => getConfiguredJellyfinSession(getResolvedJellyfinConfig()),
|
getConfiguredSession: () => getConfiguredJellyfinSession(getResolvedJellyfinConfig()),
|
||||||
getClientInfo: () => getJellyfinClientInfo(),
|
getClientInfo: () => getJellyfinClientInfo(),
|
||||||
getJellyfinConfig: () => getResolvedJellyfinConfig(),
|
getJellyfinConfig: () => getResolvedJellyfinConfig(),
|
||||||
playJellyfinItem: (params) =>
|
playJellyfinItem: (params) =>
|
||||||
playJellyfinItemInMpv(params as Parameters<typeof playJellyfinItemInMpv>[0]),
|
playJellyfinItemInMpv(params as Parameters<typeof playJellyfinItemInMpv>[0]),
|
||||||
logWarn: (message) => logger.warn(message),
|
logWarn: (message) => logger.warn(message),
|
||||||
});
|
|
||||||
const buildHandleJellyfinRemotePlaystateMainDepsHandler =
|
|
||||||
createBuildHandleJellyfinRemotePlaystateMainDepsHandler({
|
|
||||||
getMpvClient: () => appState.mpvClient,
|
getMpvClient: () => appState.mpvClient,
|
||||||
sendMpvCommand: (client, command) => sendMpvCommandRuntime(client as MpvIpcClient, command),
|
sendMpvCommand: (client, command) => sendMpvCommandRuntime(client as MpvIpcClient, command),
|
||||||
reportJellyfinRemoteProgress: (force) => reportJellyfinRemoteProgress(force),
|
|
||||||
reportJellyfinRemoteStopped: () => reportJellyfinRemoteStopped(),
|
|
||||||
jellyfinTicksToSeconds: (ticks) => jellyfinTicksToSecondsRuntime(ticks),
|
jellyfinTicksToSeconds: (ticks) => jellyfinTicksToSecondsRuntime(ticks),
|
||||||
});
|
|
||||||
const buildHandleJellyfinRemoteGeneralCommandMainDepsHandler =
|
|
||||||
createBuildHandleJellyfinRemoteGeneralCommandMainDepsHandler({
|
|
||||||
getMpvClient: () => appState.mpvClient,
|
|
||||||
sendMpvCommand: (client, command) => sendMpvCommandRuntime(client as MpvIpcClient, command),
|
|
||||||
getActivePlayback: () => activeJellyfinRemotePlayback,
|
|
||||||
reportJellyfinRemoteProgress: (force) => reportJellyfinRemoteProgress(force),
|
|
||||||
logDebug: (message) => logger.debug(message),
|
|
||||||
});
|
|
||||||
const buildReportJellyfinRemoteProgressMainDepsHandler =
|
|
||||||
createBuildReportJellyfinRemoteProgressMainDepsHandler({
|
|
||||||
getActivePlayback: () => activeJellyfinRemotePlayback,
|
getActivePlayback: () => activeJellyfinRemotePlayback,
|
||||||
clearActivePlayback: () => {
|
clearActivePlayback: () => {
|
||||||
activeJellyfinRemotePlayback = null;
|
activeJellyfinRemotePlayback = null;
|
||||||
},
|
},
|
||||||
getSession: () => appState.jellyfinRemoteSession,
|
getSession: () => appState.jellyfinRemoteSession,
|
||||||
getMpvClient: () => appState.mpvClient,
|
|
||||||
getNow: () => Date.now(),
|
getNow: () => Date.now(),
|
||||||
getLastProgressAtMs: () => jellyfinRemoteLastProgressAtMs,
|
getLastProgressAtMs: () => jellyfinRemoteLastProgressAtMs,
|
||||||
setLastProgressAtMs: (value) => {
|
setLastProgressAtMs: (value) => {
|
||||||
@@ -868,39 +834,6 @@ const buildReportJellyfinRemoteProgressMainDepsHandler =
|
|||||||
ticksPerSecond: JELLYFIN_TICKS_PER_SECOND,
|
ticksPerSecond: JELLYFIN_TICKS_PER_SECOND,
|
||||||
logDebug: (message, error) => logger.debug(message, error),
|
logDebug: (message, error) => logger.debug(message, error),
|
||||||
});
|
});
|
||||||
const buildReportJellyfinRemoteStoppedMainDepsHandler =
|
|
||||||
createBuildReportJellyfinRemoteStoppedMainDepsHandler({
|
|
||||||
getActivePlayback: () => activeJellyfinRemotePlayback,
|
|
||||||
clearActivePlayback: () => {
|
|
||||||
activeJellyfinRemotePlayback = null;
|
|
||||||
},
|
|
||||||
getSession: () => appState.jellyfinRemoteSession,
|
|
||||||
logDebug: (message, error) => logger.debug(message, error),
|
|
||||||
});
|
|
||||||
const reportJellyfinRemoteProgressMainDeps =
|
|
||||||
buildReportJellyfinRemoteProgressMainDepsHandler();
|
|
||||||
const reportJellyfinRemoteStoppedMainDeps =
|
|
||||||
buildReportJellyfinRemoteStoppedMainDepsHandler();
|
|
||||||
const reportJellyfinRemoteProgress = createReportJellyfinRemoteProgressHandler(
|
|
||||||
reportJellyfinRemoteProgressMainDeps,
|
|
||||||
);
|
|
||||||
const reportJellyfinRemoteStopped = createReportJellyfinRemoteStoppedHandler(
|
|
||||||
reportJellyfinRemoteStoppedMainDeps,
|
|
||||||
);
|
|
||||||
const handleJellyfinRemotePlayMainDeps = buildHandleJellyfinRemotePlayMainDepsHandler();
|
|
||||||
const handleJellyfinRemotePlaystateMainDeps =
|
|
||||||
buildHandleJellyfinRemotePlaystateMainDepsHandler();
|
|
||||||
const handleJellyfinRemoteGeneralCommandMainDeps =
|
|
||||||
buildHandleJellyfinRemoteGeneralCommandMainDepsHandler();
|
|
||||||
const handleJellyfinRemotePlay = createHandleJellyfinRemotePlay(
|
|
||||||
handleJellyfinRemotePlayMainDeps,
|
|
||||||
);
|
|
||||||
const handleJellyfinRemotePlaystate = createHandleJellyfinRemotePlaystate(
|
|
||||||
handleJellyfinRemotePlaystateMainDeps,
|
|
||||||
);
|
|
||||||
const handleJellyfinRemoteGeneralCommand = createHandleJellyfinRemoteGeneralCommand(
|
|
||||||
handleJellyfinRemoteGeneralCommandMainDeps,
|
|
||||||
);
|
|
||||||
|
|
||||||
const configHotReloadRuntime = createConfigHotReloadRuntime(buildConfigHotReloadRuntimeMainDepsHandler());
|
const configHotReloadRuntime = createConfigHotReloadRuntime(buildConfigHotReloadRuntimeMainDepsHandler());
|
||||||
|
|
||||||
@@ -1433,19 +1366,19 @@ const runJellyfinCommand = createRunJellyfinCommandHandler(
|
|||||||
runJellyfinCommandMainDeps,
|
runJellyfinCommandMainDeps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const buildNotifyAnilistSetupMainDepsHandler = createBuildNotifyAnilistSetupMainDepsHandler({
|
const {
|
||||||
hasMpvClient: () => Boolean(appState.mpvClient),
|
notifyAnilistSetup,
|
||||||
showMpvOsd: (message) => showMpvOsd(message),
|
consumeAnilistSetupTokenFromUrl,
|
||||||
showDesktopNotification: (title, options) => showDesktopNotification(title, options),
|
handleAnilistSetupProtocolUrl,
|
||||||
logInfo: (message) => logger.info(message),
|
registerSubminerProtocolClient,
|
||||||
});
|
} = composeAnilistSetupHandlers({
|
||||||
const notifyAnilistSetupMainDeps = buildNotifyAnilistSetupMainDepsHandler();
|
notifyDeps: {
|
||||||
const notifyAnilistSetup = createNotifyAnilistSetupHandler(
|
hasMpvClient: () => Boolean(appState.mpvClient),
|
||||||
notifyAnilistSetupMainDeps,
|
showMpvOsd: (message) => showMpvOsd(message),
|
||||||
);
|
showDesktopNotification: (title, options) => showDesktopNotification(title, options),
|
||||||
|
logInfo: (message) => logger.info(message),
|
||||||
const buildConsumeAnilistSetupTokenFromUrlMainDepsHandler =
|
},
|
||||||
createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler({
|
consumeTokenDeps: {
|
||||||
consumeAnilistSetupCallbackUrl,
|
consumeAnilistSetupCallbackUrl,
|
||||||
saveToken: (token) => anilistTokenStore.saveToken(token),
|
saveToken: (token) => anilistTokenStore.saveToken(token),
|
||||||
setCachedToken: (token) => {
|
setCachedToken: (token) => {
|
||||||
@@ -1471,26 +1404,12 @@ const buildConsumeAnilistSetupTokenFromUrlMainDepsHandler =
|
|||||||
appState.anilistSetupWindow.close();
|
appState.anilistSetupWindow.close();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
const consumeAnilistSetupTokenFromUrlMainDeps =
|
handleProtocolDeps: {
|
||||||
buildConsumeAnilistSetupTokenFromUrlMainDepsHandler();
|
|
||||||
const consumeAnilistSetupTokenFromUrl = createConsumeAnilistSetupTokenFromUrlHandler(
|
|
||||||
consumeAnilistSetupTokenFromUrlMainDeps,
|
|
||||||
);
|
|
||||||
|
|
||||||
const buildHandleAnilistSetupProtocolUrlMainDepsHandler =
|
|
||||||
createBuildHandleAnilistSetupProtocolUrlMainDepsHandler({
|
|
||||||
consumeAnilistSetupTokenFromUrl: (rawUrl) => consumeAnilistSetupTokenFromUrl(rawUrl),
|
consumeAnilistSetupTokenFromUrl: (rawUrl) => consumeAnilistSetupTokenFromUrl(rawUrl),
|
||||||
logWarn: (message, details) => logger.warn(message, details),
|
logWarn: (message, details) => logger.warn(message, details),
|
||||||
});
|
},
|
||||||
const handleAnilistSetupProtocolUrlMainDeps =
|
registerProtocolClientDeps: {
|
||||||
buildHandleAnilistSetupProtocolUrlMainDepsHandler();
|
|
||||||
const handleAnilistSetupProtocolUrl = createHandleAnilistSetupProtocolUrlHandler(
|
|
||||||
handleAnilistSetupProtocolUrlMainDeps,
|
|
||||||
);
|
|
||||||
|
|
||||||
const buildRegisterSubminerProtocolClientMainDepsHandler =
|
|
||||||
createBuildRegisterSubminerProtocolClientMainDepsHandler({
|
|
||||||
isDefaultApp: () => Boolean(process.defaultApp),
|
isDefaultApp: () => Boolean(process.defaultApp),
|
||||||
getArgv: () => process.argv,
|
getArgv: () => process.argv,
|
||||||
execPath: process.execPath,
|
execPath: process.execPath,
|
||||||
@@ -1500,12 +1419,8 @@ const buildRegisterSubminerProtocolClientMainDepsHandler =
|
|||||||
? app.setAsDefaultProtocolClient(scheme, appPath, args)
|
? app.setAsDefaultProtocolClient(scheme, appPath, args)
|
||||||
: app.setAsDefaultProtocolClient(scheme),
|
: app.setAsDefaultProtocolClient(scheme),
|
||||||
logWarn: (message, details) => logger.warn(message, details),
|
logWarn: (message, details) => logger.warn(message, details),
|
||||||
});
|
},
|
||||||
const registerSubminerProtocolClientMainDeps =
|
});
|
||||||
buildRegisterSubminerProtocolClientMainDepsHandler();
|
|
||||||
const registerSubminerProtocolClient = createRegisterSubminerProtocolClientHandler(
|
|
||||||
registerSubminerProtocolClientMainDeps,
|
|
||||||
);
|
|
||||||
|
|
||||||
const maybeFocusExistingAnilistSetupWindow = createMaybeFocusExistingAnilistSetupWindowHandler({
|
const maybeFocusExistingAnilistSetupWindow = createMaybeFocusExistingAnilistSetupWindowHandler({
|
||||||
getSetupWindow: () => appState.anilistSetupWindow,
|
getSetupWindow: () => appState.anilistSetupWindow,
|
||||||
@@ -2100,7 +2015,7 @@ const buildAppReadyRuntimeMainDepsHandler = createBuildAppReadyRuntimeMainDepsHa
|
|||||||
});
|
});
|
||||||
const appReadyRuntimeRunner = createAppReadyRuntimeRunner(buildAppReadyRuntimeMainDepsHandler());
|
const appReadyRuntimeRunner = createAppReadyRuntimeRunner(buildAppReadyRuntimeMainDepsHandler());
|
||||||
|
|
||||||
const { appLifecycleRuntimeRunner, runAndApplyStartupState } = createStartupRuntimeHandlers<
|
const { appLifecycleRuntimeRunner, runAndApplyStartupState } = runtimeRegistry.startup.createStartupRuntimeHandlers<
|
||||||
CliArgs,
|
CliArgs,
|
||||||
StartupState,
|
StartupState,
|
||||||
ReturnType<typeof createStartupBootstrapRuntimeDeps>
|
ReturnType<typeof createStartupBootstrapRuntimeDeps>
|
||||||
@@ -2770,7 +2685,10 @@ const buildMpvCommandFromIpcRuntimeMainDepsHandler =
|
|||||||
|
|
||||||
const mpvCommandFromIpcRuntimeMainDeps = buildMpvCommandFromIpcRuntimeMainDepsHandler();
|
const mpvCommandFromIpcRuntimeMainDeps = buildMpvCommandFromIpcRuntimeMainDepsHandler();
|
||||||
const { handleMpvCommandFromIpc: handleMpvCommandFromIpcHandler, runSubsyncManualFromIpc: runSubsyncManualFromIpcHandler } =
|
const { handleMpvCommandFromIpc: handleMpvCommandFromIpcHandler, runSubsyncManualFromIpc: runSubsyncManualFromIpcHandler } =
|
||||||
createIpcRuntimeHandlers<SubsyncManualRunRequest, Awaited<ReturnType<typeof subsyncRuntime.runManualFromIpc>>>({
|
runtimeRegistry.ipc.createIpcRuntimeHandlers<
|
||||||
|
SubsyncManualRunRequest,
|
||||||
|
Awaited<ReturnType<typeof subsyncRuntime.runManualFromIpc>>
|
||||||
|
>({
|
||||||
handleMpvCommandFromIpcDeps: {
|
handleMpvCommandFromIpcDeps: {
|
||||||
handleMpvCommandFromIpcRuntime,
|
handleMpvCommandFromIpcRuntime,
|
||||||
buildMpvCommandDeps: () => mpvCommandFromIpcRuntimeMainDeps,
|
buildMpvCommandDeps: () => mpvCommandFromIpcRuntimeMainDeps,
|
||||||
@@ -2923,7 +2841,7 @@ const yomitanExtensionRuntime = createYomitanExtensionRuntime({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { initializeOverlayRuntime: initializeOverlayRuntimeHandler } =
|
const { initializeOverlayRuntime: initializeOverlayRuntimeHandler } =
|
||||||
createOverlayRuntimeBootstrapHandlers({
|
runtimeRegistry.overlay.createOverlayRuntimeBootstrapHandlers({
|
||||||
initializeOverlayRuntimeMainDeps: {
|
initializeOverlayRuntimeMainDeps: {
|
||||||
appState,
|
appState,
|
||||||
overlayManager: {
|
overlayManager: {
|
||||||
|
|||||||
40
src/main/runtime/composers/anilist-setup-composer.test.ts
Normal file
40
src/main/runtime/composers/anilist-setup-composer.test.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { composeAnilistSetupHandlers } from './anilist-setup-composer';
|
||||||
|
|
||||||
|
test('composeAnilistSetupHandlers returns callable setup handlers', () => {
|
||||||
|
const composed = composeAnilistSetupHandlers({
|
||||||
|
notifyDeps: {
|
||||||
|
hasMpvClient: () => false,
|
||||||
|
showMpvOsd: () => {},
|
||||||
|
showDesktopNotification: () => {},
|
||||||
|
logInfo: () => {},
|
||||||
|
},
|
||||||
|
consumeTokenDeps: {
|
||||||
|
consumeAnilistSetupCallbackUrl: () => false,
|
||||||
|
saveToken: () => {},
|
||||||
|
setCachedToken: () => {},
|
||||||
|
setResolvedState: () => {},
|
||||||
|
setSetupPageOpened: () => {},
|
||||||
|
onSuccess: () => {},
|
||||||
|
closeWindow: () => {},
|
||||||
|
},
|
||||||
|
handleProtocolDeps: {
|
||||||
|
consumeAnilistSetupTokenFromUrl: () => false,
|
||||||
|
logWarn: () => {},
|
||||||
|
},
|
||||||
|
registerProtocolClientDeps: {
|
||||||
|
isDefaultApp: () => false,
|
||||||
|
getArgv: () => [],
|
||||||
|
execPath: process.execPath,
|
||||||
|
resolvePath: (value) => value,
|
||||||
|
setAsDefaultProtocolClient: () => true,
|
||||||
|
logWarn: () => {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(typeof composed.notifyAnilistSetup, 'function');
|
||||||
|
assert.equal(typeof composed.consumeAnilistSetupTokenFromUrl, 'function');
|
||||||
|
assert.equal(typeof composed.handleAnilistSetupProtocolUrl, 'function');
|
||||||
|
assert.equal(typeof composed.registerSubminerProtocolClient, 'function');
|
||||||
|
});
|
||||||
55
src/main/runtime/composers/anilist-setup-composer.ts
Normal file
55
src/main/runtime/composers/anilist-setup-composer.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler,
|
||||||
|
createBuildHandleAnilistSetupProtocolUrlMainDepsHandler,
|
||||||
|
createBuildNotifyAnilistSetupMainDepsHandler,
|
||||||
|
createBuildRegisterSubminerProtocolClientMainDepsHandler,
|
||||||
|
createConsumeAnilistSetupTokenFromUrlHandler,
|
||||||
|
createHandleAnilistSetupProtocolUrlHandler,
|
||||||
|
createNotifyAnilistSetupHandler,
|
||||||
|
createRegisterSubminerProtocolClientHandler,
|
||||||
|
} from '../domains/anilist';
|
||||||
|
|
||||||
|
type NotifyHandler = ReturnType<typeof createNotifyAnilistSetupHandler>;
|
||||||
|
type ConsumeHandler = ReturnType<typeof createConsumeAnilistSetupTokenFromUrlHandler>;
|
||||||
|
type HandleProtocolHandler = ReturnType<typeof createHandleAnilistSetupProtocolUrlHandler>;
|
||||||
|
type RegisterClientHandler = ReturnType<typeof createRegisterSubminerProtocolClientHandler>;
|
||||||
|
|
||||||
|
export type AnilistSetupComposerOptions = {
|
||||||
|
notifyDeps: Parameters<typeof createBuildNotifyAnilistSetupMainDepsHandler>[0];
|
||||||
|
consumeTokenDeps: Parameters<typeof createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler>[0];
|
||||||
|
handleProtocolDeps: Parameters<typeof createBuildHandleAnilistSetupProtocolUrlMainDepsHandler>[0];
|
||||||
|
registerProtocolClientDeps: Parameters<
|
||||||
|
typeof createBuildRegisterSubminerProtocolClientMainDepsHandler
|
||||||
|
>[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnilistSetupComposerResult = {
|
||||||
|
notifyAnilistSetup: NotifyHandler;
|
||||||
|
consumeAnilistSetupTokenFromUrl: ConsumeHandler;
|
||||||
|
handleAnilistSetupProtocolUrl: HandleProtocolHandler;
|
||||||
|
registerSubminerProtocolClient: RegisterClientHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function composeAnilistSetupHandlers(
|
||||||
|
options: AnilistSetupComposerOptions,
|
||||||
|
): AnilistSetupComposerResult {
|
||||||
|
const notifyAnilistSetup = createNotifyAnilistSetupHandler(
|
||||||
|
createBuildNotifyAnilistSetupMainDepsHandler(options.notifyDeps)(),
|
||||||
|
);
|
||||||
|
const consumeAnilistSetupTokenFromUrl = createConsumeAnilistSetupTokenFromUrlHandler(
|
||||||
|
createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler(options.consumeTokenDeps)(),
|
||||||
|
);
|
||||||
|
const handleAnilistSetupProtocolUrl = createHandleAnilistSetupProtocolUrlHandler(
|
||||||
|
createBuildHandleAnilistSetupProtocolUrlMainDepsHandler(options.handleProtocolDeps)(),
|
||||||
|
);
|
||||||
|
const registerSubminerProtocolClient = createRegisterSubminerProtocolClientHandler(
|
||||||
|
createBuildRegisterSubminerProtocolClientMainDepsHandler(options.registerProtocolClientDeps)(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
notifyAnilistSetup,
|
||||||
|
consumeAnilistSetupTokenFromUrl,
|
||||||
|
handleAnilistSetupProtocolUrl,
|
||||||
|
registerSubminerProtocolClient,
|
||||||
|
};
|
||||||
|
}
|
||||||
34
src/main/runtime/composers/jellyfin-remote-composer.test.ts
Normal file
34
src/main/runtime/composers/jellyfin-remote-composer.test.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { composeJellyfinRemoteHandlers } from './jellyfin-remote-composer';
|
||||||
|
|
||||||
|
test('composeJellyfinRemoteHandlers returns callable jellyfin remote handlers', () => {
|
||||||
|
let lastProgressAt = 0;
|
||||||
|
const composed = composeJellyfinRemoteHandlers({
|
||||||
|
getConfiguredSession: () => null,
|
||||||
|
getClientInfo: () => ({ clientName: 'SubMiner', clientVersion: 'test', deviceId: 'dev' }) as never,
|
||||||
|
getJellyfinConfig: () => ({ enabled: false }) as never,
|
||||||
|
playJellyfinItem: async () => {},
|
||||||
|
logWarn: () => {},
|
||||||
|
getMpvClient: () => null,
|
||||||
|
sendMpvCommand: () => {},
|
||||||
|
jellyfinTicksToSeconds: () => 0,
|
||||||
|
getActivePlayback: () => null,
|
||||||
|
clearActivePlayback: () => {},
|
||||||
|
getSession: () => null,
|
||||||
|
getNow: () => 0,
|
||||||
|
getLastProgressAtMs: () => lastProgressAt,
|
||||||
|
setLastProgressAtMs: (next) => {
|
||||||
|
lastProgressAt = next;
|
||||||
|
},
|
||||||
|
progressIntervalMs: 3000,
|
||||||
|
ticksPerSecond: 10_000_000,
|
||||||
|
logDebug: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(typeof composed.reportJellyfinRemoteProgress, 'function');
|
||||||
|
assert.equal(typeof composed.reportJellyfinRemoteStopped, 'function');
|
||||||
|
assert.equal(typeof composed.handleJellyfinRemotePlay, 'function');
|
||||||
|
assert.equal(typeof composed.handleJellyfinRemotePlaystate, 'function');
|
||||||
|
assert.equal(typeof composed.handleJellyfinRemoteGeneralCommand, 'function');
|
||||||
|
});
|
||||||
124
src/main/runtime/composers/jellyfin-remote-composer.ts
Normal file
124
src/main/runtime/composers/jellyfin-remote-composer.ts
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import {
|
||||||
|
createBuildHandleJellyfinRemoteGeneralCommandMainDepsHandler,
|
||||||
|
createBuildHandleJellyfinRemotePlayMainDepsHandler,
|
||||||
|
createBuildHandleJellyfinRemotePlaystateMainDepsHandler,
|
||||||
|
createBuildReportJellyfinRemoteProgressMainDepsHandler,
|
||||||
|
createBuildReportJellyfinRemoteStoppedMainDepsHandler,
|
||||||
|
createHandleJellyfinRemoteGeneralCommand,
|
||||||
|
createHandleJellyfinRemotePlay,
|
||||||
|
createHandleJellyfinRemotePlaystate,
|
||||||
|
createReportJellyfinRemoteProgressHandler,
|
||||||
|
createReportJellyfinRemoteStoppedHandler,
|
||||||
|
} from '../domains/jellyfin';
|
||||||
|
|
||||||
|
type RemotePlayPayload = Parameters<ReturnType<typeof createHandleJellyfinRemotePlay>>[0];
|
||||||
|
type RemotePlaystatePayload = Parameters<ReturnType<typeof createHandleJellyfinRemotePlaystate>>[0];
|
||||||
|
type RemoteGeneralPayload = Parameters<ReturnType<typeof createHandleJellyfinRemoteGeneralCommand>>[0];
|
||||||
|
|
||||||
|
export type JellyfinRemoteComposerOptions = {
|
||||||
|
getConfiguredSession: Parameters<typeof createBuildHandleJellyfinRemotePlayMainDepsHandler>[0]['getConfiguredSession'];
|
||||||
|
getClientInfo: Parameters<typeof createBuildHandleJellyfinRemotePlayMainDepsHandler>[0]['getClientInfo'];
|
||||||
|
getJellyfinConfig: Parameters<typeof createBuildHandleJellyfinRemotePlayMainDepsHandler>[0]['getJellyfinConfig'];
|
||||||
|
playJellyfinItem: Parameters<typeof createBuildHandleJellyfinRemotePlayMainDepsHandler>[0]['playJellyfinItem'];
|
||||||
|
logWarn: Parameters<typeof createBuildHandleJellyfinRemotePlayMainDepsHandler>[0]['logWarn'];
|
||||||
|
getMpvClient: Parameters<typeof createBuildReportJellyfinRemoteProgressMainDepsHandler>[0]['getMpvClient'];
|
||||||
|
sendMpvCommand: Parameters<typeof createBuildHandleJellyfinRemotePlaystateMainDepsHandler>[0]['sendMpvCommand'];
|
||||||
|
jellyfinTicksToSeconds: Parameters<
|
||||||
|
typeof createBuildHandleJellyfinRemotePlaystateMainDepsHandler
|
||||||
|
>[0]['jellyfinTicksToSeconds'];
|
||||||
|
getActivePlayback: Parameters<typeof createBuildHandleJellyfinRemoteGeneralCommandMainDepsHandler>[0]['getActivePlayback'];
|
||||||
|
clearActivePlayback: Parameters<typeof createBuildReportJellyfinRemoteProgressMainDepsHandler>[0]['clearActivePlayback'];
|
||||||
|
getSession: Parameters<typeof createBuildReportJellyfinRemoteProgressMainDepsHandler>[0]['getSession'];
|
||||||
|
getNow: Parameters<typeof createBuildReportJellyfinRemoteProgressMainDepsHandler>[0]['getNow'];
|
||||||
|
getLastProgressAtMs: Parameters<
|
||||||
|
typeof createBuildReportJellyfinRemoteProgressMainDepsHandler
|
||||||
|
>[0]['getLastProgressAtMs'];
|
||||||
|
setLastProgressAtMs: Parameters<
|
||||||
|
typeof createBuildReportJellyfinRemoteProgressMainDepsHandler
|
||||||
|
>[0]['setLastProgressAtMs'];
|
||||||
|
progressIntervalMs: number;
|
||||||
|
ticksPerSecond: number;
|
||||||
|
logDebug: Parameters<typeof createBuildReportJellyfinRemoteProgressMainDepsHandler>[0]['logDebug'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type JellyfinRemoteComposerResult = {
|
||||||
|
reportJellyfinRemoteProgress: ReturnType<typeof createReportJellyfinRemoteProgressHandler>;
|
||||||
|
reportJellyfinRemoteStopped: ReturnType<typeof createReportJellyfinRemoteStoppedHandler>;
|
||||||
|
handleJellyfinRemotePlay: (payload: RemotePlayPayload) => Promise<void>;
|
||||||
|
handleJellyfinRemotePlaystate: (payload: RemotePlaystatePayload) => Promise<void>;
|
||||||
|
handleJellyfinRemoteGeneralCommand: (payload: RemoteGeneralPayload) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function composeJellyfinRemoteHandlers(
|
||||||
|
options: JellyfinRemoteComposerOptions,
|
||||||
|
): JellyfinRemoteComposerResult {
|
||||||
|
const buildReportJellyfinRemoteProgressMainDepsHandler =
|
||||||
|
createBuildReportJellyfinRemoteProgressMainDepsHandler({
|
||||||
|
getActivePlayback: options.getActivePlayback,
|
||||||
|
clearActivePlayback: options.clearActivePlayback,
|
||||||
|
getSession: options.getSession,
|
||||||
|
getMpvClient: options.getMpvClient,
|
||||||
|
getNow: options.getNow,
|
||||||
|
getLastProgressAtMs: options.getLastProgressAtMs,
|
||||||
|
setLastProgressAtMs: options.setLastProgressAtMs,
|
||||||
|
progressIntervalMs: options.progressIntervalMs,
|
||||||
|
ticksPerSecond: options.ticksPerSecond,
|
||||||
|
logDebug: options.logDebug,
|
||||||
|
});
|
||||||
|
const buildReportJellyfinRemoteStoppedMainDepsHandler =
|
||||||
|
createBuildReportJellyfinRemoteStoppedMainDepsHandler({
|
||||||
|
getActivePlayback: options.getActivePlayback,
|
||||||
|
clearActivePlayback: options.clearActivePlayback,
|
||||||
|
getSession: options.getSession,
|
||||||
|
logDebug: options.logDebug,
|
||||||
|
});
|
||||||
|
const reportJellyfinRemoteProgress = createReportJellyfinRemoteProgressHandler(
|
||||||
|
buildReportJellyfinRemoteProgressMainDepsHandler(),
|
||||||
|
);
|
||||||
|
const reportJellyfinRemoteStopped = createReportJellyfinRemoteStoppedHandler(
|
||||||
|
buildReportJellyfinRemoteStoppedMainDepsHandler(),
|
||||||
|
);
|
||||||
|
|
||||||
|
const buildHandleJellyfinRemotePlayMainDepsHandler =
|
||||||
|
createBuildHandleJellyfinRemotePlayMainDepsHandler({
|
||||||
|
getConfiguredSession: options.getConfiguredSession,
|
||||||
|
getClientInfo: options.getClientInfo,
|
||||||
|
getJellyfinConfig: options.getJellyfinConfig,
|
||||||
|
playJellyfinItem: options.playJellyfinItem,
|
||||||
|
logWarn: options.logWarn,
|
||||||
|
});
|
||||||
|
const buildHandleJellyfinRemotePlaystateMainDepsHandler =
|
||||||
|
createBuildHandleJellyfinRemotePlaystateMainDepsHandler({
|
||||||
|
getMpvClient: options.getMpvClient as Parameters<
|
||||||
|
typeof createBuildHandleJellyfinRemotePlaystateMainDepsHandler
|
||||||
|
>[0]['getMpvClient'],
|
||||||
|
sendMpvCommand: options.sendMpvCommand,
|
||||||
|
reportJellyfinRemoteProgress: (force) => reportJellyfinRemoteProgress(force),
|
||||||
|
reportJellyfinRemoteStopped: () => reportJellyfinRemoteStopped(),
|
||||||
|
jellyfinTicksToSeconds: options.jellyfinTicksToSeconds,
|
||||||
|
});
|
||||||
|
const buildHandleJellyfinRemoteGeneralCommandMainDepsHandler =
|
||||||
|
createBuildHandleJellyfinRemoteGeneralCommandMainDepsHandler({
|
||||||
|
getMpvClient: options.getMpvClient as Parameters<
|
||||||
|
typeof createBuildHandleJellyfinRemoteGeneralCommandMainDepsHandler
|
||||||
|
>[0]['getMpvClient'],
|
||||||
|
sendMpvCommand: options.sendMpvCommand,
|
||||||
|
getActivePlayback: options.getActivePlayback,
|
||||||
|
reportJellyfinRemoteProgress: (force) => reportJellyfinRemoteProgress(force),
|
||||||
|
logDebug: (message) => options.logDebug(message, undefined),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
reportJellyfinRemoteProgress,
|
||||||
|
reportJellyfinRemoteStopped,
|
||||||
|
handleJellyfinRemotePlay: createHandleJellyfinRemotePlay(
|
||||||
|
buildHandleJellyfinRemotePlayMainDepsHandler(),
|
||||||
|
),
|
||||||
|
handleJellyfinRemotePlaystate: createHandleJellyfinRemotePlaystate(
|
||||||
|
buildHandleJellyfinRemotePlaystateMainDepsHandler(),
|
||||||
|
),
|
||||||
|
handleJellyfinRemoteGeneralCommand: createHandleJellyfinRemoteGeneralCommand(
|
||||||
|
buildHandleJellyfinRemoteGeneralCommandMainDepsHandler(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user