# Conflicts: # docs-site/anki-integration.md # docs-site/immersion-tracking.md # docs-site/shortcuts.md # docs-site/usage.md
52 KiB
outline
| outline | ||
|---|---|---|
|
Configuration
<script setup> import { withBase } from 'vitepress'; </script>All SubMiner settings live in one file, config.jsonc. Most of them are also editable in the Settings window, so you rarely need to edit the file by hand. This page lists every config block with its keys and defaults.
Config file
| Platform | Path |
|---|---|
| Linux, macOS | $XDG_CONFIG_HOME/SubMiner/config.jsonc (~/.config/SubMiner/config.jsonc if unset) |
| Windows | %APPDATA%\SubMiner\config.jsonc |
The file is JSONC, so comments and trailing commas are allowed. If both config.jsonc and config.json exist, SubMiner uses config.jsonc. Only add the keys you want to change. Everything else uses the built-in default.
The generated example config lists every option with its default and a comment. Defaults in the tables below come from that file.
::: warning mpv.socketPath differs on Windows
The example shows "socketPath": "/tmp/subminer-socket". On Windows the default is \\.\pipe\subminer-socket. Leave mpv.socketPath out of your config unless you need a custom path, and SubMiner picks the right one.
:::
To write a fresh default config:
SubMiner.AppImage --generate-config
SubMiner.AppImage --generate-config --config-path /tmp/subminer.jsonc
SubMiner.AppImage --generate-config --backup-overwrite
If the target file exists, SubMiner asks before backing it up and overwriting it. In non-interactive shells, pass --backup-overwrite.
A syntax error in the file stops startup with a message that names the file. A valid file with a bad value logs a warning and uses the default for that key. On macOS, these warnings also open a dialog.
Settings window
Open it from the tray menu, with subminer settings, or with the app's --settings flag. Options are grouped by task (Appearance, Behavior, Mining & Anki, Input, Integrations, Tracking & App, Advanced) rather than by config block, but each field saves to its normal config.jsonc path.
- Saving keeps your comments, trailing commas, and unrelated keys. Resetting a field removes its key so the default applies.
- Each field is tagged Live or Restart. After saving, a banner lists any sections that need a restart.
- Anki fields can fetch deck, note type, and field names from AnkiConnect.
- Secret fields never show the stored value, only whether one is set. Prefer the
*Commandvariants (such asjimaku.apiKeyCommand) to keep keys out of the file.
Hot-reload
SubMiner watches the config file while running. When it changes, live settings apply immediately and SubMiner shows a notification listing any changed sections that need a restart. If the new file is invalid, the previous config stays active.
These apply live:
subtitleStyle,subtitleSidebar,subtitleSelection,keybindings,shortcutslogging.level,logging.rotation,logging.filessecondarySub.defaultMode,youtube.primarySubLanguagesmpv.aniskipEnabled,mpv.aniskipButtonKey,stats.toggleKey,stats.markWatchedKeyankiConnect.deck,ankiConnect.fields.*,ankiConnect.behavior.autoUpdateNewCardsankiConnect.media.normalizeAudio,media.mirrorMpvVolume,media.reviewTimingankiConnect.knownWords(highlightEnabled,refreshMinutes,addMinedWordsImmediately,matchMode,decks) andankiConnect.nPlusOne.*ankiConnect.isLapis.sentenceCardModel,isKiku.fieldGrouping,isSenren.fieldGrouping,lapisKiku.wordCardKind
These are read at the start of the next operation, so changes take effect on the next request or run: jimaku, tmdb, subsync, subtitleGeneration, notifications.
Everything else needs a restart.
Core settings
Dictionary backend
dictionaryBackend accepts "yomitan" or "hachidori". The default is defined in the generated configuration example. Restart SubMiner after changing it. The tray shows the selected backend's settings, and the global dictionary-settings shortcut follows the same selection.
Each backend stores its own dictionaries and mining settings. yomitan.externalProfilePath applies only to Yomitan. See Hachidori setup before switching an existing installation.
hachidori.externalHostManagementUrl specifies the linked Docker host's HTTP(S) management origin for automatic character dictionary uploads and replacement. Use the management port, not the sharing or dictionary API port. See Hachidori setup for an example and the generated configuration example for the default.
Logging
Log files are named by date (app-YYYY-MM-DD.log, launcher-..., mpv-...). Log export writes a sanitized copy and leaves the originals alone.
| Key | Default | What it does |
|---|---|---|
logging.level |
"warn" |
Minimum level: debug, info, warn, error |
logging.rotation |
7 |
Days of logs to keep |
logging.files.app |
true |
Write app logs |
logging.files.launcher |
true |
Write launcher logs |
logging.files.mpv |
false |
Write mpv logs. Turn on temporarily to debug mpv/plugin |
Updates
Manual checks from the tray or subminer -u always work, even with automatic checks off. Overlay update notifications include an Update button.
| Key | Default | What it does |
|---|---|---|
updates.enabled |
true |
Check for updates in the background |
updates.checkIntervalHours |
24 |
Minimum hours between automatic checks |
updates.notificationType |
"overlay" |
overlay, system, both (overlay + system), or none |
updates.channel |
"stable" |
stable or prerelease (betas and release candidates) |
Notifications
Overlay notifications are also kept in a session-only history panel. Toggle it with shortcuts.toggleNotificationHistory. The panel opens from the same side as the notification cards.
| Key | Default | What it does |
|---|---|---|
notifications.overlayPosition |
"top-right" |
Where overlay cards appear: top-left, top, top-right |
Mining and startup status notifications use ankiConnect.behavior.notificationType (see AnkiConnect).
Auto-start overlay
When mpv is started by SubMiner or the subminer launcher, the launcher passes these settings to the bundled mpv plugin. There is no separate plugin config file. mpv.autoStartSubMiner and mpv.pauseUntilOverlayReady (see MPV launcher) control the background start and the initial pause.
| Key | Default | What it does |
|---|---|---|
auto_start_overlay |
true |
Show the visible overlay when the mpv plugin starts SubMiner |
Startup warmups
Warmups load components in the background at startup. Turn one off to load it on first use instead.
| Key | Default | What it does |
|---|---|---|
startupWarmups.lowPowerMode |
false |
Defer every warmup except the Yomitan extension |
startupWarmups.mecab |
true |
Load the MeCab tokenizer |
startupWarmups.yomitanExtension |
true |
Load the Yomitan extension |
startupWarmups.subtitleDictionaries |
true |
Load the JLPT and frequency dictionaries |
startupWarmups.jellyfinRemoteSession |
false |
Connect the Jellyfin remote session (also needs Jellyfin remote auto-connect) |
WebSocket server
Broadcasts plain subtitle text to external clients. See WebSocket / Texthooker API for payloads and client examples.
| Key | Default | What it does |
|---|---|---|
websocket.enabled |
false |
true, false, or "auto" (start unless the mpv_websocket plugin is installed) |
websocket.port |
6677 |
Server port |
Annotation WebSocket
A separate stream that adds token data (known word, N+1, frequency, JLPT, character names) to each subtitle. The bundled texthooker uses it.
| Key | Default | What it does |
|---|---|---|
annotationWebsocket.enabled |
false |
Start the annotated stream (independent of websocket) |
annotationWebsocket.port |
6678 |
Server port |
Texthooker
| Key | Default | What it does |
|---|---|---|
texthooker.launchAtStartup |
false |
Start the texthooker server when SubMiner starts |
texthooker.openBrowser |
false |
Open the texthooker page in your browser when it starts |
Subtitle display
Subtitle style
Controls how primary and secondary subtitles look and which annotations they show. css and secondary.css take CSS declarations with normal property names. See Subtitle annotations for how known-word, N+1, frequency, JLPT, and character-name highlighting work.
{
"subtitleStyle": {
"css": { "font-size": "40px", "color": "#ffffff" },
"secondary": { "css": { "font-size": "24px" } },
},
}
| Key | Default | What it does |
|---|---|---|
subtitleStyle.primaryDefaultMode |
"visible" |
Primary bar at startup: hidden, visible, or hover |
subtitleStyle.css |
see example | CSS for primary subtitles (font, size 35px, color, shadow, and so on) |
subtitleStyle.secondary.css |
see example | CSS for secondary subtitles (size 24px) |
subtitleStyle.preserveLineBreaks |
false |
Keep line breaks as mpv shows them instead of one line |
subtitleStyle.autoPauseVideoOnHover |
true |
Pause while the mouse is over subtitle text |
subtitleStyle.autoPauseVideoOnYomitanPopup |
true |
Pause while a Yomitan popup is open |
subtitleStyle.primaryVisibleOnYomitanPopup |
true |
In hover mode, keep the primary bar visible while a popup is open |
subtitleStyle.knownWordColor |
#a6da95 |
Known-word highlight color |
subtitleStyle.knownWordMaturityColors |
see example | new, learning, young, mature colors, used when ankiConnect.knownWords.maturityEnabled is on |
subtitleStyle.nPlusOneColor |
#c6a0f6 |
N+1 target word color |
subtitleStyle.enableJlpt |
false |
Underline words by JLPT level |
subtitleStyle.jlptColors |
see example | Underline colors for N1 to N5 |
subtitleStyle.nameMatchEnabled |
false |
Sync the character dictionary and color character names |
subtitleStyle.nameMatchImagesEnabled |
false |
Show small character portraits next to matched names |
subtitleStyle.nameMatchColor |
#f5bde6 |
Character-name color |
subtitleStyle.frequencyDictionary.enabled |
false |
Color words by frequency rank |
subtitleStyle.frequencyDictionary.sourcePath |
"" |
Folder with term_meta_bank_*.json files. Empty searches the default locations |
subtitleStyle.frequencyDictionary.topX |
10000 |
Only color words ranked at or below this |
subtitleStyle.frequencyDictionary.mode |
"single" |
single (one color) or banded (five colors, common to rare) |
subtitleStyle.frequencyDictionary.matchMode |
"headword" |
Look up by headword (dictionary form) or surface (text as shown) |
subtitleStyle.frequencyDictionary.singleColor |
#f5a97f |
Color for single mode |
subtitleStyle.frequencyDictionary.bandedColors |
see example | Five colors for banded mode |
Two CSS custom properties style the hovered word: --subtitle-hover-token-color (#f4dbd6) and --subtitle-hover-token-background-color (transparent). Set them inside subtitleStyle.css.
Subtitle sidebar
A scrollable cue list for the current subtitle file. It only works when SubMiner could parse the active subtitle into cues. See Subtitle sidebar.
| Key | Default | What it does |
|---|---|---|
subtitleSidebar.enabled |
true |
Enable the sidebar |
subtitleSidebar.autoOpen |
false |
Open it once when the overlay starts |
subtitleSidebar.layout |
"overlay" |
overlay floats over mpv. embedded reserves space on the right of the video |
subtitleSidebar.toggleKey |
"Backslash" |
KeyboardEvent.code that opens and closes it |
subtitleSidebar.pauseVideoOnHover |
true |
Pause while hovering the cue list |
subtitleSidebar.autoScroll |
true |
Keep the active cue in view |
subtitleSidebar.css |
see example | CSS for the sidebar, plus the custom properties below |
Sidebar custom properties: --subtitle-sidebar-max-width (420px), --subtitle-sidebar-timestamp-color, --subtitle-sidebar-active-line-color, --subtitle-sidebar-active-background-color, --subtitle-sidebar-hover-background-color. Their defaults are in the example config.
If embedded layout places the video oddly on your system, switch back to overlay.
Subtitle position
You can also drag subtitles with Right-click + drag while watching.
| Key | Default | What it does |
|---|---|---|
subtitlePosition.yPercent |
10 |
Starting distance from the bottom, as a percent of screen height |
Secondary subtitles
Shows a second track, such as English, above the Japanese line.
Secondary subtitles do not auto-load by default (autoLoadSecondarySub, default: false). To load them for local and Jellyfin playback, turn it on and list the languages you want:
{
"secondarySub": {
"secondarySubLanguages": ["eng", "en"],
"autoLoadSecondarySub": true
}
}
| Key | Default | What it does |
|---|---|---|
secondarySub.secondarySubLanguages |
[] |
Language codes in priority order. Regular tracks win over Signs/Songs tracks |
secondarySub.autoLoadSecondarySub |
false |
Load a matching secondary track when the primary loads |
secondarySub.defaultMode |
"hover" |
hidden, visible (always shown), or hover (shown when you hover the subtitle area) |
YouTube ignores the first two keys and always picks English. See YouTube integration. defaultMode applies everywhere.
Subtitle selection
Adds a modal for choosing mpv's primary and secondary subtitle tracks. Open it with g then s (shortcuts.openSubtitleSelection). While enabled, that shortcut replaces mpv's own binding for the same key. See Keyboard shortcuts for sequence conflicts.
| Key | Default | What it does |
|---|---|---|
subtitleSelection.enabled |
false |
Enable the subtitle selection modal |
Keyboard and controls
Keybindings
keybindings maps keys to mpv commands or SubMiner actions. Your entries merge with the defaults. The full default list is on Keyboard shortcuts.
{
"keybindings": [
{ "key": "Shift+ArrowRight", "command": ["seek", 30] },
{ "key": "MBTN_BACK", "command": ["sub-seek", -1] },
{ "key": "Space", "command": null }
]
}
keyusesKeyboardEvent.codenames (Space,KeyR,ArrowRight) with optionalCtrl+,Alt+,Shift+,Meta+. Mouse buttons areMBTN_LEFT,MBTN_MID,MBTN_RIGHT,MBTN_BACK,MBTN_FORWARD.commandis any mpv JSON IPC command array. Set it tonullto disable a default.- Commands starting with
__run inside SubMiner:__playlist-browser-open,__youtube-picker-open,__replay-subtitle,__play-next-subtitle,__runtime-options-open, and__runtime-option-cycle:<id>[:next|prev]. - Unused single-key bindings from your mpv config also work in the overlay. Your SubMiner bindings win on conflicts.
Shortcuts configuration
shortcuts holds SubMiner's own actions (mining, copying, opening modals). Values are Electron accelerator strings such as "CommandOrControl+S". Set one to null to disable it. Keyboard shortcuts lists every key, its default, and what it does. Anki shortcuts only run when ankiConnect.enabled is on.
| Key | Default | What it does |
|---|---|---|
shortcuts.multiCopyTimeoutMs |
3000 |
How long multi-copy and multi-mine wait for a digit (ms) |
Controller support
Gamepad input for the overlay, through the browser Gamepad API. It only works while keyboard-only mode is on. Use the Alt+C modal to pick a controller and learn bindings, and Alt+Shift+C to see raw button and axis values. Default button actions are on Keyboard shortcuts.
| Key | Default | What it does |
|---|---|---|
controller.enabled |
false |
Enable controller support. The Alt+C and Alt+Shift+C modals stay closed while off |
controller.smoothScroll |
true |
Smooth popup scrolling |
controller.scrollPixelsPerSecond |
900 |
Popup scroll speed |
controller.horizontalJumpPixels |
160 |
Popup page-jump distance |
controller.stickDeadzone |
0.2 |
Stick deadzone |
controller.triggerInputMode |
"auto" |
auto, digital, or analog. Use analog if your L2/R2 report analog values |
controller.triggerDeadzone |
0.5 |
Trigger threshold for auto and analog |
controller.repeatDelayMs |
320 |
Delay before a held button repeats |
controller.repeatIntervalMs |
120 |
Repeat interval for held buttons |
Bindings are set with Alt+C learn mode, which saves them per controller.
Anki integration
AnkiConnect
Creates and updates Anki cards with sentence, audio, and screenshot. Needs the AnkiConnect add-on and ffmpeg. See Anki integration for setup, the proxy, and media options in detail.
{
"ankiConnect": {
"deck": "Mining",
"fields": { "audio": "SentenceAudio", "image": "Picture" },
"knownWords": { "highlightEnabled": true, "decks": { "Mining": ["Expression"] } }
}
}
Connection
| Key | Default | What it does |
|---|---|---|
ankiConnect.enabled |
true |
Enable Anki integration |
ankiConnect.url |
"http://127.0.0.1:8765" |
AnkiConnect URL |
ankiConnect.pollingRate |
3000 |
Milliseconds between checks for new cards (polling mode) |
ankiConnect.proxy.enabled |
true |
Run a local AnkiConnect proxy so cards added through it are updated right away |
ankiConnect.proxy.host |
"127.0.0.1" |
Proxy bind host |
ankiConnect.proxy.port |
8766 |
Proxy bind port |
ankiConnect.proxy.upstreamUrl |
"http://127.0.0.1:8765" |
Where the proxy forwards requests |
ankiConnect.tags |
["SubMiner"] |
Tags added to mined and updated cards. [] disables |
ankiConnect.deck |
"" |
Deck for duplicate checks and enrichment. Empty uses Yomitan's mining deck |
Fields
| Key | Default | What it does |
|---|---|---|
ankiConnect.fields.word |
"Expression" |
Word field |
ankiConnect.fields.audio |
"ExpressionAudio" |
Field that receives sentence audio. Set a separate field such as SentenceAudio so it does not overwrite Yomitan's word audio |
ankiConnect.fields.wordAudio |
"ExpressionAudio" |
Existing word-audio field, read only to time animated images |
ankiConnect.fields.image |
"Picture" |
Screenshot field |
ankiConnect.fields.sentence |
"Sentence" |
Sentence field |
ankiConnect.fields.miscInfo |
"MiscInfo" |
Metadata field. null disables |
ankiConnect.metadata.pattern |
"[SubMiner] %f (%t)" |
MiscInfo template: %f filename, %F filename with extension, %t time, %T time with ms, <br> newline |
Media
| Key | Default | What it does |
|---|---|---|
ankiConnect.media.generateAudio |
true |
Cut a sentence audio clip |
ankiConnect.media.generateImage |
true |
Capture a screenshot or animation |
ankiConnect.media.imageType |
"static" |
static or avif (animated) |
ankiConnect.media.imageFormat |
"jpg" |
Static format: jpg, png, webp |
ankiConnect.media.imageQuality |
92 |
JPG/WebP quality. PNG ignores it |
ankiConnect.media.imageMaxWidth |
0 |
Max static width in px. 0 keeps the source size |
ankiConnect.media.imageMaxHeight |
0 |
Max static height in px. 0 keeps the source size |
ankiConnect.media.animatedFps |
10 |
AVIF frame rate |
ankiConnect.media.animatedMaxWidth |
640 |
AVIF max width |
ankiConnect.media.animatedMaxHeight |
0 |
AVIF max height. 0 keeps the aspect ratio |
ankiConnect.media.animatedCrf |
35 |
AVIF quality. Lower is better and larger |
ankiConnect.media.syncAnimatedImageToWordAudio |
true |
Hold the first AVIF frame for the length of the word audio |
ankiConnect.media.normalizeAudio |
true |
Normalize clip loudness |
ankiConnect.media.mirrorMpvVolume |
true |
Apply mpv's current volume to the clip |
ankiConnect.media.reviewTiming |
false |
Pause and let you adjust clip timing before media is created |
ankiConnect.media.audioPadding |
0 |
Seconds added to both ends of audio and AVIF clips |
ankiConnect.media.fallbackDuration |
3 |
Clip length in seconds when subtitle timing is missing |
ankiConnect.media.maxMediaDuration |
30 |
Longest allowed clip in seconds. 0 removes the cap |
Behavior
| Key | Default | What it does |
|---|---|---|
ankiConnect.behavior.autoUpdateNewCards |
true |
Fill new cards automatically. When off, use the manual shortcuts |
ankiConnect.behavior.overwriteAudio |
true |
Replace existing audio. When off, add alongside it |
ankiConnect.behavior.overwriteImage |
true |
Replace existing images. When off, add alongside them |
ankiConnect.behavior.mediaInsertMode |
"append" |
append or prepend when not overwriting |
ankiConnect.behavior.highlightWord |
true |
Bold the mined word in the sentence field |
ankiConnect.behavior.notificationType |
"overlay" |
Where mining and status messages go: overlay, system, both, none |
Known words and N+1
| Key | Default | What it does |
|---|---|---|
ankiConnect.knownWords.highlightEnabled |
false |
Highlight words that already exist in your Anki decks |
ankiConnect.knownWords.decks |
{} |
Decks and word fields to read, for example { "Kaishi 1.5k": ["Word"] } |
ankiConnect.knownWords.matchMode |
"headword" |
Match by headword or surface text |
ankiConnect.knownWords.refreshMinutes |
1440 |
Minutes between cache refreshes |
ankiConnect.knownWords.addMinedWordsImmediately |
true |
Add newly mined words to the cache right away |
ankiConnect.knownWords.maturityEnabled |
false |
Color known words by card maturity using subtitleStyle.knownWordMaturityColors |
ankiConnect.knownWords.matureThresholdDays |
21 |
Interval in days at which a card counts as mature |
ankiConnect.nPlusOne.enabled |
false |
Highlight the only unknown word in a sentence. Needs known-word data |
ankiConnect.nPlusOne.minSentenceWords |
3 |
Minimum words in a sentence before N+1 applies |
Use word fields such as Expression or Word in knownWords.decks, not reading fields. See Subtitle annotations for how matching and maturity tiers work.
Kiku/Lapis integration
Note-type behavior for Lapis, Kiku, and Senren. With both Lapis and Kiku on, Kiku handles duplicates and the sentence-card model comes from isLapis. Kiku and Senren are mutually exclusive. If both are on, Kiku wins and SubMiner logs a warning. See Anki integration for details.
| Key | Default | What it does |
|---|---|---|
ankiConnect.isLapis.enabled |
false |
Mine dedicated sentence cards (IsSentenceCard) |
ankiConnect.isLapis.sentenceCardModel |
"Lapis" |
Note type used for sentence cards |
ankiConnect.isKiku.enabled |
false |
Merge duplicate word cards |
ankiConnect.isKiku.fieldGrouping |
"disabled" |
auto, manual, or disabled. See below |
ankiConnect.isKiku.deleteDuplicateInAuto |
true |
Delete the duplicate after an auto merge |
ankiConnect.isSenren.enabled |
false |
Merge duplicates using Senren's scene-switching format |
ankiConnect.isSenren.fieldGrouping |
"auto" |
auto, manual, or disabled |
ankiConnect.isSenren.deleteDuplicateInAuto |
true |
Delete the duplicate after an auto merge |
ankiConnect.lapisKiku.wordCardKind |
"word-and-sentence" |
Card-type flag set on word cards. See below |
Word card type
When SubMiner fills the sentence on a word card, it sets one card-type flag and clears the others. Only applies while isLapis or isKiku is on. Cards from Mine Sentence and Mine Audio keep their own flag.
wordCardKind |
Flag set |
|---|---|
word-and-sentence (default) |
IsWordAndSentenceCard |
click |
IsClickCard |
sentence |
IsSentenceCard |
audio |
IsAudioCard |
none |
none, flags left as-is |
Field grouping modes
| Mode | What happens when you mine a duplicate |
|---|---|
auto |
Merges the new card into the existing one. deleteDuplicateInAuto decides whether the new card is deleted |
manual |
Pauses playback and opens a dialog to choose which card to keep and whether to delete the other |
disabled |
Leaves both cards as they are |
External integrations
Jimaku
Search and download Japanese subtitles from Jimaku. See Jimaku integration.
| Key | Default | What it does |
|---|---|---|
jimaku.apiKey |
"" |
API key. Optional, but raises your rate limit |
jimaku.apiKeyCommand |
"" |
Shell command that prints the key. Use instead of apiKey |
jimaku.apiBaseUrl |
"https://jimaku.cc" |
API base URL |
jimaku.languagePreference |
"ja" |
Preferred language: ja, en, or none |
jimaku.maxEntryResults |
10 |
Maximum search results |
TsukiHime
Subtitle search that needs no account or key. It does need xz on your PATH. The shortcut is shortcuts.openTsukihime. See TsukiHime integration.
| Key | Default | What it does |
|---|---|---|
tsukihime.apiBaseUrl |
"https://api.tsukihime.org/v1" |
API base URL. Only change it for a mirror |
tsukihime.maxSearchResults |
10 |
Maximum releases per search (the API caps it at 100) |
TMDB
Posters, synopses, and show grouping for live-action titles in the stats Library. Release builds include a TMDB key, so you only need your own to use your own quota or when running from source. Get one free under Settings > API on themoviedb.org. Either the API key or the read access token works.
| Key | Default | What it does |
|---|---|---|
tmdb.apiKey |
"" |
Your TMDB key or token. Overrides the bundled key |
tmdb.apiKeyCommand |
"" |
Shell command that prints the key. Use instead of apiKey |
This product uses the TMDB API but is not endorsed or certified by TMDB.
Japanese subtitle generation
Transcribes Japanese subtitles locally with whisper.cpp. Open it with Ctrl+Shift+G (shortcuts.openSubtitleGeneration) or from the subtitle sidebar. See Subtitle generation.
| Key | Default | What it does |
|---|---|---|
subtitleGeneration.modelPath |
"" |
Path to a multilingual whisper.cpp GGML model. Overrides managedModel |
subtitleGeneration.managedModel |
"small" |
Model SubMiner downloads and uses when modelPath is empty |
subtitleGeneration.threads |
4 |
CPU threads |
subtitleGeneration.vadModelPath |
"" |
Silero VAD model. Set it to focus on spoken dialogue by default |
subtitleGeneration.whisperPath |
"" |
whisper-cli path. Empty searches PATH |
subtitleGeneration.vadPath |
"" |
Speech detector path. Empty searches PATH |
subtitleGeneration.ffmpegPath |
"" |
ffmpeg path. Empty searches PATH |
subtitleGeneration.ffprobePath |
"" |
ffprobe path. Empty searches PATH |
Subtitle sync
Retimes a subtitle track with alass (against another subtitle or the video) or ffsubsync (against the video's audio). Install them yourself. Open the picker with Ctrl+Alt+S (shortcuts.triggerSubsync).
| Key | Default | What it does |
|---|---|---|
subsync.alass_path |
"" |
alass path. Empty uses /usr/bin/alass |
subsync.ffsubsync_path |
"" |
ffsubsync path. Empty uses /usr/bin/ffsubsync |
subsync.ffmpeg_path |
"" |
ffmpeg path. Empty uses /usr/bin/ffmpeg |
subsync.replace |
true |
Overwrite the subtitle file. When off, write <name>_retimed.<ext> |
If a tool lives somewhere else, such as on macOS or Windows, set its path.
AniList
Updates your AniList watch progress after an episode, and controls the character dictionary. With enabled on and no token, SubMiner opens a login window. See AniList integration and Character dictionary.
| Key | Default | What it does |
|---|---|---|
anilist.enabled |
false |
Enable progress updates |
anilist.accessToken |
"" |
Token override. Empty uses the token saved during login |
anilist.characterDictionary.maxLoaded |
3 |
How many recent shows stay in the merged character dictionary |
anilist.characterDictionary.collapsibleSections.description |
false |
Open the Description section by default |
anilist.characterDictionary.collapsibleSections.characterInformation |
false |
Open the Character Information section by default |
anilist.characterDictionary.collapsibleSections.voicedBy |
false |
Open the Voiced by section by default |
Yomitan
Point SubMiner at another app's Yomitan Electron profile to reuse its dictionaries and settings. For GameSentenceMiner on Linux this is usually ~/.config/gsm_overlay.
| Key | Default | What it does |
|---|---|---|
yomitan.externalProfilePath |
"" |
Absolute or ~ path to the external profile. Empty uses SubMiner's own |
In external-profile mode, SubMiner only reads the profile. It does not open its own Yomitan settings, does not change dictionaries, and turns off all character-dictionary features.
Jellyfin
Log in to a Jellyfin server, browse libraries, and play or cast to SubMiner. Login tokens are stored encrypted, not in this file. See Jellyfin integration.
| Key | Default | What it does |
|---|---|---|
jellyfin.enabled |
false |
Enable Jellyfin |
jellyfin.serverUrl |
"" |
Server URL, for example http://localhost:8096 |
jellyfin.username |
"" |
Default username for subminer jellyfin -l |
jellyfin.remoteControlEnabled |
true |
Let Jellyfin apps cast to SubMiner |
jellyfin.remoteControlAutoConnect |
true |
Connect the cast session on startup |
jellyfin.autoAnnounce |
false |
Announce SubMiner as a cast target on connect |
jellyfin.pullPictures |
false |
Fetch posters for launcher pickers |
jellyfin.iconCacheDir |
"/tmp/subminer-jellyfin-icons" |
Poster cache folder |
jellyfin.directPlayPreferred |
true |
Try direct play before transcoding |
jellyfin.transcodeVideoCodec |
"h264" |
Codec requested when transcoding |
Discord rich presence
Shows what you are watching on your Discord profile. Needs the Discord desktop app running. If Discord is closed, SubMiner skips updates.
| Key | Default | What it does |
|---|---|---|
discordPresence.enabled |
true |
Enable rich presence |
discordPresence.presenceStyle |
"default" |
Card text: default, meme, japanese (all Japanese), minimal |
discordPresence.updateIntervalMs |
3000 |
Minimum ms between updates |
discordPresence.debounceMs |
750 |
Debounce for bursts of playback events |
Immersion tracking
Records watch sessions, subtitle lines, and mining in a local SQLite database that feeds the stats dashboard. See Immersion tracking for retention and storage details. To turn it off for one run, start with SUBMINER_DISABLE_IMMERSION_TRACKING=1 subminer.
| Key | Default | What it does |
|---|---|---|
immersionTracking.enabled |
true |
Enable tracking |
immersionTracking.dbPath |
"" |
Database path. Empty uses immersion.sqlite in the config folder |
immersionTracking.batchSize |
25 |
Writes per transaction |
immersionTracking.flushIntervalMs |
500 |
Maximum ms before queued writes are saved |
immersionTracking.queueCap |
1000 |
Queue size. The oldest writes drop when full |
immersionTracking.payloadCapBytes |
256 |
Maximum event payload size before truncation |
immersionTracking.maintenanceIntervalMs |
86400000 |
How often pruning and rollups run (24 h) |
immersionTracking.retentionMode |
"preset" |
preset uses retentionPreset. advanced uses retention.* |
immersionTracking.retentionPreset |
"balanced" |
minimal, balanced, or deep-history |
immersionTracking.retention.eventsDays |
0 |
Days to keep raw events. 0 keeps everything |
immersionTracking.retention.telemetryDays |
0 |
Days to keep telemetry |
immersionTracking.retention.sessionsDays |
0 |
Days to keep sessions |
immersionTracking.retention.dailyRollupsDays |
0 |
Days to keep daily rollups |
immersionTracking.retention.monthlyRollupsDays |
0 |
Days to keep monthly rollups |
immersionTracking.retention.vacuumIntervalDays |
0 |
Days between VACUUM runs. 0 disables |
immersionTracking.lifetimeSummaries.global |
true |
Keep all-time totals |
immersionTracking.lifetimeSummaries.anime |
true |
Keep per-show totals |
immersionTracking.lifetimeSummaries.media |
true |
Keep per-file totals |
Stats dashboard
A local web dashboard at http://127.0.0.1:<serverPort>, also available as an overlay inside SubMiner. It reads the immersion tracking database, so tracking must be on. See Immersion tracking.
| Key | Default | What it does |
|---|---|---|
stats.toggleKey |
"Backquote" |
Key that toggles the stats overlay (overlay focus only) |
stats.markWatchedKey |
"KeyW" |
Key that marks the video watched and plays the next playlist entry |
stats.serverPort |
6969 |
Dashboard port |
stats.autoStartServer |
true |
Start the dashboard server once tracking is active |
stats.autoOpenBrowser |
false |
Open the browser when subminer stats starts the server |
MPV launcher
Settings for mpv instances that SubMiner starts, and for the bundled mpv plugin. See mpv plugin.
| Key | Default | What it does |
|---|---|---|
mpv.executablePath |
"" |
Path to mpv.exe on Windows. Empty checks SUBMINER_MPV_PATH, then PATH |
mpv.launchMode |
"normal" |
Window state: normal, maximized, or fullscreen |
mpv.profile |
"" |
mpv profile to pass. Combined with a launcher --profile if both are set |
mpv.socketPath |
platform-specific | mpv IPC socket. See the warning under Config file |
mpv.backend |
"auto" |
Window tracking: auto, hyprland, sway, x11, macos, windows |
mpv.autoStartSubMiner |
true |
Start SubMiner in the background when mpv loads a file |
mpv.pauseUntilOverlayReady |
true |
Keep mpv paused until subtitles are ready, up to 30 seconds |
mpv.subminerBinaryPath |
"" |
SubMiner app path for the plugin. Empty uses the detected path |
mpv.aniskipEnabled |
true |
Detect intros with AniSkip and show a skip prompt |
mpv.aniskipButtonKey |
"TAB" |
mpv key that skips the intro while the prompt is shown |
YouTube playback settings
Language and card-media settings for YouTube playback. YouTube always loads a Japanese primary and English secondary track, preferring manual uploads over auto captions. See YouTube integration.
| Key | Default | What it does |
|---|---|---|
youtube.primarySubLanguages |
["ja", "jpn"] |
Languages that count as a valid primary track, also used for local playback |
youtube.mediaCache.mode |
"direct" |
direct cuts card media from the stream. background downloads the video with yt-dlp first |
youtube.mediaCache.maxHeight |
720 |
Maximum download height in background mode. 0 is unlimited |
Use background if card media fails with YouTube 403 errors. Cards mined before the download finishes get their text right away and their audio and image once the file is ready.