From efe50ed1e448df7f90f9c320f2b463cabafbfdb2 Mon Sep 17 00:00:00 2001 From: sudacode Date: Tue, 26 May 2026 23:51:36 -0700 Subject: [PATCH] docs: add startup flow diagram and document new config options (#90) --- changes/docs-startup-flow-config-options.md | 7 ++++ docs-site/architecture.md | 37 +++++++++++++++++++++ docs-site/configuration.md | 32 ++++++++++++++---- docs-site/ipc-contracts.md | 31 +++++++++++++++++ docs-site/mpv-plugin.md | 2 ++ docs-site/troubleshooting.md | 2 ++ 6 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 changes/docs-startup-flow-config-options.md diff --git a/changes/docs-startup-flow-config-options.md b/changes/docs-startup-flow-config-options.md new file mode 100644 index 00000000..b22ddaa3 --- /dev/null +++ b/changes/docs-startup-flow-config-options.md @@ -0,0 +1,7 @@ +type: changed +area: docs + +- Documented all config options that were present in `config.example.jsonc` but missing from the configuration reference: `subtitleStyle.primaryDefaultMode`, `stats.markWatchedKey`, `immersionTracking.lifetimeSummaries.*`, and all seven `mpv.*` launcher options (`socketPath`, `backend`, `autoStartSubMiner`, `pauseUntilOverlayReady`, `subminerBinaryPath`, `aniskipEnabled`, `aniskipButtonKey`). +- Added a **Playback Startup Flow** diagram to the Architecture page showing how the managed launch (`subminer` CLI, app, Windows shortcut) injects the plugin, establishes the IPC socket, and brings up the overlay via the two convergent triggers. +- Added a **Runtime Sockets** section and diagram to the IPC + Runtime Contracts page showing the mpv IPC socket and app control socket topology. +- Added cross-reference pointers in the MPV Plugin and Troubleshooting pages. diff --git a/docs-site/architecture.md b/docs-site/architecture.md index 8509770d..b4671cd4 100644 --- a/docs-site/architecture.md +++ b/docs-site/architecture.md @@ -269,6 +269,43 @@ For domains migrated to reducer-style transitions (for example AniList token/que - Reducer boundary: when a domain has transition helpers in `src/main/state.ts`, new callsites should route updates through those helpers instead of ad-hoc object mutation in `main.ts` or composers. - Tests for migrated domains should assert both the intended field changes and non-targeted field invariants. +## Playback Startup Flow + +Before the app boots, something has to launch mpv, inject the plugin, and bring the overlay up. SubMiner-managed launches own this step — the `subminer` launcher, the app's own playback, and the packaged Windows shortcut all follow the same path. The launcher reads `config.jsonc`, spawns mpv with the IPC socket and the bundled plugin, and passes runtime settings as `--script-opts`. The plugin never reads a config file: the shipped `subminer.conf` is intentionally empty so command-line opts always win. + +Once mpv is up, exactly one of two triggers brings up the overlay. On a first launch the plugin's `file-loaded` hook self-starts the app once the socket is ready (because the launcher injected `auto_start=yes`). When the app is already running — or for explicit `--start-overlay` and YouTube flows — the launcher instead attaches over the control socket and suppresses the plugin's auto-start, so the two never fire together. Both converge on the same app bring-up, which then runs the Program Lifecycle below. + +```mermaid +flowchart TB + classDef entry fill:#c6a0f6,stroke:#494d64,color:#24273a,stroke-width:2px,font-weight:bold + classDef extrt fill:#eed49f,stroke:#494d64,color:#24273a,stroke-width:1.5px + classDef decision fill:#f5a97f,stroke:#494d64,color:#24273a,stroke-width:1.5px + classDef proc fill:#8aadf4,stroke:#494d64,color:#24273a,stroke-width:1.5px + classDef app fill:#b7bdf8,stroke:#494d64,color:#24273a,stroke-width:1.5px + classDef overlay fill:#8bd5ca,stroke:#494d64,color:#24273a,stroke-width:1.5px + + Entry["Managed launch
subminer CLI · app · Windows shortcut"]:::entry + Entry --> Cfg["Launcher reads config.jsonc
→ plugin runtime config"]:::extrt + Cfg --> Spawn["Spawn mpv
--input-ipc-server=/tmp/subminer-socket
--script=plugin/subminer/main.lua
--script-opts=subminer-… (auto_start, backend, …)"]:::proc + Spawn --> Boot["Plugin boot · read_options('subminer')
empty subminer.conf; CLI opts win"]:::extrt + Boot --> Sock["mpv IPC socket ready"]:::proc + Sock --> Who{"Overlay trigger"}:::decision + + Who -->|"app already running, or
--start-overlay / YouTube"| Attach["Launcher startOverlay()
attach via control socket
plugin auto-start suppressed"]:::proc + Who -->|"first launch, auto_start=yes"| Self["Plugin file-loaded hook
polls socket → process.start_overlay()"]:::extrt + + Attach --> AppUp + Self --> AppUp + + AppUp["Spawn / attach SubMiner app
--start --managed-playback --socket … --backend …"]:::app + AppUp --> Ctrl["App control server up
/tmp/subminer-control-* dedupes a 2nd launch"]:::app + Ctrl --> Life["app.whenReady → Program Lifecycle (below)"]:::app + Life --> Conn["MpvIpcClient connects to /tmp/subminer-socket"]:::overlay + Conn --> Show["Transparent overlay over mpv
Yomitan lookup · mine"]:::overlay +``` + +The runtime sockets in this flow are detailed in [IPC + Runtime Contracts](./ipc-contracts#runtime-sockets). + ## Program Lifecycle - **Module-level init:** Before `app.ready`, the composition root registers protocols, sets platform flags, constructs all services, and wires dependency injection. `runAndApplyStartupState()` parses CLI args and detects the compositor backend. diff --git a/docs-site/configuration.md b/docs-site/configuration.md index ba5fa25c..f88d091f 100644 --- a/docs-site/configuration.md +++ b/docs-site/configuration.md @@ -360,6 +360,7 @@ See `config.example.jsonc` for detailed configuration options. | Option | Values | Description | | ---------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `primaryDefaultMode` | string | Default primary subtitle bar visibility mode: `"hidden"`, `"visible"`, or `"hover"` (default: `"visible"`) | | `subtitleStyle.css` | object | CSS declaration object applied to primary subtitles after normal style defaults. Use CSS property names such as `font-size`. | | `secondary.css` | object | CSS declaration object applied to secondary subtitles after normal secondary style defaults. | | `enableJlpt` | boolean | Enable JLPT level underline styling (`false` by default) | @@ -1377,6 +1378,9 @@ Enable or disable local immersion analytics stored in SQLite for mined subtitles | `retention.dailyRollupsDays` | integer (`0`-`36500`) | Daily rollup retention window. Default `0` (keep all). | | `retention.monthlyRollupsDays` | integer (`0`-`36500`) | Monthly rollup retention window. Default `0` (keep all). | | `retention.vacuumIntervalDays` | integer (`0`-`3650`) | Minimum spacing between `VACUUM` passes. `0` disables vacuum. Default `0` (disabled). | +| `lifetimeSummaries.global` | `true`, `false` | Maintain global lifetime stats rows (default: `true`). | +| `lifetimeSummaries.anime` | `true`, `false` | Maintain per-anime lifetime stats rows (default: `true`). | +| `lifetimeSummaries.media` | `true`, `false` | Maintain per-media lifetime stats rows (default: `true`). | You can also disable immersion tracking for a single session using: @@ -1406,6 +1410,7 @@ Configure the local stats UI served from SubMiner and the in-app stats overlay t { "stats": { "toggleKey": "Backquote", + "markWatchedKey": "KeyW", "serverPort": 6969, "autoStartServer": true, "autoOpenBrowser": false @@ -1416,6 +1421,7 @@ Configure the local stats UI served from SubMiner and the in-app stats overlay t | Option | Values | Description | | ----------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------- | | `stats.toggleKey` | Electron key code | Overlay-local key code used to toggle the stats overlay. Default `Backquote`. | +| `markWatchedKey` | Electron key code | Key code to mark the current video as watched and advance to the next playlist entry. Default `KeyW`. | | `serverPort` | integer | Localhost port for the browser stats UI. Default `6969`. | | `autoStartServer` | `true`, `false` | Start the local stats HTTP server automatically once immersion tracking is active. Default `true`. | | `autoOpenBrowser` | `true`, `false` | When `subminer stats` starts the server on demand, also open the dashboard in your default browser. Default `false`. | @@ -1435,17 +1441,31 @@ Configure the mpv executable, profile, and window state for SubMiner-managed mpv { "mpv": { "executablePath": "", + "launchMode": "normal", "profile": "", - "launchMode": "normal" + "socketPath": "\\\\.\\pipe\\subminer-socket", + "backend": "auto", + "autoStartSubMiner": true, + "pauseUntilOverlayReady": true, + "subminerBinaryPath": "", + "aniskipEnabled": true, + "aniskipButtonKey": "TAB" } } ``` -| Option | Values | Description | -| ---------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `executablePath` | string | Absolute path to `mpv.exe` for Windows launch flows. Leave empty to auto-discover from `SUBMINER_MPV_PATH` or `PATH` (default `""`) | -| `profile` | string | mpv profile name passed as `--profile=`. Leave empty to pass no profile (default `""`) | -| `launchMode` | `"normal"` \| `"maximized"` \| `"fullscreen"` | Window state when SubMiner spawns mpv (default `"normal"`) | +| Option | Values | Description | +| ----------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `executablePath` | string | Absolute path to `mpv.exe` for Windows launch flows. Leave empty to auto-discover from `SUBMINER_MPV_PATH` or `PATH` (default `""`) | +| `profile` | string | mpv profile name passed as `--profile=`. Leave empty to pass no profile (default `""`) | +| `launchMode` | `"normal"` \| `"maximized"` \| `"fullscreen"` | Window state when SubMiner spawns mpv (default `"normal"`) | +| `socketPath` | string | mpv IPC socket path used by SubMiner-managed playback and the bundled mpv plugin (default: `\\\\.\\pipe\\subminer-socket`) | +| `backend` | `"auto"` \| `"hyprland"` \| `"sway"` \| `"x11"` \| `"macos"` \| `"windows"` | Window tracking backend passed to the bundled mpv plugin. Auto detects the current platform (default: `"auto"`) | +| `autoStartSubMiner` | `true`, `false` | Start SubMiner in the background when SubMiner-managed mpv loads a file (default: `true`) | +| `pauseUntilOverlayReady`| `true`, `false` | Pause mpv on visible-overlay auto-start until SubMiner signals subtitle tokenization readiness (default: `true`) | +| `subminerBinaryPath` | string | SubMiner app binary path passed to the bundled mpv plugin. Leave empty to use the launcher-detected app path (default: `""`) | +| `aniskipEnabled` | `true`, `false` | Enable AniSkip intro detection and skip markers in the bundled mpv plugin (default: `true`) | +| `aniskipButtonKey` | string | mpv key used to trigger the AniSkip button while the skip marker is visible (default: `"TAB"`) | If `mpv.profile` is configured and the launcher also receives `--profile`, SubMiner passes both as a comma-separated mpv profile list. diff --git a/docs-site/ipc-contracts.md b/docs-site/ipc-contracts.md index 28039bf3..4bf45352 100644 --- a/docs-site/ipc-contracts.md +++ b/docs-site/ipc-contracts.md @@ -36,6 +36,37 @@ flowchart TB style E fill:#ed8796,stroke:#494d64,color:#24273a,stroke-width:1.5px ``` +## Runtime Sockets + +The renderer↔main bridge above lives *inside* the Electron app. A separate set of OS sockets connects the app to the other runtimes — mpv and the launcher/plugin. These carry no renderer payloads and bypass the contract/validator layer; they are command and property channels between processes. + +- **mpv IPC socket** (`/tmp/subminer-socket`, or `\\.\pipe\subminer-socket` on Windows): the `MpvIpcClient` in the main process connects here to send JSON commands and subscribe to playback/subtitle properties via `observe_property`. Created by mpv's `--input-ipc-server`. +- **App control socket** (`/tmp/subminer-control--.sock`, or a named pipe on Windows): the launcher and the mpv plugin send CLI-style commands (`--start`, `--show-visible-overlay`, `--texthooker`) to a running app here. It also dedupes a second `subminer` invocation into the existing instance instead of launching twice. + +```mermaid +flowchart LR + classDef extrt fill:#eed49f,stroke:#494d64,color:#24273a,stroke-width:1.5px + classDef app fill:#b7bdf8,stroke:#494d64,color:#24273a,stroke-width:1.5px + classDef ext fill:#a6da95,stroke:#494d64,color:#24273a,stroke-width:1.5px + + subgraph MpvProc["mpv process"] + direction TB + Mpv["mpv core"]:::ext + Plugin["SubMiner plugin (Lua)"]:::extrt + end + + Launcher["Launcher CLI"]:::extrt + App["SubMiner app (Electron main)"]:::app + + App <-->|"mpv IPC socket · /tmp/subminer-socket
JSON commands + property observe"| Mpv + Launcher -->|"app control socket · /tmp/subminer-control-*
--start, --show-visible-overlay, …"| App + Plugin -->|"app control socket
spawn / attach"| App + + style MpvProc fill:#363a4f,stroke:#494d64,color:#cad3f5 +``` + +How these sockets are established during launch is covered in [Playback Startup Flow](./architecture#playback-startup-flow). + ## Core Surfaces | File | Role | diff --git a/docs-site/mpv-plugin.md b/docs-site/mpv-plugin.md index a73348ea..532b38f5 100644 --- a/docs-site/mpv-plugin.md +++ b/docs-site/mpv-plugin.md @@ -163,6 +163,8 @@ script-message subminer-start backend=hyprland socket=/custom/path texthooker=no ## Lifecycle +For how the plugin's auto-start fits into the full launch sequence — including when the launcher starts the overlay instead of the plugin — see [Playback Startup Flow](./architecture#playback-startup-flow). + - **File loaded**: If `auto_start=yes`, the plugin starts the overlay, then defers AniSkip lookup until after startup delay. - **Auto-start pause gate**: If `auto_start_visible_overlay=yes` and `auto_start_pause_until_ready=yes`, launcher starts mpv paused and the plugin resumes playback after SubMiner reports tokenization-ready (with timeout fallback). - **Duplicate auto-start events**: Repeated `file-loaded` hooks while overlay is already running are ignored for auto-start triggers (prevents duplicate start attempts). diff --git a/docs-site/troubleshooting.md b/docs-site/troubleshooting.md index 0cd58aa5..10f06e6f 100644 --- a/docs-site/troubleshooting.md +++ b/docs-site/troubleshooting.md @@ -14,6 +14,8 @@ SubMiner connects to mpv via a Unix socket (or named pipe on Windows). If the so SubMiner retries the connection automatically with increasing delays (200 ms, 500 ms, 1 s, 2 s on first connect; 1 s, 2 s, 5 s, 10 s on reconnect). If mpv exits and restarts, the overlay reconnects without needing a restart. +If the overlay never appears at all, see [Playback Startup Flow](./architecture#playback-startup-flow) for how a managed launch starts mpv and brings up the overlay. + ## Logging and App Mode - Default log output is `info`.