mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-10 04:46:07 -08:00
refactor(main): move domains into per-domain assemblies (#309)
* refactor(main): move the YouTube domain into an assembly createYoutubeAssembly owns the YouTube flow, playback, media cache, whisper subtitles, primary-subtitle notifications, and the in-app browser, plus the browser quit-on-close state. main.ts builds it once where the first YouTube runtime used to be and calls through the result. Siblings built later are passed as getters or callbacks; tests pin that construction calls none of them. * docs(architecture): describe per-domain assemblies * test(e2e): blank the line before mining the sub-delay cue The previous test leaves the same cue on screen, so the overlay check passed before the seek landed and --mine-sentence could read mpv's empty mid-seek sub-text and skip the card. * refactor(main): move the Jellyfin domain into an assembly createJellyfinAssembly owns the Jellyfin composer call, its playback and remote-progress state, the subtitle cache IO, mpv defaults, and the tray discovery deps. main.ts builds it where the composer call used to be and reads state through getActivePlayback/getQuitOnDisconnectArmed. * refactor(main): move the AniList domain into an assembly createAnilistAssembly owns the AniList setup and tracking composer calls, the setup window, the state runtime, and the token, media-guess, in-flight and attempted-update state they share. main.ts builds it where the setup composer call used to be and keeps the rate limiter, which the stats cover-art fetcher also uses. * refactor(main): move config hot-reload, settings, and sync UI into assemblies createSettingsAssembly owns config hot-reload and the settings window, which share the hot-reload-applied handler; main.ts still supplies that handler's cross-domain deps and the Yomitan deck-name helper. createSyncAssembly owns the sync window, sync IPC runtime, and auto-sync scheduler. Both are built where their blocks were; main.ts keeps the registerHandlers()/start() calls at the same points. * refactor(main): move dictionary runtimes into assemblies createDictionariesAssembly owns the JLPT and frequency lookups and their dictionary-root builders; main.ts still resolves the root paths at the same point. createCharacterDictionaryAssembly owns the character dictionary runtime, Yomitan auto-sync, and the portrait and name-candidate lookups. Both are built where their blocks were; later siblings (Yomitan profile policy, notifications, OSD, subtitle refresh) come in as getters or callbacks. * refactor(main): move overlay modal openers into an assembly createOverlayModalsAssembly owns the shared open-with-notification helper and the runtime options, Jimaku, TsukiHime, subtitle generation, session help, changelog, character dictionary manager, controller, and playlist browser openers. main.ts builds it where the openers used to live. * refactor(logger): export the Logger type for assembly deps The build emits declarations, and the Jellyfin assembly returns the logger in its tray discovery deps, so tsc needs a nameable Logger type. Assemblies now Pick from it directly.
This commit is contained in:
1 parent
a9a4c4f083
commit
2924f04316
23 files changed
+3173
-2010
No files matched your search
@@ -42,6 +42,7 @@ Update checks and startup launcher migration share a serialized update-state sto
|
||||
- `src/config/` owns config definitions, defaults, loading, and resolution.
|
||||
- `src/types/` owns shared cross-runtime contracts via domain entrypoints; `src/types.ts` stays a compatibility barrel.
|
||||
- `src/main/runtime/composers/` owns larger domain compositions.
|
||||
- `src/main/assemblies/` owns per-domain assemblies that `src/main.ts` builds once (see [Layering](./layering.md)).
|
||||
- `src/main.ts` call sites invoke configured runtime handlers and runtime-object methods directly;
|
||||
do not add local pass-through wrappers around them.
|
||||
|
||||
|
||||
@@ -19,21 +19,27 @@ Read when: you need to find the owner module for a behavior or test surface
|
||||
- Config system: `src/config/`; Anki resolution is composed by
|
||||
`src/config/resolve/anki-connect.ts` from focused resolvers in
|
||||
`src/config/resolve/anki-connect/`
|
||||
Config hot-reload and the settings window: `src/main/assemblies/settings.ts`
|
||||
- Overlay/window state: `src/core/services/overlay-*`, `src/main/overlay-*.ts`
|
||||
Overlay-hosted modal openers: `src/main/assemblies/overlay-modals.ts`
|
||||
- MPV runtime and protocol: `src/core/services/mpv*.ts`
|
||||
Windows executable lookup and detached process creation are shared in `src/main/runtime/mpv-process.ts`. The Windows launcher and Jellyfin handlers retain their own playback and connection workflows.
|
||||
- Subtitle/token pipeline: `src/core/services/subtitle-*.ts`, `src/core/services/tokenizer*`, `src/core/services/tokenizer/`, `src/subsync/`
|
||||
JLPT and frequency annotation lookups: `src/main/jlpt-runtime.ts`, `src/main/frequency-dictionary-runtime.ts`, assembled by `src/main/assemblies/dictionaries.ts`
|
||||
- Anki workflow: `src/anki-integration/`, `src/core/services/anki-jimaku*.ts`
|
||||
- Media timing review: `src/main/runtime/media-timing-review.ts` owns the review and hidden `MediaTimingPreviewSession`. The session waits for mpv readiness and acknowledges playback commands; its `time-pos` observations reach the modal through `media-timing-review:preview-position`. The renderer places the cursor from those timestamps and uses an inactivity timeout instead of timing the clip itself.
|
||||
- Immersion tracking: `src/core/services/immersion-tracker/`
|
||||
Includes stats storage/query schema such as `imm_videos`, `imm_media_art`, and `imm_youtube_videos` for per-video and YouTube-specific library metadata.
|
||||
Library-entry identity aliases and merge recommendations are persisted alongside this schema; the stats HTTP and SPA layers only expose and present those domain decisions.
|
||||
`delete-maintenance-scheduler.ts` coalesces and serializes stats deletes; the expensive work runs in `delete-maintenance-worker-thread.ts` while the tracker queues playback writes. Each batch uses one transaction, lexical update, rollup refresh, and incremental lifetime subtraction (`planLifetimeRemovals`/`applyLifetimeRemovals` in `lifetime.ts`). Merges, moves, AniList reassignments, and `stats cleanup -l` use `repairLifetimeSummariesFromMedia` (recompute from the per-video media ledger). The full lifetime rebuild survives only as the empty-table bootstrap; anywhere else it would collapse lifetime totals to the session retention window.
|
||||
- Immersion sync: `src/core/services/stats-sync/`, bound by `src/main/sync-cli.ts`.
|
||||
- Immersion sync: `src/core/services/stats-sync/`, bound by `src/main/sync-cli.ts`. The sync window and auto-sync scheduler live in `src/main/assemblies/sync.ts`.
|
||||
`snapshot-transfer.ts` selects compressed rsync or scp. `transfer-cache.ts` atomically retains the last successfully received snapshot per hashed peer/database identity under the config directory's `sync-transfer-cache/`. Cache copies seed isolated transfer directories; rsync verifies reconstructed files before the existing merge engine runs. The `--make-temp` / `--remove-temp` helpers accept an internal `--transfer-cache` key, with a fallback for older peers that do not recognize it.
|
||||
- AniList tracking + character dictionary: `src/core/services/anilist/`, `src/main/runtime/composers/anilist-*`, `src/main/character-dictionary-runtime.ts`, `src/main/character-dictionary-runtime/`
|
||||
- AniList tracking + character dictionary: `src/core/services/anilist/`, `src/main/runtime/composers/anilist-*` (called by `src/main/assemblies/anilist.ts`), `src/main/character-dictionary-runtime.ts`, `src/main/character-dictionary-runtime/`, assembled by `src/main/assemblies/character-dictionary.ts`
|
||||
- TMDB live-action metadata: `src/core/services/tmdb/` (client + exact-title resolver), `src/core/services/immersion-tracker/live-action-link.ts` (links an entry to a TMDB title and merges other holders of the same title). The AniList cover-art fetcher calls the resolver as its fallback; `imm_anime.media_kind` marks the result and keeps the entry out of AniList season repair.
|
||||
- Jellyfin integration: `src/core/services/jellyfin*.ts`, `src/main/runtime/composers/jellyfin-*`
|
||||
- Jellyfin integration: `src/core/services/jellyfin*.ts`, `src/main/runtime/composers/jellyfin-*`,
|
||||
assembled by `src/main/assemblies/jellyfin.ts`
|
||||
- YouTube playback, subtitles, media cache, and in-app browser: `src/core/services/youtube/`,
|
||||
`src/main/runtime/youtube-*`, assembled by `src/main/assemblies/youtube.ts`
|
||||
- User plugins: `src/core/services/plugins/` (host, `ctx`, `exec`), `src/main/runtime/plugin-panel-runtime.ts` (panel modal), `src/main/runtime/plugin-window-runtime.ts` (plugin windows), `src/renderer/modals/plugin-panel*.ts`; examples in `assets/plugins/`
|
||||
- Window trackers: `src/window-trackers/`
|
||||
- Stats HTTP app: `src/core/services/stats-server.ts`, with route groups and shared route support
|
||||
|
||||
@@ -23,6 +23,11 @@ Renderer, launcher, plugin, and stats each keep their own local layering and sho
|
||||
deps builders (`createBuild*MainDepsHandler`, `*-main-deps.ts`) that re-wrap deps.
|
||||
Adaptation logic (defaults, appState getters/setters, shared state) belongs in the
|
||||
handler or in a named adapter that returns the deps directly.
|
||||
- Group a domain's runtimes in one assembly under `src/main/assemblies/` (for example
|
||||
`createYoutubeAssembly(deps)`). It owns the domain's state, takes an explicit deps
|
||||
object, and returns its runtimes; `main.ts` builds it once and calls through the result.
|
||||
Siblings built later in `main.ts` are passed as getters or callbacks, and construction must
|
||||
not call them.
|
||||
- Prefer injecting dependencies from `src/main/` instead of reaching outward from core services.
|
||||
- Keep side effects explicit and close to composition boundaries.
|
||||
- Put reusable business logic in focused services, not in top-level lifecycle files.
|
||||
|
||||
Reference in new issue
Block a user