mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-10 04:46:07 -08:00
* refactor(main): build overlay geometry and pointer interaction in the overlay assembly Inject Electron's screen (and the stats-window promotion) into the overlay geometry and visible-overlay interaction runtimes so they load under bun test, then construct both in createOverlayAssembly together with the overlay visibility composer and the mpv subtitle suppression handlers. Replace the three regex tests that pinned the moved Linux input and shape code with behaviour tests on the runtimes. * refactor(main): move the autoplay-ready gate into the playback assembly The autoplay-ready gate, its post-warm subtitle prime, the current-media tokenization gate and managed local subtitle selection all read playback state, and playback signals through the gate, so createPlaybackAssembly now builds them. The overlay reaches the gate through a getter. Replace the last four regex guards with behaviour tests: the gate holds the release until the visible overlay has measured the line and ignores untokenized lines during warmup (playback), cached autoplay priming never paints raw first and the sidebar media path is tagged only after prefetch loads (priming runtime), and dashboard mining overrides the Hachidori Anki server only when the proxy is on (stats server runtime). main-wiring.test.ts is now empty and removed. * refactor(main): move the plugin host, panel and windows into a plugins assembly * refactor(main): move session action dispatch and renderer mpv commands into an assembly createSessionActionsAssembly owns the session action dispatcher, the secondary-subtitle mode cycle, queueing the clipboard's video, and the mpv commands the overlay renderer sends. The runtime option cycle both paths used is now one function. * refactor(main): move Whisper subtitle generation into an assembly * refactor(main): resolve subtitle annotation options in a runtime module The runtime-option-over-config resolution that the texthooker page and the MeCab startup decision share moves out of main.ts into createAnnotationOptions. * test(main): cover a non-boolean runtime annotation option value * docs: describe the plugins, session actions and subtitle generation assemblies Update ownership for overlay geometry and pointer interaction, the autoplay-ready gate, and annotation options; point the overlay priming entry points at their new modules; the main-wiring regex debt is gone. * build: export MpvClientEvents so declaration emit can name the plugins assembly's return type
126 lines
11 KiB
Markdown
126 lines
11 KiB
Markdown
<!-- read_when: locating ownership for a runtime, feature, or integration -->
|
|
|
|
# Domain Ownership
|
|
|
|
Status: active
|
|
Last verified: 2026-11-01
|
|
Owner: Kyle Yasuda
|
|
Read when: you need to find the owner module for a behavior or test surface
|
|
|
|
## Runtime Domains
|
|
|
|
- Desktop app runtime: `src/main.ts`, `src/main/`, `src/core/services/`
|
|
- Overlay renderer: `src/renderer/`
|
|
- Launcher CLI: `launcher/`
|
|
- mpv plugin: `plugin/subminer/`
|
|
|
|
## Product / Integration Domains
|
|
|
|
- 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`
|
|
- App startup: app-ready sequence, headless known-word refresh, overlay startup prerequisites and
|
|
overlay runtime bootstrap: `src/main/assemblies/startup.ts`
|
|
- Overlay/window state: `src/core/services/overlay-*`, `src/main/overlay-*.ts`
|
|
Overlay windows, visibility, geometry and pointer interaction, Linux fullscreen handling, mpv
|
|
subtitle suppression while the overlay shows, and the overlay-window IPC handlers (modal
|
|
open/close, pointer interaction, content measurement): `src/main/assemblies/overlay.ts`
|
|
Overlay-hosted modal openers: `src/main/assemblies/overlay-modals.ts`
|
|
- MPV runtime and protocol: `src/core/services/mpv*.ts`
|
|
mpv client creation, mpv event wiring, AniSkip, the autoplay-ready gate that releases mpv's
|
|
startup pause, managed local subtitle selection, subtitle prefetch, and subtitle sidebar state:
|
|
`src/main/assemblies/playback.ts`
|
|
- Keyboard input outside the renderer (overlay, global and numeric shortcuts, session bindings):
|
|
`src/main/assemblies/shortcuts.ts`
|
|
- Session actions (the dispatcher behind shortcuts, controller buttons, CLI commands and plugin
|
|
actions), the secondary-subtitle mode cycle, and the overlay renderer's mpv commands:
|
|
`src/main/assemblies/session-actions.ts`
|
|
- System tray: `src/main/assemblies/tray.ts`
|
|
- Yomitan/Hachidori extension loading, parser runtime deps, and dictionary settings windows:
|
|
`src/main/assemblies/yomitan.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`
|
|
Annotation toggles (a cycled runtime option over its config value): `src/main/runtime/annotation-options.ts`
|
|
Whisper subtitle generation runtime, modal and IPC: `src/main/assemblies/subtitle-generation.ts`
|
|
Subtitle text filters (`subtitleFilter`): `src/shared/subtitle-text-filter.ts`. Primary text is filtered at its two entry points, live `sub-text` in `mpv-protocol.ts` and parsed cues in `playback.ts`, so every consumer sees the same text and live/cue matching still works. A config change re-reads `sub-text` and re-parses the active track (the prefetch controller's parse key).
|
|
- First-run setup: `src/main/runtime/first-run-setup-*.ts`, assembled by `src/main/assemblies/first-run-setup.ts`
|
|
- Anki workflow: `src/anki-integration/`, `src/core/services/anki-jimaku*.ts`
|
|
Card mining handlers, the pending lookup context, field grouping, and media timing review wiring:
|
|
`src/main/assemblies/mining.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/`; tracker startup, the stats server,
|
|
the stats overlay window options, and the `--stats` command are assembled by `src/main/assemblies/stats.ts`
|
|
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`. 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-*` (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-*`,
|
|
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), assembled by `src/main/assemblies/plugins.ts`; `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
|
|
in `src/core/services/stats-server/`
|
|
- Stats SPA: `stats/`
|
|
- Public docs site: `docs-site/`
|
|
|
|
## Shared Contract Entry Points
|
|
|
|
Automatic mpv keyboard discovery uses the `get-mpv-input-bindings` IPC request and
|
|
`MpvInputBindingsSnapshot` in `src/types/session-bindings.ts`.
|
|
`src/main/runtime/mpv-input-bindings.ts` queries the connected player and preserves
|
|
configured keys, including disabled entries. `src/shared/mpv-input-bindings.ts`
|
|
validates discovered keys and translates browser input. The renderer's
|
|
`handlers/mpv-input-forwarding.ts` keeps the session lookup, coalesces asynchronous
|
|
refreshes, and releases held keys on blur or disposal. Discovered `WHEEL_*` bindings forward
|
|
as `keypress <key> <notches>` (Chromium reports 120 px per notch), which matches mpv's own
|
|
precise-scroll scaling. `MBTN_*` buttons forward as held `keydown`/`keyup` when mpv binds the
|
|
button or its `_DBL` variant, so mpv synthesizes double-clicks itself. Configured keybindings and
|
|
the built-in right-click pause run first. Forwarding is the only way pointer input reaches mpv on
|
|
Hyprland, where the overlay cannot be made click-through. `handlers/keyboard.ts` runs
|
|
this fallback after SubMiner controls and refreshes on startup, a delayed startup
|
|
pass, focus, binding reload, and the `mpv-input-bindings:changed` event. Main sends
|
|
that event from `session-bindings-runtime.ts` when mpv's discovered key set changes,
|
|
including the first discovery after connecting, because the overlay often loads
|
|
before mpv connects and the compiled session bindings may not change. Discovery does not enter compiled session bindings,
|
|
the plugin artifact, persistent config, or session help.
|
|
|
|
The subtitle sidebar consumes parsed cues through `SubtitleSidebarSnapshot`. Its `sourceKey`
|
|
identifies the media and subtitle source so renderer selections are invalidated on source changes,
|
|
including changes whose cue text and timings are identical. While open, the sidebar polls the
|
|
cheap `SubtitleSidebarPlaybackState` (cached time, current line, `sourceKey`, `cuesRevision`; no
|
|
mpv round-trips) every 80 ms for active-cue tracking. It fetches the full snapshot, which resolves
|
|
the source over mpv IPC and carries every cue plus config, only on open, config reload, a
|
|
`sourceKey`/`cuesRevision` change, and a ~2 s fallback. Native selection and clean clipboard
|
|
serialization live in `src/renderer/modals/subtitle-sidebar-selection.ts`. Electron lets standard
|
|
Copy input reach the renderer, where sidebar selection takes priority over the live-subtitle binding.
|
|
The preload bridge writes selections through Electron's clipboard API so copying does not depend
|
|
on Chromium document focus or require activating the overlay window.
|
|
|
|
- Config + app-state contracts: `src/types/config.ts`
|
|
- Subtitle/token/media annotation contracts: `src/types/subtitle.ts`
|
|
- Runtime/window/controller/Electron bridge contracts: `src/types/runtime.ts`
|
|
- Anki-specific contracts: `src/types/anki.ts`
|
|
- External integration contracts: `src/types/integrations.ts`
|
|
- Runtime-option contracts: `src/types/runtime-options.ts`
|
|
- Settings UI contracts: `src/types/settings.ts`
|
|
- Session-binding contracts: `src/types/session-bindings.ts`
|
|
- Stats HTTP wire contracts: `src/types/stats-wire.ts`, `src/types/stats-http-contract.ts`
|
|
- Compatibility-only barrel: `src/types.ts`
|
|
|
|
## Ownership Heuristics
|
|
|
|
- Runtime wiring or dependency setup: start in `src/main/`
|
|
- Business logic or service behavior: start in `src/core/services/`
|
|
- UI interaction or overlay DOM behavior: start in `src/renderer/`
|
|
- Command parsing or mpv launch flow: start in `launcher/`
|
|
- Shared contract changes: add or edit the narrowest `src/types/<domain>.ts` entrypoint; only touch `src/types.ts` for compatibility exports.
|
|
- User-facing docs: `docs-site/`
|
|
- Internal process/docs: `docs/`
|