mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-07-30 07:21:32 -07:00
feat(stats): add sentence search tab and fix mining card behavior
- Add Search tab with realtime subtitle sentence search, media context, and mining actions - Persist library card size selection across reloads - Fix selection text written only for sentence cards, not word/audio cards - Fix word mining audio routed to SentenceAudio field when present - Fix sentence card created immediately before slow media generation completes - Fix Anki config resolved at request time for sentence mining - Prefer non-Signs/Songs tracks when auto-selecting secondary subtitle language
This commit is contained in:
+22
-22
@@ -360,7 +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"`) |
|
||||
| `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) |
|
||||
@@ -516,11 +516,11 @@ See `config.example.jsonc` for detailed configuration options.
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| ----------------------- | ---------------------------------- | ------------------------------------------------------ |
|
||||
| `secondarySubLanguages` | string[] | Language codes to auto-load (e.g., `["eng", "en"]`) |
|
||||
| `autoLoadSecondarySub` | `true`, `false` | Auto-detect and load matching secondary subtitle track |
|
||||
| `defaultMode` | `"hidden"`, `"visible"`, `"hover"` | Initial display mode (default: `"hover"`) |
|
||||
| Option | Values | Description |
|
||||
| ----------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| `secondarySubLanguages` | string[] | Language codes to auto-load (e.g., `["eng", "en"]`); non-Signs/Songs tracks are preferred when several tracks match |
|
||||
| `autoLoadSecondarySub` | `true`, `false` | Auto-detect and load matching secondary subtitle track |
|
||||
| `defaultMode` | `"hidden"`, `"visible"`, `"hover"` | Initial display mode (default: `"hover"`) |
|
||||
|
||||
The secondary-subtitle language list also acts as the fallback secondary-language priority for managed startup subtitle selection on local playback and YouTube playback.
|
||||
|
||||
@@ -1380,9 +1380,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`). |
|
||||
| `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:
|
||||
|
||||
@@ -1433,7 +1433,7 @@ Usage notes:
|
||||
- The browser UI is served at `http://127.0.0.1:<serverPort>`.
|
||||
- The overlay toggle is local to the focused visible overlay window; it is not registered as a global OS shortcut.
|
||||
- The dashboard reads from the same immersion-tracking database, so keep `immersionTracking.enabled` on if you want data to appear.
|
||||
- The UI includes Overview, Library, Trends, Vocabulary, and Sessions tabs.
|
||||
- The UI includes Overview, Library, Trends, Vocabulary, Search, and Sessions tabs.
|
||||
|
||||
### MPV Launcher
|
||||
|
||||
@@ -1456,18 +1456,18 @@ Configure the mpv executable, profile, and window state for SubMiner-managed mpv
|
||||
}
|
||||
```
|
||||
|
||||
| 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=<name>`. 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"`) |
|
||||
| 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=<name>`. 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.
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ Episode completion for local `watched` state uses the shared `DEFAULT_MIN_WATCH_
|
||||
{
|
||||
"immersionTracking": {
|
||||
"enabled": true,
|
||||
"dbPath": ""
|
||||
}
|
||||
"dbPath": "",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -70,6 +70,10 @@ Top repeated words (click a bar to open the word), new-word timeline, frequency
|
||||
|
||||

|
||||
|
||||
#### Search
|
||||
|
||||
Realtime search across tracked primary subtitle lines and media titles. Results show the source media, session, line number, timing, and sentence text. Secondary subtitle text is not shown or searched here because separate subtitle tracks may not line up sentence-for-sentence. Sentence cards can be mined from any result with a valid local source and timing. Word and audio card buttons appear only when the searched word exactly appears in the primary sentence text; matching text is highlighted in the result.
|
||||
|
||||
Stats server config lives under `stats`:
|
||||
|
||||
```jsonc
|
||||
@@ -78,8 +82,8 @@ Stats server config lives under `stats`:
|
||||
"toggleKey": "Backquote",
|
||||
"serverPort": 6969,
|
||||
"autoStartServer": true,
|
||||
"autoOpenBrowser": false
|
||||
}
|
||||
"autoOpenBrowser": false,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -96,15 +100,15 @@ Stats server config lives under `stats`:
|
||||
|
||||
## Mining Cards from the Stats Page
|
||||
|
||||
The Vocabulary tab's word detail panel shows example lines from your viewing history. Each example line with a valid source file offers three mining buttons:
|
||||
The Search tab and the Vocabulary tab's word detail panel both mine from subtitle lines in your viewing history. Each line with a valid source file offers sentence-card mining; word/audio mining is available when the selected word or searched word appears in the sentence:
|
||||
|
||||
- **Mine Word** - performs a full Yomitan dictionary lookup for the word (definition, reading, pitch accent, etc.) via a short-lived hidden helper, then enriches the card with sentence audio, a screenshot or animated AVIF clip, the highlighted sentence, and metadata extracted from the source video file. Requires Anki and Yomitan dictionaries to be loaded.
|
||||
- **Mine Sentence** - creates a sentence card directly with the `IsSentenceCard` flag set (for Lapis/Kiku workflows), along with audio, image, and translation from the secondary subtitle if available.
|
||||
- **Mine Sentence** - creates a sentence card directly with the `IsSentenceCard` flag set (for Lapis/Kiku workflows), along with audio and image from the source video.
|
||||
- **Mine Audio** - creates an audio-only card with the `IsAudioCard` flag, attaching only the sentence audio clip.
|
||||
|
||||
All three modes respect your `ankiConnect` config: deck, model, field mappings, media settings (static vs AVIF, quality, dimensions), audio padding, metadata pattern, and tags. Media generation runs in parallel for faster card creation.
|
||||
|
||||
Secondary subtitle text (typically English translations) is stored alongside primary subtitles during playback and used as the translation field when mining from the stats page.
|
||||
Secondary subtitle text (typically English translations) is stored alongside primary subtitles during playback and can be used as the translation field when mining sentence cards from Search or vocabulary occurrences. The Search tab does not use that text for display or matching.
|
||||
|
||||
### Word Exclusion List
|
||||
|
||||
@@ -114,12 +118,12 @@ The Vocabulary tab toolbar includes an **Exclusions** button for hiding words fr
|
||||
|
||||
By default, SubMiner keeps all retention tables and raw data (`0` means keep all) while continuing daily/monthly rollup maintenance:
|
||||
|
||||
| Data type | Retention |
|
||||
| -------------- | --------- |
|
||||
| Raw events | 0 (keep all) |
|
||||
| Telemetry | 0 (keep all) |
|
||||
| Sessions | 0 (keep all) |
|
||||
| Daily rollups | 0 (keep all) |
|
||||
| Data type | Retention |
|
||||
| --------------- | ------------ |
|
||||
| Raw events | 0 (keep all) |
|
||||
| Telemetry | 0 (keep all) |
|
||||
| Sessions | 0 (keep all) |
|
||||
| Daily rollups | 0 (keep all) |
|
||||
| Monthly rollups | 0 (keep all) |
|
||||
|
||||
Maintenance runs on startup and every 24 hours. Vacuum runs only when `retention.vacuumIntervalDays` is non-zero.
|
||||
@@ -146,24 +150,24 @@ The tracker is optimized for "keep everything" defaults:
|
||||
|
||||
All policy options live under `immersionTracking` in your config:
|
||||
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| `batchSize` | Writes per flush batch |
|
||||
| `flushIntervalMs` | Max delay between flushes (default: 500ms) |
|
||||
| `queueCap` | Max queued writes before oldest are dropped |
|
||||
| `payloadCapBytes` | Max payload size per write |
|
||||
| `maintenanceIntervalMs` | How often maintenance runs |
|
||||
| `retention.eventsDays` | Raw event retention |
|
||||
| `retention.telemetryDays` | Telemetry retention |
|
||||
| `retention.sessionsDays` | Session retention |
|
||||
| `retention.dailyRollupsDays` | Daily rollup retention |
|
||||
| `retention.monthlyRollupsDays` | Monthly rollup retention |
|
||||
| `retention.vacuumIntervalDays` | Minimum spacing between vacuums |
|
||||
| `retentionMode` | `preset` or `advanced` |
|
||||
| `retentionPreset` | `minimal`, `balanced`, or `deep-history` (used by `retentionMode`) |
|
||||
| `lifetimeSummaries.global` | Maintain global lifetime totals |
|
||||
| `lifetimeSummaries.anime` | Maintain per-anime lifetime totals |
|
||||
| `lifetimeSummaries.media` | Maintain per-media lifetime totals |
|
||||
| Option | Description |
|
||||
| ------------------------------ | ------------------------------------------------------------------ |
|
||||
| `batchSize` | Writes per flush batch |
|
||||
| `flushIntervalMs` | Max delay between flushes (default: 500ms) |
|
||||
| `queueCap` | Max queued writes before oldest are dropped |
|
||||
| `payloadCapBytes` | Max payload size per write |
|
||||
| `maintenanceIntervalMs` | How often maintenance runs |
|
||||
| `retention.eventsDays` | Raw event retention |
|
||||
| `retention.telemetryDays` | Telemetry retention |
|
||||
| `retention.sessionsDays` | Session retention |
|
||||
| `retention.dailyRollupsDays` | Daily rollup retention |
|
||||
| `retention.monthlyRollupsDays` | Monthly rollup retention |
|
||||
| `retention.vacuumIntervalDays` | Minimum spacing between vacuums |
|
||||
| `retentionMode` | `preset` or `advanced` |
|
||||
| `retentionPreset` | `minimal`, `balanced`, or `deep-history` (used by `retentionMode`) |
|
||||
| `lifetimeSummaries.global` | Maintain global lifetime totals |
|
||||
| `lifetimeSummaries.anime` | Maintain per-anime lifetime totals |
|
||||
| `lifetimeSummaries.media` | Maintain per-media lifetime totals |
|
||||
|
||||
## Query Templates
|
||||
|
||||
|
||||
+1
-1
@@ -287,7 +287,7 @@ Notes:
|
||||
- For YouTube URLs, `subminer` probes available YouTube subtitle tracks, reuses existing authoritative tracks when available, and downloads only missing sides.
|
||||
- Native mpv secondary subtitle rendering stays hidden so the overlay remains the visible secondary subtitle surface.
|
||||
- Primary subtitle target languages come from `youtube.primarySubLanguages` (defaults to `["ja","jpn"]`).
|
||||
- Secondary target languages come from `secondarySub.secondarySubLanguages` (empty by default; when empty, no language-based secondary track is auto-selected, though mpv's `--slang` list above still prefers English variants).
|
||||
- Secondary target languages come from `secondarySub.secondarySubLanguages` (empty by default; when empty, no language-based secondary track is auto-selected, though mpv's `--slang` list above still prefers English variants). When multiple matching secondary tracks exist, SubMiner prefers a non-Signs/Songs track.
|
||||
- Configure defaults in `$XDG_CONFIG_HOME/SubMiner/config.jsonc` (or `~/.config/SubMiner/config.jsonc`) under `youtube` and `secondarySub`.
|
||||
|
||||
For local video files, SubMiner uses the same config-driven language priorities to auto-select the primary and secondary subtitle tracks from internal and external subtitle sources.
|
||||
|
||||
Reference in New Issue
Block a user