Null-DRM-Official/apps/wvkey
404errordeveloper 2fa8f2435f Initial commit: Null DRM Official
Capture, decrypt, and restream toolkit with compiled-in app modules
(RTE, TG4, BBC), on-device MITM proxy, streamd control plane, and www.
BBC module.yaml is published (clear streams); other module values stay local.
2026-10-06 00:25:35 +02:00
..
README.md Initial commit: Null DRM Official 2026-10-06 00:25:35 +02:00
requirements.txt Initial commit: Null DRM Official 2026-10-06 00:25:35 +02:00
wvkey.py Initial commit: Null DRM Official 2026-10-06 00:25:35 +02:00

wvkey — Widevine CDM helper

The only Python in the project. Go (apps/pkg/wvkey) shells out to it to turn a PSSH plus a license endpoint into KID:KEY lines via pywidevine.

apps/wvkey/
  wvkey.py
  requirements.txt

Keep it thin: it does the CDM exchange and nothing else.

Setup

# from the repo root
python -m venv .venv
.venv/bin/pip install -r apps/wvkey/requirements.txt    # Windows: .venv\Scripts\pip

Put your Widevine device file somewhere gitignored, e.g. data/device.wvd. The Go side finds .venv automatically; override with --python.

Every unique value is a flag. There are no baked-in device paths, account URLs or user agents.

Run

Two license shapes:

# JSON challenge wrapper with an Authorization header
.venv/bin/python apps/wvkey/wvkey.py \
  --mode modulardrm \
  --wvd data/device.wvd \
  --pssh '<base64>' \
  --auth 'Bearer ...' \
  --pid '<release id>' \
  --license-url 'https://...' \
  --quiet

# raw binary challenge (octet-stream)
.venv/bin/python apps/wvkey/wvkey.py \
  --mode raw \
  --wvd data/device.wvd \
  --pssh '<base64>' \
  --license-url 'https://...' \
  --quiet

Options: --user-agent, --all (print every CONTENT key — needed for multi-KID streams).

Which mode an app needs is declared by its module (KeyMode()), never sniffed from the license URL at runtime. See docs/capture.md for how to tell them apart from a capture.

Go callers use wvkey.Fetch / FetchRaw / FetchRawAll and always pass Script, WVD and LicenseURL.