Keep credentials, HARs and probe dumps out of git; use neutral wording around sessions and stream licenses.
202 lines
5.4 KiB
TypeScript
202 lines
5.4 KiB
TypeScript
export type ViaplayTweaks = {
|
|
/** Content deviceKey (NL DASH). */
|
|
deviceKey: string;
|
|
/** Hoeveel dagen vooruit EPG syncen. */
|
|
syncDaysAhead: number;
|
|
/** HTTP-timeout sync/play (ms). */
|
|
httpTimeoutMs: number;
|
|
/** Minuten vóór start MPD/keys ophalen. */
|
|
preLiveMinutes: number;
|
|
/** Interval van de pre-live worker (s). */
|
|
preLiveIntervalSeconds: number;
|
|
/** Max gelijktijdige pre-live jobs (1 = veilig). */
|
|
preLiveConcurrency: number;
|
|
/** Pauze tussen jobs (ms). */
|
|
preLiveStaggerMs: number;
|
|
/** Pre-live worker aan/uit. */
|
|
preLiveEnabled: boolean;
|
|
/** Keys ophalen als PSSH beschikbaar is. */
|
|
fetchKeysIfMissing: boolean;
|
|
/** MPD-cache TTL (minuten) vóór her-play. */
|
|
mpdCacheTtlMinutes: number;
|
|
/** CDM-timeout (ms). */
|
|
cdmTimeoutMs: number;
|
|
/** Deel Odido WVD-pad. */
|
|
useOdidoWvd: boolean;
|
|
};
|
|
|
|
export const VIAPLAY_TWEAK_DEFAULTS: ViaplayTweaks = {
|
|
deviceKey: "pcdash-nl",
|
|
syncDaysAhead: 7,
|
|
httpTimeoutMs: 30_000,
|
|
preLiveMinutes: 5,
|
|
preLiveIntervalSeconds: 60,
|
|
preLiveConcurrency: 1,
|
|
preLiveStaggerMs: 12_000,
|
|
preLiveEnabled: true,
|
|
fetchKeysIfMissing: true,
|
|
mpdCacheTtlMinutes: 180,
|
|
cdmTimeoutMs: 60_000,
|
|
useOdidoWvd: true,
|
|
};
|
|
|
|
export const VIAPLAY_TWEAK_META: Array<{
|
|
key: keyof ViaplayTweaks;
|
|
label: string;
|
|
hint: string;
|
|
kind: "number" | "boolean" | "string";
|
|
unit?: string;
|
|
}> = [
|
|
{
|
|
key: "deviceKey",
|
|
label: "Device key",
|
|
hint: "Viaplay content/play deviceKey (NL = pcdash-nl).",
|
|
kind: "string",
|
|
},
|
|
{
|
|
key: "syncDaysAhead",
|
|
label: "EPG-dagen vooruit",
|
|
hint: "Hoeveel dagen sport/all?date=… syncen.",
|
|
kind: "number",
|
|
},
|
|
{
|
|
key: "httpTimeoutMs",
|
|
label: "HTTP-timeout",
|
|
hint: "Timeout per Viaplay-request.",
|
|
kind: "number",
|
|
unit: "ms",
|
|
},
|
|
{
|
|
key: "preLiveMinutes",
|
|
label: "Pre-live venster",
|
|
hint: "MPD/keys ophalen vanaf N minuten vóór start.",
|
|
kind: "number",
|
|
unit: "min",
|
|
},
|
|
{
|
|
key: "preLiveIntervalSeconds",
|
|
label: "Worker-interval",
|
|
hint: "Hoe vaak de pre-live worker draait.",
|
|
kind: "number",
|
|
unit: "s",
|
|
},
|
|
{
|
|
key: "preLiveConcurrency",
|
|
label: "Pre-live concurrency",
|
|
hint: "1 = veilig voor account; nooit hoger dan 2 zonder reden.",
|
|
kind: "number",
|
|
},
|
|
{
|
|
key: "preLiveStaggerMs",
|
|
label: "Pre-live stagger",
|
|
hint: "Pauze tussen play/license-calls.",
|
|
kind: "number",
|
|
unit: "ms",
|
|
},
|
|
{
|
|
key: "preLiveEnabled",
|
|
label: "Pre-live worker",
|
|
hint: "Automatisch manifest/licentie ±5 min vóór start.",
|
|
kind: "boolean",
|
|
},
|
|
{
|
|
key: "fetchKeysIfMissing",
|
|
label: "Licenties bij miss",
|
|
hint: "Licenties ophalen als het manifest dat vereist.",
|
|
kind: "boolean",
|
|
},
|
|
{
|
|
key: "mpdCacheTtlMinutes",
|
|
label: "Manifest-cache TTL",
|
|
hint: "Hergebruik gecached manifest tot TTL verloopt.",
|
|
kind: "number",
|
|
unit: "min",
|
|
},
|
|
{
|
|
key: "cdmTimeoutMs",
|
|
label: "Licentie-timeout",
|
|
hint: "Timeout voor licentie-aanvraag.",
|
|
kind: "number",
|
|
unit: "ms",
|
|
},
|
|
{
|
|
key: "useOdidoWvd",
|
|
label: "Gedeeld device-bestand",
|
|
hint: "Zelfde Widevine-devicebestand als Odido Scripts.",
|
|
kind: "boolean",
|
|
},
|
|
];
|
|
|
|
export function mergeViaplayTweaks(
|
|
raw: Partial<ViaplayTweaks> | Record<string, unknown>
|
|
): ViaplayTweaks {
|
|
const d = VIAPLAY_TWEAK_DEFAULTS;
|
|
const n = (v: unknown, fallback: number) => {
|
|
const x = typeof v === "number" ? v : Number(v);
|
|
return Number.isFinite(x) && x > 0 ? Math.floor(x) : fallback;
|
|
};
|
|
const s = (v: unknown, fallback: string) => {
|
|
const t = String(v ?? "").trim();
|
|
return t || fallback;
|
|
};
|
|
return {
|
|
deviceKey: s(raw.deviceKey, d.deviceKey),
|
|
syncDaysAhead: Math.min(21, Math.max(1, n(raw.syncDaysAhead, d.syncDaysAhead))),
|
|
httpTimeoutMs: Math.min(120_000, Math.max(5_000, n(raw.httpTimeoutMs, d.httpTimeoutMs))),
|
|
preLiveMinutes: Math.min(60, Math.max(1, n(raw.preLiveMinutes, d.preLiveMinutes))),
|
|
preLiveIntervalSeconds: Math.min(
|
|
600,
|
|
Math.max(30, n(raw.preLiveIntervalSeconds, d.preLiveIntervalSeconds))
|
|
),
|
|
preLiveConcurrency: Math.min(
|
|
2,
|
|
Math.max(1, n(raw.preLiveConcurrency, d.preLiveConcurrency))
|
|
),
|
|
preLiveStaggerMs: Math.min(
|
|
120_000,
|
|
Math.max(0, n(raw.preLiveStaggerMs, d.preLiveStaggerMs))
|
|
),
|
|
preLiveEnabled: raw.preLiveEnabled !== false,
|
|
fetchKeysIfMissing: raw.fetchKeysIfMissing !== false,
|
|
mpdCacheTtlMinutes: Math.min(
|
|
24 * 60,
|
|
Math.max(15, n(raw.mpdCacheTtlMinutes, d.mpdCacheTtlMinutes))
|
|
),
|
|
cdmTimeoutMs: Math.min(180_000, Math.max(10_000, n(raw.cdmTimeoutMs, d.cdmTimeoutMs))),
|
|
useOdidoWvd: raw.useOdidoWvd !== false,
|
|
};
|
|
}
|
|
|
|
export type ViaplayEventSnapshot = {
|
|
guid: string;
|
|
mediaGuid: string;
|
|
title: string;
|
|
subtitle: string | null;
|
|
category: string | null;
|
|
sportLabel: string | null;
|
|
sportBucket: string | null;
|
|
startMs: number;
|
|
endMs: number;
|
|
imageUrl: string | null;
|
|
pageUrl: string | null;
|
|
channelName: string | null;
|
|
stationId: string | null;
|
|
mpdUrl: string | null;
|
|
mpdCachedAt: string | null;
|
|
hasPssh: boolean;
|
|
hasKeys: boolean;
|
|
accountIds: string[];
|
|
lastPlayError: string | null;
|
|
lastPlayAt: string | null;
|
|
};
|
|
|
|
export function isMpdCacheFresh(
|
|
cachedAt: string | null | undefined,
|
|
ttlMinutes: number,
|
|
nowMs = Date.now()
|
|
): boolean {
|
|
if (!cachedAt) return false;
|
|
const t = Date.parse(cachedAt);
|
|
if (!Number.isFinite(t)) return false;
|
|
return nowMs - t < ttlMinutes * 60_000;
|
|
}
|