diff --git a/docs/configuration.md b/docs/configuration.md index faaf219..2ebb69f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -100,6 +100,12 @@ Enable automatic Anki card creation and updates with media generation: "enabled": true, "url": "http://127.0.0.1:8765", "pollingRate": 3000, + "proxy": { + "enabled": false, + "host": "127.0.0.1", + "port": 8766, + "upstreamUrl": "http://127.0.0.1:8765" + }, "tags": ["SubMiner"], "deck": "Learning::Japanese", "fields": { @@ -163,7 +169,11 @@ This example is intentionally compact. The option table below documents availabl | --------------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | `true`, `false` | Enable AnkiConnect integration (default: `false`) | | `url` | string (URL) | AnkiConnect API URL (default: `http://127.0.0.1:8765`) | -| `pollingRate` | number (ms) | How often to check for new cards (default: `3000`) | +| `pollingRate` | number (ms) | How often to check for new cards in polling mode (default: `3000`; ignored for direct proxy `addNote`/`addNotes` updates) | +| `proxy.enabled` | `true`, `false` | Enable local AnkiConnect-compatible proxy for push-based auto-enrichment (default: `false`) | +| `proxy.host` | string | Bind host for local AnkiConnect proxy (default: `127.0.0.1`) | +| `proxy.port` | number | Bind port for local AnkiConnect proxy (default: `8766`) | +| `proxy.upstreamUrl` | string (URL) | Upstream AnkiConnect URL that proxy forwards to (default: `http://127.0.0.1:8765`) | | `tags` | array of strings | Tags automatically added to cards mined/updated by SubMiner (default: `['SubMiner']`; set `[]` to disable automatic tagging). | | `deck` | string | Anki deck to monitor for new cards | | `ankiConnect.nPlusOne.decks` | array of strings | Decks used for N+1 known-word cache lookups. When omitted/empty, falls back to `ankiConnect.deck`. | @@ -340,20 +350,6 @@ Control whether the overlay automatically becomes visible when it connects to mp The mpv plugin controls startup overlay visibility via `auto_start_visible_overlay` in `subminer.conf`. -### Visible Overlay Subtitle Binding - -Control whether toggling the visible overlay also toggles MPV subtitle visibility: - -```json -{ - "bind_visible_overlay_to_mpv_sub_visibility": true -} -``` - -| Option | Values | Description | -| -------------------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `bind_visible_overlay_to_mpv_sub_visibility` | `true`, `false` | When `true` (default), visible overlay hides MPV primary/secondary subtitles and restores them when hidden. When `false`, visible overlay toggles do not change MPV subtitle visibility. | - ### Auto Subtitle Sync Sync the active subtitle track using `alass` (preferred) or `ffsubsync`: diff --git a/src/config/config.test.ts b/src/config/config.test.ts index b756ee8..eef58e3 100644 --- a/src/config/config.test.ts +++ b/src/config/config.test.ts @@ -650,7 +650,7 @@ test('warns and ignores unknown top-level config keys', () => { assert.ok(warnings.some((warning) => warning.path === 'unknownFeatureFlag')); }); -test('parses global shortcuts and startup visibility flags', () => { +test('parses global shortcuts and startup settings', () => { const dir = makeTempDir(); fs.writeFileSync( path.join(dir, 'config.jsonc'), @@ -659,7 +659,6 @@ test('parses global shortcuts and startup visibility flags', () => { "toggleVisibleOverlayGlobal": "Alt+Shift+U", "openJimaku": "Ctrl+Alt+J" }, - "bind_visible_overlay_to_mpv_sub_visibility": false, "youtubeSubgen": { "primarySubLanguages": ["ja", "jpn", "jp"] } @@ -671,7 +670,6 @@ test('parses global shortcuts and startup visibility flags', () => { const config = service.getConfig(); assert.equal(config.shortcuts.toggleVisibleOverlayGlobal, 'Alt+Shift+U'); assert.equal(config.shortcuts.openJimaku, 'Ctrl+Alt+J'); - assert.equal(config.bind_visible_overlay_to_mpv_sub_visibility, false); assert.deepEqual(config.youtubeSubgen.primarySubLanguages, ['ja', 'jpn', 'jp']); }); diff --git a/src/config/definitions.ts b/src/config/definitions.ts index 3827dcb..09f05d5 100644 --- a/src/config/definitions.ts +++ b/src/config/definitions.ts @@ -28,7 +28,6 @@ const { secondarySub, subsync, auto_start_overlay, - bind_visible_overlay_to_mpv_sub_visibility, } = CORE_DEFAULT_CONFIG; const { ankiConnect, jimaku, anilist, jellyfin, discordPresence, youtubeSubgen } = INTEGRATIONS_DEFAULT_CONFIG; @@ -47,7 +46,6 @@ export const DEFAULT_CONFIG: ResolvedConfig = { subsync, subtitleStyle, auto_start_overlay, - bind_visible_overlay_to_mpv_sub_visibility, jimaku, anilist, jellyfin, diff --git a/src/config/definitions/defaults-core.ts b/src/config/definitions/defaults-core.ts index 3703443..c79dc22 100644 --- a/src/config/definitions/defaults-core.ts +++ b/src/config/definitions/defaults-core.ts @@ -11,7 +11,6 @@ export const CORE_DEFAULT_CONFIG: Pick< | 'secondarySub' | 'subsync' | 'auto_start_overlay' - | 'bind_visible_overlay_to_mpv_sub_visibility' > = { subtitlePosition: { yPercent: 10 }, keybindings: [], @@ -52,5 +51,4 @@ export const CORE_DEFAULT_CONFIG: Pick< ffmpeg_path: '', }, auto_start_overlay: false, - bind_visible_overlay_to_mpv_sub_visibility: true, }; diff --git a/src/config/definitions/options-core.ts b/src/config/definitions/options-core.ts index ce97521..4a611a3 100644 --- a/src/config/definitions/options-core.ts +++ b/src/config/definitions/options-core.ts @@ -38,12 +38,5 @@ export function buildCoreConfigOptionRegistry( defaultValue: defaultConfig.shortcuts.multiCopyTimeoutMs, description: 'Timeout for multi-copy/mine modes.', }, - { - path: 'bind_visible_overlay_to_mpv_sub_visibility', - kind: 'boolean', - defaultValue: defaultConfig.bind_visible_overlay_to_mpv_sub_visibility, - description: - 'Link visible overlay toggles to MPV primary subtitle visibility.', - }, ]; } diff --git a/src/config/definitions/template-sections.ts b/src/config/definitions/template-sections.ts index 20d387f..9e69e24 100644 --- a/src/config/definitions/template-sections.ts +++ b/src/config/definitions/template-sections.ts @@ -8,14 +8,6 @@ const CORE_TEMPLATE_SECTIONS: ConfigTemplateSection[] = [ ], key: 'auto_start_overlay', }, - { - title: 'Visible Overlay Subtitle Binding', - description: [ - 'Control whether visible overlay toggles also toggle MPV subtitle visibility.', - 'When enabled, visible overlay hides MPV subtitles; when disabled, MPV subtitles are left unchanged.', - ], - key: 'bind_visible_overlay_to_mpv_sub_visibility', - }, { title: 'Texthooker Server', description: ['Control whether browser opens automatically for texthooker.'], diff --git a/src/config/resolve/top-level.ts b/src/config/resolve/top-level.ts index 1f8f87f..3380581 100644 --- a/src/config/resolve/top-level.ts +++ b/src/config/resolve/top-level.ts @@ -13,16 +13,4 @@ export function applyTopLevelConfig(context: ResolveContext): void { if (asBoolean(src.auto_start_overlay) !== undefined) { resolved.auto_start_overlay = src.auto_start_overlay as boolean; } - - if (asBoolean(src.bind_visible_overlay_to_mpv_sub_visibility) !== undefined) { - resolved.bind_visible_overlay_to_mpv_sub_visibility = - src.bind_visible_overlay_to_mpv_sub_visibility as boolean; - } else if (src.bind_visible_overlay_to_mpv_sub_visibility !== undefined) { - warn( - 'bind_visible_overlay_to_mpv_sub_visibility', - src.bind_visible_overlay_to_mpv_sub_visibility, - resolved.bind_visible_overlay_to_mpv_sub_visibility, - 'Expected boolean.', - ); - } } diff --git a/src/core/services/index.ts b/src/core/services/index.ts index 46a3194..6050406 100644 --- a/src/core/services/index.ts +++ b/src/core/services/index.ts @@ -25,10 +25,10 @@ export { cycleSecondarySubMode } from './subtitle-position'; export { isAutoUpdateEnabledRuntime, shouldAutoInitializeOverlayRuntimeFromConfig, - shouldBindVisibleOverlayToMpvSubVisibility, } from './startup'; export { openYomitanSettingsWindow } from './yomitan-settings'; export { createTokenizerDepsRuntime, tokenizeSubtitle } from './tokenizer'; +export { syncYomitanDefaultAnkiServer } from './tokenizer/yomitan-parser-runtime'; export { createSubtitleProcessingController } from './subtitle-processing-controller'; export { createFrequencyDictionaryLookup } from './frequency-dictionary'; export { createJlptVocabularyLookup } from './jlpt-vocab'; diff --git a/src/core/services/mpv-protocol.test.ts b/src/core/services/mpv-protocol.test.ts index 135dcdf..f72f170 100644 --- a/src/core/services/mpv-protocol.test.ts +++ b/src/core/services/mpv-protocol.test.ts @@ -121,7 +121,6 @@ test('dispatchMpvProtocolMessage emits subtitle text on property change', async test('dispatchMpvProtocolMessage enforces sub-visibility hidden when overlay suppression is enabled', async () => { const { deps, state } = createDeps({ - shouldBindVisibleOverlayToMpvSubVisibility: () => true, isVisibleOverlayVisible: () => true, }); @@ -130,15 +129,22 @@ test('dispatchMpvProtocolMessage enforces sub-visibility hidden when overlay sup deps, ); - assert.deepEqual(state.commands.pop(), { - command: ['set_property', 'sub-visibility', 'no'], - }); + assert.deepEqual(state.commands, [ + { + command: ['set_property', 'sub-visibility', false], + }, + { + command: ['set_property', 'sub-visibility', 'no'], + }, + { + command: ['set', 'sub-visibility', 'no'], + }, + ]); }); -test('dispatchMpvProtocolMessage skips sub-visibility suppression when overlay binding is disabled', async () => { +test('dispatchMpvProtocolMessage skips sub-visibility suppression when overlay is hidden', async () => { const { deps, state } = createDeps({ - shouldBindVisibleOverlayToMpvSubVisibility: () => false, - isVisibleOverlayVisible: () => true, + isVisibleOverlayVisible: () => false, }); await dispatchMpvProtocolMessage( diff --git a/src/core/services/mpv-protocol.ts b/src/core/services/mpv-protocol.ts index ab7f6f6..b91a094 100644 --- a/src/core/services/mpv-protocol.ts +++ b/src/core/services/mpv-protocol.ts @@ -48,7 +48,6 @@ export interface MpvProtocolHandleMessageDeps { }; getSubtitleMetrics: () => MpvSubtitleRenderMetrics; isVisibleOverlayVisible: () => boolean; - shouldBindVisibleOverlayToMpvSubVisibility?: () => boolean; emitSubtitleChange: (payload: { text: string; isOverlayVisible: boolean }) => void; emitSubtitleAssChange: (payload: { text: string }) => void; emitSubtitleTiming: (payload: { text: string; start: number; end: number }) => void; @@ -218,12 +217,10 @@ export async function dispatchMpvProtocolMessage( subScaleByWindow: asBoolean(msg.data, deps.getSubtitleMetrics().subScaleByWindow), }); } else if (msg.name === 'sub-visibility') { - if ( - deps.isVisibleOverlayVisible() && - asBoolean(msg.data, false) && - (deps.shouldBindVisibleOverlayToMpvSubVisibility?.() ?? true) - ) { + if (deps.isVisibleOverlayVisible() && asBoolean(msg.data, false)) { + deps.sendCommand({ command: ['set_property', 'sub-visibility', false] }); deps.sendCommand({ command: ['set_property', 'sub-visibility', 'no'] }); + deps.sendCommand({ command: ['set', 'sub-visibility', 'no'] }); } } else if (msg.name === 'sub-use-margins') { deps.emitSubtitleMetricsChange({ diff --git a/src/core/services/mpv.test.ts b/src/core/services/mpv.test.ts index 5c8b95e..153a8a4 100644 --- a/src/core/services/mpv.test.ts +++ b/src/core/services/mpv.test.ts @@ -13,7 +13,6 @@ function makeDeps(overrides: Partial = {}): MpvIpcClie getResolvedConfig: () => ({}) as any, autoStartOverlay: false, setOverlayVisible: () => {}, - shouldBindVisibleOverlayToMpvSubVisibility: () => false, isVisibleOverlayVisible: () => false, getReconnectTimer: () => null, setReconnectTimer: () => {}, @@ -311,7 +310,6 @@ test('MpvIpcClient connect does not force primary subtitle visibility from bindi const client = new MpvIpcClient( '/tmp/mpv.sock', makeDeps({ - shouldBindVisibleOverlayToMpvSubVisibility: () => true, isVisibleOverlayVisible: () => true, }), ); @@ -332,6 +330,29 @@ test('MpvIpcClient connect does not force primary subtitle visibility from bindi assert.equal(hasPrimaryVisibilityMutation, false); }); +test('MpvIpcClient setSubVisibility writes compatibility commands for visibility toggle', () => { + const commands: unknown[] = []; + const client = new MpvIpcClient('/tmp/mpv.sock', makeDeps()); + (client as any).send = (payload: unknown) => { + commands.push(payload); + return true; + }; + + client.setSubVisibility(false); + + assert.deepEqual(commands, [ + { + command: ['set_property', 'sub-visibility', false], + }, + { + command: ['set_property', 'sub-visibility', 'no'], + }, + { + command: ['set', 'sub-visibility', 'no'], + }, + ]); +}); + test('MpvIpcClient captures and disables secondary subtitle visibility on request', async () => { const commands: unknown[] = []; const client = new MpvIpcClient('/tmp/mpv.sock', makeDeps()); diff --git a/src/core/services/mpv.ts b/src/core/services/mpv.ts index 516cbc7..5bab9a8 100644 --- a/src/core/services/mpv.ts +++ b/src/core/services/mpv.ts @@ -99,7 +99,6 @@ export interface MpvIpcClientProtocolDeps { getResolvedConfig: () => Config; autoStartOverlay: boolean; setOverlayVisible: (visible: boolean) => void; - shouldBindVisibleOverlayToMpvSubVisibility: () => boolean; isVisibleOverlayVisible: () => boolean; getReconnectTimer: () => ReturnType | null; setReconnectTimer: (timer: ReturnType | null) => void; @@ -297,8 +296,6 @@ export class MpvIpcClient implements MpvClient { getResolvedConfig: () => this.deps.getResolvedConfig(), getSubtitleMetrics: () => this.mpvSubtitleRenderMetrics, isVisibleOverlayVisible: () => this.deps.isVisibleOverlayVisible(), - shouldBindVisibleOverlayToMpvSubVisibility: () => - this.deps.shouldBindVisibleOverlayToMpvSubVisibility(), emitSubtitleChange: (payload) => { this.emit('subtitle-change', payload); }, @@ -474,6 +471,9 @@ export class MpvIpcClient implements MpvClient { setSubVisibility(visible: boolean): void { const value = visible ? 'yes' : 'no'; + this.send({ + command: ['set_property', 'sub-visibility', visible], + }); this.send({ command: ['set_property', 'sub-visibility', value], }); diff --git a/src/core/services/runtime-config.test.ts b/src/core/services/runtime-config.test.ts index 88d007d..cd98f04 100644 --- a/src/core/services/runtime-config.test.ts +++ b/src/core/services/runtime-config.test.ts @@ -3,12 +3,10 @@ import assert from 'node:assert/strict'; import { isAutoUpdateEnabledRuntime, shouldAutoInitializeOverlayRuntimeFromConfig, - shouldBindVisibleOverlayToMpvSubVisibility, } from './startup'; const BASE_CONFIG = { auto_start_overlay: false, - bind_visible_overlay_to_mpv_sub_visibility: true, ankiConnect: { behavior: { autoUpdateNewCards: true, @@ -27,17 +25,6 @@ test('shouldAutoInitializeOverlayRuntimeFromConfig respects auto start', () => { ); }); -test('shouldBindVisibleOverlayToMpvSubVisibility returns config value', () => { - assert.equal(shouldBindVisibleOverlayToMpvSubVisibility(BASE_CONFIG), true); - assert.equal( - shouldBindVisibleOverlayToMpvSubVisibility({ - ...BASE_CONFIG, - bind_visible_overlay_to_mpv_sub_visibility: false, - }), - false, - ); -}); - test('isAutoUpdateEnabledRuntime prefers runtime option and falls back to config', () => { assert.equal( isAutoUpdateEnabledRuntime(BASE_CONFIG, { diff --git a/src/core/services/startup.ts b/src/core/services/startup.ts index ebc9835..29eb249 100644 --- a/src/core/services/startup.ts +++ b/src/core/services/startup.ts @@ -18,7 +18,6 @@ interface RuntimeAutoUpdateOptionManagerLike { export interface RuntimeConfigLike { auto_start_overlay?: boolean; - bind_visible_overlay_to_mpv_sub_visibility: boolean; ankiConnect?: { behavior?: { autoUpdateNewCards?: boolean; @@ -156,10 +155,6 @@ export function shouldAutoInitializeOverlayRuntimeFromConfig(config: RuntimeConf return config.auto_start_overlay === true; } -export function shouldBindVisibleOverlayToMpvSubVisibility(config: RuntimeConfigLike): boolean { - return config.bind_visible_overlay_to_mpv_sub_visibility; -} - export function isAutoUpdateEnabledRuntime( config: ResolvedConfig | RuntimeConfigLike, runtimeOptionsManager: RuntimeAutoUpdateOptionManagerLike | null, diff --git a/src/main.ts b/src/main.ts index 6cdc734..211b130 100644 --- a/src/main.ts +++ b/src/main.ts @@ -106,6 +106,7 @@ import type { CliArgs, CliCommandSource } from './cli/args'; import { printHelp } from './cli/help'; import { buildConfigParseErrorDetails, + buildConfigWarningDialogDetails, buildConfigWarningNotificationBody, failStartupFromConfig, } from './main/config-validation'; @@ -353,6 +354,7 @@ import { resolveJellyfinPlaybackPlanRuntime, runStartupBootstrapRuntime, saveSubtitlePosition as saveSubtitlePositionCore, + syncYomitanDefaultAnkiServer as syncYomitanDefaultAnkiServerCore, sendMpvCommandRuntime, setMpvSubVisibilityRuntime, setOverlayDebugVisualizationEnabledRuntime, @@ -758,10 +760,7 @@ const restoreOverlayMpvSubtitles = createRestoreOverlayMpvSubtitlesHandler({ }); function shouldSuppressMpvSubtitlesForOverlay(): boolean { - return ( - overlayManager.getVisibleOverlayVisible() && - configDerivedRuntime.shouldBindVisibleOverlayToMpvSubVisibility() - ); + return overlayManager.getVisibleOverlayVisible(); } function syncOverlayMpvSubtitleSuppression(): void { @@ -961,6 +960,12 @@ const buildConfigHotReloadRuntimeMainDepsHandler = createBuildConfigHotReloadRun showDesktopNotification('SubMiner', { body: buildConfigWarningNotificationBody(configPath, warnings), }); + if (process.platform === 'darwin') { + dialog.showErrorBox( + 'SubMiner config validation warning', + buildConfigWarningDialogDetails(configPath, warnings), + ); + } }, }, ); @@ -1931,6 +1936,10 @@ const { reloadConfig: reloadConfigHandler, appReadyRuntimeRunner } = composeAppR logInfo: (message) => appLogger.logInfo(message), logWarning: (message) => appLogger.logWarning(message), showDesktopNotification: (title, options) => showDesktopNotification(title, options), + showConfigWarningsDialog: + process.platform === 'darwin' + ? (title, details) => dialog.showErrorBox(title, details) + : undefined, startConfigHotReload: () => configHotReloadRuntime.start(), refreshAnilistClientSecretState: (options) => refreshAnilistClientSecretState(options), failHandlers: { @@ -2203,8 +2212,6 @@ const { getResolvedConfig: () => getResolvedConfig(), isAutoStartOverlayEnabled: () => appState.autoStartOverlay, setOverlayVisible: (visible: boolean) => setOverlayVisible(visible), - shouldBindVisibleOverlayToMpvSubVisibility: () => - configDerivedRuntime.shouldBindVisibleOverlayToMpvSubVisibility(), isVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(), getReconnectTimer: () => appState.reconnectTimer, setReconnectTimer: (timer: ReturnType | null) => { @@ -2372,11 +2379,70 @@ const enforceOverlayLayerOrder = createEnforceOverlayLayerOrderHandler( ); async function loadYomitanExtension(): Promise { - return yomitanExtensionRuntime.loadYomitanExtension(); + const extension = await yomitanExtensionRuntime.loadYomitanExtension(); + if (extension) { + await syncYomitanDefaultProfileAnkiServer(); + } + return extension; } async function ensureYomitanExtensionLoaded(): Promise { - return yomitanExtensionRuntime.ensureYomitanExtensionLoaded(); + const extension = await yomitanExtensionRuntime.ensureYomitanExtensionLoaded(); + if (extension) { + await syncYomitanDefaultProfileAnkiServer(); + } + return extension; +} + +let lastSyncedYomitanAnkiServer: string | null = null; + +function getPreferredYomitanAnkiServerUrl(): string { + const config = getResolvedConfig().ankiConnect; + if (config.proxy?.enabled) { + const host = config.proxy.host || '127.0.0.1'; + const port = config.proxy.port || 8766; + return `http://${host}:${port}`; + } + return config.url; +} + +async function syncYomitanDefaultProfileAnkiServer(): Promise { + const targetUrl = getPreferredYomitanAnkiServerUrl().trim(); + if (!targetUrl || targetUrl === lastSyncedYomitanAnkiServer) { + return; + } + + const updated = await syncYomitanDefaultAnkiServerCore( + targetUrl, + { + getYomitanExt: () => appState.yomitanExt, + getYomitanParserWindow: () => appState.yomitanParserWindow, + setYomitanParserWindow: (window) => { + appState.yomitanParserWindow = window; + }, + getYomitanParserReadyPromise: () => appState.yomitanParserReadyPromise, + setYomitanParserReadyPromise: (promise) => { + appState.yomitanParserReadyPromise = promise; + }, + getYomitanParserInitPromise: () => appState.yomitanParserInitPromise, + setYomitanParserInitPromise: (promise) => { + appState.yomitanParserInitPromise = promise; + }, + }, + { + error: (message, ...args) => { + logger.error(message, ...args); + }, + info: (message, ...args) => { + logger.info(message, ...args); + }, + }, + ); + + if (updated) { + logger.info(`Yomitan default profile Anki server set to ${targetUrl}`); + } + lastSyncedYomitanAnkiServer = targetUrl; } function createOverlayWindow(kind: 'visible' | 'modal'): BrowserWindow { @@ -2999,20 +3065,32 @@ function ensureOverlayWindowsReadyForVisibilityActions(): void { function setVisibleOverlayVisible(visible: boolean): void { ensureOverlayWindowsReadyForVisibilityActions(); + if (visible) { + void ensureOverlayMpvSubtitlesHidden(); + } setVisibleOverlayVisibleHandler(visible); syncOverlayMpvSubtitleSuppression(); } function toggleVisibleOverlay(): void { ensureOverlayWindowsReadyForVisibilityActions(); + if (!overlayManager.getVisibleOverlayVisible()) { + void ensureOverlayMpvSubtitlesHidden(); + } toggleVisibleOverlayHandler(); syncOverlayMpvSubtitleSuppression(); } function setOverlayVisible(visible: boolean): void { + if (visible) { + void ensureOverlayMpvSubtitlesHidden(); + } setOverlayVisibleHandler(visible); syncOverlayMpvSubtitleSuppression(); } function toggleOverlay(): void { + if (!overlayManager.getVisibleOverlayVisible()) { + void ensureOverlayMpvSubtitlesHidden(); + } toggleOverlayHandler(); syncOverlayMpvSubtitleSuppression(); } diff --git a/src/main/runtime/composers/mpv-runtime-composer.test.ts b/src/main/runtime/composers/mpv-runtime-composer.test.ts index 0043a4b..9cf3d59 100644 --- a/src/main/runtime/composers/mpv-runtime-composer.test.ts +++ b/src/main/runtime/composers/mpv-runtime-composer.test.ts @@ -92,7 +92,6 @@ test('composeMpvRuntimeHandlers returns callable handlers and forwards to inject getResolvedConfig: () => ({ auto_start_overlay: false }), isAutoStartOverlayEnabled: () => true, setOverlayVisible: () => {}, - shouldBindVisibleOverlayToMpvSubVisibility: () => true, isVisibleOverlayVisible: () => false, getReconnectTimer: () => null, setReconnectTimer: () => {}, diff --git a/src/main/runtime/config-derived.ts b/src/main/runtime/config-derived.ts index ac97855..638e72f 100644 --- a/src/main/runtime/config-derived.ts +++ b/src/main/runtime/config-derived.ts @@ -7,7 +7,6 @@ import { jimakuFetchJson as jimakuFetchJsonCore, resolveJimakuApiKey as resolveJimakuApiKeyCore, shouldAutoInitializeOverlayRuntimeFromConfig as shouldAutoInitializeOverlayRuntimeFromConfigCore, - shouldBindVisibleOverlayToMpvSubVisibility as shouldBindVisibleOverlayToMpvSubVisibilityCore, } from '../../core/services'; export type ConfigDerivedRuntimeDeps = { @@ -20,7 +19,6 @@ export type ConfigDerivedRuntimeDeps = { export function createConfigDerivedRuntime(deps: ConfigDerivedRuntimeDeps): { shouldAutoInitializeOverlayRuntimeFromConfig: () => boolean; - shouldBindVisibleOverlayToMpvSubVisibility: () => boolean; isAutoUpdateEnabledRuntime: () => boolean; getJimakuLanguagePreference: () => JimakuLanguagePreference; getJimakuMaxEntryResults: () => number; @@ -33,8 +31,6 @@ export function createConfigDerivedRuntime(deps: ConfigDerivedRuntimeDeps): { return { shouldAutoInitializeOverlayRuntimeFromConfig: () => shouldAutoInitializeOverlayRuntimeFromConfigCore(deps.getResolvedConfig()), - shouldBindVisibleOverlayToMpvSubVisibility: () => - shouldBindVisibleOverlayToMpvSubVisibilityCore(deps.getResolvedConfig()), isAutoUpdateEnabledRuntime: () => isAutoUpdateEnabledRuntimeCore(deps.getResolvedConfig(), deps.getRuntimeOptionsManager()), getJimakuLanguagePreference: () => diff --git a/src/main/runtime/mpv-client-runtime-service-main-deps.test.ts b/src/main/runtime/mpv-client-runtime-service-main-deps.test.ts index 351dd8f..95aa2fe 100644 --- a/src/main/runtime/mpv-client-runtime-service-main-deps.test.ts +++ b/src/main/runtime/mpv-client-runtime-service-main-deps.test.ts @@ -16,7 +16,6 @@ test('mpv runtime service main deps builder maps state and callbacks', () => { getResolvedConfig: () => ({ mode: 'test' }), isAutoStartOverlayEnabled: () => true, setOverlayVisible: (visible) => calls.push(`overlay:${visible}`), - shouldBindVisibleOverlayToMpvSubVisibility: () => true, isVisibleOverlayVisible: () => false, getReconnectTimer: () => reconnectTimer, setReconnectTimer: (timer) => { @@ -29,7 +28,6 @@ test('mpv runtime service main deps builder maps state and callbacks', () => { const deps = build(); assert.equal(deps.socketPath, '/tmp/mpv.sock'); assert.equal(deps.options.autoStartOverlay, true); - assert.equal(deps.options.shouldBindVisibleOverlayToMpvSubVisibility(), true); assert.equal(deps.options.isVisibleOverlayVisible(), false); assert.deepEqual(deps.options.getResolvedConfig(), { mode: 'test' }); diff --git a/src/main/runtime/mpv-client-runtime-service-main-deps.ts b/src/main/runtime/mpv-client-runtime-service-main-deps.ts index f9831f7..d11ad7b 100644 --- a/src/main/runtime/mpv-client-runtime-service-main-deps.ts +++ b/src/main/runtime/mpv-client-runtime-service-main-deps.ts @@ -8,7 +8,6 @@ export function createBuildMpvClientRuntimeServiceFactoryDepsHandler< getResolvedConfig: () => TResolvedConfig; isAutoStartOverlayEnabled: () => boolean; setOverlayVisible: (visible: boolean) => void; - shouldBindVisibleOverlayToMpvSubVisibility: () => boolean; isVisibleOverlayVisible: () => boolean; getReconnectTimer: () => ReturnType | null; setReconnectTimer: (timer: ReturnType | null) => void; @@ -21,8 +20,6 @@ export function createBuildMpvClientRuntimeServiceFactoryDepsHandler< getResolvedConfig: () => deps.getResolvedConfig(), autoStartOverlay: deps.isAutoStartOverlayEnabled(), setOverlayVisible: (visible: boolean) => deps.setOverlayVisible(visible), - shouldBindVisibleOverlayToMpvSubVisibility: () => - deps.shouldBindVisibleOverlayToMpvSubVisibility(), isVisibleOverlayVisible: () => deps.isVisibleOverlayVisible(), getReconnectTimer: () => deps.getReconnectTimer(), setReconnectTimer: (timer: ReturnType | null) => deps.setReconnectTimer(timer), diff --git a/src/main/runtime/mpv-client-runtime-service.test.ts b/src/main/runtime/mpv-client-runtime-service.test.ts index 643338d..8449299 100644 --- a/src/main/runtime/mpv-client-runtime-service.test.ts +++ b/src/main/runtime/mpv-client-runtime-service.test.ts @@ -23,7 +23,6 @@ test('mpv runtime service factory constructs client, binds handlers, and connect getResolvedConfig: () => ({}), autoStartOverlay: true, setOverlayVisible: () => {}, - shouldBindVisibleOverlayToMpvSubVisibility: () => false, isVisibleOverlayVisible: () => false, getReconnectTimer: () => null, setReconnectTimer: () => {}, diff --git a/src/main/runtime/mpv-client-runtime-service.ts b/src/main/runtime/mpv-client-runtime-service.ts index 3f6056f..325d665 100644 --- a/src/main/runtime/mpv-client-runtime-service.ts +++ b/src/main/runtime/mpv-client-runtime-service.ts @@ -4,7 +4,6 @@ export type MpvClientRuntimeServiceOptions = { getResolvedConfig: () => Config; autoStartOverlay: boolean; setOverlayVisible: (visible: boolean) => void; - shouldBindVisibleOverlayToMpvSubVisibility: () => boolean; isVisibleOverlayVisible: () => boolean; getReconnectTimer: () => ReturnType | null; setReconnectTimer: (timer: ReturnType | null) => void; diff --git a/src/types.ts b/src/types.ts index eb08b60..516f576 100644 --- a/src/types.ts +++ b/src/types.ts @@ -192,6 +192,12 @@ export interface AnkiConnectConfig { enabled?: boolean; url?: string; pollingRate?: number; + proxy?: { + enabled?: boolean; + host?: string; + port?: number; + upstreamUrl?: string; + }; tags?: string[]; fields?: { audio?: string; @@ -413,7 +419,6 @@ export interface Config { subsync?: SubsyncConfig; subtitleStyle?: SubtitleStyleConfig; auto_start_overlay?: boolean; - bind_visible_overlay_to_mpv_sub_visibility?: boolean; jimaku?: JimakuConfig; anilist?: AnilistConfig; jellyfin?: JellyfinConfig; @@ -436,6 +441,12 @@ export interface ResolvedConfig { enabled: boolean; url: string; pollingRate: number; + proxy: { + enabled: boolean; + host: string; + port: number; + upstreamUrl: string; + }; tags: string[]; fields: { audio: string; @@ -514,7 +525,6 @@ export interface ResolvedConfig { }; }; auto_start_overlay: boolean; - bind_visible_overlay_to_mpv_sub_visibility: boolean; jimaku: JimakuConfig & { apiBaseUrl: string; languagePreference: JimakuLanguagePreference;