diff --git a/docs-site/anilist-integration.md b/docs-site/anilist-integration.md index 6338c2ff..76cb111f 100644 --- a/docs-site/anilist-integration.md +++ b/docs-site/anilist-integration.md @@ -4,6 +4,8 @@ SubMiner can sync your watch progress to [AniList](https://anilist.co) automatic AniList data also powers two additional features: [cover art](#cover-art) for the stats dashboard and the [Character Dictionary](/character-dictionary) for in-overlay name lookup. +[AniList](https://anilist.co) is a free website for tracking which anime you have watched. An **access token** is a private key SubMiner stores so it can update your list on your behalf — you approve it once during setup, and you never paste a password into SubMiner. + ## Setup AniList integration is opt-in. To enable it: diff --git a/docs-site/anki-integration.md b/docs-site/anki-integration.md index a024336d..33de7fd3 100644 --- a/docs-site/anki-integration.md +++ b/docs-site/anki-integration.md @@ -3,6 +3,13 @@ SubMiner uses the [AnkiConnect](https://ankiweb.net/shared/info/2055492159) add-on to create and update Anki cards with sentence context, audio, and screenshots. This project is built primarily for [Kiku](https://kiku.youyoumu.my.id/) and [Lapis](https://github.com/donkuri/lapis) note types, including sentence-card and field-grouping behavior. +::: tip New to these terms? +- **Anki** is the flashcard app where your study cards live. +- **AnkiConnect** is a free add-on that lets other programs (like SubMiner) talk to Anki over a local connection. SubMiner needs it installed to add or edit cards. +- A **note type** (also called a "model") is the template that defines what a card looks like — for example the Kiku or Lapis templates many Japanese learners use. +- A **field** is one labeled slot in that template, such as `Sentence`, `Expression`, or `Picture`. SubMiner fills these fields when it mines a card. +::: + ## Prerequisites 1. Install [Anki](https://apps.ankiweb.net/). @@ -15,9 +22,9 @@ AnkiConnect listens on `http://127.0.0.1:8765` by default. If you changed the po When you add a word via Yomitan, SubMiner detects the new card and fills in the sentence, audio, image, and translation fields automatically. Two detection methods are available: -**Proxy mode** — SubMiner runs a local AnkiConnect-compatible proxy and intercepts card creation instantly. Recommended when possible. +**Proxy mode** (default) — SubMiner runs a local *proxy*: a small middleman server that sits between Yomitan and Anki. Yomitan sends new cards to SubMiner, SubMiner enriches them, then passes them along to Anki. This makes enrichment instant. -**Polling mode** (default) — SubMiner polls AnkiConnect every few seconds for newly added cards. Simpler setup, but with a short delay (~3 seconds). +**Polling mode** (fallback, when the proxy is disabled) — SubMiner asks AnkiConnect every few seconds whether any new cards were added, then enriches them. Simpler setup, but with a short delay (~3 seconds). Use proxy mode if you want immediate enrichment. Use polling mode if your Yomitan instance is external (browser-based) or you prefer minimal configuration. @@ -322,6 +329,7 @@ When you mine the same word multiple times, SubMiner can merge the cards instead "upstreamUrl": "http://127.0.0.1:8765", }, "fields": { + "word": "Expression", "audio": "ExpressionAudio", "image": "Picture", "sentence": "Sentence", diff --git a/docs-site/architecture.md b/docs-site/architecture.md index bb701097..8509770d 100644 --- a/docs-site/architecture.md +++ b/docs-site/architecture.md @@ -273,7 +273,7 @@ For domains migrated to reducer-style transitions (for example AniList token/que - **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. - **Startup:** If `--generate-config` is passed, it writes the template and exits. Otherwise `app-lifecycle.ts` acquires the single-instance lock and registers Electron lifecycle hooks. -- **Critical-path init:** Once `app.whenReady()` fires, `composeAppReadyRuntime()` runs strict config reload, resolves keybindings, creates the `MpvIpcClient` (which immediately connects and subscribes to 26 properties), and initializes the `RuntimeOptionsManager`, `SubtitleTimingTracker`, and `ImmersionTrackerService`. +- **Critical-path init:** Once `app.whenReady()` fires, `composeAppReadyRuntime()` runs strict config reload, resolves keybindings, creates the `MpvIpcClient` (which immediately connects and subscribes to mpv subtitle/playback properties via `observe_property`), and initializes the `RuntimeOptionsManager`, `SubtitleTimingTracker`, and `ImmersionTrackerService`. - **Overlay runtime:** `initializeOverlayRuntime()` creates the primary overlay window (interactive Yomitan lookups and subtitle rendering), registers global shortcuts, and sets up bounds tracking via the active window tracker. mpv subtitle suppression is handled by a dedicated `overlay-mpv-sub-visibility` service. - **Background warmups:** Non-critical services are launched asynchronously: MeCab tokenizer check (with async worker thread), Yomitan extension load, JLPT + frequency dictionary prewarm, optional Jellyfin remote session, Discord presence service, AniList token refresh, and optional AnkiConnect proxy server. Warmup coverage is configurable through `startupWarmups` (including low-power mode that defers all but Yomitan). - **Runtime:** Event-driven. mpv property changes, IPC messages, CLI commands, overlay shortcuts, and hot-reload notifications route through runtime handlers/composers. Subtitle text flows through `SubtitlePipeline` (normalize → tokenize → merge), and results are sent to the main overlay renderer and modal surfaces. diff --git a/docs-site/character-dictionary.md b/docs-site/character-dictionary.md index 9de139a2..b3a731a3 100644 --- a/docs-site/character-dictionary.md +++ b/docs-site/character-dictionary.md @@ -1,6 +1,8 @@ # Character Dictionary -SubMiner can build a Yomitan-compatible character dictionary from AniList metadata so that character names in subtitles are recognized, highlighted, and enrichable with context — portraits, roles, voice actors, and biographical detail — without leaving the overlay. +SubMiner can build a Yomitan-compatible character dictionary from [AniList](https://anilist.co) metadata so that character names in subtitles are recognized, highlighted, and enrichable with context — portraits, roles, voice actors, and biographical detail — without leaving the overlay. (AniList is an online anime/manga database; SubMiner pulls each show's character list from it.) + +This is helpful because proper names rarely appear in normal dictionaries, so character names would otherwise be flagged as "unknown" words and clutter your mining. Recognizing them keeps your N+1 highlighting focused on real vocabulary. The dictionary is generated per-media, merged across your recently-watched titles, and auto-imported into Yomitan. When a character name appears in a subtitle line, it gets highlighted and becomes available for hover-driven Yomitan profile lookup. diff --git a/docs-site/configuration.md b/docs-site/configuration.md index 41728451..28b378b5 100644 --- a/docs-site/configuration.md +++ b/docs-site/configuration.md @@ -8,6 +8,8 @@ outline: [2, 3] import { withBase } from 'vitepress'; +SubMiner is configured through a single file (`config.jsonc`). Most settings are also editable from the in-app **Settings** window — you rarely need to edit the file by hand. This page is the full reference: it explains the Settings window, where the config file lives, and documents every option grouped by topic. New to SubMiner? The Quick Start below plus the [Settings window](#settings) cover everything most users need. + ## Quick Start For most users, start with this minimal configuration: @@ -228,22 +230,15 @@ Control whether the overlay automatically becomes visible when it connects to mp ```json { - "auto_start_overlay": false + "auto_start_overlay": true } ``` -| Option | Values | Description | -| -------------------- | --------------- | ------------------------------------------------------ | -| `auto_start_overlay` | `true`, `false` | Auto-show overlay on mpv connection (default: `false`) | +| Option | Values | Description | +| -------------------- | --------------- | ----------------------------------------------------- | +| `auto_start_overlay` | `true`, `false` | Auto-show overlay on mpv connection (default: `true`) | -The mpv plugin controls startup overlay visibility via `auto_start_visible_overlay` in `subminer.conf`. -For wrapper-driven playback, `subminer.conf` can also enable startup pause gating with -`auto_start_pause_until_ready` (requires `auto_start=yes` + `auto_start_visible_overlay=yes`). -Current plugin defaults in `subminer.conf` are: - -- `auto_start=yes` -- `auto_start_visible_overlay=yes` -- `auto_start_pause_until_ready=yes` +When you launch through the SubMiner app or the `subminer` wrapper, the launcher reads these settings from this config and injects them into the mpv plugin at runtime — there is no separate plugin config file to edit. `auto_start_overlay` controls whether the visible overlay shows on auto-start. Two related keys in the `mpv` block tune startup behavior: `mpv.autoStartSubMiner` starts the overlay automatically when a file loads, and `mpv.pauseUntilOverlayReady` pauses mpv on visible auto-start until SubMiner signals overlay/tokenization readiness. On Windows, packaged plugin installs also rewrite the plugin socket path to `\\.\pipe\subminer-socket`. @@ -367,7 +362,7 @@ See `config.example.jsonc` for detailed configuration options. "fontColor": "#cad3f5", "backgroundColor": "transparent", "css": { - "font-family": "Inter, Noto Sans, Helvetica Neue, sans-serif", + "font-family": "Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP", "font-size": "24px", "text-shadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)" } @@ -428,7 +423,7 @@ Character-name highlighting is separate from N+1 and frequency highlighting: - `nameMatchColor` sets the highlight color for those matched character names. - Matches come from the bundled SubMiner character dictionary, including AniList-synced merged dictionaries when enabled. -Secondary subtitle defaults: `fontFamily: "Inter, Noto Sans, Helvetica Neue, sans-serif"`, `fontSize: 24`, `fontColor: "#cad3f5"`, `textShadow: "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)"`, `backgroundColor: "transparent"`, `fontWeight: "600"`. Any property not set in `secondary` falls back to the CSS defaults. +Secondary subtitle defaults: `fontFamily: "Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP"`, `fontSize: 24`, `fontColor: "#cad3f5"`, `textShadow: "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)"`, `backgroundColor: "transparent"`, `fontWeight: "600"`. Any property not set in `secondary` falls back to the CSS defaults. **See `config.example.jsonc`** for the complete list of subtitle style configuration options. @@ -445,7 +440,7 @@ Configure the parsed-subtitle sidebar modal. "toggleKey": "Backslash", "pauseVideoOnHover": true, "autoScroll": true, - "fontFamily": "\"M PLUS 1\", \"Noto Sans CJK JP\", sans-serif", + "fontFamily": "Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP", "fontSize": 16 } } @@ -483,7 +478,7 @@ For full details on layout modes, behavior, and the keyboard shortcut, see the [ | `N1` | `#ed8796` | JLPT N1 underline color | | `N2` | `#f5a97f` | JLPT N2 underline color | | `N3` | `#f9e2af` | JLPT N3 underline color | -| `N4` | `#a6e3a1` | JLPT N4 underline color | +| `N4` | `#8bd5ca` | JLPT N4 underline color | | `N5` | `#8aadf4` | JLPT N5 underline color | **Image Quality Notes:** @@ -855,8 +850,7 @@ Palette controls: ### Shared AI Provider -Shared OpenAI-compatible transport settings live at the top level under `ai`. -Anki reads this provider directly. Legacy subtitle fallback keeps the same provider shape for compatibility, then applies feature-local overrides where supported. +This is the single, shared connection to an OpenAI-compatible LLM endpoint. Configure it **once** here at the top level, and SubMiner reuses it wherever AI is needed (today: Anki translation/enrichment). Per-feature toggles and prompt/model tweaks live in their own sections (for example `ankiConnect.ai`) and inherit this transport. ```json { @@ -864,21 +858,22 @@ Anki reads this provider directly. Legacy subtitle fallback keeps the same provi "enabled": false, "apiKey": "", "apiKeyCommand": "", + "model": "openai/gpt-4o-mini", "baseUrl": "https://openrouter.ai/api", "requestTimeoutMs": 15000 } } ``` -| Option | Values | Description | -| ------------------ | -------------------- | ------------------------------------------------------------- | -| `enabled` | `true`, `false` | Enable shared AI provider features | -| `apiKey` | string | Static API key for the shared provider | -| `apiKeyCommand` | string | Shell command used to resolve the API key | -| `baseUrl` | string (URL) | OpenAI-compatible base URL | -| `model` | string | Optional model override for shared provider workflows | -| `systemPrompt` | string | Optional system prompt override for shared provider workflows | -| `requestTimeoutMs` | integer milliseconds | Shared request timeout (default: `15000`) | +| Option | Values | Description | +| ------------------ | -------------------- | ---------------------------------------------------------------------------------- | +| `enabled` | `true`, `false` | Enable shared AI provider features (default: `false`) | +| `apiKey` | string | Static API key for the shared provider | +| `apiKeyCommand` | string | Shell command used to resolve the API key (preferred over a plaintext `apiKey`) | +| `model` | string | Default model identifier requested from the provider (default: `openai/gpt-4o-mini`) | +| `baseUrl` | string (URL) | OpenAI-compatible base URL (default: `https://openrouter.ai/api`) | +| `systemPrompt` | string | Default system prompt sent with requests (default: a translation-engine prompt) | +| `requestTimeoutMs` | integer milliseconds | Shared request timeout (default: `15000`) | SubMiner uses the shared provider for: @@ -895,7 +890,7 @@ Enable automatic Anki card creation and updates with media generation: "url": "http://127.0.0.1:8765", "pollingRate": 3000, "proxy": { - "enabled": false, + "enabled": true, "host": "127.0.0.1", "port": 8766, "upstreamUrl": "http://127.0.0.1:8765" diff --git a/docs-site/demos.md b/docs-site/demos.md index ae034e5c..86dec154 100644 --- a/docs-site/demos.md +++ b/docs-site/demos.md @@ -1,6 +1,6 @@ # Feature Demos -Short recordings of SubMiner's key features and integrations from real playback sessions. +Short recordings of SubMiner's key features and integrations from real playback sessions. A few terms you'll see below: _Yomitan_ is the pop-up dictionary used for word lookups, _Jimaku_ is a community subtitle database, _alass_ and _ffsubsync_ are tools that retime subtitles to match the audio, _Jellyfin_ is a self-hosted media server, and a _texthooker_ is a web page that mirrors the current subtitle as selectable text for browser-based tools.