refactor: extract mpv runtime command and osd helpers

This commit is contained in:
2026-02-09 23:15:15 -08:00
parent 9c4a9769a5
commit 688eedbfc0
4 changed files with 138 additions and 21 deletions

View File

@@ -0,0 +1,69 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
playNextSubtitleRuntimeService,
replayCurrentSubtitleRuntimeService,
sendMpvCommandRuntimeService,
setMpvSubVisibilityRuntimeService,
showMpvOsdRuntimeService,
} from "./mpv-runtime-service";
test("showMpvOsdRuntimeService sends show-text when connected", () => {
const commands: (string | number)[][] = [];
showMpvOsdRuntimeService(
{
connected: true,
send: ({ command }) => {
commands.push(command);
},
},
"hello",
);
assert.deepEqual(commands, [["show-text", "hello", "3000"]]);
});
test("showMpvOsdRuntimeService logs fallback when disconnected", () => {
const logs: string[] = [];
showMpvOsdRuntimeService(
{
connected: false,
send: () => {},
},
"hello",
(line) => {
logs.push(line);
},
);
assert.deepEqual(logs, ["OSD (MPV not connected): hello"]);
});
test("mpv runtime command wrappers call expected client methods", () => {
const calls: string[] = [];
const client = {
connected: true,
send: ({ command }: { command: (string | number)[] }) => {
calls.push(`send:${command.join(",")}`);
},
replayCurrentSubtitle: () => {
calls.push("replay");
},
playNextSubtitle: () => {
calls.push("next");
},
setSubVisibility: (visible: boolean) => {
calls.push(`subVisible:${visible}`);
},
};
replayCurrentSubtitleRuntimeService(client);
playNextSubtitleRuntimeService(client);
sendMpvCommandRuntimeService(client, ["script-message", "x"]);
setMpvSubVisibilityRuntimeService(client, false);
assert.deepEqual(calls, [
"replay",
"next",
"send:script-message,x",
"subVisible:false",
]);
});

View File

@@ -0,0 +1,49 @@
export interface MpvRuntimeClientLike {
connected: boolean;
send: (payload: { command: (string | number)[] }) => void;
replayCurrentSubtitle?: () => void;
playNextSubtitle?: () => void;
setSubVisibility?: (visible: boolean) => void;
}
export function showMpvOsdRuntimeService(
mpvClient: MpvRuntimeClientLike | null,
text: string,
fallbackLog: (text: string) => void = console.log,
): void {
if (mpvClient && mpvClient.connected) {
mpvClient.send({ command: ["show-text", text, "3000"] });
return;
}
fallbackLog(`OSD (MPV not connected): ${text}`);
}
export function replayCurrentSubtitleRuntimeService(
mpvClient: MpvRuntimeClientLike | null,
): void {
if (!mpvClient?.replayCurrentSubtitle) return;
mpvClient.replayCurrentSubtitle();
}
export function playNextSubtitleRuntimeService(
mpvClient: MpvRuntimeClientLike | null,
): void {
if (!mpvClient?.playNextSubtitle) return;
mpvClient.playNextSubtitle();
}
export function sendMpvCommandRuntimeService(
mpvClient: MpvRuntimeClientLike | null,
command: (string | number)[],
): void {
if (!mpvClient) return;
mpvClient.send({ command });
}
export function setMpvSubVisibilityRuntimeService(
mpvClient: MpvRuntimeClientLike | null,
visible: boolean,
): void {
if (!mpvClient?.setSubVisibility) return;
mpvClient.setSubVisibility(visible);
}

View File

@@ -132,6 +132,13 @@ import {
updateLastCardFromClipboardService,
} from "./core/services/mining-runtime-service";
import { startAppLifecycleService } from "./core/services/app-lifecycle-service";
import {
playNextSubtitleRuntimeService,
replayCurrentSubtitleRuntimeService,
sendMpvCommandRuntimeService,
setMpvSubVisibilityRuntimeService,
showMpvOsdRuntimeService,
} from "./core/services/mpv-runtime-service";
import { showDesktopNotification } from "./core/utils/notification";
import { openYomitanSettingsWindow } from "./core/services/yomitan-settings-service";
import { tokenizeSubtitleService } from "./core/services/tokenizer-service";
@@ -851,13 +858,13 @@ function cycleSecondarySubMode(): void {
}
function showMpvOsd(text: string): void {
if (mpvClient && mpvClient.connected && mpvClient.send) {
mpvClient.send({
command: ["show-text", text, "3000"],
});
} else {
console.log("OSD (MPV not connected):", text);
}
showMpvOsdRuntimeService(
mpvClient,
text,
(line) => {
console.log(line);
},
);
}
const multiCopySession = createNumericShortcutSessionService({
@@ -1095,9 +1102,7 @@ function setVisibleOverlayVisible(visible: boolean): void {
shouldBindVisibleOverlayToMpvSubVisibility(),
isMpvConnected: () => Boolean(mpvClient && mpvClient.connected),
setMpvSubVisibility: (mpvSubVisible) => {
if (mpvClient) {
mpvClient.setSubVisibility(mpvSubVisible);
}
setMpvSubVisibilityRuntimeService(mpvClient, mpvSubVisible);
},
});
}
@@ -1134,16 +1139,10 @@ function handleMpvCommandFromIpc(command: (string | number)[]): void {
);
},
showMpvOsd: (text) => showMpvOsd(text),
mpvReplaySubtitle: () => {
if (mpvClient) mpvClient.replayCurrentSubtitle();
},
mpvPlayNextSubtitle: () => {
if (mpvClient) mpvClient.playNextSubtitle();
},
mpvSendCommand: (rawCommand) => {
if (!mpvClient) return;
mpvClient.send({ command: rawCommand });
},
mpvReplaySubtitle: () => replayCurrentSubtitleRuntimeService(mpvClient),
mpvPlayNextSubtitle: () => playNextSubtitleRuntimeService(mpvClient),
mpvSendCommand: (rawCommand) =>
sendMpvCommandRuntimeService(mpvClient, rawCommand),
isMpvConnected: () => Boolean(mpvClient && mpvClient.connected),
hasRuntimeOptionsManager: () => runtimeOptionsManager !== null,
});