perf: run yt-dlp from a zipapp on a portable Python

Replaces the official yt-dlp_macos sidecar. That build is PyInstaller
one-file and unpacks 37MB on every invocation, costing ~8s per call on
this machine — ruled out signing, xattrs and thinning the universal
binary as causes, and it is 8% CPU over 8s, so it is the unpack itself.
Every stream resolve paid it.

The 3MB zipapp on a trimmed portable CPython starts in ~0.45s, a 17x
improvement; a real stream resolve goes from ~10s to ~2.4s. macOS ships
only Python 3.9 and yt-dlp needs 3.10+, hence bundling an interpreter.

yt-dlp is now resolved as an argv prefix rather than a path, so a system
install (a plain script, instant) still takes precedence.

Bundle grows 153MB -> 219MB, which buys back the responsiveness.
This commit is contained in:
vincent
2026-08-29 12:07:09 +02:00
parent 50ad908f1e
commit 9e9f71b31b
5 changed files with 130 additions and 45 deletions
+14 -3
View File
@@ -50,9 +50,17 @@ The binaries are not in git (~140 MB together). Fetch them once before building:
./scripts/fetch-binaries.sh
```
That pulls yt-dlp from its official GitHub release and static arm64 ffmpeg/ffprobe from
osxexperts.net — Homebrew's ffmpeg links a dozen dylibs and cannot be relocated into an
app bundle. Note that static ffmpeg builds are GPL, which matters if you redistribute.
That pulls static arm64 ffmpeg/ffprobe from osxexperts.net (Homebrew's ffmpeg links a
dozen dylibs and cannot be relocated into a bundle), the yt-dlp **zipapp**, and a portable
CPython from astral's python-build-standalone.
The interpreter is bundled deliberately. The official `yt-dlp_macos` binary is a
PyInstaller one-file build that unpacks 37 MB on *every* invocation — about eight seconds
per call, which every stream resolve would pay. The 3 MB zipapp on a portable interpreter
starts in under half a second. macOS ships only Python 3.9 and yt-dlp requires 3.10+,
which is why the interpreter has to come too.
Static ffmpeg builds are GPL, which matters if you redistribute.
## Running it
@@ -88,6 +96,9 @@ system by default; Settings offers System / Light / Dark.
- The bundled `yt-dlp` is frozen at build time and YouTube changes often. Re-run
`./scripts/fetch-binaries.sh` and rebuild, or install a newer one on your system —
the app prefers a system copy when it finds one.
- yt-dlp warns that extraction without a JavaScript runtime (deno) is deprecated. Format
lists are currently identical either way, but that may not hold; installing deno, or a
system yt-dlp that depends on it, is the escape hatch.
- Downloading videos is contrary to YouTube's Terms of Service.
## Tests