"""Download a static ffmpeg + ffprobe build for this OS into ./ffmpeg/bin. Uses the GPL builds from https://github.com/BtbN/FFmpeg-Builds (newest stable release branch). The app finds ./ffmpeg/bin automatically when run from source, and build.py --ffmpeg-dir ffmpeg/bin bundles them with the executable. """ from __future__ import annotations import json import re import shutil import sys import tarfile import tempfile import urllib.request import zipfile from pathlib import Path DEST = Path(__file__).resolve().parent.parent / "ffmpeg" / "bin" API = "https://api.github.com/repos/BtbN/FFmpeg-Builds/releases/latest" def pick_asset(assets: list[dict], plat: str) -> dict: ext = ".zip" if plat == "win64" else ".tar.xz" stable = [] for a in assets: m = re.fullmatch(rf"ffmpeg-n(\d+)\.(\d+)-latest-{plat}-gpl-\d+\.\d+{re.escape(ext)}", a["name"]) if m: stable.append(((int(m.group(1)), int(m.group(2))), a)) if stable: return max(stable, key=lambda x: x[0])[1] for a in assets: if a["name"] == f"ffmpeg-master-latest-{plat}-gpl{ext}": return a raise SystemExit(f"No ffmpeg build found for {plat}") def main() -> int: if sys.platform.startswith("win"): plat, exe = "win64", ".exe" elif sys.platform.startswith("linux"): plat, exe = "linux64", "" else: raise SystemExit("Only Windows and Linux are supported") with urllib.request.urlopen(API, timeout=30) as r: asset = pick_asset(json.load(r)["assets"], plat) print(f"Downloading {asset['name']} ({asset['size'] // 1_000_000} MB)...") with tempfile.TemporaryDirectory() as tmp: archive = Path(tmp) / asset["name"] with urllib.request.urlopen(asset["browser_download_url"], timeout=60) as r, open(archive, "wb") as f: shutil.copyfileobj(r, f) DEST.mkdir(parents=True, exist_ok=True) wanted = {f"ffmpeg{exe}", f"ffprobe{exe}"} if archive.suffix == ".zip": with zipfile.ZipFile(archive) as z: for info in z.infolist(): name = Path(info.filename).name if name in wanted and "/bin/" in info.filename: (DEST / name).write_bytes(z.read(info)) else: with tarfile.open(archive) as t: for m in t.getmembers(): name = Path(m.name).name if name in wanted and "/bin/" in m.name: with t.extractfile(m) as src, open(DEST / name, "wb") as out: shutil.copyfileobj(src, out) (DEST / name).chmod(0o755) missing = [n for n in wanted if not (DEST / n).is_file()] if missing: raise SystemExit(f"Archive did not contain {missing}") print(f"Installed ffmpeg and ffprobe into {DEST}") return 0 if __name__ == "__main__": sys.exit(main())