From 57ac2d443586b8fa3aaf0d4356e89c683293e959 Mon Sep 17 00:00:00 2001 From: Jos Vooges | STH Date: Tue, 22 Sep 2026 22:07:35 +0200 Subject: [PATCH] Add Viaplay Scripts: EPG sync, cookie accounts, cache-first play/keys. Sport agenda merges into Events; staggered pre-live fetches MPD/ClearKeys into the DRM DB. --- .../src/app/scripts/ScriptsPageInner.tsx | 53 +- .../admin-ui/src/app/scripts/ViaplayPanel.tsx | 636 ++++++++++++++++++ apps/master-api/scripts/viaplay_cdm.py | 53 ++ apps/master-api/src/admin/routes.ts | 105 +++ apps/master-api/src/app.ts | 2 + apps/master-api/src/viaplay/accounts.ts | 234 +++++++ apps/master-api/src/viaplay/cdm.ts | 73 ++ apps/master-api/src/viaplay/client.ts | 439 ++++++++++++ apps/master-api/src/viaplay/events.ts | 80 +++ apps/master-api/src/viaplay/play.ts | 257 +++++++ apps/master-api/src/viaplay/refresh.ts | 120 ++++ apps/master-api/src/viaplay/settings.ts | 452 +++++++++++++ apps/master-api/src/viaplay/sync.ts | 172 +++++ apps/master-api/src/viaplay/tweaks.ts | 202 ++++++ apps/master-api/src/viewer/schedule-events.ts | 56 ++ 15 files changed, 2930 insertions(+), 4 deletions(-) create mode 100644 apps/admin-ui/src/app/scripts/ViaplayPanel.tsx create mode 100644 apps/master-api/scripts/viaplay_cdm.py create mode 100644 apps/master-api/src/viaplay/accounts.ts create mode 100644 apps/master-api/src/viaplay/cdm.ts create mode 100644 apps/master-api/src/viaplay/client.ts create mode 100644 apps/master-api/src/viaplay/events.ts create mode 100644 apps/master-api/src/viaplay/play.ts create mode 100644 apps/master-api/src/viaplay/refresh.ts create mode 100644 apps/master-api/src/viaplay/settings.ts create mode 100644 apps/master-api/src/viaplay/sync.ts create mode 100644 apps/master-api/src/viaplay/tweaks.ts diff --git a/apps/admin-ui/src/app/scripts/ScriptsPageInner.tsx b/apps/admin-ui/src/app/scripts/ScriptsPageInner.tsx index dcdd1c8..bdd0cab 100644 --- a/apps/admin-ui/src/app/scripts/ScriptsPageInner.tsx +++ b/apps/admin-ui/src/app/scripts/ScriptsPageInner.tsx @@ -6,12 +6,14 @@ import { useSearchParams, useRouter } from "next/navigation"; import { Nav, useAuth } from "@/components/Nav"; import { OdidoPanel, type OdidoOverview } from "./OdidoPanel"; import { F1tvPanel, type F1tvOverview } from "./F1tvPanel"; +import { ViaplayPanel, type ViaplayOverview } from "./ViaplayPanel"; -type ScriptTab = "odido" | "f1tv"; +type ScriptTab = "odido" | "f1tv" | "viaplay"; const TABS: Array<{ id: ScriptTab; label: string; short: string }> = [ { id: "odido", label: "Odido", short: "Odido" }, { id: "f1tv", label: "F1TV", short: "F1" }, + { id: "viaplay", label: "Viaplay", short: "Via" }, ]; export default function ScriptsPageInner() { @@ -19,16 +21,19 @@ export default function ScriptsPageInner() { const search = useSearchParams(); const router = useRouter(); const tabParam = search.get("tab"); - const active: ScriptTab = tabParam === "f1tv" ? "f1tv" : "odido"; + const active: ScriptTab = + tabParam === "f1tv" ? "f1tv" : tabParam === "viaplay" ? "viaplay" : "odido"; const [odidoOverview, setOdidoOverview] = useState(null); const [f1tvOverview, setF1tvOverview] = useState(null); + const [viaplayOverview, setViaplayOverview] = useState(null); const loadOverviews = useCallback(async () => { try { - const [o, f] = await Promise.all([ + const [o, f, v] = await Promise.all([ fetch("/api/v1/admin/scripts/odido", { credentials: "include" }).then((r) => r.json()), fetch("/api/v1/admin/scripts/f1tv", { credentials: "include" }).then((r) => r.json()), + fetch("/api/v1/admin/scripts/viaplay", { credentials: "include" }).then((r) => r.json()), ]); if (o && !o.error) { setOdidoOverview({ @@ -48,6 +53,15 @@ export default function ScriptsPageInner() { lastSyncAt: f.lastSyncAt ?? null, }); } + if (v && !v.error) { + setViaplayOverview({ + configured: !!v.configured, + enabled: v.enabled !== false, + accountCount: v.accountCount ?? 0, + eventCount: v.eventCount ?? 0, + lastSyncAt: v.lastSyncAt ?? null, + }); + } } catch { /* panels load own errors */ } @@ -147,6 +161,35 @@ export default function ScriptsPageInner() { )} + +