* refactor(main): move the YouTube domain into an assembly
createYoutubeAssembly owns the YouTube flow, playback, media cache,
whisper subtitles, primary-subtitle notifications, and the in-app
browser, plus the browser quit-on-close state. main.ts builds it once
where the first YouTube runtime used to be and calls through the result.
Siblings built later are passed as getters or callbacks; tests pin that
construction calls none of them.
* docs(architecture): describe per-domain assemblies
* test(e2e): blank the line before mining the sub-delay cue
The previous test leaves the same cue on screen, so the overlay check
passed before the seek landed and --mine-sentence could read mpv's empty
mid-seek sub-text and skip the card.
* refactor(main): move the Jellyfin domain into an assembly
createJellyfinAssembly owns the Jellyfin composer call, its playback and
remote-progress state, the subtitle cache IO, mpv defaults, and the tray
discovery deps. main.ts builds it where the composer call used to be and
reads state through getActivePlayback/getQuitOnDisconnectArmed.
* refactor(main): move the AniList domain into an assembly
createAnilistAssembly owns the AniList setup and tracking composer calls,
the setup window, the state runtime, and the token, media-guess, in-flight
and attempted-update state they share. main.ts builds it where the setup
composer call used to be and keeps the rate limiter, which the stats
cover-art fetcher also uses.
* refactor(main): move config hot-reload, settings, and sync UI into assemblies
createSettingsAssembly owns config hot-reload and the settings window,
which share the hot-reload-applied handler; main.ts still supplies that
handler's cross-domain deps and the Yomitan deck-name helper.
createSyncAssembly owns the sync window, sync IPC runtime, and auto-sync
scheduler. Both are built where their blocks were; main.ts keeps the
registerHandlers()/start() calls at the same points.
* refactor(main): move dictionary runtimes into assemblies
createDictionariesAssembly owns the JLPT and frequency lookups and their
dictionary-root builders; main.ts still resolves the root paths at the
same point. createCharacterDictionaryAssembly owns the character
dictionary runtime, Yomitan auto-sync, and the portrait and name-candidate
lookups. Both are built where their blocks were; later siblings (Yomitan
profile policy, notifications, OSD, subtitle refresh) come in as getters
or callbacks.
* refactor(main): move overlay modal openers into an assembly
createOverlayModalsAssembly owns the shared open-with-notification helper
and the runtime options, Jimaku, TsukiHime, subtitle generation, session
help, changelog, character dictionary manager, controller, and playlist
browser openers. main.ts builds it where the openers used to live.
* refactor(logger): export the Logger type for assembly deps
The build emits declarations, and the Jellyfin assembly returns the logger
in its tray discovery deps, so tsc needs a nameable Logger type. Assemblies
now Pick from it directly.
* refactor(main): drop remaining pass-through main-deps builders
Jellyfin client-info/setup-window/remote, overlay shortcuts/visibility/
layout/window-factory, config hot-reload, and startup bootstrap factory
builders only forwarded deps. Callers now pass deps to the handlers
directly; createWatchConfigPathHandler moves into config-hot-reload-handlers.
* refactor(main): fold small-logic main-deps builders into their handlers
Tray click, mpv client factory, startup bootstrap exit callbacks, overlay
runtime options, and dictionary roots/runtime builders move their logic
into the owning handler or call site. The two duplicated dictionary-root
builders become one createBuildDictionaryRootsHandler(vendorDirName).
* refactor(main): fold cli command context builders into the factory
createCliCommandContextFactory now adapts appState and main services to
the CLI command context deps directly (socket-path change notification,
texthooker port/websocket URL, browser-open default). The pass-through
cli-command-context-main-deps and cli-command-context-deps layers are
removed; their behavioural tests now run against the factory's context.
* refactor(main): fold subtitle tokenization builder into the mpv composer
The tokenizer deps builder's logic (known-word lookup recording and the
character-dictionary gate on name matching) becomes
buildTokenizerRuntimeOptions in mpv-runtime-composer, tested through the
composer. The MeCab check and dictionary prewarm handlers move to
subtitle-tokenization-warmup.ts, and the unused BuiltMainDeps type is
removed from composer contracts.
* refactor(main): drop redundant tokenizer deps keys and cast
* refactor(main): end the main-deps builder pattern
mpv-main-event-main-deps becomes mpv-main-event-binding-deps
(createMpvMainEventBindingDeps), returning the binding deps directly
instead of a thunk; it owns the subtitle-recording state. The will-quit
cleanup adapter likewise returns its deps directly, and the pass-through
app-lifecycle activate builders are removed.
* docs: drop references to main-deps builders
- Generated sentence audio no longer overwrites Yomitan's ExpressionAudio on default configs
- fields.wordAudio still defaults to ExpressionAudio
- Regenerate config.example.jsonc and update the Anki and configuration docs
- Add changelog fragment
* feat(subtitles): generate Japanese subtitles during Jellyfin playback
- Read the item's original file via toJellyfinOriginalStreamUrl and write output to a temp dir
- Transcoded playback uses Jellyfin's audio index and only external references
- Show Jellyfin media by title and redact URL tokens in subprocess errors
- Update overlay copy, docs, and changelog fragment
* fix(subtitles): redact full stream tokens and reuse one Jellyfin output folder
* test(subtitles): make Jellyfin output path assertions platform-neutral
- Compare dirname/basename via node:path instead of POSIX-only regexes
- Assert the full sub-add command uses the generated output path
* refactor: remove dead code and enable noUnusedLocals
- delete launcher/jimaku.ts and the launcher Args/config jimaku* fields
that only fed it (the SUBMINER_JIMAKU_* env vars had no effect)
- delete plugin/subminer/hover.lua; nothing has sent subminer-hover-token
since Overlay 2.0
- drop never-read anilist.characterDictionary.refreshTtlHours and
evictionPolicy (still hidden in the settings UI for old configs)
- drop unused root deps: eslint, @fontsource-variable/geist{,-mono}
(stats/ declares its own)
- delete the committed draft renderer-performance plan doc
- turn on noUnusedLocals for typecheck and remove what it surfaced,
including Windows focus-handoff values computed but never consumed
* docs(changes): add docs fragment and note retired hover messages
- Install MeCab from the AUR (mecab-git) on Arch, since it is not in the official repos
- Rewrite the README feature blurbs, requirements table, and quick start so they match docs-site/installation.md
- Add fuse2, X11 window tools, whisper.cpp, and the thumbnail tools to the README requirements
- Drop the playlist browser and texthooker sections and the standalone launcher download steps
- Mention AniList as a guessit consumer in the installation guide
- Preview session observes time-pos, waits for loaded media before seeking, and acks each command
- Forward positions to the modal over media-timing-review:preview-position
- Cursor follows the real position, pauses while buffering, and stays at the clip end when done
- Replace the fixed end-of-clip timer with a 15s stall timeout
- Document preview cursor behavior and ownership in docs
- Pages now start with setup and usage, and reference material is in compact tables
- Configuration reference gives each config block a short explanation and a key/default table
- Internal detail removed from user pages, and docs that had drifted from current behavior fixed
- The status line shows today's date, set on the client, instead of the page's last-updated date
- Add changelog fragment