欢迎光临
我们一直在努力

我本来只想修一个Warning,结果写了一个CLI工具

一、一个黄色的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故事。

    赞(0)
    未经允许不得转载:171主机测评 » 我本来只想修一个Warning,结果写了一个CLI工具
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址