Commit Graph

394 Commits

Author SHA1 Message Date
sudacode 2003efa235 fix(subtitles): release prefetch pause across all priming paths
The repeated-subtitle pause leak was only fixed for ordinary subtitle
changes. Startup autoplay priming and visible-overlay priming pause the same
way and also ignored whether any tokenization was scheduled, so a cache miss
on text the controller already holds (mining a card while the line is on
screen) left prefetching idle for the rest of the cue.

Pause and release are now one operation via pausePrefetchUntilEmit, and both
controller entry points report whether an emit is expected. A repeat arriving
while a run is already in flight keeps the pause, since that run still emits.

Also invalidate the character dictionary lookups centrally from the sync
completion handler instead of at three manager call sites. Ordinary selection
sync never invalidated them, so a stale non-null name candidate list could
skip a newly added name for up to five seconds; a missing list falls back to
the exhaustive scan, but a stale one does not. Ordering matters: the
invalidation runs before the subtitle refreshes so they re-tokenize against
the new dictionary content.

Docs: subtitle-overlay-priming no longer claims every subtitle change calls
onSeek().
2026-08-04 01:56:44 -07:00
sudacode f43674cc39 fix(subtitles): release prefetch pause on repeated subtitle events
onSubtitleChange paused prefetching unconditionally, but the processing
controller returns early when the text matches what it already has. Nothing
is tokenized, so nothing is emitted, so the resume that rides on the emit
never fires and prefetching idles for the rest of the cue. The reachable
trigger is a repeat arriving after a cache invalidation, such as mining a card
while the same line is still on screen.

The controller now reports whether it scheduled processing and the caller
resumes when it did not, so every pause has a matching resume.

Also harden the character-name candidate prefilter: Yomitan collapses emphatic
sequences before matching, so a stretched spelling still resolves to its entry
(ミナァァト matches ミナト). The candidate match now skips small kana and
prolonged marks, which only widens the probe set and so cannot drop a name.
2026-08-04 01:56:44 -07:00
sudacode b0a2ce6e8a perf(tokenizer): skip character-name lookups where no name can start
The greedy name pre-pass asked the Yomitan backend at every Japanese
position, because a character name can begin mid-token. With the character
dictionary enabled that roughly doubled the round trips per line (measured
10 -> 21 on a 23-char line).

SubMiner generates the character dictionary, so the cached snapshots already
list every form a character entry can be matched by (term and reading). Those
forms are installed into the scan runtime once per media and the pre-pass now
probes only positions where one of them starts, compared after kana
normalization so a katakana name still matches a hiragana reading form. The
overhead drops to zero (21 -> 10, the same as with the dictionary disabled).

Fail-safe: with no candidate list (no media id, no cached snapshot, failed
install) the pre-pass keeps its exhaustive behavior, so stale character data
costs speed rather than a missing name. Halfwidth katakana positions bypass
the filter since kana normalization does not fold them.

The candidate lookup is consulted per subtitle line, so it caches its snapshot
directory signature for 5s; dictionary writes still call invalidate().
2026-08-04 01:56:44 -07:00
sudacode 030c94934e refactor(tokenizer): address review feedback on Yomitan scan runtime
- extract the injected scan runtime (helpers, install script, call-script
  builder) into tokenizer/yomitan-scan-runtime-script.ts; the host module drops
  from ~2700 to ~1900 lines
- append the kana run to the reading as well as the surface when an unparsed
  run extends the previous token, so the reading keeps covering the surface and
  the known-word reading fallback stays enabled (bumps scan runtime version)
- stop annotateMs before character-image resolution so the stage timing
  measures the annotation stage only
2026-08-04 01:56:44 -07:00
sudacode e7cef039f3 perf(tokenizer): single-pass Yomitan scan with install-once runtime and cross-line cache
- drop the duplicate parseText full parse per line; the termsFind scanner walk
  is now authoritative and emits its own unparsed filler runs (parseText kept
  only as error fallback)
- install scan helpers once per parser window (__subminerYomitanScan) instead
  of re-shipping ~500 lines of script per subtitle line
- persist termsFind results across lines in a window-scoped LRU keyed by
  substring, invalidated via a cache epoch on dictionary/settings changes
- skip lookups at punctuation/whitespace positions and cap the shrinking-window
  retry ladder at 4 lookups per position
- build tokenizer runtime deps once (JLPT lookup cache never hit before; mecab
  availability check ran per line)
- stop restarting the prefetch run on every subtitle change; resume prefetch
  only after the tokenized payload lands, not on provisional raw emits
- add per-stage debug timings (scanMs/mecabMs/frequencyMs/annotateMs)
2026-08-04 01:56:44 -07:00
sudacode fe4dacc1e7 fix(overlay): show plain subtitle line immediately on tokenization cache miss (#184) 2026-08-04 01:55:52 -07:00
sudacode b08cd0db35 fix(streaming): keep subtitle tokenization prefetch warm for full episodes (#183) 2026-08-03 21:22:18 -07:00
sudacode bffb1c5982 fix(logging): surface subtitle processing debug/warn logs (#182) 2026-08-03 20:44:39 -07:00
sudacode 5b8848518a feat(subsync): add reference and target subtitle track picker (#181) 2026-08-03 01:00:14 -07:00
sudacode 176edd67f1 chore(release): v0.19.1 v0.19.1 2026-08-01 23:59:20 -07:00
sudacode 4d65dec340 fix(youtube): prevent playlist URLs from stalling yt-dlp probes (#180) 2026-08-01 22:56:28 -07:00
sudacode 6607c333bc fix(overlay): strip spinner frame from subsync overlay card
- Add overlayBody override to ConfiguredStatusNotificationOptions so overlay/OSD/desktop can diverge
- Extract getSubsyncStatusNotificationOptions() to strip the ASCII spinner frame from the overlay card (OSD keeps it since it renders the raw spinner)
- Add tests for spinner stripping and subsync result notifications
2026-07-31 18:03:26 -07:00
sudacode b2bbf1ae12 chore: regenerate config example artifacts 2026-07-31 17:49:02 -07:00
sudacode b204d4dd6e feat(anki): add configurable word card type for Kiku/Lapis (#175) 2026-07-31 17:17:29 -07:00
sudacode 89ed675935 fix(overlay): keep Yomitan popup interactive on macOS/Windows (#177) 2026-07-30 19:47:08 -07:00
sudacode 1995200e76 chore(release): prepare v0.19.0 v0.19.0 2026-07-29 22:26:03 -07:00
sudacode e876e483d6 chore(release): prepare v0.19.0-beta.5 v0.19.0-beta.5 2026-07-29 02:09:01 -07:00
sudacode 6d2a72e13b feat(stats): add library entry deletion and app-wide delete progress (#174) 2026-07-29 02:00:16 -07:00
sudacode 0d7084c8aa fix(anilist): resolve later seasons via sequel relations, not title guessing (#173) 2026-07-28 22:56:26 -07:00
sudacode 95e0abc7b7 test(immersion): apply runtime SQLite pragmas in query tests
The query test suite opened each temp database with SQLite's defaults
(rollback journal, synchronous=FULL) while the runtime opens them via
applyPragmas (WAL, synchronous=NORMAL). Every statement therefore ran as
its own fsync-ing transaction.

That is unnoticeable on a fast local disk but dominates on CI: the file
took 40.6s there versus 0.5s locally, and the 106-insert case
'getVocabularyStats pages past hidden rows' crossed the 5s per-test
timeout and failed the quality gate.

Open test databases through a helper that applies the same pragmas as
production, so the tests exercise the runtime's actual SQLite
configuration instead of a slower one.
2026-07-28 02:23:16 -07:00
sudacode d9155ceacb docs: update requirements table and Windows install instructions
- Add TsukiHime and AniSkip to feature table; note xz dependency
- Clarify Anki+AnkiConnect is required to mine, not to run
- Rework Windows setup with winget/scoop commands and PATH steps
- Note ffmpeg has no path-override setting, unlike mpv
- Fix screenshot alt text and installation.md anchor link
2026-07-28 02:10:50 -07:00
sudacode 9d0585423c chore(release): prepare v0.19.0-beta.4 v0.19.0-beta.4 2026-07-28 01:09:48 -07:00
sudacode 455cfff90a docs: fix inaccuracies and add link/anchor validation tests
- Generate config.example.jsonc with a Linux socket path instead of Windows, so the example stays reproducible across platforms
- Document TsukiHime config (`tsukihime.*`), maturity-based known-word highlighting keys, and other config surfaces missing from the reference
- Correct secondary-subtitle auto-load defaults and Anki field-matching (case-insensitive) claims
- Expand Windows installation guide with winget/Scoop package tables and manual PATH setup
- Add docs-site/links.test.ts to catch broken internal links and heading-anchor mismatches
- Fix stale cross-references in jimaku-integration.md and demos.md
2026-07-28 00:56:38 -07:00
sudacode 987b325edb Anki maturity-based known-word highlighting (#172) 2026-07-27 23:58:02 -07:00
sudacode 08c6807cb1 fix(launcher): normalize rofi prompt spacing
- Add formatRofiPrompt to trim trailing whitespace and append a single space, keeping the prompt from running into the input field
- Apply it across all rofi -p usages in picker.ts and history-command.ts
- Add tests for formatRofiPrompt edge cases (empty/whitespace-only prompts)
2026-07-26 00:13:54 -07:00
sudacode 18c6410f24 feat(launcher): add previous episode option to history entry menu
- Extract buildHistoryEntryActions to build the series action menu, now including a previous-episode option alongside replay/next/browse/quit
- Update docs and changelog entry to describe the new option
- Add tests covering previous/replay/next ordering and omission when last watched file is missing
2026-07-25 23:35:44 -07:00
sudacode e223cf9b71 fix(release): restore compatible js-yaml override v0.19.0-beta.3 2026-07-22 23:51:21 -07:00
sudacode c718bb8b34 chore(release): prepare 0.19.0-beta.2 v0.19.0-beta.2 2026-07-22 23:34:08 -07:00
sudacode 177f7e5fd6 docs(readme): remove TsukiHime credit
- Drop the TsukiHime row from the open-source credits table
2026-07-22 23:07:07 -07:00
sudacode 20b50ec4e1 feat(launcher): add post-playback history menu with previous episode (#170) 2026-07-22 23:05:53 -07:00
sudacode deae61b211 refactor: split anki-connect and stats-server resolvers into modules (#169) 2026-07-17 23:05:59 -07:00
sudacode 44959ed282 fix(anki,appimage): handle proxy port conflicts and stray GPU child
- AnkiConnect proxy now detects EADDRINUSE, logs a warning, and surfaces an overlay notification instead of crashing video startup
- Background AppImage bootstrap runs Chromium with in-process-gpu so no GPU child survives app.exit() and outlives the FUSE mount, fixing the remaining DrKonqi "Service Crash" case
- Add changelog fragment for the proxy fix; update the AppImage quit fragment with the GPU child root cause
2026-07-17 23:04:56 -07:00
sudacode 2398f5c030 refactor(main): eliminate local pass-through wrappers in main.ts (#168) 2026-07-15 03:22:03 -07:00
sudacode 8711cf1a48 remove redundant isVerbNonIndependent and consolidate test lanes
- drop always-true isVerbNonIndependent export; collapse shouldMerge branch
- remove node-compat exclusion list from bun-src-full lane
- simplify test:fast (drop test:runtime:compat), test:env, test:smoke:dist scripts
- rename test:launcher:env:src -> test:env in docs
2026-07-14 19:57:50 -07:00
sudacode 9f4888293b chore(release): prepare 0.19.0-beta.1 v0.19.0-beta.1 2026-07-13 23:47:50 -07:00
sudacode 29332b103e Consolidate sync changelog fragments into one entry
- Merge the five separate sync change fragments (launcher command, UI window, close/quit fixes, active-session double-count, monthly rollup timezone) into a single changes/sync.md
- Fold kana-pos-content-classification.md into annotation-noise-rule-table.md
- Drop the now-stale Unreleased sections from CHANGELOG.md and docs-site/changelog.md
- Tweak tsukihime-english-subtitles.md wording
2026-07-13 23:40:28 -07:00
sudacode 8b2cee2c58 ci: reuse quality gate across CI and release workflows (#167) 2026-07-13 23:14:19 -07:00
sudacode 2e2ee3f028 refactor(tsukihime): swap Animetosho backend for TsukiHime API (#165) 2026-07-13 22:03:35 -07:00
sudacode 49b926e08c Sync Stats & History window, headless --sync-cli, and Windows remote support (#160) 2026-07-13 18:56:51 -07:00
sudacode 66f8ca4f80 refactor(renderer): extract modal registry for open/dismiss/active queries (#166) 2026-07-13 18:16:39 -07:00
sudacode 6fe1e0fee4 refactor(stats): drop dead IPC handlers, unify stats types over HTTP (#164) 2026-07-13 12:09:56 -07:00
sudacode 0ab840b362 refactor(tokenizer): extract subtitle annotation filter into rule table (#162) 2026-07-12 23:54:13 -07:00
sudacode 21a06c12fb refactor(tokenizer): consolidate kana/POS helpers into token-classification (#161) 2026-07-12 23:27:25 -07:00
sudacode 14070acceb fix(overlay): defer autoplay release for untokenized startup priming
- Autoplay-ready gate now ignores untokenized subtitle payloads while tokenization warmup is pending, so playback doesn't resume before the first tokenized cue
- Wire isTokenizationReady dep through main.ts and update gate/wiring tests accordingly
- Drop stale release/release-notes.md, add changelog entry under changes/
2026-07-12 02:11:10 -07:00
sudacode 7d81342f0f fix(app): keep AppImage mount alive until Chromium children finish shutdown
Background AppImage launches executed directly from a FUSE mount owned by a
short-lived helper's AppImage runtime. On quit, the runtime unmounted the
squashfs while utility children (network service) were still mid-shutdown,
SIGBUSing them and triggering KDE Service Crash notifications on every video
close. Detach a POSIX-sh supervisor instead: mount via --appimage-mount, run
AppRun from the mount, and release the holder only once no process still
executes from the mount. Falls back to the old direct launch on any failure
or with SUBMINER_NO_APPIMAGE_MOUNT_KEEPALIVE=1.
2026-07-12 02:09:42 -07:00
sudacode 4b7f750919 feat(animetosho): add English/Japanese subtitle download integration (#159) 2026-07-12 00:48:12 -07:00
sudacode 6ab3d823a4 feat(shortcuts): make clipboard-video-append shortcut configurable (#158) 2026-07-11 23:36:44 -07:00
sudacode 8797719a09 docs(docs-site): correct and clarify docs against current code
Comprehensive accuracy pass over docs-site verifying every page against
current source. Fixes wrong/stale claims (AniSkip default, YouTube track
selection, Anki sentence-card requirements, immersion schema v18 + SQL
column names, plugin entrypoint, launcher flags, Cloudflare deploy path,
etc.) and fills gaps (watch history, mediaCache.maxHeight, youtubeSubgen,
character-dictionary refresh/eviction, expanded hot-reload lists).
2026-07-11 00:53:34 -07:00
sudacode 8acc78cc1c test(tokenizer): add golden-file regression corpus with 11 fixtures (#157) 2026-07-11 00:50:03 -07:00
sudacode 321461c50f feat(launcher): add subminer sync for cross-machine stats/history merge over SSH (#152) 2026-07-11 00:40:15 -07:00