Generalize URL handling beyond YouTube to any yt-dlp-supported site
(SoundCloud, Bandcamp, etc), single tracks and playlists/sets/albums.
- probe_url(): one yt-dlp --flat-playlist probe classifies playlist vs track
and returns per-entry Hits; YouTube playlists still use ytmusicapi.
- _track_url(): YouTube tracks keep the music.youtube album-art URL; other
platforms download via their native entry URL (no more videoId reconstruction).
- Per-source folders: <root>/<artist>/<extractor>/ (soundcloud/bandcamp/youtube)
instead of hardcoded youtube; download_single derives source from metadata.
- download_hits() downloads pre-probed Hits; API probes once and passes hits
into the job closure. Replaces YouTube-only is_playlist_url/expand_playlist.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Defensive access guards against download_single returning ok=True
without title/artist keys, avoiding a KeyError in the job worker.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Live end-to-end test surfaced two bugs in youtube tagging:
- `--replace-in-metadata artist .* NAME` matched twice and doubled the
artist tag (e.g. "SLVMLORDSLVMLORD"). Anchor with ^.*$ to match once.
- Use only the first artist when several are present (SLVMLORD, not
"SLVMLORD, Travis Bradley, ...") for both the embedded tag and the
spoken/echoed API messages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>