80 lines
2.9 KiB
Python
80 lines
2.9 KiB
Python
"""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())
|