mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-19 05:16:27 -07:00
feat: add subtitle generation and bundle Bun launcher runtime
- Add local subtitle generation and card timing review workflows - Package cross-platform Bun runtimes, launchers, licenses, and source - Consolidate release packaging and refresh v0.19.6 documentation
This commit is contained in:
@@ -11,6 +11,48 @@
|
||||
`ANTHROPIC_API_KEY` works. Install from <https://claude.com/claude-code> if
|
||||
you don't already have it.
|
||||
|
||||
## Package contents and size checks
|
||||
|
||||
Stable and prerelease workflows share `.github/workflows/package-release.yml`.
|
||||
Both callers explicitly pass the five required macOS signing/notarization
|
||||
secrets; `GITHUB_TOKEN` remains automatically available to the reusable workflow.
|
||||
Each platform verifies its ASAR and external resources before signing, then
|
||||
measures the signed app and installers before upload. Missing runtime assets,
|
||||
foreign SQLite/Koffi binaries, duplicate UI fonts, demo media, source maps,
|
||||
TypeScript files, and nested test or fixture directories
|
||||
fail the build. Size measurements are informational and do not block releases.
|
||||
Current targets are Linux x64, macOS arm64, and Windows x64.
|
||||
|
||||
The runtime allowlist includes `dist/`, `stats/dist/`, and
|
||||
`vendor/texthooker-ui/docs/` plus metadata, config example, and license. The
|
||||
texthooker `docs/` directory is its built UI. Keep the positive `package.json`
|
||||
pattern in platform `files` lists: electron-builder otherwise treats an
|
||||
exclusion-only platform list as a separate include-all matcher. Windows keeps
|
||||
only its target Koffi binary; other platforms omit Koffi. Desktop UIs share the
|
||||
original M PLUS 1 TTF in `dist/fonts/`.
|
||||
|
||||
`release/package-size-<platform>-<arch>.json` reports unpacked bytes, largest
|
||||
files inside and outside ASAR, native binaries, and compressed artifact sizes.
|
||||
Framework symlinks are not counted twice. Reports are checksummed and published.
|
||||
CI downloads the preceding release's reports for comparison; older releases
|
||||
without reports skip comparison. Review the inventory and reason for growth
|
||||
when comparing releases. An AppImage normally
|
||||
runs compressed; its extracted size is a separate measurement.
|
||||
|
||||
The shared workflow runs `bun run test:package <resources-directory>` with the
|
||||
pinned Electron runtime and temporary user data. On headless Linux, prefix it
|
||||
with `xvfb-run -a`. This checks packaged SQLite, Windows FFI loading/polling,
|
||||
texthooker serving, Yomitan loading, UI assets, and Japanese font loading.
|
||||
Standalone pages lack app IPC handlers and can log related errors; this check
|
||||
does not replace an installed app session.
|
||||
|
||||
Before shipping packaging changes, check each platform's installed app:
|
||||
startup and mpv tracking, dictionary lookup and stroke orders, settings/sync UI,
|
||||
stats persistence, sentence mining with AnkiConnect, and updating from the prior
|
||||
release. Preserve Electron locales, graphics fallbacks, codecs, dictionaries,
|
||||
license notices, updater metadata, blockmaps, and the macOS updater ZIP. Trim
|
||||
files before signing and generating updater hashes, never from a signed app.
|
||||
|
||||
## Stable Release
|
||||
|
||||
1. Confirm `main` is green: `gh run list --workflow CI --limit 5`.
|
||||
@@ -31,6 +73,14 @@
|
||||
`bun run test:fast`
|
||||
`bun run test:env`
|
||||
`bun run build`
|
||||
Confirm `dist/launcher` contains only `subminer`, `subminer.cmd`,
|
||||
`subminer.js`, `prepare.cjs`, and `version`. Release CI smoke-tests
|
||||
`subminer.js` with Bun, then publishes both wrapper files and their checksums.
|
||||
Tagged CI runs `bun scripts/package-bun-source.mjs` and must publish
|
||||
`bun-v<version>-source.tar.gz` plus its `.sha256` file. The script
|
||||
fails if Bun's CMake dependency pins, WebKit pin, source checksums, patch
|
||||
inputs, or collected license files differ from
|
||||
`build/bun-source-manifest.json`.
|
||||
When validating auto-update metadata, also run the relevant platform package
|
||||
build and confirm `release/` contains the generated updater metadata
|
||||
(`latest*.yml`) and blockmaps (`*.blockmap`).
|
||||
@@ -54,6 +104,11 @@
|
||||
`bun run test:fast`
|
||||
`bun run test:env`
|
||||
`bun run build`
|
||||
Confirm both launcher wrappers and their checksums are included in the
|
||||
prerelease assets.
|
||||
Prerelease CI also assembles and publishes the pinned Bun corresponding
|
||||
source archive. A missing source repository or license file fails the
|
||||
release instead of publishing only the executable.
|
||||
When validating packaged updater output, confirm the platform build writes
|
||||
`latest*.yml` and `*.blockmap` files under `release/`.
|
||||
5. Commit the prerelease prep (package.json version bump + the generated
|
||||
@@ -97,6 +152,7 @@ Notes:
|
||||
- AUR publish is best-effort: the workflow retries transient SSH clone/push failures, then warns and leaves the GitHub Release green if AUR still fails. Follow up with a manual `git push aur master` from the AUR checkout when needed.
|
||||
- Required GitHub Actions secret: `AUR_SSH_PRIVATE_KEY`. Add the matching public key to your AUR account before relying on the automation.
|
||||
- Release and prerelease workflows upload updater metadata (`latest*.yml`) and blockmaps (`*.blockmap`) alongside platform artifacts. Do not remove those files while `electron-updater` is enabled.
|
||||
- Release and prerelease workflows publish `subminer` for POSIX systems and `subminer.cmd` for Windows. Both locate a packaged app and use its private Bun runtime. Keep the corresponding-source archive named `bun-v1.3.5-source.tar.gz`.
|
||||
- macOS tray app updates use the standard `electron-updater`/Squirrel path. Keep `latest-mac.yml`, the macOS `SubMiner-<version>-mac.zip`, and ZIP blockmap published; Squirrel uses the ZIP payload even when the DMG remains the user-facing installer.
|
||||
- macOS update metadata and full ZIP downloads are routed through `/usr/bin/curl` before Squirrel installation to avoid Electron main-process network crashes on update checks.
|
||||
- Windows tray app updates use the standard `electron-updater`/NSIS path. Keep `latest.yml`, the Windows NSIS installer, and installer blockmap published; updater HTTP is routed through main-process fetch to avoid Electron main-process network crashes during update checks.
|
||||
|
||||
@@ -10,11 +10,15 @@ Read when: runtime ownership, composition boundaries, or layering questions
|
||||
SubMiner runs as three cooperating runtimes:
|
||||
|
||||
- Electron desktop app in `src/`
|
||||
- Launcher CLI in `launcher/`
|
||||
- Launcher CLI in `launcher/`, with managed app-installed wrappers in `src/main/runtime/managed-launcher.ts`
|
||||
- mpv Lua plugin in `plugin/subminer/`
|
||||
|
||||
The desktop app keeps `src/main.ts` as composition root and pushes behavior into small runtime/domain modules.
|
||||
|
||||
Packaged apps include a private Bun runtime. Setup and release assets provide bootstrap wrappers generated from `src/main/runtime/*-launcher-bootstrap.ts`. macOS runs Bun and the CLI from app resources. Windows stages a versioned private Bun copy under `%LOCALAPPDATA%\SubMiner\launcher-runtime/<version>` so a running launcher does not lock the updater-owned app executable. Linux stages Bun, the matching CLI, and licenses under `${XDG_DATA_HOME:-~/.local/share}/SubMiner/launcher`. Its steady-state path performs one app `stat` and starts the cache without Electron. A missing cache or changed app fingerprint runs `launcher/prepare.cjs` through Electron's Node mode to refresh it. Desktop startup migrates recognized writable legacy JavaScript launchers and refreshes managed payloads after app changes. Development commands still use system Bun.
|
||||
|
||||
Update checks and startup launcher migration share a serialized update-state store. Deferred launcher paths are acknowledged only after migration succeeds or the candidate is no longer eligible. Running Windows launchers and unreadable or unwritable candidates remain pending for a later startup.
|
||||
|
||||
## Read Next
|
||||
|
||||
- [Domains](./domains.md) - who owns what
|
||||
@@ -27,6 +31,7 @@ The desktop app keeps `src/main.ts` as composition root and pushes behavior into
|
||||
- `src/main/` owns composition, runtime setup, IPC wiring, and app lifecycle adapters.
|
||||
- `src/main/boot/` owns boot-phase assembly seams so `src/main.ts` can stay focused on lifecycle coordination and startup-path selection.
|
||||
- `src/core/services/` owns focused runtime services plus pure or side-effect-bounded logic.
|
||||
- `src/core/services/subtitle-generation*.ts` shares local whisper.cpp transcription, safe model downloads, and progress between the launcher and Electron. Optional dialogue mode retains both Silero-detected speech and other audible sections, omits confidently silent gaps, decodes passages independently, and restores original media timing. `src/main/runtime/subtitle-generation-runtime.ts` owns the overlay job lifecycle and only loads completed subtitles into the same local media; `src/shared/subtitle-generation*.ts` owns configuration, the multilingual model catalog, and IPC contracts. The overlay runtime retains a session model selection, validates picker requests through IPC, and keeps external model paths authoritative.
|
||||
- `src/renderer/` owns overlay rendering and input behavior.
|
||||
- `src/config/` owns config definitions, defaults, loading, and resolution.
|
||||
- `src/types/` owns shared cross-runtime contracts via domain entrypoints; `src/types.ts` stays a compatibility barrel.
|
||||
@@ -40,3 +45,7 @@ The desktop app keeps `src/main.ts` as composition root and pushes behavior into
|
||||
- Composition over monoliths
|
||||
- Pure helpers where possible
|
||||
- Stable user behavior while internals evolve
|
||||
|
||||
Startup resolves and creates the user-data directory in `src/main-entry-runtime.ts`
|
||||
before the entry process requests Electron's single-instance lock. Main-process
|
||||
config bootstrap then writes the default config only when no config file exists.
|
||||
|
||||
@@ -27,6 +27,8 @@ Read when: you need to find the owner module for a behavior or test surface
|
||||
Includes stats storage/query schema such as `imm_videos`, `imm_media_art`, and `imm_youtube_videos` for per-video and YouTube-specific library metadata.
|
||||
Library-entry identity aliases and merge recommendations are persisted alongside this schema; the stats HTTP and SPA layers only expose and present those domain decisions.
|
||||
`delete-maintenance-scheduler.ts` coalesces and serializes stats deletes; the expensive work runs in `delete-maintenance-worker-thread.ts` while the tracker queues playback writes. Each batch uses one transaction, lexical update, rollup refresh, and incremental lifetime subtraction (`planLifetimeRemovals`/`applyLifetimeRemovals` in `lifetime.ts`). Merges, moves, AniList reassignments, and `stats cleanup -l` use `repairLifetimeSummariesFromMedia` (recompute from the per-video media ledger). The full lifetime rebuild survives only as the empty-table bootstrap; anywhere else it would collapse lifetime totals to the session retention window.
|
||||
- Immersion sync: `src/core/services/stats-sync/`, bound by `src/main/sync-cli.ts`.
|
||||
`snapshot-transfer.ts` selects compressed rsync or scp. `transfer-cache.ts` atomically retains the last successfully received snapshot per hashed peer/database identity under the config directory's `sync-transfer-cache/`. Cache copies seed isolated transfer directories; rsync verifies reconstructed files before the existing merge engine runs. The `--make-temp` / `--remove-temp` helpers accept an internal `--transfer-cache` key, with a fallback for older peers that do not recognize it.
|
||||
- AniList tracking + character dictionary: `src/core/services/anilist/`, `src/main/runtime/composers/anilist-*`, `src/main/character-dictionary-runtime.ts`, `src/main/character-dictionary-runtime/`
|
||||
- Jellyfin integration: `src/core/services/jellyfin*.ts`, `src/main/runtime/composers/jellyfin-*`
|
||||
- Anime browser: extension bridge client, sidecar, and stream handling in `src/anime-bridge/`;
|
||||
@@ -47,6 +49,25 @@ Read when: you need to find the owner module for a behavior or test surface
|
||||
|
||||
## Shared Contract Entry Points
|
||||
|
||||
Automatic mpv keyboard discovery uses the `get-mpv-input-bindings` IPC request and
|
||||
`MpvInputBindingsSnapshot` in `src/types/session-bindings.ts`.
|
||||
`src/main/runtime/mpv-input-bindings.ts` queries the connected player and preserves
|
||||
configured keys, including disabled entries. `src/shared/mpv-input-bindings.ts`
|
||||
validates discovered keys and translates browser input. The renderer's
|
||||
`handlers/mpv-input-forwarding.ts` keeps the session lookup, coalesces asynchronous
|
||||
refreshes, and releases held keys on blur or disposal. `handlers/keyboard.ts` runs
|
||||
this fallback after SubMiner controls and refreshes on startup, a delayed startup
|
||||
pass, focus, and binding reload. Discovery does not enter compiled session bindings,
|
||||
the plugin artifact, persistent config, or session help.
|
||||
|
||||
The subtitle sidebar consumes parsed cues through `SubtitleSidebarSnapshot`. Its `sourceKey`
|
||||
identifies the media and subtitle source so renderer selections are invalidated on source changes,
|
||||
including changes whose cue text and timings are identical. Native selection and clean clipboard
|
||||
serialization live in `src/renderer/modals/subtitle-sidebar-selection.ts`. Electron lets standard
|
||||
Copy input reach the renderer, where sidebar selection takes priority over the live-subtitle binding.
|
||||
The preload bridge writes selections through Electron's clipboard API so copying does not depend
|
||||
on Chromium document focus or require activating the overlay window.
|
||||
|
||||
- Config + app-state contracts: `src/types/config.ts`
|
||||
- Subtitle/token/media annotation contracts: `src/types/subtitle.ts`
|
||||
- Runtime/window/controller/Electron bridge contracts: `src/types/runtime.ts`
|
||||
|
||||
@@ -23,7 +23,7 @@ Renderer, launcher, plugin, and stats each keep their own local layering and sho
|
||||
- Keep side effects explicit and close to composition boundaries.
|
||||
- Put reusable business logic in focused services, not in top-level lifecycle files.
|
||||
- Keep renderer concerns in `src/renderer/`; avoid leaking DOM behavior into main-process code.
|
||||
- Treat `launcher/*.ts` as source of truth for the launcher. Never hand-edit `dist/launcher/subminer`.
|
||||
- Treat `launcher/*.ts` and the runtime bootstrap generators as source of truth for launcher behavior. `scripts/build-launcher.ts` creates `dist/launcher`; never hand-edit those artifacts.
|
||||
|
||||
## Smells
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ Read when: selecting the right verification lane for a change
|
||||
there instead of copying them into caller workflows.
|
||||
- The reusable gate installs Lua and runs `bun run test:env`, so the shipped mpv
|
||||
plugin tests run for every pull request and tagged release.
|
||||
Lua installation uses only the runner's Ubuntu package sources so unrelated
|
||||
third-party repository failures do not block the gate.
|
||||
|
||||
## Default Handoff Gate
|
||||
|
||||
@@ -50,6 +52,11 @@ bun run docs:build
|
||||
- Runtime-compat / compiled behavior: `bun run test:runtime:compat`
|
||||
- Stats dashboard UI: `bun run test:stats`
|
||||
- Build/release scripts (`scripts/**`): `bun run test:scripts`
|
||||
- Packaging: build the platform package, then run `bun run test:package <resources-directory>`.
|
||||
On headless Linux: `xvfb-run -a bun run test:package release/linux-unpacked/resources`.
|
||||
Content checks and informational size reporting run inside electron-builder hooks. See the
|
||||
[release guide](../RELEASING.md#package-contents-and-size-checks) for size reports
|
||||
and the installed-app verification checklist.
|
||||
- Coverage for the maintained source lane: `bun run test:coverage:src`
|
||||
- Deep/local full gate: default handoff gate above
|
||||
|
||||
|
||||
Reference in New Issue
Block a user