Files
YouTubeDL/tools/collect_release_materials.py
DepressedCat 5f2aad00f4
Check extension and helper / check (push) Canceled after 0s
Publish YouTubeDL 1.4.5 and website on Gitea
2026-10-10 23:53:17 +03:00

87 lines
4.8 KiB
Python

"""Publish license texts and pinned upstream source materials alongside the helper.
Run after tools/build_bundle.py. This does not alter or install the helper.
Third-party FFmpeg dependency download/build recipes are preserved verbatim.
"""
from __future__ import annotations
import concurrent.futures
import hashlib
import json
import subprocess
import zipfile
from pathlib import Path
import requests
ROOT = Path(__file__).resolve().parent.parent
KIT = ROOT / ".build/kit"
CACHE = ROOT / ".build-cache/release-sources"
FFMPEG_REVISION = "17ec99894249a68444d145ea8870713a4fb7f342"
BUILD_REVISION = "8fc3fe09d1d84a10cecc2b08706e303e27e64834"
def download(item):
CACHE.mkdir(parents=True, exist_ok=True)
target = CACHE / item["file"]
if not target.is_file():
response = requests.get(item["url"], timeout=(20, 180))
response.raise_for_status()
target.write_bytes(response.content)
data = target.read_bytes()
checksum = hashlib.sha256(data).hexdigest()
if item.get("expectedSHA256") and item["expectedSHA256"] != checksum:
raise ValueError(f"Source hash mismatch: {item['file']}")
print(f"Source: {item['file']} ({len(data)} bytes)", flush=True)
return {**item, "sha256": checksum, "bytes": len(data)}
def main():
manifest = json.loads((ROOT / "dist/YouTubeDL-Helper-manifest.json").read_text(encoding="utf-8"))
sources = [
{"file": f"FFmpeg-{FFMPEG_REVISION}.tar.gz", "url": f"https://codeload.github.com/FFmpeg/FFmpeg/tar.gz/{FFMPEG_REVISION}", "component": "FFmpeg"},
{"file": f"FFmpeg-Builds-{BUILD_REVISION}.tar.gz", "url": f"https://codeload.github.com/yt-dlp/FFmpeg-Builds/tar.gz/{BUILD_REVISION}", "component": "FFmpeg build and dependency source recipes"},
]
for metadata in sorted((KIT / "runtime/python/Lib/site-packages").glob("*.dist-info/METADATA")):
fields = dict(line.split(": ", 1) for line in metadata.read_text(encoding="utf-8").splitlines() if line.startswith(("Name: ", "Version: ")))
name, version = fields["Name"], fields["Version"]
response = requests.get(f"https://pypi.org/pypi/{name}/{version}/json", timeout=30)
response.raise_for_status()
sdist = next((file for file in response.json()["urls"] if file["packagetype"] == "sdist"), None)
if sdist:
sources.append({"file": sdist["filename"], "url": sdist["url"], "expectedSHA256": sdist["digests"]["sha256"], "component": f"{name} {version}"})
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
records = list(pool.map(download, sources))
configuration = subprocess.run([str(KIT / "runtime/bin/ffmpeg.exe"), "-version"], capture_output=True, text=True, check=True).stdout
destination = ROOT / "dist/YouTubeDL-ThirdParty-Materials.zip"
with zipfile.ZipFile(destination,"w",zipfile.ZIP_DEFLATED) as archive:
for name in ("THIRD_PARTY.md", "LICENSE", "CONTRIBUTING.md"):
archive.write(ROOT / name, name)
archive.writestr("helper-manifest.json", json.dumps(manifest,indent=2))
archive.writestr("source-index.json", json.dumps(records,indent=2))
archive.writestr("FFmpeg-configuration.txt", configuration)
archive.writestr("SOURCE-README.txt", f"""YouTubeDL helper {manifest['version']}: upstream source materials and licenses.
The exact FFmpeg source revision is in sources/; FFmpeg-Builds scripts contain
the pinned download and build recipes for its third-party libraries.
Extract the FFmpeg-Builds source archive and follow its Docker build instructions.
Run ./download.sh win64 gpl-shared to fetch dependency sources; build.sh is the
corresponding build recipe. Read scripts.d, variants and util for configuration.
The supplied FFmpeg binary is unchanged from yt-dlp/FFmpeg-Builds.
Python and Node.js official sources:
https://www.python.org/ftp/python/3.13.14/Python-3.13.14.tgz
https://nodejs.org/dist/v24.21.0/node-v24.21.0.tar.xz
Python package source distributions are included where PyPI provides them.
The original installer source and Native Messaging helper source are in the
YouTubeDL repository. The root LICENSE governs original YouTubeDL materials.
Third-party components are distributed under their own licenses; see THIRD_PARTY.md.
""")
for record in records:
archive.write(CACHE / record["file"], "sources/" + record["file"])
for file in KIT.rglob("*"):
if not file.is_file(): continue
relative = file.relative_to(KIT)
if "licenses" in relative.parts or (".dist-info" in str(relative) and (file.name == "METADATA" or any(word in str(relative).lower() for word in ("license","copying","notice")))) or file.name == "LICENSE.txt":
archive.write(file,"licenses/" + str(relative).replace("\\","/"))
print(f"Materials: {destination.name} ({destination.stat().st_size} bytes)", flush=True)
if __name__ == "__main__": main()