last30days-skill v2.1 版本解析:X 搜索内置化与 YouTube 字幕源的实现原理
本文基于 docs/v2.1-launch-copy.md 的 v2.1 发布说明,完整还原该版本的两大主线功能——内置 X(Twitter)搜索客户端与 YouTube 字幕(transcript)作为第四信息源——的设计动机、配置方式与源码级实现细节。读完后你可以理解 last30days-skill 如何在零 API 密钥的前提下接入 X 与 YouTube,并掌握 AUTH_TOKEN/CT0/XAI_API_KEY 的完整配置链路。
版本背景:Bird CLI 消失,v2.1 必须自给自足
v2.1 的发布动因写在文档开头:Bird CLI(@steipete/bird)已从 npm 上被弃用(deprecated),其 GitHub 仓库也被删除,且没有人 fork 后重新发布。这意味着 v2.0 时代依赖外部 bird CLI 的 X 搜索链路随时会断掉。v2.1 的解法是:在仓库内 vendor(内置)Bird v0.8.0 的一个"仅搜索"子集,用户不再需要安装任何外部 X 搜索工具。
当前仓库中该内置客户端位于 skills/last30days/scripts/lib/vendor/bird-search/,其 package.json 给出了权威版本信息:
{
"name": "bird-search",
"version": "0.8.0",
"description": "Vendored Bird CLI search subset for /last30days",
"engines": { "node": ">=22" },
"license": "MIT",
"attribution": "Based on @steipete/bird v0.8.0 by Peter Steinberger (MIT License)"
}
三个关键事实可以从这里确认:内置的是 v0.8.0、MIT 许可、运行前提是 Node.js 22+。这正好对应发布文案中"just Node.js 22+ plus AUTH_TOKEN and CT0"的表述。
第二个动因是 YouTube:v2.1 受 Peter Steinberger 的 yt-dlp + summarize 工具链启发,直接使用 yt-dlp(不引入 summarize 依赖)搜索 YouTube、抓取观看量并提取自动生成字幕,喂给合成引擎。零 API 密钥、零成本。
功能一:X 搜索完全内置
认证配置:AUTH_TOKEN 与 CT0
X 搜索优先使用显式环境变量认证,目的是让本地运行保持 headless,避免浏览器 cookie 弹窗和 macOS Keychain 提示。发布文案给出的推荐步骤是:在已登录 x.com 的浏览器中打开开发者工具,复制 x.com 域下的 auth_token 和 ct0 两个 cookie,保存为:
# ~/.config/last30days/.env 或 .claude/last30days.env
AUTH_TOKEN=your_auth_token
CT0=your_ct0_token
官方发布文案中给出的安装块 env 行也一致:
AUTH_TOKEN=... # recommended for X search
CT0=... # recommended for X search
XAI_API_KEY=xai-... # optional X fallback
xAI 回退路径:如果不愿意提供 AUTH_TOKEN 和 CT0,可以改设 XAI_API_KEY,走 xAI 的 x_search 后端。README 中同样把 XAI_API_KEY 列为 X 搜索的可选密钥路径之一(见 README.md 的源表与 keychain 存储示例)。
验证命令:确认内置客户端可认证,直接运行:
node ~/.claude/skills/last30days/scripts/lib/vendor/bird-search/bird-search.mjs --whoami
在仓库内路径对应为 skills/last30days/scripts/lib/vendor/bird-search/bird-search.mjs(注意 ~/.claude/skills/ 是 skill 安装目录,仓库内相对路径是 skills/last30days/)。
源码纵深:Python 侧如何驱动内置客户端
X 搜索的 Python 侧入口是 skills/last30days/scripts/lib/bird_x.py,值得关注的实现点有:
- 深度配置:
DEPTH_CONFIG = {"quick": 12, "default": 30, "deep": 60}控制每次搜索请求的结果数,分别对应 30/45/60 秒超时(bird_x.py#L48-L52)。 - 环境白名单:
_SUBPROCESS_ENV_ALLOWLIST精确限定了传给 Node 子进程的环境变量面——平台变量、Node TLS/代理配置,以及 X 会话 cookie(AUTH_TOKEN、CT0及其TWITTER_*别名)。.env中其他无关密钥一律不会到达这个被扫描排除的 vendor 代码(源码注释引用了 issue #1063,见 bird_x.py#L64-L78)。 - 强制禁用浏览器 cookie 回退:
_subprocess_env()中硬编码BIRD_DISABLE_BROWSER_COOKIES=1,保证正常管道运行不会触发 Safari/Chrome Keychain 弹窗——这正是发布文案"no browser-cookie prompts"承诺的底层实现。 - 反爬重试:Twitter 边缘节点偶尔返回 HTML 反爬拦截页而非 JSON,
_run_bird_search()对非 JSON stdout 最多重试 2 次、间隔 5 秒,并把该失败形态标记为 schema drift 而非"无结果"(bird_x.py#L346-L424)。 - 零结果重试阶梯:
search_x()在 0 结果时依次降级——先尝试多词 OR 组(("term A" OR "term B") since:DATE),再截短到前 2 个词,最后锚定到最强特征词(排除best/hot/latest等低信号词),宁可返回 0 也不扩散到无锚点的通用词(bird_x.py#L457-L511)。 - 探针:
probe_works()用from:x since:...发一条 1 结果探针,廉价验证认证是否真正能返回数据;网络超时会被判为"不确定"而不降级状态,避免误报故障(bird_x.py#L228-L256)。
认证状态如何被判定
skills/last30days/scripts/lib/env.py 负责把配置里的 AUTH_TOKEN/CT0 解析进运行时配置("first COMPLETE pair wins"——第一个成对出现的来源获胜),随后调用 bird_x.set_credentials() 注入模块级凭据;is_bird_authenticated() 返回的认证源字符串(如 env AUTH_TOKEN)最终出现在诊断输出中(见 env.py#L1067-L1075 附近逻辑)。这也解释了为什么 get_bird_status() 返回的 username 字段实际是认证来源标签。
功能二:YouTube 字幕作为第四信息源
使用方式:零密钥、零成本
启用 YouTube 源只需要安装 yt-dlp:
brew install yt-dlp # 或 pip install yt-dlp
安装后,/last30days 会自动搜索 YouTube、抓取观看量,并从头部视频提取自动生成字幕。首次运行向导(first-run setup wizard)也会自动完成 yt-dlp 安装——见 SKILL.md 中 Step 0 的流程说明(run_auto_setup() 会提取 cookie、安装 yt-dlp 与 Digg CLI,零交互)。
深度配置与字幕预算
skills/last30days/scripts/lib/youtube_yt.py 中的两个表定义了工作预算:
DEPTH_CONFIG = {"quick": 6, "default": 8, "deep": 40} # 搜索/抓取的候选视频数
TRANSCRIPT_LIMITS = {"quick": 0, "default": 2, "deep": 8} # 实际提取字幕的视频数上限
即 quick 档只搜视频拿元数据不抓字幕,default 档对前 2 个视频提取字幕,deep 档对前 8 个提取。关于字幕长度:发布文案中写的是"截断到每视频约 500 词",而当前仓库实现的截断常量为 TRANSCRIPT_MAX_WORDS = 5000(youtube_yt.py#L59),说明该阈值在 v2.1 之后上调过,以仓库当前值为准。
字幕提取的技术链路
search_youtube() 通过 ytsearchN:<core_topic> 让 yt-dlp 直接输出 JSON 元数据,解析出 view_count、like_count、comment_count、upload_date、时长与描述,然后:
- 软日期过滤:不加
--dateafter(YouTube 搜索按相关性排序,严格日期过滤对常青主题常返回 0 条),改为 Python 侧软过滤——窗口内结果 ≥3 条时只保留窗口内,否则全部保留(youtube_yt.py#L520-L532 与 L607-L613)。 - 按观看量降序排序,头部视频优先进入字幕提取队列。
- 字幕抓取:yt-dlp
--write-auto-subs --sub-lang en,es,pt --sub-format vtt;语言优先级可经LAST30DAYS_YT_SUB_LANGS调整(默认en,es,pt)。非零退出码被明确判定为"真实抓取错误(限流/机器人验证/网络)"而非"无字幕",瞬态错误按每视频错位的退避(2.0 * (attempt+1) + 0~1s抖动)重试 2 次(youtube_yt.py#L836-L918)。 - 并发与搜索缓存:进程级信号量把并发 yt-dlp 子进程限制在 2(
_YTDLP_MAX_CONCURRENT = 2),防止比较模式(comparison fan-out)下相同 IP 踩踏 YouTube 限流;同一次运行内相同查询经 inflight 合并 + 缓存去重(youtube_yt.py#L77-L87)。 - 高光抽取:
extract_transcript_highlights()过滤口播填充词(subscribe、welcome back 等),按具体度(数字、专有名词、主题词重叠)为句子打分,取 Top 5 可引用片段进入合成。
此外,源码还支持两个发布文案未提的运维能力(从源码结构看属于后来的增强):LAST30DAYS_YOUTUBE_SSH_HOST 可将 yt-dlp 路由到住宅 IP 的远程主机以绕开数据中心 IP 的 bot-wall(youtube_yt.py#L302-L338),以及默认注入 player_client=android 的 extractor-args 以绕过 web bot-gate(youtube_yt.py#L344-L399)。
统一的评分管道
发布文案强调:"YouTube 走与 Reddit 和 X 相同的评分管道——相关性、时效性、互动量。" 源码印证了这一点:每条视频在解析时就计算 relevance(token_overlap_relevance,与 bird_x.py 的 _compute_relevance 同源),engagement 携带 views/likes/comments,date 提供时效信号——三者随后进入与社交帖子一致的排序与融合阶段。字幕则与社交帖子一起喂给合成引擎,"一条 20 分钟评测包含的信号量是一条推文的 10 倍"这一卖点由此落地。
输出契约与社区沟通
发布文案还固定了两处对外输出格式,供后续版本保持一致:
SKILL.md 状态行(源统计输出格式):
├─ 🔵 X: {N} posts │ {N} likes │ {N} reposts
面向 issue 回复与社交发布的核心信息点(原文档保留的沟通模板,供维护者参考):
- 对 GitHub issue #19 的回复要点:Bird 已弃用且仓库被删;v2.1 直接内置 X 搜索,无需外部 CLI、无需
npm install、无需 brew,只需 Node.js 22+ 与AUTH_TOKEN/CT0(或XAI_API_KEY回退);同时新增 YouTube 作为第四源;推荐一次性从 x.com 复制 cookie 存入 env 以避开浏览器 cookie 与 Keychain 弹窗。 - 社媒短版(280 字符内)与 thread 版的四个帖子:分别讲 YouTube 字幕源、X 搜索内置化、统一评分管道与零成本("Just
brew install yt-dlp")、以及试用方式/last30days [any topic]——"Reddit + X + YouTube + Web. Four sources, one command."
适用前提与限制
以当前仓库内容为准,复现 v2.1 这两项能力需要满足:X 搜索要求 Node.js 22+(engines 字段)且 AUTH_TOKEN 与 CT0 成对出现才会被判为已认证;YouTube 源要求本机(或配置的 SSH 远程主机)装有 yt-dlp,且 quick 档不提取字幕(TRANSCRIPT_LIMITS.quick = 0)。YouTube 抓取走公共数据接口、无 API 密钥,但受 YouTube 限流与 bot-gate 影响,源码为此内置了重试、退避与并发限制;X 搜索同样可能遭遇反爬拦截页,客户端已做非 JSON 重试与失败形态分类。两项功能均由 skills/last30days/SKILL.md 的首次运行向导自动完成依赖安装,配置则集中存放于 ~/.config/last30days/.env 或 .claude/last30days.env。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00