Null-DRM-Official/apps/pkg/wvkey/wvkey.go
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

128 lines
3 KiB
Go

package wvkey
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
// Options for the Python wvkey.py helper.
type Options struct {
Python string // e.g. .venv/Scripts/python.exe
Script string // path to wvkey.py
WVD string
PSSH string
Auth string
PID string
LicenseURL string
UserAgent string
}
// Fetch runs wvkey.py --quiet (ModularDrm) and returns the first KID:KEY line.
func Fetch(opt Options) (string, error) {
lines, err := run(opt, false, false)
if err != nil {
return "", err
}
if len(lines) == 0 {
return "", fmt.Errorf("wvkey produced no KID:KEY")
}
return lines[0], nil
}
// FetchRaw runs wvkey.py --mode raw (Brightcove / octet-stream license).
func FetchRaw(opt Options) (string, error) {
lines, err := run(opt, true, false)
if err != nil {
return "", err
}
if len(lines) == 0 {
return "", fmt.Errorf("wvkey produced no KID:KEY")
}
return lines[0], nil
}
// FetchRawAll returns every CONTENT key from a raw license response.
func FetchRawAll(opt Options) ([]string, error) {
return run(opt, true, true)
}
func run(opt Options, raw, all bool) ([]string, error) {
py := opt.Python
if py == "" {
py = findPython()
}
script := opt.Script
if script == "" {
return nil, fmt.Errorf("wvkey script path required")
}
if strings.TrimSpace(opt.WVD) == "" {
return nil, fmt.Errorf("wvkey --wvd path required")
}
if strings.TrimSpace(opt.PSSH) == "" {
return nil, fmt.Errorf("wvkey --pssh required")
}
if strings.TrimSpace(opt.LicenseURL) == "" {
return nil, fmt.Errorf("wvkey --license-url required")
}
args := []string{
script,
"--wvd", opt.WVD,
"--pssh", opt.PSSH,
"--license-url", opt.LicenseURL,
"--quiet",
}
if raw {
args = append(args, "--mode", "raw")
} else {
args = append(args, "--mode", "modulardrm", "--auth", opt.Auth, "--pid", opt.PID)
}
if all {
args = append(args, "--all")
}
if opt.UserAgent != "" {
args = append(args, "--user-agent", opt.UserAgent)
}
cmd := exec.Command(py, args...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("wvkey failed: %w\n%s", err, strings.TrimSpace(stderr.String()))
}
var out []string
for _, line := range strings.Split(strings.TrimSpace(stdout.String()), "\n") {
line = strings.TrimSpace(line)
if strings.Count(line, ":") == 1 && len(line) > 40 {
out = append(out, line)
}
}
if len(out) == 0 {
return nil, fmt.Errorf("wvkey produced no KID:KEY (stderr=%s)", strings.TrimSpace(stderr.String()))
}
return out, nil
}
func findPython() string {
candidates := []string{
filepath.Join(".venv", "Scripts", "python.exe"),
filepath.Join(".venv", "bin", "python"),
"python3",
"python",
}
for _, c := range candidates {
if filepath.IsAbs(c) || strings.Contains(c, string(os.PathSeparator)) {
if st, err := os.Stat(c); err == nil && !st.IsDir() {
return c
}
continue
}
if p, err := exec.LookPath(c); err == nil {
return p
}
}
return "python"
}