refactor: remove invisible subtitle overlay code

This commit is contained in:
2026-02-26 16:40:46 -08:00
parent 643f8eb958
commit 74554a30f0
119 changed files with 691 additions and 2946 deletions

View File

@@ -27,7 +27,8 @@ test('loads defaults when config is missing', () => {
assert.equal(config.discordPresence.updateIntervalMs, 3_000);
assert.equal(config.subtitleStyle.backgroundColor, 'rgb(30, 32, 48, 0.88)');
assert.equal(config.subtitleStyle.preserveLineBreaks, false);
assert.equal(config.subtitleStyle.hoverTokenColor, '#c6a0f6');
assert.equal(config.subtitleStyle.hoverTokenColor, '#f4dbd6');
assert.equal(config.subtitleStyle.hoverTokenBackgroundColor, '#363a4fd6');
assert.equal(config.immersionTracking.enabled, true);
assert.equal(config.immersionTracking.dbPath, '');
assert.equal(config.immersionTracking.batchSize, 25);
@@ -136,6 +137,44 @@ test('parses subtitleStyle.hoverTokenColor and warns on invalid values', () => {
);
});
test('parses subtitleStyle.hoverTokenBackgroundColor and warns on invalid values', () => {
const validDir = makeTempDir();
fs.writeFileSync(
path.join(validDir, 'config.jsonc'),
`{
"subtitleStyle": {
"hoverTokenBackgroundColor": "#363a4fd6"
}
}`,
'utf-8',
);
const validService = new ConfigService(validDir);
assert.equal(validService.getConfig().subtitleStyle.hoverTokenBackgroundColor, '#363a4fd6');
const invalidDir = makeTempDir();
fs.writeFileSync(
path.join(invalidDir, 'config.jsonc'),
`{
"subtitleStyle": {
"hoverTokenBackgroundColor": true
}
}`,
'utf-8',
);
const invalidService = new ConfigService(invalidDir);
assert.equal(
invalidService.getConfig().subtitleStyle.hoverTokenBackgroundColor,
DEFAULT_CONFIG.subtitleStyle.hoverTokenBackgroundColor,
);
assert.ok(
invalidService
.getWarnings()
.some((warning) => warning.path === 'subtitleStyle.hoverTokenBackgroundColor'),
);
});
test('parses anilist.enabled and warns for invalid value', () => {
const dir = makeTempDir();
fs.writeFileSync(
@@ -597,19 +636,15 @@ test('warns and ignores unknown top-level config keys', () => {
assert.ok(warnings.some((warning) => warning.path === 'unknownFeatureFlag'));
});
test('parses invisible overlay config and new global shortcuts', () => {
test('parses global shortcuts and startup visibility flags', () => {
const dir = makeTempDir();
fs.writeFileSync(
path.join(dir, 'config.jsonc'),
`{
"shortcuts": {
"toggleVisibleOverlayGlobal": "Alt+Shift+U",
"toggleInvisibleOverlayGlobal": "Alt+Shift+I",
"openJimaku": "Ctrl+Alt+J"
},
"invisibleOverlay": {
"startupVisibility": "hidden"
},
"bind_visible_overlay_to_mpv_sub_visibility": false,
"youtubeSubgen": {
"primarySubLanguages": ["ja", "jpn", "jp"]
@@ -621,9 +656,7 @@ test('parses invisible overlay config and new global shortcuts', () => {
const service = new ConfigService(dir);
const config = service.getConfig();
assert.equal(config.shortcuts.toggleVisibleOverlayGlobal, 'Alt+Shift+U');
assert.equal(config.shortcuts.toggleInvisibleOverlayGlobal, 'Alt+Shift+I');
assert.equal(config.shortcuts.openJimaku, 'Ctrl+Alt+J');
assert.equal(config.invisibleOverlay.startupVisibility, 'hidden');
assert.equal(config.bind_visible_overlay_to_mpv_sub_visibility, false);
assert.deepEqual(config.youtubeSubgen.primarySubLanguages, ['ja', 'jpn', 'jp']);
});

View File

@@ -29,7 +29,6 @@ const {
subsync,
auto_start_overlay,
bind_visible_overlay_to_mpv_sub_visibility,
invisibleOverlay,
} = CORE_DEFAULT_CONFIG;
const { ankiConnect, jimaku, anilist, jellyfin, discordPresence, youtubeSubgen } =
INTEGRATIONS_DEFAULT_CONFIG;
@@ -54,7 +53,6 @@ export const DEFAULT_CONFIG: ResolvedConfig = {
jellyfin,
discordPresence,
youtubeSubgen,
invisibleOverlay,
immersionTracking,
};

View File

@@ -12,7 +12,6 @@ export const CORE_DEFAULT_CONFIG: Pick<
| 'subsync'
| 'auto_start_overlay'
| 'bind_visible_overlay_to_mpv_sub_visibility'
| 'invisibleOverlay'
> = {
subtitlePosition: { yPercent: 10 },
keybindings: [],
@@ -28,7 +27,6 @@ export const CORE_DEFAULT_CONFIG: Pick<
},
shortcuts: {
toggleVisibleOverlayGlobal: 'Alt+Shift+O',
toggleInvisibleOverlayGlobal: 'Alt+Shift+I',
copySubtitle: 'CommandOrControl+C',
copySubtitleMultiple: 'CommandOrControl+Shift+C',
updateLastCardFromClipboard: 'CommandOrControl+V',
@@ -55,7 +53,4 @@ export const CORE_DEFAULT_CONFIG: Pick<
},
auto_start_overlay: false,
bind_visible_overlay_to_mpv_sub_visibility: true,
invisibleOverlay: {
startupVisibility: 'platform-default',
},
};

View File

@@ -4,7 +4,8 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle'> = {
subtitleStyle: {
enableJlpt: false,
preserveLineBreaks: false,
hoverTokenColor: '#c6a0f6',
hoverTokenColor: '#f4dbd6',
hoverTokenBackgroundColor: '#363a4fd6',
fontFamily:
'M PLUS 1, Noto Sans CJK JP Regular, Noto Sans CJK JP, Hiragino Sans, Hiragino Kaku Gothic ProN, Yu Gothic, Arial Unicode MS, Arial, sans-serif',
fontSize: 35,

View File

@@ -27,6 +27,12 @@ export function buildSubtitleConfigOptionRegistry(
defaultValue: defaultConfig.subtitleStyle.hoverTokenColor,
description: 'Hex color used for hovered subtitle token highlight in mpv.',
},
{
path: 'subtitleStyle.hoverTokenBackgroundColor',
kind: 'string',
defaultValue: defaultConfig.subtitleStyle.hoverTokenBackgroundColor,
description: 'CSS color used for hovered subtitle token background highlight in mpv.',
},
{
path: 'subtitleStyle.frequencyDictionary.enabled',
kind: 'boolean',

View File

@@ -40,15 +40,6 @@ const CORE_TEMPLATE_SECTIONS: ConfigTemplateSection[] = [
notes: ['Hot-reload: shortcut changes apply live and update the session help modal on reopen.'],
key: 'shortcuts',
},
{
title: 'Invisible Overlay',
description: ['Startup behavior for the invisible interactive subtitle mining layer.'],
notes: [
'Invisible subtitle position edit mode: Ctrl/Cmd+Shift+P to toggle, arrow keys to move, Enter or Ctrl/Cmd+S to save, Esc to cancel.',
'This edit-mode shortcut is fixed and is not currently configurable.',
],
key: 'invisibleOverlay',
},
{
title: 'Keybindings (MPV Commands)',
description: [

View File

@@ -100,6 +100,8 @@ export function applySubtitleDomainConfig(context: ResolveContext): void {
const fallbackSubtitleStyleEnableJlpt = resolved.subtitleStyle.enableJlpt;
const fallbackSubtitleStylePreserveLineBreaks = resolved.subtitleStyle.preserveLineBreaks;
const fallbackSubtitleStyleHoverTokenColor = resolved.subtitleStyle.hoverTokenColor;
const fallbackSubtitleStyleHoverTokenBackgroundColor =
resolved.subtitleStyle.hoverTokenBackgroundColor;
resolved.subtitleStyle = {
...resolved.subtitleStyle,
...(src.subtitleStyle as ResolvedConfig['subtitleStyle']),
@@ -154,6 +156,24 @@ export function applySubtitleDomainConfig(context: ResolveContext): void {
);
}
const hoverTokenBackgroundColor = asString(
(src.subtitleStyle as { hoverTokenBackgroundColor?: unknown }).hoverTokenBackgroundColor,
);
if (hoverTokenBackgroundColor !== undefined) {
resolved.subtitleStyle.hoverTokenBackgroundColor = hoverTokenBackgroundColor;
} else if (
(src.subtitleStyle as { hoverTokenBackgroundColor?: unknown }).hoverTokenBackgroundColor !==
undefined
) {
resolved.subtitleStyle.hoverTokenBackgroundColor = fallbackSubtitleStyleHoverTokenBackgroundColor;
warn(
'subtitleStyle.hoverTokenBackgroundColor',
(src.subtitleStyle as { hoverTokenBackgroundColor?: unknown }).hoverTokenBackgroundColor,
resolved.subtitleStyle.hoverTokenBackgroundColor,
'Expected string.',
);
}
const frequencyDictionary = isObject(
(src.subtitleStyle as { frequencyDictionary?: unknown }).frequencyDictionary,
)