YouTube breaks old yt-dlp releases faster than songtrace is released.
songtrace now checks PyPI daily, and again after a download fails outright,
installs a newer stable release into its cache dir and tries it before the
bundled copy, which is never modified. yt-dlp runs in a subprocess through
its CLI, all from one module, so a cached release never mixes with the
imported one. ytdlp_version pins a release or turns updating off.
yt-dlp declares `dependencies = []` and puts everything in extras, so the
bare `yt-dlp` requirement installed it with no yt-dlp-ejs and no JavaScript
runtime. Without those it cannot solve YouTube's player challenges and falls
back to media URLs that YouTube rejects with HTTP 403, which is the failure
seen when adding a song. Require `yt-dlp[default,curl-cffi,deno]` instead;
the deno extra ships the JS runtime as a wheel, so the image needs no extra
apt packages.
Around that, make the stage survive the next time YouTube changes something:
the download is retried against each player client in `ytdlp_clients`
(default `["default", "tv"]`, the latter not needing a PO token) before
giving up, yt-dlp's retry counts are raised, and its own log lines are routed
into the job log so a PO-token demand can be told apart from a rate limit.
The final error names the running yt-dlp version, since a stale one is the
usual cause.
Cookies, TLS impersonation and a bgutil PO token provider URL are now config
fields, so an operator can work around a block without a code change.
`_classify_downloads` skips .part/.ytdl scratch files, which retries make far
more likely to be lying around.
- add test_rebuild_inherits_the_parents_cover: covers the cover_path
inheritance mechanism in the rebuild endpoint (Task 2's upload-retention
design relied on it, but nothing exercised it)
- tighten test_lineage_marker_survives_in_the_accessibility_tree to assert
the literal " rebuilt" screen-reader text, not just that rebuilt_from
is referenced somewhere in paintCard
- normalize submit's youtube_url/genre/language the same way rebuild does,
for symmetry, plus a pinning test
- pin acquire's stage outputs to [meta.json, audio.wav] in test_acquire.py,
since web.py's _require_source hardcodes those same filenames