refactor: extract mpv ipc dependency builder service

This commit is contained in:
2026-02-10 00:09:06 -08:00
parent 8b286f15e8
commit 6ca07abbc2
4 changed files with 158 additions and 14 deletions

View File

@@ -0,0 +1,51 @@
import test from "node:test";
import assert from "node:assert/strict";
import { createMpvIpcClientDepsRuntimeService } from "./mpv-client-deps-runtime-service";
test("createMpvIpcClientDepsRuntimeService returns passthrough dep object", async () => {
const marker = {
getResolvedConfig: () => ({ auto_start_overlay: false } as never),
autoStartOverlay: true,
setOverlayVisible: () => {},
shouldBindVisibleOverlayToMpvSubVisibility: () => true,
isVisibleOverlayVisible: () => false,
getReconnectTimer: () => null,
setReconnectTimer: () => {},
getCurrentSubText: () => "x",
setCurrentSubText: () => {},
setCurrentSubAssText: () => {},
getSubtitleTimingTracker: () => null,
subtitleWsBroadcast: () => {},
getOverlayWindowsCount: () => 0,
tokenizeSubtitle: async () => ({ text: "x", tokens: [], mergedTokens: [] }),
broadcastToOverlayWindows: () => {},
updateCurrentMediaPath: () => {},
updateMpvSubtitleRenderMetrics: () => {},
getMpvSubtitleRenderMetrics: () => ({
subPos: 100,
subFontSize: 40,
subScale: 1,
subMarginY: 0,
subMarginX: 0,
subFont: "sans",
subSpacing: 0,
subBold: false,
subItalic: false,
subBorderSize: 0,
subShadowOffset: 0,
subAssOverride: "yes",
subScaleByWindow: true,
subUseMargins: true,
osdHeight: 720,
osdDimensions: null,
}),
setPreviousSecondarySubVisibility: () => {},
showMpvOsd: () => {},
};
const deps = createMpvIpcClientDepsRuntimeService(marker);
assert.equal(deps.autoStartOverlay, true);
assert.equal(deps.getCurrentSubText(), "x");
assert.equal(deps.getOverlayWindowsCount(), 0);
assert.equal(deps.shouldBindVisibleOverlayToMpvSubVisibility(), true);
});

View File

@@ -0,0 +1,61 @@
import {
MpvIpcClientDeps,
} from "./mpv-service";
import { Config, MpvSubtitleRenderMetrics, SubtitleData } from "../../types";
interface SubtitleTimingTrackerLike {
recordSubtitle: (text: string, start: number, end: number) => void;
}
export interface MpvClientDepsRuntimeOptions {
getResolvedConfig: () => Config;
autoStartOverlay: boolean;
setOverlayVisible: (visible: boolean) => void;
shouldBindVisibleOverlayToMpvSubVisibility: () => boolean;
isVisibleOverlayVisible: () => boolean;
getReconnectTimer: () => ReturnType<typeof setTimeout> | null;
setReconnectTimer: (timer: ReturnType<typeof setTimeout> | null) => void;
getCurrentSubText: () => string;
setCurrentSubText: (text: string) => void;
setCurrentSubAssText: (text: string) => void;
getSubtitleTimingTracker: () => SubtitleTimingTrackerLike | null;
subtitleWsBroadcast: (text: string) => void;
getOverlayWindowsCount: () => number;
tokenizeSubtitle: (text: string) => Promise<SubtitleData>;
broadcastToOverlayWindows: (channel: string, ...args: unknown[]) => void;
updateCurrentMediaPath: (mediaPath: unknown) => void;
updateMpvSubtitleRenderMetrics: (
patch: Partial<MpvSubtitleRenderMetrics>,
) => void;
getMpvSubtitleRenderMetrics: () => MpvSubtitleRenderMetrics;
setPreviousSecondarySubVisibility: (value: boolean | null) => void;
showMpvOsd: (text: string) => void;
}
export function createMpvIpcClientDepsRuntimeService(
options: MpvClientDepsRuntimeOptions,
): MpvIpcClientDeps {
return {
getResolvedConfig: options.getResolvedConfig,
autoStartOverlay: options.autoStartOverlay,
setOverlayVisible: options.setOverlayVisible,
shouldBindVisibleOverlayToMpvSubVisibility:
options.shouldBindVisibleOverlayToMpvSubVisibility,
isVisibleOverlayVisible: options.isVisibleOverlayVisible,
getReconnectTimer: options.getReconnectTimer,
setReconnectTimer: options.setReconnectTimer,
getCurrentSubText: options.getCurrentSubText,
setCurrentSubText: options.setCurrentSubText,
setCurrentSubAssText: options.setCurrentSubAssText,
getSubtitleTimingTracker: options.getSubtitleTimingTracker,
subtitleWsBroadcast: options.subtitleWsBroadcast,
getOverlayWindowsCount: options.getOverlayWindowsCount,
tokenizeSubtitle: options.tokenizeSubtitle,
broadcastToOverlayWindows: options.broadcastToOverlayWindows,
updateCurrentMediaPath: options.updateCurrentMediaPath,
updateMpvSubtitleRenderMetrics: options.updateMpvSubtitleRenderMetrics,
getMpvSubtitleRenderMetrics: options.getMpvSubtitleRenderMetrics,
setPreviousSecondarySubVisibility: options.setPreviousSecondarySubVisibility,
showMpvOsd: options.showMpvOsd,
};
}

View File

@@ -203,6 +203,7 @@ import {
} from "./core/services/overlay-broadcast-runtime-service";
import { runAppReadyRuntimeService } from "./core/services/app-ready-runtime-service";
import { runAppShutdownRuntimeService } from "./core/services/app-shutdown-runtime-service";
import { createMpvIpcClientDepsRuntimeService } from "./core/services/mpv-client-deps-runtime-service";
import {
runSubsyncManualFromIpcRuntimeService,
triggerSubsyncFromConfigRuntimeService,
@@ -495,19 +496,50 @@ if (initialArgs.generateConfig && !shouldStartApp(initialArgs)) {
keybindings = resolveKeybindings(getResolvedConfig(), DEFAULT_KEYBINDINGS);
},
createMpvClient: () => {
mpvClient = new MpvIpcClient(mpvSocketPath, {
getResolvedConfig: () => getResolvedConfig(), autoStartOverlay,
setOverlayVisible: (visible) => setOverlayVisible(visible),
shouldBindVisibleOverlayToMpvSubVisibility: () => shouldBindVisibleOverlayToMpvSubVisibility(),
isVisibleOverlayVisible: () => visibleOverlayVisible,
getReconnectTimer: () => reconnectTimer, setReconnectTimer: (timer) => { reconnectTimer = timer; },
getCurrentSubText: () => currentSubText, setCurrentSubText: (text) => { currentSubText = text; }, setCurrentSubAssText: (text) => { currentSubAssText = text; },
getSubtitleTimingTracker: () => subtitleTimingTracker, subtitleWsBroadcast: (text) => { subtitleWsService.broadcast(text); },
getOverlayWindowsCount: () => getOverlayWindows().length, tokenizeSubtitle: (text) => tokenizeSubtitle(text),
broadcastToOverlayWindows: (channel, ...args) => { broadcastToOverlayWindows(channel, ...args); },
updateCurrentMediaPath: (mediaPath) => { updateCurrentMediaPath(mediaPath); }, updateMpvSubtitleRenderMetrics: (patch) => { updateMpvSubtitleRenderMetrics(patch); },
getMpvSubtitleRenderMetrics: () => mpvSubtitleRenderMetrics, setPreviousSecondarySubVisibility: (value) => { previousSecondarySubVisibility = value; }, showMpvOsd: (text) => { showMpvOsd(text); },
});
mpvClient = new MpvIpcClient(
mpvSocketPath,
createMpvIpcClientDepsRuntimeService({
getResolvedConfig: () => getResolvedConfig(),
autoStartOverlay,
setOverlayVisible: (visible) => setOverlayVisible(visible),
shouldBindVisibleOverlayToMpvSubVisibility: () =>
shouldBindVisibleOverlayToMpvSubVisibility(),
isVisibleOverlayVisible: () => visibleOverlayVisible,
getReconnectTimer: () => reconnectTimer,
setReconnectTimer: (timer) => {
reconnectTimer = timer;
},
getCurrentSubText: () => currentSubText,
setCurrentSubText: (text) => {
currentSubText = text;
},
setCurrentSubAssText: (text) => {
currentSubAssText = text;
},
getSubtitleTimingTracker: () => subtitleTimingTracker,
subtitleWsBroadcast: (text) => {
subtitleWsService.broadcast(text);
},
getOverlayWindowsCount: () => getOverlayWindows().length,
tokenizeSubtitle: (text) => tokenizeSubtitle(text),
broadcastToOverlayWindows: (channel, ...args) => {
broadcastToOverlayWindows(channel, ...args);
},
updateCurrentMediaPath: (mediaPath) => {
updateCurrentMediaPath(mediaPath);
},
updateMpvSubtitleRenderMetrics: (patch) => {
updateMpvSubtitleRenderMetrics(patch);
},
getMpvSubtitleRenderMetrics: () => mpvSubtitleRenderMetrics,
setPreviousSecondarySubVisibility: (value) => {
previousSecondarySubVisibility = value;
},
showMpvOsd: (text) => {
showMpvOsd(text);
},
}),
);
},
reloadConfig: () => {
configService.reloadConfig();