feat(config): update default startup and subtitle style options

- Disable texthooker, websocket, and annotationWebsocket servers by default
- Update primary subtitle font family to include Hiragino Sans
- Switch subtitle backgrounds to transparent for primary and secondary
- Unify text shadow to stronger two-layer value for both subtitle tracks
- Set JLPT N4 default color to #8bd5ca
- Keep Yomitan popup auto-pause enabled and secondary font stack unchanged
- Update tests, generated config examples, and docs-site to match
This commit is contained in:
2026-05-12 23:29:36 -07:00
parent d48d880ba3
commit bc8d1edf6f
8 changed files with 134 additions and 63 deletions
@@ -0,0 +1,68 @@
---
id: TASK-359
title: Update default startup and subtitle style options
status: Done
assignee:
- Codex
created_date: '2026-05-13 06:16'
updated_date: '2026-05-13 06:28'
labels:
- config
dependencies: []
priority: medium
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
Change fresh-install defaults so texthooker and associated subtitle websocket servers are disabled unless explicitly enabled, Yomitan popup auto-pause remains enabled by default, and primary/secondary subtitle style defaults match the requested font, transparent background, and stronger shadow. Keep generated example config and docs aligned with resolved defaults.
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 Fresh default config has texthooker startup disabled by default.
- [x] #2 Fresh default config disables associated subtitle websocket servers by default, or exposes/uses an existing config option that does so.
- [x] #3 Fresh default config keeps subtitleStyle.autoPauseVideoOnYomitanPopup enabled by default.
- [x] #4 Fresh default config uses fontFamily `Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP` for primary subtitles.
- [x] #5 Fresh default config keeps secondary subtitle fontFamily as `Inter, Noto Sans, Helvetica Neue, sans-serif`.
- [x] #6 Fresh default config uses textShadow `0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)` for primary and secondary subtitles.
- [x] #7 Fresh default config uses transparent subtitle backgrounds for primary and secondary subtitles.
- [x] #8 Tests and generated/docs config examples are updated for the new defaults.
- [x] #9 Fresh default config uses `#8bd5ca` for the fourth frequency band and JLPT N4 subtitle color.
<!-- AC:END -->
## Implementation Plan
<!-- SECTION:PLAN:BEGIN -->
1. Update focused config tests first for the requested fresh-install defaults.
2. Change default config values in `src/config/definitions/defaults-core.ts` and `src/config/definitions/defaults-subtitle.ts`.
3. Regenerate generated config examples with the repo generator.
4. Update docs-site configuration prose/snippets for the new defaults.
5. Run focused config/example tests and mark acceptance criteria when verified.
6. Include the requested JLPT N4 default color adjustment and verify the existing fourth frequency band default remains `#8bd5ca`.
7. Restore the secondary subtitle font default to its previous `Inter, Noto Sans, Helvetica Neue, sans-serif` stack while keeping the new primary subtitle font default.
<!-- SECTION:PLAN:END -->
## Implementation Notes
<!-- SECTION:NOTES:BEGIN -->
Context: existing config already has websocket.enabled (`true | false | "auto"`) and annotationWebsocket.enabled (`boolean`), so disabling associated websockets can be handled by default changes instead of adding a new config surface.
Scope update from user: also set JLPT N4 default color to `#8bd5ca`; fourth frequency band is already `#8bd5ca` in current defaults and has existing regression coverage.
Verification: `bun run test:config`, `bun run docs:test`, `bun run docs:build`, `bun run changelog:lint`, `bun run format:check:src`, `bun run typecheck`, `bun run build`, `bun run test:smoke:dist`, and `git diff --check` passed. Earlier full fast/env suites also passed during this task (`bun run test:fast`, `bun run test:env`) before the final N4-only default tweak; focused config/docs/build/smoke checks were rerun after that tweak.
Scope correction from user: secondary subtitles should keep the previous font stack. Interpreting the typo `snas-serif` as the previous literal default `sans-serif`.
Correction verification: restored secondary subtitle default font to `Inter, Noto Sans, Helvetica Neue, sans-serif`. Passed `bun run test:config`, `bun run docs:test`, `bun run changelog:lint`, `bun run format:check:src`, `bun run typecheck`, and `git diff --check`. Verified generated examples and docs contain the restored secondary font.
<!-- SECTION:NOTES:END -->
## Final Summary
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
Updated fresh-install defaults so texthooker startup, the regular subtitle websocket, and the annotation websocket are disabled by default while preserving Yomitan popup auto-pause. Updated primary subtitle defaults to the requested Japanese font stack, kept secondary subtitle font at the prior `Inter, Noto Sans, Helvetica Neue, sans-serif` stack, and applied shared stronger text shadow, transparent backgrounds, and teal N4/fourth-band color. Regenerated config examples, updated docs-site configuration docs, and added a changelog fragment.
Verification passed: `bun run test:config`, `bun run docs:test`, `bun run docs:build`, `bun run changelog:lint`, `bun run format:check:src`, `bun run typecheck`, `bun run build`, `bun run test:smoke:dist`, and `git diff --check`. After the secondary-font correction, reran `bun run test:config`, `bun run docs:test`, `bun run changelog:lint`, `bun run format:check:src`, `bun run typecheck`, and `git diff --check`. `bun run test:fast` and `bun run test:env` also passed during the task before the final small default corrections; affected focused checks were rerun afterward.
<!-- SECTION:FINAL_SUMMARY:END -->
@@ -0,0 +1,4 @@
type: changed
area: config
- Config: Disabled texthooker startup plus subtitle and annotation websocket servers by default, while keeping Yomitan popup auto-pause enabled and updating fresh primary subtitle style defaults to a Japanese font stack, transparent subtitle backgrounds, stronger text shadows, and teal N4/fourth-band coloring.
+9 -9
View File
@@ -17,7 +17,7 @@
// Configure texthooker startup launch and browser opening behavior. // Configure texthooker startup launch and browser opening behavior.
// ========================================== // ==========================================
"texthooker": { "texthooker": {
"launchAtStartup": true, // Launch texthooker server automatically when SubMiner starts. Values: true | false "launchAtStartup": false, // Launch texthooker server automatically when SubMiner starts. Values: true | false
"openBrowser": false // Open browser setting. Values: true | false "openBrowser": false // Open browser setting. Values: true | false
}, // Configure texthooker startup launch and browser opening behavior. }, // Configure texthooker startup launch and browser opening behavior.
@@ -27,7 +27,7 @@
// Auto mode disables built-in server if mpv_websocket is detected. // Auto mode disables built-in server if mpv_websocket is detected.
// ========================================== // ==========================================
"websocket": { "websocket": {
"enabled": "auto", // Built-in subtitle websocket server mode. Values: auto | true | false "enabled": false, // Built-in subtitle websocket server mode. Values: auto | true | false
"port": 6677 // Built-in subtitle websocket server port. "port": 6677 // Built-in subtitle websocket server port.
}, // Built-in WebSocket server broadcasts subtitle text to connected clients. }, // Built-in WebSocket server broadcasts subtitle text to connected clients.
@@ -37,7 +37,7 @@
// Independent from websocket.auto and defaults to port 6678. // Independent from websocket.auto and defaults to port 6678.
// ========================================== // ==========================================
"annotationWebsocket": { "annotationWebsocket": {
"enabled": true, // Annotated subtitle websocket server enabled state. Values: true | false "enabled": false, // Annotated subtitle websocket server enabled state. Values: true | false
"port": 6678 // Annotated subtitle websocket server port. "port": 6678 // Annotated subtitle websocket server port.
}, // Dedicated annotated subtitle websocket for bundled texthooker and token-aware clients. }, // Dedicated annotated subtitle websocket for bundled texthooker and token-aware clients.
@@ -355,7 +355,7 @@
"hoverTokenBackgroundColor": "rgba(54, 58, 79, 0.84)", // CSS color used for hovered subtitle token background highlight in mpv. "hoverTokenBackgroundColor": "rgba(54, 58, 79, 0.84)", // CSS color used for hovered subtitle token background highlight in mpv.
"nameMatchEnabled": true, // Enable subtitle token coloring for matches from the SubMiner character dictionary. Values: true | false "nameMatchEnabled": true, // Enable subtitle token coloring for matches from the SubMiner character dictionary. Values: true | false
"nameMatchColor": "#f5bde6", // Hex color used when a subtitle token matches an entry from the SubMiner character dictionary. "nameMatchColor": "#f5bde6", // Hex color used when a subtitle token matches an entry from the SubMiner character dictionary.
"fontFamily": "M PLUS 1 Medium, Source Han Sans JP, Noto Sans CJK JP", // Font family setting. "fontFamily": "Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP", // Font family setting.
"fontSize": 35, // Font size setting. "fontSize": 35, // Font size setting.
"fontColor": "#cad3f5", // Font color setting. "fontColor": "#cad3f5", // Font color setting.
"fontWeight": "600", // Font weight setting. "fontWeight": "600", // Font weight setting.
@@ -364,9 +364,9 @@
"wordSpacing": 0, // Word spacing setting. "wordSpacing": 0, // Word spacing setting.
"fontKerning": "normal", // Font kerning setting. "fontKerning": "normal", // Font kerning setting.
"textRendering": "geometricPrecision", // Text rendering setting. "textRendering": "geometricPrecision", // Text rendering setting.
"textShadow": "0 3px 10px rgba(0,0,0,0.69)", // Text shadow setting. "textShadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)", // Text shadow setting.
"fontStyle": "normal", // Font style setting. "fontStyle": "normal", // Font style setting.
"backgroundColor": "rgb(30, 32, 48, 0.88)", // Background color setting. "backgroundColor": "transparent", // Background color setting.
"backdropFilter": "blur(6px)", // Backdrop filter setting. "backdropFilter": "blur(6px)", // Backdrop filter setting.
"nPlusOneColor": "#c6a0f6", // N plus one color setting. "nPlusOneColor": "#c6a0f6", // N plus one color setting.
"knownWordColor": "#a6da95", // Known word color setting. "knownWordColor": "#a6da95", // Known word color setting.
@@ -374,7 +374,7 @@
"N1": "#ed8796", // N1 setting. "N1": "#ed8796", // N1 setting.
"N2": "#f5a97f", // N2 setting. "N2": "#f5a97f", // N2 setting.
"N3": "#f9e2af", // N3 setting. "N3": "#f9e2af", // N3 setting.
"N4": "#a6e3a1", // N4 setting. "N4": "#8bd5ca", // N4 setting.
"N5": "#8aadf4" // N5 setting. "N5": "#8aadf4" // N5 setting.
}, // Jlpt colors setting. }, // Jlpt colors setting.
"frequencyDictionary": { "frequencyDictionary": {
@@ -401,8 +401,8 @@
"wordSpacing": 0, // Word spacing setting. "wordSpacing": 0, // Word spacing setting.
"fontKerning": "normal", // Font kerning setting. "fontKerning": "normal", // Font kerning setting.
"textRendering": "geometricPrecision", // Text rendering setting. "textRendering": "geometricPrecision", // Text rendering setting.
"textShadow": "0 2px 4px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.8), 0 0 16px rgba(0,0,0,0.55)", // Text shadow setting. "textShadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)", // Text shadow setting.
"backgroundColor": "rgba(20, 22, 34, 0.78)", // Background color setting. "backgroundColor": "transparent", // Background color setting.
"backdropFilter": "blur(6px)", // Backdrop filter setting. "backdropFilter": "blur(6px)", // Backdrop filter setting.
"fontWeight": "600", // Font weight setting. "fontWeight": "600", // Font weight setting.
"fontStyle": "normal" // Font style setting. "fontStyle": "normal" // Font style setting.
+17 -16
View File
@@ -205,23 +205,23 @@ The overlay includes a built-in WebSocket server that broadcasts subtitle text t
For endpoint details, payload examples, and client patterns, see [WebSocket / Texthooker API & Integration](/websocket-texthooker-api). For endpoint details, payload examples, and client patterns, see [WebSocket / Texthooker API & Integration](/websocket-texthooker-api).
By default, the server uses "auto" mode: it starts automatically unless [mpv_websocket](https://github.com/kuroahna/mpv_websocket) is detected at `~/.config/mpv/mpv_websocket`. If you have mpv_websocket installed, the built-in server is skipped to avoid conflicts. By default, the server is disabled. Set `enabled` to `true` to force it on, or `"auto"` to start it unless [mpv_websocket](https://github.com/kuroahna/mpv_websocket) is detected at `~/.config/mpv/mpv_websocket`.
See `config.example.jsonc` for detailed configuration options. See `config.example.jsonc` for detailed configuration options.
```json ```json
{ {
"websocket": { "websocket": {
"enabled": "auto", "enabled": false,
"port": 6677 "port": 6677
} }
} }
``` ```
| Option | Values | Description | | Option | Values | Description |
| --------- | ------------------------- | -------------------------------------------------------- | | --------- | ------------------------- | --------------------------------------------- |
| `enabled` | `true`, `false`, `"auto"` | `"auto"` (default) disables if mpv_websocket is detected | | `enabled` | `true`, `false`, `"auto"` | Built-in subtitle websocket mode (default: `false`) |
| `port` | number | WebSocket server port (default: 6677) | | `port` | number | WebSocket server port (default: 6677) |
### Annotation WebSocket ### Annotation WebSocket
@@ -232,7 +232,7 @@ This stream includes subtitle text plus token metadata (N+1, known-word, frequen
```json ```json
{ {
"annotationWebsocket": { "annotationWebsocket": {
"enabled": true, "enabled": false,
"port": 6678 "port": 6678
} }
} }
@@ -245,14 +245,14 @@ This stream includes subtitle text plus token metadata (N+1, known-word, frequen
### Texthooker ### Texthooker
Control whether the browser opens automatically when texthooker starts: Control whether texthooker starts automatically and whether it opens a browser:
See `config.example.jsonc` for detailed configuration options. See `config.example.jsonc` for detailed configuration options.
```json ```json
{ {
"texthooker": { "texthooker": {
"launchAtStartup": true, "launchAtStartup": false,
"openBrowser": false "openBrowser": false
} }
} }
@@ -260,7 +260,7 @@ See `config.example.jsonc` for detailed configuration options.
| Option | Values | Description | | Option | Values | Description |
| ----------------- | --------------- | ---------------------------------------------------------------------- | | ----------------- | --------------- | ---------------------------------------------------------------------- |
| `launchAtStartup` | `true`, `false` | Start texthooker automatically with SubMiner startup (default: `true`) | | `launchAtStartup` | `true`, `false` | Start texthooker automatically with SubMiner startup (default: `false`) |
| `openBrowser` | `true`, `false` | Open browser tab when texthooker starts (default: `false`) | | `openBrowser` | `true`, `false` | Open browser tab when texthooker starts (default: `false`) |
## Subtitle Display ## Subtitle Display
@@ -274,7 +274,7 @@ See `config.example.jsonc` for detailed configuration options.
```json ```json
{ {
"subtitleStyle": { "subtitleStyle": {
"fontFamily": "M PLUS 1 Medium, Source Han Sans JP, Noto Sans CJK JP", "fontFamily": "Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP",
"fontSize": 35, "fontSize": 35,
"fontColor": "#cad3f5", "fontColor": "#cad3f5",
"fontWeight": "600", "fontWeight": "600",
@@ -283,14 +283,15 @@ See `config.example.jsonc` for detailed configuration options.
"wordSpacing": 0, "wordSpacing": 0,
"fontKerning": "normal", "fontKerning": "normal",
"textRendering": "geometricPrecision", "textRendering": "geometricPrecision",
"textShadow": "0 3px 10px rgba(0,0,0,0.69)", "textShadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)",
"fontStyle": "normal", "fontStyle": "normal",
"backgroundColor": "rgb(30, 32, 48, 0.88)", "backgroundColor": "transparent",
"backdropFilter": "blur(6px)", "backdropFilter": "blur(6px)",
"secondary": { "secondary": {
"fontFamily": "Inter, Noto Sans, Helvetica Neue, sans-serif", "fontFamily": "Inter, Noto Sans, Helvetica Neue, sans-serif",
"fontSize": 24, "fontSize": 24,
"fontColor": "#cad3f5", "fontColor": "#cad3f5",
"textShadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)",
"backgroundColor": "transparent" "backgroundColor": "transparent"
} }
} }
@@ -299,12 +300,12 @@ See `config.example.jsonc` for detailed configuration options.
| Option | Values | Description | | Option | Values | Description |
| ---------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- | | ---------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
| `fontFamily` | string | CSS font-family value (default: `"M PLUS 1 Medium, Source Han Sans JP, Noto Sans CJK JP"`) | | `fontFamily` | string | CSS font-family value (default: `"Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP"`) |
| `fontSize` | number (px) | Font size in pixels (default: `35`) | | `fontSize` | number (px) | Font size in pixels (default: `35`) |
| `fontColor` | string | Any CSS color value (default: `"#cad3f5"`) | | `fontColor` | string | Any CSS color value (default: `"#cad3f5"`) |
| `fontWeight` | string | CSS font-weight, e.g. `"bold"`, `"normal"`, `"600"` (default: `"600"`) | | `fontWeight` | string | CSS font-weight, e.g. `"bold"`, `"normal"`, `"600"` (default: `"600"`) |
| `fontStyle` | string | `"normal"` or `"italic"` (default: `"normal"`) | | `fontStyle` | string | `"normal"` or `"italic"` (default: `"normal"`) |
| `backgroundColor` | string | Any CSS color, including `"transparent"` (default: `"rgb(30, 32, 48, 0.88)"`) | | `backgroundColor` | string | Any CSS color, including `"transparent"` (default: `"transparent"`) |
| `enableJlpt` | boolean | Enable JLPT level underline styling (`false` by default) | | `enableJlpt` | boolean | Enable JLPT level underline styling (`false` by default) |
| `preserveLineBreaks` | boolean | Preserve line breaks in visible overlay subtitle rendering (`false` by default). Enable to mirror mpv line layout. | | `preserveLineBreaks` | boolean | Preserve line breaks in visible overlay subtitle rendering (`false` by default). Enable to mirror mpv line layout. |
| `autoPauseVideoOnHover` | boolean | Pause playback while mouse hovers subtitle text, then resume on leave (`true` by default). | | `autoPauseVideoOnHover` | boolean | Pause playback while mouse hovers subtitle text, then resume on leave (`true` by default). |
@@ -343,7 +344,7 @@ Character-name highlighting is separate from N+1 and frequency highlighting:
- `nameMatchColor` sets the highlight color for those matched character names. - `nameMatchColor` sets the highlight color for those matched character names.
- Matches come from the bundled SubMiner character dictionary, including AniList-synced merged dictionaries when enabled. - Matches come from the bundled SubMiner character dictionary, including AniList-synced merged dictionaries when enabled.
Secondary subtitle defaults: `fontFamily: "Inter, Noto Sans, Helvetica Neue, sans-serif"`, `fontSize: 24`, `fontColor: "#cad3f5"`, `textShadow: "0 2px 4px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.8), 0 0 16px rgba(0,0,0,0.55)"`, `backgroundColor: "rgba(20, 22, 34, 0.78)"`, `fontWeight: "600"`. Any property not set in `secondary` falls back to the CSS defaults. Secondary subtitle defaults: `fontFamily: "Inter, Noto Sans, Helvetica Neue, sans-serif"`, `fontSize: 24`, `fontColor: "#cad3f5"`, `textShadow: "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)"`, `backgroundColor: "transparent"`, `fontWeight: "600"`. Any property not set in `secondary` falls back to the CSS defaults.
**See `config.example.jsonc`** for the complete list of subtitle style configuration options. **See `config.example.jsonc`** for the complete list of subtitle style configuration options.
+9 -9
View File
@@ -17,7 +17,7 @@
// Configure texthooker startup launch and browser opening behavior. // Configure texthooker startup launch and browser opening behavior.
// ========================================== // ==========================================
"texthooker": { "texthooker": {
"launchAtStartup": true, // Launch texthooker server automatically when SubMiner starts. Values: true | false "launchAtStartup": false, // Launch texthooker server automatically when SubMiner starts. Values: true | false
"openBrowser": false // Open browser setting. Values: true | false "openBrowser": false // Open browser setting. Values: true | false
}, // Configure texthooker startup launch and browser opening behavior. }, // Configure texthooker startup launch and browser opening behavior.
@@ -27,7 +27,7 @@
// Auto mode disables built-in server if mpv_websocket is detected. // Auto mode disables built-in server if mpv_websocket is detected.
// ========================================== // ==========================================
"websocket": { "websocket": {
"enabled": "auto", // Built-in subtitle websocket server mode. Values: auto | true | false "enabled": false, // Built-in subtitle websocket server mode. Values: auto | true | false
"port": 6677 // Built-in subtitle websocket server port. "port": 6677 // Built-in subtitle websocket server port.
}, // Built-in WebSocket server broadcasts subtitle text to connected clients. }, // Built-in WebSocket server broadcasts subtitle text to connected clients.
@@ -37,7 +37,7 @@
// Independent from websocket.auto and defaults to port 6678. // Independent from websocket.auto and defaults to port 6678.
// ========================================== // ==========================================
"annotationWebsocket": { "annotationWebsocket": {
"enabled": true, // Annotated subtitle websocket server enabled state. Values: true | false "enabled": false, // Annotated subtitle websocket server enabled state. Values: true | false
"port": 6678 // Annotated subtitle websocket server port. "port": 6678 // Annotated subtitle websocket server port.
}, // Dedicated annotated subtitle websocket for bundled texthooker and token-aware clients. }, // Dedicated annotated subtitle websocket for bundled texthooker and token-aware clients.
@@ -355,7 +355,7 @@
"hoverTokenBackgroundColor": "rgba(54, 58, 79, 0.84)", // CSS color used for hovered subtitle token background highlight in mpv. "hoverTokenBackgroundColor": "rgba(54, 58, 79, 0.84)", // CSS color used for hovered subtitle token background highlight in mpv.
"nameMatchEnabled": true, // Enable subtitle token coloring for matches from the SubMiner character dictionary. Values: true | false "nameMatchEnabled": true, // Enable subtitle token coloring for matches from the SubMiner character dictionary. Values: true | false
"nameMatchColor": "#f5bde6", // Hex color used when a subtitle token matches an entry from the SubMiner character dictionary. "nameMatchColor": "#f5bde6", // Hex color used when a subtitle token matches an entry from the SubMiner character dictionary.
"fontFamily": "M PLUS 1 Medium, Source Han Sans JP, Noto Sans CJK JP", // Font family setting. "fontFamily": "Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP", // Font family setting.
"fontSize": 35, // Font size setting. "fontSize": 35, // Font size setting.
"fontColor": "#cad3f5", // Font color setting. "fontColor": "#cad3f5", // Font color setting.
"fontWeight": "600", // Font weight setting. "fontWeight": "600", // Font weight setting.
@@ -364,9 +364,9 @@
"wordSpacing": 0, // Word spacing setting. "wordSpacing": 0, // Word spacing setting.
"fontKerning": "normal", // Font kerning setting. "fontKerning": "normal", // Font kerning setting.
"textRendering": "geometricPrecision", // Text rendering setting. "textRendering": "geometricPrecision", // Text rendering setting.
"textShadow": "0 3px 10px rgba(0,0,0,0.69)", // Text shadow setting. "textShadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)", // Text shadow setting.
"fontStyle": "normal", // Font style setting. "fontStyle": "normal", // Font style setting.
"backgroundColor": "rgb(30, 32, 48, 0.88)", // Background color setting. "backgroundColor": "transparent", // Background color setting.
"backdropFilter": "blur(6px)", // Backdrop filter setting. "backdropFilter": "blur(6px)", // Backdrop filter setting.
"nPlusOneColor": "#c6a0f6", // N plus one color setting. "nPlusOneColor": "#c6a0f6", // N plus one color setting.
"knownWordColor": "#a6da95", // Known word color setting. "knownWordColor": "#a6da95", // Known word color setting.
@@ -374,7 +374,7 @@
"N1": "#ed8796", // N1 setting. "N1": "#ed8796", // N1 setting.
"N2": "#f5a97f", // N2 setting. "N2": "#f5a97f", // N2 setting.
"N3": "#f9e2af", // N3 setting. "N3": "#f9e2af", // N3 setting.
"N4": "#a6e3a1", // N4 setting. "N4": "#8bd5ca", // N4 setting.
"N5": "#8aadf4" // N5 setting. "N5": "#8aadf4" // N5 setting.
}, // Jlpt colors setting. }, // Jlpt colors setting.
"frequencyDictionary": { "frequencyDictionary": {
@@ -401,8 +401,8 @@
"wordSpacing": 0, // Word spacing setting. "wordSpacing": 0, // Word spacing setting.
"fontKerning": "normal", // Font kerning setting. "fontKerning": "normal", // Font kerning setting.
"textRendering": "geometricPrecision", // Text rendering setting. "textRendering": "geometricPrecision", // Text rendering setting.
"textShadow": "0 2px 4px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.8), 0 0 16px rgba(0,0,0,0.55)", // Text shadow setting. "textShadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)", // Text shadow setting.
"backgroundColor": "rgba(20, 22, 34, 0.78)", // Background color setting. "backgroundColor": "transparent", // Background color setting.
"backdropFilter": "blur(6px)", // Backdrop filter setting. "backdropFilter": "blur(6px)", // Backdrop filter setting.
"fontWeight": "600", // Font weight setting. "fontWeight": "600", // Font weight setting.
"fontStyle": "normal" // Font style setting. "fontStyle": "normal" // Font style setting.
+18 -20
View File
@@ -13,6 +13,11 @@ import {
import { parseConfigContent } from './parse'; import { parseConfigContent } from './parse';
import { generateConfigTemplate } from './template'; import { generateConfigTemplate } from './template';
const DEFAULT_SUBTITLE_FONT_FAMILY =
'Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP';
const DEFAULT_SECONDARY_SUBTITLE_FONT_FAMILY = 'Inter, Noto Sans, Helvetica Neue, sans-serif';
const DEFAULT_SUBTITLE_TEXT_SHADOW = '0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)';
function makeTempDir(): string { function makeTempDir(): string {
return fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-config-test-')); return fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-config-test-'));
} }
@@ -21,10 +26,11 @@ test('loads defaults when config is missing', () => {
const dir = makeTempDir(); const dir = makeTempDir();
const service = new ConfigService(dir); const service = new ConfigService(dir);
const config = service.getConfig(); const config = service.getConfig();
assert.equal(config.websocket.enabled, false);
assert.equal(config.websocket.port, DEFAULT_CONFIG.websocket.port); assert.equal(config.websocket.port, DEFAULT_CONFIG.websocket.port);
assert.equal(config.annotationWebsocket.enabled, DEFAULT_CONFIG.annotationWebsocket.enabled); assert.equal(config.annotationWebsocket.enabled, false);
assert.equal(config.annotationWebsocket.port, DEFAULT_CONFIG.annotationWebsocket.port); assert.equal(config.annotationWebsocket.port, DEFAULT_CONFIG.annotationWebsocket.port);
assert.equal(config.texthooker.launchAtStartup, true); assert.equal(config.texthooker.launchAtStartup, false);
assert.equal(config.ankiConnect.behavior.autoUpdateNewCards, true); assert.equal(config.ankiConnect.behavior.autoUpdateNewCards, true);
assert.deepEqual(config.ankiConnect.tags, ['SubMiner']); assert.deepEqual(config.ankiConnect.tags, ['SubMiner']);
assert.equal(config.anilist.enabled, false); assert.equal(config.anilist.enabled, false);
@@ -61,7 +67,7 @@ test('loads defaults when config is missing', () => {
assert.equal(config.shortcuts.toggleSubtitleSidebar, 'Backslash'); assert.equal(config.shortcuts.toggleSubtitleSidebar, 'Backslash');
assert.equal(config.discordPresence.enabled, true); assert.equal(config.discordPresence.enabled, true);
assert.equal(config.discordPresence.updateIntervalMs, 3_000); assert.equal(config.discordPresence.updateIntervalMs, 3_000);
assert.equal(config.subtitleStyle.backgroundColor, 'rgb(30, 32, 48, 0.88)'); assert.equal(config.subtitleStyle.backgroundColor, 'transparent');
assert.equal(config.subtitleStyle.primaryDefaultMode, 'visible'); assert.equal(config.subtitleStyle.primaryDefaultMode, 'visible');
assert.equal(config.subtitleStyle.preserveLineBreaks, false); assert.equal(config.subtitleStyle.preserveLineBreaks, false);
assert.equal(config.subtitleStyle.autoPauseVideoOnHover, true); assert.equal(config.subtitleStyle.autoPauseVideoOnHover, true);
@@ -69,29 +75,21 @@ test('loads defaults when config is missing', () => {
assert.equal(config.subtitleSidebar.enabled, true); assert.equal(config.subtitleSidebar.enabled, true);
assert.equal(config.subtitleStyle.hoverTokenColor, '#f4dbd6'); assert.equal(config.subtitleStyle.hoverTokenColor, '#f4dbd6');
assert.equal(config.subtitleStyle.hoverTokenBackgroundColor, 'rgba(54, 58, 79, 0.84)'); assert.equal(config.subtitleStyle.hoverTokenBackgroundColor, 'rgba(54, 58, 79, 0.84)');
assert.equal( assert.equal(config.subtitleStyle.fontFamily, DEFAULT_SUBTITLE_FONT_FAMILY);
config.subtitleStyle.fontFamily,
'M PLUS 1 Medium, Source Han Sans JP, Noto Sans CJK JP',
);
assert.equal(config.subtitleStyle.fontWeight, '600'); assert.equal(config.subtitleStyle.fontWeight, '600');
assert.equal(config.subtitleStyle.lineHeight, 1.35); assert.equal(config.subtitleStyle.lineHeight, 1.35);
assert.equal(config.subtitleStyle.letterSpacing, '-0.01em'); assert.equal(config.subtitleStyle.letterSpacing, '-0.01em');
assert.equal(config.subtitleStyle.wordSpacing, 0); assert.equal(config.subtitleStyle.wordSpacing, 0);
assert.equal(config.subtitleStyle.fontKerning, 'normal'); assert.equal(config.subtitleStyle.fontKerning, 'normal');
assert.equal(config.subtitleStyle.textRendering, 'geometricPrecision'); assert.equal(config.subtitleStyle.textRendering, 'geometricPrecision');
assert.equal(config.subtitleStyle.textShadow, '0 3px 10px rgba(0,0,0,0.69)'); assert.equal(config.subtitleStyle.textShadow, DEFAULT_SUBTITLE_TEXT_SHADOW);
assert.equal(config.subtitleStyle.backdropFilter, 'blur(6px)'); assert.equal(config.subtitleStyle.backdropFilter, 'blur(6px)');
assert.equal( assert.equal(config.subtitleStyle.jlptColors.N4, '#8bd5ca');
config.subtitleStyle.secondary.fontFamily, assert.equal(config.subtitleStyle.secondary.fontFamily, DEFAULT_SECONDARY_SUBTITLE_FONT_FAMILY);
'Inter, Noto Sans, Helvetica Neue, sans-serif',
);
assert.equal(config.subtitleStyle.secondary.fontColor, '#cad3f5'); assert.equal(config.subtitleStyle.secondary.fontColor, '#cad3f5');
assert.equal(config.subtitleStyle.secondary.fontWeight, '600'); assert.equal(config.subtitleStyle.secondary.fontWeight, '600');
assert.equal( assert.equal(config.subtitleStyle.secondary.textShadow, DEFAULT_SUBTITLE_TEXT_SHADOW);
config.subtitleStyle.secondary.textShadow, assert.equal(config.subtitleStyle.secondary.backgroundColor, 'transparent');
'0 2px 4px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.8), 0 0 16px rgba(0,0,0,0.55)',
);
assert.equal(config.subtitleStyle.secondary.backgroundColor, 'rgba(20, 22, 34, 0.78)');
assert.equal(config.immersionTracking.enabled, true); assert.equal(config.immersionTracking.enabled, true);
assert.equal(config.immersionTracking.dbPath, ''); assert.equal(config.immersionTracking.dbPath, '');
assert.equal(config.immersionTracking.batchSize, 25); assert.equal(config.immersionTracking.batchSize, 25);
@@ -2142,11 +2140,11 @@ test('template generator includes known keys', () => {
); );
assert.match( assert.match(
output, output,
/"enabled": "auto",? \/\/ Built-in subtitle websocket server mode\. Values: auto \| true \| false/, /"enabled": false,? \/\/ Built-in subtitle websocket server mode\. Values: auto \| true \| false/,
); );
assert.match( assert.match(
output, output,
/"enabled": true,? \/\/ Annotated subtitle websocket server enabled state\. Values: true \| false/, /"enabled": false,? \/\/ Annotated subtitle websocket server enabled state\. Values: true \| false/,
); );
assert.match( assert.match(
output, output,
@@ -2221,7 +2219,7 @@ test('template generator includes known keys', () => {
assert.doesNotMatch(output, /"whisperThreads": 4/); assert.doesNotMatch(output, /"whisperThreads": 4/);
assert.match( assert.match(
output, output,
/"launchAtStartup": true,? \/\/ Launch texthooker server automatically when SubMiner starts\. Values: true \| false/, /"launchAtStartup": false,? \/\/ Launch texthooker server automatically when SubMiner starts\. Values: true \| false/,
); );
}); });
+3 -3
View File
@@ -19,18 +19,18 @@ export const CORE_DEFAULT_CONFIG: Pick<
subtitlePosition: { yPercent: 10 }, subtitlePosition: { yPercent: 10 },
keybindings: [], keybindings: [],
websocket: { websocket: {
enabled: 'auto', enabled: false,
port: 6677, port: 6677,
}, },
annotationWebsocket: { annotationWebsocket: {
enabled: true, enabled: false,
port: 6678, port: 6678,
}, },
logging: { logging: {
level: 'info', level: 'info',
}, },
texthooker: { texthooker: {
launchAtStartup: true, launchAtStartup: false,
openBrowser: false, openBrowser: false,
}, },
controller: { controller: {
+6 -6
View File
@@ -11,7 +11,7 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle' | 'su
hoverTokenBackgroundColor: 'rgba(54, 58, 79, 0.84)', hoverTokenBackgroundColor: 'rgba(54, 58, 79, 0.84)',
nameMatchEnabled: true, nameMatchEnabled: true,
nameMatchColor: '#f5bde6', nameMatchColor: '#f5bde6',
fontFamily: 'M PLUS 1 Medium, Source Han Sans JP, Noto Sans CJK JP', fontFamily: 'Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP',
fontSize: 35, fontSize: 35,
fontColor: '#cad3f5', fontColor: '#cad3f5',
fontWeight: '600', fontWeight: '600',
@@ -20,9 +20,9 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle' | 'su
wordSpacing: 0, wordSpacing: 0,
fontKerning: 'normal', fontKerning: 'normal',
textRendering: 'geometricPrecision', textRendering: 'geometricPrecision',
textShadow: '0 3px 10px rgba(0,0,0,0.69)', textShadow: '0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)',
fontStyle: 'normal', fontStyle: 'normal',
backgroundColor: 'rgb(30, 32, 48, 0.88)', backgroundColor: 'transparent',
backdropFilter: 'blur(6px)', backdropFilter: 'blur(6px)',
nPlusOneColor: '#c6a0f6', nPlusOneColor: '#c6a0f6',
knownWordColor: '#a6da95', knownWordColor: '#a6da95',
@@ -30,7 +30,7 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle' | 'su
N1: '#ed8796', N1: '#ed8796',
N2: '#f5a97f', N2: '#f5a97f',
N3: '#f9e2af', N3: '#f9e2af',
N4: '#a6e3a1', N4: '#8bd5ca',
N5: '#8aadf4', N5: '#8aadf4',
}, },
frequencyDictionary: { frequencyDictionary: {
@@ -51,8 +51,8 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle' | 'su
wordSpacing: 0, wordSpacing: 0,
fontKerning: 'normal', fontKerning: 'normal',
textRendering: 'geometricPrecision', textRendering: 'geometricPrecision',
textShadow: '0 2px 4px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.8), 0 0 16px rgba(0,0,0,0.55)', textShadow: '0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)',
backgroundColor: 'rgba(20, 22, 34, 0.78)', backgroundColor: 'transparent',
backdropFilter: 'blur(6px)', backdropFilter: 'blur(6px)',
fontWeight: '600', fontWeight: '600',
fontStyle: 'normal', fontStyle: 'normal',