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.
62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
package tg4
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"drmdecryption/brightcove"
|
|
"drmdecryption/repo"
|
|
"drmdecryption/session"
|
|
"drmdecryption/wvkey"
|
|
)
|
|
|
|
// EnrichWithKeys fetches the HLS master, extracts the Widevine PSSH and resolves
|
|
// every content key through the local CDM. Brightcove returns multiple CONTENT
|
|
// keys and a downloader needs all of them.
|
|
func (a *App) EnrichWithKeys(info *session.Stream, python, wvd string) error {
|
|
if info == nil || info.MPD == "" {
|
|
return fmt.Errorf("missing manifest URL")
|
|
}
|
|
if info.LicenseURL == "" {
|
|
return fmt.Errorf("missing license_url")
|
|
}
|
|
if strings.TrimSpace(wvd) == "" {
|
|
return fmt.Errorf("key fetch requires --wvd (path to .wvd device file)")
|
|
}
|
|
body, err := brightcove.Get(info.MPD)
|
|
if err != nil {
|
|
return fmt.Errorf("hls master: %w", err)
|
|
}
|
|
pssh := brightcove.ExtractWidevinePSSH(body)
|
|
if pssh == "" {
|
|
return fmt.Errorf("no Widevine PSSH in HLS master")
|
|
}
|
|
info.PSSH = pssh
|
|
info.PrimaryKID = brightcove.PrimaryKID(body)
|
|
|
|
all, err := wvkey.FetchRawAll(wvkey.Options{
|
|
Python: python,
|
|
Script: filepath.Join(repo.Root(), "apps", "wvkey", "wvkey.py"),
|
|
WVD: wvd,
|
|
PSSH: pssh,
|
|
LicenseURL: info.LicenseURL,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(all) == 0 {
|
|
return fmt.Errorf("license returned no content keys")
|
|
}
|
|
info.Keys = all
|
|
info.Key = all[0]
|
|
if info.PrimaryKID != "" {
|
|
for _, k := range all {
|
|
if strings.HasPrefix(strings.ToLower(k), info.PrimaryKID+":") {
|
|
info.Key = k
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|