mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-28 06:22:45 -08:00
initial commit
This commit is contained in:
18
docs/README.md
Normal file
18
docs/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Documentation
|
||||
|
||||
Use this directory for detailed SubMiner documentation.
|
||||
|
||||
- [Installation](installation.md)
|
||||
- Platform requirements
|
||||
- AppImage / macOS / source installs
|
||||
- mpv plugin setup
|
||||
- [Usage](usage.md)
|
||||
- Script vs plugin workflow
|
||||
- Running SubMiner with mpv
|
||||
- Keybindings and runtime behavior
|
||||
- [Configuration](configuration.md)
|
||||
- Full config file reference and option details
|
||||
- [Development](development.md)
|
||||
- Contributor notes
|
||||
- Environment variables
|
||||
- License and acknowledgments
|
||||
565
docs/configuration.md
Normal file
565
docs/configuration.md
Normal file
@@ -0,0 +1,565 @@
|
||||
# Configuration
|
||||
|
||||
Settings are stored in `~/.config/SubMiner/config.jsonc`
|
||||
|
||||
### Configuration File
|
||||
|
||||
See `config.example.jsonc` for a comprehensive example configuration file with all available options, default values, and detailed comments. Only include the options you want to customize in your config file.
|
||||
|
||||
Generate a fresh default config from the centralized config registry:
|
||||
|
||||
```bash
|
||||
subminer.AppImage --generate-config
|
||||
subminer.AppImage --generate-config --config-path /tmp/subminer.jsonc
|
||||
subminer.AppImage --generate-config --backup-overwrite
|
||||
```
|
||||
|
||||
- `--generate-config` writes a default JSONC config template.
|
||||
- If the target file exists, SubMiner prompts to create a timestamped backup and overwrite.
|
||||
- In non-interactive shells, use `--backup-overwrite` to explicitly back up and overwrite.
|
||||
- `pnpm run generate:config-example` regenerates repository `config.example.jsonc` from the same centralized defaults.
|
||||
- `make generate-config` builds and runs the same default-config generator via local Electron.
|
||||
|
||||
Invalid config values are handled with warn-and-fallback behavior: SubMiner logs the bad key/value and continues with the default for that option.
|
||||
|
||||
|
||||
### Configuration Options Overview
|
||||
|
||||
The configuration file includes several main sections:
|
||||
|
||||
- [**AnkiConnect**](#ankiconnect) - Automatic Anki card creation with media
|
||||
- [**Auto-Start Overlay**](#auto-start-overlay) - Automatically show overlay on MPV connection
|
||||
- [**Visible Overlay Subtitle Binding**](#visible-overlay-subtitle-binding) - Link visible overlay toggles to MPV subtitle visibility
|
||||
- [**Auto Subtitle Sync**](#auto-subtitle-sync) - Sync current subtitle with `alass`/`ffsubsync`
|
||||
- [**Invisible Overlay**](#invisible-overlay) - Startup visibility behavior for the invisible mining layer
|
||||
- [**Jimaku**](#jimaku) - Jimaku API configuration and defaults
|
||||
- [**Keybindings**](#keybindings) - MPV command shortcuts
|
||||
- [**Runtime Option Palette**](#runtime-option-palette) - Live, session-only option toggles
|
||||
- [**Secondary Subtitles**](#secondary-subtitles) - Dual subtitle track support
|
||||
- [**Shortcuts Configuration**](#shortcuts-configuration) - Overlay keyboard shortcuts
|
||||
- [**Subtitle Position**](#subtitle-position) - Overlay vertical positioning
|
||||
- [**Subtitle Style**](#subtitle-style) - Appearance customization
|
||||
- [**Texthooker**](#texthooker) - Control browser opening behavior
|
||||
- [**WebSocket Server**](#websocket-server) - Built-in subtitle broadcasting server
|
||||
- [**YouTube Subtitle Generation**](#youtube-subtitle-generation) - Launcher defaults for yt-dlp + local whisper fallback
|
||||
|
||||
|
||||
### AnkiConnect
|
||||
|
||||
Enable automatic Anki card creation and updates with media generation:
|
||||
|
||||
```json
|
||||
{
|
||||
"ankiConnect": {
|
||||
"enabled": true,
|
||||
"url": "http://127.0.0.1:8765",
|
||||
"pollingRate": 3000,
|
||||
"deck": "Learning::Japanese",
|
||||
"fields": {
|
||||
"audio": "ExpressionAudio",
|
||||
"image": "Picture",
|
||||
"sentence": "Sentence",
|
||||
"miscInfo": "MiscInfo",
|
||||
"translation": "SelectionText"
|
||||
},
|
||||
"ai": {
|
||||
"enabled": false,
|
||||
"alwaysUseAiTranslation": false,
|
||||
"apiKey": "",
|
||||
"model": "openai/gpt-4o-mini",
|
||||
"baseUrl": "https://openrouter.ai/api",
|
||||
"targetLanguage": "English",
|
||||
"systemPrompt": "You are a translation engine. Return only the translated text with no explanations."
|
||||
},
|
||||
"media": {
|
||||
"generateAudio": true,
|
||||
"generateImage": true,
|
||||
"imageType": "static",
|
||||
"imageFormat": "jpg",
|
||||
"imageQuality": 92,
|
||||
"imageMaxWidth": 1280,
|
||||
"imageMaxHeight": 720,
|
||||
"animatedFps": 10,
|
||||
"animatedMaxWidth": 640,
|
||||
"animatedMaxHeight": 360,
|
||||
"animatedCrf": 35,
|
||||
"audioPadding": 0.5,
|
||||
"fallbackDuration": 3,
|
||||
"maxMediaDuration": 30
|
||||
},
|
||||
"behavior": {
|
||||
"autoUpdateNewCards": true,
|
||||
"overwriteAudio": true,
|
||||
"overwriteImage": true
|
||||
},
|
||||
"metadata": {
|
||||
"pattern": "[SubMiner] %f (%t)"
|
||||
},
|
||||
"isLapis": {
|
||||
"enabled": true,
|
||||
"sentenceCardModel": "Japanese sentences",
|
||||
"sentenceCardSentenceField": "Sentence",
|
||||
"sentenceCardAudioField": "SentenceAudio"
|
||||
},
|
||||
"isKiku": {
|
||||
"enabled": false,
|
||||
"fieldGrouping": "disabled",
|
||||
"deleteDuplicateInAuto": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example is intentionally compact. The option table below documents available `ankiConnect` settings and behavior.
|
||||
|
||||
**Requirements:** [AnkiConnect](https://github.com/FooSoft/anki-connect) plugin must be installed and running in Anki. ffmpeg must be installed for media generation.
|
||||
|
||||
| Option | Values | Description |
|
||||
| -------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `enabled` | `true`, `false` | Enable AnkiConnect integration (default: `false`) |
|
||||
| `url` | string (URL) | AnkiConnect API URL (default: `http://127.0.0.1:8765`) |
|
||||
| `pollingRate` | number (ms) | How often to check for new cards (default: `3000`) |
|
||||
| `deck` | string | Anki deck to monitor for new cards |
|
||||
| `fields.audio` | string | Card field for audio files (default: `ExpressionAudio`) |
|
||||
| `fields.image` | string | Card field for images (default: `Picture`) |
|
||||
| `fields.sentence` | string | Card field for sentences (default: `Sentence`) |
|
||||
| `fields.miscInfo` | string | Card field for metadata (default: `"MiscInfo"`, set to `null` to disable) |
|
||||
| `fields.translation` | string | Card field for sentence-card translation/back text (default: `SelectionText`) |
|
||||
| `ai.enabled` | `true`, `false` | Use AI translation for sentence cards. Also auto-attempted when secondary subtitle is missing. |
|
||||
| `ai.alwaysUseAiTranslation` | `true`, `false` | When `true`, always use AI translation even if secondary subtitles exist. When `false`, AI is used only when no secondary subtitle exists. |
|
||||
| `ai.apiKey` | string | API key for your OpenAI-compatible endpoint (required for translation). |
|
||||
| `ai.model` | string | Model id for your OpenAI-compatible endpoint (default: `openai/gpt-4o-mini`). |
|
||||
| `ai.baseUrl` | string (URL) | OpenAI-compatible API base URL; accepts with or without `/v1`. |
|
||||
| `ai.targetLanguage` | string | Target language name used in translation prompt (default: `English`). |
|
||||
| `ai.systemPrompt` | string | System prompt used for translation (default returns translation text only). |
|
||||
| `media.generateAudio` | `true`, `false` | Generate audio clips from video (default: `true`) |
|
||||
| `media.generateImage` | `true`, `false` | Generate image/animation screenshots (default: `true`) |
|
||||
| `media.imageType` | `"static"`, `"avif"` | Image type: static screenshot or animated AVIF (default: `"static"`) |
|
||||
| `media.imageFormat` | `"jpg"`, `"png"`, `"webp"` | Image format (default: `"jpg"`) |
|
||||
| `media.imageQuality` | number (1-100) | Image quality for JPG/WebP; PNG ignores this (default: `92`) |
|
||||
| `media.imageMaxWidth` | number (px) | Optional max width for static screenshots. Unset keeps source width. |
|
||||
| `media.imageMaxHeight` | number (px) | Optional max height for static screenshots. Unset keeps source height. |
|
||||
| `media.animatedFps` | number (1-60) | FPS for animated AVIF (default: `10`) |
|
||||
| `media.animatedMaxWidth` | number (px) | Max width for animated AVIF (default: `640`) |
|
||||
| `media.animatedMaxHeight` | number (px) | Optional max height for animated AVIF. Unset keeps source aspect-constrained height. |
|
||||
| `media.animatedCrf` | number (0-63) | CRF quality for AVIF; lower = higher quality (default: `35`) |
|
||||
| `media.audioPadding` | number (seconds) | Padding around audio clip timing (default: `0.5`) |
|
||||
| `media.fallbackDuration` | number (seconds) | Default duration if timing unavailable (default: `3.0`) |
|
||||
| `media.maxMediaDuration` | number (seconds) | Max duration for generated media from multi-line copy (default: `30`, `0` to disable) |
|
||||
| `behavior.overwriteAudio` | `true`, `false` | Replace existing audio on updates; when `false`, new audio is appended/prepended per `behavior.mediaInsertMode` (default: `true`) |
|
||||
| `behavior.overwriteImage` | `true`, `false` | Replace existing images on updates; when `false`, new images are appended/prepended per `behavior.mediaInsertMode` (default: `true`) |
|
||||
| `behavior.mediaInsertMode` | `"append"`, `"prepend"` | Where to insert new media when overwrite is off (default: `"append"`) |
|
||||
| `behavior.highlightWord` | `true`, `false` | Highlight the word in sentence context (default: `true`) |
|
||||
| `behavior.notificationType` | `"osd"`, `"system"`, `"both"`, `"none"` | Notification type on card update (default: `"osd"`) |
|
||||
| `behavior.autoUpdateNewCards` | `true`, `false` | Automatically update cards on creation (default: `true`) |
|
||||
| `metadata.pattern` | string | Format pattern for metadata: `%f`=filename, `%F`=filename+ext, `%t`=time |
|
||||
| `isLapis` | object | Lapis/shared sentence-card config: `{ enabled, sentenceCardModel, sentenceCardSentenceField, sentenceCardAudioField }` |
|
||||
| `isKiku` | object | Kiku-only config: `{ enabled, fieldGrouping, deleteDuplicateInAuto }` (shared sentence/audio/model settings are inherited from `isLapis`) |
|
||||
|
||||
**Kiku / Lapis Note Type Support:**
|
||||
|
||||
SubMiner supports the [Lapis](https://github.com/donkuri/lapis) and [Kiku](https://kiku.youyoumu.my.id/) note types. Both `isLapis.enabled` and `isKiku.enabled` can be true; Kiku takes precedence for grouping behavior, while sentence-card model/field settings come from `isLapis`.
|
||||
|
||||
When enabled, sentence cards automatically set `IsSentenceCard` to `"x"` and populate the `Expression` field. Audio cards set `IsAudioCard` to `"x"`.
|
||||
|
||||
Kiku extends Lapis with **field grouping** — when a duplicate card is detected (same Word/Expression), SubMiner merges the two cards' content into one using Kiku's `data-group-id` HTML structure, organizing each mining instance into separate pages within the note.
|
||||
|
||||
[](https://github.com/user-attachments/assets/bf2476cb-2351-4622-8143-c90e59b19213)
|
||||
|
||||
|
||||
| Mode | Behavior |
|
||||
| ---------- | -------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `auto` | Automatically merges the new card's content into the original; duplicate deletion is controlled by `deleteDuplicateInAuto` |
|
||||
| `manual` | Shows an overlay popup to choose which card to keep and whether to delete the duplicate after merge |
|
||||
| `disabled` | No field grouping; duplicate cards are left as-is |
|
||||
|
||||
`deleteDuplicateInAuto` controls whether `auto` mode deletes the duplicate after merge (default: `true`). In `manual` mode, the popup asks each time whether to delete the duplicate.
|
||||
|
||||
**Image Quality Notes:**
|
||||
|
||||
- `imageQuality` affects JPG and WebP only; PNG is lossless and ignores this setting
|
||||
- JPG quality is mapped to FFmpeg's scale (2-31, lower = better)
|
||||
- WebP quality uses FFmpeg's native 0-100 scale
|
||||
|
||||
**Manual Card Update:**
|
||||
|
||||
When `behavior.autoUpdateNewCards` is set to `false`, new cards are detected but not automatically updated. Instead, you can manually update cards using keyboard shortcuts:
|
||||
|
||||
| Shortcut | Action |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `Ctrl+C` | Copy the current subtitle line to clipboard (preserves line breaks) |
|
||||
| `Ctrl+Shift+C` | Enter multi-copy mode. Press `1-9` to copy that many recent lines, or `Esc` to cancel. Timeout: 3 seconds |
|
||||
| `Ctrl+V` | Update the last added Anki card using subtitles from clipboard |
|
||||
| `Ctrl+G` | Trigger Kiku duplicate field grouping for the last added card (only when `behavior.autoUpdateNewCards` is `false`) |
|
||||
| `Ctrl+S` | Create a sentence card from the current subtitle line |
|
||||
| `Ctrl+Shift+S` | Enter multi-mine mode. Press `1-9` to create a sentence card from that many recent lines, or `Esc` to cancel |
|
||||
| `Ctrl+Shift+V` | Cycle secondary subtitle display mode (hidden → visible → hover) |
|
||||
| `Ctrl+Shift+A` | Mark the last added Anki card as an audio card (sets IsAudioCard, SentenceAudio, Sentence, Picture) |
|
||||
| `Ctrl+Shift+O` | Open runtime options palette (session-only live toggles) |
|
||||
|
||||
To copy multiple lines (current + previous):
|
||||
|
||||
1. Press `Ctrl+Shift+C`
|
||||
2. Press a number key (`1-9`) within 3 seconds
|
||||
3. The specified number of most recent subtitle lines are copied
|
||||
4. Press `Ctrl+V` to update the last added card with the copied lines
|
||||
|
||||
These shortcuts are only active when the overlay window is visible. They are automatically disabled when the overlay is hidden to avoid interfering with normal system clipboard operations.
|
||||
|
||||
|
||||
### Auto-Start Overlay
|
||||
|
||||
Control whether the overlay automatically becomes visible when it connects to mpv:
|
||||
|
||||
```json
|
||||
{
|
||||
"auto_start_overlay": false
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| -------------------- | --------------- | ------------------------------------------------------ |
|
||||
| `auto_start_overlay` | `true`, `false` | Auto-show overlay on mpv connection (default: `false`) |
|
||||
|
||||
The mpv plugin now controls startup per layer via `auto_start_visible_overlay` and `auto_start_invisible_overlay` in `subminer.conf` (`platform-default` for invisible means hidden on Linux, visible on macOS/Windows).
|
||||
|
||||
### Visible Overlay Subtitle Binding
|
||||
|
||||
Control whether toggling the visible overlay also toggles MPV subtitle visibility:
|
||||
|
||||
```json
|
||||
{
|
||||
"bind_visible_overlay_to_mpv_sub_visibility": true
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| --------------------------------------------- | --------------- | ----------- |
|
||||
| `bind_visible_overlay_to_mpv_sub_visibility` | `true`, `false` | When `true` (default), visible overlay hides MPV primary/secondary subtitles and restores them when hidden. When `false`, visible overlay toggles do not change MPV subtitle visibility. |
|
||||
|
||||
|
||||
### Auto Subtitle Sync
|
||||
|
||||
Sync the active subtitle track using `alass` (preferred) or `ffsubsync`:
|
||||
|
||||
```json
|
||||
{
|
||||
"subsync": {
|
||||
"defaultMode": "auto",
|
||||
"alass_path": "",
|
||||
"ffsubsync_path": "",
|
||||
"ffmpeg_path": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| ---------------- | -------------------- | ----------- |
|
||||
| `defaultMode` | `"auto"`, `"manual"` | `auto`: try `alass` against secondary subtitle, then fallback to `ffsubsync`; `manual`: open overlay picker |
|
||||
| `alass_path` | string path | Path to `alass` executable. Empty or `null` falls back to `/usr/bin/alass`. |
|
||||
| `ffsubsync_path` | string path | Path to `ffsubsync` executable. Empty or `null` falls back to `/usr/bin/ffsubsync`. |
|
||||
| `ffmpeg_path` | string path | Path to `ffmpeg` (used for internal subtitle extraction). Empty or `null` falls back to `/usr/bin/ffmpeg`. |
|
||||
|
||||
Default trigger is `Ctrl+Alt+S` via `shortcuts.triggerSubsync`.
|
||||
Customize it there, or set it to `null` to disable.
|
||||
|
||||
|
||||
### Invisible Overlay
|
||||
|
||||
SubMiner includes a second subtitle mining layer that can be visually invisible while still interactive for Yomitan lookups.
|
||||
|
||||
- `invisibleOverlay.startupVisibility` values:
|
||||
1. `"platform-default"`: hidden on Wayland, visible on Windows/macOS/other sessions.
|
||||
2. `"visible"`: always shown on startup.
|
||||
3. `"hidden"`: always hidden on startup.
|
||||
|
||||
|
||||
### Jimaku
|
||||
|
||||
Configure Jimaku API access and defaults:
|
||||
|
||||
```json
|
||||
{
|
||||
"jimaku": {
|
||||
"apiKey": "YOUR_API_KEY",
|
||||
"apiKeyCommand": "cat ~/.jimaku_key",
|
||||
"apiBaseUrl": "https://jimaku.cc",
|
||||
"languagePreference": "ja",
|
||||
"maxEntryResults": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Jimaku is rate limited; if you hit a limit, SubMiner will surface the retry delay from the API response.
|
||||
|
||||
Set `openBrowser` to `false` to only print the URL without opening a browser.
|
||||
|
||||
|
||||
### Keybindings
|
||||
|
||||
Add a `keybindings` array to configure keyboard shortcuts that send commands to mpv:
|
||||
|
||||
See `config.example.jsonc` for detailed configuration options and more examples.
|
||||
|
||||
**Default keybindings:**
|
||||
|
||||
| Key | Command | Description |
|
||||
| ----------------- | -------------------------- | ------------------------------------- |
|
||||
| `Space` | `["cycle", "pause"]` | Toggle pause |
|
||||
| `ArrowRight` | `["seek", 5]` | Seek forward 5 seconds |
|
||||
| `ArrowLeft` | `["seek", -5]` | Seek backward 5 seconds |
|
||||
| `ArrowUp` | `["seek", 60]` | Seek forward 60 seconds |
|
||||
| `ArrowDown` | `["seek", -60]` | Seek backward 60 seconds |
|
||||
| `Shift+KeyH` | `["sub-seek", -1]` | Jump to previous subtitle |
|
||||
| `Shift+KeyL` | `["sub-seek", 1]` | Jump to next subtitle |
|
||||
| `Ctrl+Shift+KeyH` | `["__replay-subtitle"]` | Replay current subtitle, pause at end |
|
||||
| `Ctrl+Shift+KeyL` | `["__play-next-subtitle"]` | Play next subtitle, pause at end |
|
||||
| `KeyQ` | `["quit"]` | Quit mpv |
|
||||
| `Ctrl+KeyW` | `["quit"]` | Quit mpv |
|
||||
|
||||
**Custom keybindings example:**
|
||||
|
||||
```json
|
||||
{
|
||||
"keybindings": [
|
||||
{ "key": "ArrowRight", "command": ["seek", 5] },
|
||||
{ "key": "ArrowLeft", "command": ["seek", -5] },
|
||||
{ "key": "Shift+ArrowRight", "command": ["seek", 30] },
|
||||
{ "key": "KeyR", "command": ["script-binding", "immersive/auto-replay"] },
|
||||
{ "key": "KeyA", "command": ["script-message", "ankiconnect-add-note"] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Key format:** Use `KeyboardEvent.code` values (`Space`, `ArrowRight`, `KeyR`, etc.) with optional modifiers (`Ctrl+`, `Alt+`, `Shift+`, `Meta+`).
|
||||
|
||||
**Disable a default binding:** Set command to `null`:
|
||||
|
||||
```json
|
||||
{ "key": "Space", "command": null }
|
||||
```
|
||||
|
||||
**Special commands:** Commands prefixed with `__` are handled internally by the overlay rather than sent to mpv. `__replay-subtitle` replays the current subtitle and pauses at its end. `__play-next-subtitle` seeks to the next subtitle, plays it, and pauses at its end. `__runtime-options-open` opens the runtime options palette. `__runtime-option-cycle:<id>[:next|prev]` cycles a runtime option value.
|
||||
|
||||
**Supported commands:** Any valid mpv JSON IPC command array (`["cycle", "pause"]`, `["seek", 5]`, `["script-binding", "..."]`, etc.)
|
||||
|
||||
**See `config.example.jsonc`** for more keybinding examples and configuration options.
|
||||
|
||||
|
||||
### Runtime Option Palette
|
||||
|
||||
Use the runtime options palette to toggle settings live while SubMiner is running. These changes are session-only and reset on restart.
|
||||
|
||||
Current runtime options:
|
||||
|
||||
- `ankiConnect.behavior.autoUpdateNewCards` (`On` / `Off`)
|
||||
- `ankiConnect.isKiku.fieldGrouping` (`auto` / `manual` / `disabled`)
|
||||
|
||||
Default shortcut: `Ctrl+Shift+O`
|
||||
|
||||
Palette controls:
|
||||
|
||||
- `Arrow Up/Down`: select option
|
||||
- `Arrow Left/Right`: change selected value
|
||||
- `Enter`: apply selected value
|
||||
- `Esc`: close
|
||||
|
||||
|
||||
### Secondary Subtitles
|
||||
|
||||
Display a second subtitle track (e.g., English alongside Japanese) in the overlay:
|
||||
|
||||
See `config.example.jsonc` for detailed configuration options.
|
||||
|
||||
```json
|
||||
{
|
||||
"secondarySub": {
|
||||
"secondarySubLanguages": ["eng", "en"],
|
||||
"autoLoadSecondarySub": true,
|
||||
"defaultMode": "hover"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| 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"`) |
|
||||
|
||||
**Display modes:**
|
||||
|
||||
- **hidden** — Secondary subtitles not shown
|
||||
- **visible** — Always visible at top of overlay
|
||||
- **hover** — Only visible when hovering over the subtitle area (default)
|
||||
|
||||
**See `config.example.jsonc`** for additional secondary subtitle configuration options.
|
||||
|
||||
|
||||
### Shortcuts Configuration
|
||||
|
||||
Customize or disable the overlay keyboard shortcuts:
|
||||
|
||||
See `config.example.jsonc` for detailed configuration options.
|
||||
|
||||
```json
|
||||
{
|
||||
"shortcuts": {
|
||||
"toggleVisibleOverlayGlobal": "Alt+Shift+O",
|
||||
"toggleInvisibleOverlayGlobal": "Alt+Shift+I",
|
||||
"copySubtitle": "CommandOrControl+C",
|
||||
"copySubtitleMultiple": "CommandOrControl+Shift+C",
|
||||
"updateLastCardFromClipboard": "CommandOrControl+V",
|
||||
"triggerFieldGrouping": "CommandOrControl+G",
|
||||
"triggerSubsync": "Ctrl+Alt+S",
|
||||
"mineSentence": "CommandOrControl+S",
|
||||
"mineSentenceMultiple": "CommandOrControl+Shift+S",
|
||||
"markAudioCard": "CommandOrControl+Shift+A",
|
||||
"openRuntimeOptions": "CommandOrControl+Shift+O",
|
||||
"multiCopyTimeoutMs": 3000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| ----------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `toggleVisibleOverlayGlobal` | string \| `null` | Global accelerator for toggling visible subtitle overlay (default: `"Alt+Shift+O"`) |
|
||||
| `toggleInvisibleOverlayGlobal` | string \| `null` | Global accelerator for toggling invisible interactive overlay (default: `"Alt+Shift+I"`) |
|
||||
| `copySubtitle` | string \| `null` | Accelerator for copying current subtitle (default: `"CommandOrControl+C"`) |
|
||||
| `copySubtitleMultiple` | string \| `null` | Accelerator for multi-copy mode (default: `"CommandOrControl+Shift+C"`) |
|
||||
| `updateLastCardFromClipboard` | string \| `null` | Accelerator for updating card from clipboard (default: `"CommandOrControl+V"`) |
|
||||
| `triggerFieldGrouping` | string \| `null` | Accelerator for Kiku field grouping on last card (default: `"CommandOrControl+G"`; only active when `behavior.autoUpdateNewCards` is `false`) |
|
||||
| `triggerSubsync` | string \| `null` | Accelerator for running Subsync (default: `"Ctrl+Alt+S"`) |
|
||||
| `mineSentence` | string \| `null` | Accelerator for creating sentence card from current subtitle (default: `"CommandOrControl+S"`) |
|
||||
| `mineSentenceMultiple` | string \| `null` | Accelerator for multi-mine sentence card mode (default: `"CommandOrControl+Shift+S"`) |
|
||||
| `multiCopyTimeoutMs` | number | Timeout in ms for multi-copy/mine digit input (default: `3000`) |
|
||||
| `toggleSecondarySub` | string \| `null` | Accelerator for cycling secondary subtitle mode (default: `"CommandOrControl+Shift+V"`) |
|
||||
| `markAudioCard` | string \| `null` | Accelerator for marking last card as audio card (default: `"CommandOrControl+Shift+A"`) |
|
||||
| `openRuntimeOptions` | string \| `null` | Opens runtime options palette for live session-only toggles (default: `"CommandOrControl+Shift+O"`) |
|
||||
|
||||
**See `config.example.jsonc`** for the complete list of shortcut configuration options.
|
||||
|
||||
Set any shortcut to `null` to disable it.
|
||||
|
||||
|
||||
### Subtitle Position
|
||||
|
||||
Set the initial vertical subtitle position (measured from the bottom of the screen):
|
||||
|
||||
```json
|
||||
{
|
||||
"subtitlePosition": {
|
||||
"yPercent": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| ---------- | --------------- | ------------------------------------------------------------------ |
|
||||
| `yPercent` | number (0 - 100) | Distance from the bottom as a percent of screen height (default: `10`) |
|
||||
|
||||
|
||||
### Subtitle Style
|
||||
|
||||
Customize the appearance of primary and secondary subtitles:
|
||||
|
||||
See `config.example.jsonc` for detailed configuration options.
|
||||
|
||||
```json
|
||||
{
|
||||
"subtitleStyle": {
|
||||
"fontFamily": "Noto Sans CJK JP Regular, Noto Sans CJK JP, Arial Unicode MS, Arial, sans-serif",
|
||||
"fontSize": 35,
|
||||
"fontColor": "#cad3f5",
|
||||
"fontWeight": "normal",
|
||||
"fontStyle": "normal",
|
||||
"backgroundColor": "rgba(54, 58, 79, 0.5)",
|
||||
"secondary": {
|
||||
"fontSize": 24,
|
||||
"fontColor": "#ffffff",
|
||||
"backgroundColor": "transparent"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| ----------------- | ----------- | ----------------------------------------------------------------------------- |
|
||||
| `fontFamily` | string | CSS font-family value (default: `"Noto Sans CJK JP Regular, ..."`) |
|
||||
| `fontSize` | number (px) | Font size in pixels (default: `35`) |
|
||||
| `fontColor` | string | Any CSS color value (default: `"#cad3f5"`) |
|
||||
| `fontWeight` | string | CSS font-weight, e.g. `"bold"`, `"normal"`, `"600"` (default: `"normal"`) |
|
||||
| `fontStyle` | string | `"normal"` or `"italic"` (default: `"normal"`) |
|
||||
| `backgroundColor` | string | Any CSS color, including `"transparent"` (default: `"rgba(54, 58, 79, 0.5)"`) |
|
||||
| `secondary` | object | Override any of the above for secondary subtitles (optional) |
|
||||
|
||||
Secondary subtitle defaults: `fontSize: 24`, `fontColor: "#ffffff"`, `backgroundColor: "transparent"`. 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.
|
||||
|
||||
|
||||
### Texthooker
|
||||
|
||||
Control whether the browser opens automatically when texthooker starts:
|
||||
|
||||
See `config.example.jsonc` for detailed configuration options.
|
||||
|
||||
```json
|
||||
{
|
||||
"texthooker": {
|
||||
"openBrowser": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### WebSocket Server
|
||||
|
||||
The overlay includes a built-in WebSocket server that broadcasts subtitle text to connected clients (such as texthooker-ui) for external processing.
|
||||
|
||||
By default, the server uses "auto" mode: it starts automatically unless [mpv_websocket](https://github.com/kuroahna/mpv_websocket) is detected at `~/.config/mpv/mpv_websocket`. If you have mpv_websocket installed, the built-in server is skipped to avoid conflicts.
|
||||
|
||||
See `config.example.jsonc` for detailed configuration options.
|
||||
|
||||
```json
|
||||
{
|
||||
"websocket": {
|
||||
"enabled": "auto",
|
||||
"port": 6677
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| --------- | ------------------------- | -------------------------------------------------------- |
|
||||
| `enabled` | `true`, `false`, `"auto"` | `"auto"` (default) disables if mpv_websocket is detected |
|
||||
| `port` | number | WebSocket server port (default: 6677) |
|
||||
|
||||
|
||||
### YouTube Subtitle Generation
|
||||
|
||||
Set defaults used by the `subminer` launcher for YouTube subtitle extraction/transcription:
|
||||
|
||||
```json
|
||||
{
|
||||
"youtubeSubgen": {
|
||||
"mode": "automatic",
|
||||
"whisperBin": "/path/to/whisper-cli",
|
||||
"whisperModel": "/path/to/ggml-model.bin",
|
||||
"primarySubLanguages": ["ja", "jpn"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Values | Description |
|
||||
| -------------- | --------------------------------------- | ----------- |
|
||||
| `mode` | `"automatic"`, `"preprocess"`, `"off"` | `automatic`: play immediately and load generated subtitles in background; `preprocess`: generate before playback; `off`: disable launcher generation. |
|
||||
| `whisperBin` | string path | Path to `whisper.cpp` CLI binary used as fallback transcription engine. |
|
||||
| `whisperModel` | string path | Path to whisper model used by fallback transcription. |
|
||||
| `primarySubLanguages` | string[] | Primary subtitle language priority for YouTube subtitle generation (default `["ja", "jpn"]`). |
|
||||
|
||||
YouTube language targets are derived from subtitle config:
|
||||
- primary track: `youtubeSubgen.primarySubLanguages` (falls back to `["ja","jpn"]`)
|
||||
- secondary track: `secondarySub.secondarySubLanguages` (falls back to English when empty)
|
||||
|
||||
Precedence for launcher defaults is: CLI flag > environment variable > `config.jsonc` > built-in default.
|
||||
15
docs/development.md
Normal file
15
docs/development.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Contributor Note
|
||||
|
||||
To add or change a config option, update `src/config/definitions.ts` first. Defaults, runtime-option metadata, and generated `config.example.jsonc` are derived from this centralized source.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description |
|
||||
| ------------------------ | ---------------------------------------------- |
|
||||
| `SUBMINER_APPIMAGE_PATH` | Override AppImage location for subminer script |
|
||||
| `SUBMINER_YT_SUBGEN_MODE` | Override `youtubeSubgen.mode` for launcher |
|
||||
| `SUBMINER_WHISPER_BIN` | Override `youtubeSubgen.whisperBin` for launcher |
|
||||
| `SUBMINER_WHISPER_MODEL` | Override `youtubeSubgen.whisperModel` for launcher |
|
||||
| `SUBMINER_YT_SUBGEN_OUT_DIR` | Override generated subtitle output directory |
|
||||
| `SUBMINER_YT_SUBGEN_AUDIO_FORMAT` | Override extraction format used for whisper fallback |
|
||||
| `SUBMINER_YT_SUBGEN_KEEP_TEMP` | Set to `1` to keep temporary subtitle-generation workspace |
|
||||
246
docs/installation.md
Normal file
246
docs/installation.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# Requirements
|
||||
|
||||
### Linux
|
||||
|
||||
- **Wayland/X11 compositor** (one of the following):
|
||||
- Hyprland (uses `hyprctl`)
|
||||
- X11 (uses `xdotool` and `xwininfo`)
|
||||
- mpv (with IPC socket support)
|
||||
- mecab and mecab-ipadic (Japanese morphological analyzer)
|
||||
- fuse2 (for AppImage support)
|
||||
|
||||
### macOS
|
||||
|
||||
- macOS 10.13 or later
|
||||
- mpv (with IPC socket support)
|
||||
- mecab and mecab-ipadic (Japanese morphological analyzer) - optional
|
||||
- **Accessibility permission** required for window tracking (see [macOS Installation](#macos-installation))
|
||||
|
||||
**Optional:**
|
||||
|
||||
- fzf (terminal-based video picker, default)
|
||||
- rofi (GUI-based video picker)
|
||||
- chafa (thumbnail previews in fzf)
|
||||
- ffmpegthumbnailer (generate video thumbnails)
|
||||
- yt-dlp (recommended for reliable YouTube playback/subtitles in mpv)
|
||||
- bun (required to run the `subminer` wrapper script from source/local installs)
|
||||
|
||||
## Installation
|
||||
|
||||
### From AppImage (Recommended)
|
||||
|
||||
Download the latest AppImage from GitHub Releases:
|
||||
|
||||
```bash
|
||||
# Download and install AppImage
|
||||
wget https://github.com/sudacode/subminer/releases/download/v1.0.0/subminer-1.0.0.AppImage -O ~/.local/bin/subminer.AppImage
|
||||
chmod +x ~/.local/bin/subminer.AppImage
|
||||
|
||||
# Download subminer wrapper script
|
||||
wget https://github.com/sudacode/subminer/releases/download/v1.0.0/subminer -O ~/.local/bin/subminer
|
||||
chmod +x ~/.local/bin/subminer
|
||||
```
|
||||
|
||||
Note: the `subminer` wrapper uses a Bun shebang (`#!/usr/bin/env bun`), so `bun` must be installed and available on `PATH`.
|
||||
|
||||
### macOS Installation
|
||||
|
||||
If you download a release, use the **DMG** artifact. Open it and drag `SubMiner.app` into `/Applications`.
|
||||
If needed, you can use the **ZIP** artifact as a fallback by unzipping and dragging `SubMiner.app` into `/Applications`.
|
||||
|
||||
Install dependencies using Homebrew:
|
||||
|
||||
```bash
|
||||
brew install mpv mecab mecab-ipadic
|
||||
```
|
||||
|
||||
Build from source:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/sudacode/subminer.git
|
||||
cd subminer
|
||||
pnpm install
|
||||
cd vendor/texthooker-ui && pnpm install && pnpm build && cd ../..
|
||||
pnpm run build:mac
|
||||
```
|
||||
|
||||
The built app will be available in the `release` directory (`.dmg` and `.zip` on macOS).
|
||||
|
||||
If you are building locally without Apple signing credentials, use:
|
||||
|
||||
```bash
|
||||
pnpm run build:mac:unsigned
|
||||
```
|
||||
|
||||
You can launch `SubMiner.app` directly (double-click or `open -a SubMiner`).
|
||||
Use `--start` when you want SubMiner to begin MPV IPC connection/reconnect behavior.
|
||||
Use `--texthooker` when you only want the texthooker page (no overlay window).
|
||||
|
||||
**Accessibility Permission:**
|
||||
|
||||
After launching the app for the first time, grant accessibility permission:
|
||||
|
||||
1. Open **System Preferences** → **Security & Privacy** → **Privacy** tab
|
||||
2. Select **Accessibility** from the left sidebar
|
||||
3. Add SubMiner to the list
|
||||
|
||||
Without this permission, window tracking will not work and the overlay won't follow the MPV window.
|
||||
|
||||
<!-- ### Maintainer: macOS Release Signing/Notarization
|
||||
|
||||
The GitHub release workflow builds signed and notarized macOS artifacts on `macos-latest`.
|
||||
Set these GitHub Actions secrets before creating a release tag:
|
||||
|
||||
- `CSC_LINK` (base64 `.p12` certificate or file URL for Developer ID Application cert)
|
||||
- `CSC_KEY_PASSWORD` (password for the `.p12`)
|
||||
- `APPLE_ID` (Apple ID email)
|
||||
- `APPLE_APP_SPECIFIC_PASSWORD` (app-specific password for notarization)
|
||||
- `APPLE_TEAM_ID` (Apple Developer Team ID) -->
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/sudacode/subminer.git
|
||||
cd subminer
|
||||
make build
|
||||
|
||||
# Install platform artifacts
|
||||
# - Linux: wrapper + theme (+ AppImage if present)
|
||||
# - macOS: wrapper + theme + SubMiner.app (from release/*.app or release/*.zip)
|
||||
make install
|
||||
```
|
||||
|
||||
<!-- ### Arch Linux -->
|
||||
|
||||
<!-- ```bash -->
|
||||
<!-- # Using the PKGBUILD -->
|
||||
<!-- makepkg -si -->
|
||||
<!-- ``` -->
|
||||
|
||||
### macOS Usage Notes
|
||||
|
||||
**Launching MPV with IPC:**
|
||||
|
||||
```bash
|
||||
mpv --input-ipc-server=/tmp/subminer-socket video.mkv
|
||||
```
|
||||
|
||||
**Config Location:**
|
||||
|
||||
Settings are stored in `~/.config/SubMiner/config.jsonc` (same as Linux).
|
||||
|
||||
**MeCab Installation Paths:**
|
||||
|
||||
Common Homebrew install paths:
|
||||
|
||||
- Apple Silicon (M1/M2): `/opt/homebrew/bin/mecab`
|
||||
- Intel: `/usr/local/bin/mecab`
|
||||
|
||||
Ensure that `mecab` is available on your PATH when launching subminer (for example, by starting it from a terminal where `which mecab` works), otherwise MeCab may not be detected.
|
||||
|
||||
**Fullscreen Mode:**
|
||||
|
||||
The overlay should appear correctly in fullscreen. If you encounter issues, check that macOS accessibility permissions are granted (see [macOS Installation](#macos-installation)).
|
||||
|
||||
**mpv Plugin Binary Path (macOS):**
|
||||
|
||||
Set `binary_path` to your app binary, for example:
|
||||
|
||||
```ini
|
||||
binary_path=/Applications/SubMiner.app/Contents/MacOS/subminer
|
||||
```
|
||||
|
||||
### MPV Plugin (Optional)
|
||||
|
||||
The Lua plugin allows you to control the overlay directly from mpv using keybindings:
|
||||
|
||||
> [!IMPORTANT]
|
||||
> `mpv` must be launched with `--input-ipc-server=/tmp/subminer-socket` to allow communication with the application
|
||||
|
||||
```bash
|
||||
# Copy plugin files to mpv config
|
||||
cp plugin/subminer.lua ~/.config/mpv/scripts/
|
||||
cp plugin/subminer.conf ~/.config/mpv/script-opts/
|
||||
```
|
||||
|
||||
#### Plugin Keybindings
|
||||
|
||||
All keybindings use chord sequences starting with `y`:
|
||||
|
||||
| Keybind | Action |
|
||||
| ------- | ------------------------------------- |
|
||||
| `y-y` | Open SubMiner menu (fuzzy-searchable) |
|
||||
| `y-s` | Start overlay |
|
||||
| `y-S` | Stop overlay |
|
||||
| `y-t` | Toggle visible overlay |
|
||||
| `y-i` | Toggle invisible overlay |
|
||||
| `y-I` | Show invisible overlay |
|
||||
| `y-u` | Hide invisible overlay |
|
||||
| `y-o` | Open Yomitan settings |
|
||||
| `y-r` | Restart overlay |
|
||||
| `y-c` | Check overlay status |
|
||||
|
||||
The menu provides options to start/stop/toggle the visible or invisible overlay layers and open settings. Type to filter or use arrow keys to navigate.
|
||||
|
||||
#### Plugin Configuration
|
||||
|
||||
Edit `~/.config/mpv/script-opts/subminer.conf`:
|
||||
|
||||
```ini
|
||||
# Path to SubMiner binary (leave empty for auto-detection)
|
||||
binary_path=
|
||||
|
||||
# Path to mpv IPC socket (must match input-ipc-server in mpv.conf)
|
||||
socket_path=/tmp/subminer-socket
|
||||
|
||||
# Enable texthooker WebSocket server
|
||||
texthooker_enabled=yes
|
||||
|
||||
# Texthooker WebSocket port
|
||||
texthooker_port=5174
|
||||
|
||||
# Window manager backend: auto, hyprland, x11, macos
|
||||
backend=auto
|
||||
|
||||
# Automatically start overlay when a file is loaded
|
||||
auto_start=no
|
||||
|
||||
# Automatically show visible overlay when overlay starts
|
||||
auto_start_visible_overlay=no
|
||||
|
||||
# Automatically show invisible overlay when overlay starts
|
||||
# Values: platform-default, visible, hidden
|
||||
# platform-default => hidden on Linux, visible on macOS/Windows
|
||||
auto_start_invisible_overlay=platform-default
|
||||
|
||||
# Show OSD messages for overlay status
|
||||
osd_messages=yes
|
||||
```
|
||||
|
||||
The plugin auto-detects the binary location, searching:
|
||||
|
||||
- `/Applications/SubMiner.app/Contents/MacOS/subminer`
|
||||
- `~/Applications/SubMiner.app/Contents/MacOS/subminer`
|
||||
- `C:\Program Files\subminer\subminer.exe`
|
||||
- `C:\Program Files (x86)\subminer\subminer.exe`
|
||||
- `C:\subminer\subminer.exe`
|
||||
- `~/.local/bin/subminer.AppImage`
|
||||
- `/opt/subminer/subminer.AppImage`
|
||||
- `/usr/local/bin/subminer`
|
||||
- `/usr/bin/subminer`
|
||||
|
||||
**Windows Notes:**
|
||||
|
||||
Set the binary and socket path like this:
|
||||
|
||||
```ini
|
||||
binary_path=C:\\Program Files\\subminer\\subminer.exe
|
||||
socket_path=\\\\.\\pipe\\subminer-socket
|
||||
```
|
||||
|
||||
Launch mpv with:
|
||||
|
||||
```bash
|
||||
mpv --input-ipc-server=\\\\.\\pipe\\subminer-socket video.mkv
|
||||
```
|
||||
|
||||
131
docs/usage.md
Normal file
131
docs/usage.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# SubMiner Script vs MPV Plugin
|
||||
|
||||
There are two ways to use SubMiner:
|
||||
|
||||
| Approach | Best For |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **subminer script** | All-in-one solution. Handles video selection, launches MPV with the correct socket, starts the overlay automatically, and cleans up on exit. |
|
||||
| **MPV plugin** | When you launch MPV yourself or from other tools. Provides in-MPV chord keybindings (e.g. `y-y` for menu) to control visible and invisible overlay layers. Requires `--input-ipc-server=/tmp/subminer-socket`. |
|
||||
|
||||
You can use both together—install the plugin for on-demand control, but use `subminer` when you want the streamlined workflow.
|
||||
|
||||
`subminer` is implemented as a Bun script and runs directly via shebang (no `bun run` needed), for example: `subminer video.mkv`.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Browse and play videos
|
||||
subminer # Current directory (uses fzf)
|
||||
subminer -R # Use rofi instead of fzf
|
||||
subminer -d ~/Videos # Specific directory
|
||||
subminer -r -d ~/Anime # Recursive search
|
||||
subminer video.mkv # Play specific file
|
||||
subminer https://youtu.be/... # Play a YouTube URL
|
||||
subminer ytsearch:"jp news" # Play first YouTube search result
|
||||
|
||||
# Options
|
||||
subminer -T video.mkv # Disable texthooker server
|
||||
subminer -b x11 video.mkv # Force X11 backend
|
||||
subminer video.mkv # Uses mpv profile "subminer" by default
|
||||
subminer -p gpu-hq video.mkv # Override mpv profile
|
||||
subminer --yt-subgen-mode preprocess --whisper-bin /path/to/whisper-cli --whisper-model /path/to/model.bin https://youtu.be/... # Pre-generate subtitle tracks before playback
|
||||
|
||||
# Direct AppImage control
|
||||
subminer.AppImage --start --texthooker # Start overlay with texthooker
|
||||
subminer.AppImage --texthooker # Launch texthooker only (no overlay window)
|
||||
subminer.AppImage --stop # Stop overlay
|
||||
subminer.AppImage --start --toggle # Start MPV IPC + toggle visibility
|
||||
subminer.AppImage --start --toggle-invisible-overlay # Start MPV IPC + toggle invisible layer
|
||||
subminer.AppImage --show-visible-overlay # Force show visible overlay
|
||||
subminer.AppImage --hide-visible-overlay # Force hide visible overlay
|
||||
subminer.AppImage --show-invisible-overlay # Force show invisible overlay
|
||||
subminer.AppImage --hide-invisible-overlay # Force hide invisible overlay
|
||||
subminer.AppImage --settings # Open Yomitan settings
|
||||
subminer.AppImage --help # Show all options
|
||||
```
|
||||
|
||||
### MPV Profile Example (mpv.conf)
|
||||
|
||||
Add a profile to `~/.config/mpv/mpv.conf`; `subminer` now launches mpv with `--profile=subminer` by default (or override with `subminer -p <profile> ...`):
|
||||
|
||||
```ini
|
||||
[subminer]
|
||||
# IPC socket (must match SubMiner config)
|
||||
input-ipc-server=/tmp/subminer-socket
|
||||
|
||||
# Prefer JP subs, then EN
|
||||
slang=ja,jpn,en,eng
|
||||
|
||||
# Auto-load external subtitles
|
||||
sub-auto=fuzzy
|
||||
sub-file-paths=.;subs;subtitles
|
||||
|
||||
# Select primary + secondary subtitle tracks automatically
|
||||
sid=auto
|
||||
secondary-sid=auto
|
||||
secondary-sub-visibility=no
|
||||
```
|
||||
|
||||
`secondary-slang` is not an mpv option; use `slang` with `sid=auto` / `secondary-sid=auto` instead.
|
||||
|
||||
### YouTube Playback
|
||||
|
||||
`subminer` accepts direct URLs (for example, YouTube links) and `ytsearch:` targets, and forwards them to mpv.
|
||||
|
||||
Notes:
|
||||
|
||||
- Install `yt-dlp` so mpv can resolve YouTube streams and subtitle tracks reliably.
|
||||
- `subminer` supports three subtitle-generation modes for YouTube URLs:
|
||||
- `automatic` (default): starts playback immediately, generates subtitles in the background, and loads them into mpv when ready.
|
||||
- `preprocess`: generates subtitles first, then starts playback with generated `.srt` files attached.
|
||||
- `off`: disables launcher generation and leaves subtitle handling to mpv/yt-dlp.
|
||||
- Primary subtitle target languages come from `youtubeSubgen.primarySubLanguages` (defaults to `["ja","jpn"]`).
|
||||
- Secondary target languages come from `secondarySub.secondarySubLanguages` (defaults to English if unset).
|
||||
- `subminer` prefers subtitle tracks from yt-dlp first, then falls back to local `whisper.cpp` (`whisper-cli`) when tracks are missing.
|
||||
- Whisper translation fallback currently only supports English secondary targets; non-English secondary targets rely on yt-dlp subtitle availability.
|
||||
- Configure defaults in `~/.config/SubMiner/config.jsonc` under `youtubeSubgen` and `secondarySub`, or override mode/tool paths via CLI flags/environment variables.
|
||||
|
||||
## Keybindings
|
||||
|
||||
### Global Shortcuts
|
||||
|
||||
| Keybind | Action |
|
||||
| ------------- | ------------------------- |
|
||||
| `Alt+Shift+O` | Toggle visible overlay |
|
||||
| `Alt+Shift+I` | Toggle invisible overlay |
|
||||
| `Alt+Shift+Y` | Open Yomitan settings |
|
||||
|
||||
### Overlay Controls (Configurable)
|
||||
|
||||
| Input | Action |
|
||||
| -------------------- | -------------------------------------------------- |
|
||||
| `Space` | Toggle MPV pause |
|
||||
| `ArrowRight` | Seek forward 5 seconds |
|
||||
| `ArrowLeft` | Seek backward 5 seconds |
|
||||
| `ArrowUp` | Seek forward 60 seconds |
|
||||
| `ArrowDown` | Seek backward 60 seconds |
|
||||
| `Shift+H` | Jump to previous subtitle |
|
||||
| `Shift+L` | Jump to next subtitle |
|
||||
| `Ctrl+Shift+H` | Replay current subtitle (play to end, then pause) |
|
||||
| `Ctrl+Shift+L` | Play next subtitle (jump, play to end, then pause) |
|
||||
| `Q` | Quit mpv |
|
||||
| `Ctrl+W` | Quit mpv |
|
||||
| `Right-click` | Toggle MPV pause (outside subtitle area) |
|
||||
| `Right-click + drag` | Move subtitle position (on subtitle) |
|
||||
|
||||
These keybindings only work when the overlay window has focus. See [Configuration](configuration.md) for customization.
|
||||
|
||||
### Overlay Chord Shortcuts
|
||||
|
||||
| Chord | Action |
|
||||
| --------- | ------------------------- |
|
||||
| `y` → `j` | Open Jimaku subtitle menu |
|
||||
|
||||
## How It Works
|
||||
|
||||
1. MPV runs with an IPC socket at `/tmp/subminer-socket`
|
||||
2. The overlay connects and subscribes to subtitle changes
|
||||
3. Subtitles are tokenized with MeCab and merged into natural word boundaries
|
||||
4. Words are displayed as clickable spans
|
||||
5. Clicking a word triggers Yomitan popup for dictionary lookup
|
||||
6. Texthooker server runs at `http://127.0.0.1:5174` for external tools
|
||||
Reference in New Issue
Block a user