Files
SubMiner/docs-site/usage.md
T
sudacode b31ddce627 feat(controller): add hold + press combos to main bindings (#328)
* feat(controller): add hold + press combos to main bindings

Main Alt+C actions can now be learned as combos such as L1 + D-pad right.
A combo fires on each press while its hold button is down, and claims its
press input so token move and popup scroll ignore it until it is released.
A plain action on a hold button fires on release, unless another bound
button was pressed during the hold.

The save path needed two changes for combos to persist. The IPC validator
rebuilt bindings field by field and dropped `hold`, so Alt+C showed a combo
from its local copy until the next reload turned it back into a plain
button. Validator and config resolver now share one parser. Saves also
replace the controller section, since the deep merge in patchRawConfig kept
the old `hold` when a combo was rebound to one button.

Also fixes Learn on the (D-pad) rows, which threw after cancel() cleared
the capture target.

* test(launcher): wait for content in background child test

The test polled for the fake app's output files to exist, but the shell
creates a redirect target before writing to it. A poll landing in that gap
read an empty env file and failed with '' !== '1', as seen once in CI.
Wait until both files have content instead.

* fix(controller): keep a diagonal push from learning as a combo

Learn took the first axis of a diagonal stick push as the hold and the
second as the press, saving a combo that one axis could never trigger. This
reached main Alt+C rows when they moved to combo capture. Axes crossing the
threshold in the same poll as the first input now count as one movement. A
second axis moved in a later poll still records a combo.

* fix(controller): only treat simultaneous axes as one movement

The diagonal push guard also blocked an axis activated in the same poll as a
button, so L1 plus a stick direction could not record the stick until it was
released and moved again. Apply the guard only when the first input is an
axis, so that input pair records as a combo again.
2026-11-05 23:23:54 -08:00

214 lines
17 KiB
Markdown

# Usage
This page covers everyday use: starting playback, working with the overlay, and the commands you will reach for most. For every `subminer` subcommand and flag, see [Launcher script](/launcher-script).
## Play a video
```bash
subminer video.mkv
```
On Windows, double-click the **SubMiner mpv** shortcut or drag a video onto it.
SubMiner starts mpv, connects to it, and opens the overlay. Subtitle lines appear as hoverable words. Hover a word to look it up, then mine it into Anki. [Mining workflow](/mining-workflow) covers lookup and card creation in detail.
Run `subminer` with no file to pick one from the current directory instead. See [Picking files](#picking-files).
### Yomitan setup
Lookups need at least one dictionary in SubMiner's bundled Yomitan (or in Hachidori, if you [switched backends](#hachidori-setup)). First-run setup asks you to import one. To add more later, open Yomitan settings with `Alt+Shift+Y` or `subminer app --yomitan`.
The bundled Yomitan is separate from any Yomitan in your browser. It has its own dictionaries and settings.
### Hachidori setup
[Hachidori](https://github.com/bee-san/hachidori) is an alternative lookup backend. Set `dictionaryBackend` to `"hachidori"` in settings or `config.jsonc`, then restart SubMiner. Set it back to `"yomitan"` and restart to switch back.
Open Hachidori settings with `Alt+Shift+Y`, the tray's **Open Hachidori Settings**, or `subminer app --hachidori`. Import dictionary ZIPs or use Hachidori's recommended dictionary installer, then set up its Anki template (SubMiner [fills in what it can](/anki-integration#hachidori-settings-from-subminer)). Yomitan and Hachidori keep separate dictionaries and settings. Yomitan profiles, custom Handlebars templates, and `yomitan.externalProfilePath` do not carry over. Subtitle annotations and lookups wait while Hachidori imports a dictionary, so large imports pause them until the import finishes.
Hachidori uses SubMiner's subtitle scanning, popup pause, controller commands, character dictionaries, and Anki media. Keep the [Anki proxy](/anki-integration#proxy-mode-setup-yomitan-texthooker) on for screenshots and sentence audio. Hachidori's own screen recorder and screenshot capture are off inside SubMiner. `startupWarmups.yomitanExtension` and `subtitleStyle.autoPauseVideoOnYomitanPopup` apply to whichever backend is selected.
Switching backends:
- First-run setup asks for dictionaries the first time you switch to a backend. Switching back to a backend that already finished setup skips it.
- Until you restart, SubMiner keeps running the backend it started with. The launcher waits for that backend before playback and logs a restart reminder.
- `--yomitan` and `--hachidori` both work whichever backend is selected. Opening settings does not switch backends.
- When `yomitan.externalProfilePath` is set, `--yomitan` is disabled to keep the external profile read-only. Hachidori settings still open.
#### External dictionary host
First-run setup can link a Hachidori host instead of using local dictionaries: **Dictionary source → Use an external dictionary host → Link host**. Turn on sharing in the other Hachidori app or browser, or start a compatible Docker host, then enter its sharing address, for example `127.0.0.1:8771` or `ws://host:8771/link`. Use the WebSocket sharing port, not the management page or HTTP API port.
| Host | Must be running |
| -------- | ------------------------------------------- |
| Browser | The browser, the Hachidori extension, relay |
| Electron | The host app and any relay it needs |
| Docker | The container only |
Setup checks the connection and the host's dictionaries before **Finish** unlocks, so import at least one dictionary on the host and refresh. The link survives restarts. **Unlink and use local dictionaries** goes back to local.
While linked, dictionaries and dictionary settings come from the host. Anki templates, pronunciation sources, custom buttons, and SubMiner's audio and image processing stay local. Frequency annotations use ranks returned with dictionary entries, and SubMiner asks the host for missing ones. Words with no matching definition entry may stay unranked even if a frequency dictionary lists them.
SubMiner sends [character dictionaries](/character-dictionary) to the linked host over the link and replaces the previous one once the import succeeds, retrying while the host is busy. The host needs Hachidori 0.2.3 or later, or a current Docker host. With an older host, sync reports where the merged ZIP is so you can import it from that host's Hachidori settings.
## Picking files
```bash
subminer # fzf picker for the current directory
subminer -d ~/Anime -r # pick from a directory, searching subfolders
subminer -R # rofi picker instead of fzf (Linux)
subminer -H # watch history: replay, next, or previous episode
```
See [Launcher script](/launcher-script#video-picker) for picker and history details.
## Overlay basics
| Key | Action |
| ------------- | ---------------------------------------------------------------------------- |
| `Alt+Shift+O` | Show or hide the overlay (works while the overlay or mpv has focus) |
| `Alt+Shift+Y` | Open Yomitan or Hachidori settings (works from any window, not configurable) |
| `V` | Cycle the subtitle bar through hidden, visible, and hover-only |
| `Ctrl+Alt+P` | Open the playlist browser to queue, reorder, or jump between episodes |
| `Ctrl/Cmd+/` | Show every overlay and mpv keybinding for this session |
Hovering subtitle text pauses mpv, and moving away resumes it. An open dictionary popup also keeps playback paused. Turn these off with `subtitleStyle.autoPauseVideoOnHover` and `subtitleStyle.autoPauseVideoOnYomitanPopup`.
**Pause Video In Keyboard-Only Mode** (`subtitleStyle.autoPauseVideoOnKeyboardMode`, off by default) pauses mpv when keyboard-only mode turns on, from the keyboard or a controller, and resumes it when the mode turns off. It only resumes a pause it made: if the video was already paused, or you played or paused it yourself in the meantime, leaving the mode leaves playback as it is.
Turning keyboard-only mode off also closes the dictionary popup, whether or not this setting is on.
You can drop files onto the overlay:
- A video replaces what is playing. Hold `Shift` to add it to the playlist instead.
- A subtitle file loads as a new subtitle track.
The full list is in [Keyboard shortcuts](/shortcuts). The in-player `y` key chords are in [mpv plugin](/mpv-plugin).
## YouTube playback
Pass a URL or a search. Install `yt-dlp` first.
```bash
subminer https://youtu.be/...
subminer ytsearch:"jp news" # play the first search result
```
SubMiner picks subtitles during startup while mpv is paused. It selects a Japanese primary track and an English secondary track, downloads whatever is missing, and resumes once the primary subtitles are ready. If the choice is wrong, press `Ctrl+Alt+C` to open the YouTube subtitle picker and choose again.
Language preferences live under `youtube` and `secondarySub` in the config. See [YouTube integration](/youtube-integration).
## Common commands
```bash
subminer stats # start the immersion stats dashboard
subminer settings # open the settings window
subminer yt # browse YouTube; picked videos play in mpv
subminer doctor # check dependencies, config, and the mpv socket
subminer generate-subs video.mkv # make Japanese subtitles from the audio
subminer logs -e # export a log ZIP for bug reports
subminer app --setup # reopen first-run setup
subminer app --plugin-action <id>/<name> # run a plugin action
subminer -u # update SubMiner
```
Two flags help early on:
- `-a/--args` passes options to mpv, for example `subminer --args "--volume=80" video.mkv`.
- `--log-level debug` turns on verbose logs when something is wrong.
[Launcher script](/launcher-script) lists every command. Jellyfin, sync, and character dictionary commands are covered in [Jellyfin](/jellyfin-integration), [Sync between machines](/launcher-script#sync-between-machines), and [Character dictionary](/character-dictionary).
### Generate Japanese subtitles locally
`subminer generate-subs` transcribes audio with whisper.cpp and writes a Japanese SRT file. If that file is playing in mpv, it loads the new subtitles right away. Leave out the path to use the file mpv is playing.
```bash
subminer generate-subs video.mkv --download-model # download a model on first use
subminer generate-subs video.mkv --model-path ~/models/ggml-medium.bin
```
You need `whisper-cli`, `ffmpeg`, and `ffprobe`. Check the output before mining, since speech recognition makes mistakes over music and overlapping voices. See [Subtitle generation](/subtitle-generation) for models, timing references, and settings.
## Windows mpv shortcut
First-run setup can create a **SubMiner mpv** shortcut in the Start menu and on the desktop. It is the easiest way to play local files on Windows:
- Double-click it to open mpv with SubMiner attached.
- Drag a video onto it to play that file.
- Run it from a terminal:
```powershell
& "C:\Program Files\SubMiner\SubMiner.exe" --launch-mpv "C:\Videos\episode 01.mkv"
```
mpv must be on `PATH`, or `mpv.executablePath` must point to `mpv.exe`. The `subminer` terminal command also works on Windows if you installed it during setup.
## Tray menu
The tray icon gives you:
- **Export Logs**: saves a log ZIP and shows its path. Usernames, IP addresses, emails, tokens, passwords, and cookies are masked in the exported copy. Your log files on disk stay unchanged.
- **View Changelog**: release notes, including versions newer than yours. Use `J`/`K` to move between versions, `Enter` to expand one, and `Esc` to close.
- **Sync Stats & History**: opens the [sync window](/launcher-script#sync-between-machines).
- **Jellyfin Discovery**: turns cast discovery on or off for this session, once [Jellyfin](/jellyfin-integration) is set up.
On Wayland, the tray icon only appears if your panel provides a StatusNotifier (AppIndicator) tray.
## Controller support {#controller-support}
You can drive the overlay with a gamepad.
1. Set `controller.enabled` to `true` in your config.
2. Connect a controller and press a button. SubMiner uses the first one it sees and announces it through [`ankiConnect.behavior.notificationType`](/configuration#ankiconnect).
3. Press `Y` on the controller to turn on keyboard-only mode. Most controller actions only work in this mode.
4. Move between words with the left stick, press `A` to look one up, and `X` to mine it.
Press `Alt+C` to choose a controller and remap buttons. Click an action's **Learn** button, then press the button you want, or hold one button and press another to make a combo such as `L1` + D-pad right. Set **Button Style** to Xbox, Nintendo or PlayStation so buttons are named as printed on your controller; it is saved per controller. Changes apply right away. When two actions share an input, both fire, so their rows show a ⚠ warning naming the other action; this includes a button on the D-pad while a **(D-pad)** row under **Navigation** is still on, and a stick direction used by a stick action. The window only sees a controller after you press one of its buttons; until then it shows the bindings of the controller in use as a preview, and editing stays locked. With several controllers connected, it selects the one you pressed last. `Alt+Shift+C` shows raw input values for unusual pads.
A combo fires each time you press its second button while the first is down, so holding `L1` and pressing right twice runs it twice. While a combo's hold button is down, other buttons only run combos that use it, and its press no longer drives a **(D-pad)** or stick row. A hold button can keep its own action: that action then runs when you let go, unless you pressed another bound button during the hold. The exception is **Show Secondary Subtitle (Hold)**, which can't wait for release, so its row warns if it shares a hold button.
| Button | Action |
| --------------------- | -------------------------------------- |
| `A` (South) | Look up the selected word |
| `B` (East) | Close the lookup |
| `X` (West) | Mine a card |
| `Y` (North) | Toggle keyboard-only mode |
| `L1` | Play the current Yomitan audio |
| `R1` | Next Yomitan audio source |
| `L3` | Pause or resume mpv (any mode) |
| `Select` / `Minus` | Quit mpv |
| Left stick | Move between words, scroll the popup |
| Right stick (up/down) | Jump through the popup |
| Unbound by default | Show the secondary subtitle while held |
| Unbound by default | Previous word entry in the popup |
| Unbound by default | Next word entry in the popup |
| Unbound by default | Previous / next subtitle line |
| Unbound by default | Replay the current line, then pause |
| Unbound by default | Play the next line, then pause |
| Unbound by default | Move by word or by character |
The secondary subtitle hold works with or without keyboard-only mode. Assign it with **Learn** on the **Show Secondary Subtitle (Hold)** row in `Alt+C`. While held, the secondary subtitle shows as if its mode were `visible`; releasing the button returns it to your chosen mode.
The **Subtitles** rows in `Alt+C` do the same as the keyboard shortcuts: **Previous Subtitle** and **Next Subtitle** jump a line like `Shift+H` / `Shift+L` (a paused video stays paused), **Replay Subtitle** is `Ctrl+Shift+H` and **Play Next Subtitle** is `Ctrl+Shift+L`. Like the secondary subtitle hold and pause, they work with or without keyboard-only mode. If you put them on the D-pad, click **Clear** on the matching **(D-pad)** row under **Navigation** too (both rows warn until you do), or in keyboard-only mode the D-pad will also move between words or scroll the popup.
**Previous Entry** and **Next Entry** move one word entry at a time in the open popup, and Mine Card then mines the selected entry. They send Yomitan's default `Alt+Up` / `Alt+Down` entry shortcuts, so they stop working if you rebind those in Yomitan's keyboard settings. If you assign them to the D-pad, click **Clear** on the **Popup Scroll (D-pad)** row too, or the D-pad will also scroll the popup.
When the subtitle is split in the wrong place, a word can start in the middle of a box (in もっとハ|キ|ハキしなくちゃ, ハキハキ starts at the last character of the first box) and moving by word never reaches it. In keyboard-only mode, press `C` on the keyboard, or the **Toggle Character Navigation** button (unbound by default, under **Navigation** in `Alt+C`), to move one character at a time: the box turns orange and covers one character, and a lookup searches from that character, so Yomitan finds the longest word starting there. Press it again to go back to moving by word. It stays on until you switch it back, even after leaving keyboard-only mode.
The media timing review and duplicate card (field grouping) dialogs have their own controller layouts, which you can change in the **Review media timing** and **Duplicate card (field grouping)** groups of `Alt+C`; see [Review media timing](/anki-integration#with-a-controller) and [Field grouping](/anki-integration#field-grouping-with-a-controller).
On controllers that report the W3C standard layout, the default quit button lands on `L2` instead of `Select`, and the default pause button on `Start` instead of `L3`. The default right-stick popup jump does nothing on these controllers; click **Learn** on **Popup Jump (Stick)** and move the right stick up or down to set it. Remap anything else with `Alt+C`, which names buttons according to the layout your controller reports. All options are in [Configuration](/configuration#controller-support).
On macOS, a controller only reaches the app in front. When mpv is in front, a controller button brings the overlay to the front and then runs that button's action. With more than one controller connected, that first press only brings the overlay to the front; press the button again to run its action. Stick movements only work once the overlay is in front. Buttons pressed while another app is in front are left alone.
## Development profiles
`--dev` and `--debug` use a separate `SubMiner-dev` profile. They do not read or modify dictionaries and configuration from the installed app unless `SUBMINER_USE_PRODUCTION_PROFILE=1` is explicitly set. See [Development](/development#run-locally).
## Changing settings while you watch
SubMiner watches your config file and applies most changes without a restart, including subtitle style, keybindings, and most Anki settings. If a change needs a restart, SubMiner tells you. If the file has an error, it keeps the last working config and shows a notification. See [Configuration](/configuration).
Next: [Mining workflow](/mining-workflow).