fix(downloads): netloc-scoped adapter host match (review round 2)

resolve_adapter matched sources by loose substring over the netloc, so a
look-alike host ('myyoutube.com', 'youtube.com.evil') misresolved. Match the
host exactly or as a subdomain via a _host_is() helper, and identify from the
netloc of BOTH source_ref and yt-dlp's webpage_url — the latter by host only,
never a substring over its path. This also restores a host signal to the
early-fill path (resolve_adapter(None, None, info)), which has no source_ref,
so a Facebook asset's uploader_url no longer depends on extractor_key being
present in the progress-hook info_dict.

Tests: look-alike hosts stay generic while real subdomains resolve; a
webpage_url netloc identifies the source when extractor_key is absent.
This commit is contained in:
2026-08-13 01:18:25 +02:00
parent 883e8515b9
commit 2cd02eb1af
2 changed files with 44 additions and 15 deletions
+19
View File
@@ -40,6 +40,25 @@ def test_youtube_nocookie_host_still_gets_the_youtube_adapter():
assert resolve_adapter("url", "https://www.youtube-nocookie.com/embed/abc123").key == "youtube"
def test_lookalike_hosts_do_not_misresolve_but_subdomains_do():
# Netloc-scoped match: a look-alike host that merely CONTAINS the domain string is NOT the source.
assert resolve_adapter("url", "https://myyoutube.com/watch?v=x").key == "generic"
assert resolve_adapter("url", "https://youtube.com.evil.example/x").key == "generic"
assert resolve_adapter("url", "https://notreddit.com/r/x").key == "generic"
# …but real subdomains still resolve.
assert resolve_adapter("url", "https://m.youtube.com/watch?v=x").key == "youtube"
assert resolve_adapter("url", "https://music.youtube.com/watch?v=x").key == "youtube"
def test_webpage_url_netloc_identifies_source_when_extractor_key_absent():
# The early-fill path passes info with no source_ref; the webpage_url netloc still resolves the
# source even if extractor_key is missing from the progress-hook info_dict.
assert resolve_adapter(None, None, {"webpage_url": "https://www.facebook.com/reel/123"}).key == "facebook"
# A sibling source's name in the webpage_url PATH must not misresolve (host, not substring).
info = {"extractor_key": "Reddit", "webpage_url": "https://www.reddit.com/r/x/comments/y/youtube"}
assert resolve_adapter(None, None, info).key == "reddit"
def test_uploader_url_youtube_uses_channel_url():
a = YouTubeAdapter()
assert a.uploader_url({"channel_url": "https://youtube.com/@chan"}) == "https://youtube.com/@chan"