diff --git a/agent_reach/channels/youtube.py b/agent_reach/channels/youtube.py index aaae963..17332f1 100644 --- a/agent_reach/channels/youtube.py +++ b/agent_reach/channels/youtube.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -"""YouTube — check if yt-dlp is available.""" +"""YouTube — check if yt-dlp is available with JS runtime.""" +import os import shutil from .base import Channel @@ -17,6 +18,23 @@ class YouTubeChannel(Channel): return "youtube.com" in d or "youtu.be" in d def check(self, config=None): - if shutil.which("yt-dlp"): - return "ok", "可提取视频信息和字幕" - return "off", "yt-dlp 未安装。安装:pip install yt-dlp" + if not shutil.which("yt-dlp"): + return "off", "yt-dlp 未安装。安装:pip install yt-dlp" + # Check JS runtime + has_js = shutil.which("deno") or shutil.which("node") + if not has_js: + return "warn", ( + "yt-dlp 已安装但缺少 JS runtime(YouTube 必须)。\n" + " 安装 Node.js 或 deno,然后运行:agent-reach install" + ) + # Check yt-dlp config for --js-runtimes + ytdlp_config = os.path.expanduser("~/.config/yt-dlp/config") + has_deno = shutil.which("deno") + if not has_deno and os.path.exists(ytdlp_config): + with open(ytdlp_config, "r") as f: + if "--js-runtimes" not in f.read(): + return "warn", ( + "yt-dlp 已安装但未配置 JS runtime。运行:\n" + " mkdir -p ~/.config/yt-dlp && echo '--js-runtimes node' >> ~/.config/yt-dlp/config" + ) + return "ok", "可提取视频信息和字幕" diff --git a/agent_reach/cli.py b/agent_reach/cli.py index b734130..c484416 100644 --- a/agent_reach/cli.py +++ b/agent_reach/cli.py @@ -419,6 +419,25 @@ def _install_system_deps(): except Exception: print(" ⬜ undici install failed (optional — xreach may not work behind proxies)") + # ── yt-dlp JS runtime config (YouTube requires external JS runtime) ── + if shutil.which("node"): + ytdlp_config_dir = os.path.expanduser("~/.config/yt-dlp") + ytdlp_config = os.path.join(ytdlp_config_dir, "config") + needs_config = True + if os.path.exists(ytdlp_config): + with open(ytdlp_config, "r") as f: + if "--js-runtimes" in f.read(): + needs_config = False + print(" ✅ yt-dlp JS runtime already configured") + if needs_config: + try: + os.makedirs(ytdlp_config_dir, exist_ok=True) + with open(ytdlp_config, "a") as f: + f.write("--js-runtimes node\n") + print(" ✅ yt-dlp configured to use Node.js as JS runtime (YouTube)") + except Exception: + print(" ⬜ Could not configure yt-dlp JS runtime (YouTube may not work)") + def _install_system_deps_safe(): """Safe mode: check what's installed, print instructions for what's missing.""" diff --git a/agent_reach/skill/SKILL.md b/agent_reach/skill/SKILL.md index 4b9e15b..f737290 100644 --- a/agent_reach/skill/SKILL.md +++ b/agent_reach/skill/SKILL.md @@ -93,7 +93,8 @@ xreach tweets @username --json -n 20 ### YouTube (yt-dlp) -> ⚠️ 服务器 IP 可能触发 YouTube 反爬("Sign in to confirm you're not a bot")。遇到时加 `--cookies-from-browser chrome` 或通过代理。 +> ⚠️ yt-dlp 需要 JS runtime 才能下载 YouTube。`agent-reach install` 会自动配置 Node.js 作为 runtime。 +> 如果遇到 "Sign in to confirm you're not a bot",是 IP 被 YouTube 反爬,换代理或加 cookies。 ```bash # Get video metadata @@ -106,8 +107,8 @@ yt-dlp --write-sub --write-auto-sub --sub-lang "zh-Hans,zh,en" --skip-download - # Search (yt-dlp ytsearch) yt-dlp --dump-json "ytsearch5:query" -# If blocked ("Sign in to confirm you're not a bot"): -yt-dlp --cookies-from-browser chrome --dump-json "URL" +# If "no JS runtime" warning: ensure Node.js is installed, then run: +# mkdir -p ~/.config/yt-dlp && echo "--js-runtimes node" >> ~/.config/yt-dlp/config ``` ### Bilibili (yt-dlp)