127 lines
3.9 KiB
Markdown
127 lines
3.9 KiB
Markdown
# Private yt-dlp build
|
|
|
|
MeTube uses [yt-dlp](https://github.com/yt-dlp/yt-dlp) as its core downloader,
|
|
pinned to the official PyPI release via `pyproject.toml` / `uv.lock`.
|
|
|
|
There is currently an extractor bug in the official release that is not yet
|
|
fixed upstream. Until it is, the Docker image bakes a wheel built from a local,
|
|
patched yt-dlp checkout (`~/Dev/github/yt-dlp`) instead of the pinned release.
|
|
|
|
This document explains how the override works, how to build/update the private
|
|
wheel, and — most importantly — **how to switch back to the official build once
|
|
the upstream fix lands**.
|
|
|
|
---
|
|
|
|
## How the override works
|
|
|
|
1. `./build-ytdlp.sh` builds a wheel from a local yt-dlp checkout and stages it
|
|
as `vendor/yt_dlp-*.whl` (the versioned filename is required by `uv`).
|
|
2. The `Dockerfile`, right after `uv sync`, force-reinstalls that wheel over the
|
|
version pinned in `uv.lock`:
|
|
|
|
```dockerfile
|
|
COPY vendor ./vendor
|
|
RUN if [ -n "$(ls /app/vendor/yt_dlp-*.whl 2>/dev/null || true)" ]; then \
|
|
uv pip install --python /usr/local/bin/python --force-reinstall --no-deps /app/vendor/yt_dlp-*.whl; \
|
|
else \
|
|
echo "No private yt-dlp wheel in vendor/ - using pinned yt-dlp from uv.lock"; \
|
|
fi
|
|
```
|
|
|
|
3. `publish.sh` runs `./build-ytdlp.sh` before every build, so published images
|
|
always carry the patched build (and the publish aborts loudly if the local
|
|
checkout is missing).
|
|
4. The wheel is **git-ignored** (`/vendor/yt_dlp-*.whl`). `vendor/.gitkeep` and
|
|
`vendor/.gitignore` are committed so the directory always exists for
|
|
`COPY vendor ./vendor`.
|
|
|
|
## Building / updating the private wheel
|
|
|
|
```sh
|
|
./build-ytdlp.sh # builds from ~/Dev/github/yt-dlp
|
|
YTDLP_REPO=/path/to/yt-dlp ./build-ytdlp.sh # custom checkout path
|
|
```
|
|
|
|
Rebuild whenever the local checkout changes, then rebuild the image:
|
|
|
|
```sh
|
|
docker compose up -d --build --force-recreate
|
|
```
|
|
|
|
The script fails with a clear error if the configured checkout is missing.
|
|
|
|
---
|
|
|
|
## Switching back to the official build (when upstream fixes it)
|
|
|
|
### 1. Remove the Dockerfile override
|
|
|
|
Delete the `COPY vendor` / `RUN uv pip install` block from `Dockerfile`
|
|
(added in the "Private yt-dlp build" section, right after `uv sync`).
|
|
|
|
### 2. Remove the build step from `publish.sh`
|
|
|
|
Delete the block:
|
|
|
|
```sh
|
|
# Bake the private yt-dlp build (see build-ytdlp.sh) into the image until the
|
|
# upstream fix lands. Fails loudly if the local checkout is missing.
|
|
./build-ytdlp.sh
|
|
```
|
|
|
|
### 3. Update the pinned version
|
|
|
|
Bump `yt-dlp` to the fixed release and re-resolve the lockfile:
|
|
|
|
```sh
|
|
uv add "yt-dlp[default,curl-cffi]@latest" # or pin the exact fixed version
|
|
uv lock
|
|
```
|
|
|
|
Commit the updated `pyproject.toml` and `uv.lock`.
|
|
|
|
### 4. Clean up the override artifacts
|
|
|
|
```sh
|
|
rm build-ytdlp.sh # no longer needed
|
|
rm -f vendor/yt_dlp-*.whl # delete any staged wheel
|
|
```
|
|
|
|
You may also remove the `vendor/` directory (`.gitkeep`, `.gitignore`) and the
|
|
`/vendor/yt_dlp-*.whl` entry from `.gitignore`.
|
|
|
|
### 5. Update the docs
|
|
|
|
Remove the "Private yt-dlp build" section from `DEPLOY.md` (and delete this file
|
|
if you no longer want the guide around).
|
|
|
|
### 6. Rebuild and verify
|
|
|
|
```sh
|
|
docker compose up -d --build --force-recreate
|
|
```
|
|
|
|
Confirm the installed version is the official release:
|
|
|
|
```sh
|
|
docker compose exec metube python3 -c "import yt_dlp; print(yt_dlp.version.__version__)"
|
|
```
|
|
|
|
### 7. Publish
|
|
|
|
When you next publish, `./publish.sh` will no longer stage a private wheel and
|
|
the image will use the official yt-dlp release.
|
|
|
|
---
|
|
|
|
## Verifying which build is running
|
|
|
|
The `/version` endpoint reports `METUBE_VERSION`; the yt-dlp version is logged
|
|
by the app at startup. To check inside a running container:
|
|
|
|
```sh
|
|
docker compose exec metube python3 -c \
|
|
"import yt_dlp, yt_dlp.extractor.spankbang as s; import inspect; print(yt_dlp.version.__version__, 'patched:', 'spankbang' in inspect.getsource(s).lower())"
|
|
```
|