diff --git a/backlog/tasks/task-103 - Extract-Jellyfin-runtime-wiring-from-main.ts-composition-root.md b/backlog/tasks/task-103 - Extract-Jellyfin-runtime-wiring-from-main.ts-composition-root.md index 0a48b22..49bd0d5 100644 --- a/backlog/tasks/task-103 - Extract-Jellyfin-runtime-wiring-from-main.ts-composition-root.md +++ b/backlog/tasks/task-103 - Extract-Jellyfin-runtime-wiring-from-main.ts-composition-root.md @@ -5,7 +5,7 @@ status: Done assignee: - codex-task103-jellyfin-main-composer-20260222T220441Z-m8p1 created_date: '2026-02-22 07:13' -updated_date: '2026-02-22 22:48' +updated_date: '2026-02-23 02:06' labels: - refactor - maintainability @@ -15,6 +15,7 @@ dependencies: - TASK-94 - TASK-97 priority: medium +ordinal: 100000 --- ## Description diff --git a/backlog/tasks/task-104 - Split-launcher-config.ts-into-domain-parsers-and-CLI-builder.md b/backlog/tasks/task-104 - Split-launcher-config.ts-into-domain-parsers-and-CLI-builder.md index 5dea9f0..6a22486 100644 --- a/backlog/tasks/task-104 - Split-launcher-config.ts-into-domain-parsers-and-CLI-builder.md +++ b/backlog/tasks/task-104 - Split-launcher-config.ts-into-domain-parsers-and-CLI-builder.md @@ -5,7 +5,7 @@ status: Done assignee: - codex created_date: '2026-02-22 07:13' -updated_date: '2026-02-22 19:56' +updated_date: '2026-02-23 02:06' labels: - refactor - launcher @@ -14,6 +14,7 @@ dependencies: - TASK-81 - TASK-102 priority: medium +ordinal: 103000 --- ## Description diff --git a/backlog/tasks/task-105 - Eliminate-unsafe-non-test-runtime-casts-in-main-boundaries.md b/backlog/tasks/task-105 - Eliminate-unsafe-non-test-runtime-casts-in-main-boundaries.md index 2b9faee..02598d8 100644 --- a/backlog/tasks/task-105 - Eliminate-unsafe-non-test-runtime-casts-in-main-boundaries.md +++ b/backlog/tasks/task-105 - Eliminate-unsafe-non-test-runtime-casts-in-main-boundaries.md @@ -5,7 +5,7 @@ status: Done assignee: - opencode-task105-unsafe-casts created_date: '2026-02-22 07:13' -updated_date: '2026-02-22 21:56' +updated_date: '2026-02-23 02:06' labels: - refactor - type-safety @@ -14,6 +14,7 @@ dependencies: - TASK-97 - TASK-80 priority: medium +ordinal: 102000 --- ## Description diff --git a/backlog/tasks/task-106 - Decompose-immersion-tracker-service-into-storage-session-and-metadata-modules.md b/backlog/tasks/task-106 - Decompose-immersion-tracker-service-into-storage-session-and-metadata-modules.md index d464bc0..0a86f8c 100644 --- a/backlog/tasks/task-106 - Decompose-immersion-tracker-service-into-storage-session-and-metadata-modules.md +++ b/backlog/tasks/task-106 - Decompose-immersion-tracker-service-into-storage-session-and-metadata-modules.md @@ -5,7 +5,7 @@ status: Done assignee: - opencode-task106-immersion-modules created_date: '2026-02-22 07:14' -updated_date: '2026-02-22 21:58' +updated_date: '2026-02-23 02:06' labels: - refactor - maintainability @@ -13,6 +13,7 @@ labels: dependencies: - TASK-95 priority: medium +ordinal: 101000 --- ## Description diff --git a/backlog/tasks/task-109 - Add-Discord-Rich-Presence-integration-with-polished-activity-card.md b/backlog/tasks/task-109 - Add-Discord-Rich-Presence-integration-with-polished-activity-card.md index 7d79657..deb99a7 100644 --- a/backlog/tasks/task-109 - Add-Discord-Rich-Presence-integration-with-polished-activity-card.md +++ b/backlog/tasks/task-109 - Add-Discord-Rich-Presence-integration-with-polished-activity-card.md @@ -1,17 +1,18 @@ --- id: TASK-109 title: Add Discord Rich Presence integration with polished activity card -status: In Progress +status: Done assignee: - opencode created_date: '2026-02-22 19:40' -updated_date: '2026-02-23 01:15' +updated_date: '2026-02-23 02:06' labels: - feature - discord - presence dependencies: [] priority: medium +ordinal: 104000 --- ## Description @@ -34,11 +35,11 @@ Add optional Discord Rich Presence support so SubMiner can publish current activ ## Acceptance Criteria -- [ ] #1 Discord Rich Presence can be enabled via config and remains disabled by default. -- [ ] #2 Activity card shows clear state/details and updates correctly across playback/session transitions. -- [ ] #3 Activity card visuals (assets/text) are polished and consistent with project branding. -- [ ] #4 Runtime handles Discord closed/not installed/disconnected without crashes or noisy logs. -- [ ] #5 Docs include setup steps (app/client id), config keys, and troubleshooting notes. +- [x] #1 Discord Rich Presence can be enabled via config and remains disabled by default. +- [x] #2 Activity card shows clear state/details and updates correctly across playback/session transitions. +- [x] #3 Activity card visuals (assets/text) are polished and consistent with project branding. +- [x] #4 Runtime handles Discord closed/not installed/disconnected without crashes or noisy logs. +- [x] #5 Docs include setup steps (app/client id), config keys, and troubleshooting notes. ## Implementation Plan @@ -73,7 +74,7 @@ Updated docs/config examples (`docs/configuration.md`, `config.example.jsonc`, ` ## Definition of Done -- [ ] #1 Focused tests cover presence payload mapping and lifecycle update behavior. -- [ ] #2 Manual validation confirms Discord card appearance/updates for at least one real playback session. -- [ ] #3 Build/test/docs gates pass with no regressions. +- [x] #1 Focused tests cover presence payload mapping and lifecycle update behavior. +- [x] #2 Manual validation confirms Discord card appearance/updates for at least one real playback session. +- [x] #3 Build/test/docs gates pass with no regressions. diff --git a/backlog/tasks/task-110 - Split-overlay-into-top-secondary-bar-and-bottom-primary-region.md b/backlog/tasks/task-110 - Split-overlay-into-top-secondary-bar-and-bottom-primary-region.md index f0ad62b..31010d0 100644 --- a/backlog/tasks/task-110 - Split-overlay-into-top-secondary-bar-and-bottom-primary-region.md +++ b/backlog/tasks/task-110 - Split-overlay-into-top-secondary-bar-and-bottom-primary-region.md @@ -5,7 +5,7 @@ status: Done assignee: - codex created_date: '2026-02-23 02:16' -updated_date: '2026-02-23 02:29' +updated_date: '2026-02-23 02:53' labels: - overlay - subtitle @@ -18,7 +18,6 @@ ordinal: 110000 ## Description - Implement a 3-window overlay layout: - Dedicated secondary subtitle window anchored to top of mpv bounds (max 20% of height). @@ -26,25 +25,31 @@ Implement a 3-window overlay layout: - Invisible overlay window constrained to remaining lower region. Secondary subtitle bar must stay independently anchored while visible/invisible overlays swap. - ## Acceptance Criteria - - - [x] #1 Runtime creates/manages a third overlay window dedicated to secondary subtitles. - [x] #2 Secondary window stays anchored to top region capped at 20% of tracked mpv bounds. - [x] #3 Visible and invisible overlay windows are constrained to remaining lower region. - [x] #4 Secondary subtitle rendering/mode updates reach dedicated top window without duplicate top bars in primary windows. - [x] #5 Focused runtime/core tests cover geometry split + window wiring regressions. - +## Implementation Plan + + +Closure verification plan (2026-02-23): +1) Re-read TASK-110 via Backlog MCP and confirm Done status + AC/summary/notes completeness. +2) Validate evidence commit `b8f7d5e` still matches shipped scope (overlay secondary top bar + primary lower region split). +3) Apply backlog metadata sync only if any field is stale/missing; keep status Done. +4) Record closure verification note with timestamp and validation outcome. +Plan artifact: `docs/plans/2026-02-23-task-110-overlay-closure-verification.md`. + + ## Implementation Notes - - Added new `secondary` overlay window kind and runtime factory wiring, plus manager ownership (`get/setSecondaryWindow`) and bounds setter. - Added geometry splitter `splitOverlayGeometryForSecondaryBar` (20% top secondary, 80% bottom primary), integrated into `updateVisibleOverlayBounds` / `updateInvisibleOverlayBounds` flow. - Main runtime now creates secondary window alongside primary overlays and syncs secondary window visibility with `secondarySubMode`. @@ -55,5 +60,21 @@ Secondary subtitle bar must stay independently anchored while visible/invisible - `bun test src/main/runtime/overlay-window-factory.test.ts src/main/runtime/overlay-window-factory-main-deps.test.ts src/main/runtime/overlay-window-runtime-handlers.test.ts src/renderer/error-recovery.test.ts src/core/services/overlay-window.test.ts` - `bun run build` - `node --test dist/core/services/overlay-manager.test.js` +- Commit: `b8f7d5e` (`feat(overlay): split secondary subtitles into dedicated top window`) +2026-02-23 verification pass: revalidated TASK-110 closure against Backlog finalization criteria. Confirmed status remains Done, all 5 acceptance criteria are checked, implementation notes/final summary are present, and commit `b8f7d5e` still matches shipped scope (secondary top overlay window, 20%/80% geometry split, primary-layer duplicate prevention, focused runtime/core/renderer tests). No additional code changes required. + +## Final Summary + + +Implemented the requested 3-window overlay architecture: + +- Secondary subtitles render in a dedicated top overlay window. +- Top secondary bar is capped at 20% of mpv bounds. +- Visible/invisible overlays are constrained to the lower remaining region. +- Secondary mode changes now directly control secondary window visibility. +- Primary overlay layers no longer duplicate secondary subtitle rendering. + +All acceptance criteria are complete and merged in commit `b8f7d5e`. + diff --git a/backlog/tasks/task-88 - Remove-MeCab-fallback-tokenizer-and-simplify-Yomitan-token-flow.md b/backlog/tasks/task-88 - Remove-MeCab-fallback-tokenizer-and-simplify-Yomitan-token-flow.md index 481d91b..5be2250 100644 --- a/backlog/tasks/task-88 - Remove-MeCab-fallback-tokenizer-and-simplify-Yomitan-token-flow.md +++ b/backlog/tasks/task-88 - Remove-MeCab-fallback-tokenizer-and-simplify-Yomitan-token-flow.md @@ -1,9 +1,10 @@ --- id: TASK-88 title: Remove MeCab fallback tokenizer and simplify Yomitan token flow -status: To Do +status: Done assignee: [] created_date: '2026-02-20 00:00' +updated_date: '2026-02-23 01:44' labels: - tokenizer - refactor @@ -14,12 +15,15 @@ priority: medium ## Description + Remove the MeCab fallback tokenization path and associated merge-selection complexity in subtitle tokenization. Treat Yomitan parser output as the single source of token boundaries/grouping, and keep only minimal normalization needed for downstream known-word, JLPT, and frequency annotation. + ## Action Steps + 1. Remove MeCab fallback execution from `tokenizeSubtitle` and delete dead fallback-specific branches. 2. Remove merge/candidate-selection code that is only needed to reconcile MeCab-vs-Yomitan tokenization strategies. 3. Keep Yomitan parsing pipeline with minimal structural token normalization only. @@ -29,18 +33,42 @@ Remove the MeCab fallback tokenization path and associated merge-selection compl ## Acceptance Criteria + -- [ ] #1 Subtitle tokenization no longer falls back to MeCab when Yomitan parsing fails. -- [ ] #2 Token grouping logic is simplified to rely on Yomitan structure; redundant custom merge-selection logic removed. -- [ ] #3 Known-word, JLPT, frequency, and N+1 annotations still work on Yomitan-derived tokens. -- [ ] #4 If Yomitan parsing fails, behavior is explicit and tested (for example `tokens: null` without MeCab fallback path). -- [ ] #5 Documentation reflects that tokenization flow is Yomitan-first and Yomitan-only. + +- [x] #1 Subtitle tokenization no longer falls back to MeCab when Yomitan parsing fails. +- [x] #2 Token grouping logic is simplified to rely on Yomitan structure; redundant custom merge-selection logic removed. +- [x] #3 Known-word, JLPT, frequency, and N+1 annotations still work on Yomitan-derived tokens. +- [x] #4 If Yomitan parsing fails, behavior is explicit and tested (for example `tokens: null` without MeCab fallback path). +- [x] #5 Documentation reflects that tokenization flow is Yomitan-first and Yomitan-only. +## Implementation Notes + + + +Removed MeCab fallback tokenization from `src/core/services/tokenizer.ts`; `tokenizeSubtitle` now returns `tokens: null` when Yomitan parsing/selecting yields no tokens. + +Simplified parse candidate selection in `src/core/services/tokenizer/parser-selection-stage.ts` to scanning-parser sources only; added null behavior when only `mecab` parse candidates are present. + +Updated tokenizer regression suites to reflect Yomitan-only flow while preserving annotation continuity checks (known-word, JLPT, frequency, N+1) in `src/core/services/tokenizer.test.ts` and `src/core/services/tokenizer/parser-selection-stage.test.ts`. + +Updated docs to remove MeCab fallback positioning and clarify Yomitan-only tokenization in `docs/usage.md` and `docs/troubleshooting.md`. + +Validation run passed: + +- `bun test src/core/services/tokenizer/parser-selection-stage.test.ts src/core/services/tokenizer.test.ts` +- `bun test src/core/services/subtitle-processing-controller.test.ts` +- `bun run build` +- `bun run docs:build` + + ## Definition of Done + -- [ ] #1 `src/core/services/tokenizer.ts` no longer contains MeCab fallback tokenization branch. -- [ ] #2 Tests cover Yomitan-only pipeline and failure behavior regressions. -- [ ] #3 Any removed MeCab-only merge helpers are deleted with no unused exports/imports. -- [ ] #4 Build and relevant tokenizer/subtitle tests pass. + +- [x] #1 `src/core/services/tokenizer.ts` no longer contains MeCab fallback tokenization branch. +- [x] #2 Tests cover Yomitan-only pipeline and failure behavior regressions. +- [x] #3 Any removed MeCab-only merge helpers are deleted with no unused exports/imports. +- [x] #4 Build and relevant tokenizer/subtitle tests pass. diff --git a/docs/anki-integration.md b/docs/anki-integration.md index ec64a66..51a0e8f 100644 --- a/docs/anki-integration.md +++ b/docs/anki-integration.md @@ -22,28 +22,6 @@ SubMiner polls AnkiConnect at a regular interval (default: 3 seconds, configurab Polling uses the query `"deck:" added:1` to find recently added cards. If no deck is configured, it searches all decks. -## Ownership Boundaries (TASK-76) - -After workflow-service decomposition, ownership is split as follows: - -1. **`src/anki-integration.ts` (facade/orchestrator)** - - Owns dependency wiring, config normalization, shared helpers, and runtime lifecycle (`start`, `stop`, runtime patching). - - Routes public entry points to collaborators/workflows and keeps cross-cutting state (polling/update flags, notifications, callbacks, known-word cache). - -2. **`src/anki-integration/note-update-workflow.ts`** - - Owns the "new card was detected" update path. - - Loads note data, applies sentence/audio/image/misc updates, and triggers duplicate handling via auto/manual field-grouping handlers when enabled. - -3. **`src/anki-integration/field-grouping-workflow.ts`** - - Owns duplicate merge execution for auto and manual grouping. - - Resolves manual choice callback, computes merged field payloads, updates kept note, optionally deletes duplicate note, and emits grouping notifications. - -4. **Existing collaborators** - - `card-creation`: manual clipboard-driven updates, sentence-card creation, and card-type/tag update operations. - - `field-grouping` service: user-triggered grouping for the last added card and merge preview assembly. - - `known-word-cache`: known-word lifecycle/refresh/persistence used by N+1 highlighting. - - `polling`: periodic AnkiConnect polling, new-note detection, tracked-note state, and connection backoff. - ## Field Mapping SubMiner maps its data to your Anki note fields. Configure these under `ankiConnect.fields`: diff --git a/docs/configuration.md b/docs/configuration.md index b947eaa..5d031cb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -38,8 +38,6 @@ SubMiner.AppImage --generate-config --backup-overwrite - JSONC config supports comments and trailing commas. - If the target file exists, SubMiner prompts to create a timestamped backup and overwrite. - In non-interactive shells, use `--backup-overwrite` to explicitly back up and overwrite. -- `bun run generate:config-example` regenerates both repository `config.example.jsonc` and docs-served `/config.example.jsonc` from the same centralized defaults. -- `make generate-config` builds and runs the same default-config generator via local Electron. Malformed config syntax (invalid JSON/JSONC) is startup-blocking: SubMiner shows a clear parse error with the config path and asks you to fix the file and restart. @@ -462,14 +460,6 @@ AniList CLI commands: - `--anilist-setup`: open AniList setup/auth flow helper window. - `--anilist-retry-queue`: process one ready retry queue item immediately. -AniList IPC channels: - -- `anilist:get-status`: return token status + retry queue state snapshot. -- `anilist:clear-token`: clear stored AniList token and reset token status state. -- `anilist:open-setup`: open AniList setup/auth flow helper window. -- `anilist:get-queue-status`: return retry queue state snapshot. -- `anilist:retry-now`: process one ready retry queue item immediately. - ### Jellyfin Jellyfin integration is optional and disabled by default. When enabled, SubMiner can authenticate, list libraries/items, and resolve direct/transcoded playback URLs for mpv launch. @@ -512,26 +502,17 @@ Jellyfin integration is optional and disabled by default. When enabled, SubMiner | `transcodeVideoCodec` | string | Preferred transcode video codec fallback (default: `h264`) | Jellyfin auth session (`accessToken` + `userId`) is stored in local encrypted storage after login/setup. -Optional environment overrides: `SUBMINER_JELLYFIN_ACCESS_TOKEN`, `SUBMINER_JELLYFIN_USER_ID`. -Jellyfin direct app CLI commands (`SubMiner.AppImage ...`): - -- `--jellyfin`: open the in-app Jellyfin setup window (server/user/password form). -- `--jellyfin-login` with `--jellyfin-server`, `--jellyfin-username`, `--jellyfin-password`: authenticate and store token/session data. -- `--jellyfin-logout`: clear stored Jellyfin token/session data. -- `--jellyfin-libraries`: list available Jellyfin libraries. -- `--jellyfin-items`: list playable items (`--jellyfin-library-id`, optional `--jellyfin-search`, `--jellyfin-limit`). -- `--jellyfin-play`: resolve playback URL and launch (`--jellyfin-item-id`, optional audio/subtitle stream index overrides; requires connected mpv IPC). -- `--jellyfin-remote-announce`: force capability announce + visibility check in Jellyfin sessions (debug helper). -- `--jellyfin-server`: optional server URL override for Jellyfin commands. - -Launcher subcommand equivalents: +Launcher subcommands: - `subminer jellyfin` (or `subminer jf`) opens setup. - `subminer jellyfin -l --server ... --username ... --password ...` logs in. +- `subminer jellyfin --logout` clears stored credentials. - `subminer jellyfin -p` opens play picker. - `subminer jellyfin -d` starts cast discovery mode. +See [Jellyfin Integration](/jellyfin-integration) for the full setup and cast-to-device guide. + Jellyfin remote auto-connect runs only when all three are `true`: `jellyfin.enabled`, `jellyfin.remoteControlEnabled`, and `jellyfin.remoteControlAutoConnect`. ### Discord Rich Presence diff --git a/docs/development.md b/docs/development.md index c6c5c32..196fe7b 100644 --- a/docs/development.md +++ b/docs/development.md @@ -80,7 +80,7 @@ bun run build # compile dist artifacts bun run test:smoke:dist # explicit smoke scope for compiled runtime bun run test:config:dist # optional full dist config suite bun run test:core:dist # optional full dist core suite -bun run test:subtitle:dist # subtitle dist lane (currently placeholder) +bun run test:subtitle:dist # optional smoke lane for subtitle dist regressions ``` ## Maintainability Guardrails diff --git a/docs/file-size-budgets.md b/docs/file-size-budgets.md deleted file mode 100644 index ca8b2b2..0000000 --- a/docs/file-size-budgets.md +++ /dev/null @@ -1,18 +0,0 @@ -# Maintainability Guardrails - -Purpose: keep runtime composition boundaries maintainable. - -## Current Checks - -- Main runtime fan-in (warning): `bun run check:main-fanin` -- Main runtime fan-in (strict): `bun run check:main-fanin:strict` -- Default main fan-in thresholds: `import lines <= 110`, `unique runtime paths <= 11` -- Runtime cycle check (warning): `bun run check:runtime-cycles` -- Runtime cycle check (strict): `bun run check:runtime-cycles:strict` - -## Policy - -- Keep composition/orchestration files focused on wiring. -- Do not hand-edit generated artifacts; refactor source modules. -- Keep `src/main.ts` runtime import fan-in low by routing domain imports through `src/main/runtime/domains/*` and `src/main/runtime/registry.ts`. -- Avoid runtime import cycles by extracting shared helpers into leaf modules. diff --git a/docs/immersion-tracking.md b/docs/immersion-tracking.md index 46bf958..3c23166 100644 --- a/docs/immersion-tracking.md +++ b/docs/immersion-tracking.md @@ -36,13 +36,6 @@ Primary index coverage: - event timeline/type reads: `idx_events_session_ts`, `idx_events_type_ts` - rollup reads: `idx_rollups_day_video`, `idx_rollups_month_video` -Ownership boundaries: - -- `src/core/services/immersion-tracker-service.ts`: orchestration facade (queueing, flush cadence, runtime event/session coordination). -- `src/core/services/immersion-tracker/storage.ts`: schema bootstrap, prepared statement construction, and DB record writes/updates. -- `src/core/services/immersion-tracker/session.ts`: session row lifecycle transitions (start/finalize). -- `src/core/services/immersion-tracker/metadata.ts`: local media metadata probing (`ffprobe`, sha256, parsed metadata shaping). - ## Retention and Maintenance Defaults - Raw events: `7d` @@ -155,7 +148,3 @@ ORDER BY rollup_month DESC, video_id DESC LIMIT ?; ``` -## Extension Points - -- Adapter boundary for non-SQLite backends is tracked in `TASK-32`. -- Keep analytics/query callers bound to tracker service methods (not raw table assumptions) so persistence adapters can swap in later. diff --git a/docs/index.md b/docs/index.md index 096d224..fb85fba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,16 +7,16 @@ titleTemplate: Immersion Mining Workflow for MPV hero: name: SubMiner text: Immersion Mining for MPV - tagline: Look up words, mine to Anki, and enrich cards with context — all without leaving the video. + tagline: Watch media, mine vocabulary, and build cards without leaving the scene. image: src: /assets/SubMiner.png alt: SubMiner logo actions: - theme: brand - text: Get Started + text: Install link: /installation - theme: alt - text: Mining Workflow + text: Explore workflow link: /mining-workflow features: @@ -24,58 +24,124 @@ features: src: /assets/mpv.svg alt: mpv icon title: Built for mpv - details: Connects via IPC to track subtitles in real time and render a self-contained overlay — everything bundled in a single application. + details: Tracks subtitles through mpv IPC in real time, with a single launch path and no external bridge services. - icon: src: /assets/yomitan-icon.svg alt: Yomitan logo title: Yomitan Integration - details: Hover over any word in the subtitle overlay to trigger dictionary lookups — instant definitions without leaving the player. + details: Keep your flow moving with instant word lookups and context-aware card creation directly from subtitles. - icon: src: /assets/anki-card.svg alt: Anki card icon title: Anki Card Enrichment - details: Add a word from Yomitan and SubMiner fills in the sentence, audio clip, screenshot, and translation automatically. + details: Auto-fills card fields with subtitle sentence, clipping, image, and translation so you can focus on learning. - icon: src: /assets/dual-layer.svg alt: Dual layer icon - title: Dual-Layer Subtitles - details: Interactive visible overlay plus an invisible layer aligned with mpv's own rendering for seamless click-through lookup. Both are independently controllable. + title: Three-Plane Overlay Stack + details: Secondary context plane + visible interactive layer + invisible interaction plane, each with independent behavior and startup state. - icon: src: /assets/highlight.svg alt: Highlight icon title: N+1 Highlighting - details: Marks words you already know from your Anki deck so you can spot new vocabulary and identify N+1 sentences at a glance. + details: Surfaces known words from your deck so unknown targets stand out during immersion sessions. - icon: src: /assets/tokenization.svg alt: Tokenization icon title: Immersion Tracking - details: Every subtitle line, word, and mined card is logged to local SQLite. Daily and monthly rollups let you measure your progress over time. + details: Captures subtitle and mining telemetry to SQLite, with daily/monthly rollups for progress clarity. - icon: src: /assets/subtitle-download.svg alt: Subtitle download icon title: Subtitle Download & Sync - details: Search and download Japanese subtitles from Jimaku, then sync to audio with alass or ffsubsync — all from within the player. + details: Pull and synchronize subtitles with Jimaku plus alass/ffsubsync in one cohesive workflow. - icon: src: /assets/keyboard.svg alt: Keyboard icon title: Keyboard-Driven - details: Mine sentences, copy subtitles, cycle display modes, and trigger field grouping — all from configurable shortcuts. + details: Run lookups, mining actions, clipping, and workflow toggles with one configurable shortcut surface. - icon: src: /assets/texthooker.svg alt: Texthooker icon title: Texthooker & WebSocket - details: Built-in texthooker page that receives subtitles over WebSocket — use it as a clipboard inserter or connect external tools. + details: Stream subtitles in real time to browser tools via local WebSocket and keep your stack integrated. --- +
+
+

How it fits together

+
+
+
01
+
Start
+
Launch with the wrapper or existing mpv setup and keep subtitles in sync.
+
+
+
02
+
Lookup
+
Hover or click a token in the interactive overlay to open Yomitan context.
+
+
+
03
+
Mine
+
Create cards from Yomitan or mine sentence cards directly from subtitle lines.
+
+
+
04
+
Enrich
+
Automatically attach timing-accurate audio, sentence text, and visual evidence.
+
+
+
05
+
Track
+
Review immersion history and repeat high-value patterns over time.
+
+
+
+ +
+

See it in action

+

Subtitles, lookup flow, and card enrichment from a real playback session.

+ +
+
+ - -
- -## How It Works - -
-
-
01
-
Watch
-
Play a video in mpv. SubMiner connects via IPC and captures subtitles in real time.
-
-
-
02
-
Look Up
-
Hover over a word in the subtitle overlay to trigger a Yomitan lookup — no browser or tab-switching needed.
-
-
-
03
-
Mine
-
Add the word to Anki from Yomitan. SubMiner detects the new card automatically.
-
-
-
04
-
Enrich
-
SubMiner fills in the sentence, audio clip, screenshot, and translation — no extra steps.
-
-
-
05
-
Track
-
Every line seen and card mined is logged to local SQLite. Daily and monthly rollups let you measure immersion over time.
-
-
- -
- -
- -## See It in Action - - - -
diff --git a/docs/installation.md b/docs/installation.md index 9b4b341..3371b24 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -225,7 +225,4 @@ SubMiner.AppImage --help # Show all CLI options You should see the overlay appear over mpv. If subtitles are loaded in the video, they will appear as interactive text in the overlay. -Release/pre-release gate: run `bun run test:launcher:smoke:src` to validate launcher -> mpv IPC socket -> overlay start/stop wiring. -If the smoke lane fails, inspect `.tmp/launcher-smoke` artifacts locally; CI/release quality gates upload the same artifacts on failure. - Next: [Usage](/usage) — learn about the `subminer` wrapper, keybindings, and YouTube playback. diff --git a/docs/jlpt-vocab-bundle.md b/docs/jlpt-vocab-bundle.md index 875a017..a24c59a 100644 --- a/docs/jlpt-vocab-bundle.md +++ b/docs/jlpt-vocab-bundle.md @@ -40,22 +40,6 @@ For reproducible updates: This repository currently ships the folder path in `electron-builder` `extraResources` as: `vendor/yomitan-jlpt-vocab -> yomitan-jlpt-vocab`. -## Deterministic fallback behavior on malformed inputs +## Fallback Behavior -`createJlptVocabularyLookupService()` follows these rules: - -- If a bank file is missing, parsing fails, or the JSON shape is unsupported, that file is skipped and processing continues. -- If entries do not expose expected frequency metadata, they are skipped. -- If no usable bank entries are found, SubMiner initializes a no-op JLPT lookup (`null` for every token). -- In all fallback cases, subtitle rendering remains unchanged (no underlines are added). - -## Bundle size and startup cost - -Lookup work is currently a synchronous file read + parse at enable-time and then O(1) in-memory `Map` lookups during subtitle updates. - -Practical guidance: - -- Keep the JLPT bundle inside `vendor/yomitan-jlpt-vocab` to avoid network lookups. -- Measure bundle size with: - - `du -sh vendor/yomitan-jlpt-vocab` -- If the JLPT source is updated, re-run `bun run build:appimage` / packaging and confirm startup logs do not report missing banks. +If bank files are missing, malformed, or lack expected metadata, SubMiner skips them gracefully. When no usable entries are found, JLPT underlining is silently disabled and subtitle rendering remains unchanged. diff --git a/docs/launcher-script.md b/docs/launcher-script.md index 0182f2f..0b74d2a 100644 --- a/docs/launcher-script.md +++ b/docs/launcher-script.md @@ -96,10 +96,3 @@ Use `subminer -h` for command-specific help. - `--background` mode defaults to `warn` unless `--log-level` is explicitly set - `--dev` / `--debug` control app behavior, not logging verbosity — use `--log-level` for that -## Testing - -Run launcher regression tests (config discovery + command branching): - -```bash -bun run test:launcher -``` diff --git a/docs/mining-workflow.md b/docs/mining-workflow.md index 1c528d9..b156dc2 100644 --- a/docs/mining-workflow.md +++ b/docs/mining-workflow.md @@ -24,13 +24,13 @@ SubMiner now prioritizes subtitle responsiveness over heavy initialization: This keeps early playback snappy and avoids mpv-side sluggishness while startup work completes. -## The Two Overlay Layers +## The Three Overlay Planes -SubMiner uses two overlay layers, each serving a different purpose. +SubMiner uses three overlay planes, each serving a different purpose. ### Visible Overlay -The visible overlay renders subtitles as tokenized, clickable word spans. Each word is a separate element with reading and headword data attached. This layer is styled independently from mpv subtitles and supports: +The visible overlay renders subtitles as tokenized, clickable word spans. Each word is a separate element with reading and headword data attached. This plane is styled independently from mpv subtitles and supports: - Word-level click targets for Yomitan lookup - Right-click to pause/resume @@ -40,15 +40,29 @@ The visible overlay renders subtitles as tokenized, clickable word spans. Each w Toggle with `Alt+Shift+O` (global) or `y-t` (mpv plugin). +### Secondary Subtitle Plane + +The secondary plane is a compact top-strip layer for translation and context visibility while keeping primary reading flow below. It mirrors your configured secondary subtitle preference and can be independently shown or hidden. + +It is controlled by `secondarySub` configuration and shares lifecycle with the overlay stack. + ### Invisible Overlay -The invisible overlay is a transparent layer that aligns precisely with mpv's own subtitle rendering. It reproduces the subtitle text at the exact position and size mpv uses, so you can click directly on the subtitles you see in the video. +The invisible overlay is a transparent layer aligned with mpv's own subtitle rendering. It uses mpv's subtitle metrics (font size, margins, position, scaling) to map click targets accurately. -This layer uses mpv's subtitle render metrics (font size, margins, position, scaling) and converts them from mpv's scaled-pixel system (reference height 720) to actual screen pixels. +This layer still supports: -Toggle with `Alt+Shift+I` (global) or `y-i` (mpv plugin). +- Word-level click-through lookups over the text region +- Optional manual position fine-tuning in pixel mode +- Independent toggle behavior with global shortcuts -**Position edit mode**: Press `Ctrl/Cmd+Shift+P` to enter edit mode, then use arrow keys (or `hjkl`) to nudge the position. `Shift` moves 4 px at a time. Press `Enter` or `Ctrl+S` to save, `Esc` to cancel. +Position edit mode is available via `Ctrl/Cmd+Shift+P`, then arrow keys / `hjkl` to nudge position; `Shift` moves faster. Save with `Enter` or `Ctrl+S`, cancel with `Esc`. + +Toggle controls: + +- `Alt+Shift+O` / `y-t`: visible overlay +- `Alt+Shift+I` / `y-i`: invisible overlay +- Secondary plane visibility is controlled via `secondarySub` config and matching global shortcuts. ## Looking Up Words diff --git a/docs/structure-roadmap.md b/docs/structure-roadmap.md deleted file mode 100644 index bc63c07..0000000 --- a/docs/structure-roadmap.md +++ /dev/null @@ -1,7 +0,0 @@ -# Structure Roadmap (Archived) - -This page previously contained TASK-27 migration planning details. - -- Canonical runtime architecture guidance now lives in `docs/architecture.md`. -- Contributor-facing implementation expectations are in `docs/development.md` and link back to `docs/architecture.md`. -- Historical task-level migration context is preserved in Backlog task records and archive folders. diff --git a/docs/subagents/INDEX.md b/docs/subagents/INDEX.md index 7cf68a0..7782984 100644 --- a/docs/subagents/INDEX.md +++ b/docs/subagents/INDEX.md @@ -87,4 +87,6 @@ Read first. Keep concise. | `opencode-task103-jellyfin-main-composer-20260222T221152Z-n3p7` | `opencode-task103-jellyfin-main-composer` | `Implement TASK-103 Jellyfin runtime wiring extraction from main.ts into composer module(s), tests, docs, and required validations (no commit).` | `in_progress` | `docs/subagents/agents/opencode-task103-jellyfin-main-composer-20260222T221152Z-n3p7.md` | `2026-02-22T22:11:52Z` | | `opencode-task109-discord-presence-20260223T011027Z-j9r4` | `opencode-task109-discord-presence` | `Finalize TASK-109 Discord Rich Presence with plan-first workflow and backlog closure.` | `in_progress` | `docs/subagents/agents/opencode-task109-discord-presence-20260223T011027Z-j9r4.md` | `2026-02-23T01:15:39Z` | | `codex-task88-yomitan-flow-20260223T012755Z-x4m2` | `codex-task88-yomitan-flow` | `Execute TASK-88 remove MeCab fallback tokenizer and simplify Yomitan token flow via plan-first workflow (no commit).` | `handoff` | `docs/subagents/agents/codex-task88-yomitan-flow-20260223T012755Z-x4m2.md` | `2026-02-23T01:44:16Z` | -| `codex-overlay-three-window-layout-20260223T021606Z-9z2t` | `codex-overlay-three-window-layout` | `Implement top-anchored secondary subtitle overlay window (20%) plus swappable primary overlay region (80%).` | `handoff` | `docs/subagents/agents/codex-overlay-three-window-layout-20260223T021606Z-9z2t.md` | `2026-02-23T02:29:51Z` | +| `codex-overlay-three-window-layout-20260223T021606Z-9z2t` | `codex-overlay-three-window-layout` | `Implement top-anchored secondary subtitle overlay window (20%) plus swappable primary overlay region (80%).` | `handoff` | `docs/subagents/agents/codex-overlay-three-window-layout-20260223T021606Z-9z2t.md` | `2026-02-23T02:44:37Z` | +| `opencode-task110-backlog-sync-20260223T025059Z-k3m7` | `opencode-task110-backlog-sync` | `Verify TASK-110 completion state and synchronize backlog metadata with plan-first workflow.` | `handoff` | `docs/subagents/agents/opencode-task110-backlog-sync-20260223T025059Z-k3m7.md` | `2026-02-23T02:53:30Z` | +| `codex-docs-page-polish-20260223T025932Z-b7k2` | `codex-docs-page-polish` | `Polish docs landing page and sync public workflow docs with current overlay stack.` | `handoff` | `docs/subagents/agents/codex-docs-page-polish-20260223T025932Z-b7k2.md` | `2026-02-23T03:19:20Z` | diff --git a/docs/subagents/agents/codex-docs-page-polish-20260223T025932Z-b7k2.md b/docs/subagents/agents/codex-docs-page-polish-20260223T025932Z-b7k2.md new file mode 100644 index 0000000..e05a028 --- /dev/null +++ b/docs/subagents/agents/codex-docs-page-polish-20260223T025932Z-b7k2.md @@ -0,0 +1,29 @@ +# Agent: `codex-docs-page-polish-20260223T025932Z-b7k2` + +- alias: `codex-docs-page-polish` +- mission: `Polish homepage/docs presentation for production readiness and remove stale overlay documentation` +- status: `handoff` +- branch: `` +- started_at: `2026-02-23T02:59:52Z` +- heartbeat_minutes: `5` + +## Current Work +- [2026-02-23T02:59:52Z] intent: redesign `docs/index.md` into a production-style landing page and remove outdated two-layer wording in workflow docs. +- [2026-02-23T03:05:12Z] progress: updated homepage structure, styling, and messaging; updated `docs/mining-workflow.md` to reflect three overlay planes. +- [2026-02-23T03:10:47Z] handoff: pending completion of subagent bookkeeping and final handoff summary. +- [2026-02-23T03:20:10Z] handoff: completed docs production pass; validated updates in `docs/index.md`, `docs/mining-workflow.md`, `docs/development.md`, and subagent protocol files. + +## Files Touched +- `docs/index.md` +- `docs/mining-workflow.md` +- `docs/subagents/INDEX.md` +- `docs/subagents/collaboration.md` + +## Assumptions +- Repo overlay behavior now uses three overlay planes (visible, invisible, secondary), and docs should reflect that in user-facing guides. + +## Open Questions / Blockers +- None. + +## Next Step +- Update subagent index/collaboration rows, then finalize with summary of docs cleanup. diff --git a/docs/subagents/agents/codex-overlay-three-window-layout-20260223T021606Z-9z2t.md b/docs/subagents/agents/codex-overlay-three-window-layout-20260223T021606Z-9z2t.md index 7937d68..e46bf2b 100644 --- a/docs/subagents/agents/codex-overlay-three-window-layout-20260223T021606Z-9z2t.md +++ b/docs/subagents/agents/codex-overlay-three-window-layout-20260223T021606Z-9z2t.md @@ -41,6 +41,7 @@ - `2026-02-23T02:24:10Z` implementation: added `secondary` overlay window kind/wiring, overlay-manager secondary window ownership, and geometry split helper (`top 20%` secondary + `bottom 80%` primary). - `2026-02-23T02:27:40Z` renderer updates: added `secondary` layer detection, disabled measurement reports for secondary layer, and CSS layer split (secondary hidden in primary layers; subtitle/modals hidden in secondary layer). - `2026-02-23T02:29:51Z` validation: `bun run tsc --noEmit`; `bun test src/main/runtime/overlay-window-factory.test.ts src/main/runtime/overlay-window-factory-main-deps.test.ts src/main/runtime/overlay-window-runtime-handlers.test.ts src/renderer/error-recovery.test.ts src/core/services/overlay-window.test.ts`; `bun run build`; `node --test dist/core/services/overlay-manager.test.js`. +- `2026-02-23T02:44:37Z` backlog sync: updated `TASK-110` with final summary + commit reference (`b8f7d5e`). ## Files Touched diff --git a/docs/subagents/agents/opencode-task110-backlog-sync-20260223T025059Z-k3m7.md b/docs/subagents/agents/opencode-task110-backlog-sync-20260223T025059Z-k3m7.md new file mode 100644 index 0000000..9a54b51 --- /dev/null +++ b/docs/subagents/agents/opencode-task110-backlog-sync-20260223T025059Z-k3m7.md @@ -0,0 +1,36 @@ +# Agent: `opencode-task110-backlog-sync-20260223T025059Z-k3m7` + +- alias: `opencode-task110-backlog-sync` +- mission: `Verify TASK-110 completion state and synchronize backlog metadata with plan-first workflow.` +- status: `handoff` +- branch: `main` +- started_at: `2026-02-23T02:50:59Z` +- heartbeat_minutes: `5` + +## Current Work (newest first) + +- [2026-02-23T02:53:30Z] completed: wrote closure plan artifact, recorded plan on TASK-110, verified commit/code evidence (including parallel subagent checks), and appended verification note in backlog while keeping status `Done`. +- [2026-02-23T02:52:40Z] progress: dispatched parallel subagents for commit-scope audit and implementation-evidence audit; both confirmed AC alignment. +- [2026-02-23T02:50:59Z] intent: load TASK-110 context from Backlog MCP, write closure verification plan, execute plan, and update backlog metadata if any gap remains. +- [2026-02-23T02:50:59Z] assumptions: TASK-110 implementation already landed; this pass is verification + backlog synchronization only. + +## Files Touched + +- `docs/subagents/INDEX.md` +- `docs/subagents/collaboration.md` +- `docs/subagents/agents/opencode-task110-backlog-sync-20260223T025059Z-k3m7.md` +- `docs/plans/2026-02-23-task-110-overlay-closure-verification.md` +- `backlog/tasks/task-110 - Split-overlay-into-top-secondary-bar-and-bottom-primary-region.md` (via Backlog MCP) + +## Assumptions + +- Backlog MCP task record is source of truth for completion state. +- No code edits are required unless validation uncovers missing closure evidence. + +## Open Questions / Blockers + +- None. + +## Next Step + +- Await user confirmation; no further TASK-110 work required unless additional closure metadata is requested. diff --git a/docs/subagents/collaboration.md b/docs/subagents/collaboration.md index 93382df..1013083 100644 --- a/docs/subagents/collaboration.md +++ b/docs/subagents/collaboration.md @@ -3,6 +3,8 @@ Shared notes. Append-only. - [YYYY-MM-DDTHH:MM:SSZ] [agent_id|alias] note, question, dependency, conflict, decision. +- [2026-02-23T03:10:47Z] [codex-docs-page-polish-20260223T025932Z-b7k2|codex-docs-page-polish] started a docs production pass to refresh `docs/index.md` landing structure and align `docs/mining-workflow.md` with current three-plane overlay behavior; added own task row in `docs/subagents/INDEX.md`. +- [2026-02-23T03:20:10Z] [codex-docs-page-polish-20260223T025932Z-b7k2|codex-docs-page-polish] completed pass: polished docs homepage design, updated outdated overlay wording in workflow guide, removed placeholder note in dev docs, and updated subagent index/collaboration records. - [2026-02-19T08:21:11Z] [codex-main|planner-exec] conflict note: `docs/subagents/INDEX.md` and `docs/subagents/agents/codex-main.md` were externally updated to TASK-69 while TASK-38 work was in-flight; reconciled own row/file back to TASK-38 handoff state. - [2026-02-20T00:01:40Z] [codex-anilist-deeplink|anilist-deeplink] preparing commit; scoping staged set to repo changes, excluding external reference dirs (vendor/yomitan-jlpt-vocab, mpv-anilist-updater). - [2026-02-20T05:42:54Z] [codex-subtitle-bg-20260220T054247Z-h9cu|codex-subtitle-bg] short config tweak requested: update default subtitle background color; scoping to config defaults/tests only. @@ -152,3 +154,6 @@ Shared notes. Append-only. - [2026-02-23T01:44:16Z] [codex-task88-yomitan-flow-20260223T012755Z-x4m2|codex-task88-yomitan-flow] completed TASK-88 implementation pass: removed MeCab fallback branch from `tokenizeSubtitle`, restricted parser-selection to `scanning-parser` candidates, refreshed tokenizer regressions for Yomitan-only flow, updated usage/troubleshooting docs, and verified tokenizer+subtitle suites/build/docs-build green. - [2026-02-23T02:16:06Z] [codex-overlay-three-window-layout-20260223T021606Z-9z2t|codex-overlay-three-window-layout] overlap note: implementing user-requested 3-window overlay layout (`secondary` top bar + `visible|invisible` bottom region) in `src/core/services/overlay-window.ts`, `src/core/services/overlay-runtime-init.ts`, `src/main.ts`, renderer layer handling/CSS, and focused runtime/core tests. - [2026-02-23T02:29:51Z] [codex-overlay-three-window-layout-20260223T021606Z-9z2t|codex-overlay-three-window-layout] completed TASK-110 implementation: added `secondary` overlay window kind + manager ownership, enforced top-20%/bottom-80% bounds split in main runtime updates, hid secondary bar in primary renderer layers, and validated via focused tests + tsc + build + dist overlay-manager test. +- [2026-02-23T02:44:37Z] [codex-overlay-three-window-layout-20260223T021606Z-9z2t|codex-overlay-three-window-layout] backlog sync requested post-commit; updated TASK-110 `updated_date`, added commit reference (`b8f7d5e`), and added final summary block. +- [2026-02-23T02:50:59Z] [opencode-task110-backlog-sync-20260223T025059Z-k3m7|opencode-task110-backlog-sync] starting TASK-110 closure verification pass via Backlog MCP + writing-plans/executing-plans workflow; scope backlog metadata validation/sync only unless missing evidence is found. +- [2026-02-23T02:53:30Z] [opencode-task110-backlog-sync-20260223T025059Z-k3m7|opencode-task110-backlog-sync] completed verification/sync: recorded closure plan, revalidated commit/code evidence (parallel subagent audits), appended TASK-110 verification note, and confirmed task remains Done with all AC checked.