diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml
index 95e149cb..8818ca4e 100644
--- a/.github/workflows/prerelease.yml
+++ b/.github/workflows/prerelease.yml
@@ -148,7 +148,7 @@ jobs:
name: appimage
path: |
release/*.AppImage
- release/*.yml
+ release/latest*.yml
release/*.blockmap
if-no-files-found: error
@@ -226,7 +226,7 @@ jobs:
path: |
release/*.dmg
release/*.zip
- release/*.yml
+ release/latest*.yml
release/*.blockmap
if-no-files-found: error
@@ -279,7 +279,7 @@ jobs:
path: |
release/*.exe
release/*.zip
- release/*.yml
+ release/latest*.yml
release/*.blockmap
if-no-files-found: error
@@ -353,7 +353,7 @@ jobs:
- name: Generate checksums
run: |
shopt -s nullglob
- files=(release/*.AppImage release/*.dmg release/*.exe release/*.zip release/*.tar.gz release/*.yml release/*.blockmap dist/launcher/subminer)
+ files=(release/*.AppImage release/*.dmg release/*.exe release/*.zip release/*.tar.gz release/latest*.yml release/*.blockmap dist/launcher/subminer)
if [ "${#files[@]}" -eq 0 ]; then
echo "No release artifacts found for checksum generation."
exit 1
@@ -389,7 +389,7 @@ jobs:
release/*.exe
release/*.zip
release/*.tar.gz
- release/*.yml
+ release/latest*.yml
release/*.blockmap
release/SHA256SUMS.txt
dist/launcher/subminer
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f60d05ad..e1778227 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -139,7 +139,7 @@ jobs:
name: appimage
path: |
release/*.AppImage
- release/*.yml
+ release/latest*.yml
release/*.blockmap
build-macos:
@@ -216,7 +216,7 @@ jobs:
path: |
release/*.dmg
release/*.zip
- release/*.yml
+ release/latest*.yml
release/*.blockmap
build-windows:
@@ -268,7 +268,7 @@ jobs:
path: |
release/*.exe
release/*.zip
- release/*.yml
+ release/latest*.yml
release/*.blockmap
if-no-files-found: error
@@ -342,7 +342,7 @@ jobs:
- name: Generate checksums
run: |
shopt -s nullglob
- files=(release/*.AppImage release/*.dmg release/*.exe release/*.zip release/*.tar.gz release/*.yml release/*.blockmap dist/launcher/subminer)
+ files=(release/*.AppImage release/*.dmg release/*.exe release/*.zip release/*.tar.gz release/latest*.yml release/*.blockmap dist/launcher/subminer)
if [ "${#files[@]}" -eq 0 ]; then
echo "No release artifacts found for checksum generation."
exit 1
@@ -396,7 +396,7 @@ jobs:
release/*.exe
release/*.zip
release/*.tar.gz
- release/*.yml
+ release/latest*.yml
release/*.blockmap
release/SHA256SUMS.txt
dist/launcher/subminer
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f2f50aa1..ab0e125b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,68 +4,151 @@
### Breaking Changes
-- Subsync: The `subsync.defaultMode` config option has been removed; Subsync now always opens the manual subtitle picker regardless of any previously set default mode.
+- **Subsync:**
+ - The `subsync.defaultMode` config option has been removed
+ - Subsync now always opens the manual subtitle picker regardless of any previously set default mode
+- **N+1 Highlighting:**
+ - N+1 highlighting now has its own dedicated `ankiConnect.nPlusOne.enabled` option, separate from known-word highlighting
+ - It is no longer enabled automatically when known-word highlighting is on — enable it explicitly to keep N+1 annotations
### Added
-- Auto-Updater: Adds tray and `subminer -u` update checks with app update prompts, launcher and Linux rofi theme auto-updates, checksum verification, configurable notifications, and an opt-in prerelease channel via `updates.channel: "prerelease"`.
-- Settings Window: New dedicated Settings window via `subminer --settings` or `subminer settings`, organized into Appearance, Behavior, Anki, Input, and Integration sections; click-to-learn keybinding controls including the AniSkip button key; AnkiConnect-backed deck, field, and note-type pickers that auto-fill from the configured Anki deck; cross-category search; and live save for most options including subtitle CSS, stats keys, logging level, Jimaku, Subsync, and Anki mappings. AI and translation settings remain config-file only.
-- Inline Character Portraits: Optional AniList character portraits appear inline for name-matched subtitle text; manual AniList overrides scoped per parent media directory so separate season folders maintain separate character dictionary selections.
-- Log Export: Sanitized log ZIP export from the tray menu and via `subminer logs -e`, with home-directory usernames redacted from exported contents.
-- Launcher CLI: `subminer --version` / `subminer -v` prints the installed app version; `mpv.profile` config and Settings support passes a named mpv profile to managed launches; bundled mpv plugin startup options are now configurable from SubMiner config.
-- First-Run Setup: Optional installer for Bun and the `subminer` CLI on Linux, macOS, and Windows, including a Windows `subminer.cmd` PATH shim so `subminer` works without manually adding `SubMiner.exe` to PATH; setup recognizes existing Homebrew or user PATH installs and avoids writing into Homebrew-owned paths; includes an Open SubMiner Settings button; standalone setup app quits after completing, returning terminal control.
-- Primary Subtitle Visibility on Yomitan Popup: New `subtitleStyle.primaryVisibleOnYomitanPopup` option keeps hover-mode primary subtitles visible while a Yomitan popup is open.
+- **Auto-Updater:**
+ - Tray and `subminer -u` update checks with app update prompts
+ - Launcher and Linux rofi theme auto-updates
+ - Checksum verification and configurable notifications
+ - Opt-in prerelease channel via `updates.channel: "prerelease"`
+- **Settings Window:**
+ - New dedicated Settings window via `subminer --settings` or `subminer settings`, organized into Appearance, Behavior, Anki, Input, and Integration sections
+ - Click-to-learn keybinding controls
+ - AnkiConnect-backed deck, field, and note-type pickers that auto-fill from the configured Anki deck
+ - Cross-category search
+ - Live save for most options including subtitle CSS, stats keys, logging level, Jimaku, Subsync, and Anki mappings
+ - AI and translation settings remain config-file only
+- **Inline Character Portraits:**
+ - Optional AniList character portraits appear inline for name-matched subtitle text
+ - Manual AniList overrides scoped per parent media directory so separate season folders maintain separate character dictionary selections
+- **Character Dictionary Manager:** New `Ctrl/Cmd+D` manager modal to remove, reorder, or override loaded entries.
+- **Log Export:** Sanitized log ZIP export from the tray menu and via `subminer logs -e`, with home-directory usernames redacted from exported contents.
+- **Launcher CLI:**
+ - `subminer --version` / `subminer -v` prints the installed app version
+ - `mpv.profile` config and Settings support passes a named mpv profile to managed launches
+ - Bundled mpv plugin startup options are now configurable from SubMiner config
+- **First-Run Setup:**
+ - Optional installer for Bun and the `subminer` CLI on Linux, macOS, and Windows
+ - Windows `subminer.cmd` PATH shim so `subminer` works without manually adding `SubMiner.exe` to PATH
+ - Setup recognizes existing Homebrew or user PATH installs and avoids writing into Homebrew-owned paths
+ - Includes an Open SubMiner Settings button
+ - Standalone setup app quits after completing, returning terminal control
+- **Primary Subtitle Visibility on Yomitan Popup:** New `subtitleStyle.primaryVisibleOnYomitanPopup` option keeps hover-mode primary subtitles visible while a Yomitan popup is open.
### Changed
-- Subtitle Appearance Config: Primary and secondary subtitle appearance now use color controls plus CSS declaration editors, saved as `subtitleStyle.css`, `subtitleStyle.secondary.css`, and `subtitleSidebar.css`; known-word and N+1 annotation colors moved to `subtitleStyle.knownWordColor` and `subtitleStyle.nPlusOneColor`; subtitle font defaults updated to `Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP`. Existing configs migrate automatically; legacy Anki color keys still accepted with deprecation warnings.
-- Subtitle Style Defaults: Stronger outline-style text shadow, thicker JLPT underlines, and frequency `topX` default raised to `10000`.
-- Character Dictionary: Entries scoped to the current AniList media for name matching and inline portraits; generates Japanese-only name aliases so raw romanized/English aliases no longer surface as separate results; new `Ctrl/Cmd+D` manager modal to remove, reorder, or override loaded entries; in-app AniList selector waits for an explicit search with the box prefilled from the current filename; `subtitleStyle.nameMatchEnabled` is now the sole switch for dictionary sync and builds.
-- Electron Runtime: Updated from 39.8.6 to 42.2.0, returning SubMiner to a supported Electron release line.
-- N+1 Highlighting Default: `ankiConnect.nPlusOne.enabled` is no longer implicitly enabled when known-word highlighting is on; existing configs that already had N+1 enabled are unchanged, but new configs must set it explicitly.
-- Linux Auto-Update Flow: Linux tray "Check for Updates" now installs the new AppImage automatically, matching macOS and Windows; AppImages managed by a system package (e.g. AUR) and non-AppImage launches still use the GitHub-asset flow.
-- Jellyfin Setup: Removed the server presets dropdown; setup now shows a single editable server URL field.
-- Jellyfin Cast Identity: Device identity now derived from the OS hostname and always reported as SubMiner; previously configurable identity fields are ignored, preventing multiple installs from sharing a remote-session identity.
-- Startup Defaults: Jellyfin remote-session startup warmup and character-name subtitle highlighting now default to off.
-- Setup Appearance: Removed the bundled mpv runtime plugin readiness card from the setup flow.
+- **Subtitle Appearance Config:**
+ - Primary and secondary subtitle appearance now use color controls plus CSS declaration editors, saved as `subtitleStyle.css`, `subtitleStyle.secondary.css`, and `subtitleSidebar.css`
+ - Known-word and N+1 annotation colors moved to `subtitleStyle.knownWordColor` and `subtitleStyle.nPlusOneColor`
+ - Subtitle font defaults updated to `Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP`
+ - Existing configs migrate automatically; legacy Anki color keys still accepted with deprecation warnings
+- **Subtitle Style Defaults:**
+ - Stronger outline-style text shadow
+ - Thicker JLPT underlines
+ - Frequency `topX` default raised to `10000`
+- **Character Dictionary:**
+ - Entries scoped to the current AniList media for name matching and inline portraits
+ - Generates Japanese-only name aliases so raw romanized/English aliases no longer surface as separate results
+ - In-app AniList selector waits for an explicit search with the box prefilled from the current filename
+ - `subtitleStyle.nameMatchEnabled` is now the sole switch for dictionary sync and builds
+- **Electron Runtime:** Updated from 39.8.6 to 42.2.0, returning SubMiner to a supported Electron release line.
+- **Jellyfin Setup:**
+ - Removed the server presets dropdown
+ - Setup now shows a single editable server URL field
+- **Jellyfin Cast Identity:**
+ - Device identity now derived from the OS hostname and always reported as SubMiner
+ - Previously configurable identity fields are ignored, preventing multiple installs from sharing a remote-session identity
+- **Startup Defaults:** Jellyfin remote-session startup warmup and character-name subtitle highlighting now default to off.
+- **Setup Appearance:** Removed the bundled mpv runtime plugin readiness card from the setup flow.
### Fixed
-- AniList Progress: Progress updates fire correctly when playback reaches or skips past the watched threshold using fresh mpv timing events; season-specific results preferred for multi-season files with a clear message when the matched season is not in Planning or Watching; repeated missing-token checks no longer exhaust retry attempts or duplicate dead-letter entries.
-- Anki Mining: Sentence-audio padding is opt-in by default; animated AVIF freeze-frame duration aligned to word audio length without double-counting; multi-line sentence alignment fixed for repeated subtitle text; Kiku duplicate-card detection, auto-merge, modal acknowledgment race, and field/tag ordering corrected; YouTube playback cards use mpv's resolved stream URLs; sentence cards refresh the secondary subtitle before saving; known-word cache appends correctly with multiple deck field mappings.
-- Jellyfin Discovery: Startup, subtitle track selection, and duplicate ready-signal handling all fixed; paused mpv no longer misreported as playing; startup unpause no longer repeats after a manual pause or `y-t` toggle; delayed Japanese subtitle selection, later-loading foreign track hijacking, and long-lived sidebar ffmpeg extractor leaks fixed; resume corrected when a remote play command sends `StartPositionTicks: 0` despite saved progress; picker library discovery kept working regardless of app log level.
-- Jellyfin Remote: Tray checkbox stays in sync on Linux after tray, CLI, or startup changes; stale discovery sessions restarted when the server no longer lists the SubMiner cast target; remote controller visibility and progress sync fixed for seeks, stops, startup path changes, and Linux websocket reconnect windows; Play and Resume now behave correctly (Play from beginning, Resume from saved position); final progress reports reuse SubMiner's last known position when mpv resets on stop; Windows setup login flow fixed with an IPC bridge, immediate feedback, and a timeout with inline error for unreachable servers.
-- Jellyfin Subtitles and Overlay: Subtitle overlay shown automatically during Jellyfin playback; `y-t` toggle made reliable and sticky across stream redirects; managed subtitle defaults re-armed on redirect; passive Linux/Hyprland overlay shows no longer steal keyboard focus from mpv; subtitle timing improved with preferred embedded streams over external sidecars, correct Japanese-vs-English cue offset handling, per-stream delay shift restoration, and transient track-list read failure tolerance.
-- Overlay (macOS): Overlay hides when mpv loses focus, is minimized, or is no longer the foreground app; stable through transient window geometry disappearances from macOS APIs and when clicking from the overlay back into mpv; stats overlay opened inactive so it appears over fullscreen mpv without switching Spaces; passthrough fixed so mpv controls stay clickable before hovering a subtitle bar; window-tracker polling reduced while mpv is stably focused.
-- Overlay (Linux / Hyprland): Placement refreshes after leaving fullscreen; overlay stays above mpv after focus changes from clicks or movement; Settings and Yomitan windows promoted above the subtitle overlay instead of opening behind it; overlay hides when the character dictionary modal opens, including during AniList lookup.
-- Overlay Lifecycle: First startup subtitle primed before autoplay resumes so the overlay renders text before playback begins; overlay and subtitle stream kept alive after `y-r` restart with correct Linux bounds reapplication; launcher-owned playback quits SubMiner on end while background/tray sessions stay alive; subtitle sync modal fixed on macOS so it no longer flashes on first attempt or leaves stale state; Windows managed mpv launches from a background instance now correctly receive the start command, retarget the new socket, bind to the player window, and receive startup overlay options.
-- Yomitan Sidebar: Playback stays paused for sidebar-opened Yomitan popups when auto-pause is enabled; fixed popups not opening when startup races the Yomitan extension load; sidebar mining cards use audio and images from the clicked sidebar line instead of the current primary subtitle.
-- Launcher: Warm launches reuse a running background instance, reapply preferred subtitles, and close launcher-owned tray apps after playback ends; videos stay paused until subtitle priming and tokenization readiness complete; `subminer settings` on macOS exits cleanly when the window is closed; `subminer app` on Linux returns terminal control immediately; Linux first-run installs build with a valid Bun shebang; `subminer app --setup` opens the setup flow when SubMiner is already running in background.
-- YouTube Playback: Selected subtitles downloaded to local temp files so the primary bar and sidebar read the same source, with cleanup on reload and quit; false load-failure notifications suppressed; tray icon created on launcher-managed playback that attaches to an already-running process; mpv plugin no longer starts a second SubMiner instance for app-owned YouTube playback.
-- Shortcuts: Native mpv menu shortcuts disabled during managed macOS playback so configured SubMiner shortcuts work while mpv has focus; custom session shortcuts including `stats.markWatchedKey` wired through mpv; multi-line copy/mine overlay correctly focused so number keys choose the line count on macOS and Windows.
-- Controller Bindings: Controller config and debug shortcuts stay closed while controller support is disabled; binding learn mode starts from the edit pencil; remaps saved per controller profile; binding badges also start learn mode; row reset buttons restore individual bindings to defaults.
-- Logging: `logging.level` forwarded to launcher-started and Windows shortcut-started mpv sessions covering mpv log verbosity, plugin logging, and plugin-launched app logging; `logging.rotation` (default 7 days) and per-component `logging.files` toggles added with mpv logs disabled by default; repeated IPC socket warning spam suppressed while waiting for mpv to recreate the socket; Windows mpv IPC, subtitle track, and Yomitan diagnostics added.
-- Updater: Linux `subminer -u` performs release updates independently of any running tray app using GitHub release metadata; macOS update dialogs from `subminer -u` reliably appear in the foreground with a manual-install message for builds that cannot apply native updates; macOS and Linux `electron-updater` routes through `/usr/bin/curl` to avoid Electron network crashes; Windows automatic updates keep the native NSIS install path while routing updater HTTP through main-process fetch to avoid delayed exit after launch.
-- In-Player Stats: Layering fixed so delete confirmations, overlay modals, and update-check dialogs appear above the stats window; Jellyfin playback stats grouped by item metadata so watched episodes merge with matching local library titles and keep clean display names.
-- Tray: Tray stays running when Yomitan settings are closed; settings loading no longer blocks other tray actions; Yomitan extension refreshes serialized at startup; embedded popup preview disabled to prevent renderer hangs during sidebar navigation; Windows "Open SubMiner Setup" action opens the setup window correctly after first-run is complete; session help modal close fixed without mpv running.
-- Discord Rich Presence: No longer falls back to Jellyfin stream URLs; Jellyfin playback titles primed before stream loading so presence shows the show/episode title instead of a URL.
-- WebSocket Annotations: Annotation spans and token metadata stay on the annotation WebSocket; the regular subtitle WebSocket is plain-text only.
-- Subtitle Frequency Highlighting: Frequency annotations kept for determiner-led noun compounds like `その場` while still filtering standalone determiners; fixed for Yomitan single-token compounds with internal particles such as `目の前` while keeping pure grammar/kana helper spans unannotated.
-- Subtitle Annotation Prefetching: Cached colored annotations and character images ready sooner for live subtitle changes without delaying raw subtitle display.
-- Packaging: macOS compiled mpv window helper correctly built into `dist/scripts` and bundled, preventing fallback to slow Swift source startup; stale Windows helper resource entry removed; one-shot `make clean build install` AppImage flows fixed so install picks up the AppImage built earlier in the same invocation.
-- Windows Startup Errors: Fatal startup failures now show a native error dialog and write details to the app log instead of exiting silently.
+- **AniList Progress:**
+ - Progress updates fire correctly when playback reaches or skips past the watched threshold, using fresh mpv timing events
+ - Season-specific results preferred for multi-season files, with a clear message when the matched season is not in Planning or Watching
+ - Repeated missing-token checks no longer exhaust retry attempts or duplicate dead-letter entries
+- **Anki Mining:**
+ - Sentence-audio padding is opt-in by default
+ - Animated AVIF freeze-frame duration aligned to word audio length without double-counting
+ - Multi-line sentence alignment fixed for repeated subtitle text
+ - Kiku duplicate-card detection, auto-merge, modal acknowledgment race, and field/tag ordering corrected
+ - YouTube playback cards use mpv's resolved stream URLs
+ - Sentence cards refresh the secondary subtitle before saving
+- **Jellyfin Discovery:**
+ - Startup, subtitle track selection, and duplicate ready-signal handling all fixed
+ - Paused mpv no longer misreported as playing
+ - Resume corrected when a remote play command sends `StartPositionTicks: 0` despite saved progress
+- **Jellyfin Remote:**
+ - Tray checkbox stays in sync on Linux after tray, CLI, or startup changes
+ - Remote controller visibility and progress sync fixed for seeks, stops, startup path changes, and Linux websocket reconnect windows
+ - Play and Resume now behave correctly (Play from beginning, Resume from saved position)
+ - Final progress reports reuse SubMiner's last known position when mpv resets on stop
+ - Windows setup login flow fixed with an IPC bridge, immediate feedback, and a timeout with inline error for unreachable servers
+- **Overlay (macOS):**
+ - Overlay hides when mpv loses focus, is minimized, or is no longer the foreground app
+ - Stays stable through transient window geometry disappearances from macOS APIs and when clicking from the overlay back into mpv
+ - Stats overlay opened inactive so it appears over fullscreen mpv without switching Spaces
+ - Passthrough fixed so mpv controls stay clickable before hovering a subtitle bar
+- **Yomitan Sidebar:**
+ - Playback stays paused for sidebar-opened Yomitan popups when auto-pause is enabled
+ - Popups now open when startup races the Yomitan extension load
+ - Sidebar mining cards use audio and images from the clicked sidebar line instead of the current primary subtitle
+- **Launcher:**
+ - `subminer app` on Linux returns terminal control immediately
+ - `subminer app --setup` opens the setup flow when SubMiner is already running in the background
+- **YouTube Playback:**
+ - Selected subtitles downloaded to local temp files so the primary bar and sidebar read the same source, with cleanup on reload and quit
+ - False load-failure notifications suppressed
+ - Tray icon created on launcher-managed playback that attaches to an already-running process
+- **Shortcuts:**
+ - Native mpv menu shortcuts disabled during managed macOS playback so configured SubMiner shortcuts work while mpv has focus
+ - Custom session shortcuts including `stats.markWatchedKey` wired through mpv
+ - Multi-line copy/mine overlay correctly focused so number keys choose the line count on macOS and Windows
+- **Controller Bindings:**
+ - Controller config and debug shortcuts stay closed while controller support is disabled
+ - Binding learn mode starts from the edit pencil
+ - Remaps saved per controller profile
+ - Binding badges also start learn mode
+ - Row reset buttons restore individual bindings to defaults
+- **Logging:**
+ - `logging.level` forwarded to launcher-started and Windows shortcut-started mpv sessions, covering mpv log verbosity, plugin logging, and plugin-launched app logging
+ - `logging.rotation` (default 7 days) and per-component `logging.files` toggles added, with mpv logs disabled by default
+ - Repeated IPC socket warning spam suppressed while waiting for mpv to recreate the socket
+ - Windows mpv IPC, subtitle track, and Yomitan diagnostics added
+- **In-Player Stats:**
+ - Layering fixed so delete confirmations, overlay modals, and update-check dialogs appear above the stats window
+ - Jellyfin playback stats grouped by item metadata so watched episodes merge with matching local library titles and keep clean display names
+- **WebSocket Annotations:**
+ - Annotation spans and token metadata stay on the annotation WebSocket
+ - The regular subtitle WebSocket is plain-text only
+- **Subtitle Annotation Prefetching:** Cached colored annotations and character images ready sooner for live subtitle changes without delaying raw subtitle display.
+- **Windows Startup Errors:** Fatal startup failures now show a native error dialog and write details to the app log instead of exiting silently.
### Docs
-- Documentation Site: Published stable docs at the site root with current development docs under `/main/`; fixed versioned docs navigation, archived page link handling, and local dev version routing; documented all previously undocumented config options including `subtitleStyle.primaryDefaultMode`, `stats.markWatchedKey`, `immersionTracking.lifetimeSummaries.*`, and all seven `mpv.*` launcher options; added Playback Startup Flow and Runtime Sockets diagrams to the architecture docs with cross-reference pointers in the MPV Plugin and Troubleshooting pages.
+- **Documentation Site:**
+ - Published stable docs at the site root with current development docs under `/main/`
+ - Fixed versioned docs navigation, archived page link handling, and local dev version routing
+ - Documented all previously undocumented config options including `subtitleStyle.primaryDefaultMode`, `stats.markWatchedKey`, `immersionTracking.lifetimeSummaries.*`, and all seven `mpv.*` launcher options
+ - Added Playback Startup Flow and Runtime Sockets diagrams to the architecture docs with cross-reference pointers in the MPV Plugin and Troubleshooting pages
Internal changes
### Internal
-- Release Tooling: Release-note polishing treats pending fragments and reviewed prerelease notes as a cumulative final outcome, collapsing prerelease-only fixes into the final user-facing change; prerelease generation reuses existing reviewed notes and merges only new fragment material; `make clean` preserves `release/prerelease-notes.md`.
-- Tests: Removed stale Yomitan vendor source-inspection assertions for changes that were not shipped.
+- **Release Tooling:**
+ - Release-note polishing treats pending fragments and reviewed prerelease notes as a cumulative final outcome, collapsing prerelease-only fixes into the final user-facing change
+ - Prerelease generation reuses existing reviewed notes and merges only new fragment material
+ - `make clean` preserves `release/prerelease-notes.md`
+- **Tests:** Removed stale Yomitan vendor source-inspection assertions for changes that were not shipped.
diff --git a/docs-site/changelog.md b/docs-site/changelog.md
index 7e5011d2..c1897771 100644
--- a/docs-site/changelog.md
+++ b/docs-site/changelog.md
@@ -4,68 +4,151 @@
**Breaking Changes**
-- Subsync: The `subsync.defaultMode` config option has been removed; Subsync now always opens the manual subtitle picker regardless of any previously set default mode.
+- **Subsync:**
+ - The `subsync.defaultMode` config option has been removed
+ - Subsync now always opens the manual subtitle picker regardless of any previously set default mode
+- **N+1 Highlighting:**
+ - N+1 highlighting now has its own dedicated `ankiConnect.nPlusOne.enabled` option, separate from known-word highlighting
+ - It is no longer enabled automatically when known-word highlighting is on — enable it explicitly to keep N+1 annotations
**Added**
-- Auto-Updater: Adds tray and `subminer -u` update checks with app update prompts, launcher and Linux rofi theme auto-updates, checksum verification, configurable notifications, and an opt-in prerelease channel via `updates.channel: "prerelease"`.
-- Settings Window: New dedicated Settings window via `subminer --settings` or `subminer settings`, organized into Appearance, Behavior, Anki, Input, and Integration sections; click-to-learn keybinding controls including the AniSkip button key; AnkiConnect-backed deck, field, and note-type pickers that auto-fill from the configured Anki deck; cross-category search; and live save for most options including subtitle CSS, stats keys, logging level, Jimaku, Subsync, and Anki mappings. AI and translation settings remain config-file only.
-- Inline Character Portraits: Optional AniList character portraits appear inline for name-matched subtitle text; manual AniList overrides scoped per parent media directory so separate season folders maintain separate character dictionary selections.
-- Log Export: Sanitized log ZIP export from the tray menu and via `subminer logs -e`, with home-directory usernames redacted from exported contents.
-- Launcher CLI: `subminer --version` / `subminer -v` prints the installed app version; `mpv.profile` config and Settings support passes a named mpv profile to managed launches; bundled mpv plugin startup options are now configurable from SubMiner config.
-- First-Run Setup: Optional installer for Bun and the `subminer` CLI on Linux, macOS, and Windows, including a Windows `subminer.cmd` PATH shim so `subminer` works without manually adding `SubMiner.exe` to PATH; setup recognizes existing Homebrew or user PATH installs and avoids writing into Homebrew-owned paths; includes an Open SubMiner Settings button; standalone setup app quits after completing, returning terminal control.
-- Primary Subtitle Visibility on Yomitan Popup: New `subtitleStyle.primaryVisibleOnYomitanPopup` option keeps hover-mode primary subtitles visible while a Yomitan popup is open.
+- **Auto-Updater:**
+ - Tray and `subminer -u` update checks with app update prompts
+ - Launcher and Linux rofi theme auto-updates
+ - Checksum verification and configurable notifications
+ - Opt-in prerelease channel via `updates.channel: "prerelease"`
+- **Settings Window:**
+ - New dedicated Settings window via `subminer --settings` or `subminer settings`, organized into Appearance, Behavior, Anki, Input, and Integration sections
+ - Click-to-learn keybinding controls
+ - AnkiConnect-backed deck, field, and note-type pickers that auto-fill from the configured Anki deck
+ - Cross-category search
+ - Live save for most options including subtitle CSS, stats keys, logging level, Jimaku, Subsync, and Anki mappings
+ - AI and translation settings remain config-file only
+- **Inline Character Portraits:**
+ - Optional AniList character portraits appear inline for name-matched subtitle text
+ - Manual AniList overrides scoped per parent media directory so separate season folders maintain separate character dictionary selections
+- **Character Dictionary Manager:** New `Ctrl/Cmd+D` manager modal to remove, reorder, or override loaded entries.
+- **Log Export:** Sanitized log ZIP export from the tray menu and via `subminer logs -e`, with home-directory usernames redacted from exported contents.
+- **Launcher CLI:**
+ - `subminer --version` / `subminer -v` prints the installed app version
+ - `mpv.profile` config and Settings support passes a named mpv profile to managed launches
+ - Bundled mpv plugin startup options are now configurable from SubMiner config
+- **First-Run Setup:**
+ - Optional installer for Bun and the `subminer` CLI on Linux, macOS, and Windows
+ - Windows `subminer.cmd` PATH shim so `subminer` works without manually adding `SubMiner.exe` to PATH
+ - Setup recognizes existing Homebrew or user PATH installs and avoids writing into Homebrew-owned paths
+ - Includes an Open SubMiner Settings button
+ - Standalone setup app quits after completing, returning terminal control
+- **Primary Subtitle Visibility on Yomitan Popup:** New `subtitleStyle.primaryVisibleOnYomitanPopup` option keeps hover-mode primary subtitles visible while a Yomitan popup is open.
**Changed**
-- Subtitle Appearance Config: Primary and secondary subtitle appearance now use color controls plus CSS declaration editors, saved as `subtitleStyle.css`, `subtitleStyle.secondary.css`, and `subtitleSidebar.css`; known-word and N+1 annotation colors moved to `subtitleStyle.knownWordColor` and `subtitleStyle.nPlusOneColor`; subtitle font defaults updated to `Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP`. Existing configs migrate automatically; legacy Anki color keys still accepted with deprecation warnings.
-- Subtitle Style Defaults: Stronger outline-style text shadow, thicker JLPT underlines, and frequency `topX` default raised to `10000`.
-- Character Dictionary: Entries scoped to the current AniList media for name matching and inline portraits; generates Japanese-only name aliases so raw romanized/English aliases no longer surface as separate results; new `Ctrl/Cmd+D` manager modal to remove, reorder, or override loaded entries; in-app AniList selector waits for an explicit search with the box prefilled from the current filename; `subtitleStyle.nameMatchEnabled` is now the sole switch for dictionary sync and builds.
-- Electron Runtime: Updated from 39.8.6 to 42.2.0, returning SubMiner to a supported Electron release line.
-- N+1 Highlighting Default: `ankiConnect.nPlusOne.enabled` is no longer implicitly enabled when known-word highlighting is on; existing configs that already had N+1 enabled are unchanged, but new configs must set it explicitly.
-- Linux Auto-Update Flow: Linux tray "Check for Updates" now installs the new AppImage automatically, matching macOS and Windows; AppImages managed by a system package (e.g. AUR) and non-AppImage launches still use the GitHub-asset flow.
-- Jellyfin Setup: Removed the server presets dropdown; setup now shows a single editable server URL field.
-- Jellyfin Cast Identity: Device identity now derived from the OS hostname and always reported as SubMiner; previously configurable identity fields are ignored, preventing multiple installs from sharing a remote-session identity.
-- Startup Defaults: Jellyfin remote-session startup warmup and character-name subtitle highlighting now default to off.
-- Setup Appearance: Removed the bundled mpv runtime plugin readiness card from the setup flow.
+- **Subtitle Appearance Config:**
+ - Primary and secondary subtitle appearance now use color controls plus CSS declaration editors, saved as `subtitleStyle.css`, `subtitleStyle.secondary.css`, and `subtitleSidebar.css`
+ - Known-word and N+1 annotation colors moved to `subtitleStyle.knownWordColor` and `subtitleStyle.nPlusOneColor`
+ - Subtitle font defaults updated to `Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP`
+ - Existing configs migrate automatically; legacy Anki color keys still accepted with deprecation warnings
+- **Subtitle Style Defaults:**
+ - Stronger outline-style text shadow
+ - Thicker JLPT underlines
+ - Frequency `topX` default raised to `10000`
+- **Character Dictionary:**
+ - Entries scoped to the current AniList media for name matching and inline portraits
+ - Generates Japanese-only name aliases so raw romanized/English aliases no longer surface as separate results
+ - In-app AniList selector waits for an explicit search with the box prefilled from the current filename
+ - `subtitleStyle.nameMatchEnabled` is now the sole switch for dictionary sync and builds
+- **Electron Runtime:** Updated from 39.8.6 to 42.2.0, returning SubMiner to a supported Electron release line.
+- **Jellyfin Setup:**
+ - Removed the server presets dropdown
+ - Setup now shows a single editable server URL field
+- **Jellyfin Cast Identity:**
+ - Device identity now derived from the OS hostname and always reported as SubMiner
+ - Previously configurable identity fields are ignored, preventing multiple installs from sharing a remote-session identity
+- **Startup Defaults:** Jellyfin remote-session startup warmup and character-name subtitle highlighting now default to off.
+- **Setup Appearance:** Removed the bundled mpv runtime plugin readiness card from the setup flow.
**Fixed**
-- AniList Progress: Progress updates fire correctly when playback reaches or skips past the watched threshold using fresh mpv timing events; season-specific results preferred for multi-season files with a clear message when the matched season is not in Planning or Watching; repeated missing-token checks no longer exhaust retry attempts or duplicate dead-letter entries.
-- Anki Mining: Sentence-audio padding is opt-in by default; animated AVIF freeze-frame duration aligned to word audio length without double-counting; multi-line sentence alignment fixed for repeated subtitle text; Kiku duplicate-card detection, auto-merge, modal acknowledgment race, and field/tag ordering corrected; YouTube playback cards use mpv's resolved stream URLs; sentence cards refresh the secondary subtitle before saving; known-word cache appends correctly with multiple deck field mappings.
-- Jellyfin Discovery: Startup, subtitle track selection, and duplicate ready-signal handling all fixed; paused mpv no longer misreported as playing; startup unpause no longer repeats after a manual pause or `y-t` toggle; delayed Japanese subtitle selection, later-loading foreign track hijacking, and long-lived sidebar ffmpeg extractor leaks fixed; resume corrected when a remote play command sends `StartPositionTicks: 0` despite saved progress; picker library discovery kept working regardless of app log level.
-- Jellyfin Remote: Tray checkbox stays in sync on Linux after tray, CLI, or startup changes; stale discovery sessions restarted when the server no longer lists the SubMiner cast target; remote controller visibility and progress sync fixed for seeks, stops, startup path changes, and Linux websocket reconnect windows; Play and Resume now behave correctly (Play from beginning, Resume from saved position); final progress reports reuse SubMiner's last known position when mpv resets on stop; Windows setup login flow fixed with an IPC bridge, immediate feedback, and a timeout with inline error for unreachable servers.
-- Jellyfin Subtitles and Overlay: Subtitle overlay shown automatically during Jellyfin playback; `y-t` toggle made reliable and sticky across stream redirects; managed subtitle defaults re-armed on redirect; passive Linux/Hyprland overlay shows no longer steal keyboard focus from mpv; subtitle timing improved with preferred embedded streams over external sidecars, correct Japanese-vs-English cue offset handling, per-stream delay shift restoration, and transient track-list read failure tolerance.
-- Overlay (macOS): Overlay hides when mpv loses focus, is minimized, or is no longer the foreground app; stable through transient window geometry disappearances from macOS APIs and when clicking from the overlay back into mpv; stats overlay opened inactive so it appears over fullscreen mpv without switching Spaces; passthrough fixed so mpv controls stay clickable before hovering a subtitle bar; window-tracker polling reduced while mpv is stably focused.
-- Overlay (Linux / Hyprland): Placement refreshes after leaving fullscreen; overlay stays above mpv after focus changes from clicks or movement; Settings and Yomitan windows promoted above the subtitle overlay instead of opening behind it; overlay hides when the character dictionary modal opens, including during AniList lookup.
-- Overlay Lifecycle: First startup subtitle primed before autoplay resumes so the overlay renders text before playback begins; overlay and subtitle stream kept alive after `y-r` restart with correct Linux bounds reapplication; launcher-owned playback quits SubMiner on end while background/tray sessions stay alive; subtitle sync modal fixed on macOS so it no longer flashes on first attempt or leaves stale state; Windows managed mpv launches from a background instance now correctly receive the start command, retarget the new socket, bind to the player window, and receive startup overlay options.
-- Yomitan Sidebar: Playback stays paused for sidebar-opened Yomitan popups when auto-pause is enabled; fixed popups not opening when startup races the Yomitan extension load; sidebar mining cards use audio and images from the clicked sidebar line instead of the current primary subtitle.
-- Launcher: Warm launches reuse a running background instance, reapply preferred subtitles, and close launcher-owned tray apps after playback ends; videos stay paused until subtitle priming and tokenization readiness complete; `subminer settings` on macOS exits cleanly when the window is closed; `subminer app` on Linux returns terminal control immediately; Linux first-run installs build with a valid Bun shebang; `subminer app --setup` opens the setup flow when SubMiner is already running in background.
-- YouTube Playback: Selected subtitles downloaded to local temp files so the primary bar and sidebar read the same source, with cleanup on reload and quit; false load-failure notifications suppressed; tray icon created on launcher-managed playback that attaches to an already-running process; mpv plugin no longer starts a second SubMiner instance for app-owned YouTube playback.
-- Shortcuts: Native mpv menu shortcuts disabled during managed macOS playback so configured SubMiner shortcuts work while mpv has focus; custom session shortcuts including `stats.markWatchedKey` wired through mpv; multi-line copy/mine overlay correctly focused so number keys choose the line count on macOS and Windows.
-- Controller Bindings: Controller config and debug shortcuts stay closed while controller support is disabled; binding learn mode starts from the edit pencil; remaps saved per controller profile; binding badges also start learn mode; row reset buttons restore individual bindings to defaults.
-- Logging: `logging.level` forwarded to launcher-started and Windows shortcut-started mpv sessions covering mpv log verbosity, plugin logging, and plugin-launched app logging; `logging.rotation` (default 7 days) and per-component `logging.files` toggles added with mpv logs disabled by default; repeated IPC socket warning spam suppressed while waiting for mpv to recreate the socket; Windows mpv IPC, subtitle track, and Yomitan diagnostics added.
-- Updater: Linux `subminer -u` performs release updates independently of any running tray app using GitHub release metadata; macOS update dialogs from `subminer -u` reliably appear in the foreground with a manual-install message for builds that cannot apply native updates; macOS and Linux `electron-updater` routes through `/usr/bin/curl` to avoid Electron network crashes; Windows automatic updates keep the native NSIS install path while routing updater HTTP through main-process fetch to avoid delayed exit after launch.
-- In-Player Stats: Layering fixed so delete confirmations, overlay modals, and update-check dialogs appear above the stats window; Jellyfin playback stats grouped by item metadata so watched episodes merge with matching local library titles and keep clean display names.
-- Tray: Tray stays running when Yomitan settings are closed; settings loading no longer blocks other tray actions; Yomitan extension refreshes serialized at startup; embedded popup preview disabled to prevent renderer hangs during sidebar navigation; Windows "Open SubMiner Setup" action opens the setup window correctly after first-run is complete; session help modal close fixed without mpv running.
-- Discord Rich Presence: No longer falls back to Jellyfin stream URLs; Jellyfin playback titles primed before stream loading so presence shows the show/episode title instead of a URL.
-- WebSocket Annotations: Annotation spans and token metadata stay on the annotation WebSocket; the regular subtitle WebSocket is plain-text only.
-- Subtitle Frequency Highlighting: Frequency annotations kept for determiner-led noun compounds like `その場` while still filtering standalone determiners; fixed for Yomitan single-token compounds with internal particles such as `目の前` while keeping pure grammar/kana helper spans unannotated.
-- Subtitle Annotation Prefetching: Cached colored annotations and character images ready sooner for live subtitle changes without delaying raw subtitle display.
-- Packaging: macOS compiled mpv window helper correctly built into `dist/scripts` and bundled, preventing fallback to slow Swift source startup; stale Windows helper resource entry removed; one-shot `make clean build install` AppImage flows fixed so install picks up the AppImage built earlier in the same invocation.
-- Windows Startup Errors: Fatal startup failures now show a native error dialog and write details to the app log instead of exiting silently.
+- **AniList Progress:**
+ - Progress updates fire correctly when playback reaches or skips past the watched threshold, using fresh mpv timing events
+ - Season-specific results preferred for multi-season files, with a clear message when the matched season is not in Planning or Watching
+ - Repeated missing-token checks no longer exhaust retry attempts or duplicate dead-letter entries
+- **Anki Mining:**
+ - Sentence-audio padding is opt-in by default
+ - Animated AVIF freeze-frame duration aligned to word audio length without double-counting
+ - Multi-line sentence alignment fixed for repeated subtitle text
+ - Kiku duplicate-card detection, auto-merge, modal acknowledgment race, and field/tag ordering corrected
+ - YouTube playback cards use mpv's resolved stream URLs
+ - Sentence cards refresh the secondary subtitle before saving
+- **Jellyfin Discovery:**
+ - Startup, subtitle track selection, and duplicate ready-signal handling all fixed
+ - Paused mpv no longer misreported as playing
+ - Resume corrected when a remote play command sends `StartPositionTicks: 0` despite saved progress
+- **Jellyfin Remote:**
+ - Tray checkbox stays in sync on Linux after tray, CLI, or startup changes
+ - Remote controller visibility and progress sync fixed for seeks, stops, startup path changes, and Linux websocket reconnect windows
+ - Play and Resume now behave correctly (Play from beginning, Resume from saved position)
+ - Final progress reports reuse SubMiner's last known position when mpv resets on stop
+ - Windows setup login flow fixed with an IPC bridge, immediate feedback, and a timeout with inline error for unreachable servers
+- **Overlay (macOS):**
+ - Overlay hides when mpv loses focus, is minimized, or is no longer the foreground app
+ - Stays stable through transient window geometry disappearances from macOS APIs and when clicking from the overlay back into mpv
+ - Stats overlay opened inactive so it appears over fullscreen mpv without switching Spaces
+ - Passthrough fixed so mpv controls stay clickable before hovering a subtitle bar
+- **Yomitan Sidebar:**
+ - Playback stays paused for sidebar-opened Yomitan popups when auto-pause is enabled
+ - Popups now open when startup races the Yomitan extension load
+ - Sidebar mining cards use audio and images from the clicked sidebar line instead of the current primary subtitle
+- **Launcher:**
+ - `subminer app` on Linux returns terminal control immediately
+ - `subminer app --setup` opens the setup flow when SubMiner is already running in the background
+- **YouTube Playback:**
+ - Selected subtitles downloaded to local temp files so the primary bar and sidebar read the same source, with cleanup on reload and quit
+ - False load-failure notifications suppressed
+ - Tray icon created on launcher-managed playback that attaches to an already-running process
+- **Shortcuts:**
+ - Native mpv menu shortcuts disabled during managed macOS playback so configured SubMiner shortcuts work while mpv has focus
+ - Custom session shortcuts including `stats.markWatchedKey` wired through mpv
+ - Multi-line copy/mine overlay correctly focused so number keys choose the line count on macOS and Windows
+- **Controller Bindings:**
+ - Controller config and debug shortcuts stay closed while controller support is disabled
+ - Binding learn mode starts from the edit pencil
+ - Remaps saved per controller profile
+ - Binding badges also start learn mode
+ - Row reset buttons restore individual bindings to defaults
+- **Logging:**
+ - `logging.level` forwarded to launcher-started and Windows shortcut-started mpv sessions, covering mpv log verbosity, plugin logging, and plugin-launched app logging
+ - `logging.rotation` (default 7 days) and per-component `logging.files` toggles added, with mpv logs disabled by default
+ - Repeated IPC socket warning spam suppressed while waiting for mpv to recreate the socket
+ - Windows mpv IPC, subtitle track, and Yomitan diagnostics added
+- **In-Player Stats:**
+ - Layering fixed so delete confirmations, overlay modals, and update-check dialogs appear above the stats window
+ - Jellyfin playback stats grouped by item metadata so watched episodes merge with matching local library titles and keep clean display names
+- **WebSocket Annotations:**
+ - Annotation spans and token metadata stay on the annotation WebSocket
+ - The regular subtitle WebSocket is plain-text only
+- **Subtitle Annotation Prefetching:** Cached colored annotations and character images ready sooner for live subtitle changes without delaying raw subtitle display.
+- **Windows Startup Errors:** Fatal startup failures now show a native error dialog and write details to the app log instead of exiting silently.
**Docs**
-- Documentation Site: Published stable docs at the site root with current development docs under `/main/`; fixed versioned docs navigation, archived page link handling, and local dev version routing; documented all previously undocumented config options including `subtitleStyle.primaryDefaultMode`, `stats.markWatchedKey`, `immersionTracking.lifetimeSummaries.*`, and all seven `mpv.*` launcher options; added Playback Startup Flow and Runtime Sockets diagrams to the architecture docs with cross-reference pointers in the MPV Plugin and Troubleshooting pages.
+- **Documentation Site:**
+ - Published stable docs at the site root with current development docs under `/main/`
+ - Fixed versioned docs navigation, archived page link handling, and local dev version routing
+ - Documented all previously undocumented config options including `subtitleStyle.primaryDefaultMode`, `stats.markWatchedKey`, `immersionTracking.lifetimeSummaries.*`, and all seven `mpv.*` launcher options
+ - Added Playback Startup Flow and Runtime Sockets diagrams to the architecture docs with cross-reference pointers in the MPV Plugin and Troubleshooting pages
Internal changes
**Internal**
-- Release Tooling: Release-note polishing treats pending fragments and reviewed prerelease notes as a cumulative final outcome, collapsing prerelease-only fixes into the final user-facing change; prerelease generation reuses existing reviewed notes and merges only new fragment material; `make clean` preserves `release/prerelease-notes.md`.
-- Tests: Removed stale Yomitan vendor source-inspection assertions for changes that were not shipped.
+- **Release Tooling:**
+ - Release-note polishing treats pending fragments and reviewed prerelease notes as a cumulative final outcome, collapsing prerelease-only fixes into the final user-facing change
+ - Prerelease generation reuses existing reviewed notes and merges only new fragment material
+ - `make clean` preserves `release/prerelease-notes.md`
+- **Tests:** Removed stale Yomitan vendor source-inspection assertions for changes that were not shipped.
diff --git a/docs/RELEASING.md b/docs/RELEASING.md
index ec6b34e3..95aed8a3 100644
--- a/docs/RELEASING.md
+++ b/docs/RELEASING.md
@@ -33,7 +33,7 @@
`bun run build`
When validating auto-update metadata, also run the relevant platform package
build and confirm `release/` contains the generated updater metadata
- (`*.yml`) and blockmaps (`*.blockmap`).
+ (`latest*.yml`) and blockmaps (`*.blockmap`).
8. If `docs-site/` changed, also run:
`bun run docs:test`
`bun run docs:build`
@@ -55,7 +55,7 @@
`bun run test:env`
`bun run build`
When validating packaged updater output, confirm the platform build writes
- `*.yml` and `*.blockmap` files under `release/`.
+ `latest*.yml` and `*.blockmap` files under `release/`.
5. Commit the prerelease prep (package.json version bump + the generated
`release/prerelease-notes.md`). CI does not regenerate notes — it uses the
committed file — so review it before committing. If you add more
@@ -87,7 +87,7 @@ Notes:
- Keep Cloudflare Pages Git auto-deploy disabled for `docs.subminer.moe`. Production docs are direct-uploaded by Wrangler from GitHub Actions with `--branch main`.
- AUR publish is best-effort: the workflow retries transient SSH clone/push failures, then warns and leaves the GitHub Release green if AUR still fails. Follow up with a manual `git push aur master` from the AUR checkout when needed.
- Required GitHub Actions secret: `AUR_SSH_PRIVATE_KEY`. Add the matching public key to your AUR account before relying on the automation.
-- Release and prerelease workflows upload updater metadata (`*.yml`) and blockmaps (`*.blockmap`) alongside platform artifacts. Do not remove those files while `electron-updater` is enabled.
+- Release and prerelease workflows upload updater metadata (`latest*.yml`) and blockmaps (`*.blockmap`) alongside platform artifacts. Do not remove those files while `electron-updater` is enabled.
- macOS tray app updates use the standard `electron-updater`/Squirrel path. Keep `latest-mac.yml`, the macOS `SubMiner--mac.zip`, and ZIP blockmap published; Squirrel uses the ZIP payload even when the DMG remains the user-facing installer.
- macOS update metadata and full ZIP downloads are routed through `/usr/bin/curl` before Squirrel installation to avoid Electron main-process network crashes on update checks.
- Windows tray app updates use the standard `electron-updater`/NSIS path. Keep `latest.yml`, the Windows NSIS installer, and installer blockmap published; updater HTTP is routed through main-process fetch to avoid Electron main-process network crashes during update checks.
diff --git a/release/release-notes.md b/release/release-notes.md
index 30b06d2b..d4bd91de 100644
--- a/release/release-notes.md
+++ b/release/release-notes.md
@@ -1,60 +1,140 @@
## Highlights
### Breaking Changes
-- Subsync: The `subsync.defaultMode` config option has been removed; Subsync now always opens the manual subtitle picker regardless of any previously set default mode.
+- **Subsync:**
+ - The `subsync.defaultMode` config option has been removed
+ - Subsync now always opens the manual subtitle picker regardless of any previously set default mode
+- **N+1 Highlighting:**
+ - N+1 highlighting now has its own dedicated `ankiConnect.nPlusOne.enabled` option, separate from known-word highlighting
+ - It is no longer enabled automatically when known-word highlighting is on — enable it explicitly to keep N+1 annotations
### Added
-- Auto-Updater: Adds tray and `subminer -u` update checks with app update prompts, launcher and Linux rofi theme auto-updates, checksum verification, configurable notifications, and an opt-in prerelease channel via `updates.channel: "prerelease"`.
-- Settings Window: New dedicated Settings window via `subminer --settings` or `subminer settings`, organized into Appearance, Behavior, Anki, Input, and Integration sections; click-to-learn keybinding controls including the AniSkip button key; AnkiConnect-backed deck, field, and note-type pickers that auto-fill from the configured Anki deck; cross-category search; and live save for most options including subtitle CSS, stats keys, logging level, Jimaku, Subsync, and Anki mappings. AI and translation settings remain config-file only.
-- Inline Character Portraits: Optional AniList character portraits appear inline for name-matched subtitle text; manual AniList overrides scoped per parent media directory so separate season folders maintain separate character dictionary selections.
-- Log Export: Sanitized log ZIP export from the tray menu and via `subminer logs -e`, with home-directory usernames redacted from exported contents.
-- Launcher CLI: `subminer --version` / `subminer -v` prints the installed app version; `mpv.profile` config and Settings support passes a named mpv profile to managed launches; bundled mpv plugin startup options are now configurable from SubMiner config.
-- First-Run Setup: Optional installer for Bun and the `subminer` CLI on Linux, macOS, and Windows, including a Windows `subminer.cmd` PATH shim so `subminer` works without manually adding `SubMiner.exe` to PATH; setup recognizes existing Homebrew or user PATH installs and avoids writing into Homebrew-owned paths; includes an Open SubMiner Settings button; standalone setup app quits after completing, returning terminal control.
-- Primary Subtitle Visibility on Yomitan Popup: New `subtitleStyle.primaryVisibleOnYomitanPopup` option keeps hover-mode primary subtitles visible while a Yomitan popup is open.
+- **Auto-Updater:**
+ - Tray and `subminer -u` update checks with app update prompts
+ - Launcher and Linux rofi theme auto-updates
+ - Checksum verification and configurable notifications
+ - Opt-in prerelease channel via `updates.channel: "prerelease"`
+- **Settings Window:**
+ - New dedicated Settings window via `subminer --settings` or `subminer settings`, organized into Appearance, Behavior, Anki, Input, and Integration sections
+ - Click-to-learn keybinding controls
+ - AnkiConnect-backed deck, field, and note-type pickers that auto-fill from the configured Anki deck
+ - Cross-category search
+ - Live save for most options including subtitle CSS, stats keys, logging level, Jimaku, Subsync, and Anki mappings
+ - AI and translation settings remain config-file only
+- **Inline Character Portraits:**
+ - Optional AniList character portraits appear inline for name-matched subtitle text
+ - Manual AniList overrides scoped per parent media directory so separate season folders maintain separate character dictionary selections
+- **Character Dictionary Manager:** New `Ctrl/Cmd+D` manager modal to remove, reorder, or override loaded entries.
+- **Log Export:** Sanitized log ZIP export from the tray menu and via `subminer logs -e`, with home-directory usernames redacted from exported contents.
+- **Launcher CLI:**
+ - `subminer --version` / `subminer -v` prints the installed app version
+ - `mpv.profile` config and Settings support passes a named mpv profile to managed launches
+ - Bundled mpv plugin startup options are now configurable from SubMiner config
+- **First-Run Setup:**
+ - Optional installer for Bun and the `subminer` CLI on Linux, macOS, and Windows
+ - Windows `subminer.cmd` PATH shim so `subminer` works without manually adding `SubMiner.exe` to PATH
+ - Setup recognizes existing Homebrew or user PATH installs and avoids writing into Homebrew-owned paths
+ - Includes an Open SubMiner Settings button
+ - Standalone setup app quits after completing, returning terminal control
+- **Primary Subtitle Visibility on Yomitan Popup:** New `subtitleStyle.primaryVisibleOnYomitanPopup` option keeps hover-mode primary subtitles visible while a Yomitan popup is open.
### Changed
-- Subtitle Appearance Config: Primary and secondary subtitle appearance now use color controls plus CSS declaration editors, saved as `subtitleStyle.css`, `subtitleStyle.secondary.css`, and `subtitleSidebar.css`; known-word and N+1 annotation colors moved to `subtitleStyle.knownWordColor` and `subtitleStyle.nPlusOneColor`; subtitle font defaults updated to `Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP`. Existing configs migrate automatically; legacy Anki color keys still accepted with deprecation warnings.
-- Subtitle Style Defaults: Stronger outline-style text shadow, thicker JLPT underlines, and frequency `topX` default raised to `10000`.
-- Character Dictionary: Entries scoped to the current AniList media for name matching and inline portraits; generates Japanese-only name aliases so raw romanized/English aliases no longer surface as separate results; new `Ctrl/Cmd+D` manager modal to remove, reorder, or override loaded entries; in-app AniList selector waits for an explicit search with the box prefilled from the current filename; `subtitleStyle.nameMatchEnabled` is now the sole switch for dictionary sync and builds.
-- Electron Runtime: Updated from 39.8.6 to 42.2.0, returning SubMiner to a supported Electron release line.
-- N+1 Highlighting Default: `ankiConnect.nPlusOne.enabled` is no longer implicitly enabled when known-word highlighting is on; existing configs that already had N+1 enabled are unchanged, but new configs must set it explicitly.
-- Linux Auto-Update Flow: Linux tray "Check for Updates" now installs the new AppImage automatically, matching macOS and Windows; AppImages managed by a system package (e.g. AUR) and non-AppImage launches still use the GitHub-asset flow.
-- Jellyfin Setup: Removed the server presets dropdown; setup now shows a single editable server URL field.
-- Jellyfin Cast Identity: Device identity now derived from the OS hostname and always reported as SubMiner; previously configurable identity fields are ignored, preventing multiple installs from sharing a remote-session identity.
-- Startup Defaults: Jellyfin remote-session startup warmup and character-name subtitle highlighting now default to off.
-- Setup Appearance: Removed the bundled mpv runtime plugin readiness card from the setup flow.
+- **Subtitle Appearance Config:**
+ - Primary and secondary subtitle appearance now use color controls plus CSS declaration editors, saved as `subtitleStyle.css`, `subtitleStyle.secondary.css`, and `subtitleSidebar.css`
+ - Known-word and N+1 annotation colors moved to `subtitleStyle.knownWordColor` and `subtitleStyle.nPlusOneColor`
+ - Subtitle font defaults updated to `Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP`
+ - Existing configs migrate automatically; legacy Anki color keys still accepted with deprecation warnings
+- **Subtitle Style Defaults:**
+ - Stronger outline-style text shadow
+ - Thicker JLPT underlines
+ - Frequency `topX` default raised to `10000`
+- **Character Dictionary:**
+ - Entries scoped to the current AniList media for name matching and inline portraits
+ - Generates Japanese-only name aliases so raw romanized/English aliases no longer surface as separate results
+ - In-app AniList selector waits for an explicit search with the box prefilled from the current filename
+ - `subtitleStyle.nameMatchEnabled` is now the sole switch for dictionary sync and builds
+- **Electron Runtime:** Updated from 39.8.6 to 42.2.0, returning SubMiner to a supported Electron release line.
+- **Jellyfin Setup:**
+ - Removed the server presets dropdown
+ - Setup now shows a single editable server URL field
+- **Jellyfin Cast Identity:**
+ - Device identity now derived from the OS hostname and always reported as SubMiner
+ - Previously configurable identity fields are ignored, preventing multiple installs from sharing a remote-session identity
+- **Startup Defaults:** Jellyfin remote-session startup warmup and character-name subtitle highlighting now default to off.
+- **Setup Appearance:** Removed the bundled mpv runtime plugin readiness card from the setup flow.
### Fixed
-- AniList Progress: Progress updates fire correctly when playback reaches or skips past the watched threshold using fresh mpv timing events; season-specific results preferred for multi-season files with a clear message when the matched season is not in Planning or Watching; repeated missing-token checks no longer exhaust retry attempts or duplicate dead-letter entries.
-- Anki Mining: Sentence-audio padding is opt-in by default; animated AVIF freeze-frame duration aligned to word audio length without double-counting; multi-line sentence alignment fixed for repeated subtitle text; Kiku duplicate-card detection, auto-merge, modal acknowledgment race, and field/tag ordering corrected; YouTube playback cards use mpv's resolved stream URLs; sentence cards refresh the secondary subtitle before saving; known-word cache appends correctly with multiple deck field mappings.
-- Jellyfin Discovery: Startup, subtitle track selection, and duplicate ready-signal handling all fixed; paused mpv no longer misreported as playing; startup unpause no longer repeats after a manual pause or `y-t` toggle; delayed Japanese subtitle selection, later-loading foreign track hijacking, and long-lived sidebar ffmpeg extractor leaks fixed; resume corrected when a remote play command sends `StartPositionTicks: 0` despite saved progress; picker library discovery kept working regardless of app log level.
-- Jellyfin Remote: Tray checkbox stays in sync on Linux after tray, CLI, or startup changes; stale discovery sessions restarted when the server no longer lists the SubMiner cast target; remote controller visibility and progress sync fixed for seeks, stops, startup path changes, and Linux websocket reconnect windows; Play and Resume now behave correctly (Play from beginning, Resume from saved position); final progress reports reuse SubMiner's last known position when mpv resets on stop; Windows setup login flow fixed with an IPC bridge, immediate feedback, and a timeout with inline error for unreachable servers.
-- Jellyfin Subtitles and Overlay: Subtitle overlay shown automatically during Jellyfin playback; `y-t` toggle made reliable and sticky across stream redirects; managed subtitle defaults re-armed on redirect; passive Linux/Hyprland overlay shows no longer steal keyboard focus from mpv; subtitle timing improved with preferred embedded streams over external sidecars, correct Japanese-vs-English cue offset handling, per-stream delay shift restoration, and transient track-list read failure tolerance.
-- Overlay (macOS): Overlay hides when mpv loses focus, is minimized, or is no longer the foreground app; stable through transient window geometry disappearances from macOS APIs and when clicking from the overlay back into mpv; stats overlay opened inactive so it appears over fullscreen mpv without switching Spaces; passthrough fixed so mpv controls stay clickable before hovering a subtitle bar; window-tracker polling reduced while mpv is stably focused.
-- Overlay (Linux / Hyprland): Placement refreshes after leaving fullscreen; overlay stays above mpv after focus changes from clicks or movement; Settings and Yomitan windows promoted above the subtitle overlay instead of opening behind it; overlay hides when the character dictionary modal opens, including during AniList lookup.
-- Overlay Lifecycle: First startup subtitle primed before autoplay resumes so the overlay renders text before playback begins; overlay and subtitle stream kept alive after `y-r` restart with correct Linux bounds reapplication; launcher-owned playback quits SubMiner on end while background/tray sessions stay alive; subtitle sync modal fixed on macOS so it no longer flashes on first attempt or leaves stale state; Windows managed mpv launches from a background instance now correctly receive the start command, retarget the new socket, bind to the player window, and receive startup overlay options.
-- Yomitan Sidebar: Playback stays paused for sidebar-opened Yomitan popups when auto-pause is enabled; fixed popups not opening when startup races the Yomitan extension load; sidebar mining cards use audio and images from the clicked sidebar line instead of the current primary subtitle.
-- Launcher: Warm launches reuse a running background instance, reapply preferred subtitles, and close launcher-owned tray apps after playback ends; videos stay paused until subtitle priming and tokenization readiness complete; `subminer settings` on macOS exits cleanly when the window is closed; `subminer app` on Linux returns terminal control immediately; Linux first-run installs build with a valid Bun shebang; `subminer app --setup` opens the setup flow when SubMiner is already running in background.
-- YouTube Playback: Selected subtitles downloaded to local temp files so the primary bar and sidebar read the same source, with cleanup on reload and quit; false load-failure notifications suppressed; tray icon created on launcher-managed playback that attaches to an already-running process; mpv plugin no longer starts a second SubMiner instance for app-owned YouTube playback.
-- Shortcuts: Native mpv menu shortcuts disabled during managed macOS playback so configured SubMiner shortcuts work while mpv has focus; custom session shortcuts including `stats.markWatchedKey` wired through mpv; multi-line copy/mine overlay correctly focused so number keys choose the line count on macOS and Windows.
-- Controller Bindings: Controller config and debug shortcuts stay closed while controller support is disabled; binding learn mode starts from the edit pencil; remaps saved per controller profile; binding badges also start learn mode; row reset buttons restore individual bindings to defaults.
-- Logging: `logging.level` forwarded to launcher-started and Windows shortcut-started mpv sessions covering mpv log verbosity, plugin logging, and plugin-launched app logging; `logging.rotation` (default 7 days) and per-component `logging.files` toggles added with mpv logs disabled by default; repeated IPC socket warning spam suppressed while waiting for mpv to recreate the socket; Windows mpv IPC, subtitle track, and Yomitan diagnostics added.
-- Updater: Linux `subminer -u` performs release updates independently of any running tray app using GitHub release metadata; macOS update dialogs from `subminer -u` reliably appear in the foreground with a manual-install message for builds that cannot apply native updates; macOS and Linux `electron-updater` routes through `/usr/bin/curl` to avoid Electron network crashes; Windows automatic updates keep the native NSIS install path while routing updater HTTP through main-process fetch to avoid delayed exit after launch.
-- In-Player Stats: Layering fixed so delete confirmations, overlay modals, and update-check dialogs appear above the stats window; Jellyfin playback stats grouped by item metadata so watched episodes merge with matching local library titles and keep clean display names.
-- Tray: Tray stays running when Yomitan settings are closed; settings loading no longer blocks other tray actions; Yomitan extension refreshes serialized at startup; embedded popup preview disabled to prevent renderer hangs during sidebar navigation; Windows "Open SubMiner Setup" action opens the setup window correctly after first-run is complete; session help modal close fixed without mpv running.
-- Discord Rich Presence: No longer falls back to Jellyfin stream URLs; Jellyfin playback titles primed before stream loading so presence shows the show/episode title instead of a URL.
-- WebSocket Annotations: Annotation spans and token metadata stay on the annotation WebSocket; the regular subtitle WebSocket is plain-text only.
-- Subtitle Frequency Highlighting: Frequency annotations kept for determiner-led noun compounds like `その場` while still filtering standalone determiners; fixed for Yomitan single-token compounds with internal particles such as `目の前` while keeping pure grammar/kana helper spans unannotated.
-- Subtitle Annotation Prefetching: Cached colored annotations and character images ready sooner for live subtitle changes without delaying raw subtitle display.
-- Packaging: macOS compiled mpv window helper correctly built into `dist/scripts` and bundled, preventing fallback to slow Swift source startup; stale Windows helper resource entry removed; one-shot `make clean build install` AppImage flows fixed so install picks up the AppImage built earlier in the same invocation.
-- Windows Startup Errors: Fatal startup failures now show a native error dialog and write details to the app log instead of exiting silently.
+- **AniList Progress:**
+ - Progress updates fire correctly when playback reaches or skips past the watched threshold, using fresh mpv timing events
+ - Season-specific results preferred for multi-season files, with a clear message when the matched season is not in Planning or Watching
+ - Repeated missing-token checks no longer exhaust retry attempts or duplicate dead-letter entries
+- **Anki Mining:**
+ - Sentence-audio padding is opt-in by default
+ - Animated AVIF freeze-frame duration aligned to word audio length without double-counting
+ - Multi-line sentence alignment fixed for repeated subtitle text
+ - Kiku duplicate-card detection, auto-merge, modal acknowledgment race, and field/tag ordering corrected
+ - YouTube playback cards use mpv's resolved stream URLs
+ - Sentence cards refresh the secondary subtitle before saving
+- **Jellyfin Discovery:**
+ - Startup, subtitle track selection, and duplicate ready-signal handling all fixed
+ - Paused mpv no longer misreported as playing
+ - Resume corrected when a remote play command sends `StartPositionTicks: 0` despite saved progress
+- **Jellyfin Remote:**
+ - Tray checkbox stays in sync on Linux after tray, CLI, or startup changes
+ - Remote controller visibility and progress sync fixed for seeks, stops, startup path changes, and Linux websocket reconnect windows
+ - Play and Resume now behave correctly (Play from beginning, Resume from saved position)
+ - Final progress reports reuse SubMiner's last known position when mpv resets on stop
+ - Windows setup login flow fixed with an IPC bridge, immediate feedback, and a timeout with inline error for unreachable servers
+- **Overlay (macOS):**
+ - Overlay hides when mpv loses focus, is minimized, or is no longer the foreground app
+ - Stays stable through transient window geometry disappearances from macOS APIs and when clicking from the overlay back into mpv
+ - Stats overlay opened inactive so it appears over fullscreen mpv without switching Spaces
+ - Passthrough fixed so mpv controls stay clickable before hovering a subtitle bar
+- **Yomitan Sidebar:**
+ - Playback stays paused for sidebar-opened Yomitan popups when auto-pause is enabled
+ - Popups now open when startup races the Yomitan extension load
+ - Sidebar mining cards use audio and images from the clicked sidebar line instead of the current primary subtitle
+- **Launcher:**
+ - `subminer app` on Linux returns terminal control immediately
+ - `subminer app --setup` opens the setup flow when SubMiner is already running in the background
+- **YouTube Playback:**
+ - Selected subtitles downloaded to local temp files so the primary bar and sidebar read the same source, with cleanup on reload and quit
+ - False load-failure notifications suppressed
+ - Tray icon created on launcher-managed playback that attaches to an already-running process
+- **Shortcuts:**
+ - Native mpv menu shortcuts disabled during managed macOS playback so configured SubMiner shortcuts work while mpv has focus
+ - Custom session shortcuts including `stats.markWatchedKey` wired through mpv
+ - Multi-line copy/mine overlay correctly focused so number keys choose the line count on macOS and Windows
+- **Controller Bindings:**
+ - Controller config and debug shortcuts stay closed while controller support is disabled
+ - Binding learn mode starts from the edit pencil
+ - Remaps saved per controller profile
+ - Binding badges also start learn mode
+ - Row reset buttons restore individual bindings to defaults
+- **Logging:**
+ - `logging.level` forwarded to launcher-started and Windows shortcut-started mpv sessions, covering mpv log verbosity, plugin logging, and plugin-launched app logging
+ - `logging.rotation` (default 7 days) and per-component `logging.files` toggles added, with mpv logs disabled by default
+ - Repeated IPC socket warning spam suppressed while waiting for mpv to recreate the socket
+ - Windows mpv IPC, subtitle track, and Yomitan diagnostics added
+- **In-Player Stats:**
+ - Layering fixed so delete confirmations, overlay modals, and update-check dialogs appear above the stats window
+ - Jellyfin playback stats grouped by item metadata so watched episodes merge with matching local library titles and keep clean display names
+- **WebSocket Annotations:**
+ - Annotation spans and token metadata stay on the annotation WebSocket
+ - The regular subtitle WebSocket is plain-text only
+- **Subtitle Annotation Prefetching:** Cached colored annotations and character images ready sooner for live subtitle changes without delaying raw subtitle display.
+- **Windows Startup Errors:** Fatal startup failures now show a native error dialog and write details to the app log instead of exiting silently.
### Docs
-- Documentation Site: Published stable docs at the site root with current development docs under `/main/`; fixed versioned docs navigation, archived page link handling, and local dev version routing; documented all previously undocumented config options including `subtitleStyle.primaryDefaultMode`, `stats.markWatchedKey`, `immersionTracking.lifetimeSummaries.*`, and all seven `mpv.*` launcher options; added Playback Startup Flow and Runtime Sockets diagrams to the architecture docs with cross-reference pointers in the MPV Plugin and Troubleshooting pages.
+- **Documentation Site:**
+ - Published stable docs at the site root with current development docs under `/main/`
+ - Fixed versioned docs navigation, archived page link handling, and local dev version routing
+ - Documented all previously undocumented config options including `subtitleStyle.primaryDefaultMode`, `stats.markWatchedKey`, `immersionTracking.lifetimeSummaries.*`, and all seven `mpv.*` launcher options
+ - Added Playback Startup Flow and Runtime Sockets diagrams to the architecture docs with cross-reference pointers in the MPV Plugin and Troubleshooting pages
## Installation
diff --git a/src/prerelease-workflow.test.ts b/src/prerelease-workflow.test.ts
index 1b1ea5f9..129966a5 100644
--- a/src/prerelease-workflow.test.ts
+++ b/src/prerelease-workflow.test.ts
@@ -69,14 +69,19 @@ test('prerelease workflow builds and uploads all release platforms', () => {
test('prerelease workflow publishes the same release assets as the stable workflow', () => {
assert.match(
prereleaseWorkflow,
- /files=\(release\/\*\.AppImage release\/\*\.dmg release\/\*\.exe release\/\*\.zip release\/\*\.tar\.gz release\/\*\.yml release\/\*\.blockmap dist\/launcher\/subminer\)/,
+ /files=\(release\/\*\.AppImage release\/\*\.dmg release\/\*\.exe release\/\*\.zip release\/\*\.tar\.gz release\/latest\*\.yml release\/\*\.blockmap dist\/launcher\/subminer\)/,
);
assert.match(
prereleaseWorkflow,
- /artifacts=\([\s\S]*release\/\*\.exe[\s\S]*release\/\*\.yml[\s\S]*release\/\*\.blockmap[\s\S]*release\/SHA256SUMS\.txt[\s\S]*\)/,
+ /artifacts=\([\s\S]*release\/\*\.exe[\s\S]*release\/latest\*\.yml[\s\S]*release\/\*\.blockmap[\s\S]*release\/SHA256SUMS\.txt[\s\S]*\)/,
);
});
+test('prerelease workflow uploads updater metadata without builder debug YAML files', () => {
+ assert.match(prereleaseWorkflow, /release\/latest\*\.yml/);
+ assert.doesNotMatch(prereleaseWorkflow, /release\/\*\.yml/);
+});
+
test('prerelease workflow writes checksum entries using release asset basenames', () => {
assert.match(prereleaseWorkflow, /: > release\/SHA256SUMS\.txt/);
assert.match(prereleaseWorkflow, /for file in "\$\{files\[@\]\}"; do/);
diff --git a/src/release-workflow.test.ts b/src/release-workflow.test.ts
index cc678f1b..641ed17c 100644
--- a/src/release-workflow.test.ts
+++ b/src/release-workflow.test.ts
@@ -105,14 +105,19 @@ test('release workflow generates release notes from committed changelog output',
test('release workflow includes the Windows installer in checksums and uploaded assets', () => {
assert.match(
releaseWorkflow,
- /files=\(release\/\*\.AppImage release\/\*\.dmg release\/\*\.exe release\/\*\.zip release\/\*\.tar\.gz release\/\*\.yml release\/\*\.blockmap dist\/launcher\/subminer\)/,
+ /files=\(release\/\*\.AppImage release\/\*\.dmg release\/\*\.exe release\/\*\.zip release\/\*\.tar\.gz release\/latest\*\.yml release\/\*\.blockmap dist\/launcher\/subminer\)/,
);
assert.match(
releaseWorkflow,
- /artifacts=\([\s\S]*release\/\*\.exe[\s\S]*release\/\*\.yml[\s\S]*release\/\*\.blockmap[\s\S]*release\/SHA256SUMS\.txt[\s\S]*\)/,
+ /artifacts=\([\s\S]*release\/\*\.exe[\s\S]*release\/latest\*\.yml[\s\S]*release\/\*\.blockmap[\s\S]*release\/SHA256SUMS\.txt[\s\S]*\)/,
);
});
+test('release workflow uploads updater metadata without builder debug YAML files', () => {
+ assert.match(releaseWorkflow, /release\/latest\*\.yml/);
+ assert.doesNotMatch(releaseWorkflow, /release\/\*\.yml/);
+});
+
test('release package metadata enables GitHub updater metadata without builder uploads', () => {
assert.equal(packageJson.build?.publish?.[0]?.provider, 'github');
assert.equal(packageJson.build?.publish?.[0]?.owner, 'ksyasuda');