From 23b78e6c9ba33b141df1273d79992d40d4550a5b Mon Sep 17 00:00:00 2001 From: sudacode Date: Mon, 16 Feb 2026 19:26:34 -0800 Subject: [PATCH] Update docs and gitignore changes --- .gitignore | 2 +- README.md | 149 ++++++++++++----------------------------- docs/architecture.md | 142 ++++++++++++++++++++++----------------- docs/index.md | 153 ++++++++++++++++--------------------------- 4 files changed, 179 insertions(+), 267 deletions(-) diff --git a/.gitignore b/.gitignore index 47a2af5..80ad383 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,7 @@ environment.toml .vitepress/dist/ docs/.vitepress/cache/ docs/.vitepress/dist/ -test/* +tests/* .worktrees/ .codex/* .agents/* diff --git a/README.md b/README.md index d1910f1..5528fb9 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,37 @@
SubMiner logo

SubMiner

+

Immersion mining overlay for mpv — look up words, mine to Anki, and enrich cards with context without leaving the video.

-An all-in-one immersion mining overlay for MPV with AnkiConnect and dictionary (Yomitan) integration. +--- -## What This Project Is For - -SubMiner is for Japanese learners who watch subtitled content in mpv and want a low-friction mining loop: - -- stay inside the video while doing lookups -- mine to Anki quickly without manual copy/paste workflows -- preserve card context (sentence, audio, screenshot, translation, metadata) -- reduce tool switching between player, dictionary, and card workflow - -## Project Goals - -1. Keep immersion continuous by making lookup and mining happen over mpv subtitles. -2. Preserve card quality with context-rich media and subtitle timing. -3. Support real daily workflows (subtitle management, sync, known-word awareness, keyboard-first controls). -4. Stay configurable with sensible defaults and advanced customization. -5. Evolve quickly and safely with a TypeScript codebase and automated tests that make refactors easier to ship. - -## Who It's For - -- learners using mpv as their primary immersion player -- users already working with Yomitan and AnkiConnect -- miners who care about long-term card quality, not just quick word capture - -SubMiner is likely overkill if you only want lightweight dictionary lookup without card enrichment or integrated workflow tools. +[![Demo](./assets/demo-poster.jpg)](https://github.com/user-attachments/assets/9235a554-ea51-4284-b14b-7bbf3defaf58) ## Features -- Real-time subtitle display from MPV via IPC socket -- Yomitan integration for fast, on-screen lookups -- Japanese text tokenization using MeCab with smart word boundary detection -- Integrated texthooker-ui server for use with Yomitan -- Integrated WebSocket server (if [mpv_websocket](https://github.com/kuroahna/mpv_websocket) is not found) to send lines to the texthooker -- AnkiConnect integration for automatic card creation with media (audio/image) -- Invisible subtitle position edit mode (`Ctrl/Cmd+Shift+P`, arrow keys to adjust, `Enter`/`Ctrl+S` save, `Esc` cancel) - -## Demo - -[![Demo screenshot](./assets/demo-poster.jpg)](https://github.com/user-attachments/assets/9235a554-ea51-4284-b14b-7bbf3defaf58) +- **Yomitan Integration** — Hover subtitle words to trigger dictionary lookups in the player +- **Anki Card Enrichment** — Fills sentence, audio, screenshot, and translation on new cards automatically +- **Dual-Layer Subtitles** — Interactive visible overlay + invisible click-through layer aligned with mpv rendering +- **N+1 Highlighting** — Marks known vocabulary from your Anki deck so you can spot new words at a glance +- **Texthooker & WebSocket** — Built-in texthooker page with WebSocket streaming for external tools +- **Subtitle Download & Sync** — Search Jimaku, sync with alass or ffsubsync — all from the player +- **Keyboard-Driven** — Mine, copy, cycle display modes, and navigate from configurable shortcuts +- **Japanese Tokenization** — MeCab-powered word boundary detection with smart grouping ## Requirements - `mpv` with IPC socket support -- `mecab` and `mecab-ipadic` (recommended for Japanese tokenization) +- `mecab` and `mecab-ipadic` - Linux: Hyprland (`hyprctl`) or X11 (`xdotool` + `xwininfo`) - macOS: Accessibility permission for window tracking -Optional but recommended: `yt-dlp`, `fzf`, `rofi`, `chafa`, `ffmpegthumbnailer`. +Optional: `yt-dlp`, `fzf`, `rofi`, `chafa`, `ffmpegthumbnailer` ## Install ### Linux (AppImage) -Download the latest release from [GitHub Releases](https://github.com/ksyasuda/SubMiner/releases/latest): - ```bash wget https://github.com/ksyasuda/SubMiner/releases/download/v0.1.0/SubMiner-0.1.0.AppImage -O ~/.local/bin/SubMiner.AppImage chmod +x ~/.local/bin/SubMiner.AppImage @@ -73,49 +46,34 @@ The `subminer` wrapper uses a [Bun](https://bun.sh) shebang, so `bun` must be on ```bash git clone --recurse-submodules https://github.com/ksyasuda/SubMiner.git cd SubMiner -make build -make install +make build && make install ``` -If you already cloned without submodules: - -```bash -cd SubMiner -git submodule update --init --recursive -``` - -For macOS builds, signing, and platform-specific details, see [docs/installation.md](docs/installation.md). +For macOS builds and platform details, see the [installation docs](docs/installation.md). ## Quick Start -1. Copy and customize [`config.example.jsonc`](config.example.jsonc) to `$XDG_CONFIG_HOME/SubMiner/config.jsonc` (or `~/.config/SubMiner/config.jsonc`). -2. Start mpv with IPC enabled: - -```bash -mpv --input-ipc-server=/tmp/subminer-socket video.mkv -``` - +1. Copy [`config.example.jsonc`](config.example.jsonc) to `~/.config/SubMiner/config.jsonc` +2. Start mpv with IPC: + ```bash + mpv --input-ipc-server=/tmp/subminer-socket video.mkv + ``` 3. Launch SubMiner: + ```bash + subminer video.mkv + ``` ```bash -subminer video.mkv -# or -subminer https://youtu.be/... +subminer # pick video from cwd (fzf) +subminer -R # rofi picker +subminer -d ~/Videos # set source directory +subminer -r -d ~/Anime # recursive search +subminer -p gpu-hq video.mkv # override mpv profile +subminer -T video.mkv # disable texthooker +subminer https://youtu.be/... # YouTube playback ``` -## Common Commands - -```bash -subminer # pick video from current dir (fzf) -subminer -R # use rofi picker -subminer -d ~/Videos # set source directory -subminer -r -d ~/Anime # recursive search -subminer video.mkv # launch with default mpv profile (subminer) -subminer -p gpu-hq video.mkv # override mpv profile -subminer -T video.mkv # disable texthooker -``` - -## MPV Plugin (Optional) +## MPV Plugin ```bash cp plugin/subminer.lua ~/.config/mpv/scripts/ @@ -123,46 +81,23 @@ cp plugin/subminer.conf ~/.config/mpv/script-opts/ # or: make install-plugin ``` -Requires mpv IPC: `--input-ipc-server=/tmp/subminer-socket` - -Default chord prefix: `y` (`y-y` menu, `y-s` start, `y-S` stop, `y-t` toggle visible layer). -Overlay Jimaku shortcut default: `Ctrl+Shift+J` (`shortcuts.openJimaku`). +Default chord prefix: `y` (`y-y` menu, `y-s` start, `y-S` stop, `y-t` toggle overlay). +Jimaku shortcut: `Ctrl+Shift+J`. ## Documentation -Detailed guides live in [`docs/`](docs/README.md): +Full guides at [**docs/**](docs/README.md): +[Installation](docs/installation.md) · [Usage](docs/usage.md) · [Mining Workflow](docs/mining-workflow.md) · [Configuration](docs/configuration.md) · [Anki Integration](docs/anki-integration.md) · [MPV Plugin](docs/mpv-plugin.md) · [Troubleshooting](docs/troubleshooting.md) · [Architecture](docs/architecture.md) -- [Installation](docs/installation.md) — Platform requirements, AppImage/macOS/source installs, mpv plugin -- [Usage](docs/usage.md) — Script vs plugin workflow, keybindings, YouTube playback -- [Mining Workflow](docs/mining-workflow.md) — End-to-end mining guide, overlay layers, card creation -- [Configuration](docs/configuration.md) — Full config reference and option details -- [Anki Integration](docs/anki-integration.md) — AnkiConnect setup, field mapping, media generation -- [MPV Plugin](docs/mpv-plugin.md) — Chord keybindings, subminer.conf options, script messages -- [Troubleshooting](docs/troubleshooting.md) — Common issues and solutions -- [Development](docs/development.md) — Building, testing, contributing -- [Architecture](docs/architecture.md) — Service-oriented design, composition model, and modular renderer layout (`src/renderer/{modals,handlers,utils,...}`) +## Acknowledgments -### Third-Party Components - -This project includes the following third-party components: - -- **[Yomitan](https://github.com/yomidevs/yomitan)** - Pop-up dictionary -- **[texthooker-ui](https://github.com/ksyasuda/texthooker-ui/tree/subminer)** - Texthooker Page -- **[yomitan-jlpt-vocab](https://github.com/stephenmk/yomitan-jlpt-vocab)** - JLPT Yomitan Dictionary -- **[Jiten Frequency Dictionary](https://jiten.moe/)** - Frequency Dictionary - -### Acknowledgments - -- **[GameSentenceMiner](https://github.com/bpwhelan/GameSentenceMiner)** — Inspiration for the subtitle overlay and Yomitan integration -- **[Jimaku.cc](https://jimaku.cc)** — Japanese subtitle provider - -This project cherry-picks features from the following MPV scripts, ported to TypeScript: - -- **[mpvacious](https://github.com/Ajatt-Tools/mpvacious)** — Sentence mining, screenshotting, and card updating logic -- **[Anacreon-Script (animecards)](https://github.com/friedrich-de/Anacreon-Script)** — Copy/paste to card update flow -- **[autosubsync-mpv](https://github.com/joaquintorres/autosubsync-mpv)** — Subtitle synchronization +- [GameSentenceMiner](https://github.com/bpwhelan/GameSentenceMiner) — Inspiration for the overlay and Yomitan integration +- [Jimaku.cc](https://jimaku.cc) — Japanese subtitle provider +- [mpvacious](https://github.com/Ajatt-Tools/mpvacious), [Anacreon-Script](https://github.com/friedrich-de/Anacreon-Script), [autosubsync-mpv](https://github.com/joaquintorres/autosubsync-mpv) — Mining and sync logic ported to TypeScript +**Third-party:** +[Yomitan](https://github.com/yomidevs/yomitan) · [texthooker-ui](https://github.com/ksyasuda/texthooker-ui/tree/subminer) · [yomitan-jlpt-vocab](https://github.com/stephenmk/yomitan-jlpt-vocab) · [Jiten Frequency Dictionary](https://jiten.moe/) ## License -GNU General Public License v3.0. See [LICENSE](LICENSE). +[GNU General Public License v3.0](LICENSE) diff --git a/docs/architecture.md b/docs/architecture.md index cdb4b39..fd158c6 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -84,53 +84,63 @@ src/renderer/ ## Flow Diagram +The main process has three layers: `main.ts` delegates to composition modules that wire together domain services. The renderer runs in a separate Electron process, connected through `preload.ts`. + ```mermaid flowchart TD - classDef root fill:#c6a0f6,stroke:#24273a,color:#24273a,stroke-width:2px - classDef comp fill:#b7bdf8,stroke:#24273a,color:#24273a,stroke-width:1.5px - classDef svc fill:#8aadf4,stroke:#24273a,color:#24273a,stroke-width:1.5px - classDef ext fill:#a6da95,stroke:#24273a,color:#24273a,stroke-width:1.5px + classDef entry fill:#c6a0f6,stroke:#363a4f,color:#24273a,stroke-width:2px + classDef comp fill:#b7bdf8,stroke:#363a4f,color:#24273a,stroke-width:1.5px + classDef svc fill:#8aadf4,stroke:#363a4f,color:#24273a,stroke-width:1.5px + classDef bridge fill:#f5a97f,stroke:#363a4f,color:#24273a,stroke-width:1.5px + classDef rend fill:#8bd5ca,stroke:#363a4f,color:#24273a,stroke-width:1.5px + classDef ext fill:#a6da95,stroke:#363a4f,color:#24273a,stroke-width:1.5px - Main["src/main.ts"]:::root + Main["main.ts"]:::entry - subgraph Composition["Composition Modules"] - Startup["Startup & Lifecycle"]:::comp - IpcCli["IPC & CLI Wiring"]:::comp - Overlay["Overlay & Shortcuts"]:::comp - Subsync["Subsync"]:::comp + subgraph Comp["Composition — src/main/"] + Startup["Startup & Lifecycle
startup · app-lifecycle
startup-lifecycle · state"]:::comp + Wiring["Runtime Wiring
ipc-runtime · cli-runtime
overlay-runtime · subsync-runtime"]:::comp end - subgraph Services["Domain Services"] - OverlaySvc["Overlay Services"]:::svc - MpvSvc["MPV Stack"]:::svc - MiningSvc["Mining & Subtitles"]:::svc - ShortcutIpc["Shortcuts & IPC"]:::svc + subgraph Svc["Services — src/core/services/"] + Mpv["MPV Stack
transport · protocol
state · properties"]:::svc + Overlay["Overlay
manager · window
visibility · bridge"]:::svc + Mining["Mining & Subtitles
mining · field-grouping
subtitle-ws · tokenizer"]:::svc + Integrations["Integrations
jimaku · subsync
texthooker · yomitan"]:::svc end - subgraph External["External Boundaries"] - Config["Config & CLI"]:::ext - Trackers["Window Trackers"]:::ext - Integrations["Jimaku & Subsync"]:::ext + Bridge(["preload.ts — Electron IPC"]):::bridge + + subgraph Rend["Renderer — src/renderer/"] + Orchestration["renderer.ts
orchestration · IPC wiring"]:::rend + UI["subtitle-render · positioning
handlers · modals"]:::rend end - Main --> Startup - Main --> IpcCli - Main --> Overlay - Main --> Subsync + subgraph Ext["External Systems"] + mpv["mpv"]:::ext + Anki["AnkiConnect"]:::ext + Jimaku["Jimaku API"]:::ext + Tracker["Window Tracker"]:::ext + end - Startup --> OverlaySvc - IpcCli --> ShortcutIpc - Overlay --> OverlaySvc - Overlay --> MpvSvc - Subsync --> Integrations + Main -->|delegates| Comp + Startup -->|initializes| Svc + Wiring -->|dispatches to| Svc - OverlaySvc --> Trackers - MpvSvc --> MiningSvc - ShortcutIpc --> Config + Overlay <--> Bridge + Mining <--> Bridge + Bridge <--> Orchestration + Orchestration --> UI - style Composition fill:#363a4f,stroke:#494d64,color:#cad3f5 - style Services fill:#363a4f,stroke:#494d64,color:#cad3f5 - style External fill:#363a4f,stroke:#494d64,color:#cad3f5 + Mpv <-->|JSON socket| mpv + Mining -->|HTTP| Anki + Integrations -->|HTTP| Jimaku + Overlay --> Tracker + + style Comp fill:#363a4f,stroke:#494d64,color:#cad3f5 + style Svc fill:#363a4f,stroke:#494d64,color:#cad3f5 + style Rend fill:#363a4f,stroke:#494d64,color:#cad3f5 + style Ext fill:#363a4f,stroke:#494d64,color:#cad3f5 ``` ## Composition Pattern @@ -154,43 +164,53 @@ The composition root (`src/main.ts`) delegates to focused modules in `src/main/` This keeps side effects explicit and makes behavior easy to unit-test with fakes. -## Lifecycle Model +## Program Lifecycle -- **Startup:** - - `src/main/startup.ts` (`startup-service`) handles initial argv/env/backend setup and decides generate-config flow vs app lifecycle start. - - `src/main/app-lifecycle.ts` (`app-lifecycle-service`) handles Electron single-instance + lifecycle event registration. - - `src/main/startup-lifecycle.ts` performs ready-time initialization (config load, websocket policy, tokenizer/tracker setup, overlay auto-init decisions). -- **Runtime:** - - CLI/shortcut/IPC events map to service calls through `src/main/cli-runtime.ts`, `src/main/ipc-runtime.ts`, and `src/main/overlay-runtime.ts`. - - Overlay and MPV state sync through dedicated services. - - Runtime options and mining flows are coordinated via service boundaries. -- **Shutdown:** - - `app-lifecycle-service` registers cleanup hooks (`will-quit`) while teardown behavior stays delegated to focused services from `src/main/*` composition modules. +- **Startup:** `startup.ts` parses CLI args and detects the compositor backend. If `--generate-config` is passed, it writes the template and exits. Otherwise `app-lifecycle.ts` acquires the single-instance lock and registers Electron lifecycle hooks. +- **Initialization:** Once `app.whenReady()` fires, `startup-lifecycle.ts` loads config, resolves keybindings, creates the mpv client, initializes the MeCab tokenizer, starts the window tracker, and applies WebSocket policy — then creates the overlay window and establishes the IPC bridge. +- **Runtime:** Event-driven. mpv property changes, IPC messages, CLI commands, and keyboard shortcuts all route through the composition layer to domain services, which update state and broadcast to the renderer. +- **Shutdown:** Electron's `will-quit` triggers service teardown — closes the mpv socket, unregisters shortcuts, stops WebSocket and texthooker servers, destroys the window tracker, and cleans up Anki state. ```mermaid flowchart TD - classDef phase fill:#b7bdf8,stroke:#24273a,color:#24273a,stroke-width:1.5px - classDef decision fill:#f5a97f,stroke:#24273a,color:#24273a,stroke-width:1.5px - classDef runtime fill:#8aadf4,stroke:#24273a,color:#24273a,stroke-width:1.5px - classDef shutdown fill:#a6da95,stroke:#24273a,color:#24273a,stroke-width:1.5px + classDef start fill:#c6a0f6,stroke:#363a4f,color:#24273a,stroke-width:2px + classDef phase fill:#b7bdf8,stroke:#363a4f,color:#24273a,stroke-width:1.5px + classDef decision fill:#f5a97f,stroke:#363a4f,color:#24273a,stroke-width:1.5px + classDef init fill:#8aadf4,stroke:#363a4f,color:#24273a,stroke-width:1.5px + classDef runtime fill:#8bd5ca,stroke:#363a4f,color:#24273a,stroke-width:1.5px + classDef shutdown fill:#ed8796,stroke:#363a4f,color:#24273a,stroke-width:1.5px - Args["CLI args / env"]:::phase --> Startup["src/main/startup.ts"]:::phase + CLI["CLI args & environment"]:::start + CLI --> Parse["startup.ts
Parse argv · detect backend · resolve config"]:::phase + Parse --> GenCheck{"--generate-config?"}:::decision + GenCheck -->|yes| GenExit["Write config template & exit"]:::phase + GenCheck -->|no| Lifecycle["app-lifecycle.ts
Acquire single-instance lock
Register Electron lifecycle hooks"]:::phase + Lifecycle -->|"app.whenReady()"| Ready["startup-lifecycle.ts"]:::phase - Startup --> Decision{"generate-config?"}:::decision + Ready --> Init + subgraph Init["Initialization"] + direction LR + Config["Load config
resolve keybindings"]:::init + Runtime["Create mpv client
init MeCab tokenizer"]:::init + Platform["Start window tracker
WebSocket policy"]:::init + end - Decision -->|yes| WriteConfig["Write config + exit"]:::phase - Decision -->|no| AppLifecycle["src/main/app-lifecycle.ts"]:::phase + Init --> Create["Create overlay window
Establish IPC bridge
Load Yomitan extension"]:::phase - AppLifecycle --> Ready["src/main/startup-lifecycle.ts\nConfig · WebSocket · Tracker · Tokenizer · State"]:::phase + Create --> Loop + subgraph Loop["Runtime — event-driven"] + direction LR + Events["mpv · IPC · CLI
shortcut events"]:::runtime + Dispatch["Route to service
via composition layer"]:::runtime + State["Update state
broadcast to renderer"]:::runtime + Events --> Dispatch --> State + end - Ready --> Runtime["Runtime Modules\nipc · cli · overlay · subsync"]:::runtime + Loop -->|"app close"| Quit["Electron will-quit"]:::shutdown + Quit --> Teardown["Close mpv socket · unregister shortcuts
Stop WebSocket & texthooker
Destroy tracker · clean Anki state"]:::shutdown - Runtime --> Overlay["Overlay & Mining"]:::runtime - Runtime --> Subtitle["Subtitle Processing"]:::runtime - Runtime --> SubsyncInt["Subsync & Jimaku"]:::runtime - - Runtime --> WillQuit["Electron will-quit"]:::shutdown - WillQuit --> Cleanup["Service Teardown"]:::shutdown + style Init fill:#363a4f,stroke:#494d64,color:#cad3f5 + style Loop fill:#363a4f,stroke:#494d64,color:#cad3f5 ``` ## Why This Design diff --git a/docs/index.md b/docs/index.md index cf45588..8efeeba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,8 +6,8 @@ titleTemplate: Immersion Mining Workflow for MPV hero: name: SubMiner - text: Built for Immersion Mining - tagline: A self-contained MPV overlay for Japanese study. Look up words, mine cards, and enrich Anki without breaking playback flow. + text: Immersion Mining for MPV + tagline: Look up words, mine to Anki, and enrich cards with context — all without leaving the video. image: src: /assets/SubMiner.png alt: SubMiner logo @@ -18,80 +18,80 @@ hero: - theme: alt text: Mining Workflow link: /mining-workflow - - theme: alt - text: Is This For Me? - link: "#who-this-is-for" features: - icon: src: /assets/mpv.svg alt: mpv icon title: Built for mpv - details: Connects directly to mpv over IPC — tracks subtitles in real time, observes playback properties, and renders a self-contained overlay with everything bundled in a single application. + details: Connects via IPC to track subtitles in real time and render a self-contained overlay — everything bundled in a single application. - icon: src: /assets/yomitan-icon.svg alt: Yomitan logo title: Yomitan Integration - details: Hover over any word in the subtitles to trigger Yomitan dictionary lookups — get instant definitions without leaving the video player. + details: Hover over any word in the subtitle overlay to trigger dictionary lookups — instant definitions without leaving the player. - icon: src: /assets/anki-card.svg alt: Anki card icon title: Anki Card Enrichment - details: Add a word from Yomitan and SubMiner automatically updates the card with the sentence, audio clip, screenshot, and translation — no extra steps needed. + details: Add a word from Yomitan and SubMiner fills in the sentence, audio clip, screenshot, and translation automatically. - icon: src: /assets/dual-layer.svg alt: Dual layer icon - title: Dual-Layer Subtitle System - details: Visible overlay with styled, interactive subtitles — plus an invisible layer that aligns with mpv's own subtitle rendering for seamless click-through lookup. + title: Dual-Layer Subtitles + details: Interactive visible overlay plus an invisible layer aligned with mpv's own rendering for seamless click-through lookup. - icon: src: /assets/highlight.svg alt: Highlight icon - title: N+1 Word Highlighting - details: Highlights words you already know from your Anki deck, making it easy to spot new vocabulary and identify true N+1 sentences during immersion. + title: N+1 Highlighting + details: Marks words you already know from your Anki deck so you can spot new vocabulary and identify N+1 sentences at a glance. - icon: src: /assets/texthooker.svg alt: Texthooker icon title: Texthooker & WebSocket - details: Built-in texthooker page that receives subtitles over WebSocket — use it as a clipboard inserter for Yomitan or connect external tools for real-time subtitle streaming. + details: Built-in texthooker page that receives subtitles over WebSocket — use it as a clipboard inserter or connect external tools. - icon: src: /assets/subtitle-download.svg alt: Subtitle download icon title: Subtitle Download & Sync - details: Search and download Japanese subtitles from Jimaku, then sync them to the audio with alass or ffsubsync — all from within the player. + details: Search and download Japanese subtitles from Jimaku, then sync to audio with alass or ffsubsync — all from within the player. - icon: src: /assets/keyboard.svg alt: Keyboard icon - title: Keyboard-Driven Workflow - details: Mine sentences, copy subtitles, cycle display modes, and trigger field grouping — all from configurable keyboard shortcuts without touching the mouse. + title: Keyboard-Driven + details: Mine sentences, copy subtitles, cycle display modes, and trigger field grouping — all from configurable shortcuts. --- -
- -## What SubMiner Is For - -SubMiner is for people who learn Japanese by watching subtitled content in mpv and want a low-friction mining loop: - -- stay inside the video while looking up words -- send mined content to Anki quickly -- keep media context (audio, screenshot, timestamp, subtitle context) attached to each card -- reduce tool switching between player, dictionary, and card workflow - -
- -
- -## Project Goals - -
-
-
1. Keep Immersion Continuous
-
Minimize context switching by making lookup and mining happen directly over mpv subtitles.
-
-
-
2. Preserve Card Quality
-
Attach sentence context, audio, image, and translation so mined cards stay reviewable and useful long-term.
-
-
-
3. Support Real Workflows
-
Handle day-to-day immersion needs: subtitle management, syncing, known-word awareness, and keyboard-first controls.
-
-
-
4. Stay Configurable
-
Offer defaults that work out of the box, while still letting advanced users shape behavior around their note type and setup.
-
-
-
5. Evolve Safely
-
Use a modular TypeScript codebase and automated tests so features can ship faster without breaking core mining behavior.
-
-
- -
- -
- -## See It in Action - -SubMiner sits as a transparent overlay on top of mpv. Subtitles appear as interactive, clickable text — click a word to look it up with Yomitan, then add it to Anki with one click. - - - -
- -
- -## Who This Is For - -- learners using mpv as their main immersion player -- users who already rely on Yomitan + AnkiConnect -- miners who care about preserving context on cards, not just raw words - -SubMiner is likely overkill if you only want lightweight lookup without card enrichment, overlay controls, or integrated workflow tooling. - -
-
## How It Works @@ -212,7 +158,7 @@ SubMiner is likely overkill if you only want lightweight lookup without card enr
02
Look Up
-
Hover over a word in the subtitle overlay and hold Shift to trigger a Yomitan dictionary lookup.
+
Hover over a word in the subtitle overlay and hold Shift to trigger a Yomitan lookup.
03
@@ -227,3 +173,14 @@ SubMiner is likely overkill if you only want lightweight lookup without card enr
+ +
+ +## See It in Action + + + +