mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
Merge pull request #10 from ksyasuda/fix/bun-tooling-migration
fix: migrate tooling to bun and accept file path targets
This commit is contained in:
38
.github/workflows/ci.yml
vendored
38
.github/workflows/ci.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
lint-and-audit:
|
||||
build-test-audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -15,38 +15,46 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
version: 9
|
||||
bun-version: 1.3.5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.bun/install/cache
|
||||
node_modules
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build (TypeScript check)
|
||||
run: pnpm exec tsc --noEmit
|
||||
# Keep explicit typecheck for fast fail before full build/bundle.
|
||||
run: bun run tsc --noEmit
|
||||
|
||||
- name: Build (bundle)
|
||||
run: pnpm run build
|
||||
run: bun run build
|
||||
|
||||
- name: Test suite
|
||||
run: pnpm test
|
||||
run: bun run test:fast
|
||||
|
||||
- name: Build docs
|
||||
run: bun run docs:build
|
||||
|
||||
- name: Security audit
|
||||
run: pnpm audit --audit-level=high
|
||||
run: bun audit --audit-level high
|
||||
continue-on-error: true
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Build Bun subminer wrapper
|
||||
run: make build-launcher
|
||||
|
||||
|
||||
1
.github/workflows/claude.yml
vendored
1
.github/workflows/claude.yml
vendored
@@ -47,4 +47,3 @@ jobs:
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
||||
|
||||
|
||||
113
.github/workflows/release.yml
vendored
113
.github/workflows/release.yml
vendored
@@ -5,11 +5,15 @@ on:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
concurrency:
|
||||
group: release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
quality-gate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -17,28 +21,75 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
version: 9
|
||||
bun-version: 1.3.5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: pnpm
|
||||
node-version: 22
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.bun/install/cache
|
||||
node_modules
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build + test
|
||||
run: |
|
||||
bun run build
|
||||
bun run test:fast
|
||||
|
||||
build-linux:
|
||||
needs: [quality-gate]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.bun/install/cache
|
||||
node_modules
|
||||
vendor/texthooker-ui/node_modules
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock', 'vendor/texthooker-ui/package.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build texthooker-ui
|
||||
run: |
|
||||
cd vendor/texthooker-ui
|
||||
pnpm install
|
||||
pnpm build
|
||||
bun install
|
||||
bun run build
|
||||
|
||||
- name: Build AppImage
|
||||
run: pnpm run build:appimage
|
||||
run: bun run build:appimage
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -49,6 +100,7 @@ jobs:
|
||||
path: release/*.AppImage
|
||||
|
||||
build-macos:
|
||||
needs: [quality-gate]
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -56,16 +108,26 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
version: 9
|
||||
bun-version: 1.3.5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: pnpm
|
||||
node-version: 22
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.bun/install/cache
|
||||
node_modules
|
||||
vendor/texthooker-ui/node_modules
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock', 'vendor/texthooker-ui/package.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Validate macOS signing/notarization secrets
|
||||
run: |
|
||||
@@ -88,16 +150,16 @@ jobs:
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build texthooker-ui
|
||||
run: |
|
||||
cd vendor/texthooker-ui
|
||||
pnpm install
|
||||
pnpm build
|
||||
bun install
|
||||
bun run build
|
||||
|
||||
- name: Build signed + notarized macOS artifacts
|
||||
run: pnpm run build:mac
|
||||
run: bun run build:mac
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||
@@ -138,7 +200,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
bun-version: 1.3.5
|
||||
|
||||
- name: Build Bun subminer wrapper
|
||||
run: make build-launcher
|
||||
@@ -146,6 +208,16 @@ jobs:
|
||||
- name: Verify Bun subminer wrapper
|
||||
run: ./subminer --help >/dev/null
|
||||
|
||||
- name: Generate checksums
|
||||
run: |
|
||||
shopt -s nullglob
|
||||
files=(release/*.AppImage release/*.dmg release/*.zip subminer)
|
||||
if [ "${#files[@]}" -eq 0 ]; then
|
||||
echo "No release artifacts found for checksum generation."
|
||||
exit 1
|
||||
fi
|
||||
sha256sum "${files[@]}" > release/SHA256SUMS.txt
|
||||
|
||||
- name: Get version from tag
|
||||
id: version
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
@@ -196,6 +268,7 @@ jobs:
|
||||
release/*.AppImage
|
||||
release/*.dmg
|
||||
release/*.zip
|
||||
release/SHA256SUMS.txt
|
||||
subminer
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
6
.prettierignore
Normal file
6
.prettierignore
Normal file
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
dist
|
||||
release
|
||||
coverage
|
||||
vendor
|
||||
*.log
|
||||
5
.prettierrc.json
Normal file
5
.prettierrc.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
76
Makefile
76
Makefile
@@ -1,4 +1,4 @@
|
||||
.PHONY: help deps build build-launcher install build-linux build-macos build-macos-unsigned clean install-linux install-macos install-plugin uninstall uninstall-linux uninstall-macos print-dirs pretty ensure-pnpm generate-config generate-example-config docs-dev docs docs-preview dev-start dev-start-macos dev-toggle dev-stop
|
||||
.PHONY: help deps build build-launcher install build-linux build-macos build-macos-unsigned clean install-linux install-macos install-plugin uninstall uninstall-linux uninstall-macos print-dirs pretty ensure-bun generate-config generate-example-config docs-dev docs docs-preview dev-start dev-start-macos dev-toggle dev-stop
|
||||
|
||||
APP_NAME := subminer
|
||||
THEME_FILE := subminer.rasi
|
||||
@@ -90,15 +90,15 @@ print-dirs:
|
||||
"MACOS_ZIP_SRC=$(MACOS_ZIP_SRC)"
|
||||
|
||||
deps:
|
||||
@$(MAKE) --no-print-directory ensure-pnpm
|
||||
@pnpm install
|
||||
@pnpm -C vendor/texthooker-ui install
|
||||
@$(MAKE) --no-print-directory ensure-bun
|
||||
@bun install
|
||||
@cd vendor/texthooker-ui && bun install
|
||||
|
||||
ensure-pnpm:
|
||||
@command -v pnpm >/dev/null 2>&1 || { printf '%s\n' "[ERROR] pnpm not found"; exit 1; }
|
||||
ensure-bun:
|
||||
@command -v bun >/dev/null 2>&1 || { printf '%s\n' "[ERROR] bun not found"; exit 1; }
|
||||
|
||||
pretty:
|
||||
@pnpm exec prettier --write 'src/**/*.ts'
|
||||
pretty: ensure-bun
|
||||
@bun run format
|
||||
|
||||
build:
|
||||
@printf '%s\n' "[INFO] Detected platform: $(PLATFORM)"
|
||||
@@ -118,23 +118,25 @@ install:
|
||||
|
||||
build-linux: deps
|
||||
@printf '%s\n' "[INFO] Building Linux package (AppImage)"
|
||||
@pnpm -C vendor/texthooker-ui build
|
||||
@pnpm run build:appimage
|
||||
@cd vendor/texthooker-ui && bun run build
|
||||
@bun run build:appimage
|
||||
|
||||
build-macos: deps
|
||||
@printf '%s\n' "[INFO] Building macOS package (DMG + ZIP)"
|
||||
@pnpm -C vendor/texthooker-ui build
|
||||
@pnpm run build:mac
|
||||
@cd vendor/texthooker-ui && bun run build
|
||||
@bun run build:mac
|
||||
|
||||
build-macos-unsigned: deps
|
||||
@printf '%s\n' "[INFO] Building macOS package (DMG + ZIP, unsigned)"
|
||||
@pnpm -C vendor/texthooker-ui build
|
||||
@pnpm run build:mac:unsigned
|
||||
@cd vendor/texthooker-ui && bun run build
|
||||
@bun run build:mac:unsigned
|
||||
|
||||
build-launcher:
|
||||
@printf '%s\n' "[INFO] Bundling launcher script"
|
||||
@bun build ./launcher/main.ts --target=bun --packages=bundle --outfile=subminer
|
||||
@python3 -c 'from pathlib import Path; p=Path("subminer"); c=p.read_text(); c=("#!/usr/bin/env bun\n"+c) if not c.startswith("#!/usr/bin/env bun\n") else c; p.write_text(c)'
|
||||
@if ! head -1 subminer | grep -q '^#!/usr/bin/env bun'; then \
|
||||
{ printf '#!/usr/bin/env bun\n'; cat subminer; } > subminer.tmp && mv subminer.tmp subminer; \
|
||||
fi
|
||||
@chmod +x subminer
|
||||
|
||||
clean:
|
||||
@@ -144,36 +146,36 @@ clean:
|
||||
@rm -f "$(BINDIR)/subminer" "$(BINDIR)/SubMiner.AppImage"
|
||||
@rm -rf dist release
|
||||
|
||||
generate-config: ensure-pnpm
|
||||
@pnpm run build
|
||||
@pnpm exec electron . --generate-config
|
||||
generate-config: ensure-bun
|
||||
@bun run build
|
||||
@bun run electron . --generate-config
|
||||
|
||||
generate-example-config: ensure-pnpm
|
||||
@pnpm run build
|
||||
@pnpm run generate:config-example
|
||||
generate-example-config: ensure-bun
|
||||
@bun run build
|
||||
@bun run generate:config-example
|
||||
|
||||
docs-dev: ensure-pnpm
|
||||
@pnpm run docs:dev
|
||||
docs-dev: ensure-bun
|
||||
@bun run docs:dev
|
||||
|
||||
docs: ensure-pnpm
|
||||
@pnpm run docs:build
|
||||
docs: ensure-bun
|
||||
@bun run docs:build
|
||||
|
||||
docs-preview: ensure-pnpm
|
||||
@pnpm run docs:preview
|
||||
docs-preview: ensure-bun
|
||||
@bun run docs:preview
|
||||
|
||||
dev-start: ensure-pnpm
|
||||
@pnpm run build
|
||||
@pnpm exec electron . --start
|
||||
dev-start: ensure-bun
|
||||
@bun run build
|
||||
@bun run electron . --start
|
||||
|
||||
dev-start-macos: ensure-pnpm
|
||||
@pnpm run build
|
||||
@pnpm exec electron . --start --backend macos
|
||||
dev-start-macos: ensure-bun
|
||||
@bun run build
|
||||
@bun run electron . --start --backend macos
|
||||
|
||||
dev-toggle: ensure-pnpm
|
||||
@pnpm exec electron . --toggle
|
||||
dev-toggle: ensure-bun
|
||||
@bun run electron . --toggle
|
||||
|
||||
dev-stop: ensure-pnpm
|
||||
@pnpm exec electron . --stop
|
||||
dev-stop: ensure-bun
|
||||
@bun run electron . --stop
|
||||
|
||||
|
||||
install-linux: build-launcher
|
||||
|
||||
@@ -46,7 +46,10 @@ The `subminer` wrapper uses a [Bun](https://bun.sh) shebang, so `bun` must be on
|
||||
```bash
|
||||
git clone --recurse-submodules https://github.com/ksyasuda/SubMiner.git
|
||||
cd SubMiner
|
||||
make build && make install
|
||||
bun install
|
||||
cd vendor/texthooker-ui && bun install && cd ../..
|
||||
make build
|
||||
make install
|
||||
```
|
||||
|
||||
For macOS builds and platform details, see the [installation docs](docs/installation.md).
|
||||
@@ -54,6 +57,7 @@ For macOS builds and platform details, see the [installation docs](docs/installa
|
||||
## Quick Start
|
||||
|
||||
1. Copy [`config.example.jsonc`](config.example.jsonc) to `~/.config/SubMiner/config.jsonc`
|
||||
- Regenerate anytime from source: `make generate-example-config` or `bun run generate:config-example`
|
||||
2. Start mpv with IPC:
|
||||
```bash
|
||||
mpv --input-ipc-server=/tmp/subminer-socket video.mkv
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
id: m-0
|
||||
title: "Codebase Clarity & Composability"
|
||||
title: 'Codebase Clarity & Composability'
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
@@ -13,12 +13,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Restored task after accidental cleanup. Ensure keybindings are available whenever the Electron runtime is active, while respecting focused overlay/input contexts that require local key handling.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Started implementation: tracing overlay shortcut registration lifecycle and runtime activation gating.
|
||||
|
||||
Root cause: overlay shortcut sync executes during overlay runtime initialization before overlayRuntimeInitialized is set true, so registration could be skipped until a later visibility toggle.
|
||||
@@ -32,12 +35,15 @@ Updated CLI runtime gating so --start initializes overlay runtime, which activat
|
||||
User clarified MPV-only workflow requirement. Added MPV plugin keybindings and script messages for mining/runtime actions (copy/mine/multi/mode/field-grouping/subsync/audio-card/runtime-options) so these actions are available from mpv chord bindings without relying on overlay global shortcuts.
|
||||
|
||||
Per user direction, reverted all shortcut/runtime/plugin changes from this implementation cycle. Desired behavior is to keep keybindings working only when overlay is active.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Ensured overlay shortcuts are available as soon as overlay runtime becomes active by resyncing after activation flag is set. This prevents startup states where shortcuts remained inactive until a later overlay visibility change.
|
||||
|
||||
Follow-up fix: included --start in overlay-runtime-required commands so keybinds are active right after startup, even before toggling visible/invisible overlays.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -13,11 +13,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement the overlay sizing redesign documented in `overlay_window.md`: move visible/invisible overlays from fullscreen bounds to content-bounded sizing, and decouple secondary subtitle rendering into an independent top bar window/lifecycle.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Per-layer bounds ownership is implemented for overlay windows (no shared full-bounds setter for all layers).
|
||||
- [ ] #2 Renderer-to-main IPC contract exists for measured overlay content bounds with layer identity and safe validation.
|
||||
- [ ] #3 Visible and invisible overlays use content-bounded sizing with padding/clamp/jitter protections and full-bounds fallback when measurements are unavailable.
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement content-bounded sizing for visible/invisible windows using measured rects plus tracker origin, with robust clamping and jitter resistance.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Bounds algorithm applies configurable padding, minimum size, display-workarea clamp, and integer snap.
|
||||
- [ ] #2 Main-process bounds updates are thresholded/debounced to reduce jitter and unnecessary `setBounds` churn.
|
||||
- [ ] #3 When no valid measurement exists, layer falls back to safe tracker/display bounds without breaking interaction.
|
||||
|
||||
@@ -13,11 +13,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Create and integrate a dedicated secondary subtitle overlay window with independent lifecycle, z-order, bounds, and pointer policy, decoupled from primary visible/invisible overlay windows.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 A third overlay window dedicated to secondary subtitles is created and managed alongside existing visible/invisible windows.
|
||||
- [ ] #2 Secondary window visibility follows secondary mode semantics (`hidden`/`visible`/`hover`) independent of primary overlay visibility.
|
||||
- [ ] #3 Secondary subtitle text/mode/style updates are routed directly to the secondary window renderer path.
|
||||
|
||||
@@ -13,11 +13,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add safety controls and verification coverage for the new content-bounded overlay architecture and secondary top-bar window.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Feature flag or equivalent rollout guard exists for switching to new sizing/window behavior.
|
||||
- [ ] #2 Service-level/unit tests cover bounds clamping, jitter thresholding, invalid measurement fallback, and per-layer updates.
|
||||
- [ ] #3 Manual validation checklist documents and verifies wrap/no-wrap, style changes, monitor moves, tracker churn, modal interactions, and simultaneous overlay states.
|
||||
|
||||
@@ -12,11 +12,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Investigate and implement a UX where secondary subtitles (e.g., English text in our current sessions) become visible when hovered, while explicitly preventing user interactions that allow text lookup (including Yomitan integration) on those subtitles. This should allow readability-on-hover without exposing the secondary overlay text to selection/lookup workflows.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Secondary subtitles become visible only while hovered (or via equivalent hover-triggered mechanism), and return to default hidden/low-visibility state when not hovered.
|
||||
- [ ] #2 When hovered, secondary subtitles do not trigger Yomitan lookup behavior in sessions where Yomitan is enabled.
|
||||
- [ ] #3 Secondary subtitles remain non-interactive for lookup paths (for example, text selection or lookup event propagation) while hover-visibility still works as intended.
|
||||
@@ -25,6 +29,8 @@ Investigate and implement a UX where secondary subtitles (e.g., English text in
|
||||
<!-- AC:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Acceptance criteria are reviewed and covered by explicit manual/automated test coverage for hover reveal and lookup suppression behavior.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -13,13 +13,17 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add a feature to query configured extension repositories for anime titles/episodes from SubMiner, let users select a streamable source, and play it through mpv with minimal friction. The result should be interactive from Electron (and triggered from mpv via existing command bridge), and fully configurable in app config.
|
||||
|
||||
The implementation should provide a modular backend resolver and a clear UI flow that mirrors existing modal interaction patterns, while keeping mpv playback unchanged (use loadfile with resolved URL and optional headers/referrer metadata).
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Create a stable config schema for one or more extension source backends (repos/endpoints/flags) and persist in user config + default template.
|
||||
- [ ] #2 Resolve an anime search term to candidate series from configured sources.
|
||||
- [ ] #3 Resolve an episode selection to at least one playable stream URL candidate with playback metadata when available.
|
||||
@@ -32,13 +36,17 @@ The implementation should provide a modular backend resolver and a clear UI flow
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Execution sequence for implementation: 1) TASK-30.1 (config/model), 2) TASK-30.2 (resolver), 3) TASK-30.3 (IPC), 4) TASK-30.4 (UI modal), 5) TASK-30.5 (mpv trigger), 6) TASK-30.6 (validation/rollout checklist).
|
||||
|
||||
Rollout recommendation: complete TASK-30.6 only after TASK-30.1-30.5 are done and can be verified in combination.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Config schema validated in app startup (bad config surfaces clear error).
|
||||
- [ ] #2 No hardcoded source/resolver URLs in UI layer; resolver details are backend-driven.
|
||||
- [ ] #3 Play command path uses existing mpv IPC/runtime helpers.
|
||||
|
||||
@@ -14,11 +14,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Define a backend-agnostic configuration contract for extension repository streaming, including resolver endpoints/process mode, query/auth headers, timeouts, enable flags, and source preference. Wire schema through Config/ResolvedConfig and generated template/defaults so users can manage repos entirely through config.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Add new config sections for extension source providers in Config and ResolvedConfig types.
|
||||
- [ ] #2 Add validation defaults and env-compatible parsing for provider list, auth, header overrides, and feature flags.
|
||||
- [ ] #3 Update config template and docs text so defaults are discoverable and editable.
|
||||
@@ -29,11 +33,15 @@ Define a backend-agnostic configuration contract for extension repository stream
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Phase 1 — Foundation: config contract + validation + defaults
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Config examples in template/docs include at least one provider entry shape.
|
||||
- [ ] #2 Defaults remain backward-compatible when key is absent.
|
||||
- [ ] #3 Feature can be disabled without touching unrelated settings.
|
||||
|
||||
@@ -15,11 +15,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Build a dedicated service in main process that queries configured extension repos and normalizes results into a unified internal model, including optional playback metadata. Keep transport abstracted so future backends (local process, remote API, Manatán-compatible source) can be swapped without changing renderer contracts.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Create a typed internal model for source, series, episode, and playable candidate with fields for quality/audio/headers/referrer/userAgent.
|
||||
- [ ] #2 Implement provider abstraction with pluggable fetch/execution strategy from config.
|
||||
- [ ] #3 Add services for searchAnime, listEpisodes, resolveStream (or equivalent) with cancellation/error boundaries.
|
||||
@@ -30,11 +34,15 @@ Build a dedicated service in main process that queries configured extension repo
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Phase 2 — Core service: provider integration and stream resolution
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Resolver never leaks raw provider payload to renderer.
|
||||
- [ ] #2 Streaming URL output includes reason for failure when unavailable.
|
||||
- [ ] #3 Service boundaries allow unit-level validation of request/response mapping logic.
|
||||
|
||||
@@ -15,11 +15,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add a typed preload and main-IPC contract for streaming queries and playback resolution so the renderer can initiate search/list/resolve without embedding network/provider logic in UI code.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Define IPC handlers in main with input/output schema validation and timeouts.
|
||||
- [ ] #2 Expose corresponding functions in preload `window.electronAPI` and ElectronAPI types.
|
||||
- [ ] #3 Reuse existing mpv command channel for playback and add a dedicated request/response flow for resolver actions.
|
||||
@@ -31,11 +35,15 @@ Add a typed preload and main-IPC contract for streaming queries and playback res
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Phase 3 — API surface: IPC/preload contract for resolver operations
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Renderer code can query providers without importing Node-only modules.
|
||||
- [ ] #2 IPC paths have clear names and consistent response shapes across all calls.
|
||||
- [ ] #3 Error paths return explicit machine-readable codes mapped to user-visible messages.
|
||||
|
||||
@@ -15,11 +15,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement a renderer flow to query configured providers, display results, let user choose series and episode, and trigger playback for a selected stream. The UI should support keyboard interactions and surface backend errors clearly.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Create modal UI/state model for query, results list, selected item, episode list, candidate qualities, and loading/error status.
|
||||
- [ ] #2 Wire renderer actions to new IPC methods for search/episode/resolve.
|
||||
- [ ] #3 Render one-click or enter-to-play action that calls existing mpv playback pathway.
|
||||
@@ -31,11 +35,15 @@ Implement a renderer flow to query configured providers, display results, let us
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Phase 4 — UX: interactive modal flow and playback callout
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Modal state is isolated and unsubscribes listeners on close.
|
||||
- [ ] #2 No direct network logic in renderer beyond IPC calls.
|
||||
- [ ] #3 Visual style and behavior are consistent with existing modal patterns.
|
||||
|
||||
@@ -18,11 +18,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Allow users to open streaming selection from within mpv via keybind/menu and route that intent into renderer modal and playback flow without requiring separate window focus changes.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Add/extend mpv Lua plugin or existing command registry to emit a custom action for opening the streaming picker.
|
||||
- [ ] #2 Handle this action in main IPC/mpv-command pipeline and forward to renderer modal state.
|
||||
- [ ] #3 Add at least one default keybinding/menu entry documented in config/plugin notes.
|
||||
@@ -33,11 +37,15 @@ Allow users to open streaming selection from within mpv via keybind/menu and rou
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Phase 5 — In-player entry: mpv trigger/menu integration
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 No duplicate mpv command parsing between picker and legacy commands.
|
||||
- [ ] #2 Feature can be used in overlay and mpv-only mode where applicable.
|
||||
- [ ] #3 No dependency on modal open state when launched by mpv trigger.
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Create a concrete validation task that defines end-to-end acceptance checks for config loading, resolver behavior, IPC contract correctness, UI flow, and mpv-triggered launch. The checklist should be actionable and align with existing project conventions so completion can be verified without guesswork.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Define test scenarios for config success/failure cases, including invalid provider config and feature disabled mode.
|
||||
- [ ] #2 Define search/list/resolve API contract tests and error-code assertions (empty, timeout, auth error, no playable URL).
|
||||
- [ ] #3 Define renderer UX checks for modal state transitions, loading indicators, empty results, selection, and play invocation.
|
||||
@@ -33,11 +37,15 @@ Create a concrete validation task that defines end-to-end acceptance checks for
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Phase 6 — Validation: rollout, smoke tests, and release readiness checklist
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Checklist covers happy-path and failure-path for each task dependency.
|
||||
- [ ] #2 Verification steps are executable without external tooling assumptions.
|
||||
- [ ] #3 No task can be marked done without explicit evidence fields filled in.
|
||||
|
||||
@@ -17,11 +17,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Improve the Aniyomi/anime extension streaming flow to prefer English-capable sources with soft subtitles, and automatically recover when only hard-subbed streams are available by stripping embedded subtitles with ffmpeg and attaching external Jimaku subtitle files into mpv.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 During source scoring/selection, prefer providers/sources that declare or expose soft subtitles for English audio or subtitle tracks over hard-subbed alternatives.
|
||||
- [ ] #2 Add a config option for preferred language targets (default English) and fallback policy (favor soft subtitles, then hard-sub fallback).
|
||||
- [ ] #3 Detect when a resolved stream is hard-sub-only and a soft-sub source is unavailable for the same episode.
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add lightweight telemetry/analytics hooks (local logs + optional structured counters) to measure how Aniyomi/anime streaming source selection behaves, including soft-sub preference, hard-sub fallback usage, and ffmpeg+Jimaku post-processing outcomes, to support source ranking tuning.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Track per-playback decision metadata including chosen source, language match score, subtitle mode (soft/hard), and reason for source preference ordering.
|
||||
- [ ] #2 Emit success/failure counters for hard-sub stripping attempts (started/succeeded/failed/unsupported codec) with reason codes.
|
||||
- [ ] #3 Log whether Jimaku subtitle attachment was available and successfully loaded for ffmpeg-assisted flows.
|
||||
|
||||
@@ -15,11 +15,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add user-configurable controls for Aniyomi streaming subtitle behavior, including preferred language profile, soft-vs-hard source preference, ffmpeg-assisted hard-sub removal behavior, and policy toggles so quality and fallback behavior can be tuned without code changes.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Add settings UI fields to define preferred subtitle/audiotrack language order (e.g., en, ja) and enable/disable hard-sub fallback mode.
|
||||
- [ ] #2 Add explicit toggle for enabling hard-sub stripping via ffmpeg and configurable timeout/quality limits to avoid long waits.
|
||||
- [ ] #3 Expose source ranking preferences for soft-sub vs hard-sub sources and optional fallback to native/transcoded source when preferred modes are unavailable.
|
||||
|
||||
@@ -16,12 +16,15 @@ priority: low
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Allow users to share their subtitle timing corrections to a community database, so other users watching the same video file get pre-synced subtitles automatically.
|
||||
|
||||
## Motivation
|
||||
|
||||
Subtitle synchronization (alass/ffsubsync) is one of the most friction-heavy steps in the mining workflow. Users spend time syncing subtitles that someone else has already synced for the exact same video. A shared database of timing corrections keyed by video file hash would eliminate redundant work.
|
||||
|
||||
## Design
|
||||
|
||||
1. **Video identification**: Use a partial file hash (first + last N bytes, or a media fingerprint) to identify video files without uploading content
|
||||
2. **Timing data**: Store the timing offset/warp parameters produced by alass/ffsubsync, not the full subtitle file
|
||||
3. **Upload flow**: After a successful sync, offer to share the timing correction (opt-in)
|
||||
@@ -29,6 +32,7 @@ Subtitle synchronization (alass/ffsubsync) is one of the most friction-heavy ste
|
||||
5. **Trust model**: Simple upvote/downvote on corrections; show number of users who confirmed a correction works
|
||||
|
||||
## Technical considerations
|
||||
|
||||
- Backend could be a simple REST API with a lightweight database (or even a GitHub-hosted JSON/SQLite file for v1)
|
||||
- Privacy: only file hashes and timing parameters are shared, never video content or personal data
|
||||
- Subtitle source (jimaku entry ID) can serve as an additional matching key
|
||||
@@ -36,12 +40,15 @@ Subtitle synchronization (alass/ffsubsync) is one of the most friction-heavy ste
|
||||
- Could integrate with existing jimaku modal flow
|
||||
|
||||
## Phasing
|
||||
|
||||
- v1: Local export/import of timing corrections (share as files)
|
||||
- v2: Optional cloud sync with community database
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Video files are identified by content hash without uploading video data.
|
||||
- [ ] #2 Timing corrections (offset/warp parameters) can be exported and shared.
|
||||
- [ ] #3 Before syncing, the app checks for existing community corrections for the current video.
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement a new streaming mode so SubMiner can resolve and play episodes via ani-cli stream sources instead of existing file/download flow. The mode is enabled with a CLI flag (`-s` / `--stream`) and, when active, should prefer streamed playback and subtitle handling that keeps Japanese (or configured primary) subtitles as the main track. If a stream lacks Japanese subtitle tracks, fetch and inject subtitles from Jimaku and set them as primary subtitles according to SubMiner config.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Add a command-line option `-s`/`--stream` that enables streaming mode and is documented in help/config UX.
|
||||
- [ ] #2 When streaming mode is enabled, resolve episode/video URLs using existing ani-cli stream selection logic (ported into SubMiner) and route playback to the resolved stream source.
|
||||
- [ ] #3 If stream metadata contains a Japanese subtitle track, preserve that track as the primary subtitle stream path per current primary-subtitle selection behavior.
|
||||
@@ -32,11 +36,15 @@ Implement a new streaming mode so SubMiner can resolve and play episodes via ani
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Superseded by TASK-51. Streaming via ani-cli in subminer was removed due Cloudflare 403/unreliable source metadata; re-evaluate later if reintroduced behind a feature flag and redesigned resolver/metadata pipeline.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 CLI accepts both `-s` and `--stream` and enables streaming-specific behavior.
|
||||
- [ ] #2 Streaming mode resolves streams through migrated ani-cli logic.
|
||||
- [ ] #3 Japanese subs are preferred from stream metadata when available; Jimaku fallback is used only when absent.
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add the `-s`/`--stream` option end-to-end in SubMiner CLI and configuration handling, including defaults, help text, parsing/validation, and explicit routing so streaming mode is only enabled when requested.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Introduce `-s` short option and `--stream` long option in CLI parsing without breaking existing flags.
|
||||
- [ ] #2 When set, the resulting config state reflects streaming mode enabled and is propagated to playback/session startup.
|
||||
- [ ] #3 When unset, behavior remains identical to current non-streaming flows.
|
||||
@@ -29,5 +33,7 @@ Add the `-s`/`--stream` option end-to-end in SubMiner CLI and configuration hand
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Superseded by TASK-51. CLI stream mode work deferred until streaming architecture is revisited.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement stream URL resolution by porting ani-cli logic for selecting providers/episodes and obtaining playable stream URLs so SubMiner can consume stream sources directly.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Encapsulate stream search/provider selection logic in a dedicated module in SubMiner.
|
||||
- [ ] #2 Resolve episode query input into a canonical playable stream URL in streaming mode.
|
||||
- [ ] #3 Preserve existing behavior for non-streaming flow and expose errors when stream resolution fails.
|
||||
@@ -29,5 +33,7 @@ Implement stream URL resolution by porting ani-cli logic for selecting providers
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Superseded by TASK-51. Stream URL resolution via ani-cli postponed; previous attempt exposed anti-bot/403 fragility and poor title-source reliability.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Handle subtitle track selection for stream playback so Japanese (or configured primary language) subtitle behavior is correctly applied when stream metadata includes or omits JP tracks.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Use stream metadata to choose and mark the configured primary language subtitle as active when available.
|
||||
- [ ] #2 If no matching primary language track exists in stream metadata, keep previous fallback behavior only for non-streaming mode.
|
||||
- [ ] #3 When no Japanese track exists and config primary is different, explicitly set configured primary as primary track for streaming flow.
|
||||
@@ -29,5 +33,7 @@ Handle subtitle track selection for stream playback so Japanese (or configured p
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Superseded by TASK-51. Stream subtitle language precedence in streaming mode deferred with full design revisit.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -17,11 +17,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
When a resolved stream lacks JP/primary-language tracks, fetch subtitles from Jimaku and inject them for playback, overriding non-primary subtitle defaults in streaming mode according to config.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Detect missing primary subtitle from stream metadata and trigger Jimaku lookup for matching episode.
|
||||
- [ ] #2 Load fetched Jimaku subtitles into playback pipeline and mark them as the primary subtitle track.
|
||||
- [ ] #3 Fallback is only used in streaming mode and should not alter subtitle behavior outside streaming.
|
||||
@@ -30,5 +34,7 @@ When a resolved stream lacks JP/primary-language tracks, fetch subtitles from Ji
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Superseded by TASK-51. Jimaku fallback for streams deferred along with entire streaming flow.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: low
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Create a validation plan or tests for CLI flag behavior, stream resolution, and subtitle precedence/fallback rules so streaming mode changes are measurable and regressions are caught.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Document/manual checklist covers `-s` and `--stream` invocation and streaming-only behavior.
|
||||
- [ ] #2 Include cases for (a) stream with JP subtitles, (b) no JP subtitles with Jimaku fallback, (c) primary-language not Japanese.
|
||||
- [ ] #3 Run or provide reproducible checks to confirm non-streaming behavior unchanged.
|
||||
@@ -29,5 +33,7 @@ Create a validation plan or tests for CLI flag behavior, stream resolution, and
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Superseded by TASK-51. Verification plan moved to deferred reimplementation context.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -22,11 +22,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement SubMiner streaming mode end-to-end behind a `-s`/`--stream` flag. In stream mode, use the vendored ani-cli resolution flow to get playable stream URLs instead of local file/YouTube URL handling. If resolved streams do not expose Japanese subtitles, fetch matching subtitles from Jimaku and load them into mpv as the active primary subtitle track, overwriting the current non-primary/non-Japanese default according to subminer primary-subtitle configuration.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 When `subminer -s` is used, resolution should pass a search/query through ani-cli stream logic and play the resolved stream source.
|
||||
- [ ] #2 If the stream includes a Japanese subtitle track, preserve and select the configured primary subtitle language behavior without Jimaku injection.
|
||||
- [ ] #3 If no Japanese (or configured primary language) subtitle exists in stream metadata, fetch and inject Jimaku subtitles before playback starts.
|
||||
@@ -37,11 +41,15 @@ Implement SubMiner streaming mode end-to-end behind a `-s`/`--stream` flag. In s
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Superseded by TASK-51. End-to-end stream wiring to ani-cli is deferred.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 CLI exposes both `-s` and `--stream` in help/config and validation.
|
||||
- [ ] #2 Implementation includes a clear fallback path when stream subtitles are absent and Jimaku search/download fails gracefully.
|
||||
- [ ] #3 Subtitles loading path avoids temp-file leaks; temporary media/subtitle artifacts are cleaned up on exit.
|
||||
|
||||
@@ -15,9 +15,11 @@ dependencies: []
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Current codebase has removed ani-cli integration and stream-mode from subminer temporarily. Keep a deferred design task to reintroduce streaming mode in a future cycle.
|
||||
|
||||
Findings from prior attempts:
|
||||
|
||||
- `subminer -s <query>` path relied on `ani-cli` resolving stream URLs, but returned stream URLs that are Cloudflare-protected (`tools.fast4speed.rsvp`) and often returned 403 from mpv/ytdl-hook (generic anti-bot/Forbidden).
|
||||
- Even after passing `ytdl` extractor args, stream playback via subminer still failed because URL/anti-bot handling differed from direct ani-cli execution context.
|
||||
- We also observed stream title resolution issues: selected titles from ani-cli menu were unreliable/random and broke downstream Jimaku matching behavior.
|
||||
@@ -25,6 +27,7 @@ Findings from prior attempts:
|
||||
- Based on these findings and instability, stream mode should be explicitly deferred rather than partially reintroduced.
|
||||
|
||||
Proposal:
|
||||
|
||||
- Reintroduce behind a feature flag / future milestone only.
|
||||
- Re-design around a dedicated stream source resolver with robust URL acquisition and source metadata preservation (query/episode/title) before subtitle sync flows.
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
@@ -19,7 +19,9 @@ priority: low
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
The service layer has inconsistent naming:
|
||||
|
||||
- Some functions end in `Service`: `handleCliCommandService`, `loadSubtitlePositionService`
|
||||
- Some end in `RuntimeService`: `replayCurrentSubtitleRuntimeService`, `sendMpvCommandRuntimeService`
|
||||
- Some are plain: `shortcutMatchesInputForLocalFallback`
|
||||
@@ -28,13 +30,16 @@ The service layer has inconsistent naming:
|
||||
The barrel export (src/core/services/index.ts) re-exports 79 symbols from 28 files through a single surface, which obscures dependency boundaries. Consumers import everything from `./core/services` and can't tell which service file they actually depend on.
|
||||
|
||||
Establish consistent naming:
|
||||
|
||||
- Exported service functions: `verbNounService` (e.g., `handleCliCommand`)
|
||||
- Deps factory functions: `create*Deps`
|
||||
- Consider whether the barrel re-export is still the right pattern vs direct imports from individual files.
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 All service functions follow a consistent naming convention
|
||||
- [ ] #2 Decision documented on barrel export vs direct imports
|
||||
- [ ] #3 No functional changes
|
||||
@@ -43,11 +48,15 @@ Establish consistent naming:
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Naming convention consolidation should be addressed as part of TASK-27.2 (split main.ts) and TASK-27.3 (anki-integration split). As modules are extracted and given clear boundaries, naming will be standardized at each boundary. No need to do a standalone naming pass — it's wasted effort if the module structure is about to change.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Subsumed by TASK-27.2 and TASK-27.3. Naming conventions were standardized at module boundaries during extraction. A standalone global naming pass would be churn with no structural benefit now that modules have clear ownership boundaries.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -20,19 +20,24 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
In renderer.ts (around lines 865-1075), `applyInvisibleSubtitleLayoutFromMpvMetrics` is a 211-line function with up to 5 levels of nesting. It handles OSD scaling calculations, platform-specific font compensation (macOS vs Linux), DPR calculations, ASS alignment tag interpretation (\an tags), baseline compensation, line-height fixes, font property application, and transform origin — all interleaved.
|
||||
|
||||
Extract into focused helpers:
|
||||
|
||||
- `calculateOsdScale(metrics, renderAreaHeight)` — pure scaling math
|
||||
- `calculateSubtitlePosition(metrics, scale, alignment)` — ASS \an tag interpretation + positioning
|
||||
- `applyPlatformFontCompensation(style, platform)` — macOS kerning/size adjustments
|
||||
- `applySubtitleStyle(element, computedStyle)` — DOM style application
|
||||
|
||||
This can be done independently of or as part of TASK-6 (renderer split).
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 No single function exceeds ~50 lines in the positioning logic
|
||||
- [x] #2 Helper functions are pure where possible (take inputs, return outputs)
|
||||
- [x] #3 Platform-specific branches isolated into dedicated helpers
|
||||
@@ -42,13 +47,17 @@ This can be done independently of or as part of TASK-6 (renderer split).
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Helpers were split so positioning math, base layout, and typography/vertical handling are no longer in one monolith; see `src/renderer/positioning/invisible-layout.ts` and peer files.
|
||||
|
||||
Applied as part of TASK-27.5 with helper extraction: moved mpv subtitle layout orchestration to `invisible-layout.ts` and extracted metric/base/style helpers into `invisible-layout-metrics.ts` and `invisible-layout-helpers.ts`.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Decomposition of `applyInvisibleSubtitleLayoutFromMpvMetrics` completed as part of TASK-27.5: function body split into metric/layout/typography helpers and small coordinator preserved. Manual validation completed by user; behavior remains stable.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -23,18 +23,23 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Currently renderer.ts is a single file loaded directly by Electron's renderer process via a script tag in index.html. To split it into modules (TASK-6), we need a bundling step since Electron renderer's default context doesn't support bare ES module imports without additional configuration.
|
||||
|
||||
Options:
|
||||
|
||||
1. **esbuild** — fast, minimal config, already used in many Electron projects
|
||||
2. **Electron's native ESM support** — requires `"type": "module"` and sandbox configuration
|
||||
3. **TypeScript compiler output** — if targeting a single concatenated bundle
|
||||
|
||||
The build pipeline already compiles TypeScript and copies renderer assets. Adding a bundling step for the renderer would slot into the existing `npm run build` script.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Renderer code can be split across multiple .ts files with imports
|
||||
- [x] #2 Build pipeline bundles renderer modules into a single output for Electron
|
||||
- [x] #3 Existing `make build` still works end-to-end
|
||||
@@ -44,13 +49,17 @@ The build pipeline already compiles TypeScript and copies renderer assets. Addin
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Updated root npm build pipeline to use an explicit renderer bundle step via esbuild. Added `build:renderer` script to emit a single `dist/renderer/renderer.js` from `src/renderer/renderer.ts`; `build` now runs `pnpm run build:renderer` and preserves existing index/style copy and macOS helper step. Added `esbuild` to devDependencies.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Implemented renderer bundling step and wired `build` to use it. This adds `pnpm run build:renderer` which bundles `src/renderer/renderer.ts` into a single `dist/renderer/renderer.js` for Electron to load. Also added `esbuild` as a dev dependency and aligned `pnpm-lock.yaml` importer metadata for dependency consistency. Kept `index.html`/`style.css` copy path unchanged, so renderer asset layout remains stable.
|
||||
|
||||
Implemented additional test-layer type fix after build breakage by correcting `makeDepsFromMecabTokenizer` and related `tokenizeWithMecab` mocks to match expected `Token` vs `MergedToken` shapes, keeping runtime behavior unchanged while satisfying TS checks.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -14,11 +14,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Refactor overlay runtime so each overlay layer owns and applies its bounds independently. Keep tracker geometry as shared origin input only.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 `updateOverlayBoundsService` no longer applies the same bounds to every overlay window by default.
|
||||
- [x] #2 Main runtime/manager exposes per-layer bounds update paths for visible and invisible overlays.
|
||||
- [x] #3 Window tracker updates feed shared origin data; each layer applies its own computed bounds.
|
||||
@@ -28,6 +32,7 @@ Refactor overlay runtime so each overlay layer owns and applies its bounds indep
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Started implementation for per-layer overlay bounds ownership refactor.
|
||||
|
||||
Implemented per-layer bounds ownership path: visible and invisible layers now update bounds independently through overlay manager/runtime plumbing, while preserving existing geometry source behavior.
|
||||
@@ -35,10 +40,13 @@ Implemented per-layer bounds ownership path: visible and invisible layers now up
|
||||
Replaced shared all-window bounds application with per-window bound application service and layer-specific runtime calls from visibility/tracker flows.
|
||||
|
||||
Archiving requested by user.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Refactored overlay bounds ownership to per-layer update paths. Tracker geometry remains shared input, but visible/invisible windows apply bounds independently via explicit layer routes. Existing single-layer UX behavior is preserved.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -18,14 +18,18 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Create a phased backlog-backed restructuring plan that keeps current service-oriented architecture while reducing cognitive load from oversized modules and tightening module ownership boundaries.
|
||||
|
||||
This initiative should make future feature work easier by splitting high-complexity files, reducing tightly-coupled orchestration, and introducing measurable structural guardrails.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 A phased decomposition plan is defined in task links and references the following target files: src/main.ts, src/anki-integration.ts, src/core/services/mpv-service.ts, src/renderer/*, src/config/*, and src/core/services/*.
|
||||
|
||||
- [ ] #1 A phased decomposition plan is defined in task links and references the following target files: src/main.ts, src/anki-integration.ts, src/core/services/mpv-service.ts, src/renderer/_, src/config/_, and src/core/services/\*.
|
||||
- [ ] #2 Tasks are assigned with clear owners and include explicit dependencies so execution can proceed in parallel where safe.
|
||||
- [ ] #3 Changes are constrained to structural refactors first (no behavior changes until foundational splits are in place).
|
||||
- [ ] #4 Each subtask includes test/verification expectations (manual or automated) and a rollback-safe checkpoint.
|
||||
@@ -34,27 +38,35 @@ This initiative should make future feature work easier by splitting high-complex
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
## Revised Execution Sequence
|
||||
|
||||
### Phase 0 — Prerequisites (outside TASK-27 tree)
|
||||
|
||||
- **TASK-7** — Extract main.ts global state into AppState container (required before TASK-27.2)
|
||||
- **TASK-9** — Remove trivial wrapper functions from main.ts (depends on TASK-7; recommended before TASK-27.2 but not blocking)
|
||||
|
||||
### Phase 1 — Lightweight Inventory
|
||||
|
||||
- **TASK-27.1** — Inventory files >400 LOC, document contracts, define smoke test checklist
|
||||
|
||||
### Phase 2 — Sequential Split Wave
|
||||
|
||||
Order matters to avoid merge conflicts:
|
||||
|
||||
1. **TASK-27.3** — anki-integration.ts split (self-contained, doesn't affect main.ts wiring until facade is stable)
|
||||
2. **TASK-27.2** — main.ts split (after TASK-7 provides AppState container and 27.3 stabilizes the Anki facade)
|
||||
3. **TASK-27.4** — mpv-service.ts split (absorbs TASK-8 scope; blocked until 27.1 is done)
|
||||
4. **TASK-27.5** — renderer positioning.ts split (downscoped; after 27.2 to avoid import-path conflicts)
|
||||
|
||||
### Phase 3 — Stabilization
|
||||
|
||||
- **TASK-27.7** — Finalization and validation cleanup
|
||||
|
||||
## Smoke Test Checklist (applies to all subtasks)
|
||||
|
||||
Every subtask must verify before merging:
|
||||
|
||||
- [ ] App starts and connects to MPV
|
||||
- [ ] Subtitle text appears in overlay
|
||||
- [ ] Card mining creates a note in Anki
|
||||
@@ -68,9 +80,11 @@ Every subtask must verify before merging:
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
## Review Findings (2026-02-13)
|
||||
|
||||
### Key changes from original plan:
|
||||
|
||||
1. **Dropped parallel execution of Phase 2** — TASK-27.2 and 27.5 share import paths; 27.2 and 27.3 share main.ts wiring. Sequential order prevents merge conflicts.
|
||||
2. **Added TASK-7 as external prerequisite** — main.ts has 30+ module-level `let` declarations. Splitting files without a state container first just scatters mutable state.
|
||||
3. **TASK-8 absorbed into TASK-27.4** — TASK-8 (separate protocol from app logic) and TASK-27.4 (physical file split) overlap significantly. TASK-27.4 now covers both.
|
||||
@@ -82,11 +96,15 @@ Every subtask must verify before merging:
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
TASK-27 completed: plan execution sequence completed through all major refactor subtasks. Done status now confirmed for 27.1 (ownership mapping), 27.2 (main.ts split), 27.3 (anki-integration service-domain extraction), 27.4 (mpv-service split), 27.5 (renderer positioning split), and 27.7 (final validation summary, build + tests). Remaining work is now outside TASK-27 scope.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Plan task links and ordering are recorded in backlog descriptions.
|
||||
- [ ] #2 At least 2 independent owners are assigned with explicit labels in subtasks.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -25,21 +25,26 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
TASK-27.3 extracted leaf clusters (duplicate-detection 102 LOC, ai-translation 158 LOC, ui-feedback 107 LOC) but the core class remains at 2935 LOC. The heavy decomposition from the original TASK-27.3 plan was never executed.
|
||||
|
||||
Remaining extractions from the original plan:
|
||||
|
||||
1. **field-grouping** (~900 LOC) — `triggerFieldGroupingForLastAddedCard`, `applyFieldGrouping`, `computeFieldGroupingMergedFields`, `buildFieldGroupingPreview`, `performFieldGroupingMerge`, `handleFieldGroupingAuto`, `handleFieldGroupingManual`, plus ~15 span/parse/normalize helpers
|
||||
2. **card-creation** (~350 LOC) — `createSentenceCard`, `setCardTypeFields`, `extractFields`, `processSentence`, field resolution helpers
|
||||
3. **polling/lifecycle** (~250 LOC) — `start`, `stop`, `poll`, `pollOnce`, `processNewCard`
|
||||
|
||||
Also consolidate the scattered extraction files into `src/anki-integration/`:
|
||||
|
||||
- `src/anki-integration-duplicate.ts` → `src/anki-integration/duplicate.ts`
|
||||
- `src/anki-integration-ui-feedback.ts` → `src/anki-integration/ui-feedback.ts`
|
||||
- `src/anki-integration/ai.ts` (already there)
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 anki-integration.ts reduced below 800 LOC (facade + private state wiring only)
|
||||
- [ ] #2 Field-grouping cluster (~900 LOC) extracted as its own module under src/anki-integration/
|
||||
- [ ] #3 Card-creation and polling/lifecycle extracted as separate modules
|
||||
@@ -51,5 +56,7 @@ Also consolidate the scattered extraction files into `src/anki-integration/`:
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Implemented and stabilized the anki-integration refactor + transport/protocol fixes needed to keep 27.7 moving: fixed MPV protocol sub-end timing behavior, corrected split-buffer test fixtures, added injectable mpv transport socket factory to eliminate readonly Socket monkey-patching, and resolved TypeScript strictness issues in card-creation path (typed notesInfo cast, option signature/field guards/audio stream index). Updated related tests and build outputs accordingly. Validation results: `bun run build` passes and targeted suites pass: `src/core/services/mpv-protocol.test.ts`, `src/core/services/mpv-transport.test.ts`, `src/anki-integration.test.ts` (16/16).
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -15,7 +15,9 @@ priority: low
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
The core/services directory has inconsistent naming patterns that create confusion:
|
||||
|
||||
- Some files use `*Service.ts` suffix (e.g., `mpv-service.ts`, `tokenizer-service.ts`)
|
||||
- Others use `*RuntimeService.ts` or just descriptive names (e.g., `overlay-visibility-service.ts` exports functions with 'Service' in name)
|
||||
- Some functions in files have 'Service' suffix, others don't
|
||||
@@ -23,18 +25,23 @@ The core/services directory has inconsistent naming patterns that create confusi
|
||||
This inconsistency makes it hard to predict file/function names and creates cognitive overhead.
|
||||
|
||||
Standardize on:
|
||||
|
||||
- File names: `kebab-case.ts` without 'service' suffix (e.g., `mpv.ts`, `tokenizer.ts`)
|
||||
- Function names: descriptive verbs without 'Service' suffix (e.g., `createMpvClient()`, `tokenizeSubtitle()`)
|
||||
- Barrel exports: clean, predictable names
|
||||
|
||||
Files needing audit (47 services):
|
||||
|
||||
- All files in src/core/services/ need review
|
||||
|
||||
Note: This is a large-scale refactor that should be done carefully to avoid breaking changes.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Establish naming convention rules (document in code or docs)
|
||||
- [x] #2 Audit all service files for naming inconsistencies
|
||||
- [x] #3 Rename files to follow convention (kebab-case, no 'service' suffix)
|
||||
@@ -48,6 +55,7 @@ Note: This is a large-scale refactor that should be done carefully to avoid brea
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Starting implementation. Planning and executing a mechanical refactor: file names and exported symbols with Service suffix in `src/core/services`, then cascading import updates across `src/`.
|
||||
|
||||
Implemented naming convention refactor across `src/core/services`: removed `-service` from service file names, renamed Service-suffixed exported symbols to non-Service names, and updated barrel exports in `src/core/services/index.ts`.
|
||||
@@ -55,10 +63,13 @@ Implemented naming convention refactor across `src/core/services`: removed `-ser
|
||||
Updated call sites across `src/main/**`, `src/core/services/**` tests, `scripts/**`, `package.json` test paths, and docs references (`docs/development.md`, `docs/architecture.md`, `docs/structure-roadmap.md`).
|
||||
|
||||
Validation completed: `pnpm run build` and `pnpm run test:fast` both pass after refactor.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Normalized `src/core/services` naming by removing `-service` from module filenames, dropping `Service` suffixes from exported service functions, and updating `src/core/services/index.ts` barrel exports to the new names. Updated all import/call sites across `src/main/**`, service tests, scripts, and docs/package test paths to match the new module and symbol names. Verified no behavior regressions with `pnpm run build` and `pnpm run test:fast` (all passing).
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -15,14 +15,17 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
main.ts is still 1481 lines after previous refactoring efforts. While significant progress has been made, there are still opportunities to extract runtime functions into dedicated modules to further reduce its size and improve maintainability.
|
||||
|
||||
Current opportunities:
|
||||
|
||||
1. **JLPT dictionary lookup functions** (lines 470-535) - initializeJlptDictionaryLookup, ensureJlptDictionaryLookup, getJlptDictionarySearchPaths
|
||||
2. **Media path utilities** (lines 552-590) - updateCurrentMediaPath, updateCurrentMediaTitle, resolveMediaPathForJimaku
|
||||
3. **Overlay visibility helpers** (lines 1273-1360) - updateVisibleOverlayVisibility, updateInvisibleOverlayVisibility, syncInvisibleOverlayMousePassthrough
|
||||
|
||||
These functions are largely self-contained and could be moved to:
|
||||
|
||||
- `src/main/jlpt-runtime.ts`
|
||||
- `src/main/media-runtime.ts`
|
||||
- `src/main/overlay-visibility-runtime.ts`
|
||||
@@ -30,13 +33,16 @@ These functions are largely self-contained and could be moved to:
|
||||
Goal: Reduce main.ts complexity by extracting focused runtime helpers into dedicated modules
|
||||
|
||||
Benefits:
|
||||
|
||||
- Faster navigation and comprehension of main.ts
|
||||
- Easier to test extracted modules independently
|
||||
- Clearer separation of concerns
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Extract JLPT dictionary lookup functions to dedicated module
|
||||
- [x] #2 Extract media path utilities to dedicated module
|
||||
- [x] #3 Extract overlay visibility helpers to dedicated module
|
||||
@@ -49,7 +55,9 @@ Benefits:
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Refactor complete for targeted runtime extraction: JLPT lookup, media utilities, and overlay visibility helpers were moved into dedicated main-runtime modules and wired from main.ts. Existing behavior preserved and full typecheck + test suite passed.
|
||||
|
||||
Task intent updated to prioritize readability over strict line-count target.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -21,17 +21,22 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
MpvIpcClient (761 lines) in src/core/services/mpv-service.ts has a 22-property `MpvIpcClientDeps` interface that reaches back into main.ts state for application-level concerns (overlay visibility, subtitle timing, media path updates, OSD display).
|
||||
|
||||
The class mixes two responsibilities:
|
||||
|
||||
1. **IPC Protocol**: Socket connection, JSON message framing, reconnection, property observation
|
||||
2. **Application Integration**: Subtitle text broadcasting, overlay visibility sync, timing tracking
|
||||
|
||||
Separating these would let the protocol layer be simpler and testable, while application-level reactions to mpv events could be handled by listeners/callbacks registered externally.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 MpvIpcClient deps interface reduced to protocol-level concerns only
|
||||
- [ ] #2 Application-level reactions (subtitle broadcast, overlay sync, timing) handled via event emitter or external listeners
|
||||
- [ ] #3 MpvIpcClient is testable without mocking 22 callbacks
|
||||
@@ -41,5 +46,7 @@ Separating these would let the protocol layer be simpler and testable, while app
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Superseded by TASK-27.4 which absorbed this task's full scope (protocol/application separation, deps interface reduction from 22 properties to protocol-level concerns, event-based app reactions). All acceptance criteria met by TASK-27.4.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -20,6 +20,7 @@ priority: low
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
main.ts contains many trivial single-line wrapper functions that add indirection without value:
|
||||
|
||||
```typescript
|
||||
@@ -37,10 +38,13 @@ function ensureOverlayWindowLevel(window: BrowserWindow): void {
|
||||
Similarly, config accessor wrappers like `getJimakuLanguagePreference()`, `getJimakuMaxEntryResults()`, `resolveJimakuApiKey()` are pure boilerplate.
|
||||
|
||||
After TASK-7 (AppState container), many of these can be eliminated by having services access the state container directly, or by using the service functions directly at call sites without local wrappers.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Trivial pass-through wrappers eliminated (call service/manager directly)
|
||||
- [ ] #2 Config accessor wrappers replaced with direct calls or a config accessor helper
|
||||
- [ ] #3 main.ts line count reduced
|
||||
@@ -50,11 +54,15 @@ After TASK-7 (AppState container), many of these can be eliminated by having ser
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Priority changed from medium to low: this work is largely subsumed by TASK-27.2 (split main.ts). When main.ts is decomposed into composition-root modules, trivial wrappers will naturally be eliminated or inlined. Recommend folding remaining wrapper cleanup into TASK-27.2 rather than tracking separately. Keep this ticket as a checklist reference but don't execute independently.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Subsumed by TASK-27.2 (main.ts split). Trivial wrappers were eliminated or inlined as composition-root modules were extracted. main.ts reduced from ~2000+ LOC to 1384 with state routed through appState container. Standalone wrapper removal pass no longer needed.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
project_name: "SubMiner"
|
||||
default_status: "To Do"
|
||||
statuses: ["To Do", "In Progress", "Done"]
|
||||
project_name: 'SubMiner'
|
||||
default_status: 'To Do'
|
||||
statuses: ['To Do', 'In Progress', 'Done']
|
||||
labels: []
|
||||
milestones: []
|
||||
date_format: yyyy-mm-dd
|
||||
max_column_width: 20
|
||||
default_editor: "nvim"
|
||||
default_editor: 'nvim'
|
||||
auto_open_browser: false
|
||||
default_port: 6420
|
||||
remote_operations: true
|
||||
@@ -13,4 +13,4 @@ auto_commit: false
|
||||
bypass_git_hooks: false
|
||||
check_active_branches: true
|
||||
active_branch_days: 30
|
||||
task_prefix: "task"
|
||||
task_prefix: 'task'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
id: m-0
|
||||
title: "Release v0.1.0"
|
||||
title: 'Release v0.1.0'
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
@@ -15,11 +15,15 @@ ordinal: 2000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Execute the SubMiner refactoring initiative documented in plan.md to reduce thin abstractions, consolidate service boundaries, fix known quality issues, and increase test coverage while preserving current behavior.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Phase-based execution tasks are created and linked under this initiative.
|
||||
- [x] #2 Each phase task includes clear, testable outcomes aligned with plan.md.
|
||||
- [x] #3 Implementation proceeds with build/test verification checkpoints after each completed phase.
|
||||
@@ -29,6 +33,7 @@ Execute the SubMiner refactoring initiative documented in plan.md to reduce thin
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Created initiative subtasks TASK-1.1 through TASK-1.6 with phase-aligned acceptance criteria and sequential dependencies.
|
||||
|
||||
Completed TASK-1.1 (Phase 1 thin-wrapper removal) with green build/core tests.
|
||||
@@ -40,10 +45,13 @@ Completed TASK-1.5 (critical behavior tests) with expanded tokenizer/mpv/subsync
|
||||
Completed TASK-1.6 with documented no-go decision for optional domain-directory reorganization (kept current structure; tests remain green).
|
||||
|
||||
TASK-1.4 remains the only open phase, blocked on interactive desktop smoke checks that cannot be fully validated in this headless environment.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Completed the plan.md refactor initiative across Phases 1-5 and optional Phase 6 decisioning: removed thin wrappers, consolidated DI adapters and related services, fixed targeted runtime correctness issues, expanded critical behavior test coverage, and kept build/core tests green throughout. Final runtime smoke checks (start/toggle/trigger-field-grouping/stop) passed in this headless environment, with known limitation that visual overlay rendering itself was not directly inspectable.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -19,11 +19,15 @@ ordinal: 12000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Inline trivial wrapper services into their call sites and delete redundant service/test files listed in Phase 1 of plan.md.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Wrapper logic from the Phase 1 file list is inlined at call sites without behavior changes.
|
||||
- [x] #2 Phase 1 wrapper service files and corresponding trivial tests are removed from the codebase.
|
||||
- [x] #3 `src/core/services/index.ts` exports are updated to remove deleted modules.
|
||||
@@ -33,6 +37,7 @@ Inline trivial wrapper services into their call sites and delete redundant servi
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Locate all Phase 1 wrapper service call sites and classify direct-inline substitutions vs orchestration-flow inlines.
|
||||
2. Remove the lowest-risk wrappers first (`config-warning-runtime-service`, `app-logging-runtime-service`, `runtime-options-manager-runtime-service`, `overlay-modal-restore-service`, `overlay-send-service`) and update imports/exports.
|
||||
3. Continue with startup and shutdown wrappers (`startup-resource-runtime-service`, `config-generation-runtime-service`, `app-shutdown-runtime-service`, `shortcut-ui-deps-runtime-service`) by inlining behavior into `main.ts` or direct callers.
|
||||
@@ -43,6 +48,7 @@ Inline trivial wrapper services into their call sites and delete redundant servi
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Inlined wrapper behaviors into direct call sites in `main.ts` and `overlay-bridge-runtime-service.ts` for config warning/app logging, runtime options manager construction, generate-config bootstrap path, startup resource initialization, app shutdown sequence, overlay modal restore handling, overlay send behavior, and overlay shortcut local fallback invocation.
|
||||
|
||||
Deleted 16 Phase 1 files (9 wrapper services + 7 wrapper tests) and removed corresponding barrel exports from `src/core/services/index.ts`.
|
||||
@@ -50,4 +56,5 @@ Deleted 16 Phase 1 files (9 wrapper services + 7 wrapper tests) and removed corr
|
||||
Updated `package.json` `test:core` list to remove deleted test entries so the script tracks current sources accurately.
|
||||
|
||||
Verification: `pnpm run build && pnpm run test:core` passes after refactor.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -22,11 +22,15 @@ ordinal: 10000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Absorb dependency adapter runtime services into core service modules and remove adapter files/tests while preserving runtime behavior.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 CLI, IPC, tokenizer, and app lifecycle adapter logic is merged into their target service modules.
|
||||
- [x] #2 Adapter service and adapter test files listed in Phase 2 are removed.
|
||||
- [x] #3 Callers pass dependency shapes expected by updated services without redundant mapping layers.
|
||||
@@ -36,6 +40,7 @@ Absorb dependency adapter runtime services into core service modules and remove
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Audit `cli-command-deps-runtime-service.ts`, `ipc-deps-runtime-service.ts`, `tokenizer-deps-runtime-service.ts`, and `app-lifecycle-deps-runtime-service.ts` usage sites in `main.ts` and corresponding services.
|
||||
2. For each adapter, move null-guarding and shape-normalization logic into its target service (`cli-command-service.ts`, `ipc-service.ts`, `tokenizer-service.ts`, `app-lifecycle-service.ts`) and simplify caller dependency objects.
|
||||
3. Remove adapter service files/tests and update `src/core/services/index.ts` exports/import sites.
|
||||
@@ -46,6 +51,7 @@ Absorb dependency adapter runtime services into core service modules and remove
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Merged adapter-constructor logic into target services: `createCliCommandDepsRuntimeService` moved into `cli-command-service.ts`, `createIpcDepsRuntimeService` moved into `ipc-service.ts`, `createTokenizerDepsRuntimeService` moved into `tokenizer-service.ts`, and `createAppLifecycleDepsRuntimeService` moved into `app-lifecycle-service.ts`.
|
||||
|
||||
Deleted adapter service files and tests for cli-command deps, ipc deps, tokenizer deps, and app lifecycle deps.
|
||||
@@ -53,4 +59,5 @@ Deleted adapter service files and tests for cli-command deps, ipc deps, tokenize
|
||||
Updated `src/core/services/index.ts` exports and `package.json` `test:core` entries to remove deleted adapter test modules.
|
||||
|
||||
Verification: `pnpm run build && pnpm run test:core` passes after consolidation.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -23,11 +23,15 @@ ordinal: 6000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Merge split modules for overlay visibility, broadcast, shortcuts, numeric shortcuts, and startup orchestration into cohesive service files.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Overlay visibility/runtime split is consolidated into a single service module.
|
||||
- [x] #2 Overlay broadcast functions are merged with overlay manager responsibilities.
|
||||
- [x] #3 Shortcut and numeric shortcut runtime/lifecycle splits are consolidated as described in plan.md.
|
||||
@@ -38,6 +42,7 @@ Merge split modules for overlay visibility, broadcast, shortcuts, numeric shortc
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Merge `overlay-visibility-runtime-service.ts` exports into `overlay-visibility-service.ts` and update imports/exports.
|
||||
2. Merge overlay broadcast responsibilities from `overlay-broadcast-runtime-service.ts` into `overlay-manager-service.ts` while preserving current APIs used by `main.ts`.
|
||||
3. Consolidate shortcut modules by absorbing lifecycle utilities into `overlay-shortcut-service.ts` and fallback-runner logic into `overlay-shortcut-runtime-service.ts` (or successor handler module), then remove obsolete files.
|
||||
@@ -48,6 +53,7 @@ Merge split modules for overlay visibility, broadcast, shortcuts, numeric shortc
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Merged overlay visibility runtime API into `overlay-visibility-service.ts` and removed `overlay-visibility-runtime-service.ts`.
|
||||
|
||||
Merged overlay broadcast behavior into `overlay-manager-service.ts` (including manager-level broadcasting) and removed `overlay-broadcast-runtime-service.ts` + test, with equivalent coverage moved into `overlay-manager-service.test.ts`.
|
||||
@@ -59,4 +65,5 @@ Merged numeric shortcut runtime/session split into `numeric-shortcut-service.ts`
|
||||
Merged startup bootstrap + app-ready orchestration into `startup-service.ts`; removed `startup-bootstrap-runtime-service.ts` and `app-ready-runtime-service.ts` with tests updated to new module path.
|
||||
|
||||
Verification: `pnpm run build && pnpm run test:core` passes after consolidation.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -21,11 +21,15 @@ ordinal: 3000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Address identified correctness and code-quality issues from plan.md, including race conditions, unsafe typing, callback rejection handling, and runtime naming cleanup.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Debug `console.log`/`console.warn` usage in overlay visibility logic is removed or replaced with structured logging where needed.
|
||||
- [x] #2 Tokenizer type mismatch is fixed without unsafe `as never` casting.
|
||||
- [x] #3 Field grouping resolver handling is made concurrency-safe against overlapping requests.
|
||||
@@ -37,6 +41,7 @@ Address identified correctness and code-quality issues from plan.md, including r
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Remove or replace debug `console.log`/`console.warn` usage in `overlay-visibility-service.ts` while preserving useful operational logging semantics.
|
||||
2. Confirm and fix unsafe tokenizer casting paths (already partially addressed during Phase 2) and ensure no remaining `as never` escape hatches in tokenizer dependency flows.
|
||||
3. Make field grouping resolver handling in `main.ts` concurrency-safe by adding request sequencing and stale-resolution guards.
|
||||
@@ -47,6 +52,7 @@ Address identified correctness and code-quality issues from plan.md, including r
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Removed debug overlay-visibility `console.log`/`console.warn` statements from `overlay-visibility-service.ts`.
|
||||
|
||||
Eliminated unsafe tokenizer cast path during prior consolidation (`createTokenizerDepsRuntimeService` now uses typed `Token[]` and `mergeTokens(rawTokens)` without `as never`).
|
||||
@@ -80,10 +86,13 @@ Automated interactive-smoke surrogate 2 (outside sandbox): started app, sent `--
|
||||
Observed expected reconnect behavior when MPV socket was absent (`ENOENT /tmp/subminer-socket`), with no regressions in startup/bootstrap flow.
|
||||
|
||||
Note: this environment is headless, so visual overlay rendering cannot be directly confirmed; command-path and process-lifecycle smoke checks passed.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Completed Phase 4 by removing debug logging noise, fixing unsafe typing and concurrency risks, adding async rejection handling, completing naming cleanup, and validating startup/command-path behavior through repeated build/test and live Electron smoke runs.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -22,11 +22,15 @@ ordinal: 5000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add meaningful behavior tests for high-risk services called out in plan.md: mpv, subsync, tokenizer, and expanded CLI command coverage.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 `mpv` service has focused tests for protocol parsing, event dispatch, request/response matching, reconnection, and subtitle extraction behavior.
|
||||
- [x] #2 `subsync` service has focused tests for engine path resolution, command construction, timeout/error handling, and result parsing.
|
||||
- [x] #3 `tokenizer` service has focused tests for parser readiness, token extraction, fallback behavior, and edge-case inputs.
|
||||
@@ -37,6 +41,7 @@ Add meaningful behavior tests for high-risk services called out in plan.md: mpv,
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Add focused tests for `tokenizer-service.ts` behavior (normalization, Yomitan-unavailable fallback, mecab fallback success/error paths, empty input handling).
|
||||
2. Add focused tests for `subsync-service.ts` command/engine selection and failure handling using mocked command utilities where feasible.
|
||||
3. Add focused tests for `mpv-service.ts` protocol handling (line parsing, request-response routing, property-change dispatch) with lightweight socket stubs.
|
||||
@@ -47,6 +52,7 @@ Add meaningful behavior tests for high-risk services called out in plan.md: mpv,
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Added new tokenizer behavior tests in `src/core/services/tokenizer-service.test.ts` covering empty normalized input, newline normalization, mecab fallback success, and mecab error fallback-to-null.
|
||||
|
||||
Added new mpv protocol tests in `src/core/services/mpv-service.test.ts` covering JSON line-buffer parsing, property-change subtitle dispatch behavior, and request/response resolution by `request_id`.
|
||||
@@ -72,4 +78,5 @@ Added subsync command-construction tests using executable stubs for both engines
|
||||
Expanded CLI dispatch tests with broad branch coverage for visibility/settings/copy/multi-copy/mining/open-runtime-options/stop/help/second-instance behaviors and async error propagation.
|
||||
|
||||
Verification: `pnpm run test:core` passes with 18 green tests including newly added `dist/subsync/utils.test.js`.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -17,11 +17,15 @@ ordinal: 4000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
If service flattening remains hard to navigate after Phases 1-5, optionally move modules into domain-based folders and update imports.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 A clear go/no-go decision for domain restructuring is documented based on post-phase-5 codebase state.
|
||||
- [ ] #2 If executed, service modules are reorganized into domain folders with no import or runtime breakage.
|
||||
- [x] #3 Build and core test commands pass after any directory reorganization.
|
||||
@@ -30,6 +34,7 @@ If service flattening remains hard to navigate after Phases 1-5, optionally move
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Assess post-phase-5 directory complexity and determine whether domain reorganization is still justified.
|
||||
2. If complexity remains acceptable, record a no-go decision and keep current structure stable.
|
||||
3. If complexity is still problematic, perform import-safe domain reorganization and re-run build/tests.
|
||||
@@ -38,9 +43,11 @@ If service flattening remains hard to navigate after Phases 1-5, optionally move
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Decision: no-go on Phase 6 directory reorganization for now. After Phases 1-5, service/module consolidation and test expansion have improved maintainability without introducing a high-risk import churn.
|
||||
|
||||
Rationale: preserving path stability now reduces regression risk while Phase 4 smoke validation remains open and large refactor commits are still stabilizing.
|
||||
|
||||
Verification baseline remains green (`pnpm run test:core`) with current structure.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: TASK-13
|
||||
title: Fix macOS native window bounds for overlay binding
|
||||
status: Done
|
||||
assignee:
|
||||
- codex
|
||||
created_date: '2026-02-11 15:45'
|
||||
updated_date: '2026-02-11 16:36'
|
||||
labels:
|
||||
- bug
|
||||
- macos
|
||||
- overlay
|
||||
dependencies: []
|
||||
references:
|
||||
- src/window-trackers/macos-tracker.ts
|
||||
- scripts/get-mpv-window-macos.swift
|
||||
priority: high
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Overlay windows on macOS are not properly aligned to the mpv window after switching from AppleScript window discovery to native Swift/CoreGraphics bounds retrieval.
|
||||
|
||||
Implement a robust native bounds strategy that prefers Accessibility window geometry (matching app-window coordinates used previously) and falls back to filtered CoreGraphics windows when Accessibility data is unavailable.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Overlay bounds track the active mpv window with correct position and size on macOS.
|
||||
- [x] #2 Helper avoids selecting off-screen/non-primary mpv-related windows.
|
||||
- [x] #3 Build succeeds with the updated macOS helper.
|
||||
<!-- AC:END -->
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Follow-up in progress after packaged app runtime showed fullscreen fallback behavior:
|
||||
|
||||
- Added packaged-app helper path resolution in tracker (`process.resourcesPath/scripts/get-mpv-window-macos`).
|
||||
- Added `.asar` helper materialization to temp path so child process execution is possible if candidate path resolves inside asar.
|
||||
- Added throttled tracker logging for helper execution failures to expose runtime errors without log spam.
|
||||
- Updated Electron builder `extraResources` to ship `dist/scripts/get-mpv-window-macos` outside asar at `resources/scripts/get-mpv-window-macos`.
|
||||
- Added macOS-only invisible subtitle vertical nudge (`+5px`) in renderer layout to align interactive subtitles with mpv glyph baseline after bounds fix.
|
||||
- Increased macOS-only invisible subtitle line-height for multi-line text to improve separation as line count grows.
|
||||
<!-- SECTION:NOTES:END -->
|
||||
@@ -17,11 +17,15 @@ ordinal: 51000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
When SubMiner is already running in texthooker-only mode, a subsequent `--start` command from a second instance is currently ignored. This can leave users without an initialized overlay runtime even though startup commands were issued. Adjust CLI command handling so `--start` on second-instance initializes overlay runtime when it is not yet initialized, while preserving current ignore behavior when overlay runtime is already active.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Second-instance `--start` initializes overlay runtime when current instance has deferred/not-initialized overlay runtime.
|
||||
- [x] #2 Second-instance `--start` remains ignored (existing behavior) when overlay runtime is already initialized.
|
||||
- [x] #3 CLI command service tests cover both behaviors and pass.
|
||||
@@ -30,23 +34,28 @@ When SubMiner is already running in texthooker-only mode, a subsequent `--start`
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Patched CLI second-instance `--start` handling in `src/core/services/cli-command-service.ts` to initialize overlay runtime when deferred.
|
||||
|
||||
Added regression test for deferred-runtime start path and updated initialized-runtime second-instance tests in `src/core/services/cli-command-service.test.ts`.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Fixed overlay startup regression path where a second-instance `--start` could be ignored even when the primary instance was running in texthooker-only/deferred overlay mode.
|
||||
|
||||
Changes:
|
||||
|
||||
- Updated `handleCliCommandService` logic so `ignoreStart` applies only when source is second-instance, `--start` is present, and overlay runtime is already initialized.
|
||||
- Added explicit overlay-runtime initialization path for second-instance `--start` when runtime is not initialized.
|
||||
- Kept existing behavior for already-initialized runtime (still logs and ignores redundant `--start`).
|
||||
- Added and updated tests in `cli-command-service.test.ts` to validate both deferred and initialized second-instance startup behaviors.
|
||||
|
||||
Validation:
|
||||
|
||||
- `pnpm run build` succeeded.
|
||||
- `node dist/core/services/cli-command-service.test.js` passed (11/11).
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -17,11 +17,15 @@ ordinal: 50000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
The `subminer` launcher starts SubMiner with `--start` but can leave the visible overlay hidden when runtime config defers auto-show (`auto_start_overlay=false`). Update launcher command args to explicitly request visible overlay at startup so script-mode behavior matches user expectations.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Running `subminer <video>` starts SubMiner with startup args that include visible-overlay show intent.
|
||||
- [x] #2 Launcher startup remains compatible with texthooker-enabled startup and backend/socket args.
|
||||
- [x] #3 No regressions in existing startup argument construction for texthooker-only mode.
|
||||
@@ -30,15 +34,18 @@ The `subminer` launcher starts SubMiner with `--start` but can leave the visible
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Updated `subminer` launcher startup args in `startOverlay()` to include `--show-visible-overlay` alongside `--start`.
|
||||
|
||||
This makes script-mode startup idempotently request visible overlay presentation instead of depending on runtime config auto-start visibility flags, while preserving existing backend/socket and optional texthooker args.
|
||||
|
||||
Scope:
|
||||
|
||||
- `subminer` script only.
|
||||
- No changes to AppImage internal CLI parsing or runtime services.
|
||||
|
||||
Validation:
|
||||
|
||||
- Verified argument block in `startOverlay()` now includes `--show-visible-overlay` and preserves existing flags.
|
||||
- Confirmed texthooker-only path (`launchTexthookerOnly`) is unchanged.
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -17,11 +17,15 @@ ordinal: 49000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Overlay renderer stopped initializing after renderer.ts was split into modules. The emitted JS now uses CommonJS require/exports in a browser context (nodeIntegration disabled), causing script load failure and a blank transparent overlay with missing subtitle interactions.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Renderer script loads successfully in overlay BrowserWindow without nodeIntegration.
|
||||
- [x] #2 Visible overlay displays subtitles again on initial launch.
|
||||
- [x] #3 Overlay keyboard/mouse interactions are functional again.
|
||||
@@ -31,5 +35,7 @@ Overlay renderer stopped initializing after renderer.ts was split into modules.
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Fixed a renderer module-loading regression introduced by renderer modularization. Added a dedicated renderer TypeScript build target (`tsconfig.renderer.json`) that emits browser-compatible ES modules, updated build script to compile renderer with that config, switched overlay HTML to load `renderer.js` as a module, and updated renderer runtime imports to `.js` module specifiers. Verified that built renderer output no longer contains CommonJS `require(...)` and that core test suite passes (`pnpm run test:core`).
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -17,11 +17,15 @@ ordinal: 48000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
User confirmed renderer module-loading fix resolved the broken overlay, but startup experiment changes introduced side effects (e.g., y-s start path re-launch behavior). Revert non-essential auto-start/debugging changes in launcher/plugin/CLI startup flow while preserving renderer ESM fix.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Remove wrapper/plugin auto-start experiment changes that were added during debugging.
|
||||
- [x] #2 Restore previous y-s start behavior without relaunching a new overlay session from wrapper-managed startup side effects.
|
||||
- [x] #3 Keep renderer ESM/module-loading fix intact.
|
||||
@@ -31,5 +35,7 @@ User confirmed renderer module-loading fix resolved the broken overlay, but star
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Reverted startup experiment changes while preserving the renderer ESM fix. Removed wrapper-forced visible overlay startup and wrapper-managed mpv script opts from `subminer`, restored plugin defaults/behavior (`auto_start=true`) and removed `wrapper_managed` handling from `plugin/subminer.lua` + `plugin/subminer.conf`, and reverted CLI/bootstrap debug-path changes in `src/core/services/cli-command-service.ts` and `src/core/services/startup-service.ts` with matching test updates. Verified `pnpm run build` and full `pnpm run test:core` pass.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -20,11 +20,15 @@ ordinal: 47000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Current visible and invisible overlays can both be enabled at once, but both windows occupy full mpv bounds so hover/input targets conflict. Investigate feasibility of sizing each overlay window to subtitle content bounds (including secondary subtitles) instead of fullscreen. Also investigate decoupling secondary subtitle rendering from overlay visibility by introducing a dedicated top bar region (full-width or text-width) that remains at top and respects secondary subtitle display mode config (hover/always/never).
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Document current overlap/input conflict behavior when both overlays are enabled.
|
||||
- [x] #2 Prototype or design approach for content-bounded overlay window sizing for visible and invisible overlays.
|
||||
- [x] #3 Evaluate interaction model and technical constraints for a dedicated top secondary-subtitle bar independent from overlay visibility.
|
||||
@@ -34,26 +38,32 @@ Current visible and invisible overlays can both be enabled at once, but both win
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Baseline current behavior
|
||||
|
||||
- Trace current visible/invisible overlay window creation and sizing behavior in main process and renderer paths.
|
||||
- Document why enabling both overlays causes overlap and input/hover conflict.
|
||||
|
||||
2. Design content-bounded overlay sizing
|
||||
|
||||
- Evaluate measurement sources (renderer DOM bounds vs main process approximations).
|
||||
- Define sizing algorithm (content bounds + padding + min/max + screen clamping) and update triggers.
|
||||
- Identify required IPC contracts and ownership boundaries.
|
||||
|
||||
3. Design decoupled top secondary-subtitle bar
|
||||
|
||||
- Define a dedicated top region/window independent from primary subtitle visibility.
|
||||
- Specify behavior for secondary subtitle display modes (hover/always/never) and pointer-event policy.
|
||||
|
||||
4. Recommend phased implementation
|
||||
|
||||
- Produce concrete file-level rollout steps, risks, edge cases (wrapping, long lines, resize, multi-monitor, style sync), and validation approach.
|
||||
<!-- SECTION:PLAN:END -->
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Completed code-path investigation across overlay window creation/sizing, visibility gating, IPC mouse passthrough, and renderer interaction layers.
|
||||
|
||||
Documented current conflict mechanism and architecture limitation: shared fullscreen bounds ownership across both overlay windows blocks safe simultaneous activation.
|
||||
@@ -63,14 +73,17 @@ Proposed renderer-driven content-bounds IPC model, per-window bounds ownership,
|
||||
Included phased implementation plan with risks and edge-case handling in docs/overlay-window-sizing-investigation.md.
|
||||
|
||||
Updated documentation reference to `overlay_window.md` because previous `docs/overlay-window-sizing-investigation.md` path is not present in repository.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Completed investigation and design for dynamic overlay window sizing and decoupled secondary subtitle rendering.
|
||||
|
||||
What changed:
|
||||
|
||||
- Added `docs/overlay-window-sizing-investigation.md` with a code-referenced analysis of current overlay behavior.
|
||||
- Documented why overlap/input conflicts emerge under simultaneous overlay activation: both windows are full-size and currently share bounds ownership semantics.
|
||||
- Designed a content-bounded sizing approach based on renderer-measured DOM bounds reported to main via IPC, with clamping, jitter guards, and fallback behavior.
|
||||
@@ -78,6 +91,7 @@ What changed:
|
||||
- Defined a phased file-level implementation path and explicit edge-case handling (wrapping/long lines, resize churn, multi-monitor transitions, mpv style/render sync).
|
||||
|
||||
Validation:
|
||||
|
||||
- Investigation validated by tracing current runtime/services/renderer code paths; no runtime behavior changes were applied in this task.
|
||||
- No automated tests were run because this task produced design documentation only (no executable code changes).
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -20,11 +20,15 @@ ordinal: 54000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add a script that offloads macOS package builds to a remote Mac mini over SSH, then syncs release artifacts back to the local workspace.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Script supports remote host and path configuration.
|
||||
- [x] #2 Script supports signed and unsigned macOS build modes.
|
||||
- [x] #3 Script syncs project sources to remote and copies release artifacts back locally.
|
||||
@@ -33,7 +37,9 @@ Add a script that offloads macOS package builds to a remote Mac mini over SSH, t
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Added `scripts/build-external.sh` with:
|
||||
|
||||
- Defaults for host alias (`mac-mini`) and remote path (`~/build/SubMiner`)
|
||||
- Argument flags: `--host`, `--remote-path`, `--signed`, `--unsigned`, `--skip-sync`, `--sync-only`
|
||||
- Rsync-based upload excluding heavyweight build artifacts and local dependencies
|
||||
|
||||
@@ -18,11 +18,15 @@ ordinal: 14000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Execute the remaining follow-up work identified in investigation.md: remove unused scaffolding, add tests for high-risk consolidated services, and run manual smoke validation in a desktop MPV session.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Follow-up subtasks are created with explicit scope and dependencies.
|
||||
- [x] #2 Unused architectural scaffolding and abandoned IPC abstraction files are removed or explicitly retained with documented rationale.
|
||||
- [x] #3 Dedicated tests are added for higher-risk consolidated services (`overlay-shortcut-handler`, `mining-service`, `anki-jimaku-service`).
|
||||
@@ -32,6 +36,7 @@ Execute the remaining follow-up work identified in investigation.md: remove unus
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Create scoped subtasks for each recommendation in investigation.md and sequence them by risk and execution constraints.
|
||||
2. Remove dead scaffolding files and any now-unneeded exports/imports; verify build/tests remain green.
|
||||
3. Add focused behavior tests for the three higher-risk consolidated services.
|
||||
@@ -41,7 +46,9 @@ Execute the remaining follow-up work identified in investigation.md: remove unus
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Completed:
|
||||
|
||||
- Created TASK-2.1 through TASK-2.5 from `investigation.md` recommendations.
|
||||
- Finished TASK-2.1: removed unused scaffolding in `src/core/`, `src/modules/`, `src/ipc/` and cleaned internal-only service barrel export.
|
||||
- Finished TASK-2.2: added dedicated tests for `overlay-shortcut-handler.ts`.
|
||||
@@ -49,5 +56,6 @@ Completed:
|
||||
- Finished TASK-2.4: added dedicated tests for `anki-jimaku-service.ts`.
|
||||
|
||||
Remaining:
|
||||
|
||||
- TASK-2.5: desktop smoke validation with MPV session
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -26,11 +26,15 @@ ordinal: 11000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Remove unused module-architecture scaffolding and IPC abstraction files identified as dead code, and clean service barrel exports that are not needed outside service internals.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Files under `src/core/{action-bus.ts,actions.ts,app-context.ts,module-registry.ts,module.ts}` are removed if unreferenced.
|
||||
- [x] #2 Unused `src/modules/` and `src/ipc/` scaffolding files are removed if unreferenced.
|
||||
- [x] #3 `src/core/services/index.ts` no longer exports symbols that are only consumed internally (`isGlobalShortcutRegisteredSafe`).
|
||||
@@ -40,6 +44,7 @@ Remove unused module-architecture scaffolding and IPC abstraction files identifi
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Verify all candidate files are truly unreferenced in runtime/test paths.
|
||||
2. Delete dead scaffolding files and folders.
|
||||
3. Remove unnecessary service barrel exports and fix any import fallout.
|
||||
@@ -49,11 +54,13 @@ Remove unused module-architecture scaffolding and IPC abstraction files identifi
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Removed unused scaffolding files from `src/core/`, `src/modules/`, and `src/ipc/` that were unreferenced by runtime code.
|
||||
|
||||
Updated `src/core/services/index.ts` to stop re-exporting `isGlobalShortcutRegisteredSafe`, which is only used internally by service files.
|
||||
|
||||
Verification:
|
||||
|
||||
- `pnpm run build` passed
|
||||
- `pnpm run test:core` passed (18/18)
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -19,11 +19,15 @@ ordinal: 9000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add dedicated tests for `overlay-shortcut-handler.ts`, covering shortcut runtime handlers, fallback behavior, and key edge/error paths.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Shortcut registration/unregistration handler behavior is covered.
|
||||
- [x] #2 Fallback handling paths are covered for valid and invalid input.
|
||||
- [x] #3 Error and guard behavior is covered for missing dependencies/state.
|
||||
@@ -33,7 +37,9 @@ Add dedicated tests for `overlay-shortcut-handler.ts`, covering shortcut runtime
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Added `src/core/services/overlay-shortcut-handler.test.ts` with coverage for:
|
||||
|
||||
- runtime handler dispatch for sync and async actions
|
||||
- async error propagation to OSD/log handling
|
||||
- local fallback action matching, including timeout forwarding
|
||||
@@ -43,4 +49,5 @@ Added `src/core/services/overlay-shortcut-handler.test.ts` with coverage for:
|
||||
Updated `package.json` `test:core` to include `dist/core/services/overlay-shortcut-handler.test.js`.
|
||||
|
||||
Verification: `pnpm run test:core` passed (19/19 at completion of this ticket).
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -19,11 +19,15 @@ ordinal: 8000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add dedicated behavior tests for `mining-service.ts` covering sentence/card mining orchestration and error boundaries.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Happy-path behavior is covered for mining entry points.
|
||||
- [x] #2 Guard/early-return behavior is covered for missing runtime state.
|
||||
- [x] #3 Error paths are covered with expected logging/OSD behavior.
|
||||
@@ -33,7 +37,9 @@ Add dedicated behavior tests for `mining-service.ts` covering sentence/card mini
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Added `src/core/services/mining-service.test.ts` with focused coverage for:
|
||||
|
||||
- `copyCurrentSubtitleService` guard and success behavior
|
||||
- `mineSentenceCardService` integration/connection guards and success path
|
||||
- `handleMultiCopyDigitService` history-copy behavior with truncation messaging
|
||||
@@ -42,4 +48,5 @@ Added `src/core/services/mining-service.test.ts` with focused coverage for:
|
||||
Updated `package.json` `test:core` to include `dist/core/services/mining-service.test.js`.
|
||||
|
||||
Verification: `pnpm run test:core` passed (20/20 after adding mining tests).
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -19,11 +19,15 @@ ordinal: 7000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add dedicated tests for `anki-jimaku-service.ts` focusing on IPC handler registration, request dispatch, and error handling behavior.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 IPC registration behavior is validated for all channels exposed by this service.
|
||||
- [x] #2 Success-path behavior for core handler flows is validated.
|
||||
- [x] #3 Failure-path behavior is validated with expected error propagation.
|
||||
@@ -33,9 +37,11 @@ Add dedicated tests for `anki-jimaku-service.ts` focusing on IPC handler registr
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Added a lightweight registration-injection seam to `registerAnkiJimakuIpcRuntimeService` so runtime behavior can be tested without Electron IPC globals.
|
||||
|
||||
Added `src/core/services/anki-jimaku-service.test.ts` with coverage for:
|
||||
|
||||
- runtime handler surface registration
|
||||
- integration disable path and runtime-options broadcast
|
||||
- subtitle history clear and field-grouping response callbacks
|
||||
@@ -46,4 +52,5 @@ Added `src/core/services/anki-jimaku-service.test.ts` with coverage for:
|
||||
Updated `package.json` `test:core` to include `dist/core/services/anki-jimaku-service.test.js`.
|
||||
|
||||
Verification: `pnpm run test:core` passed (21/21).
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -20,11 +20,15 @@ ordinal: 13000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Execute manual desktop smoke checks in an MPV-enabled environment to validate overlay rendering and key user workflows not fully covered by automated tests.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Overlay rendering and visibility toggling are verified in a real desktop session.
|
||||
- [x] #2 Card mining flow is verified end-to-end.
|
||||
- [x] #3 Field-grouping interaction is verified end-to-end.
|
||||
@@ -34,9 +38,11 @@ Execute manual desktop smoke checks in an MPV-enabled environment to validate ov
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Smoke run executed on 2026-02-10 with real Electron launch (outside sandbox) after unsetting `ELECTRON_RUN_AS_NODE=1` in command context.
|
||||
|
||||
Commands executed:
|
||||
|
||||
- `electron . --help`
|
||||
- `electron . --start`
|
||||
- `electron . --toggle-visible-overlay`
|
||||
@@ -47,12 +53,14 @@ Commands executed:
|
||||
- `electron . --stop`
|
||||
|
||||
Observed runtime evidence from app logs:
|
||||
|
||||
- CLI help output rendered with expected flags.
|
||||
- App started and connected to MPV after reconnect attempts.
|
||||
- Mining flow executed and produced `Created sentence card: ...`, plus media upload logs.
|
||||
- Tracker/runtime loop started (`hyprland` tracker connected) and app stopped cleanly.
|
||||
|
||||
Follow-up/constraints:
|
||||
- Overlay *visual rendering* and visibility correctness are not directly observable from terminal logs alone and still require direct desktop visual confirmation.
|
||||
|
||||
- Overlay _visual rendering_ and visibility correctness are not directly observable from terminal logs alone and still require direct desktop visual confirmation.
|
||||
- Field-grouping trigger command was sent, but explicit end-state confirmation in UI still needs manual verification.
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -15,11 +15,15 @@ ordinal: 45000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add renderer-to-main IPC for content measurement reporting, so main process can size each overlay window from post-layout DOM bounds.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Preload exposes a typed API for reporting overlay content bounds with layer metadata.
|
||||
- [x] #2 Main-process IPC handler validates payload shape/range and stores latest measurement per layer.
|
||||
- [x] #3 Renderer emits measurement updates on subtitle, mode, style, and render-metric changes with throttling/debounce.
|
||||
@@ -29,15 +33,19 @@ Add renderer-to-main IPC for content measurement reporting, so main process can
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Added a typed `OverlayContentMeasurement` IPC contract exposed in preload and Electron API typings. Implemented a main-process measurement store with strict payload validation and rate-limited warning logs for invalid reports. Added renderer-side debounced measurement reporting that emits updates on subtitle content/mode/style/render-metric and resize changes, explicitly sending `contentRect: null` when no measured content exists to signal fallback behavior.
|
||||
|
||||
Added unit coverage for measurement validation and store behavior.
|
||||
|
||||
Closed per user request to delete parent task and subtasks.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Implemented renderer-to-main measurement reporting for overlay content bounds with per-layer metadata. Main now validates and stores latest measurements per layer safely, renderer emits debounced updates on relevant state changes, and invalid/missing payload handling is explicit and non-spammy.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -14,11 +14,15 @@ ordinal: 46000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
When SubMiner connects to MPV, capture the current MPV `secondary-sub-visibility` value and force it off. Keep it off during SubMiner runtime regardless of overlay visibility toggles. On app shutdown (and MPV shutdown event when possible), restore MPV `secondary-sub-visibility` to the captured pre-SubMiner value.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Capture MPV `secondary-sub-visibility` once per MPV connection before overriding it.
|
||||
- [x] #2 Set MPV `secondary-sub-visibility` to `no` after capture regardless of `bind_visible_overlay_to_mpv_sub_visibility`.
|
||||
- [x] #3 Do not mutate/restore secondary MPV visibility as a side effect of visible overlay toggles.
|
||||
@@ -29,7 +33,9 @@ When SubMiner connects to MPV, capture the current MPV `secondary-sub-visibility
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Implemented MPV secondary subtitle visibility lifecycle management:
|
||||
|
||||
- Moved secondary-sub visibility capture/disable to MPV connection initialization (`getInitialState` requests `secondary-sub-visibility`, then request handler stores prior value and forces `secondary-sub-visibility=no`).
|
||||
- Removed secondary-sub visibility side effects from visible overlay visibility service so overlay toggles no longer capture/restore secondary MPV state.
|
||||
- Added `restorePreviousSecondarySubVisibility()` to `MpvIpcClient`, invoked on MPV `shutdown` event and from app `onWillQuitCleanup` (best effort while connected).
|
||||
|
||||
@@ -16,11 +16,15 @@ ordinal: 34000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement an opt-in JLPT token annotation feature that annotates subtitle words with JLPT level in-session. The feature should use a bundled dictionary source from the existing JLPT Yomitan extension, parse/query its dictionary file to determine whether a token appears and its JLPT level, and render token-level visual tags as a colored underline spanning each token length. Colors must correspond to JLPT levels (e.g., N5/N4/N3/N2/N1) using a consistent mapping.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Add an opt-in setting/feature flag so JLPT tagging is disabled by default and can be enabled per user/session as requested.
|
||||
- [x] #2 Bundle the existing JLPT Yomitan extension package/data into the project so lookups can be performed offline from local files.
|
||||
- [x] #3 Implement token-level dictionary lookup against the bundled JLPT dictionary file to determine presence and JLPT level for words in subtitle lines.
|
||||
@@ -34,7 +38,9 @@ Implement an opt-in JLPT token annotation feature that annotates subtitle words
|
||||
<!-- AC:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 Feature has a clear toggle and persistence of preference if applicable.
|
||||
- [x] #2 JLPT rendering is visually verified for all supported levels with distinct colors and no overlap/regression in subtitle legibility.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -15,11 +15,15 @@ ordinal: 32000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Create a lookup layer that parses/queries the bundled JLPT dictionary file and returns JLPT level for a given token/word. Integrate with subtitle tokenization path with minimal performance overhead.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Service accepts a token/normalized token and returns JLPT level or no-match deterministically.
|
||||
- [x] #2 Lookup handles expected dictionary format edge cases and unknown tokens without throwing.
|
||||
- [x] #3 Lookup path is efficient enough for frame-by-frame subtitle updates.
|
||||
@@ -28,6 +32,8 @@ Create a lookup layer that parses/queries the bundled JLPT dictionary file and r
|
||||
<!-- AC:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 Lookup service returns JLPT level with deterministic output for test fixtures.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -15,11 +15,15 @@ ordinal: 33000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Package and include the JLPT Yomitan extension dictionary assets in SubMiner so JLPT tagging can run without external network calls. Define a deterministic build/runtime path and loading strategy for the dictionary file and metadata versioning.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 JLPT dictionary asset from the existing Yomitan extension is added to the repository/build output in a tracked, offline-available location.
|
||||
- [x] #2 The loader locates and opens the JLPT dictionary file deterministically at runtime.
|
||||
- [x] #3 Dictionary version/source is documented so future updates are explicit and reproducible.
|
||||
@@ -27,6 +31,8 @@ Package and include the JLPT Yomitan extension dictionary assets in SubMiner so
|
||||
<!-- AC:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 Dictionary data is bundled and consumable during development and packaged app runs.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -15,11 +15,15 @@ ordinal: 44000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Render JLPT-aware token annotations as token-length colored underlines in the subtitle UI based on returned JLPT levels, without changing existing subtitle layout or primary interaction behavior.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 For each token with JLPT level, renderer draws an underline matching token width/length.
|
||||
- [x] #2 Underlines use distinct colors by JLPT level (e.g., N5/N4/N3/N2/N1) and mapping is consistent/documented.
|
||||
- [x] #3 Non-tagged tokens remain visually unchanged.
|
||||
@@ -28,6 +32,8 @@ Render JLPT-aware token annotations as token-length colored underlines in the su
|
||||
<!-- AC:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 Visual output validated for all mapped JLPT levels with no legibility/layout regressions.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -15,11 +15,15 @@ ordinal: 35000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add user/config setting to enable JLPT tagging, wire the feature toggle through subtitle processing/rendering, and add tests/verification for positive match, non-match, and disabled-mode behavior.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 JLPT tagging is opt-in and defaults to disabled.
|
||||
- [x] #2 When disabled, lookup/rendering pipeline does not execute JLPT processing.
|
||||
- [x] #3 When enabled, end-to-end flow tags subtitle words via token-level lookup and rendering.
|
||||
@@ -27,6 +31,8 @@ Add user/config setting to enable JLPT tagging, wire the feature toggle through
|
||||
<!-- AC:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 End-to-end option behavior and opt-in state persistence are implemented and verified.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -16,11 +16,15 @@ ordinal: 37000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement subtitle highlighting for words already known in Anki (N+1 workflow support) by introducing a one-time bootstrap query of the user’s Anki known-word set, storing it locally, and refreshing it periodically to reflect deck updates. The feature should allow fast in-session lookups to determine known words and visually distinguish them in subtitle rendering.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Add an opt-in setting/feature flag for N+1 highlighting and default it to disabled for backward-compatible behavior.
|
||||
- [x] #2 Implement a one-time import/sync that queries known-word data from Anki into a local store on first enable or explicit refresh.
|
||||
- [x] #3 Store known words locally in an efficient structure for fast lookup during subtitle rendering.
|
||||
@@ -36,10 +40,14 @@ Implement subtitle highlighting for words already known in Anki (N+1 workflow su
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Implemented in refactor via merge from task-24-known-word-refresh (commits 854b8fb, e8f2431, ed5a249). Includes manual/periodic known-word cache refresh, opt-in N+1 highlighting path, cache persistence behavior, CLI refresh command, and related tests/docs updates.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 N+1 known-word highlighting is configurable, performs local cached lookups, and is demonstrated to update correctly after periodic/manual refresh.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -19,11 +19,15 @@ ordinal: 28000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Leverage user-installed frequency dictionaries to color subtitle tokens based on word frequency rank, with configurable behavior: either one shared color for all words below a rank threshold or a multi-color range mapping based on frequency bands. The feature should support a configurable X (top-N words) cutoff and integrate with existing subtitle rendering flow.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Add a feature flag and configuration for frequency-based highlighting with default disabled state.
|
||||
- [x] #2 Support selecting a user-installed frequency dictionary source and reading word frequency data from it.
|
||||
- [x] #3 Introduce a configurable top-X threshold in config for which words are eligible for frequency-based coloring.
|
||||
@@ -40,6 +44,7 @@ Leverage user-installed frequency dictionaries to color subtitle tokens based on
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
2026-02-16: Updated docs for frequency dictionary behavior. Clarified built-in fallback, precedence, and shared format expectations in and .
|
||||
|
||||
Added docs references for frequency dictionary defaults and fallback behavior.
|
||||
@@ -47,9 +52,12 @@ Added docs references for frequency dictionary defaults and fallback behavior.
|
||||
As of 2026-02-16, docs and implementation are considered complete for TASK-25; frequency highlighting fallback, custom sourcePath precedence, topX, single/banded modes, token pipeline integration, and fallback behavior are present; documentation and tests exist in src/core/services and src/renderer.
|
||||
|
||||
2026-02-16: Frequency-dictionary highlighting feature fully complete and shipped. Task acceptance criteria, DoD, and docs alignment are all marked complete in this task record.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 Frequency-based highlighting renders using either single-color or banded-colors for valid matches, with configurable top-X threshold and documented setup.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -16,11 +16,15 @@ ordinal: 43000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Create a help modal that auto-generates its content from the project/app layout and current configuration, showing the active keybindings and color keys for the current session in a presentable way. The modal should be navigable with arrow keys and Vim-style hjkl-style movement behavior internally but without labeling hjkl in UI, and support mouse interaction. Escape closes/goes back. Open the modal with `y-h`, and if that binding is already taken, use `y-k` as fallback.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Help modal content is generated automatically from current keybinding config and project/app layout rather than hardcoded static text.
|
||||
- [x] #2 Modal displays current session keybindings and active color-key mappings in a clear, grouped layout with section separation for readability.
|
||||
- [x] #3 Modal can be opened with `y-h` when available; if `y-h` is already bound, modal opens with `y-k` instead.
|
||||
@@ -34,6 +38,8 @@ Create a help modal that auto-generates its content from the project/app layout
|
||||
<!-- AC:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 Auto-generated help modal displays up-to-date keybinding + color mapping data and supports both keyboard (arrow/fallback path) and mouse navigation with Escape-to-close.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -22,13 +22,17 @@ ordinal: 42000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Create a lightweight inventory of files needing refactoring and their API contracts to prevent accidental coupling regression during splits.
|
||||
|
||||
This is a documentation-only task — no code changes. Its output (docs/structure-roadmap.md) is the prerequisite gate for all Phase 2 subtasks.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Inventory source files with >400 LOC and categorize by concern (bootstrap, Anki integration, MPV protocol, renderer, config, services).
|
||||
- [ ] #2 Document exported API surface for each target file (entry points, exported types, event names, primary callers).
|
||||
- [ ] #3 List the split sequence from the parent task plan and note any known risks per step.
|
||||
@@ -39,6 +43,7 @@ This is a documentation-only task — no code changes. Its output (docs/structur
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
## Simplification Notes
|
||||
|
||||
Original task called for named maintainer owners per component, risk-gated migration sequences, and success metrics per slice. This is heavyweight for a solo project where the developer already knows the codebase intimately.
|
||||
@@ -46,4 +51,5 @@ Original task called for named maintainer owners per component, risk-gated migra
|
||||
Reduced to: file inventory, API contracts, sequence + risks, and a shared smoke test checklist. The review analysis (in TASK-27 notes) already covers much of what this task would produce — this task captures it in a durable docs file.
|
||||
|
||||
Generated docs/structure-roadmap.md with file inventory, task-specific API contracts, split sequence, known risks, and smoke checklist to unlock TASK-27 subtasks.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -24,11 +24,15 @@ ordinal: 40000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Reduce main.ts complexity by extracting bootstrap, lifecycle, overlay, IPC, and CLI wiring into explicit modules while keeping runtime behavior unchanged.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Create modules under src/main/ for bootstrap/lifecycle/ipc/overlay/cli concerns.
|
||||
- [x] #2 main.ts no longer owns session-specific business state; it only composes services and starts the app.
|
||||
- [ ] #3 Public service behavior, startup order, and flags remain unchanged, validated by existing integration/manual smoke checks.
|
||||
@@ -40,6 +44,7 @@ Reduce main.ts complexity by extracting bootstrap, lifecycle, overlay, IPC, and
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
## Dependency Context
|
||||
|
||||
**TASK-7 is a hard prerequisite.** main.ts currently has 30+ module-level `let` declarations (mpvClient, yomitanExt, reconnectTimer, currentSubText, subtitlePosition, keybindings, ankiIntegration, secondarySubMode, etc.). Splitting main.ts into src/main/ submodules without first consolidating this state into a typed AppState container would scatter mutable state across files, making data flow even harder to trace.
|
||||
@@ -49,7 +54,9 @@ Reduce main.ts complexity by extracting bootstrap, lifecycle, overlay, IPC, and
|
||||
**Sequencing note:** This task should run AFTER TASK-27.3 (anki-integration split) completes, because AnkiIntegration is instantiated and heavily wired in main.ts. Changing both the composition root and the Anki facade simultaneously creates integration risk. Let 27.3 stabilize the Anki module boundaries first, then split main.ts around the stable API.
|
||||
|
||||
## Folded-in work from TASK-9 and TASK-10
|
||||
|
||||
TASK-9 (remove trivial wrappers) and TASK-10 (naming conventions) have been deprioritized to low. Their scope is largely subsumed by this task:
|
||||
|
||||
- When main.ts is split into composition-root modules, trivial wrappers will naturally be eliminated or inlined at each module boundary.
|
||||
- Naming conventions should be standardized per-module as they are extracted, not as a separate global pass.
|
||||
Refer to TASK-9 and TASK-10 acceptance criteria as checklists during execution of this task.
|
||||
@@ -91,10 +98,13 @@ TASK-27.2 refactor is now complete for composition-root extraction path: startup
|
||||
Updated `src/main/state.ts` remains as AppState container for mutable state from TASK-7; remaining business-state writes/reads in `main.ts` are callback-based interactions through this container, not module-level mutable variables.
|
||||
|
||||
Per build validation after each chunk, `pnpm build` has been passing.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Refactored IPC runtime registration in `main.ts` to pass `ankiJimaku` deps through `createAnkiJimakuIpcRuntimeServiceDeps(...)` and removed the bespoke `buildIpcRuntimeServicesParams()` helper; registration remains in `main.ts` via `registerIpcRuntimeServices({ ... })` with shared runtime service builders.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -22,6 +22,7 @@ ordinal: 39000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Split anki-integration.ts (2,679 LOC, 60+ methods) into cohesive modules with clear handoff contracts. Keep a stable facade API to avoid broad call-site churn.
|
||||
|
||||
## Target Decomposition (7 modules)
|
||||
@@ -37,10 +38,13 @@ Based on method clustering analysis:
|
||||
7. **ui-feedback** (~150 LOC) — progress tracking, OSD notifications, status notifications
|
||||
|
||||
Plus a **facade** (`src/anki-integration/index.ts`) that re-exports the public API for backward compatibility.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Extract at least 6 modules matching the decomposition map above (7 recommended).
|
||||
- [ ] #2 Keep a stable facade API in src/anki-integration/index.ts so external callers (main.ts, mining-service) don't change.
|
||||
- [ ] #3 Field grouping cluster (~900 LOC) is extracted as its own module — it's the largest single concern.
|
||||
@@ -54,16 +58,19 @@ Plus a **facade** (`src/anki-integration/index.ts`) that re-exports the public A
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
## Execution Notes
|
||||
|
||||
This task is self-contained — anki-integration.ts is a single class with a clear public API consumed by main.ts and mining-service. Internal restructuring doesn't affect other files as long as the facade is maintained.
|
||||
|
||||
**Should run first in Phase 2** because:
|
||||
|
||||
- It's the largest file (2,679 LOC vs 1,392 for main.ts)
|
||||
- Its public API is narrow (class constructor + ~5 public methods)
|
||||
- main.ts instantiates AnkiIntegration, so stabilizing its API before splitting main.ts avoids double-refactoring
|
||||
|
||||
## Key Risk
|
||||
|
||||
The class has 15 private state fields that create implicit coupling between methods. The `updateLastAddedFromClipboard` method alone is ~230 lines and touches polling state, media generation, and card updates. Extraction order matters: start with the leaf clusters (ai-translation, ui-feedback, duplicate-detection) and work inward toward the stateful core (polling, card-creation, field-grouping).
|
||||
|
||||
Started TASK-27.3 with a surgical extraction of the duplicate-detection cluster into `src/anki-integration-duplicate.ts` and refactoring `AnkiIntegration.findDuplicateNote()` to delegate all deck query, search escaping, and normalization logic to the new module while preserving behavior. This reduces `anki-integration.ts` by removing three private duplicate-parsing methods and keeps callsites unchanged. Remaining decomposition work still needed across polling/card-creation/field-grouping/notification clusters from the task map.
|
||||
@@ -71,4 +78,5 @@ Started TASK-27.3 with a surgical extraction of the duplicate-detection cluster
|
||||
Second extraction pass completed: moved sentence-translation decision + AI fallback behavior out of `createSentenceCard` into `src/anki-integration/ai.ts` as `resolveSentenceBackText(...)`, with `AnkiIntegration` now delegating translation result generation to this function. This further isolates AI concerns from card-creation flow while keeping behavior and defaults intact.
|
||||
|
||||
Refactor for TASK-27.3 is complete and build passes after cleanup of ui-feedback delegation (src/anki-integration.ts, src/anki-integration-ui-feedback.ts).
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -22,22 +22,27 @@ ordinal: 41000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Split mpv-service.ts (773 LOC) into thin, testable layers without changing wire protocol behavior.
|
||||
|
||||
**This task absorbs the scope of TASK-8** (Reduce MpvIpcClient deps interface and separate protocol from application logic). The work proceeds in two phases:
|
||||
|
||||
### Phase A (was TASK-8): Separate protocol from application logic
|
||||
|
||||
- Reduce the 22-property `MpvIpcClientDeps` interface to protocol-level concerns only
|
||||
- Move application-level reactions (subtitle broadcast, overlay visibility sync, timing tracking) to event emitter or external listener pattern
|
||||
- Make MpvIpcClient testable without mocking 22 callbacks
|
||||
|
||||
### Phase B: Physical file split
|
||||
|
||||
- Create submodules for: protocol parsing/dispatch, connection lifecycle/retry, property subscriptions/state mapping
|
||||
- Wire the public facade to maintain API compatibility for all existing consumers
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 MpvIpcClient deps interface reduced to protocol-level concerns only (from current 22 properties).
|
||||
- [x] #2 Application-level reactions (subtitle broadcast, overlay sync, timing) handled via event emitter or external listeners registered by main.ts.
|
||||
- [x] #3 Create submodules for protocol parsing/dispatch, connection lifecycle/retry, and property subscriptions/state mapping.
|
||||
@@ -50,9 +55,11 @@ Split mpv-service.ts (773 LOC) into thin, testable layers without changing wire
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
## TASK-8 Absorption
|
||||
|
||||
TASK-8 and TASK-27.4 overlapped significantly:
|
||||
|
||||
- TASK-8: "Separate protocol from application logic" + shrink deps interface
|
||||
- TASK-27.4: "Split into protocol, transport, property, and facade layers"
|
||||
|
||||
@@ -61,6 +68,7 @@ TASK-27.4 is TASK-8 + physical file splitting. Running them as separate tasks wo
|
||||
**TASK-8 should be marked as superseded** once this task begins.
|
||||
|
||||
## Dependency Note
|
||||
|
||||
Original plan listed TASK-8 as a dependency. Since TASK-8's scope is now absorbed here, the only remaining dependency is TASK-27.1 (inventory/contracts map).
|
||||
|
||||
Started prep: reviewed mpv-service coupling and prepared sequence for protocol/application split; no code split performed yet due current focus on keeping 27.2/27.3 sequencing compatible.
|
||||
@@ -78,12 +86,15 @@ Progress update: extracted socket connect/data/error/close/send/reconnect schedu
|
||||
Added focused transport lifecycle regression coverage in `src/core/services/mpv-transport.test.ts`: connect/connect-idempotence, lifecycle callback ordering, and `shutdown()` resets connection/socket state. This covers reconnect/edge-case behavior at transport layer as part of criterion #6 toward protocol + lifecycle regression protection.
|
||||
|
||||
Added mpv-service unit regression for close lifecycle: `MpvIpcClient onClose resolves outstanding pending requests and triggers reconnect scheduling path via client transport callbacks (`src/core/services/mpv-service.test.ts`). This complements transport-level lifecycle tests for reconnect behavior regression coverage.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Split mpv-service internals into protocol, transport, and property/state-mapping boundaries; reduced MpvIpcClient deps to protocol-level concerns with event-based app reactions in main.ts; added mpv-service/mpv-transport tests for protocol dispatch, reconnect scheduling, and lifecycle regressions; documented expected event flow in docs/structure-roadmap.md.
|
||||
|
||||
Added mpv-service reconnect regression test that asserts a reconnect lifecycle replays mpv property bootstrap commands (`secondary-sub-visibility` reset, `observe_property`, and initial `get_property` state fetches) during reconnection.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -27,9 +27,11 @@ ordinal: 36000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Split positioning.ts (513 LOC) — the only oversized file in the renderer — into focused modules. The rest of the renderer structure is already well-organized and does not need reorganization.
|
||||
|
||||
## Current Renderer State (already good)
|
||||
|
||||
- `renderer.ts` (241 lines) — pure composition, well-factored
|
||||
- `state.ts` (132 lines), `context.ts` (14 lines), `subtitle-render.ts` (206 lines) — reasonable sizes
|
||||
- `handlers/keyboard.ts` (238 lines), `handlers/mouse.ts` (271 lines) — focused
|
||||
@@ -37,11 +39,15 @@ Split positioning.ts (513 LOC) — the only oversized file in the renderer — i
|
||||
- Communication already uses explicit `ctx` pattern and function parameters, not globals
|
||||
|
||||
## What Actually Needs Work
|
||||
|
||||
`positioning.ts` mixes visible overlay positioning, invisible overlay positioning, MPV subtitle render metrics layout, and position persistence. These are distinct concerns that should be separate modules.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Split positioning.ts into at least 2 focused modules (e.g., visible-positioning and invisible-positioning, or by concern: layout, persistence, metrics).
|
||||
- [x] #2 No module exceeds 300 LOC.
|
||||
- [x] #3 Existing overlay behavior (subtitle positioning, drag, invisible layer metrics) unchanged.
|
||||
@@ -52,6 +58,7 @@ Split positioning.ts (513 LOC) — the only oversized file in the renderer — i
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
TASK-11 decomposition is implemented as part of this task by moving the prior monolithic mpv-metrics function into dedicated helper modules.
|
||||
|
||||
Refactored renderer positioning into focused modules via a new controller barrel plus helpers: position-state, invisible-offset, invisible-layout, invisible-layout-metrics, and invisible-layout-helpers.
|
||||
@@ -63,10 +70,13 @@ Validation done in this run: TypeScript build passes (`npm run build`). Manual b
|
||||
`src/renderer/positioning.ts` now re-exports `createPositioningController` from `./positioning/controller.js`.
|
||||
|
||||
Acceptance updates: checked #1 (at least two focused modules) and #2 (no module >300 LOC).
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Completed the renderer positioning split. `src/renderer/positioning.ts` is now a thin re-export and logic is decomposed into focused modules (`controller.ts`, `position-state.ts`, `invisible-offset.ts`, `invisible-layout.ts`, `invisible-layout-helpers.ts`, `invisible-layout-metrics.ts`). Kept `renderer.ts` call-sites unchanged and preserved APIs via controller return shape. Verified by `npm run build` and user manual validation.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -18,10 +18,13 @@ ordinal: 15000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
## Updated scope
|
||||
|
||||
Implement SQLite-first immersion tracking for mining sessions optimized for speed/size and designed for a future external DB adapter.
|
||||
|
||||
## Runtime defaults
|
||||
|
||||
- Flush batch policy: flush every `25` telemetry points or `500ms`.
|
||||
- SQLite: `journal_mode = WAL`, `synchronous = NORMAL`, `foreign_keys = ON`, `busy_timeout = 2500ms`.
|
||||
- Query target: `<150ms p95` for session/video/time-window reads at ~1M rows.
|
||||
@@ -136,23 +139,28 @@ CREATE INDEX idx_rollups_month_video ON imm_monthly_rollups(rollup_month, video_
|
||||
```
|
||||
|
||||
Notes
|
||||
|
||||
- Integer enums keep hot rows narrow and fast; resolve labels in app layer.
|
||||
- JSON fields are only for non-core overflow attributes (bounded by policy).
|
||||
- `source_type`/`status`/`subtitle_mode` are compact enums and keep strings out of high-frequency rows.
|
||||
- This schema is a v1 contract for TASK-32 adapter work later.
|
||||
|
||||
## Future portability
|
||||
|
||||
- Keep all analytics logic behind a storage interface in TASK-32.
|
||||
- Keep raw SQL/DDL details inside adapters.
|
||||
|
||||
## Execution principle
|
||||
|
||||
- Tracking is strictly asynchronous and must never block hot paths.
|
||||
- Tokenization/rendering pipelines must not await DB operations.
|
||||
- If tracker queue is saturated, user experience must remain unchanged; telemetry may be dropped with bounded loss and explicit internal warning/logging.
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 A SQLite database schema is defined and created automatically (or initialized on startup) for immersion tracking if not present.
|
||||
- [x] #2 Recorded events persist at least the following fields per session/item: video name, video directory/URL, video length, lines seen, words/tokens seen, cards mined.
|
||||
- [x] #3 Tracking defaults to storing data in SQLite without requiring additional DB setup for local usage.
|
||||
@@ -180,6 +188,7 @@ Notes
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Progress review (2026-02-17): `src/core/services/immersion-tracker-service.ts` now implements SQLite-first schema init, WAL/NORMAL pragmas, async queue + batch flush (25/500ms), queue cap 1000 with drop-oldest overflow policy, payload clamp (256B), retention pruning (events 7d, telemetry 30d, daily 365d, monthly 5y), startup+24h maintenance, weekly vacuum, rollup maintenance, and query paths (`getSessionSummaries`, `getSessionTimeline`, `getDailyRollups`, `getMonthlyRollups`, `getQueryHints`).
|
||||
|
||||
Metadata capture is implemented for local media via ffprobe/stat/SHA-256 (`captureVideoMetadataAsync`, `getLocalVideoMetadata`) with safe null handling for missing fields.
|
||||
@@ -195,10 +204,13 @@ Implementation docs now include query templates and storage behavior in `docs/im
|
||||
Validation/tests expanded: `src/config/config.test.ts` now covers immersion tuning parse+fallback warnings; `src/core/services/immersion-tracker-service.test.ts` adds minimum persisted/retrievable field checks and configurable policy checks.
|
||||
|
||||
Verification run: `pnpm run build && node --test dist/config/config.test.js dist/core/services/immersion-tracker-service.test.js` passed; sqlite-specific tracker tests are skipped automatically in environments without `node:sqlite` support.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 SQLite tracking table(s), migration history table, and indices created as part of startup or init path.
|
||||
- [x] #2 Unit/integration coverage (or validated test plan) confirms minimum fields are persisted and retrievable.
|
||||
- [x] #3 README or docs updated with storage schema, retention defaults, and extension points.
|
||||
|
||||
@@ -19,9 +19,11 @@ ordinal: 16000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add Anilist integration so the app can update user anime progress after watching, by porting the core functionality of `AzuredBlue/mpv-anilist-updater` into the Electron app. The initial implementation should focus on reliable sync of watch status/progress and be structured to support future Anilist features beyond updates.
|
||||
|
||||
Requirements:
|
||||
|
||||
- Port the core behavior from `AzuredBlue/mpv-anilist-updater` needed for post-watch syncing into the Electron architecture.
|
||||
- Authenticate and persist Anilist credentials securely in the desktop environment.
|
||||
- Identify anime/media item and track watched status/progress based on existing video/session data.
|
||||
@@ -32,7 +34,9 @@ Requirements:
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Application can authenticate with Anilist and store tokens securely for desktop user sessions.
|
||||
- [x] #2 Anilist update flow from existing local watch/session metadata can update animes watched progress after watching.
|
||||
- [x] #3 Core functionality equivalent to mpv-anilist-updater is implemented for this use case (progress/status sync) inside the Electron app.
|
||||
@@ -45,21 +49,27 @@ Requirements:
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Completed child tasks TASK-29.1 and TASK-29.2: secure token persistence/fallback and persistent retry queue with backoff/dead-letter are now implemented.
|
||||
|
||||
Implemented AniList control surfaces across CLI and IPC. CLI: added `--anilist-status`, `--anilist-logout`, `--anilist-setup`, `--anilist-retry-queue` parsing/help/dispatch/runtime wiring in `src/cli/args.ts`, `src/cli/help.ts`, `src/core/services/cli-command.ts`, `src/main/cli-runtime.ts`, and `src/main.ts`. IPC: added `anilist:get-status`, `anilist:clear-token`, `anilist:open-setup`, `anilist:get-queue-status`, `anilist:retry-now` handlers and dependency wiring in `src/core/services/ipc.ts`, `src/main/dependencies.ts`, and `src/main.ts`. Added retry queue tests in `src/core/services/anilist/anilist-update-queue.test.ts`; added token-store tests in `src/core/services/anilist/anilist-token-store.test.ts` with runtime guard for environments without Electron safeStorage; updated `package.json` test list and AniList command/channel docs in `docs/configuration.md`.
|
||||
|
||||
Validation run: `pnpm run test:fast` passed (config + core dist suite). New AniList queue tests run in core suite; token-store tests are auto-skipped in plain Node environments where Electron `safeStorage` is unavailable (still active when safeStorage exists).
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Completed AniList post-watch integration in the Electron app with secure token lifecycle, post-watch progress sync, and persistent retry/backoff queue with dead-letter behavior. Added user-facing control surfaces via CLI (`--anilist-status`, `--anilist-logout`, `--anilist-setup`, `--anilist-retry-queue`) and IPC (`anilist:get-status`, `anilist:clear-token`, `anilist:open-setup`, `anilist:get-queue-status`, `anilist:retry-now`), plus docs and test coverage; validated via `pnpm run test:fast`.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [x] #1 Core Anilist service module exists and is wired into application flow for post-watch updates.
|
||||
- [x] #2 OAuth/token lifecycle is implemented with safe local persistence and revocation/logout behavior.
|
||||
- [x] #3 A retry/backoff and dead-letter strategy for failed syncs is implemented.
|
||||
|
||||
@@ -16,7 +16,9 @@ ordinal: 18000
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Access token is stored in secure local storage rather than plain config.
|
||||
- [ ] #2 Token connect/disconnect UX supports revocation/logout and re-auth setup.
|
||||
- [ ] #3 Startup flow validates token presence/state and surfaces actionable errors.
|
||||
@@ -26,11 +28,15 @@ ordinal: 18000
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Implemented secure AniList token lifecycle: config token persists to encrypted token store, stored token fallback is auto-resolved at runtime, and auth state source now distinguishes literal vs stored.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Token lifecycle module wired into AniList update/auth flow.
|
||||
- [ ] #2 Unit/integration coverage added for token storage and logout paths.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -16,7 +16,9 @@ ordinal: 19000
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Failed AniList mutations are enqueued with retry metadata and exponential backoff.
|
||||
- [ ] #2 Transient API/network failures retry automatically without blocking playback.
|
||||
- [ ] #3 Queue is idempotent per media+episode update key and survives app restarts.
|
||||
@@ -26,11 +28,15 @@ ordinal: 19000
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Implemented persistent AniList retry queue with exponential backoff, dead-lettering after max attempts, queue snapshot state wiring, and retry processing integrated into playback-triggered AniList update flow.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Queue service integrated into AniList post-watch update path.
|
||||
- [ ] #2 Backoff/retry behavior covered by unit tests.
|
||||
<!-- DOD:END -->
|
||||
|
||||
@@ -14,12 +14,15 @@ ordinal: 1000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add keybinding that will toggle edit mode on the invisible subtitles allowing for fine-grained control over positioning. use arrow keys and vim hjkl for motion and enter/ctrl+s to save and esc to cancel
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
- Implemented invisible subtitle position edit mode toggle with movement/save/cancel controls.
|
||||
- Added persistence for invisible subtitle offsets (`invisibleOffsetXPx`, `invisibleOffsetYPx`) alongside existing `yPercent` subtitle position state.
|
||||
- Updated edit mode visuals to highlight invisible subtitle text using the same styling as debug visualization.
|
||||
|
||||
@@ -16,11 +16,15 @@ ordinal: 57000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement optional Jellyfin integration so SubMiner can act as a lightweight Jellyfin client similar to jellyfin-mpv-shim. The feature should support connecting to Jellyfin servers, browsing playable media, and launching playback through SubMiner, including direct play when possible and transparent transcoding when required.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Add a configurable Jellyfin integration path that can be enabled/disabled without impacting core non-Jellyfin functionality.
|
||||
- [x] #2 Support authenticating against a user-selected Jellyfin server (server URL + credentials/token) and securely storing/reusing connection settings.
|
||||
- [x] #3 Allow discovery or manual selection of movies/tv shows/music libraries and playback items from the connected Jellyfin server.
|
||||
@@ -35,9 +39,11 @@ Implement optional Jellyfin integration so SubMiner can act as a lightweight Jel
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Status snapshot (2026-02-18): TASK-31 is mostly complete and now tracks remaining closure work only for #2 and #3.
|
||||
|
||||
Completed acceptance criteria and evidence:
|
||||
|
||||
- #1 Optional/disabled Jellyfin integration boundary verified.
|
||||
- Added tests in `src/core/services/app-ready.test.ts`, `src/core/services/cli-command.test.ts`, `src/core/services/startup-bootstrap.test.ts`, `src/core/services/jellyfin-remote.test.ts`, and `src/config/config.test.ts` to prove disabled paths do not impact core non-Jellyfin functionality and that Jellyfin side effects are gated.
|
||||
- #4 Jellyfin playback launch through existing pipeline verified.
|
||||
@@ -52,20 +58,23 @@ Completed acceptance criteria and evidence:
|
||||
- #9 Docs + key integration tests/mocks completed.
|
||||
|
||||
Key verification runs (all passing):
|
||||
|
||||
- `pnpm run build`
|
||||
- `node --test dist/core/services/app-ready.test.js dist/core/services/cli-command.test.js dist/core/services/startup-bootstrap.test.js dist/core/services/jellyfin-remote.test.js dist/config/config.test.js`
|
||||
- `node --test dist/core/services/jellyfin.test.js dist/core/services/cli-command.test.js`
|
||||
- `pnpm run test:fast`
|
||||
|
||||
Open acceptance criteria (remaining work):
|
||||
|
||||
- #2 Authentication/settings persistence hardening and explicit lifecycle validation:
|
||||
1) login -> persist -> restart -> token reuse verification
|
||||
2) token-expiry re-auth/recovery path verification
|
||||
3) document storage guarantees/edge cases
|
||||
1. login -> persist -> restart -> token reuse verification
|
||||
2. token-expiry re-auth/recovery path verification
|
||||
3. document storage guarantees/edge cases
|
||||
- #3 Library discovery/manual selection UX closure across intended media scope:
|
||||
1) explicit verification for movies/TV/music discovery and selection paths
|
||||
2) document any intentionally out-of-scope media types/flows
|
||||
1. explicit verification for movies/TV/music discovery and selection paths
|
||||
2. document any intentionally out-of-scope media types/flows
|
||||
|
||||
Task relationship:
|
||||
|
||||
- TASK-64 remains a focused implementation slice under this epic and provides foundational cast/remote playback work referenced by this task.
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
@@ -16,11 +16,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Establish objective pass/fail evidence that Jellyfin playback preserves metadata and media-feature parity needed for TASK-31 acceptance criterion #7, so completion is based on repeatable test coverage rather than ad-hoc checks.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Automated test coverage verifies Jellyfin playback launch preserves title and episodic identity metadata when provided by server data.
|
||||
- [ ] #2 Automated test coverage verifies subtitle and audio track selection behavior is preserved through playback launch and control paths.
|
||||
- [ ] #3 Automated test coverage verifies resume position/marker behavior is preserved for partially watched items.
|
||||
|
||||
@@ -21,11 +21,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Validate real playback behavior against Jellyfin server media in a reproducible manual matrix, then capture evidence needed to confidently close TASK-31 acceptance criterion #7.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Manual verification covers at least one movie and one TV episode and confirms playback shows expected title/episode identity where applicable.
|
||||
- [ ] #2 Manual verification confirms subtitle track selection behavior during playback, including enable/disable or track change flows where available.
|
||||
- [ ] #3 Manual verification confirms audio track selection behavior during playback for media with multiple audio tracks.
|
||||
|
||||
@@ -20,11 +20,15 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Drive TASK-31 to completion by collecting and documenting verification evidence for the remaining acceptance criteria (#2, #5, #6, #8), then update criterion status based on observed behavior and any explicit scope limits.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Authentication flow against a user-selected Jellyfin server is verified, including persisted/reused connection settings and token reuse behavior across restart.
|
||||
- [ ] #2 Direct-play-first behavior is verified for compatible media profiles, with evidence that attempt order matches expected policy.
|
||||
- [ ] #3 Transcoding fallback behavior is verified for incompatible media, including correct transcode parameter handoff to playback.
|
||||
|
||||
@@ -19,32 +19,38 @@ priority: low
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
## Scope
|
||||
|
||||
Create a storage abstraction for immersion analytics so existing SQLite-first tracking can evolve to external backends (PostgreSQL/MySQL/other) without rewriting core analytics behavior.
|
||||
|
||||
## Backend portability and performance contract
|
||||
|
||||
- Define a canonical interface that avoids SQL dialect leakage and returns stable query result shapes for session, video, and trend analytics.
|
||||
- Decouple all `TASK-28` persistence callers from raw SQLite access behind a repository/adapter boundary.
|
||||
- Keep domain model and query DTOs backend-agnostic; SQL specifics live in adapters.
|
||||
|
||||
## Target architecture
|
||||
|
||||
- Add provider config: `storage.provider` default `sqlite`.
|
||||
- Use dependency injection/service factory to select adapter at startup.
|
||||
- Add adapter contract tests to validate `Session`, `Video`, `Telemetry`, `Event`, and `Rollup` operations behave identically across backends.
|
||||
- Include migration and rollout contract with compatibility/rollback notes.
|
||||
|
||||
## Numeric operational constraints to preserve (from TASK-28)
|
||||
|
||||
- All adapters must support write batching (or equivalent) with flush cadence equivalent to 25 records or 500ms.
|
||||
- All adapters must enforce bounded in-memory write queue (default 1000 rows) and explicit overflow policy.
|
||||
- All adapters should preserve index/query shapes needed for ~150ms p95 read targets on session/video/time-window queries at ~1M events.
|
||||
- All adapters should support retention semantics equivalent to: events 7d, telemetry 30d, daily rollups 365d, monthly rollups 5y, and prune-on-startup + every 24h + idle vacuum schedule.
|
||||
|
||||
## Async and isolation constraint
|
||||
|
||||
- Adapter API must support enqueue/write-queue semantics so tokenization/render loops never block on persistence.
|
||||
- Background worker owns DB I/O; storage adapter exposes non-blocking API surface to tracking pipeline.
|
||||
|
||||
Acceptance Criteria:
|
||||
--------------------------------------------------
|
||||
## Acceptance Criteria:
|
||||
|
||||
- [ ] #1 Define a stable `ImmersionTrackingStore` interface covering session lifecycle, telemetry counters, event writes, and analytics queries (timeline, video stats, throughput, and streak/trend summaries).
|
||||
- [ ] #2 Implement a DI-bound storage repository that encapsulates all DB interaction behind the interface.
|
||||
- [ ] #3 Refactor `TASK-28`-related data writes/reads in the tracking pipeline to depend on the abstraction (not raw SQLite calls).
|
||||
@@ -55,8 +61,8 @@ Acceptance Criteria:
|
||||
- [ ] #8 Expose retention and write profile defaults in backend contracts: 25 events/500ms batching, queue cap 1000, event payload cap 256B, overflow policy, and retention windows equivalent to TASK-28.
|
||||
- [ ] #9 Preserve performance contract semantics in adapters: query/index assumptions for sub-150ms p95 local reads on ~1M event scale and same read-path shapes as TASK-28.
|
||||
|
||||
Definition of Done:
|
||||
--------------------------------------------------
|
||||
## Definition of Done:
|
||||
|
||||
- [ ] #1 Storage interface with required method signatures and query contracts is documented in code and backlog docs.
|
||||
- [ ] #2 Default SQLite adapter remains the primary implementation and passes existing/ planned immersion tracking expectations.
|
||||
- [ ] #3 Non-SQLite implementation path is explicitly represented in config and adapter scaffolding.
|
||||
@@ -66,7 +72,9 @@ Definition of Done:
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Define a stable `ImmersionTrackingStore` interface covering session lifecycle, telemetry counters, event writes, and analytics queries (timeline, video stats, throughput, and streak/trend summaries).
|
||||
- [ ] #2 Implement a DI-bound storage repository that encapsulates all DB interaction behind the interface.
|
||||
- [ ] #3 Refactor `TASK-28`-related data writes/reads in the tracking pipeline to depend on the abstraction (not raw SQLite calls).
|
||||
@@ -83,11 +91,15 @@ Definition of Done:
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Priority deferred from medium to low: this is premature until TASK-28 (SQLite tracking) ships and a concrete second backend need emerges. The SQLite-first design in TASK-28 already accounts for future portability via schema contracts and adapter boundaries. Revisit after TASK-28 has been in use.
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Storage interface with required method signatures and query contracts is documented in code and backlog docs.
|
||||
- [ ] #2 Default SQLite adapter remains the primary implementation and passes existing/ planned immersion tracking expectations.
|
||||
- [ ] #3 Non-SQLite implementation path is explicitly represented in config and adapter scaffolding.
|
||||
|
||||
@@ -19,11 +19,15 @@ ordinal: 31000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
In normal operation, Electron should not spam logs while waiting for mpv socket connection. Emit mpv socket connection logs only when app logging level is debug. In regular use, keep connection attempts silent while waiting, and log exactly once when the socket connects successfully.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 When logging level is not debug, do not emit logs for mpv socket connection attempts, retries, or wait loops.
|
||||
- [ ] #2 In non-debug mode, the app should silently wait for mpv socket readiness instead of printing connection-loop noise.
|
||||
- [ ] #3 Log exactly one concise INFO log entry when a mpv socket connection succeeds (e.g., per lifecycle attempt/session).
|
||||
@@ -35,11 +39,15 @@ In normal operation, Electron should not spam logs while waiting for mpv socket
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Implemented debug-gated MPV socket noise suppression in normal mode while preserving reconnect behavior. Added an internal check for SUBMINER_LOG_LEVEL==='debug' and wrapped socket reconnect-attempt, close, and error logs so regular startup/reconnect loops no longer emit per-interval messages unless debug logging is enabled. Kept existing connection-success flow unchanged. Validation: `pnpm run build`, `node --test dist/core/services/mpv-service.test.js`.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 No connection-attempt/connect-wait logs are produced in non-debug mode.
|
||||
- [ ] #2 Exactly one success log is produced when connection is established in non-debug mode.
|
||||
- [ ] #3 Debug mode continues to emit detailed connection logs as before.
|
||||
|
||||
@@ -14,11 +14,15 @@ dependencies: []
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Implement an in-app episode browser invoked by Ctrl+E when mpv is open and connected to the Electron UI. The viewer should use the currently supplied directory (if app was launched with one) or fallback to the parent directory of the currently playing video. It should enumerate all available video files in target directory and sort them deterministically, then display them in a polished list/gallery with thumbnails in the Electron UI. Thumbnail behavior should prioritize existing matching images in the directory; otherwise generate thumbnails asynchronously in the background and update the modal as they become available. The same menu infrastructure should be shared with the planned Jellyfin integration and designed so it can display additional Jellyfin-sourced metadata without UI rewrites. It should also support launching/using an alternate picker mode compatible with external launcher UX patterns (e.g., via fzf/rofi), showing the same episode list/metadata in those contexts.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Pressing Ctrl+E in connected mode opens an episode viewer modal and closes/overlays correctly in the Electron app.
|
||||
- [ ] #2 Episode browser source directory is resolved from CLI-provided path when present, else from currently playing video's parent directory.
|
||||
- [ ] #3 Browser enumerates all supported video files in target directory and sorts them deterministically (e.g., natural/season-episode aware when possible).
|
||||
@@ -34,7 +38,9 @@ Implement an in-app episode browser invoked by Ctrl+E when mpv is open and conne
|
||||
<!-- AC:END -->
|
||||
|
||||
## Definition of Done
|
||||
|
||||
<!-- DOD:BEGIN -->
|
||||
|
||||
- [ ] #1 Feature supports Ctrl+E invocation from connected mpv session.
|
||||
- [ ] #2 Directory fallback behavior is implemented and validated with both passed-in and default paths.
|
||||
- [ ] #3 Video listing excludes unsupported formats and is correctly sorted.
|
||||
|
||||
@@ -17,11 +17,15 @@ ordinal: 17000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
CI should focus on build, test, and type-check validation and should not enforce fixed-size implementation ceilings.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 CI is still triggered on `push` and `pull_request` to `main`.
|
||||
- [x] #2 A canonical test entrypoint is added (`pnpm test`) and executed in CI, or CI explicitly runs equivalent test commands.
|
||||
- [x] #3 CI focuses on functional validation (build, tests, type checks) without hardcoded size gates.
|
||||
@@ -34,6 +38,7 @@ CI should focus on build, test, and type-check validation and should not enforce
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
|
||||
1. Add a root `pnpm test` script that runs both `test:config` and `test:core`, or keep CI explicit on these two commands.
|
||||
2. Add explicit type-check step (`pnpm exec tsc --noEmit`) unless `pnpm run build` is accepted as the intended check.
|
||||
3. Confirm no hardcoded size gates are treated as mandatory CI quality gates.
|
||||
@@ -44,5 +49,7 @@ CI should focus on build, test, and type-check validation and should not enforce
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Updated `.github/workflows/ci.yml` to complete the CI contract without hardcoded size gates: added explicit `pnpm exec tsc --noEmit`, switched test execution to a canonical `pnpm test`, and kept build verification on `pnpm run build` on `ubuntu-latest` for `push`/`pull_request` to `main`. Also removed CI line-count gate enforcement by deleting `check:main-lines*` scripts from `package.json` and removing `scripts/check-main-lines.sh` from the repo. The workflow remains Linux-only by design and continues to show PR checks.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -17,15 +17,18 @@ ordinal: 20000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Replace ad-hoc console.log/console.error calls throughout the codebase with a lightweight structured logger that supports configurable verbosity levels (debug, info, warn, error).
|
||||
|
||||
## Motivation
|
||||
|
||||
- TASK-33 (restrict mpv socket logs) is a symptom of a broader problem: no log-level filtering
|
||||
- Debugging production issues requires grepping through noisy output
|
||||
- Users report log spam in normal operation
|
||||
- No way to enable verbose logging for bug reports without code changes
|
||||
|
||||
## Scope
|
||||
|
||||
1. Create a minimal logger module (no external dependencies needed) with `debug`, `info`, `warn`, `error` levels
|
||||
2. Add a config option for log verbosity (default: `info`)
|
||||
3. Add a CLI flag to control logging verbosity (`--log-level`) while keeping `--debug` as app/dev mode.
|
||||
@@ -33,6 +36,7 @@ Replace ad-hoc console.log/console.error calls throughout the codebase with a li
|
||||
5. Include context tags (service name, operation) in log output for filterability
|
||||
|
||||
## Design constraints
|
||||
|
||||
- Zero external dependencies — use a simple wrapper over console methods
|
||||
- Must not impact hot-path performance (subtitle rendering, tokenization)
|
||||
- Log level should be changeable at runtime via config hot-reload if that feature exists
|
||||
@@ -40,7 +44,9 @@ Replace ad-hoc console.log/console.error calls throughout the codebase with a li
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 A logger module exists with debug/info/warn/error levels.
|
||||
- [x] #2 Config option controls default verbosity level.
|
||||
- [x] #3 CLI `--log-level` override config.
|
||||
@@ -53,17 +59,19 @@ Replace ad-hoc console.log/console.error calls throughout the codebase with a li
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
1) Audit remaining runtime console calls and classify by target (core runtime vs help/UI/test-only).
|
||||
2) Keep `--debug` scoped to Electron app/dev mode only; `--log-level` controls logging verbosity.
|
||||
3) Add tests for parsing and startup to keep logging override behavior stable.
|
||||
4) Migrate remaining non-user-facing `console.*` calls in core paths (especially tokenization, jimaku, config generation, electron-backend/notifications) to logger and include context via child loggers.
|
||||
5) Ensure mpv-related connection/reconnect messages use debug level; keep user-facing success/failure outputs when intended.
|
||||
6) Run focused test updates for impacted files, update task notes/acceptance criteria, and finalize task state.
|
||||
|
||||
1. Audit remaining runtime console calls and classify by target (core runtime vs help/UI/test-only).
|
||||
2. Keep `--debug` scoped to Electron app/dev mode only; `--log-level` controls logging verbosity.
|
||||
3. Add tests for parsing and startup to keep logging override behavior stable.
|
||||
4. Migrate remaining non-user-facing `console.*` calls in core paths (especially tokenization, jimaku, config generation, electron-backend/notifications) to logger and include context via child loggers.
|
||||
5. Ensure mpv-related connection/reconnect messages use debug level; keep user-facing success/failure outputs when intended.
|
||||
6. Run focused test updates for impacted files, update task notes/acceptance criteria, and finalize task state.
|
||||
<!-- SECTION:PLAN:END -->
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Updated logging override semantics so `--debug` stays an app/dev-only flag and `--log-level` is the CLI logging control.
|
||||
|
||||
Migrated remaining non-user-facing runtime `console.*` calls in core paths (`notification`, `config-gen`, `electron-backend`, `jimaku`, `tokenizer`) to structured logger
|
||||
@@ -75,12 +83,15 @@ Updated help text and CLI parsing/tests for logging via `--log-level` while keep
|
||||
Validated with focused test run: `node --test dist/cli/args.test.js dist/core/services/startup-bootstrap-service.test.js dist/core/services/cli-command-service.test.js`
|
||||
|
||||
Build still passes via `pnpm run build`
|
||||
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
TASK-36 is now complete; structured logging is consistently used in core runtime paths, with CLI log verbosity controlled by `--log-level`, while `--debug` remains an Electron app/dev-mode toggle.
|
||||
|
||||
Backlog task moved to Done after verification of build and focused tests.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -15,12 +15,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Add a top-level error boundary in the renderer orchestrator that catches unhandled errors in modals and rendering logic, displays a user-friendly error message, and recovers without crashing the overlay.
|
||||
|
||||
## Motivation
|
||||
|
||||
If a renderer modal throws (e.g., jimaku API timeout, DOM manipulation error, malformed subtitle data), the entire overlay can become unresponsive. Since the overlay is transparent and positioned over mpv, a crashed renderer is invisible but blocks interaction.
|
||||
|
||||
## Scope
|
||||
|
||||
1. Wrap the renderer orchestrator's modal dispatch and subtitle rendering in try/catch boundaries
|
||||
2. On error: log the error, dismiss the active modal, show a brief toast/notification in the overlay
|
||||
3. Ensure the overlay returns to a usable state (subtitle display, click-through, shortcuts all work)
|
||||
@@ -28,13 +31,16 @@ If a renderer modal throws (e.g., jimaku API timeout, DOM manipulation error, ma
|
||||
5. Consider a "renderer health" heartbeat from main process that can force-reload the renderer if it becomes unresponsive
|
||||
|
||||
## Design constraints
|
||||
|
||||
- Error recovery must not disrupt mpv playback
|
||||
- Toast notifications should auto-dismiss and not interfere with subtitle layout
|
||||
- Errors should be logged with enough context for debugging (stack trace, active modal, last subtitle state)
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Unhandled errors in modal flows are caught and do not crash the overlay.
|
||||
- [ ] #2 After an error, the overlay returns to a functional state (subtitles render, shortcuts work).
|
||||
- [ ] #3 A brief toast/notification informs the user that an error occurred.
|
||||
|
||||
@@ -15,12 +15,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Improve config validation to surface clear, actionable error messages at startup when the user's config file has invalid values, missing required fields, or type mismatches.
|
||||
|
||||
## Motivation
|
||||
|
||||
The project has a config schema with validation, but invalid configs (wrong types, unknown keys after an upgrade, deprecated fields) can cause cryptic failures deep in service initialization rather than being caught and reported clearly at launch.
|
||||
|
||||
## Scope
|
||||
|
||||
1. Validate the full config against the schema at startup, before any services initialize
|
||||
2. Collect all validation errors (don't fail on the first one) and present them as a summary
|
||||
3. Show the specific field path, expected type, and actual value for each error
|
||||
@@ -29,13 +32,16 @@ The project has a config schema with validation, but invalid configs (wrong type
|
||||
6. Allow the app to start with defaults for non-critical invalid fields, warning the user about the fallback
|
||||
|
||||
## Design constraints
|
||||
|
||||
- Must not block startup for non-critical warnings (e.g., unknown extra keys)
|
||||
- Critical errors (e.g., invalid Anki field mappings) should prevent startup with a clear message
|
||||
- Config file location should be shown in error output so users know what to edit
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 All config fields are validated against the schema before service initialization.
|
||||
- [ ] #2 Validation errors show field path, expected type, and actual value.
|
||||
- [ ] #3 Multiple errors are collected and shown together, not one at a time.
|
||||
|
||||
@@ -15,12 +15,15 @@ priority: low
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Watch the config file for changes and apply non-destructive updates (colors, font sizes, subtitle modes, overlay opacity, keybindings) without requiring an app restart.
|
||||
|
||||
## Motivation
|
||||
|
||||
Currently all config is loaded at startup. Users tweaking visual settings (font size, colors, subtitle positioning) must restart the app after every change, which breaks their video session. Hot-reload for safe config values would dramatically improve the tuning experience.
|
||||
|
||||
## Scope
|
||||
|
||||
1. Watch the config file using `fs.watch` or similar
|
||||
2. On change, re-parse and re-validate the config
|
||||
3. Categorize config fields as hot-reloadable vs restart-required
|
||||
@@ -29,6 +32,7 @@ Currently all config is loaded at startup. Users tweaking visual settings (font
|
||||
6. Debounce file-change events (editors save multiple times rapidly)
|
||||
|
||||
## Hot-reloadable candidates
|
||||
|
||||
- Font family, size, weight, color
|
||||
- Subtitle background opacity/color
|
||||
- Secondary subtitle display mode
|
||||
@@ -37,6 +41,7 @@ Currently all config is loaded at startup. Users tweaking visual settings (font
|
||||
- AI translation provider settings
|
||||
|
||||
## Restart-required (NOT hot-reloadable)
|
||||
|
||||
- Anki field mappings (affects card creation pipeline)
|
||||
- MeCab path / tokenizer settings
|
||||
- MPV socket path
|
||||
@@ -44,7 +49,9 @@ Currently all config is loaded at startup. Users tweaking visual settings (font
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Config file changes are detected automatically via file watcher.
|
||||
- [ ] #2 Hot-reloadable fields are applied immediately without restart.
|
||||
- [ ] #3 Restart-required fields trigger a user-visible notification.
|
||||
|
||||
@@ -14,11 +14,15 @@ ordinal: 55000
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Refine Mermaid charts in documentation (primarily architecture docs) to improve readability, grouping, and label clarity without changing system behavior.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [x] #1 Mermaid diagrams render successfully in VitePress docs build
|
||||
- [x] #2 Diagrams have clearer grouping, edge labels, and flow direction
|
||||
- [x] #3 No broken markdown or Mermaid syntax in updated docs
|
||||
@@ -27,5 +31,7 @@ Refine Mermaid charts in documentation (primarily architecture docs) to improve
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
|
||||
Improved Mermaid diagrams in docs/architecture.md by redesigning both flowcharts with clearer subgraphs, labeled edges, and consistent lifecycle/runtime separation. Verified successful rendering via `pnpm run docs:build` with no chunk-size warning regressions.
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
|
||||
@@ -17,12 +17,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Build a visual comprehension dashboard that renders per-video "comprehension heatmaps" showing which segments had high lookup density versus segments where the user understood everything without lookups.
|
||||
|
||||
## Motivation
|
||||
|
||||
Immersion tracking data (TASK-28) captures lookup counts, words seen, and cards mined per time segment. Visualizing this data gives learners a powerful way to see their progress: early episodes of a show will be "hot" (many lookups), while later episodes should cool down as vocabulary grows.
|
||||
|
||||
## Features
|
||||
|
||||
1. **Per-video heatmap**: A timeline bar colored by lookup density (green = understood, yellow = some lookups, red = many lookups)
|
||||
2. **Cross-video trends**: Show comprehension improvement across episodes of the same series
|
||||
3. **Session summary cards**: After each session, show a summary with key metrics (time watched, words seen, cards mined, comprehension estimate)
|
||||
@@ -30,11 +33,13 @@ Immersion tracking data (TASK-28) captures lookup counts, words seen, and cards
|
||||
5. **Export**: Generate a shareable image or markdown summary
|
||||
|
||||
## Data sources
|
||||
|
||||
- `imm_session_telemetry` (lookup_count, words_seen per sample interval)
|
||||
- `imm_session_events` (individual lookup events with timestamps)
|
||||
- `imm_daily_rollups` / `imm_monthly_rollups` for trend data
|
||||
|
||||
## Implementation notes
|
||||
|
||||
- Could be rendered in a dedicated Electron window or an overlay modal
|
||||
- Use canvas or SVG for the heatmap visualization
|
||||
- Consider a simple HTML report that can be opened in a browser for sharing
|
||||
@@ -42,7 +47,9 @@ Immersion tracking data (TASK-28) captures lookup counts, words seen, and cards
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Per-video heatmap renders a timeline colored by lookup density.
|
||||
- [ ] #2 Cross-video trend view shows comprehension change across episodes.
|
||||
- [ ] #3 Session summary displays time watched, words seen, cards mined, and comprehension estimate.
|
||||
|
||||
@@ -18,12 +18,15 @@ priority: medium
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Compute a real-time difficulty score for each subtitle line using JLPT level data (TASK-23) and frequency dictionary data (TASK-25), and use this score to drive smart playback features.
|
||||
|
||||
## Motivation
|
||||
|
||||
Learners at different levels have different needs. N4 learners want to pause on N2+ lines; advanced learners want to skip easy content. A per-line difficulty score enables intelligent playback that adapts to the learner's level.
|
||||
|
||||
## Features
|
||||
|
||||
1. **Per-line difficulty score**: Combine JLPT levels and frequency ranks of tokens to produce a composite difficulty score (e.g., 1-5 scale or JLPT-equivalent label)
|
||||
2. **Visual difficulty indicator**: Subtle color/icon on each subtitle line indicating difficulty
|
||||
3. **Auto-pause on difficult lines**: Configurable threshold — pause playback when a line exceeds the user's set difficulty level
|
||||
@@ -31,19 +34,23 @@ Learners at different levels have different needs. N4 learners want to pause on
|
||||
5. **Difficulty trend within a video**: Show whether difficulty increases/decreases over the episode (useful for detecting climax scenes with complex dialogue)
|
||||
|
||||
## Scoring algorithm (suggested)
|
||||
|
||||
- For each token in a line, look up JLPT level (N5=1, N1=5) and frequency rank
|
||||
- Weight unknown words (not in Anki known-word cache from TASK-24) more heavily
|
||||
- Composite score = weighted average of token difficulties, with bonus for line length and grammar complexity
|
||||
- Configurable weights so users can tune sensitivity
|
||||
|
||||
## Design constraints
|
||||
|
||||
- Scoring must run synchronously during subtitle rendering without perceptible latency
|
||||
- Score computation should be cached per subtitle line (lines repeat on seeks/replays)
|
||||
- Auto-pause should be debounced to avoid rapid pause/unpause on sequential hard lines
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 Each subtitle line receives a difficulty score based on JLPT and frequency data.
|
||||
- [ ] #2 A visual indicator shows per-line difficulty in the overlay.
|
||||
- [ ] #3 Auto-pause triggers when a line exceeds the user's configured difficulty threshold.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user