Reject Viaplay Don't go fallback and restore live play-live query.

This commit is contained in:
Jos Vooges | STH 2026-09-28 04:24:55 +02:00
parent e4714a7d09
commit 98c38826e1
2 changed files with 34 additions and 49 deletions

View file

@ -766,8 +766,12 @@ function extractProducts(json: unknown): ViaplayEpgProduct[] {
return out; return out;
} }
/** HAR: Don't go-placeholder (live soft-fail). Clips mogen dit pad wél hebben. */ /**
export const VIAPLAY_DONT_GO_MEDIA_RE = /\/7c4cd64\/88000100-1778484912807\.ism\b/i; * Don't go is Viaplay's soft-fail (200 + promo-VOD) i.p.v. 403.
* Titel/guid van het event kloppen vaak wél; alleen de media is fout.
*/
const VIAPLAY_DONT_GO_MEDIA_RE =
/88000100-1778484912807|\b7c4cd64\b|\/dont[-_]?go/i;
export function isDontGoPlaceholder(mpdUrl: string | null | undefined): boolean { export function isDontGoPlaceholder(mpdUrl: string | null | undefined): boolean {
return !!mpdUrl && VIAPLAY_DONT_GO_MEDIA_RE.test(mpdUrl); return !!mpdUrl && VIAPLAY_DONT_GO_MEDIA_RE.test(mpdUrl);
@ -777,31 +781,18 @@ export function isLiveDashMpd(mpdUrl: string | null | undefined): boolean {
return !!mpdUrl && /live-dash/i.test(mpdUrl); return !!mpdUrl && /live-dash/i.test(mpdUrl);
} }
function sportContentUrls( function assertLivePlayNotSoftFail(played: ViaplayPlayResult): void {
pageUrl: string | null | undefined, if (isPromoVodTitle(played.title)) {
deviceKey: string, throw new Error(`Viaplay gaf promo-stream (“${played.title}”)`);
mediaGuid: string
): { productUrl: string; contextualUrl: string; contextualv2Url: string } {
const guidPath = mediaGuid.replace(/-NL$/i, "").toLowerCase();
let clean = "";
const raw = (pageUrl || "").trim();
if (raw) {
try {
const u = new URL(raw);
u.search = "";
clean = u.toString().replace(/\/$/, "");
} catch {
clean = "";
} }
if (isDontGoPlaceholder(played.mpdUrl)) {
throw new Error("Viaplay gaf Don't go-placeholder i.p.v. de wedstrijdstream");
} }
if (!clean) { if (!isLiveDashMpd(played.mpdUrl)) {
clean = `https://content.viaplay.com/${deviceKey}/sport/${guidPath}`; throw new Error(
"Viaplay gaf geen live-dash stream (Don't go/VOD-fallback — sessie of rechten)"
);
} }
return {
productUrl: `${clean}?partial=true`,
contextualUrl: `${clean}?contextual=true`,
contextualv2Url: `${clean}?contextualV2=true&productType=sport`,
};
} }
export async function playByMediaGuid( export async function playByMediaGuid(
@ -810,11 +801,8 @@ export async function playByMediaGuid(
opts: { deviceKey: string; timeoutMs: number; pageUrl?: string | null } opts: { deviceKey: string; timeoutMs: number; pageUrl?: string | null }
): Promise<ViaplayPlayResult> { ): Promise<ViaplayPlayResult> {
const mediaGuid = toMediaGuid(mediaGuidRaw); const mediaGuid = toMediaGuid(mediaGuidRaw);
const pages = sportContentUrls(opts.pageUrl, opts.deviceKey, mediaGuid); // Zelfde query als het werkende live-script. Extra HAR-svod/producturl
const returnUrl = new URL(`https://content.viaplay.com/${opts.deviceKey}`); // triggert bij terugkijken de Don't go-VOD-fallback.
returnUrl.searchParams.set("language", "nl");
if (creds.profileId) returnUrl.searchParams.set("profileId", creds.profileId);
const u = new URL("https://play-live.viaplay.com/api/stream/bymediaguid"); const u = new URL("https://play-live.viaplay.com/api/stream/bymediaguid");
u.searchParams.set("deviceId", creds.deviceId || randomUUID()); u.searchParams.set("deviceId", creds.deviceId || randomUUID());
u.searchParams.set("deviceName", "web"); u.searchParams.set("deviceName", "web");
@ -822,19 +810,7 @@ export async function playByMediaGuid(
u.searchParams.set("userAgent", VIAPLAY_USER_AGENT); u.searchParams.set("userAgent", VIAPLAY_USER_AGENT);
u.searchParams.set("deviceKey", opts.deviceKey); u.searchParams.set("deviceKey", opts.deviceKey);
u.searchParams.set("mediaGuid", mediaGuid); u.searchParams.set("mediaGuid", mediaGuid);
u.searchParams.set("cse", "true");
u.searchParams.set("nocc", "autoplayer"); u.searchParams.set("nocc", "autoplayer");
u.searchParams.set(
"splitIOFlagIds",
"all_sports_beyondLiveBeacon_on,web_player_pause_ads_on"
);
u.searchParams.set("returnurl", returnUrl.toString());
u.searchParams.set("producturl", pages.productUrl);
u.searchParams.set("contextualurl", pages.contextualUrl);
u.searchParams.set("contextualv2url", pages.contextualv2Url);
u.searchParams.set("sectionPath", "/sport");
u.searchParams.set("defaultAvailabilityContext", "svod");
u.searchParams.set("win10edge", "true");
if (creds.profileId) u.searchParams.set("profileId", creds.profileId); if (creds.profileId) u.searchParams.set("profileId", creds.profileId);
const res = await fetchJson(u.toString(), { const res = await fetchJson(u.toString(), {
@ -849,11 +825,7 @@ export async function playByMediaGuid(
throw new Error(msg); throw new Error(msg);
} }
const played = parsePlayStreamBody(body, mediaGuid); const played = parsePlayStreamBody(body, mediaGuid);
if (isDontGoPlaceholder(played.mpdUrl)) { assertLivePlayNotSoftFail(played);
throw new Error(
"Viaplay play-live gaf Don't go-placeholder i.p.v. de wedstrijdstream"
);
}
return played; return played;
} }
@ -969,8 +941,7 @@ function playBodyGuid(body: Record<string, unknown>): string | null {
} }
/** /**
* HAR afspelen.har: web speelt clip als guid+titel kloppen, ook zonder DRM * Soft-fail: 200 met juiste product-metadata maar Don't go / promo-MPD.
* en met cse mediaGuid=unknown. Alleen een promo-titel is een echte soft-fail.
*/ */
function assertVodPlayMatchesGuid( function assertVodPlayMatchesGuid(
body: Record<string, unknown>, body: Record<string, unknown>,
@ -991,6 +962,11 @@ function assertVodPlayMatchesGuid(
if (isPromoVodTitle(played.title)) { if (isPromoVodTitle(played.title)) {
throw new Error(`Viaplay gaf promo-stream (“${played.title}”)`); throw new Error(`Viaplay gaf promo-stream (“${played.title}”)`);
} }
if (isDontGoPlaceholder(played.mpdUrl)) {
throw new Error(
"Viaplay gaf Don't go-placeholder i.p.v. de gevraagde stream"
);
}
const links = asRecord(body._links); const links = asRecord(body._links);
const productHref = asRecord(links?.["viaplay:product"])?.href; const productHref = asRecord(links?.["viaplay:product"])?.href;

View file

@ -368,6 +368,12 @@ export async function ensureViaplayEventReady(
if (play.licenseUrl && !keys.length) { if (play.licenseUrl && !keys.length) {
throw new Error("Viaplay-licentie aanwezig maar geen keys"); throw new Error("Viaplay-licentie aanwezig maar geen keys");
} }
if (isDontGoPlaceholder(play.mpdUrl) || isDontGoPlaceholder(kap.mpdUrl)) {
throw new Error("Viaplay gaf Don't go-placeholder i.p.v. de wedstrijdstream");
}
if (!isLiveDashMpd(play.mpdUrl)) {
throw new Error("Viaplay gaf geen live-dash stream (Don't go/VOD-fallback)");
}
await patchViaplayEventCache(mediaGuid, { await patchViaplayEventCache(mediaGuid, {
mpdUrl: kap.mpdUrl, mpdUrl: kap.mpdUrl,
@ -576,6 +582,9 @@ async function resolveViaplayGuidPlayInner(
throw new Error("Viaplay-licentie aanwezig maar geen VOD-keys"); throw new Error("Viaplay-licentie aanwezig maar geen VOD-keys");
} }
} }
if (isDontGoPlaceholder(mpdUrl)) {
throw new Error("Viaplay gaf Don't go-placeholder i.p.v. de gevraagde stream");
}
recordVodPlay({ recordVodPlay({
guid, guid,