mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
chore: contents
This commit is contained in:
5
Makefile
5
Makefile
@@ -1,6 +1,7 @@
|
|||||||
.PHONY: help deps build build-launcher install build-linux build-macos build-macos-unsigned clean install-linux install-macos install-plugin uninstall uninstall-linux uninstall-macos print-dirs pretty ensure-bun generate-config generate-example-config docs-dev docs docs-preview dev-start dev-start-macos dev-toggle dev-stop
|
.PHONY: help deps build build-launcher install build-linux build-macos build-macos-unsigned clean install-linux install-macos install-plugin uninstall uninstall-linux uninstall-macos print-dirs pretty ensure-bun generate-config generate-example-config docs-dev docs docs-preview dev-start dev-start-macos dev-toggle dev-stop
|
||||||
|
|
||||||
APP_NAME := subminer
|
APP_NAME := subminer
|
||||||
|
THEME_SOURCE := assets/themes/subminer.rasi
|
||||||
THEME_FILE := subminer.rasi
|
THEME_FILE := subminer.rasi
|
||||||
PLUGIN_LUA := plugin/subminer.lua
|
PLUGIN_LUA := plugin/subminer.lua
|
||||||
PLUGIN_CONF := plugin/subminer.conf
|
PLUGIN_CONF := plugin/subminer.conf
|
||||||
@@ -181,7 +182,7 @@ install-linux: build-launcher
|
|||||||
@install -d "$(BINDIR)"
|
@install -d "$(BINDIR)"
|
||||||
@install -m 0755 "./$(APP_NAME)" "$(BINDIR)/$(APP_NAME)"
|
@install -m 0755 "./$(APP_NAME)" "$(BINDIR)/$(APP_NAME)"
|
||||||
@install -d "$(LINUX_DATA_DIR)/themes"
|
@install -d "$(LINUX_DATA_DIR)/themes"
|
||||||
@install -m 0644 "./$(THEME_FILE)" "$(LINUX_DATA_DIR)/themes/$(THEME_FILE)"
|
@install -m 0644 "./$(THEME_SOURCE)" "$(LINUX_DATA_DIR)/themes/$(THEME_FILE)"
|
||||||
@if [ -n "$(APPIMAGE_SRC)" ]; then \
|
@if [ -n "$(APPIMAGE_SRC)" ]; then \
|
||||||
install -m 0755 "$(APPIMAGE_SRC)" "$(BINDIR)/SubMiner.AppImage"; \
|
install -m 0755 "$(APPIMAGE_SRC)" "$(BINDIR)/SubMiner.AppImage"; \
|
||||||
else \
|
else \
|
||||||
@@ -195,7 +196,7 @@ install-macos: build-launcher
|
|||||||
@install -d "$(BINDIR)"
|
@install -d "$(BINDIR)"
|
||||||
@install -m 0755 "./$(APP_NAME)" "$(BINDIR)/$(APP_NAME)"
|
@install -m 0755 "./$(APP_NAME)" "$(BINDIR)/$(APP_NAME)"
|
||||||
@install -d "$(MACOS_DATA_DIR)/themes"
|
@install -d "$(MACOS_DATA_DIR)/themes"
|
||||||
@install -m 0644 "./$(THEME_FILE)" "$(MACOS_DATA_DIR)/themes/$(THEME_FILE)"
|
@install -m 0644 "./$(THEME_SOURCE)" "$(MACOS_DATA_DIR)/themes/$(THEME_FILE)"
|
||||||
@install -d "$(MACOS_APP_DIR)"
|
@install -d "$(MACOS_APP_DIR)"
|
||||||
@if [ -n "$(MACOS_APP_SRC)" ]; then \
|
@if [ -n "$(MACOS_APP_SRC)" ]; then \
|
||||||
rm -rf "$(MACOS_APP_DEST)"; \
|
rm -rf "$(MACOS_APP_DEST)"; \
|
||||||
|
|||||||
150
README.md
150
README.md
@@ -1,139 +1,95 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="assets/SubMiner.png" width="169" alt="SubMiner logo">
|
<img src="assets/SubMiner.png" width="169" alt="SubMiner logo">
|
||||||
<h1>SubMiner</h1>
|
<h1>SubMiner</h1>
|
||||||
<p>Immersion mining overlay for mpv — look up words, mine to Anki, and enrich cards with context without leaving the video.</p>
|
<strong>Look up words, mine to Anki, and enrich cards with context — without leaving mpv.</strong>
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||||
|
[]()
|
||||||
|
[](https://docs.subminer.moe)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
---
|
<br />
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
[](https://github.com/user-attachments/assets/9235a554-ea51-4284-b14b-7bbf3defaf58)
|
[](https://github.com/user-attachments/assets/9235a554-ea51-4284-b14b-7bbf3defaf58)
|
||||||
|
|
||||||
## Features
|
_Click to watch the demo_
|
||||||
|
|
||||||
- **Yomitan Integration** — Hover subtitle words to trigger dictionary lookups in the player
|
</div>
|
||||||
- **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
|
|
||||||
- **Queue Control In-Player** — Drop videos on overlay to load/queue in mpv; `Ctrl/Cmd+A` appends clipboard path
|
|
||||||
- **Keyboard-Driven** — Mine, copy, cycle display modes, and navigate from configurable shortcuts
|
|
||||||
- **Config Hot Reload** — Apply subtitle style and shortcut updates from `config.jsonc` without restarting
|
|
||||||
- **Japanese Tokenization** — MeCab-powered word boundary detection with smart grouping
|
|
||||||
|
|
||||||
## Requirements
|
<br />
|
||||||
|
|
||||||
- `mpv` with IPC socket support
|
## What it does
|
||||||
- `mecab` and `mecab-ipadic`
|
|
||||||
- Linux: Hyprland (`hyprctl`) or X11 (`xdotool` + `xwininfo`)
|
|
||||||
- macOS: Accessibility permission for window tracking
|
|
||||||
|
|
||||||
Optional: `yt-dlp`, `fzf`, `rofi`, `chafa`, `ffmpegthumbnailer`
|
SubMiner is an Electron overlay that sits on top of mpv. It turns your video player into a full sentence-mining workstation:
|
||||||
|
|
||||||
## Install
|
- **Hover to look up** — Yomitan dictionary popups directly on subtitles
|
||||||
|
- **One-key mining** — Creates Anki cards with sentence, audio, screenshot, and translation
|
||||||
|
- **N+1 highlighting** — Marks known words from your Anki deck so unknown ones jump out
|
||||||
|
- **Subtitle tools** — Download from Jimaku, sync with alass/ffsubsync, all in-player
|
||||||
|
- **Immersion tracking** — SQLite-powered stats on your watch time and mining activity
|
||||||
|
- **Texthooker page built in** — WebSocket streaming to external tools, no extra setup
|
||||||
|
|
||||||
### Linux (AppImage)
|
## Quick start
|
||||||
|
|
||||||
|
### 1. Install
|
||||||
|
|
||||||
|
**Linux (AppImage):**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/ksyasuda/SubMiner/releases/download/v0.1.0/SubMiner-0.1.0.AppImage -O ~/.local/bin/SubMiner.AppImage
|
wget https://github.com/ksyasuda/SubMiner/releases/latest/download/SubMiner-0.1.0.AppImage -O ~/.local/bin/SubMiner.AppImage
|
||||||
chmod +x ~/.local/bin/SubMiner.AppImage
|
chmod +x ~/.local/bin/SubMiner.AppImage
|
||||||
wget https://github.com/ksyasuda/SubMiner/releases/download/v0.1.0/subminer -O ~/.local/bin/subminer
|
wget https://github.com/ksyasuda/SubMiner/releases/latest/download/subminer -O ~/.local/bin/subminer
|
||||||
chmod +x ~/.local/bin/subminer
|
chmod +x ~/.local/bin/subminer
|
||||||
```
|
```
|
||||||
|
|
||||||
The `subminer` wrapper uses a [Bun](https://bun.sh) shebang, so `bun` must be on `PATH`.
|
> [!NOTE]
|
||||||
|
> The `subminer` wrapper uses a [Bun](https://bun.sh) shebang. Make sure `bun` is on your `PATH`.
|
||||||
|
|
||||||
### From Source
|
**From source** or **macOS** — see the [installation guide](https://docs.subminer.moe/installation#from-source).
|
||||||
|
|
||||||
|
### 2. Install the mpv plugin and configuration file
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone --recurse-submodules https://github.com/ksyasuda/SubMiner.git
|
wget https://github.com/ksyasuda/SubMiner/releases/latest/download/subminer-assets-0.1.0.tar.gz -O /tmp/subminer-assets.tar.gz
|
||||||
cd SubMiner
|
tar -xzf /tmp/subminer-assets.tar.gz -C /tmp
|
||||||
bun install
|
cp /tmp/plugin/subminer.lua ~/.config/mpv/scripts/
|
||||||
cd vendor/texthooker-ui && pnpm install --frozen-lockfile && cd ../..
|
cp /tmp/plugin/subminer.conf ~/.config/mpv/script-opts/
|
||||||
make build
|
mkdir -p ~/.config/SubMiner && cp /tmp/config.example.jsonc ~/.config/SubMiner/config.jsonc
|
||||||
make install
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For macOS builds and platform details, see the [installation docs](docs/installation.md).
|
### 3. Set up Yomitan Dictionaries
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
1. Copy [`config.example.jsonc`](config.example.jsonc) to `~/.config/SubMiner/config.jsonc`
|
|
||||||
- Regenerate anytime from source: `make generate-example-config` or `bun run generate:config-example`
|
|
||||||
2. Start mpv with IPC:
|
|
||||||
```bash
|
|
||||||
mpv --input-ipc-server=/tmp/subminer-socket video.mkv
|
|
||||||
```
|
|
||||||
3. Launch SubMiner:
|
|
||||||
```bash
|
|
||||||
subminer --start video.mkv
|
|
||||||
SubMiner.AppImage --background # tray/background mode (desktop launcher default)
|
|
||||||
```
|
|
||||||
|
|
||||||
Config tip: while SubMiner is running, safe config edits (subtitle style, keybindings, shortcuts, secondary subtitle default mode, and `ankiConnect.ai`) hot-reload automatically.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
subminer # pick video from cwd (fzf)
|
subminer app --start --yomitan
|
||||||
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
|
|
||||||
subminer jellyfin -d # Jellyfin cast discovery mode
|
|
||||||
subminer doctor # dependency/config/socket diagnostics
|
|
||||||
subminer config path # print active config file path
|
|
||||||
subminer mpv status # mpv socket readiness check
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Launcher Subcommands
|
### 4. Mine
|
||||||
|
|
||||||
- `subminer jellyfin` / `subminer jf` — Jellyfin workflows (`-d` discovery, `-p` play, `-l` login)
|
|
||||||
- `subminer yt` / `subminer youtube` — YouTube shorthand (`-o/--out-dir`, `-m/--mode`)
|
|
||||||
- `subminer doctor` — quick environment health checks
|
|
||||||
- `subminer config path|show` — inspect active config path/content
|
|
||||||
- `subminer mpv status|socket|idle` — mpv socket and idle-launch helpers
|
|
||||||
- `subminer texthooker` — texthooker-only shortcut
|
|
||||||
|
|
||||||
Use `subminer <subcommand> -h` for command-specific help pages (for example `subminer jellyfin -h`).
|
|
||||||
|
|
||||||
### CLI Logging and Dev Mode
|
|
||||||
|
|
||||||
- Use `--log-level` to control logger verbosity (for example `--log-level debug`).
|
|
||||||
- Use `--dev` and `--debug` only for app/dev-mode behavior; they are not tied to logging level.
|
|
||||||
- Default logging is `info`, except `--background` mode defaults to `warn` unless `--log-level` is set.
|
|
||||||
|
|
||||||
### Overlay Queue Controls
|
|
||||||
|
|
||||||
- Drag/drop video file(s) onto overlay:
|
|
||||||
- default: replace current playback with first file, append remaining dropped files
|
|
||||||
- hold `Shift`: append all dropped files
|
|
||||||
- Press `Ctrl/Cmd+A` to append the clipboard path when it points to a readable local video file.
|
|
||||||
|
|
||||||
## MPV Plugin
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp plugin/subminer.lua ~/.config/mpv/scripts/
|
subminer app --start --background
|
||||||
cp plugin/subminer.conf ~/.config/mpv/script-opts/
|
subminer video.mkv
|
||||||
# or: make install-plugin
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Default chord prefix: `y` (`y-y` menu, `y-s` start, `y-S` stop, `y-t` toggle overlay).
|
## Requirements
|
||||||
Jimaku shortcut: `Ctrl+Shift+J`.
|
|
||||||
|
| Required | Optional |
|
||||||
|
| ------------------------------------------ | ---------------------------- |
|
||||||
|
| `mpv` with IPC socket | `yt-dlp` |
|
||||||
|
| `mecab` + `mecab-ipadic` | `fzf` / `rofi` |
|
||||||
|
| Linux: `hyprctl` or `xdotool` + `xwininfo` | `chafa`, `ffmpegthumbnailer` |
|
||||||
|
| macOS: Accessibility permission | |
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
Full guides at [**docs/**](docs/README.md):
|
For full guides on configuration, Anki, Jellyfin, and more, see [docs.subminer.moe](https://docs.subminer.moe).
|
||||||
[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)
|
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
- [GameSentenceMiner](https://github.com/bpwhelan/GameSentenceMiner) — Inspiration for the overlay and Yomitan integration
|
Built on the shoulders of [GameSentenceMiner](https://github.com/bpwhelan/GameSentenceMiner), [mpvacious](https://github.com/Ajatt-Tools/mpvacious), [Anacreon-Script](https://github.com/friedrich-de/Anacreon-Script), and [autosubsync-mpv](https://github.com/joaquintorres/autosubsync-mpv). Subtitles powered by [Jimaku.cc](https://jimaku.cc). Dictionary lookups via [Yomitan](https://github.com/yomidevs/yomitan).
|
||||||
- [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
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
mantle: #1e2030;
|
mantle: #1e2030;
|
||||||
crust: #181926;
|
crust: #181926;
|
||||||
|
|
||||||
background-color: @base;
|
background-color: @mantle;
|
||||||
text-color: @text;
|
text-color: @text;
|
||||||
accent: @mauve;
|
accent: @mauve;
|
||||||
}
|
}
|
||||||
@@ -37,25 +37,26 @@ configuration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window {
|
window {
|
||||||
width: 88%;
|
width: 69%;
|
||||||
height: 88%;
|
height: 69%;
|
||||||
background-color: @base;
|
background-color: @mantle;
|
||||||
border: 2px;
|
border: 1px;
|
||||||
border-color: @mauve;
|
border-color: @surface1;
|
||||||
border-radius: 8px;
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
mainbox {
|
mainbox {
|
||||||
children: [inputbar, listview-split];
|
children: [inputbar, listview-split];
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
inputbar {
|
inputbar {
|
||||||
children: [prompt, entry];
|
children: [prompt, entry];
|
||||||
background-color: @surface0;
|
background-color: @base;
|
||||||
padding: 12px;
|
padding: 14px 18px;
|
||||||
border-radius: 4px;
|
border-radius: 8px;
|
||||||
margin: 8px;
|
margin: 4px 4px 0px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
prompt {
|
prompt {
|
||||||
@@ -73,53 +74,60 @@ entry {
|
|||||||
listview-split {
|
listview-split {
|
||||||
orientation: horizontal;
|
orientation: horizontal;
|
||||||
children: [listview];
|
children: [listview];
|
||||||
spacing: 8px;
|
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
listview {
|
listview {
|
||||||
columns: 1;
|
columns: 1;
|
||||||
lines: 12;
|
lines: 14;
|
||||||
scrollbar: true;
|
scrollbar: true;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
padding: 4px;
|
padding: 6px 4px;
|
||||||
fixed-columns: true;
|
fixed-columns: true;
|
||||||
|
spacing: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
element {
|
element {
|
||||||
padding: 4px 8px;
|
padding: 10px 14px;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
element normal.normal {
|
element normal.normal {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
text-color: @text;
|
text-color: @subtext1;
|
||||||
|
}
|
||||||
|
|
||||||
|
element alternate.normal {
|
||||||
|
background-color: transparent;
|
||||||
|
text-color: @subtext1;
|
||||||
}
|
}
|
||||||
|
|
||||||
element selected.normal {
|
element selected.normal {
|
||||||
background-color: @surface1;
|
background-color: @base;
|
||||||
text-color: @mauve;
|
text-color: @text;
|
||||||
border: 2px;
|
border: 0px 0px 0px 3px;
|
||||||
border-color: @mauve;
|
border-color: @mauve;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
element-icon {
|
element-icon {
|
||||||
size: 128px;
|
size: 48px;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
margin: 0px 4px;
|
margin: 0px 10px 0px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
element-text {
|
element-text {
|
||||||
text-color: inherit;
|
text-color: inherit;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
margin: 50px 0 0 0;
|
vertical-align: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollbar {
|
scrollbar {
|
||||||
width: 4px;
|
width: 3px;
|
||||||
handle-color: @surface2;
|
handle-color: @surface2;
|
||||||
handle-width: 4px;
|
handle-width: 3px;
|
||||||
background-color: @surface0;
|
background-color: transparent;
|
||||||
|
margin: 4px 0px 4px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
@@ -63,6 +63,7 @@ export default {
|
|||||||
items: [
|
items: [
|
||||||
{ text: 'Overview', link: '/' },
|
{ text: 'Overview', link: '/' },
|
||||||
{ text: 'Installation', link: '/installation' },
|
{ text: 'Installation', link: '/installation' },
|
||||||
|
{ text: 'Launcher Script', link: '/launcher-script' },
|
||||||
{ text: 'Usage', link: '/usage' },
|
{ text: 'Usage', link: '/usage' },
|
||||||
{ text: 'Mining Workflow', link: '/mining-workflow' },
|
{ text: 'Mining Workflow', link: '/mining-workflow' },
|
||||||
],
|
],
|
||||||
@@ -88,6 +89,9 @@ export default {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
search: {
|
||||||
|
provider: 'local',
|
||||||
|
},
|
||||||
socialLinks: [{ icon: 'github', link: 'https://github.com/ksyasuda/SubMiner' }],
|
socialLinks: [{ icon: 'github', link: 'https://github.com/ksyasuda/SubMiner' }],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
97
docs/launcher-script.md
Normal file
97
docs/launcher-script.md
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# Launcher Script
|
||||||
|
|
||||||
|
The `subminer` wrapper script is an all-in-one launcher that handles video selection, mpv startup, and overlay management. It's a Bun script distributed alongside the AppImage.
|
||||||
|
|
||||||
|
## Video Picker
|
||||||
|
|
||||||
|
When you run `subminer` without specifying a file, it opens an interactive video picker. By default it uses **fzf** in the terminal; pass `-R` to use **rofi** instead.
|
||||||
|
|
||||||
|
### fzf (default)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
subminer # pick from current directory
|
||||||
|
subminer -d ~/Videos # pick from a specific directory
|
||||||
|
subminer -r -d ~/Anime # recursive search
|
||||||
|
```
|
||||||
|
|
||||||
|
fzf shows video files in a fuzzy-searchable list. If `chafa` is installed, you get thumbnail previews in the right pane. Thumbnails are sourced from the freedesktop thumbnail cache first, then generated on the fly with `ffmpegthumbnailer` or `ffmpeg` as fallback.
|
||||||
|
|
||||||
|
| Optional tool | Purpose |
|
||||||
|
| --------------------- | -------------------------------- |
|
||||||
|
| `chafa` | Render thumbnails in the terminal |
|
||||||
|
| `ffmpegthumbnailer` | Generate thumbnails on the fly |
|
||||||
|
|
||||||
|
### rofi
|
||||||
|
|
||||||
|
```bash
|
||||||
|
subminer -R # rofi picker, current directory
|
||||||
|
subminer -R -d ~/Videos # rofi picker, specific directory
|
||||||
|
subminer -R -r -d ~/Anime # rofi picker, recursive
|
||||||
|
```
|
||||||
|
|
||||||
|
rofi shows a GUI menu with icon thumbnails when available. SubMiner ships a custom rofi theme that can be installed from the release assets:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/.local/share/SubMiner/themes
|
||||||
|
cp /tmp/assets/themes/subminer.rasi ~/.local/share/SubMiner/themes/subminer.rasi
|
||||||
|
```
|
||||||
|
|
||||||
|
The theme is auto-detected from these paths (first match wins):
|
||||||
|
|
||||||
|
- `$SUBMINER_ROFI_THEME` environment variable (absolute path)
|
||||||
|
- `$XDG_DATA_HOME/SubMiner/themes/subminer.rasi` (default: `~/.local/share/SubMiner/themes/subminer.rasi`)
|
||||||
|
- `/usr/local/share/SubMiner/themes/subminer.rasi`
|
||||||
|
- `/usr/share/SubMiner/themes/subminer.rasi`
|
||||||
|
- macOS: `~/Library/Application Support/SubMiner/themes/subminer.rasi`
|
||||||
|
|
||||||
|
Override with the `SUBMINER_ROFI_THEME` environment variable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SUBMINER_ROFI_THEME=/path/to/custom-theme.rasi subminer -R
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
subminer video.mkv # play a specific file
|
||||||
|
subminer --start video.mkv # play + explicitly start overlay
|
||||||
|
subminer https://youtu.be/... # YouTube playback (requires yt-dlp)
|
||||||
|
subminer ytsearch:"jp news" # YouTube search
|
||||||
|
```
|
||||||
|
|
||||||
|
## Subcommands
|
||||||
|
|
||||||
|
| Subcommand | Purpose |
|
||||||
|
| ------------------------- | ---------------------------------------------- |
|
||||||
|
| `subminer jellyfin` / `jf` | Jellyfin workflows (`-d` discovery, `-p` play, `-l` login) |
|
||||||
|
| `subminer yt` / `youtube` | YouTube shorthand (`-o`, `-m`) |
|
||||||
|
| `subminer doctor` | Dependency + config + socket diagnostics |
|
||||||
|
| `subminer config path` | Print active config file path |
|
||||||
|
| `subminer config show` | Print active config contents |
|
||||||
|
| `subminer mpv status` | Check mpv socket readiness |
|
||||||
|
| `subminer mpv socket` | Print active socket path |
|
||||||
|
| `subminer mpv idle` | Launch detached idle mpv instance |
|
||||||
|
| `subminer texthooker` | Launch texthooker-only mode |
|
||||||
|
| `subminer app` | Pass arguments directly to SubMiner binary |
|
||||||
|
|
||||||
|
Use `subminer <subcommand> -h` for command-specific help.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
| Flag | Description |
|
||||||
|
| -------------------- | -------------------------------------------- |
|
||||||
|
| `-d, --directory` | Video search directory (default: cwd) |
|
||||||
|
| `-r, --recursive` | Search directories recursively |
|
||||||
|
| `-R, --rofi` | Use rofi instead of fzf |
|
||||||
|
| `-S, --start` | Start overlay after mpv launches |
|
||||||
|
| `-T, --no-texthooker`| Disable texthooker server |
|
||||||
|
| `-p, --profile` | mpv profile name (default: `subminer`) |
|
||||||
|
| `-b, --backend` | Force window backend (`hyprland`, `sway`, `x11`) |
|
||||||
|
| `--log-level` | Logger verbosity (`debug`, `info`, `warn`, `error`) |
|
||||||
|
| `--dev`, `--debug` | Enable app dev-mode (not tied to log level) |
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
- Default log level is `info`
|
||||||
|
- `--background` mode defaults to `warn` unless `--log-level` is explicitly set
|
||||||
|
- `--dev` / `--debug` control app behavior, not logging verbosity — use `--log-level` for that
|
||||||
@@ -86,7 +86,24 @@ This is the most common flow. Yomitan creates a card in Anki, and SubMiner detec
|
|||||||
|
|
||||||
Configure which fields to fill in `ankiConnect.fields`. See [Anki Integration](/anki-integration) for details.
|
Configure which fields to fill in `ankiConnect.fields`. See [Anki Integration](/anki-integration) for details.
|
||||||
|
|
||||||
### 2. Mine Sentence (Hotkey)
|
### 2. Manual Update from Clipboard
|
||||||
|
|
||||||
|
If you prefer a hands-on approach (animecards-style), you can copy the current subtitle to the clipboard and then paste it onto the last-added Anki card:
|
||||||
|
|
||||||
|
1. Add a word via Yomitan as usual.
|
||||||
|
2. Press `Ctrl/Cmd+C` to copy the current subtitle line to the clipboard.
|
||||||
|
- For multiple lines: press `Ctrl/Cmd+Shift+C`, then a digit `1`–`9` to select how many recent subtitle lines to combine. The combined text is copied to the clipboard.
|
||||||
|
3. Press `Ctrl/Cmd+V` to update the last-added card with the clipboard contents plus audio, image, and translation — the same fields auto-update would fill.
|
||||||
|
|
||||||
|
This is useful when auto-update polling is disabled or when you want explicit control over which subtitle line gets attached to the card.
|
||||||
|
|
||||||
|
| Shortcut | Action | Config key |
|
||||||
|
| --------------------------- | ----------------------------------------- | ------------------------------------- |
|
||||||
|
| `Ctrl/Cmd+C` | Copy current subtitle | `shortcuts.copySubtitle` |
|
||||||
|
| `Ctrl/Cmd+Shift+C` + digit | Copy multiple recent lines | `shortcuts.copySubtitleMultiple` |
|
||||||
|
| `Ctrl/Cmd+V` | Update last card from clipboard | `shortcuts.updateLastCardFromClipboard` |
|
||||||
|
|
||||||
|
### 3. Mine Sentence (Hotkey)
|
||||||
|
|
||||||
Create a standalone sentence card without going through Yomitan:
|
Create a standalone sentence card without going through Yomitan:
|
||||||
|
|
||||||
@@ -95,7 +112,7 @@ Create a standalone sentence card without going through Yomitan:
|
|||||||
|
|
||||||
The sentence card uses the note type configured in `isLapis.sentenceCardModel` and always maps sentence/audio to `Sentence` and `SentenceAudio`.
|
The sentence card uses the note type configured in `isLapis.sentenceCardModel` and always maps sentence/audio to `Sentence` and `SentenceAudio`.
|
||||||
|
|
||||||
### 3. Mark as Audio Card
|
### 4. Mark as Audio Card
|
||||||
|
|
||||||
After adding a word via Yomitan, press the audio card shortcut to overwrite the audio with a longer clip spanning the full subtitle timing.
|
After adding a word via Yomitan, press the audio card shortcut to overwrite the audio with a longer clip spanning the full subtitle timing.
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ All shortcuts are configurable in `config.jsonc` under `shortcuts` and `keybindi
|
|||||||
These work system-wide regardless of which window has focus.
|
These work system-wide regardless of which window has focus.
|
||||||
|
|
||||||
| Shortcut | Action | Configurable |
|
| Shortcut | Action | Configurable |
|
||||||
| -------- | ------ | ------------ |
|
| ------------- | ------------------------ | ---------------------------------------- |
|
||||||
| `Alt+Shift+O` | Toggle visible overlay | `shortcuts.toggleVisibleOverlayGlobal` |
|
| `Alt+Shift+O` | Toggle visible overlay | `shortcuts.toggleVisibleOverlayGlobal` |
|
||||||
| `Alt+Shift+I` | Toggle invisible overlay | `shortcuts.toggleInvisibleOverlayGlobal` |
|
| `Alt+Shift+I` | Toggle invisible overlay | `shortcuts.toggleInvisibleOverlayGlobal` |
|
||||||
| `Alt+Shift+Y` | Open Yomitan settings | Fixed (not configurable) |
|
| `Alt+Shift+Y` | Open Yomitan settings | Fixed (not configurable) |
|
||||||
@@ -21,7 +21,7 @@ Global shortcuts are registered with the OS. If they conflict with another appli
|
|||||||
These work when the overlay window has focus.
|
These work when the overlay window has focus.
|
||||||
|
|
||||||
| Shortcut | Action | Config key |
|
| Shortcut | Action | Config key |
|
||||||
| -------- | ------ | ---------- |
|
| ------------------ | ----------------------------------------------- | --------------------------------------- |
|
||||||
| `Ctrl/Cmd+S` | Mine current subtitle as sentence card | `shortcuts.mineSentence` |
|
| `Ctrl/Cmd+S` | Mine current subtitle as sentence card | `shortcuts.mineSentence` |
|
||||||
| `Ctrl/Cmd+Shift+S` | Mine multiple lines (press 1–9 to select count) | `shortcuts.mineSentenceMultiple` |
|
| `Ctrl/Cmd+Shift+S` | Mine multiple lines (press 1–9 to select count) | `shortcuts.mineSentenceMultiple` |
|
||||||
| `Ctrl/Cmd+C` | Copy current subtitle text | `shortcuts.copySubtitle` |
|
| `Ctrl/Cmd+C` | Copy current subtitle text | `shortcuts.copySubtitle` |
|
||||||
@@ -37,7 +37,7 @@ The multi-line shortcuts open a digit selector with a 3-second timeout (`shortcu
|
|||||||
These control playback and subtitle display. They require overlay window focus.
|
These control playback and subtitle display. They require overlay window focus.
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| -------- | ------ |
|
| -------------------- | -------------------------------------------------- |
|
||||||
| `Space` | Toggle mpv pause |
|
| `Space` | Toggle mpv pause |
|
||||||
| `ArrowRight` | Seek forward 5 seconds |
|
| `ArrowRight` | Seek forward 5 seconds |
|
||||||
| `ArrowLeft` | Seek backward 5 seconds |
|
| `ArrowLeft` | Seek backward 5 seconds |
|
||||||
@@ -58,7 +58,7 @@ These keybindings can be overridden or disabled via the `keybindings` config arr
|
|||||||
## Subtitle & Feature Shortcuts
|
## Subtitle & Feature Shortcuts
|
||||||
|
|
||||||
| Shortcut | Action | Config key |
|
| Shortcut | Action | Config key |
|
||||||
| -------- | ------ | ---------- |
|
| ------------------ | -------------------------------------------------------- | ------------------------------ |
|
||||||
| `Ctrl/Cmd+Shift+V` | Cycle secondary subtitle mode (hidden → visible → hover) | `shortcuts.toggleSecondarySub` |
|
| `Ctrl/Cmd+Shift+V` | Cycle secondary subtitle mode (hidden → visible → hover) | `shortcuts.toggleSecondarySub` |
|
||||||
| `Ctrl/Cmd+Shift+O` | Open runtime options palette | `shortcuts.openRuntimeOptions` |
|
| `Ctrl/Cmd+Shift+O` | Open runtime options palette | `shortcuts.openRuntimeOptions` |
|
||||||
| `Ctrl+Shift+J` | Open Jimaku subtitle search modal | `shortcuts.openJimaku` |
|
| `Ctrl+Shift+J` | Open Jimaku subtitle search modal | `shortcuts.openJimaku` |
|
||||||
@@ -69,7 +69,7 @@ These keybindings can be overridden or disabled via the `keybindings` config arr
|
|||||||
Enter edit mode to fine-tune invisible overlay alignment with mpv's native subtitles.
|
Enter edit mode to fine-tune invisible overlay alignment with mpv's native subtitles.
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| -------- | ------ |
|
| --------------------- | -------------------------------- |
|
||||||
| `Ctrl/Cmd+Shift+P` | Toggle position edit mode |
|
| `Ctrl/Cmd+Shift+P` | Toggle position edit mode |
|
||||||
| `ArrowKeys` or `hjkl` | Nudge position by 1 px |
|
| `ArrowKeys` or `hjkl` | Nudge position by 1 px |
|
||||||
| `Shift+Arrow` | Nudge position by 4 px |
|
| `Shift+Arrow` | Nudge position by 4 px |
|
||||||
@@ -81,7 +81,7 @@ Enter edit mode to fine-tune invisible overlay alignment with mpv's native subti
|
|||||||
When the mpv plugin is installed, all commands use a `y` chord prefix — press `y`, then the second key within 1 second.
|
When the mpv plugin is installed, all commands use a `y` chord prefix — press `y`, then the second key within 1 second.
|
||||||
|
|
||||||
| Chord | Action |
|
| Chord | Action |
|
||||||
| ----- | ------ |
|
| ----- | --------------------------------------- |
|
||||||
| `y-y` | Open SubMiner menu (OSD) |
|
| `y-y` | Open SubMiner menu (OSD) |
|
||||||
| `y-s` | Start overlay |
|
| `y-s` | Start overlay |
|
||||||
| `y-S` | Stop overlay |
|
| `y-S` | Stop overlay |
|
||||||
@@ -97,13 +97,13 @@ When the mpv plugin is installed, all commands use a `y` chord prefix — press
|
|||||||
## Drag-and-Drop
|
## Drag-and-Drop
|
||||||
|
|
||||||
| Gesture | Action |
|
| Gesture | Action |
|
||||||
| ------- | ------ |
|
| ------------------------- | ------------------------------------------------ |
|
||||||
| Drop file(s) onto overlay | Replace current mpv playlist with dropped files |
|
| Drop file(s) onto overlay | Replace current mpv playlist with dropped files |
|
||||||
| `Shift` + drop file(s) | Append all dropped files to current mpv playlist |
|
| `Shift` + drop file(s) | Append all dropped files to current mpv playlist |
|
||||||
|
|
||||||
## Customizing Shortcuts
|
## Customizing Shortcuts
|
||||||
|
|
||||||
All `shortcuts.*` keys accept [Electron accelerator strings](https://www.electronjs.org/docs/latest/api/accelerator), for example `"CommandOrControl+Shift+M"`. Use `null` to disable a shortcut.
|
All `shortcuts.*` keys accept [Electron accelerator strings](https://www.electronjs.org/docs/latest/tutorial/keyboard-shortcuts), for example `"CommandOrControl+Shift+M"`. Use `null` to disable a shortcut.
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
{
|
{
|
||||||
@@ -112,8 +112,8 @@ All `shortcuts.*` keys accept [Electron accelerator strings](https://www.electro
|
|||||||
"copySubtitle": "CommandOrControl+C",
|
"copySubtitle": "CommandOrControl+C",
|
||||||
"toggleVisibleOverlayGlobal": "Alt+Shift+O",
|
"toggleVisibleOverlayGlobal": "Alt+Shift+O",
|
||||||
"toggleInvisibleOverlayGlobal": "Alt+Shift+I",
|
"toggleInvisibleOverlayGlobal": "Alt+Shift+I",
|
||||||
"openJimaku": null // disabled
|
"openJimaku": null, // disabled
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -124,8 +124,8 @@ The `keybindings` array overrides or extends the overlay's built-in key handling
|
|||||||
"keybindings": [
|
"keybindings": [
|
||||||
{ "key": "f", "command": ["cycle", "fullscreen"] },
|
{ "key": "f", "command": ["cycle", "fullscreen"] },
|
||||||
{ "key": "m", "command": ["cycle", "mute"] },
|
{ "key": "m", "command": ["cycle", "mute"] },
|
||||||
{ "key": "Space", "command": null } // disable default Space → pause
|
{ "key": "Space", "command": null }, // disable default Space → pause
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Agent Log — codex-release-mpv-plugin-20260220T035757Z-d4yf
|
||||||
|
|
||||||
|
- alias: `codex-release-mpv-plugin`
|
||||||
|
- mission: `Package optional release assets bundle (mpv plugin + rofi theme), move theme to assets/themes, update install/docs`
|
||||||
|
- status: `completed`
|
||||||
|
- started_utc: `2026-02-20T03:57:57Z`
|
||||||
|
- planned_files: `.github/workflows/release.yml`, `Makefile`, `launcher/picker.ts`, `README.md`, `docs/installation.md`, `docs/mpv-plugin.md`, `assets/themes/subminer.rasi`, `docs/subagents/INDEX.md`, `docs/subagents/agents/codex-release-mpv-plugin-20260220T035757Z-d4yf.md`
|
||||||
|
- assumptions:
|
||||||
|
- `Backlog.md` not configured in repo root (no backlog ticket linkage required).
|
||||||
|
- change limited to release asset generation/upload; no app packaging behavior changes.
|
||||||
|
- notes:
|
||||||
|
- [2026-02-20T03:58:30Z] context loaded; proceeding with workflow-only patch.
|
||||||
|
- [2026-02-20T03:58:36Z] edit: added `Package mpv plugin` step to release job; emits `release/subminer-mpv-plugin-<tag>.tar.gz`.
|
||||||
|
- [2026-02-20T03:58:36Z] edit: checksum input now includes `release/*.tar.gz`; release upload globs now include `release/*.tar.gz`.
|
||||||
|
- [2026-02-20T03:58:36Z] edit: release body now includes optional mpv plugin install steps.
|
||||||
|
- [2026-02-20T03:58:36Z] validation: reviewed workflow diff only; no runtime tests executed (CI-config change).
|
||||||
|
- [2026-02-20T03:58:36Z] handoff: ready to merge; preserves existing AppImage/DMG/ZIP flow.
|
||||||
|
- [2026-02-20T04:00:49Z] scope expanded per user request: include default rofi theme, choose `assets/themes` location, update CI/install/docs/readme.
|
||||||
|
- [2026-02-20T04:00:49Z] edit: moved `subminer.rasi` -> `assets/themes/subminer.rasi`; patched Makefile theme install source.
|
||||||
|
- [2026-02-20T04:00:49Z] edit: patched launcher theme discovery to include `<scriptDir>/assets/themes/subminer.rasi` before legacy fallback.
|
||||||
|
- [2026-02-20T04:00:49Z] edit: release bundle renamed to `subminer-assets-<tag>.tar.gz` including plugin + theme; release notes updated.
|
||||||
|
- [2026-02-20T04:00:49Z] edit: docs/readme install snippets updated for new assets bundle path.
|
||||||
|
- [2026-02-20T04:02:26Z] validation: `bun run build` pass.
|
||||||
|
- [2026-02-20T04:02:26Z] handoff: release/install/docs now align on `assets/themes/subminer.rasi` + `subminer-assets-<tag>.tar.gz`.
|
||||||
@@ -366,6 +366,8 @@ export function findRofiTheme(scriptPath: string): string | null {
|
|||||||
candidates.push(path.join('/usr/share/SubMiner/themes', ROFI_THEME_FILE));
|
candidates.push(path.join('/usr/share/SubMiner/themes', ROFI_THEME_FILE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
candidates.push(path.join(scriptDir, 'assets', 'themes', ROFI_THEME_FILE));
|
||||||
|
candidates.push(path.join(scriptDir, 'themes', ROFI_THEME_FILE));
|
||||||
candidates.push(path.join(scriptDir, ROFI_THEME_FILE));
|
candidates.push(path.join(scriptDir, ROFI_THEME_FILE));
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
|
|||||||
Reference in New Issue
Block a user