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 1/3] 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; }) From 88a118c37ee95be6447b28b5775b977b72ad2499 Mon Sep 17 00:00:00 2001 From: fmbearmf <77757734+fmbearmf@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:06:08 -0700 Subject: [PATCH 2/3] widevine-cdm: refactor to use regex, various other update script changes --- pkgs/by-name/wi/widevine-cdm/update-x86_64.py | 81 +++++++++---------- pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix | 5 +- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/pkgs/by-name/wi/widevine-cdm/update-x86_64.py b/pkgs/by-name/wi/widevine-cdm/update-x86_64.py index 636d11a10f18..76a7becb15dd 100755 --- a/pkgs/by-name/wi/widevine-cdm/update-x86_64.py +++ b/pkgs/by-name/wi/widevine-cdm/update-x86_64.py @@ -4,11 +4,12 @@ from __future__ import annotations import sys, os, json, base64, re, subprocess, shutil, argparse, urllib.request, time from typing import Dict, Optional, Tuple +from pathlib import Path 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"] + "linux_x86_64": ["Linux_x86_64-gcc3"], + "linux_aarch64": ["Linux_aarch64-gcc3"] } def fetch_json(url: str) -> dict: @@ -67,11 +68,37 @@ def build_entry(pkey: str, pentry: dict) -> dict: version = extract_ver_from_url(url) return {"platform_key": pkey, "url": url, "hashValue": hv, "sri": sri, "version": version} +def subst_version(file: str, new_version: str) -> str: + return re.sub( + r'(?m)^(?P\s*)version\s*=\s*(?P["\'])(?P[^"\']*)(?P=q)\s*;', + lambda m: f'{m.group("ind")}version = {m.group("q")}{new_version}{m.group("q")};', + file, + count=1 + ) +def subst_src_url(file: str, new_url: str) -> str: + return re.sub( + r'(?m)^(?P\s*)url\s*=\s*(?P["\'])(?P[^"\']*)(?P=q)\s*;', + lambda m: f'{m.group("ind")}url = {m.group("q")}{new_url}{m.group("q")};', + file, + count=1 + ) + +def subst_src_hash(file: str, new_hash: str) -> str: + return re.sub( + r'(?m)^(?P\s*)hash\s*=\s*(?P["\'])(?P[^"\']*)(?P=q)\s*;', + lambda m: f'{m.group("ind")}hash = {m.group("q")}{new_hash}{m.group("q")};', + file, + count=1 + ) def main(): + WIDEVINE_DIR = Path(__file__).resolve().parent + DEFAULT_FILE = WIDEVINE_DIR / "x86_64-linux.nix" + 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") + ap.add_argument("file", type=Path, nargs="?", default=DEFAULT_FILE) + ap.add_argument("--json-url", default=DEFAULT_JSON) args = ap.parse_args() print(f"# fetching {args.json_url} !", file=sys.stderr) @@ -97,52 +124,16 @@ def main(): linux_x64 = results["linux_x86_64"] - try: - with open("x86_64-linux.nix", "w") as f: - f.write(f"""{{ - lib, - stdenv, - fetchurl, - go-crx3, -}}: + txt = args.file.read_text(encoding="utf-8") -stdenv.mkDerivation (finalAttrs: {{ - # Generated by update.py (don't edit this file manually) - pname = "widevine-cdm"; - version = "{linux_x64["version"]}"; + txt = subst_version(txt, linux_x64["version"]) - src = fetchurl {{ - url = "{linux_x64["url"]}"; - hash = "{linux_x64["sri"]}"; - }}; + txt = subst_src_url(txt, linux_x64["url"]) - 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) + txt = subst_src_hash(txt, linux_x64["sri"]) + args.file.write_text(txt, encoding="utf-8") + print("# updated", 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 0bf431fa3efb..c43c56322eb8 100644 --- a/pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix +++ b/pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix @@ -6,7 +6,7 @@ }: stdenv.mkDerivation (finalAttrs: { - # Generated by update.py (don't edit this file manually) + # version, src.url, and src.hash generated by update-x86_64.py pname = "widevine-cdm"; version = "4.10.2891.0"; @@ -35,6 +35,7 @@ stdenv.mkDerivation (finalAttrs: { runHook postInstall ''; - meta = import ./meta.nix lib; passthru.updateScript = ./update-x86_64.py; + + meta = import ./meta.nix lib; }) From ecec1b7411695b67fc7ca5538ae7dcce4fd59e14 Mon Sep 17 00:00:00 2001 From: fmbearmf <77757734+fmbearmf@users.noreply.github.com> Date: Mon, 1 Sep 2025 03:00:41 -0700 Subject: [PATCH 3/3] widevine-cdm: refactor --- pkgs/by-name/wi/widevine-cdm/update-x86_64.py | 40 ++----------------- pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix | 11 +++-- .../wi/widevine-cdm/x86_64-manifest.json | 6 +++ 3 files changed, 17 insertions(+), 40 deletions(-) create mode 100644 pkgs/by-name/wi/widevine-cdm/x86_64-manifest.json diff --git a/pkgs/by-name/wi/widevine-cdm/update-x86_64.py b/pkgs/by-name/wi/widevine-cdm/update-x86_64.py index 76a7becb15dd..4b18c1dd0b78 100755 --- a/pkgs/by-name/wi/widevine-cdm/update-x86_64.py +++ b/pkgs/by-name/wi/widevine-cdm/update-x86_64.py @@ -2,7 +2,7 @@ #! nix-shell -i python3 -p python3 from __future__ import annotations -import sys, os, json, base64, re, subprocess, shutil, argparse, urllib.request, time +import sys, os, json, base64, re, argparse, urllib.request, time from typing import Dict, Optional, Tuple from pathlib import Path @@ -66,35 +66,11 @@ def build_entry(pkey: str, pentry: dict) -> dict: sri = hex_to_sri(hv) version = extract_ver_from_url(url) - return {"platform_key": pkey, "url": url, "hashValue": hv, "sri": sri, "version": version} - -def subst_version(file: str, new_version: str) -> str: - return re.sub( - r'(?m)^(?P\s*)version\s*=\s*(?P["\'])(?P[^"\']*)(?P=q)\s*;', - lambda m: f'{m.group("ind")}version = {m.group("q")}{new_version}{m.group("q")};', - file, - count=1 - ) - -def subst_src_url(file: str, new_url: str) -> str: - return re.sub( - r'(?m)^(?P\s*)url\s*=\s*(?P["\'])(?P[^"\']*)(?P=q)\s*;', - lambda m: f'{m.group("ind")}url = {m.group("q")}{new_url}{m.group("q")};', - file, - count=1 - ) - -def subst_src_hash(file: str, new_hash: str) -> str: - return re.sub( - r'(?m)^(?P\s*)hash\s*=\s*(?P["\'])(?P[^"\']*)(?P=q)\s*;', - lambda m: f'{m.group("ind")}hash = {m.group("q")}{new_hash}{m.group("q")};', - file, - count=1 - ) + return {"platform_key": pkey, "url": url, "sri": sri, "version": version} def main(): WIDEVINE_DIR = Path(__file__).resolve().parent - DEFAULT_FILE = WIDEVINE_DIR / "x86_64-linux.nix" + DEFAULT_FILE = WIDEVINE_DIR / "x86_64-manifest.json" ap = argparse.ArgumentParser() ap.add_argument("file", type=Path, nargs="?", default=DEFAULT_FILE) @@ -124,15 +100,7 @@ def main(): linux_x64 = results["linux_x86_64"] - txt = args.file.read_text(encoding="utf-8") - - txt = subst_version(txt, linux_x64["version"]) - - txt = subst_src_url(txt, linux_x64["url"]) - - txt = subst_src_hash(txt, linux_x64["sri"]) - - args.file.write_text(txt, encoding="utf-8") + args.file.write_text(json.dumps(linux_x64, indent=2) + "\n", encoding="utf-8") print("# updated", file=sys.stderr) if __name__ == "__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 c43c56322eb8..35b83199467b 100644 --- a/pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix +++ b/pkgs/by-name/wi/widevine-cdm/x86_64-linux.nix @@ -5,14 +5,17 @@ go-crx3, }: +let + manifest = builtins.fromJSON (builtins.readFile ./x86_64-manifest.json); +in + stdenv.mkDerivation (finalAttrs: { - # version, src.url, and src.hash generated by update-x86_64.py pname = "widevine-cdm"; - version = "4.10.2891.0"; + version = manifest.version; 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=="; + url = manifest.url; + hash = manifest.sri; }; nativeBuildInputs = [ go-crx3 ]; diff --git a/pkgs/by-name/wi/widevine-cdm/x86_64-manifest.json b/pkgs/by-name/wi/widevine-cdm/x86_64-manifest.json new file mode 100644 index 000000000000..07fa91d5592b --- /dev/null +++ b/pkgs/by-name/wi/widevine-cdm/x86_64-manifest.json @@ -0,0 +1,6 @@ +{ + "platform_key": "Linux_x86_64-gcc3", + "url": "https://edgedl.me.gvt1.com/edgedl/release2/chrome_component/aclxnidwwkj5di3vduduj2gqpgpq_4.10.2891.0/oimompecagnajdejgnnjijobebaeigek_4.10.2891.0_linux_b4hin3q5s66ws2322cyyfp35lu.crx3", + "sri": "sha512-8S/4FRQQmQAO9wJ7QGJg8KUVxUQgm5/oEl6l9N2/WGAdMCIqxBoBPrCkPadrpwQUpK0WYX2fIZ8Zzfx3lNm8lA==", + "version": "4.10.2891.0" +}