Send Viaplay session cookies encoded and reject Don't go without a license.

This commit is contained in:
Jos Vooges | STH 2026-09-28 04:40:17 +02:00
parent 65c144d8b6
commit 379fbdab6d

View file

@ -21,12 +21,23 @@ function asRecord(v: unknown): Record<string, unknown> | null {
: null; : null;
} }
/** Netscape/browser-cookies blijven encoded; decoded JSON in Cookie-header = Don't go. */
function cookieValue(raw: string): string {
const v = raw.trim();
if (!v) return v;
if (/%[0-9A-Fa-f]{2}/.test(v)) return v;
if (/[{}"\s]/.test(v)) return encodeURIComponent(v);
return v;
}
function cookieHeader(creds: ViaplayAccountCreds): string { function cookieHeader(creds: ViaplayAccountCreds): string {
const parts: string[] = []; const parts: string[] = [];
if (creds.session) parts.push(`session=${creds.session}`); if (creds.session) parts.push(`session=${cookieValue(creds.session)}`);
if (creds.accessToken) parts.push(`accessToken=${creds.accessToken}`); if (creds.accessToken) parts.push(`accessToken=${creds.accessToken.trim()}`);
if (creds.profileId) parts.push(`viaplay_profileId=${creds.profileId}`); if (creds.profileId) parts.push(`viaplay_profileId=${creds.profileId.trim()}`);
if (creds.persistentLogin) parts.push(`persistentLogin=${creds.persistentLogin}`); if (creds.persistentLogin) {
parts.push(`persistentLogin=${cookieValue(creds.persistentLogin)}`);
}
return parts.join("; "); return parts.join("; ");
} }
@ -127,22 +138,9 @@ export async function refreshViaplaySession(
: ""); : "");
if (!sessionRaw || !accessRaw) return null; if (!sessionRaw || !accessRaw) return null;
let session = sessionRaw; const session = sessionRaw;
try {
session = decodeURIComponent(sessionRaw);
} catch {
/* keep raw */
}
const accessToken = normalizeAccessToken(accessRaw) || accessRaw.trim(); const accessToken = normalizeAccessToken(accessRaw) || accessRaw.trim();
const nextPl = jar.persistentLogin const nextPl = jar.persistentLogin || pl;
? (() => {
try {
return decodeURIComponent(jar.persistentLogin);
} catch {
return jar.persistentLogin;
}
})()
: pl;
return { return {
...creds, ...creds,
@ -818,6 +816,12 @@ function assertPlayNotSoftFail(
if (isDontGoPlaceholder(played.mpdUrl)) { if (isDontGoPlaceholder(played.mpdUrl)) {
throw new Error("Viaplay gaf Don't go-placeholder i.p.v. de wedstrijdstream"); throw new Error("Viaplay gaf Don't go-placeholder i.p.v. de wedstrijdstream");
} }
if (/vod-dash/i.test(played.mpdUrl) && !played.licenseUrl) {
throw new Error("Viaplay gaf Don't go-VOD zonder licentie");
}
if (!played.licenseUrl) {
throw new Error("Viaplay play-response mist Widevine-licentie (Don't go-fallback)");
}
if (opts?.requireLiveDash && !isLiveDashMpd(played.mpdUrl)) { if (opts?.requireLiveDash && !isLiveDashMpd(played.mpdUrl)) {
throw new Error( throw new Error(
"Viaplay gaf geen live-dash stream (Don't go/VOD-fallback — sessie of rechten)" "Viaplay gaf geen live-dash stream (Don't go/VOD-fallback — sessie of rechten)"
@ -903,12 +907,12 @@ export async function playByMediaGuid(
const urls = [ const urls = [
buildPlayLiveUrl(creds, mediaGuid, { buildPlayLiveUrl(creds, mediaGuid, {
deviceKey: opts.deviceKey, deviceKey: opts.deviceKey,
pageUrl: opts.pageUrl, harStyle: false,
harStyle: true,
}), }),
buildPlayLiveUrl(creds, mediaGuid, { buildPlayLiveUrl(creds, mediaGuid, {
deviceKey: opts.deviceKey, deviceKey: opts.deviceKey,
harStyle: false, pageUrl: opts.pageUrl,
harStyle: true,
}), }),
]; ];
@ -1076,6 +1080,9 @@ function assertVodPlayMatchesGuid(
"Viaplay gaf Don't go-placeholder i.p.v. de gevraagde stream" "Viaplay gaf Don't go-placeholder i.p.v. de gevraagde stream"
); );
} }
if (/vod-dash/i.test(played.mpdUrl) && !played.licenseUrl) {
throw new Error("Viaplay gaf Don't go-VOD zonder licentie");
}
const links = asRecord(body._links); const links = asRecord(body._links);
const productHref = asRecord(links?.["viaplay:product"])?.href; const productHref = asRecord(links?.["viaplay:product"])?.href;