diff --git a/CHANGELOG.md b/CHANGELOG.md
index abc40835..f2f50aa1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,74 @@
# Changelog
+## v0.15.0 (2026-05-29)
+
+### 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.
+
+### 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.
+
+### 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.
+
+### 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.
+
+### 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.
+
+
+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.
+
+
+
## v0.14.0 (2026-05-12)
### Added
diff --git a/changes/anilist-progress.md b/changes/anilist-progress.md
deleted file mode 100644
index 08806c87..00000000
--- a/changes/anilist-progress.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: fixed
-area: anilist
-
-- Used fresh mpv time-position, duration, and subtitle timing events for AniList post-watch threshold checks so progress updates still fire when playback reaches or skips past the watched threshold.
-- Prefer season-specific AniList search results for multi-season files before falling back to the base title, and show a clear message when the matched season is not in Planning or Watching instead of silently queueing an impossible update.
-- Prevent repeated missing-token checks from rapidly exhausting AniList retry attempts or duplicating dead-letter entries for the same episode.
diff --git a/changes/anki-mining.md b/changes/anki-mining.md
deleted file mode 100644
index ee0223e0..00000000
--- a/changes/anki-mining.md
+++ /dev/null
@@ -1,10 +0,0 @@
-type: fixed
-area: anki
-
-- Made sentence-audio padding opt-in by default, and kept animated AVIF freeze-frame duration aligned to the word audio length without double-counting sentence audio padding.
-- Kept multi-line sentence mining aligned when repeated subtitle text appears in the selected history range.
-- Fixed Kiku duplicate-card detection so local duplicate sentence cards trigger the manual modal or auto merge, modal-open acknowledgement races no longer cancel the flow, and merged fields follow Kiku's group ordering, sentence-audio, furigana, and tag semantics.
-- Fixed manual clipboard card updates from YouTube playback so generated audio and images use mpv's resolved stream URLs instead of the YouTube page URL.
-- Sentence cards now refresh the current secondary subtitle before saving, so the translation field uses the loaded subtitle instead of repeating the primary text.
-- Fixed immediate known-word cache append when no default Anki mining deck is configured but multiple known-word deck field mappings are present.
-- Added an AnkiConnect deck dropdown at the top of Mining & Anki settings that auto-fills from Yomitan's current mining deck when available.
diff --git a/changes/auto-update.md b/changes/auto-update.md
deleted file mode 100644
index f281a705..00000000
--- a/changes/auto-update.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: added
-area: updater
-
-- Added tray and `subminer -u` update checks for SubMiner releases, including app update prompts, launcher and Linux rofi theme updates, checksum verification, configurable update notifications, and an opt-in prerelease channel. Set `updates.channel` to `"prerelease"` to receive beta/RC builds.
diff --git a/changes/character-dictionary-fixes.md b/changes/character-dictionary-fixes.md
deleted file mode 100644
index e116d64f..00000000
--- a/changes/character-dictionary-fixes.md
+++ /dev/null
@@ -1,8 +0,0 @@
-type: fixed
-area: character-dictionary
-
-- Reused cached character-dictionary media matches so loading a title with an existing snapshot no longer sends another AniList search request.
-- Block the character dictionary manager when annotations are disabled, with a notice through the configured OSD/system notification surfaces.
-- Added surname honorific matches for Japanese localized character aliases embedded in AniList alternative names (e.g. Korean-source characters with Japanese names in parentheses), and refresh cached snapshots so those aliases are regenerated.
-- Use `subtitleStyle.nameMatchEnabled` as the only switch for character-dictionary sync/builds, hiding the legacy `anilist.characterDictionary.enabled` option.
-- Forward character dictionary manager session-action keybindings to the mpv plugin.
diff --git a/changes/character-dictionary.md b/changes/character-dictionary.md
deleted file mode 100644
index 3518b8cb..00000000
--- a/changes/character-dictionary.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: changed
-area: character-dictionary
-
-- Character dictionary entries are now scoped to the current AniList media for name matching and inline portraits, and generate Japanese name aliases only so raw romanized/English aliases no longer surface as separate results.
-- Added a `Ctrl/Cmd+D` manager modal to remove, reorder, or override loaded dictionary entries.
-- The in-app AniList selector now waits for an explicit title search, with the search box prefilled from the current filename guess so you can edit it before choosing an override.
diff --git a/changes/character-name-inline-images.md b/changes/character-name-inline-images.md
deleted file mode 100644
index 3e41ee2d..00000000
--- a/changes/character-name-inline-images.md
+++ /dev/null
@@ -1,7 +0,0 @@
-type: added
-area: subtitles
-
-- Added optional inline AniList portraits for character-name subtitle matches, including automatic refresh of cached character dictionary snapshots that do not contain portrait data.
-- Scoped manual AniList overrides by parent media directory, so separate season folders can keep separate character dictionary selections.
-- Fixed large character dictionary imports by serving the merged ZIP through a local URL when supported, with a base64 fallback for older bundled Yomitan builds.
-- Allowed subtitle overlay data image sources so inline character portraits render instead of showing a broken image icon.
diff --git a/changes/controller-config-enables-input.md b/changes/controller-config-enables-input.md
deleted file mode 100644
index fc72de07..00000000
--- a/changes/controller-config-enables-input.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: fixed
-area: overlay
-
-- Controller config and debug shortcuts now stay closed while controller support is disabled and show a notice to enable `controller.enabled` manually.
-- Controller binding rows now start learn mode from the edit pencil, so clicking edit and pressing a controller button saves the remap.
-- Controller remaps are now saved per controller profile, binding badges also start learn mode, and row reset buttons restore individual bindings to their defaults.
diff --git a/changes/default-opt-in-warmup-name-highlighting.md b/changes/default-opt-in-warmup-name-highlighting.md
deleted file mode 100644
index 9c326dc3..00000000
--- a/changes/default-opt-in-warmup-name-highlighting.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: changed
-area: config
-
-- Defaulted Jellyfin remote-session startup warmup and character-name subtitle highlighting to off.
diff --git a/changes/docs.md b/changes/docs.md
deleted file mode 100644
index f1544d06..00000000
--- a/changes/docs.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: docs
-area: docs
-
-- Published stable docs at the site root with current development docs under `/main/`, and fixed versioned docs navigation so archived pages keep local links under the selected version, the version switcher no longer nests paths incorrectly, local dev version routes serve warmed archive files, and internal README files no longer break archived builds.
-- Documented all previously undocumented config options, including `subtitleStyle.primaryDefaultMode`, `stats.markWatchedKey`, `immersionTracking.lifetimeSummaries.*`, and all seven `mpv.*` launcher options.
-- Added a Playback Startup Flow diagram and a Runtime Sockets section/diagram to the architecture docs, with cross-reference pointers in the MPV Plugin and Troubleshooting pages.
diff --git a/changes/electron-42-runtime.md b/changes/electron-42-runtime.md
deleted file mode 100644
index 16b1982c..00000000
--- a/changes/electron-42-runtime.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: changed
-area: runtime
-
-- Updated the bundled Electron runtime from 39.8.6 to 42.2.0, moving SubMiner back onto a supported Electron release line.
diff --git a/changes/fix-discord-presence-jellyfin-title.md b/changes/fix-discord-presence-jellyfin-title.md
deleted file mode 100644
index 5320f61c..00000000
--- a/changes/fix-discord-presence-jellyfin-title.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: fixed
-area: integrations
-
-- Prevented Discord Rich Presence from falling back to Jellyfin stream URLs, and primed Jellyfin playback titles before loading tokenized streams so presence shows the show/episode title
diff --git a/changes/hide-setup-runtime-plugin.md b/changes/hide-setup-runtime-plugin.md
deleted file mode 100644
index 2274043d..00000000
--- a/changes/hide-setup-runtime-plugin.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: changed
-area: setup
-
-- Setup: Removed the bundled mpv runtime plugin readiness card; legacy mpv plugin removal still appears when needed.
diff --git a/changes/jellyfin-discovery.md b/changes/jellyfin-discovery.md
deleted file mode 100644
index 65abb67b..00000000
--- a/changes/jellyfin-discovery.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: fixed
-area: jellyfin
-
-- Fixed Jellyfin discovery playback: the active item is no longer reloaded on startup, paused mpv is no longer misreported as playing, startup unpause no longer repeats after a manual pause or `y-t` toggle, duplicate ready signals no longer re-show the overlay, delayed Japanese subtitle selection is handled correctly, later-loading foreign tracks no longer steal the active Japanese track, and long-lived sidebar ffmpeg extractors no longer run against stream URLs.
-- Fixed discovery resume when a remote play command sends `StartPositionTicks: 0` despite saved progress on the item.
-- Kept Jellyfin picker library discovery working when the app log level is above info.
diff --git a/changes/jellyfin-remote.md b/changes/jellyfin-remote.md
deleted file mode 100644
index 9428d6ec..00000000
--- a/changes/jellyfin-remote.md
+++ /dev/null
@@ -1,8 +0,0 @@
-type: fixed
-area: jellyfin
-
-- Keep the discovery tray checkbox in sync on Linux after tray, CLI, or startup remote-session changes, and restart stale discovery sessions when the server no longer lists the SubMiner cast target.
-- Fixed remote controller visibility and progress sync for mpv/SubMiner seek jumps, stopped sessions, startup path changes, and Linux websocket reconnect windows.
-- Kept Play and Resume distinct: Play starts from the beginning while Resume starts at the saved position, and final progress reports reuse SubMiner's last known position when mpv resets during stop.
-- Derived cast device identity from the OS hostname and always report the client as SubMiner, ignoring legacy configurable identity fields so multiple installs no longer share a remote-session identity.
-- Fixed the Windows setup login flow with an IPC bridge, immediate progress feedback, and a timeout with an inline error for unreachable servers.
diff --git a/changes/jellyfin-subtitles-overlay.md b/changes/jellyfin-subtitles-overlay.md
deleted file mode 100644
index 8b2afeeb..00000000
--- a/changes/jellyfin-subtitles-overlay.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: fixed
-area: jellyfin
-
-- Show the visible subtitle overlay automatically during Jellyfin playback so `subtitleStyle` appearance applies, and inject the bundled mpv plugin when SubMiner auto-launches mpv so mpv-side keybindings work without overlay focus.
-- Made the `y-t` overlay toggle reliable and sticky across stream redirects that change mpv's path, re-arming managed subtitle defaults on redirect so Japanese primary subtitles load, collapsing duplicate toggle events on Hyprland, and keeping passive Linux/Hyprland overlay shows from stealing keyboard focus from mpv.
-- Improved subtitle timing by preferring default embedded streams over external sidecars, stripping Jellyfin's server-selected stream from playback URLs, suppressing mpv auto-selection while SubMiner stages managed tracks, correcting clear Japanese-vs-English cue offsets, and restoring per-stream subtitle delay shifts. Track selection tolerates transient `track-list` read failures and numeric string track IDs on Linux.
diff --git a/changes/launcher-fixes.md b/changes/launcher-fixes.md
deleted file mode 100644
index 54a93536..00000000
--- a/changes/launcher-fixes.md
+++ /dev/null
@@ -1,8 +0,0 @@
-type: fixed
-area: launcher
-
-- Launcher-opened videos reuse an already-running background SubMiner instance, reapply preferred subtitles on warm launches, and close launcher-owned tray apps after playback ends.
-- Videos stay paused when attaching to a running background app until subtitle priming and tokenization readiness complete, with mpv plugin subtitle auto-selection moved to pre-load so launch-time choices are not reset.
-- `subminer settings` on macOS no longer emits Electron menu diagnostics and exits cleanly when the window is closed.
-- `subminer app` on Linux returns control to the terminal immediately, and Linux first-run launcher installs build with a valid Bun shebang.
-- `subminer app --setup` opens the setup flow when SubMiner is already running in the background.
diff --git a/changes/launcher-mpv.md b/changes/launcher-mpv.md
deleted file mode 100644
index 3a1ed5a9..00000000
--- a/changes/launcher-mpv.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: added
-area: launcher
-
-- Added `subminer --version` / `subminer -v` to print the installed app version.
-- Added `mpv.profile` config and Settings support for passing an mpv profile to SubMiner-managed mpv launches.
-- Made bundled mpv plugin startup options configurable from SubMiner config.
diff --git a/changes/linux-tray-appimage-update.md b/changes/linux-tray-appimage-update.md
deleted file mode 100644
index f6be21e0..00000000
--- a/changes/linux-tray-appimage-update.md
+++ /dev/null
@@ -1,5 +0,0 @@
-type: changed
-area: updater
-
-- Linux tray "Check for Updates" now installs the new AppImage automatically via `electron-updater`, matching the macOS and Windows tray flow, instead of stopping at a "manual update required" dialog. AppImages managed by a system package (AUR `/opt/SubMiner/SubMiner.AppImage`) and non-AppImage launches (no `APPIMAGE` env) still fall back to the GitHub-asset flow.
-- Routed `electron-updater` HTTP through `/usr/bin/curl` on Linux and disabled differential downloads, matching the macOS path, so background update checks stay off Electron's network service.
diff --git a/changes/log-export.md b/changes/log-export.md
deleted file mode 100644
index fc1d9ccb..00000000
--- a/changes/log-export.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: added
-area: logs
-
-- Add sanitized log ZIP exports from the tray menu and `subminer logs -e`, with home-directory usernames redacted from exported log contents.
diff --git a/changes/logging.md b/changes/logging.md
deleted file mode 100644
index 45e4add5..00000000
--- a/changes/logging.md
+++ /dev/null
@@ -1,7 +0,0 @@
-type: fixed
-area: logging
-
-- Forward SubMiner `logging.level` into launcher-started and Windows shortcut-started mpv sessions, covering mpv log verbosity, plugin script logging, and plugin-launched app logging.
-- Added numeric `logging.rotation` (default 7 days of retained daily app, launcher, and mpv logs) and `logging.files` toggles per component, with mpv logs disabled by default unless explicitly enabled for debugging.
-- Added Windows mpv launch, IPC socket, subtitle track, and Yomitan/dictionary diagnostics, including expected/active IPC socket values when plugin auto-start skips on a socket mismatch.
-- Stop repeated mpv IPC socket warning spam while the app waits in the background for mpv to recreate the socket.
diff --git a/changes/nplusone-defaults.md b/changes/nplusone-defaults.md
deleted file mode 100644
index 53e453b4..00000000
--- a/changes/nplusone-defaults.md
+++ /dev/null
@@ -1,5 +0,0 @@
-type: changed
-area: config
-
-- `ankiConnect.nPlusOne.enabled` is no longer implicitly set to `true` when known-word highlighting is enabled; existing configs that already had N+1 highlighting keep it, but new configs leave it disabled unless `ankiConnect.nPlusOne.enabled` is set explicitly.
-- Updated known-word cache docs and examples to recommend expression/word fields and removed legacy-option references from user-facing config docs.
diff --git a/changes/overlay-lifecycle.md b/changes/overlay-lifecycle.md
deleted file mode 100644
index 695cd60f..00000000
--- a/changes/overlay-lifecycle.md
+++ /dev/null
@@ -1,8 +0,0 @@
-type: fixed
-area: overlay
-
-- Primed the first startup subtitle before autoplay resumes so the overlay renders text before video playback begins.
-- Kept the visible overlay and subtitle stream alive after restarting SubMiner from the mpv `y-r` shortcut, with correct Linux bounds reapplication and user-paused playback preserved through readiness gates.
-- Fixed managed mpv startup so launcher-owned videos quit SubMiner when playback ends while background/tray sessions stay alive, with pause-until-ready waiting for overlay and tokenization readiness.
-- Fixed the subtitle sync modal on macOS so it no longer flashes and hides on the first attempt or leaves stale state after syncing.
-- Fixed Windows managed mpv launches from a background instance so the warm app receives the start command, retargets the new mpv socket, binds to the player window, and receives startup overlay options.
diff --git a/changes/overlay-linux.md b/changes/overlay-linux.md
deleted file mode 100644
index cfa9e598..00000000
--- a/changes/overlay-linux.md
+++ /dev/null
@@ -1,7 +0,0 @@
-type: fixed
-area: overlay
-
-- Refreshed overlay placement after leaving mpv fullscreen so the visible overlay stays aligned to the player on Hyprland.
-- Kept the visible overlay stacked above mpv after mpv regains focus from clicks or overlay movement, and suspended it while the in-player stats window is open, restoring it mouse-passive afterward.
-- Promoted SubMiner and Yomitan settings windows above the subtitle overlay on Hyprland instead of opening behind it, without hiding subtitles.
-- Hid the visible overlay as soon as the character dictionary modal opens, including while AniList lookup is loading or returns no results.
diff --git a/changes/overlay-macos.md b/changes/overlay-macos.md
deleted file mode 100644
index 357ec91a..00000000
--- a/changes/overlay-macos.md
+++ /dev/null
@@ -1,7 +0,0 @@
-type: fixed
-area: overlay
-
-- Hid the macOS visible overlay when mpv loses focus, is minimized, or is no longer the foreground target so other apps and Spaces are not covered, treating the frontmost mpv app as the focus signal.
-- Kept the overlay stable through transient window-tracking misses, when mpv remains frontmost but window geometry temporarily disappears from macOS APIs, and when clicking from the overlay back into mpv.
-- Kept the overlay correctly layered during stats mouse passthrough, opened the stats overlay inactive so it appears over fullscreen mpv without switching Spaces, and fixed passthrough so mpv controls stay clickable before hovering a subtitle bar.
-- Reduced window-tracker background work by preferring the compiled helper and slowing polls while mpv is stably focused.
diff --git a/changes/overlay-yomitan-sidebar.md b/changes/overlay-yomitan-sidebar.md
deleted file mode 100644
index a65a0a52..00000000
--- a/changes/overlay-yomitan-sidebar.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: fixed
-area: overlay
-
-- Kept playback paused for Yomitan lookup popups opened from the subtitle sidebar when popup auto-pause is enabled.
-- Fixed Yomitan popups not opening when playback/overlay startup races the Yomitan extension load.
-- Fixed subtitle sidebar mining so Yomitan-enriched cards use audio and images from the clicked sidebar line instead of the current primary subtitle line.
diff --git a/changes/packaging.md b/changes/packaging.md
deleted file mode 100644
index 3e4d95f8..00000000
--- a/changes/packaging.md
+++ /dev/null
@@ -1,5 +0,0 @@
-type: fixed
-area: release
-
-- Fixed macOS packaging so the compiled mpv window helper is built into `dist/scripts` and bundled, preventing the overlay from falling back to slow Swift source startup, and removed a stale Windows helper resource entry that produced harmless missing-file warnings.
-- Fixed one-shot `make clean build install` flows so install picks up the AppImage built earlier in the same make invocation.
diff --git a/changes/plain-websocket-annotations.md b/changes/plain-websocket-annotations.md
deleted file mode 100644
index c883df74..00000000
--- a/changes/plain-websocket-annotations.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: fixed
-area: websocket
-
-- WebSocket: Kept the regular subtitle websocket plain-text only; annotation spans and token metadata now stay on the annotation websocket.
diff --git a/changes/primary-visible-yomitan-popup.md b/changes/primary-visible-yomitan-popup.md
deleted file mode 100644
index 3bd42332..00000000
--- a/changes/primary-visible-yomitan-popup.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: added
-area: config
-
-- Added `subtitleStyle.primaryVisibleOnYomitanPopup` to keep hover-mode primary subtitles visible while a Yomitan popup is open.
diff --git a/changes/release-notes-tooling.md b/changes/release-notes-tooling.md
deleted file mode 100644
index d6aa7e6a..00000000
--- a/changes/release-notes-tooling.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: internal
-area: release
-
-- Release-note polishing treats pending fragments and reviewed prerelease notes as a cumulative final outcome, collapsing prerelease-only fixes or breakages into the final user-facing change.
-- Prerelease note generation reuses existing reviewed notes and merges only new fragment material, and `make clean` preserves `release/prerelease-notes.md`.
-- Release-note polishing now asks Claude to write short, nested highlight bullets so longer changes are easier to scan.
diff --git a/changes/remove-jellyfin-server-presets.md b/changes/remove-jellyfin-server-presets.md
deleted file mode 100644
index 329a137e..00000000
--- a/changes/remove-jellyfin-server-presets.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: changed
-area: jellyfin
-
-- Removed the Jellyfin setup server presets dropdown; setup now shows a single editable server URL field.
diff --git a/changes/remove-yomitan-vendor-test-assertions.md b/changes/remove-yomitan-vendor-test-assertions.md
deleted file mode 100644
index 85f1529d..00000000
--- a/changes/remove-yomitan-vendor-test-assertions.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: internal
-area: tests
-
-- Removed stale Yomitan vendor source-inspection assertions for changes that were not shipped.
diff --git a/changes/settings-window.md b/changes/settings-window.md
deleted file mode 100644
index 4f489f3a..00000000
--- a/changes/settings-window.md
+++ /dev/null
@@ -1,8 +0,0 @@
-type: added
-area: config
-
-- Added a dedicated Settings window via `subminer --settings` or `subminer settings`, organized into Appearance, Behavior, Anki, Input, and Integration sections with click-to-learn keybinding controls (including the AniSkip button key) and AnkiConnect-backed deck, field, and note-type pickers.
-- Expanded live reload so Settings saves apply immediately for stats keys, logging level, Jimaku, Subsync, YouTube language defaults, Anki field mappings, sentence card model, and selected annotation/runtime options.
-- Settings search works across all categories, narrows on multi-word terms, and hides settings owned by richer editors.
-- The note-fields note type picker defaults to the configured Anki deck's note type, then exact `Kiku`, then exact `Lapis`, leaving it blank for manual selection otherwise.
-- AI and translation settings remain config-file only.
diff --git a/changes/setup.md b/changes/setup.md
deleted file mode 100644
index e5fbbc7e..00000000
--- a/changes/setup.md
+++ /dev/null
@@ -1,7 +0,0 @@
-type: added
-area: setup
-
-- Added optional first-run setup controls to install Bun and the `subminer` command-line launcher on Linux, macOS, and Windows, with a Windows `subminer.cmd` PATH shim so `subminer` works without manually adding `SubMiner.exe` to PATH.
-- Added an Open SubMiner Settings button to first-run setup and moved Finish to the right-side action slot.
-- First-run setup recognizes existing `subminer` installs in Homebrew or user PATH directories, while manual setup avoids writing into Homebrew-owned paths.
-- The standalone setup app quits after completing first-run setup, returning the terminal instead of leaving the process open.
diff --git a/changes/shortcuts.md b/changes/shortcuts.md
deleted file mode 100644
index 0dda12e6..00000000
--- a/changes/shortcuts.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: fixed
-area: shortcuts
-
-- Disabled native mpv menu shortcuts during managed macOS playback so configured SubMiner shortcuts work while mpv has focus.
-- Wired configured session shortcuts, including `stats.markWatchedKey`, through mpv so custom changes work while mpv has focus.
-- Focus the visible overlay when entering multi-line copy/mine selection so number keys choose the line count on macOS and Windows.
diff --git a/changes/stats.md b/changes/stats.md
deleted file mode 100644
index 1d3b215c..00000000
--- a/changes/stats.md
+++ /dev/null
@@ -1,5 +0,0 @@
-type: fixed
-area: stats
-
-- Fixed in-player stats layering so delete confirmations, overlay modals, and update-check dialogs appear above the stats window.
-- Grouped Jellyfin playback stats under item metadata instead of stream URLs, so watched episodes merge with matching local library titles and keep clean display names.
diff --git a/changes/subsync-manual-only.md b/changes/subsync-manual-only.md
deleted file mode 100644
index 41cb3fbd..00000000
--- a/changes/subsync-manual-only.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: changed
-area: subtitles
-
-- Subsync now always opens the manual picker and the `subsync.defaultMode` config/settings option has been removed.
diff --git a/changes/subtitle-appearance.md b/changes/subtitle-appearance.md
deleted file mode 100644
index e1b23356..00000000
--- a/changes/subtitle-appearance.md
+++ /dev/null
@@ -1,8 +0,0 @@
-type: changed
-area: config
-
-- Primary and secondary subtitle appearance now use color controls plus CSS declaration editors, saved as `subtitleStyle.css` and `subtitleStyle.secondary.css`; sidebar appearance uses `subtitleSidebar.css`.
-- Moved known-word and N+1 annotation colors to `subtitleStyle.knownWordColor` and `subtitleStyle.nPlusOneColor`; legacy Anki color keys are still accepted with deprecation warnings.
-- Updated subtitle font defaults to `Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP`.
-- Existing configs are migrated automatically: legacy primary/secondary appearance options and hover token colors fold into `subtitleStyle.css`, and user config files are preserved during legacy compatibility handling.
-- Live Settings saves apply subtitle CSS declarations immediately to open video overlays, and the generated example config uses the same CSS declaration paths.
diff --git a/changes/subtitle-frequency.md b/changes/subtitle-frequency.md
deleted file mode 100644
index 83771425..00000000
--- a/changes/subtitle-frequency.md
+++ /dev/null
@@ -1,5 +0,0 @@
-type: fixed
-area: subtitles
-
-- Kept frequency highlighting for determiner-led noun compounds like `その場` while still filtering standalone determiners.
-- Fixed frequency annotations for Yomitan single-token compounds with internal particles such as `目の前`, while keeping pure grammar/kana helper spans unannotated.
diff --git a/changes/subtitle-prefetch-annotations.md b/changes/subtitle-prefetch-annotations.md
deleted file mode 100644
index c1b92de9..00000000
--- a/changes/subtitle-prefetch-annotations.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: fixed
-area: subtitles
-
-- Improved subtitle annotation prefetching so cached colored annotations and character images are ready for more live subtitle changes without delaying raw subtitle display.
diff --git a/changes/subtitle-style-defaults.md b/changes/subtitle-style-defaults.md
deleted file mode 100644
index b2f60ead..00000000
--- a/changes/subtitle-style-defaults.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: changed
-area: subtitles
-
-- Updated subtitle defaults with a stronger outline-style text shadow, thicker JLPT underlines, and a `topX` frequency highlighting default of `10000`.
diff --git a/changes/tray.md b/changes/tray.md
deleted file mode 100644
index 26b3bace..00000000
--- a/changes/tray.md
+++ /dev/null
@@ -1,7 +0,0 @@
-type: fixed
-area: tray
-
-- Kept the tray app running when closing tray-launched Yomitan settings, with a close-only menu so closing settings does not quit the tray, and an in-page close button on Hyprland where native window controls are unavailable.
-- Kept settings loading from blocking other tray actions, serialized copied Yomitan extension refreshes at startup, and disabled the embedded popup preview to avoid renderer hangs during sidebar navigation.
-- Fixed session help focus handling so the modal can close without mpv running.
-- Fixed the Windows tray "Open SubMiner Setup" action so it opens the setup window after first-run setup is complete.
diff --git a/changes/updater-fixes.md b/changes/updater-fixes.md
deleted file mode 100644
index 9313d498..00000000
--- a/changes/updater-fixes.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: fixed
-area: updater
-
-- Linux: `subminer -u` performs release updates independently of any running tray app (reporting `up to date` without downloading when not newer), and update checks use GitHub release metadata/assets instead of the native Electron updater to avoid network-service crashes during startup.
-- macOS: update dialogs from `subminer -u` reliably appear in the foreground; builds that cannot apply native updates show a manual-install message instead of a restart prompt; `electron-updater` metadata and ZIP downloads route through `/usr/bin/curl` to avoid Electron network crashes while preserving the Squirrel install path; and metadata mismatches from conflicting ZIP filenames are resolved.
-- Windows: automatic updates keep the native `electron-updater`/NSIS install path while routing updater HTTP through main-process fetch, avoiding the delayed app exit after launch.
diff --git a/changes/windows-startup-fatal-errors.md b/changes/windows-startup-fatal-errors.md
deleted file mode 100644
index 578fbaa4..00000000
--- a/changes/windows-startup-fatal-errors.md
+++ /dev/null
@@ -1,4 +0,0 @@
-type: fixed
-area: windows
-
-- Windows startup failures now show a native error dialog and write fatal details to the SubMiner app log instead of exiting silently.
diff --git a/changes/youtube.md b/changes/youtube.md
deleted file mode 100644
index 815ecfab..00000000
--- a/changes/youtube.md
+++ /dev/null
@@ -1,6 +0,0 @@
-type: fixed
-area: youtube
-
-- Downloaded selected YouTube primary subtitles to temporary local files so the primary bar and sidebar read the same source, with cleanup on reload and quit, and suppressed false load-failure notifications by re-checking live mpv subtitle state.
-- Launcher-managed playback commands create the tray icon even when attaching to an already-running process, and app-owned YouTube playback no longer lets the mpv plugin start a second SubMiner instance.
-- Logged Linux tray registration failures with a StatusNotifier/AppIndicator hint and documented the Hyprland tray-host requirement.
diff --git a/docs-site/changelog.md b/docs-site/changelog.md
index 84410370..7e5011d2 100644
--- a/docs-site/changelog.md
+++ b/docs-site/changelog.md
@@ -1,12 +1,80 @@
# Changelog
-## Unreleased
+## v0.15.0 (2026-05-29)
-- **Character Dictionary:** Loaded entries are now scoped to the current AniList media for subtitle name matching and inline portraits. Added a character dictionary manager at `Ctrl/Cmd+D`; AniList overrides now live inside that manager instead of using a separate default shortcut.
+**Breaking Changes**
-## v0.14.0 (2026-05-12)
+- Subsync: The `subsync.defaultMode` config option has been removed; Subsync now always opens the manual subtitle picker regardless of any previously set default mode.
-SubMiner no longer requires a globally-installed mpv plugin. The bundled plugin is injected at runtime only when SubMiner launches mpv — through the `subminer` launcher, the app's managed launch, or the packaged Windows SubMiner mpv shortcut. When you open mpv on its own, SubMiner is not involved and the plugin is never loaded. If you have a legacy global SubMiner plugin under mpv's `scripts` directory, first-run setup detects it and prompts you to remove it before playback starts.
+**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.
+
+**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.
+
+**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.
+
+**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.
+
+
+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.
+
+
+
+## Previous Versions
+
+
+v0.14.x
+
+v0.14.0 (2026-05-12)
**Added**
@@ -68,7 +136,7 @@ SubMiner no longer requires a globally-installed mpv plugin. The bundled plugin
-## Previous Versions
+
v0.12.x
diff --git a/package.json b/package.json
index 4abc155f..669a5c17 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "subminer",
"productName": "SubMiner",
"desktopName": "SubMiner.desktop",
- "version": "0.15.0-beta.12",
+ "version": "0.15.0",
"description": "All-in-one sentence mining overlay with AnkiConnect and dictionary integration",
"packageManager": "bun@1.3.5",
"main": "dist/main-entry.js",
diff --git a/release/release-notes.md b/release/release-notes.md
new file mode 100644
index 00000000..30b06d2b
--- /dev/null
+++ b/release/release-notes.md
@@ -0,0 +1,70 @@
+## 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.
+
+### 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.
+
+### 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.
+
+### 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.
+
+### 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.
+
+## Installation
+
+See the README and docs/installation guide for full setup steps.
+
+## Assets
+
+- Linux: `SubMiner.AppImage`
+- macOS: `SubMiner-*.dmg` and `SubMiner-*.zip`
+- Windows: `SubMiner-*.exe` and `SubMiner-*-win.zip`
+- Optional extras: `subminer-assets.tar.gz` and the `subminer` launcher
+
+Note: the `subminer` wrapper script uses Bun (`#!/usr/bin/env bun`), so `bun` must be installed and on `PATH`.
diff --git a/scripts/build-changelog.test.ts b/scripts/build-changelog.test.ts
index c45a1f85..cdc0dcc3 100644
--- a/scripts/build-changelog.test.ts
+++ b/scripts/build-changelog.test.ts
@@ -179,6 +179,7 @@ test('writeChangelogArtifacts ignores README, groups fragments by type, writes r
assert.match(releaseNotes, /## Highlights\n### Added\n- Polished: added entry\./);
assert.match(releaseNotes, /### Fixed\n- Polished: fixed entry\./);
assert.match(releaseNotes, /## Installation\n\nSee the README and docs\/installation guide/);
+ assert.match(releaseNotes, /- Windows: `SubMiner-\*\.exe` and `SubMiner-\*-win\.zip`/);
} finally {
fs.rmSync(workspace, { recursive: true, force: true });
}
diff --git a/scripts/build-changelog.ts b/scripts/build-changelog.ts
index 6a268993..f30935ea 100644
--- a/scripts/build-changelog.ts
+++ b/scripts/build-changelog.ts
@@ -489,6 +489,7 @@ function renderReleaseNotes(
'',
'- Linux: `SubMiner.AppImage`',
'- macOS: `SubMiner-*.dmg` and `SubMiner-*.zip`',
+ '- Windows: `SubMiner-*.exe` and `SubMiner-*-win.zip`',
'- Optional extras: `subminer-assets.tar.gz` and the `subminer` launcher',
'',
'Note: the `subminer` wrapper script uses Bun (`#!/usr/bin/env bun`), so `bun` must be installed and on `PATH`.',
diff --git a/src/core/services/subtitle-prefetch.test.ts b/src/core/services/subtitle-prefetch.test.ts
index ad1fe018..5458e349 100644
--- a/src/core/services/subtitle-prefetch.test.ts
+++ b/src/core/services/subtitle-prefetch.test.ts
@@ -295,6 +295,9 @@ test('prefetch service deduplicates repeated cue text within a run', async () =>
}
service.stop();
- assert.deepEqual(tokenizedTexts.filter((text) => text === 'same'), ['same']);
+ assert.deepEqual(
+ tokenizedTexts.filter((text) => text === 'same'),
+ ['same'],
+ );
assert.ok(tokenizedTexts.includes('other'));
});
diff --git a/src/main/main-wiring.test.ts b/src/main/main-wiring.test.ts
index 4e688b1d..cede491d 100644
--- a/src/main/main-wiring.test.ts
+++ b/src/main/main-wiring.test.ts
@@ -122,7 +122,10 @@ test('autoplay subtitle prime prefers cached annotated payload before raw fallba
);
assert.match(actionBlock, /if \(cachedPayload\) \{/);
assert.match(actionBlock, /emitSubtitlePayload\(cachedPayload\);/);
- assert.match(actionBlock, /const rawPayload = withCurrentSubtitleTiming\(\{ text, tokens: null \}\);/);
+ assert.match(
+ actionBlock,
+ /const rawPayload = withCurrentSubtitleTiming\(\{ text, tokens: null \}\);/,
+ );
assert.ok(
actionBlock.indexOf('consumeCachedSubtitle(text)') <
actionBlock.indexOf('withCurrentSubtitleTiming({ text, tokens: null })'),
@@ -144,7 +147,9 @@ test('known-word updates invalidate prefetched tokenizations before refreshing c
);
assert.ok(
actionBlock.indexOf('subtitleProcessingController.invalidateTokenizationCache();') <
- actionBlock.indexOf('subtitleProcessingController.refreshCurrentSubtitle(appState.currentSubText);'),
+ actionBlock.indexOf(
+ 'subtitleProcessingController.refreshCurrentSubtitle(appState.currentSubText);',
+ ),
);
});