Repository navigation
v0.3.0 — Python 3.14, security backlog cleared, Maple Mono UI
Maintenance and hardening release on top of v0.2.3. The backlog of 13 stale Dependabot PRs is cleared, every known vulnerability in both lockfiles is gone, the runtime moves to Python 3.14, and the release pipeline no longer publishes images that failed CI.
No API changes. /api/info and /api/download behave exactly as before — verified against a real video on every step of the way.
⚠️ Breaking for local development
requires-python is now >=3.14 and mise.toml pins python = "3.14". Contributors on 3.12 will need to re-run mise install and rebuild .venv. Container users are unaffected: the image ships its own interpreter.
If mise install fails with Python installation is missing a 'lib' directory, your mise is too old to pick the right precompiled CPython flavor for 3.14 — run mise self-update (fixed as of 2026.9.12).
Security
pip-audit --strict went from 15 vulnerabilities across 3 packages to 0; npm audit from 5 (3 high, 2 moderate) to 0. None of the vulnerable code paths were reachable from this service's API, but they gated CI and all sat on the request path.
| Package | Fixed | Advisories |
|---|---|---|
| yt-dlp | 2026.3.17 → 2026.8.19 | GHSA-69qj-pvh9-c5wg, CVE-2026-50019, CVE-2026-50023, CVE-2026-50574, CVE-2026-55404 |
| starlette | 1.2.1 → 1.6.0 | CVE-2026-54283 (high), CVE-2026-54282 |
| anyio | 4.13.0 → 4.15.1 | CVE-2026-63374 (critical), CVE-2026-64847 |
| postcss | 8.5.15 → 8.5.28 | CVE-2026-73646 (high), CVE-2026-69153 |
| nanoid | 3.3.12 → 3.3.19 | CVE-2026-67214, CVE-2026-67213 |
| ws (via happy-dom) | 8.20.0 → 8.21.3 | GHSA-96hv-2xvq-fx4p (high) |
| node (build stage) | 26.3.0 → 26.9.0-alpine | covers the 26.3.1 and 26.5.1 security releases |
Hardening: yt-dlp subprocesses now pass --ignore-config (#81). A yt-dlp.conf picked up from ~/.config/yt-dlp, ~/.yt-dlp, /etc/yt-dlp or beside the binary could otherwise inject --exec, an external downloader, a cookie file, or -P/-o — the last of which would write media to disk and break the project's no-disk-I/O guarantee.
Repository settings: Dependabot alerts and security updates are now enabled. Every advisory above is transitive, so none of them would have opened a PR on their own.
Runtime
- Python 3.12.13 → 3.14.7 (#74), with
mise.toml,requires-python, ruff'starget-version, both Dockerfile stages, the README and both lockfiles moved together. Regenerating the lockfiles under 3.14 changed no package versions. - Deno bin-2.8.2 → 2.9.7 (#51) — the JS runtime yt-dlp uses for YouTube player challenges.
- uvicorn 0.49.0 → 0.53.0 (#73, #75), fastapi 0.136.3 → 0.141.1 (#72).
fastapi 0.137 turned router.routes into a tree, which changes how slowapi's middleware resolves handlers. The outcome is unchanged — rate limiting is performed by the @limiter.limit decorators either way — and test_returns_429_after_info_limit_exceeded covers it.
Interface
- The UI is now set in Maple Mono (#78), by name only. No webfont is shipped: the CN build is 20.4 MB per weight with no upstream woff2, and a CDN would leak viewers' IPs, which is the opposite of what this service is for. Anyone with the font installed sees it; everyone else gets their platform's monospace face. CJK video titles fall back cleanly to the system face.
Build and release pipeline
- GHCR publishes only after CI passes (#77). The publish job used to trigger on push to main independently of every check — during this release cycle alone it would have published ~13 times, several while the audit was red. It is now a
needs-gated job insideci.yaml, and CI also runs onv*tags so a tagged release is validated before it ships. This release is the first to go through that path. npm auditandpip-auditare separate jobs (#77). As sequential steps, a frontend finding aborted the run beforepip-auditever executed, so a red X said nothing about the backend.- Dependabot is grouped and labelled (#76). The five labels the config had always requested did not exist, so every PR got a complaint comment instead. npm dev-dependencies group by minor+patch,
tailwindcssand@tailwindcss/*are pinned to the same group (updating one alone leaves a nested duplicate in the lockfile), docker patches group, actions group. pip stays ungrouped on purpose — its lockfiles must be regenerated by hand, one package at a time.
Toolchain
vitest 4.1.6 → 5.0.1, TypeScript 6.0.3 → 7.0.2, vite 8.0.12 → 8.3.0, happy-dom 20.9.0 → 20.14.5, tailwindcss 4.3.0 → 4.3.3, actions/cache v5 → v6, actions/checkout v6 → v7. All dev-only; the emitted bundle is byte-identical across the TypeScript 7 migration.
Verification
Every change in this release was checked against a real video through the full Docker stack, not just unit tests — the backend suite mocks yt-dlp, so version bumps to it cannot be validated any other way. /api/info returns 6 formats, /api/download returns valid mp4 and mp3 streams, and container logs are unchanged from the v0.2.3 baseline.
Backend 56 tests, frontend 20 tests, pre-commit run --all-files clean.
Pull the image
docker pull ghcr.io/fdff87554/youtube-downloader:0.3.0
# or the floating minor tag:
docker pull ghcr.io/fdff87554/youtube-downloader:0.3Digest: sha256:aa46bcd6fb62c67d2192e6c1bfda08a7875f88b584435071d25d410541daa8af
Run command and configuration are unchanged from v0.2.0 — see that release for the full setup notes.