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.
4.7 KiB
DRM-Decryption
Capture Widevine live sessions from Android streaming apps and restream them.
Everything is one Go binary — drm — with every app module compiled in. Each
streaming app (RTE, TG4, …) is a Go package under apps/modules/; its secrets and
IDs live in a local, gitignored values file that you fill in yourself.
- docs/ — architecture, module authoring, per-provider setup
- docs/quickstart.md — the longer version of what follows
Quick start
1. Prerequisites
| Need | Why |
|---|---|
| Go 1.25+ | builds everything |
| Python 3.10+ | apps/wvkey/wvkey.py talks to the Widevine CDM |
adb (platform-tools) on PATH |
only for phone capture |
A .wvd Widevine device file |
only for fetching keys |
Phone capture additionally needs a rooted Android device (Magisk) so the MITM CA can be injected into the system trust store. Catalog lookups need no phone.
2. Clone and build
git clone https://git.nulldrm.com/nulldrm/Null-DRM-Official.git
cd Null-DRM-Official
# Linux / macOS
go -C apps/cli build -o ../../bin/drm .
# Windows
go -C apps/cli build -o ../../bin/drm.exe .
Check it:
./bin/drm help
./bin/drm modules # which app modules this build contains
drm modules works immediately, but channel lists stay empty until you add
values — that is the next step.
3. Python CDM helper
python -m venv .venv
.venv/bin/pip install -r apps/wvkey/requirements.txt # Windows: .venv\Scripts\pip
Put your Widevine device file in data/ (gitignored), e.g. data/device.wvd.
4. Fill in a module's values
Compiled-in module code carries no account IDs, policy keys, video IDs, license URLs or key IDs. Those go in a gitignored file per module, which you create:
apps/modules/tg4/module.yaml
apps/modules/rte/module.yaml
Where each value comes from:
- docs/providers/tg4.md — Brightcove account ID, policy key, video IDs
- docs/providers/rte.md — license URL, origin hosts, channel KIDs
- docs/capture.md — how to discover all of it for a new app
Any value can be passed per-run instead of stored:
./bin/drm catalog --app tg4 --channel ioi --tg4.policy-key 'BCpkAD...'
TG4_POLICY_KEY='BCpkAD...' ./bin/drm catalog --app tg4 --channel ioi
5. Run something
# keys from a public catalog — no phone needed
./bin/drm catalog --app tg4 --channel ioi --keys --wvd data/device.wvd
# phone capture: launch the app, drive it to a channel, grab license + keys
./bin/drm proxy build # once: cross-compile the on-device MITM
./bin/drm capture --app rte --channel rteone --auto-play --wvd data/device.wvd
# control plane + dashboard on http://127.0.0.1:8083
./bin/drm serve --bind 127.0.0.1:8083 --data .cache/streamd --token SECRET
# always-on refresher: watches streamd, re-captures dead channels
STREAMD_TOKEN=SECRET ./bin/drm agent run --config apps/agent/agent.yaml
Results land in outputs/<app>/<timestamp>/, with latest/ kept as a copy.
Subcommands
| Command | What it does |
|---|---|
drm modules |
list compiled-in app modules, their channels and config source |
drm capture |
one-shot phone MITM capture → outputs/<app>/<stamp>/ |
drm catalog |
resolve a channel from its public catalog, no phone |
drm serve |
streamd: REST API + dashboard + media supervisor |
drm agent |
run / status / devices / enqueue / cancel |
drm proxy |
build / push / install-ca / start / stop / discover / pull |
Run any of them with --help.
Layout
apps/cli/ the binary -> bin/drm
apps/modules/ app modules: Go (tracked) + module.yaml (gitignored)
apps/pkg/ shared, provider-neutral libraries
apps/capture/ phone capture command
apps/agent/ always-on key refresher
apps/streamd/ control plane: API, SQLite, dashboard, supervisor
apps/proxy/ MITM host CLI + on-device proxy source
apps/wvkey/ wvkey.py — CDM only
docs/ architecture, authoring, provider setup
data/ secrets: .wvd, CA (gitignored)
outputs/ capture sessions (gitignored)
bin/ built binaries (gitignored)
www/ static site
Tests
go -C apps/pkg test ./...
go -C apps/modules test ./...
go -C apps/streamd test ./...
Tests that hit a live origin are behind a build tag, so they stay out of the normal run:
go -C apps/modules test -tags live ./rte/ -v
Scope
For use only on services you are authorised to access, with content you have the right to decrypt. docs/architecture.md describes what the system does and where it stops.