fix(downloads): a site the downloader no longer understands says so, and offers a retry
yt-dlp asks for a bug report on an extraction failure it did not expect: the site answered in a way its extractor does not read (measured on a TikTok link: fails on every attempt under yt-dlp 2026.07.04, downloads under 2026.08.19). That failure read as "Something went wrong" with no retry; it is now its own category, site_changed, with a Retry in the failure window. A contract test holds every failure category to its copy in both languages.
This commit is contained in:
@@ -5,6 +5,14 @@ from app.downloads import errors as dlerrors
|
||||
from app.downloads.errors import classify
|
||||
|
||||
|
||||
# Verbatim from dev job 128 (2026-10-09, yt-dlp 2026.07.04); the same link downloads under 2026.08.19.
|
||||
_TIKTOK_UNEXPECTED = (
|
||||
"ERROR: [TikTok] 7418778475890232609: Unexpected response from webpage request; please report "
|
||||
"this issue on https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue "
|
||||
"template. Confirm you are on the latest version using yt-dlp -U"
|
||||
)
|
||||
|
||||
|
||||
def test_real_ytdlp_messages_map_to_categories():
|
||||
# Verbatim-shaped yt-dlp / ffmpeg output → the category the UI explains.
|
||||
cases = {
|
||||
@@ -32,6 +40,7 @@ def test_real_ytdlp_messages_map_to_categories():
|
||||
"The source file is missing.": "source_missing",
|
||||
"ERROR: unable to download video data: HTTP Error 403: Forbidden": "network",
|
||||
"ERROR: Unable to download webpage: <urlopen error timed out>": "network",
|
||||
_TIKTOK_UNEXPECTED: "site_changed",
|
||||
}
|
||||
for msg, expected in cases.items():
|
||||
assert classify(msg) == expected, f"{msg!r} → {classify(msg)!r}, expected {expected!r}"
|
||||
@@ -211,13 +220,25 @@ def test_our_post_without_a_video_verdict_names_the_group_link():
|
||||
|
||||
|
||||
def test_a_catalog_entry_never_leaves_its_host():
|
||||
# "Cannot parse data" is yt-dlp's wording for a broken extractor on every site.
|
||||
# "Cannot parse data" is yt-dlp's wording for a broken extractor on every site: elsewhere it is
|
||||
# only the category — the site changed under the extractor.
|
||||
other = _FB_PARSE.replace("[facebook]", "[vimeo]")
|
||||
assert dlerrors.diagnose(other, url="https://vimeo.com/1") == ("unknown", None)
|
||||
assert dlerrors.diagnose(other, url="https://vimeo.com/1") == ("site_changed", None)
|
||||
# The Facebook text for a link that is not Facebook's (a look-alike host) is not the Facebook wall.
|
||||
assert dlerrors.diagnose(_FB_PARSE, url="https://facebook.com.evil/reel/1") == ("unknown", None)
|
||||
assert dlerrors.diagnose(_FB_PARSE, url="https://facebook.com.evil/reel/1") == (
|
||||
"site_changed",
|
||||
None,
|
||||
)
|
||||
# No link known: the category only.
|
||||
assert dlerrors.diagnose(_FB_PARSE) == ("unknown", None)
|
||||
assert dlerrors.diagnose(_FB_PARSE) == ("site_changed", None)
|
||||
|
||||
|
||||
def test_a_bug_report_request_keeps_the_more_specific_category():
|
||||
# yt-dlp asks for the bug report on these too; what they say about the media wins.
|
||||
assert classify(_FB_NO_FORMATS) == "format_unavailable"
|
||||
assert classify("ERROR: [x] 1: Unable to extract title; please report this issue") == (
|
||||
"format_unavailable"
|
||||
)
|
||||
|
||||
|
||||
def test_diagnose_falls_back_to_the_category():
|
||||
|
||||
Reference in New Issue
Block a user