87 lines
4.8 KiB
Python
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()
|