#!/usr/bin/env python3 """F1TV Widevine license helper. Requires: pip install pywidevine requests""" import json import sys import requests from pywidevine.cdm import Cdm from pywidevine.device import Device from pywidevine.pssh import PSSH def main(): data = json.load(sys.stdin) device = Device.load(data["wvdPath"]) headers = { "Accept": "*/*", "Origin": "https://f1tv.formula1.com", "Referer": "https://f1tv.formula1.com/", "User-Agent": data.get("userAgent") or "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.0.0 Safari/537.36", "Content-Type": "application/octet-stream", "ascendontoken": data["ascendontoken"], "entitlementtoken": data["entitlementtoken"], } keys = [] for pssh in data["psshList"]: cdm = Cdm.from_device(device) session_id = cdm.open() try: # Browser vraagt eerst het service-certificaat op (body 08 04) en gebruikt privacy mode. try: cert = requests.post(data["licUrl"], headers=headers, data=b"\x08\x04", timeout=30) if cert.ok and cert.content: cdm.set_service_certificate(session_id, cert.content) except Exception: pass challenge = cdm.get_license_challenge(session_id, PSSH(pssh)) response = requests.post(data["licUrl"], headers=headers, data=challenge, timeout=30) if not response.ok: raise RuntimeError(f"license HTTP {response.status_code}: {response.text[:200]}") cdm.parse_license(session_id, response.content) for key in cdm.get_keys(session_id): if key.type == "CONTENT": pair = f"{key.kid.hex}:{key.key.hex()}" if pair not in keys: keys.append(pair) finally: cdm.close(session_id) print(json.dumps({"keys": keys}, separators=(",", ":"))) if __name__ == "__main__": try: main() except Exception as exc: print(str(exc), file=sys.stderr) sys.exit(1)