一、一个黄色的Warning
事情开始于一个黄色的Warning。
WARNING: Signature solving failed.
视频还是能下。
只是终端一直在那里提醒。
很多人会选择忽略。
我也准备忽略。
但手已经放在键盘上了。
既然它出现了,总得知道为什么。
我以为五分钟能解决。
环境:
-
Python>=3.8
-
yt-dlp>=2024.03.10
-
Node.js>=22.22.0
-
FFmpeg>=8.1.1
-
curl-cffi>=0.15.0
二、两个小时以后
我先看了一下yt-dlp的文档。
签名失败,通常是因为目标平台更新了加密算法,而本地的解密器没有跟上。
解决方案有两个:
安装Node.js,用作JavaScript运行时来处理签名
启用Remote Components,让工具自动下载最新的解密脚本
我检查了一下系统:
$ node –version
v22.22.1
Node.js已经有了。
那我试试Remote Components。在下载器中添加自动检测和配置逻辑:
# downloader.py — build_ytdlp_options 函数中
def detect_js_runtime():
for runtime in ["node", "deno", "quickjs", "qjs"]:
path = shutil.which(runtime)
if path:
if runtime in ["quickjs", "qjs"]:
return f"quickjs:{path}"
return f"{runtime}:{path}"
return None
# 在 build_ytdlp_options 中调用
js_runtime = detect_js_runtime()
if js_runtime:
runtime_name, runtime_path = js_runtime.split(":", 1)
ydl_opts["js_runtimes"] = {runtime_name: {"path": runtime_path}}
ydl_opts["executables"] = {runtime_name: runtime_path}
ydl_opts["remote_components"] = ["ejs:github"]
这段代码会自动检测系统中的JavaScript运行时,并配置yt-dlp从GitHub下载最新的远程组件,从而解决签名解密问题。
跑了一下。
Warning少了两个。
但还有一个顽固地留着。
三、四个小时以后
剩下的那个Warning,指向了一个更深的问题。
不同客户端的TLS特征存在差异。部分平台会根据这些特征返回不同的数据格式和媒体流。
于是,同样一个请求,浏览器可以正常获取,脚本却可能收到完全不同的响应。
Python的requests库,在这些特征上太明显了。
解决方案是:让客户端行为更符合常见浏览器环境,减少因客户端差异导致的兼容性问题。
四、第二天
我找到了一个库叫 curl-cffi。
它能做的事情很简单:支持多种浏览器兼容目标,根据环境自动选择合适的客户端特征。
支持的客户端目标列表很长:
chrome-136
safari-18.4
firefox-145
edge-130
opera-112
……
一共37种。
我把它集成到了下载器里:
# downloader.py 中的相关代码
import random
def get_random_impersonate_target():
targets = get_available_impersonate_targets()
if not targets:
return None
return random.choice(targets)
# 在 build_ytdlp_options 中使用
if check_curl_cffi_available():
from yt_dlp import ImpersonateTarget
target = get_random_impersonate_target()
if target is not None:
ydl_opts["impersonate"] = target
每次请求,随机选择一个客户端兼容目标。
请求特征更接近真实浏览器,兼容性和稳定性明显提高。
五、第三天
配置好以后,我跑了一次测试。
python3 main.py download "https://www.某视频平台.com/shorts/sYDFysbXwyI"
终端输出:

终端一片寂静。
没有Warning。
没有Error。
只有干干净净的输出。
我盯着屏幕看了几秒钟。
一个Warning没了。
代码多了几百行。
README也多了一份。
六、后来
后来我发现,我有一个坏习惯。
遇到Warning,总想点进去看看。
明明视频已经能下了。
明明程序已经能跑了。
明明关掉终端就可以睡觉了。
但总觉得:
它为什么在那里?
很多项目,就是这么来的。
后来我打开项目目录。
media-downloader-cli/
├── main.py
├── downloader.py
├── config.py
├── requirements.txt
├── config/
└── downloads/
我突然想起来。
三天前,这个目录里只有三个文件。
现在已经变成了一个CLI工具。
后来朋友说:“整理一下,放GitHub吧。”
我想了想,也是。
也许以后还有人,会遇到同样的Warning。
如果它能帮别人少查几个小时资料,那这几百行代码也算没白写。
GitHub: https://github.com/EricFeng-super/media-downloader-cli
如果以后你也遇到同样的Warning:
Signature solving failed
429 Too Many Requests
JS Challenge
希望这个项目,能帮你少查几个小时资料。
如果真的帮到了,回来点个Star。
这样我就知道,那个黄色Warning,确实不止困扰过我一个人。
如果以后目标平台更新了校验逻辑,欢迎提 Issue。
我应该还会继续折腾。
【合规说明】
本文记录的是一次 CLI 工具的工程化调试过程,重点在于客户端兼容、依赖配置、错误排查和稳定性优化。
项目本身不提供、不存储、不传播任何视频内容。
具体能够访问哪些资源,取决于用户自身拥有的访问权限、目标平台规则,以及所在地区的法律法规。
请勿将本工具用于侵犯版权、违反平台服务协议或其他不合规用途。
【评论区开放】
你曾经为了一个Warning折腾过多久?最后是怎么解决的?欢迎在评论区分享你的Debug故事。



