mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-18 05:16:21 -07:00
feat: add subtitle generation and bundle Bun launcher runtime
- Add local subtitle generation and card timing review workflows - Package cross-platform Bun runtimes, launchers, licenses, and source - Consolidate release packaging and refresh v0.19.6 documentation
This commit is contained in:
@@ -10,11 +10,15 @@ Read when: runtime ownership, composition boundaries, or layering questions
|
||||
SubMiner runs as three cooperating runtimes:
|
||||
|
||||
- Electron desktop app in `src/`
|
||||
- Launcher CLI in `launcher/`
|
||||
- Launcher CLI in `launcher/`, with managed app-installed wrappers in `src/main/runtime/managed-launcher.ts`
|
||||
- mpv Lua plugin in `plugin/subminer/`
|
||||
|
||||
The desktop app keeps `src/main.ts` as composition root and pushes behavior into small runtime/domain modules.
|
||||
|
||||
Packaged apps include a private Bun runtime. Setup and release assets provide bootstrap wrappers generated from `src/main/runtime/*-launcher-bootstrap.ts`. macOS runs Bun and the CLI from app resources. Windows stages a versioned private Bun copy under `%LOCALAPPDATA%\SubMiner\launcher-runtime/<version>` so a running launcher does not lock the updater-owned app executable. Linux stages Bun, the matching CLI, and licenses under `${XDG_DATA_HOME:-~/.local/share}/SubMiner/launcher`. Its steady-state path performs one app `stat` and starts the cache without Electron. A missing cache or changed app fingerprint runs `launcher/prepare.cjs` through Electron's Node mode to refresh it. Desktop startup migrates recognized writable legacy JavaScript launchers and refreshes managed payloads after app changes. Development commands still use system Bun.
|
||||
|
||||
Update checks and startup launcher migration share a serialized update-state store. Deferred launcher paths are acknowledged only after migration succeeds or the candidate is no longer eligible. Running Windows launchers and unreadable or unwritable candidates remain pending for a later startup.
|
||||
|
||||
## Read Next
|
||||
|
||||
- [Domains](./domains.md) - who owns what
|
||||
@@ -27,6 +31,7 @@ The desktop app keeps `src/main.ts` as composition root and pushes behavior into
|
||||
- `src/main/` owns composition, runtime setup, IPC wiring, and app lifecycle adapters.
|
||||
- `src/main/boot/` owns boot-phase assembly seams so `src/main.ts` can stay focused on lifecycle coordination and startup-path selection.
|
||||
- `src/core/services/` owns focused runtime services plus pure or side-effect-bounded logic.
|
||||
- `src/core/services/subtitle-generation*.ts` shares local whisper.cpp transcription, safe model downloads, and progress between the launcher and Electron. Optional dialogue mode retains both Silero-detected speech and other audible sections, omits confidently silent gaps, decodes passages independently, and restores original media timing. `src/main/runtime/subtitle-generation-runtime.ts` owns the overlay job lifecycle and only loads completed subtitles into the same local media; `src/shared/subtitle-generation*.ts` owns configuration, the multilingual model catalog, and IPC contracts. The overlay runtime retains a session model selection, validates picker requests through IPC, and keeps external model paths authoritative.
|
||||
- `src/renderer/` owns overlay rendering and input behavior.
|
||||
- `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.
|
||||
@@ -40,3 +45,7 @@ The desktop app keeps `src/main.ts` as composition root and pushes behavior into
|
||||
- Composition over monoliths
|
||||
- Pure helpers where possible
|
||||
- Stable user behavior while internals evolve
|
||||
|
||||
Startup resolves and creates the user-data directory in `src/main-entry-runtime.ts`
|
||||
before the entry process requests Electron's single-instance lock. Main-process
|
||||
config bootstrap then writes the default config only when no config file exists.
|
||||
|
||||
@@ -27,6 +27,8 @@ Read when: you need to find the owner module for a behavior or test surface
|
||||
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`.
|
||||
`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/`
|
||||
- Jellyfin integration: `src/core/services/jellyfin*.ts`, `src/main/runtime/composers/jellyfin-*`
|
||||
- Anime browser: extension bridge client, sidecar, and stream handling in `src/anime-bridge/`;
|
||||
@@ -47,6 +49,25 @@ Read when: you need to find the owner module for a behavior or test surface
|
||||
|
||||
## 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. `handlers/keyboard.ts` runs
|
||||
this fallback after SubMiner controls and refreshes on startup, a delayed startup
|
||||
pass, focus, and binding reload. 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. 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`
|
||||
|
||||
@@ -23,7 +23,7 @@ Renderer, launcher, plugin, and stats each keep their own local layering and sho
|
||||
- Keep side effects explicit and close to composition boundaries.
|
||||
- Put reusable business logic in focused services, not in top-level lifecycle files.
|
||||
- Keep renderer concerns in `src/renderer/`; avoid leaking DOM behavior into main-process code.
|
||||
- Treat `launcher/*.ts` as source of truth for the launcher. Never hand-edit `dist/launcher/subminer`.
|
||||
- Treat `launcher/*.ts` and the runtime bootstrap generators as source of truth for launcher behavior. `scripts/build-launcher.ts` creates `dist/launcher`; never hand-edit those artifacts.
|
||||
|
||||
## Smells
|
||||
|
||||
|
||||
Reference in New Issue
Block a user