mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-28 06:22:45 -08:00
refactor state and overlay runtime helpers
This commit is contained in:
167
src/core/services/mpv-properties.ts
Normal file
167
src/core/services/mpv-properties.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import {
|
||||
MPV_REQUEST_ID_AID,
|
||||
MPV_REQUEST_ID_OSD_DIMENSIONS,
|
||||
MPV_REQUEST_ID_OSD_HEIGHT,
|
||||
MPV_REQUEST_ID_PATH,
|
||||
MPV_REQUEST_ID_SECONDARY_SUBTEXT,
|
||||
MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY,
|
||||
MPV_REQUEST_ID_SUB_ASS_OVERRIDE,
|
||||
MPV_REQUEST_ID_SUB_BOLD,
|
||||
MPV_REQUEST_ID_SUB_BORDER_SIZE,
|
||||
MPV_REQUEST_ID_SUB_FONT,
|
||||
MPV_REQUEST_ID_SUB_FONT_SIZE,
|
||||
MPV_REQUEST_ID_SUB_ITALIC,
|
||||
MPV_REQUEST_ID_SUB_MARGIN_X,
|
||||
MPV_REQUEST_ID_SUB_MARGIN_Y,
|
||||
MPV_REQUEST_ID_SUB_POS,
|
||||
MPV_REQUEST_ID_SUB_SCALE,
|
||||
MPV_REQUEST_ID_SUB_SCALE_BY_WINDOW,
|
||||
MPV_REQUEST_ID_SUB_SHADOW_OFFSET,
|
||||
MPV_REQUEST_ID_SUB_SPACING,
|
||||
MPV_REQUEST_ID_SUBTEXT,
|
||||
MPV_REQUEST_ID_SUBTEXT_ASS,
|
||||
MPV_REQUEST_ID_SUB_USE_MARGINS,
|
||||
} from "./mpv-protocol";
|
||||
|
||||
type MpvProtocolCommand = {
|
||||
command: unknown[];
|
||||
request_id?: number;
|
||||
};
|
||||
|
||||
export interface MpvSendCommand {
|
||||
(command: MpvProtocolCommand): boolean;
|
||||
}
|
||||
|
||||
const MPV_SUBTITLE_PROPERTY_OBSERVATIONS: string[] = [
|
||||
"sub-text",
|
||||
"path",
|
||||
"sub-start",
|
||||
"sub-end",
|
||||
"time-pos",
|
||||
"secondary-sub-text",
|
||||
"aid",
|
||||
"sub-pos",
|
||||
"sub-font-size",
|
||||
"sub-scale",
|
||||
"sub-margin-y",
|
||||
"sub-margin-x",
|
||||
"sub-font",
|
||||
"sub-spacing",
|
||||
"sub-bold",
|
||||
"sub-italic",
|
||||
"sub-scale-by-window",
|
||||
"osd-height",
|
||||
"osd-dimensions",
|
||||
"sub-text-ass",
|
||||
"sub-border-size",
|
||||
"sub-shadow-offset",
|
||||
"sub-ass-override",
|
||||
"sub-use-margins",
|
||||
"media-title",
|
||||
];
|
||||
|
||||
const MPV_INITIAL_PROPERTY_REQUESTS: Array<MpvProtocolCommand> = [
|
||||
{
|
||||
command: ["get_property", "sub-text"],
|
||||
request_id: MPV_REQUEST_ID_SUBTEXT,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-text-ass"],
|
||||
request_id: MPV_REQUEST_ID_SUBTEXT_ASS,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "path"],
|
||||
request_id: MPV_REQUEST_ID_PATH,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "media-title"],
|
||||
},
|
||||
{
|
||||
command: ["get_property", "secondary-sub-text"],
|
||||
request_id: MPV_REQUEST_ID_SECONDARY_SUBTEXT,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "secondary-sub-visibility"],
|
||||
request_id: MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "aid"],
|
||||
request_id: MPV_REQUEST_ID_AID,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-pos"],
|
||||
request_id: MPV_REQUEST_ID_SUB_POS,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-font-size"],
|
||||
request_id: MPV_REQUEST_ID_SUB_FONT_SIZE,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-scale"],
|
||||
request_id: MPV_REQUEST_ID_SUB_SCALE,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-margin-y"],
|
||||
request_id: MPV_REQUEST_ID_SUB_MARGIN_Y,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-margin-x"],
|
||||
request_id: MPV_REQUEST_ID_SUB_MARGIN_X,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-font"],
|
||||
request_id: MPV_REQUEST_ID_SUB_FONT,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-spacing"],
|
||||
request_id: MPV_REQUEST_ID_SUB_SPACING,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-bold"],
|
||||
request_id: MPV_REQUEST_ID_SUB_BOLD,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-italic"],
|
||||
request_id: MPV_REQUEST_ID_SUB_ITALIC,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-scale-by-window"],
|
||||
request_id: MPV_REQUEST_ID_SUB_SCALE_BY_WINDOW,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "osd-height"],
|
||||
request_id: MPV_REQUEST_ID_OSD_HEIGHT,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "osd-dimensions"],
|
||||
request_id: MPV_REQUEST_ID_OSD_DIMENSIONS,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-border-size"],
|
||||
request_id: MPV_REQUEST_ID_SUB_BORDER_SIZE,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-shadow-offset"],
|
||||
request_id: MPV_REQUEST_ID_SUB_SHADOW_OFFSET,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-ass-override"],
|
||||
request_id: MPV_REQUEST_ID_SUB_ASS_OVERRIDE,
|
||||
},
|
||||
{
|
||||
command: ["get_property", "sub-use-margins"],
|
||||
request_id: MPV_REQUEST_ID_SUB_USE_MARGINS,
|
||||
},
|
||||
];
|
||||
|
||||
export function subscribeToMpvProperties(send: MpvSendCommand): void {
|
||||
MPV_SUBTITLE_PROPERTY_OBSERVATIONS.forEach((property, index) => {
|
||||
send({ command: ["observe_property", index + 1, property] });
|
||||
});
|
||||
}
|
||||
|
||||
export function requestMpvInitialState(send: MpvSendCommand): void {
|
||||
MPV_INITIAL_PROPERTY_REQUESTS.forEach((payload) => {
|
||||
send(payload);
|
||||
});
|
||||
}
|
||||
168
src/core/services/mpv-protocol.test.ts
Normal file
168
src/core/services/mpv-protocol.test.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import type { MpvSubtitleRenderMetrics } from "../../types";
|
||||
import {
|
||||
dispatchMpvProtocolMessage,
|
||||
MPV_REQUEST_ID_TRACK_LIST_SECONDARY,
|
||||
MpvProtocolHandleMessageDeps,
|
||||
splitMpvMessagesFromBuffer,
|
||||
parseVisibilityProperty,
|
||||
asBoolean,
|
||||
} from "./mpv-protocol";
|
||||
|
||||
function createDeps(overrides: Partial<MpvProtocolHandleMessageDeps> = {}): {
|
||||
deps: MpvProtocolHandleMessageDeps;
|
||||
state: {
|
||||
subText: string;
|
||||
secondarySubText: string;
|
||||
events: Array<unknown>;
|
||||
commands: unknown[];
|
||||
mediaPath: string;
|
||||
restored: number;
|
||||
};
|
||||
} {
|
||||
const state = {
|
||||
subText: "",
|
||||
secondarySubText: "",
|
||||
events: [] as Array<unknown>,
|
||||
commands: [] as unknown[],
|
||||
mediaPath: "",
|
||||
restored: 0,
|
||||
};
|
||||
const metrics: MpvSubtitleRenderMetrics = {
|
||||
subPos: 100,
|
||||
subFontSize: 36,
|
||||
subScale: 1,
|
||||
subMarginY: 0,
|
||||
subMarginX: 0,
|
||||
subFont: "",
|
||||
subSpacing: 0,
|
||||
subBold: false,
|
||||
subItalic: false,
|
||||
subBorderSize: 0,
|
||||
subShadowOffset: 0,
|
||||
subAssOverride: "yes",
|
||||
subScaleByWindow: true,
|
||||
subUseMargins: true,
|
||||
osdHeight: 0,
|
||||
osdDimensions: null,
|
||||
};
|
||||
|
||||
return {
|
||||
state,
|
||||
deps: {
|
||||
getResolvedConfig: () => ({ secondarySub: { secondarySubLanguages: ["ja"] } }),
|
||||
getSubtitleMetrics: () => metrics,
|
||||
isVisibleOverlayVisible: () => false,
|
||||
emitSubtitleChange: (payload) => state.events.push(payload),
|
||||
emitSubtitleAssChange: (payload) => state.events.push(payload),
|
||||
emitSubtitleTiming: (payload) => state.events.push(payload),
|
||||
emitSecondarySubtitleChange: (payload) => state.events.push(payload),
|
||||
getCurrentSubText: () => state.subText,
|
||||
setCurrentSubText: (text) => {
|
||||
state.subText = text;
|
||||
},
|
||||
setCurrentSubStart: () => {},
|
||||
getCurrentSubStart: () => 0,
|
||||
setCurrentSubEnd: () => {},
|
||||
getCurrentSubEnd: () => 0,
|
||||
emitMediaPathChange: (payload) => {
|
||||
state.mediaPath = payload.path;
|
||||
},
|
||||
emitMediaTitleChange: (payload) => state.events.push(payload),
|
||||
emitSubtitleMetricsChange: (payload) => state.events.push(payload),
|
||||
setCurrentSecondarySubText: (text) => {
|
||||
state.secondarySubText = text;
|
||||
},
|
||||
resolvePendingRequest: () => false,
|
||||
setSecondarySubVisibility: () => {},
|
||||
syncCurrentAudioStreamIndex: () => {},
|
||||
setCurrentAudioTrackId: () => {},
|
||||
setCurrentTimePos: () => {},
|
||||
getCurrentTimePos: () => 0,
|
||||
getPendingPauseAtSubEnd: () => false,
|
||||
setPendingPauseAtSubEnd: () => {},
|
||||
getPauseAtTime: () => null,
|
||||
setPauseAtTime: () => {},
|
||||
autoLoadSecondarySubTrack: () => {},
|
||||
setCurrentVideoPath: () => {},
|
||||
emitSecondarySubtitleVisibility: (payload) => state.events.push(payload),
|
||||
setCurrentAudioStreamIndex: () => {},
|
||||
sendCommand: (payload) => {
|
||||
state.commands.push(payload);
|
||||
return true;
|
||||
},
|
||||
restorePreviousSecondarySubVisibility: () => {
|
||||
state.restored += 1;
|
||||
},
|
||||
...overrides,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test("dispatchMpvProtocolMessage emits subtitle text on property change", async () => {
|
||||
const { deps, state } = createDeps();
|
||||
|
||||
await dispatchMpvProtocolMessage(
|
||||
{ event: "property-change", name: "sub-text", data: "字幕" },
|
||||
deps,
|
||||
);
|
||||
|
||||
assert.equal(state.subText, "字幕");
|
||||
assert.deepEqual(state.events, [{ text: "字幕", isOverlayVisible: false }]);
|
||||
});
|
||||
|
||||
test("dispatchMpvProtocolMessage sets secondary subtitle track based on track list response", async () => {
|
||||
const { deps, state } = createDeps();
|
||||
|
||||
await dispatchMpvProtocolMessage(
|
||||
{
|
||||
request_id: MPV_REQUEST_ID_TRACK_LIST_SECONDARY,
|
||||
data: [
|
||||
{ type: "audio", id: 1, lang: "eng" },
|
||||
{ type: "sub", id: 2, lang: "ja" },
|
||||
],
|
||||
},
|
||||
deps,
|
||||
);
|
||||
|
||||
assert.deepEqual(state.commands, [{ command: ["set_property", "secondary-sid", 2] }]);
|
||||
});
|
||||
|
||||
test("dispatchMpvProtocolMessage restores secondary visibility on shutdown", async () => {
|
||||
const { deps, state } = createDeps();
|
||||
|
||||
await dispatchMpvProtocolMessage({ event: "shutdown" }, deps);
|
||||
|
||||
assert.equal(state.restored, 1);
|
||||
});
|
||||
|
||||
test("splitMpvMessagesFromBuffer parses complete lines and preserves partial buffer", () => {
|
||||
const parsed = splitMpvMessagesFromBuffer(
|
||||
"{\"event\":\"shutdown\"}\\n{\"event\":\"property-change\",\"name\":\"media-title\",\"data\":\"x\"}\\n{\"partial\"",
|
||||
);
|
||||
|
||||
assert.equal(parsed.messages.length, 2);
|
||||
assert.equal(parsed.nextBuffer, "{\"partial\"");
|
||||
assert.equal(parsed.messages[0].event, "shutdown");
|
||||
assert.equal(parsed.messages[1].name, "property-change");
|
||||
});
|
||||
|
||||
test("splitMpvMessagesFromBuffer reports invalid JSON lines", () => {
|
||||
const errors: Array<{ line: string; error?: string }> = [];
|
||||
|
||||
splitMpvMessagesFromBuffer("{\"event\":\"x\"}\\n{invalid}\\n", undefined, (line, error) => {
|
||||
errors.push({ line, error: String(error) });
|
||||
});
|
||||
|
||||
assert.equal(errors.length, 1);
|
||||
assert.equal(errors[0].line, "{invalid}");
|
||||
});
|
||||
|
||||
test("visibility and boolean parsers handle text values", () => {
|
||||
assert.equal(parseVisibilityProperty("true"), true);
|
||||
assert.equal(parseVisibilityProperty("0"), false);
|
||||
assert.equal(parseVisibilityProperty("unknown"), null);
|
||||
assert.equal(asBoolean("yes", false), true);
|
||||
assert.equal(asBoolean("0", true), false);
|
||||
});
|
||||
@@ -7,34 +7,14 @@ import {
|
||||
} from "../../types";
|
||||
import {
|
||||
dispatchMpvProtocolMessage,
|
||||
MPV_REQUEST_ID_AID,
|
||||
MPV_REQUEST_ID_OSD_DIMENSIONS,
|
||||
MPV_REQUEST_ID_OSD_HEIGHT,
|
||||
MPV_REQUEST_ID_PATH,
|
||||
MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY,
|
||||
MPV_REQUEST_ID_SECONDARY_SUBTEXT,
|
||||
MPV_REQUEST_ID_SUB_ASS_OVERRIDE,
|
||||
MPV_REQUEST_ID_SUB_BOLD,
|
||||
MPV_REQUEST_ID_SUB_BORDER_SIZE,
|
||||
MPV_REQUEST_ID_SUB_FONT,
|
||||
MPV_REQUEST_ID_SUB_FONT_SIZE,
|
||||
MPV_REQUEST_ID_SUB_ITALIC,
|
||||
MPV_REQUEST_ID_SUB_MARGIN_X,
|
||||
MPV_REQUEST_ID_SUB_MARGIN_Y,
|
||||
MPV_REQUEST_ID_SUB_POS,
|
||||
MPV_REQUEST_ID_SUB_SCALE,
|
||||
MPV_REQUEST_ID_SUB_SCALE_BY_WINDOW,
|
||||
MPV_REQUEST_ID_SUB_SHADOW_OFFSET,
|
||||
MPV_REQUEST_ID_SUB_SPACING,
|
||||
MPV_REQUEST_ID_SUBTEXT,
|
||||
MPV_REQUEST_ID_SUBTEXT_ASS,
|
||||
MPV_REQUEST_ID_SUB_USE_MARGINS,
|
||||
MPV_REQUEST_ID_TRACK_LIST_AUDIO,
|
||||
MPV_REQUEST_ID_TRACK_LIST_SECONDARY,
|
||||
MpvMessage,
|
||||
MpvProtocolHandleMessageDeps,
|
||||
splitMpvMessagesFromBuffer,
|
||||
} from "./mpv-protocol";
|
||||
import { requestMpvInitialState, subscribeToMpvProperties } from "./mpv-properties";
|
||||
import { getMpvReconnectDelay } from "./mpv-transport";
|
||||
|
||||
export {
|
||||
MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY,
|
||||
@@ -170,8 +150,8 @@ export class MpvIpcClient implements MpvClient {
|
||||
this.reconnectAttempt = 0;
|
||||
this.hasConnectedOnce = true;
|
||||
this.setSecondarySubVisibility(false);
|
||||
this.subscribeToProperties();
|
||||
this.getInitialState();
|
||||
subscribeToMpvProperties(this.send.bind(this));
|
||||
requestMpvInitialState(this.send.bind(this));
|
||||
|
||||
const shouldAutoStart =
|
||||
this.deps.autoStartOverlay ||
|
||||
@@ -217,28 +197,7 @@ export class MpvIpcClient implements MpvClient {
|
||||
clearTimeout(reconnectTimer);
|
||||
}
|
||||
const attempt = this.reconnectAttempt++;
|
||||
let delay: number;
|
||||
if (this.hasConnectedOnce) {
|
||||
if (attempt < 2) {
|
||||
delay = 1000;
|
||||
} else if (attempt < 4) {
|
||||
delay = 2000;
|
||||
} else if (attempt < 7) {
|
||||
delay = 5000;
|
||||
} else {
|
||||
delay = 10000;
|
||||
}
|
||||
} else {
|
||||
if (attempt < 2) {
|
||||
delay = 200;
|
||||
} else if (attempt < 4) {
|
||||
delay = 500;
|
||||
} else if (attempt < 6) {
|
||||
delay = 1000;
|
||||
} else {
|
||||
delay = 2000;
|
||||
}
|
||||
}
|
||||
const delay = getMpvReconnectDelay(attempt, this.hasConnectedOnce);
|
||||
this.deps.setReconnectTimer(
|
||||
setTimeout(() => {
|
||||
console.log(
|
||||
@@ -457,128 +416,6 @@ export class MpvIpcClient implements MpvClient {
|
||||
return true;
|
||||
}
|
||||
|
||||
private subscribeToProperties(): void {
|
||||
this.send({ command: ["observe_property", 1, "sub-text"] });
|
||||
this.send({ command: ["observe_property", 2, "path"] });
|
||||
this.send({ command: ["observe_property", 3, "sub-start"] });
|
||||
this.send({ command: ["observe_property", 4, "sub-end"] });
|
||||
this.send({ command: ["observe_property", 5, "time-pos"] });
|
||||
this.send({ command: ["observe_property", 6, "secondary-sub-text"] });
|
||||
this.send({ command: ["observe_property", 7, "aid"] });
|
||||
this.send({ command: ["observe_property", 8, "sub-pos"] });
|
||||
this.send({ command: ["observe_property", 9, "sub-font-size"] });
|
||||
this.send({ command: ["observe_property", 10, "sub-scale"] });
|
||||
this.send({ command: ["observe_property", 11, "sub-margin-y"] });
|
||||
this.send({ command: ["observe_property", 12, "sub-margin-x"] });
|
||||
this.send({ command: ["observe_property", 13, "sub-font"] });
|
||||
this.send({ command: ["observe_property", 14, "sub-spacing"] });
|
||||
this.send({ command: ["observe_property", 15, "sub-bold"] });
|
||||
this.send({ command: ["observe_property", 16, "sub-italic"] });
|
||||
this.send({ command: ["observe_property", 17, "sub-scale-by-window"] });
|
||||
this.send({ command: ["observe_property", 18, "osd-height"] });
|
||||
this.send({ command: ["observe_property", 19, "osd-dimensions"] });
|
||||
this.send({ command: ["observe_property", 20, "sub-text-ass"] });
|
||||
this.send({ command: ["observe_property", 21, "sub-border-size"] });
|
||||
this.send({ command: ["observe_property", 22, "sub-shadow-offset"] });
|
||||
this.send({ command: ["observe_property", 23, "sub-ass-override"] });
|
||||
this.send({ command: ["observe_property", 24, "sub-use-margins"] });
|
||||
this.send({ command: ["observe_property", 25, "media-title"] });
|
||||
}
|
||||
|
||||
private getInitialState(): void {
|
||||
this.send({
|
||||
command: ["get_property", "sub-text"],
|
||||
request_id: MPV_REQUEST_ID_SUBTEXT,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-text-ass"],
|
||||
request_id: MPV_REQUEST_ID_SUBTEXT_ASS,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "path"],
|
||||
request_id: MPV_REQUEST_ID_PATH,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "media-title"],
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "secondary-sub-text"],
|
||||
request_id: MPV_REQUEST_ID_SECONDARY_SUBTEXT,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "secondary-sub-visibility"],
|
||||
request_id: MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "aid"],
|
||||
request_id: MPV_REQUEST_ID_AID,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-pos"],
|
||||
request_id: MPV_REQUEST_ID_SUB_POS,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-font-size"],
|
||||
request_id: MPV_REQUEST_ID_SUB_FONT_SIZE,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-scale"],
|
||||
request_id: MPV_REQUEST_ID_SUB_SCALE,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-margin-y"],
|
||||
request_id: MPV_REQUEST_ID_SUB_MARGIN_Y,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-margin-x"],
|
||||
request_id: MPV_REQUEST_ID_SUB_MARGIN_X,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-font"],
|
||||
request_id: MPV_REQUEST_ID_SUB_FONT,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-spacing"],
|
||||
request_id: MPV_REQUEST_ID_SUB_SPACING,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-bold"],
|
||||
request_id: MPV_REQUEST_ID_SUB_BOLD,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-italic"],
|
||||
request_id: MPV_REQUEST_ID_SUB_ITALIC,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-scale-by-window"],
|
||||
request_id: MPV_REQUEST_ID_SUB_SCALE_BY_WINDOW,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "osd-height"],
|
||||
request_id: MPV_REQUEST_ID_OSD_HEIGHT,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "osd-dimensions"],
|
||||
request_id: MPV_REQUEST_ID_OSD_DIMENSIONS,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-border-size"],
|
||||
request_id: MPV_REQUEST_ID_SUB_BORDER_SIZE,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-shadow-offset"],
|
||||
request_id: MPV_REQUEST_ID_SUB_SHADOW_OFFSET,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-ass-override"],
|
||||
request_id: MPV_REQUEST_ID_SUB_ASS_OVERRIDE,
|
||||
});
|
||||
this.send({
|
||||
command: ["get_property", "sub-use-margins"],
|
||||
request_id: MPV_REQUEST_ID_SUB_USE_MARGINS,
|
||||
});
|
||||
}
|
||||
|
||||
setSubVisibility(visible: boolean): void {
|
||||
this.send({
|
||||
command: ["set_property", "sub-visibility", visible ? "yes" : "no"],
|
||||
|
||||
16
src/core/services/mpv-transport.test.ts
Normal file
16
src/core/services/mpv-transport.test.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { getMpvReconnectDelay } from "./mpv-transport";
|
||||
|
||||
test("getMpvReconnectDelay follows existing reconnect ramp", () => {
|
||||
assert.equal(getMpvReconnectDelay(0, true), 1000);
|
||||
assert.equal(getMpvReconnectDelay(1, true), 1000);
|
||||
assert.equal(getMpvReconnectDelay(2, true), 2000);
|
||||
assert.equal(getMpvReconnectDelay(4, true), 5000);
|
||||
assert.equal(getMpvReconnectDelay(7, true), 10000);
|
||||
|
||||
assert.equal(getMpvReconnectDelay(0, false), 200);
|
||||
assert.equal(getMpvReconnectDelay(2, false), 500);
|
||||
assert.equal(getMpvReconnectDelay(4, false), 1000);
|
||||
assert.equal(getMpvReconnectDelay(6, false), 2000);
|
||||
});
|
||||
28
src/core/services/mpv-transport.ts
Normal file
28
src/core/services/mpv-transport.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
export function getMpvReconnectDelay(
|
||||
attempt: number,
|
||||
hasConnectedOnce: boolean,
|
||||
): number {
|
||||
if (hasConnectedOnce) {
|
||||
if (attempt < 2) {
|
||||
return 1000;
|
||||
}
|
||||
if (attempt < 4) {
|
||||
return 2000;
|
||||
}
|
||||
if (attempt < 7) {
|
||||
return 5000;
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
|
||||
if (attempt < 2) {
|
||||
return 200;
|
||||
}
|
||||
if (attempt < 4) {
|
||||
return 500;
|
||||
}
|
||||
if (attempt < 6) {
|
||||
return 1000;
|
||||
}
|
||||
return 2000;
|
||||
}
|
||||
Reference in New Issue
Block a user