"""E11.5 S3 — a Facebook cookie download stuck at "Cannot parse data" is retried as Chrome. Measured on dev (yt-dlp 2026.07.04, the owner's cookie): reel 806379462330494 fails with the cookie alone and extracts 2560p with `--impersonate chrome`; the reels that already download with the cookie keep their plain first attempt. These pin the attempt order through the real download loop (`pipeline._extract_with_fallback`, with yt-dlp faked at the `YoutubeDL` boundary), and that the LOCKED curl_cffi can actually impersonate — the pair only works inside yt-dlp's own version range, and outside it every target silently reports "unavailable". """ import pytest import yt_dlp from yt_dlp.networking.impersonate import ImpersonateTarget from app.downloads import adapters, pipeline _URL = "https://www.facebook.com/reel/806379462330494/?fs=e&fs=e" _WALL = ( "ERROR: [facebook] 806379462330494: Cannot parse data; please report this issue on " "https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template." ) _NO_FORMATS = "ERROR: [facebook] 2541212983053999: No video formats found!" def test_the_locked_curl_cffi_can_impersonate_chrome(): # YoutubeDL refuses to start when the target is unavailable — the same check a download makes. with yt_dlp.YoutubeDL({"impersonate": ImpersonateTarget.from_str("chrome"), "quiet": True}): pass @pytest.fixture def ydl(monkeypatch): """Fake `yt_dlp.YoutubeDL`: records each attempt's options and plays back `outcomes` in order.""" seen: list[dict] = [] outcomes: list = [] class FakeYDL: def __init__(self, opts): seen.append(opts) def __enter__(self): return self def __exit__(self, *exc): return False def extract_info(self, url, download): outcome = outcomes.pop(0) if isinstance(outcome, str): raise yt_dlp.utils.DownloadError(outcome) return outcome monkeypatch.setattr(pipeline.yt_dlp, "YoutubeDL", FakeYDL) monkeypatch.setattr(pipeline, "_touch_job", lambda job_id: None) monkeypatch.setattr(pipeline, "_set_job", lambda job_id, **fields: None) return seen, outcomes def _run(tmp_path, cookiefile): return pipeline._extract_with_fallback( 1, 1, _URL, {}, tmp_path, adapters.FacebookAdapter(), cookiefile=cookiefile ) def test_a_cookie_download_at_the_wall_is_retried_as_chrome(ydl, tmp_path): seen, outcomes = ydl outcomes += [_WALL, {"id": "806379462330494"}] assert _run(tmp_path, "/cookies.txt") == {"id": "806379462330494"} assert [o.get("impersonate") for o in seen] == [None, ImpersonateTarget.from_str("chrome")] assert all(o["cookiefile"] == "/cookies.txt" for o in seen) # the retry stays signed in def test_without_a_cookie_the_wall_is_the_login_wall_and_final(ydl, tmp_path): seen, outcomes = ydl outcomes += [_WALL] with pytest.raises(yt_dlp.utils.DownloadError): _run(tmp_path, None) assert len(seen) == 1 and "impersonate" not in seen[0] def test_other_facebook_failures_are_not_retried_as_chrome(ydl, tmp_path): seen, outcomes = ydl outcomes += [_NO_FORMATS] with pytest.raises(yt_dlp.utils.DownloadError): _run(tmp_path, "/cookies.txt") assert len(seen) == 1 and "impersonate" not in seen[0]