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.
This commit is contained in:
commit
2fa8f2435f
121 changed files with 17802 additions and 0 deletions
224
docs/providers/rte.md
Normal file
224
docs/providers/rte.md
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
# RTE module — filling in `module.yaml`
|
||||
|
||||
DASH + ModularDrm Widevine, captured from the phone. There is no public catalog, so
|
||||
every channel needs one phone capture to bootstrap.
|
||||
|
||||
Create `apps/modules/rte/module.yaml`. It is gitignored. Nothing below is shipped
|
||||
in the repo — you obtain it yourself from your own device.
|
||||
|
||||
## Skeleton
|
||||
|
||||
```yaml
|
||||
package: <android package id>
|
||||
license_url: "<Widevine ModularDrm endpoint, incl. its account query string>"
|
||||
proxy_bin: bin/proxy-android-arm64
|
||||
ca_hash: "6c3578b4"
|
||||
|
||||
score:
|
||||
hosts:
|
||||
- <manifest CDN host>
|
||||
- <ad-stitching host, if the app uses one>
|
||||
deny:
|
||||
- <EPG / schedules host fragment>
|
||||
|
||||
aliases:
|
||||
one: chanone
|
||||
two: chantwo
|
||||
|
||||
channels:
|
||||
chanone:
|
||||
label: "Channel One"
|
||||
chip_desc: ["^chanone$"]
|
||||
play_desc: ["play\\s*chanone"]
|
||||
chantwo:
|
||||
label: "Channel Two"
|
||||
chip_desc: ["^chantwo$"]
|
||||
play_desc: ["play\\s*chantwo"]
|
||||
|
||||
# Origin encoders behind the live channels.
|
||||
origins:
|
||||
vc11: "https://<origin host>/live/<path>/vc11/vc11.isml/"
|
||||
vc12: "https://<origin host>/live/<path>/vc12/vc12.isml/"
|
||||
|
||||
kids:
|
||||
vc11: "<uuid-form KID>"
|
||||
vc12: "<uuid-form KID>"
|
||||
```
|
||||
|
||||
## Where each value comes from
|
||||
|
||||
### `package`
|
||||
|
||||
Open the app on the phone, then:
|
||||
|
||||
```bash
|
||||
adb shell dumpsys window | grep mCurrentFocus
|
||||
```
|
||||
|
||||
The part before `/` is the package id.
|
||||
|
||||
### `license_url`
|
||||
|
||||
Run a discover session and play a channel ([capture.md](capture.md)):
|
||||
|
||||
```bash
|
||||
./bin/drm proxy discover --install-ca --reinject
|
||||
grep -iE 'ModularDrm|widevine|license' outputs/discover/*/appproxy.log
|
||||
```
|
||||
|
||||
Take the full URL including its query string — the account reference in it is part
|
||||
of the endpoint. The module also accepts it per run:
|
||||
|
||||
```bash
|
||||
./bin/drm capture --app rte --rte.license-url 'https://.../ModularDrm?...'
|
||||
```
|
||||
|
||||
### `score.hosts` / `score.deny`
|
||||
|
||||
`hosts` are the hosts that legitimately serve manifests; `deny` are hosts or URL
|
||||
fragments that must never be mistaken for one.
|
||||
|
||||
```bash
|
||||
grep -oE '"host":"[^"]+"' outputs/discover/*/appproxy_traffic.jsonl \
|
||||
| sort | uniq -c | sort -rn | head -20
|
||||
```
|
||||
|
||||
Put the origin and any ad-stitching host in `hosts`. Put EPG/schedule feeds and
|
||||
analytics in `deny` — this app's schedule feed otherwise scores as a manifest
|
||||
because its URL looks plausible.
|
||||
|
||||
Format-level scoring (`.mpd`, `.m3u8`, `/manifest`, `.isml`) is built in; you only
|
||||
supply the provider-specific parts.
|
||||
|
||||
### `channels.*.chip_desc` and `play_desc`
|
||||
|
||||
These are the regexes that locate the channel chip on the Live tab and the large
|
||||
hero Play button. They match the node **content-description**, case-insensitively.
|
||||
|
||||
Navigate to the Live tab by hand and dump the tree:
|
||||
|
||||
```bash
|
||||
adb shell uiautomator dump /sdcard/ui.xml
|
||||
adb shell cat /sdcard/ui.xml | grep -oE 'content-desc="[^"]*"' | sort -u
|
||||
```
|
||||
|
||||
You are looking for two things:
|
||||
|
||||
- a small chip per channel — its description is usually the bare channel name, so
|
||||
anchor the regex (`^chanone$`) to avoid matching a longer label
|
||||
- a large "play <channel>" button that appears after the chip is tapped
|
||||
|
||||
The module taps the hero Play directly when it is already on screen, otherwise it
|
||||
taps the chip first and waits for Play to appear. A match is only accepted as the
|
||||
hero button if its area is at least `hero_min_area` (default 200000), which keeps
|
||||
small list-item play icons from winning.
|
||||
|
||||
### `origins` and `kids` — the important pair
|
||||
|
||||
These let the manifest rewriter keep working after the ad-stitched manifest session
|
||||
expires. Both come from a capture.
|
||||
|
||||
**The KID** is in the capture session:
|
||||
|
||||
```bash
|
||||
./bin/drm capture --app rte --channel chanone --auto-play --wvd data/device.wvd
|
||||
jq -r '.kid' outputs/rte/latest/session.json
|
||||
```
|
||||
|
||||
Convert it to dashed UUID form for the `kids:` map
|
||||
(`8-4-4-4-12`), e.g. `df1633821dddfdd5bec9822c1ec0f052` becomes
|
||||
`df163382-1ddd-fdd5-bec9-822c1ec0f052`. Either form is accepted, but UUID form is
|
||||
easier to read.
|
||||
|
||||
**The origin** is the Smooth Streaming base URL. Find it in the discover traffic:
|
||||
|
||||
```bash
|
||||
grep -oE 'https?://[^"]+\.isml[^"]*' outputs/discover/*/appproxy_traffic.jsonl \
|
||||
| sed -E 's#(\.isml).*#\1/#' | sort -u
|
||||
```
|
||||
|
||||
The last path element before `.isml` is the encoder channel id, which becomes the
|
||||
map key. So `https://host/live/tc-1/vc11/vc11.isml/` is keyed `vc11`.
|
||||
|
||||
**Pair them up** by capturing each channel in turn and noting which KID appeared:
|
||||
|
||||
```bash
|
||||
for ch in chanone chantwo; do
|
||||
./bin/drm capture --app rte --channel $ch --auto-play --wvd data/device.wvd
|
||||
echo "$ch -> $(jq -r .kid outputs/rte/latest/session.json)"
|
||||
done
|
||||
```
|
||||
|
||||
Then confirm the mapping resolves:
|
||||
|
||||
```bash
|
||||
go -C apps/modules test -tags live ./rte/ -v
|
||||
```
|
||||
|
||||
That test fetches each configured origin's manifest, checks the KID resolves back
|
||||
to its channel, and verifies the synthetic manifest lands on the live encoder's
|
||||
segment grid. If a KID does not resolve, `kids:` and `origins:` disagree.
|
||||
|
||||
### `ca_hash`
|
||||
|
||||
The subject hash of the MITM CA, which is what the Magisk mount installs as
|
||||
`<hash>.0`. `6c3578b4` is the bundled CA; change it only if you generated your own.
|
||||
|
||||
```bash
|
||||
adb shell 'ls /system/etc/security/cacerts/'
|
||||
```
|
||||
|
||||
## Optional tuning
|
||||
|
||||
All of these have working defaults — set them only if the app changes.
|
||||
|
||||
```yaml
|
||||
encoder_channel_re: '^(vc|channel)\d+$' # which origin ids use the encoder timeline
|
||||
origin_marker: .isml # path element identifying an origin BaseURL
|
||||
hero_min_area: 200000 # smallest node accepted as the hero Play
|
||||
|
||||
ui:
|
||||
launch_desc_contains: ["live tab", "header logo"]
|
||||
live_tab_desc_re: ["Live tab"]
|
||||
|
||||
timeouts:
|
||||
launch_wait_ui: 25s
|
||||
live_tab: 30s
|
||||
chip_wait: 20s
|
||||
play_wait: 15s
|
||||
playback: 45s
|
||||
|
||||
synthetic:
|
||||
video_timescale: 600
|
||||
audio_timescale: 48000
|
||||
video_name: video
|
||||
audio_name: audio_128k
|
||||
video_bandwidth: 6000000
|
||||
audio_bandwidth: 128000
|
||||
width: 1920
|
||||
height: 1080
|
||||
live_edge_offset_s: 12
|
||||
window_segments: 6
|
||||
```
|
||||
|
||||
The `synthetic` block describes the origin encoder. Its defaults match a common
|
||||
Smooth-to-DASH setup; if your origin uses different stream names or bitrates, read
|
||||
them off the origin manifest:
|
||||
|
||||
```bash
|
||||
curl -s 'https://<origin>/live/<path>/vc11/vc11.isml/Manifest' | head -40
|
||||
```
|
||||
|
||||
`StreamIndex Name="…"` gives `video_name` / `audio_name`, and `Bitrate="…"` gives
|
||||
the bandwidths. Segment duration and phase are learned at runtime, not configured.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
./bin/drm modules # channel count should match your file
|
||||
./bin/drm capture --app rte --channel chanone --auto-play --wvd data/device.wvd
|
||||
go -C apps/modules test -tags live ./rte/ -v
|
||||
```
|
||||
|
||||
A good capture yields `auth`, `pid`, `pssh` and `mpd`, and a single `KID:KEY` whose
|
||||
KID matches the `kids:` entry for that channel's encoder.
|
||||
Loading…
Add table
Add a link
Reference in a new issue