yt-dlp/yt-dlp · error · ExtractorError
Unable to download JS dependency (crypto-js/md5)
Error message
Unable to download JS dependency (crypto-js/md5)
What it means
Douyu signing dependency failure. Douyu stream URLs require an MD5-based signature computed by executing crypto-js 3.1.2 inside PhantomJS; DouyuBaseIE first downloads the md5 rollup from cdnjs.cloudflare.com or unpkg.com (both fatal=False) and caches it. If both downloads fail and no cache entry with min_ver 2024.07.04 exists, this unexpected error is raised. The bootcdn mirror was deliberately removed after the polyfill supply-chain attack.
Source
Thrown at yt_dlp/extractor/douyutv.py:36
url_or_none,
urlencode_postdata,
urljoin,
)
class DouyuBaseIE(InfoExtractor):
def _download_cryptojs_md5(self, video_id):
for url in [
# XXX: Do NOT use cdn.bootcdn.net; ref: https://sansec.io/research/polyfill-supply-chain-attack
'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/md5.js',
'https://unpkg.com/cryptojslib@3.1.2/rollups/md5.js',
]:
js_code = self._download_webpage(
url, video_id, note='Downloading signing dependency', fatal=False)
if js_code:
self.cache.store('douyu', 'crypto-js-md5', js_code)
return js_code
raise ExtractorError('Unable to download JS dependency (crypto-js/md5)')
def _get_cryptojs_md5(self, video_id):
return self.cache.load(
'douyu', 'crypto-js-md5', min_ver='2024.07.04') or self._download_cryptojs_md5(video_id)
def _calc_sign(self, sign_func, video_id, a):
b = uuid.uuid4().hex
c = round(time.time())
js_script = f'{self._get_cryptojs_md5(video_id)};{sign_func};console.log(ub98484234("{a}","{b}","{c}"))'
phantom = PhantomJSwrapper(self)
result = phantom.execute(js_script, video_id,
note='Executing JS signing script').strip()
return {i: v[0] for i, v in urllib.parse.parse_qs(result).items()}
def _search_js_sign_func(self, webpage, fatal=True):
# The greedy look-behind ensures last possible script tag is matched
return self._search_regex(
r'(?:<script.*)?<script[^>]*>(.*?ub98484234.*?)</script>', webpage, 'JS sign func', fatal=fatal)View on GitHub (pinned to 81ecd58b13)
Solutions
- Check reachability of cdnjs.cloudflare.com and unpkg.com (curl) and fix proxy/DNS; pass --proxy if yt-dlp must route through one.
- Update yt-dlp - the CDN list has changed before and may change again.
- Run once from an unrestricted network to warm the 'douyu/crypto-js-md5' cache; later runs reuse it.
- Note PhantomJS is required for the next step anyway - run yt-dlp --update-to nightly / check requirements so JS execution works.
Defensive patterns
Strategy: retry
Validate before calling
import urllib.request
def cdn_reachable(url: str = 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/md5.js') -> bool:
try:
urllib.request.urlopen(url, timeout=10)
return True
except OSError:
return False Try / catch
from yt_dlp.utils import ExtractorError
for attempt in range(3):
try:
info = ydl.extract_info(url, download=False)
break
except ExtractorError as e:
if 'JS dependency' not in str(e) or attempt == 2:
raise
time.sleep(2 ** attempt) Prevention
- Warm the douyu cache once from an unrestricted network so later runs need no CDN.
- Configure --proxy in environments where cdnjs/unpkg are blocked.
When it happens
Trigger: _download_webpage of both CDN URLs returns empty: cdnjs.cloudflare.com/unpkg.com unreachable (GFW, corporate proxy, DNS filtering), offline machine, or TLS interception; first run has no cached copy to fall back on.
Common situations: Running yt-dlp in mainland China where those CDNs are blocked; locked-down CI containers with no internet beyond douyu.com; air-gapped machines with a pre-min_ver cache.
Related errors
- The channel is auto-playing VODs
- The channel is not currently live
- {} said: {}
- PhantomJS not found, Please download it from https://phantom
- {note} failed: Unable to run PhantomJS binary
AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22).
Data as JSON: /api/errors/ca588e7b6c97c6ac.
Report an issue: GitHub.