From 450c540f1adb4db92cd1a68a4fd46bd26f494159 Mon Sep 17 00:00:00 2001 From: fmbearmf <77757734+fmbearmf@users.noreply.github.com> Date: Sat, 30 Aug 2025 21:48:05 -0700 Subject: [PATCH] widevine-cdm: refactor x86_64-linux to use official sources, add update script --- pkgs/by-name/wi/widevine-cdm/package.nix | 1 + pkgs/by-name/wi/widevine-cdm/update-x86_64.py | 148 ++++++++++++++++++ pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix | 27 +++- 3 files changed, 168 insertions(+), 8 deletions(-) create mode 100755 pkgs/by-name/wi/widevine-cdm/update-x86_64.py diff --git a/pkgs/by-name/wi/widevine-cdm/package.nix b/pkgs/by-name/wi/widevine-cdm/package.nix index bae718940d20..11160260b665 100644 --- a/pkgs/by-name/wi/widevine-cdm/package.nix +++ b/pkgs/by-name/wi/widevine-cdm/package.nix @@ -5,6 +5,7 @@ }: let + # TODO: update aarch64 to use crx3 targets = lib.genAttrs [ "aarch64-linux" "x86_64-linux" diff --git a/pkgs/by-name/wi/widevine-cdm/update-x86_64.py b/pkgs/by-name/wi/widevine-cdm/update-x86_64.py new file mode 100755 index 000000000000..636d11a10f18 --- /dev/null +++ b/pkgs/by-name/wi/widevine-cdm/update-x86_64.py @@ -0,0 +1,148 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i python3 -p python3 + +from __future__ import annotations +import sys, os, json, base64, re, subprocess, shutil, argparse, urllib.request, time +from typing import Dict, Optional, Tuple + +DEFAULT_JSON = "https://raw.githubusercontent.com/mozilla/gecko-dev/master/toolkit/content/gmp-sources/widevinecdm.json" +ARCH_PATTERNS = { + "linux_x86_64": ["Linux_x86_64-gcc3", "Linux_x86_64", "linux_x86_64"], # trying to predict the future rn... + "linux_aarch64": ["Linux_aarch64-gcc3", "Linux_aarch64", "linux_aarch64"] +} + +def fetch_json(url: str) -> dict: + with urllib.request.urlopen(url) as r: + return json.load(r) + +def hex_to_sri(hexstr: str) -> str: + b = bytes.fromhex(hexstr) + return "sha512-" + base64.b64encode(b).decode() + +def find_widevine_vendor(data: dict) -> dict: + vendors = data.get("vendors") or {} + for key, value in vendors.items(): + if "gmp-widevinecdm" in key.lower(): + return value + + raise SystemExit("ERR: couldn't find a widevine vendor entry in JSON !") + +def judge_platforms(platforms: dict, patterns) -> Optional[Tuple[str, dict]]: + for plkey, plvalue in platforms.items(): + if plvalue.get("alias"): + continue + + low = plkey.lower() + for pat in patterns: + if pat.lower() in low: + return plkey, plvalue + + return None + +def normalize_fileurl(entry: dict) -> Optional[str]: + if entry.get("fileUrl"): + return entry["fileUrl"] + + m = entry.get("mirrorUrls") + if isinstance(m, list) and m: + return m[0] + + return None + +def extract_ver_from_url(url: str) -> Optional[str]: + m = re.search(r'[_-](\d+\.\d+\.\d+\.\d+)[_-]', url) + if m: + return m.group(1) + m = re.search(r'(\d+\.\d+\.\d+\.\d+)', url) + return m.group(1) if m else None + +def build_entry(pkey: str, pentry: dict) -> dict: + url = normalize_fileurl(pentry) + hv = pentry.get("hashValue") + + if not url or not hv: + raise SystemExit(f"ERR: platform {pkey} is missing a file URL or hash !") + + sri = hex_to_sri(hv) + version = extract_ver_from_url(url) + return {"platform_key": pkey, "url": url, "hashValue": hv, "sri": sri, "version": version} + + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--json-url", default="https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/main/toolkit/content/gmp-sources/widevinecdm.json") + args = ap.parse_args() + + print(f"# fetching {args.json_url} !", file=sys.stderr) + data = fetch_json(args.json_url) + vendor = find_widevine_vendor(data) + platforms = vendor.get("platforms") or {} # should never be null but moz could forseeably delete it + if not platforms: + raise SystemExit("ERR: no widevine platforms !") + + results = {} + for arch, patterns in ARCH_PATTERNS.items(): + found = judge_platforms(platforms, patterns) + if not found: + print(f"# WARN: no platform for {arch}. skipping !", file=sys.stderr) + continue + pkey, pentry = found + print(f"# found {arch} --> {pkey}", file=sys.stderr) + entry = build_entry(pkey, pentry) + results[arch] = entry + + if not results: + raise SystemExit("ERR: no linux platform entries !") + + linux_x64 = results["linux_x86_64"] + + try: + with open("x86_64-linux.nix", "w") as f: + f.write(f"""{{ + lib, + stdenv, + fetchurl, + go-crx3, +}}: + +stdenv.mkDerivation (finalAttrs: {{ + # Generated by update.py (don't edit this file manually) + pname = "widevine-cdm"; + version = "{linux_x64["version"]}"; + + src = fetchurl {{ + url = "{linux_x64["url"]}"; + hash = "{linux_x64["sri"]}"; + }}; + + nativeBuildInputs = [ go-crx3 ]; + + unpackPhase = '' + unpackDir="src" + cp "$src" "$unpackDir".crx # go-crx3 doesn't like .crx3 extensions + crx3 unpack "$unpackDir".crx + + cd "$unpackDir" + ''; + + installPhase = '' + runHook preInstall + + install -vD manifest.json $out/share/google/chrome/WidevineCdm/manifest.json + install -vD LICENSE $out/share/google/chrome/WidevineCdm/LICENSE.txt + install -vD _platform_specific/linux_x64/libwidevinecdm.so $out/share/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so + + runHook postInstall + ''; + + meta = import ./meta.nix lib; + passthru.updateScript = ./update-x86_64.py; +}})""") + + except Exception as e: + print("failed to write x86_64-linux.nix: ", e, file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix b/pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix index ae16e951c666..0bf431fa3efb 100644 --- a/pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix +++ b/pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix @@ -1,29 +1,40 @@ { lib, stdenv, - fetchzip, + fetchurl, + go-crx3, }: stdenv.mkDerivation (finalAttrs: { + # Generated by update.py (don't edit this file manually) pname = "widevine-cdm"; version = "4.10.2891.0"; - src = fetchzip { - # The download 404s - url = "https://web.archive.org/web/20250725071306/https://dl.google.com/widevine-cdm/4.10.2891.0-linux-x64.zip"; - hash = "sha256-ZO6FmqJUnB9VEJ7caJt58ym8eB3/fDATri3iOWCULRI="; - stripRoot = false; + src = fetchurl { + url = "https://edgedl.me.gvt1.com/edgedl/release2/chrome_component/aclxnidwwkj5di3vduduj2gqpgpq_4.10.2891.0/oimompecagnajdejgnnjijobebaeigek_4.10.2891.0_linux_b4hin3q5s66ws2322cyyfp35lu.crx3"; + hash = "sha512-8S/4FRQQmQAO9wJ7QGJg8KUVxUQgm5/oEl6l9N2/WGAdMCIqxBoBPrCkPadrpwQUpK0WYX2fIZ8Zzfx3lNm8lA=="; }; + nativeBuildInputs = [ go-crx3 ]; + + unpackPhase = '' + unpackDir="src" + cp "$src" "$unpackDir".crx # go-crx3 doesn't like .crx3 extensions + crx3 unpack "$unpackDir".crx + + cd "$unpackDir" + ''; + installPhase = '' runHook preInstall install -vD manifest.json $out/share/google/chrome/WidevineCdm/manifest.json - install -vD LICENSE.txt $out/share/google/chrome/WidevineCdm/LICENSE.txt - install -vD libwidevinecdm.so $out/share/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so + install -vD LICENSE $out/share/google/chrome/WidevineCdm/LICENSE.txt + install -vD _platform_specific/linux_x64/libwidevinecdm.so $out/share/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so runHook postInstall ''; meta = import ./meta.nix lib; + passthru.updateScript = ./update-x86_64.py; })