YT2BILI — YouTube 到 Bilibili 自动化搬运系统
摘要
YT2BILI v1.5 是一套 YouTube 到 Bilibili 的自动化搬运系统。基于 Cloudflare Workers 与 GitHub Actions,系统自动下载视频,通过 MiMo ASR 和 stable-ts 进行转录对齐,利用 LLM 翻译,并自动投稿 B 站。v1.5 版本修复了 26 项审核问题,优化了验证逻辑、队列清理及超时机制。
YT2BILI — YouTube 到 Bilibili 自动化搬运系统
项目文档 v1.5 适用于公司矩阵号自有视频的自动转录、翻译与投稿 最后更新:2026-07-06
版本 | 日期 | 变更摘要 |
|---|---|---|
v1.0 | 2026-07-06 | 初始版本 |
v1.1 | 2026-07-06 | 修复 ac_time_value 获取方式、音频/视频下载逻辑、安全设计、LLM 时间戳保护等 37 项问题;新增安全说明、故障排查、FAQ、成本估算、升级与备份、术语表等章节 |
v1.2 | 2026-07-06 | ASR 对接改为 MiMo |
v1.3 | 2026-07-06 | 时间戳方案升级为 stable-ts 强制对齐(±0.2s 词级精度);新增字幕模式开关(翻译/原语言/双字幕/无字幕);新增手动添加视频功能 |
v1.4 | 2026-07-06 | 修复第三轮审核 22 项问题:手动队列状态生命周期+清理机制;MAX_VIDEOS_PER_RUN 三处矛盾统一;Whisper 模型缓存+单例加载;format_timestamp 浮点进位 bug;srt_to_bili_subtitle lan 参数化;§16.3 翻译前置条件;MiMo ASR MIME 动态选择;ffmpeg 切分精度修复;超时表补充环境安装/模型下载时间 |
v1.5 | 2026-07-06 | 修复第四轮审核 26 项问题:validate_response 拆分为 ASR/翻译独立校验;手动队列清理逻辑分类明确;超时统一为 300 分钟;stage 字段三处统一为过去式;channel_id 语义冲突改为 channel_config_id;Pipeline POST 请求体结构定义;source_language 参数化+stable-ts 多语言映射;翻译条数不匹配自动拆分重试;Cookie Artifact 安全提示;processing 卡死保护;流水线各环节重试策略;部署指南补 wrangler 安装;动态裁剪算法;备份补全 manual_queue/status 键 |
目录
1. 项目概述
1.1 一句话描述
在 Web 后台填好所有配置后,系统定时自动从 YouTube 下载公司频道的新视频,通过 ASR 转录为字幕、LLM 翻译为中文,自动投稿到 B 站指定合集并挂载 CC 字幕,全程无需人工干预。
1.2 核心能力
能力 | 说明 |
|---|---|
YouTube 频道订阅 | 支持搜索添加或手动添加 YouTube 频道,按频道配置独立的 B 站投稿参数 |
自动下载 | 通过 yt-dlp 下载完整视频文件(供投稿)并提取音轨(供 ASR),支持 Cookie 下载受限内容 |
语音识别 | 调用 MiMo |
LLM 翻译 | 调用用户自有的 HTTPS 翻译 API,翻译字幕和标题,保持时间轴对齐(可按频道开关翻译) |
B 站自动投稿 | 视频上传 + 标题 + 分区 + 标签 + 简介 + 封面,纯 Cookie 鉴权 |
CC 字幕上传 | 通过 |
合集归档 | 投稿后自动将视频追加到指定合集的小节中 |
Cookie 自动续期 | 利用 |
Web 管理后台 | 单页配置所有信息,频道搜索、合集/分区下拉选择、状态监控、连通性测试 |
YouTube 频道搜索 | 通过 YouTube Data API v3 在后台搜索频道,无需手动查找 channel_id |
1.3 适用场景
公司矩阵号自有 YouTube 内容同步到 B 站
需要中文字幕的海外视频搬运
多频道、多合集的批量管理
2. 系统架构
2.1 架构总览
注意:Cookie 续期在流水线最前面执行(详见 §8),确保后续所有 B 站操作使用有效凭证。上图中 Cookie 续期排在 RSS 轮询之前。
2.2 设计原则
原则 | 说明 |
|---|---|
配置与执行分离 | 控制平面(Worker+KV)管理配置,数据平面(Actions)执行流水线 |
零服务器 | 全部基于免费 Serverless 服务,无需自建服务器 |
单页配置 | 所有填写项集中在同一页面,降低小白用户使用门槛 |
持续部署 | 代码推送主分支即自动部署 Worker,无需手动操作 |
幂等处理 | 通过去重表保证视频不会被重复处理 |
时间戳安全 | ASR 产生的时间戳在翻译过程中不被 LLM 篡改(详见 §16.3.4) |
3. 技术选型
3.1 技术栈一览
层级 | 技术 | 用途 |
|---|---|---|
Web 后台 | Cloudflare Workers + Hono 框架 | API 服务 + 静态页面托管 |
数据存储 | Cloudflare KV | 配置/频道/状态/去重表 |
前端 | 原生 HTML/CSS/JS(单文件) | 管理界面,无框架依赖 |
流水线执行 | GitHub Actions | 定时调度 + 任务执行 |
视频下载 | yt-dlp(Python) | YouTube 视频下载 + 音轨提取 |
音频处理 | ffmpeg | 从视频中提取音轨、长音频切分 |
语音识别 | MiMo | 音频转文本(纯文本转录) |
时间戳对齐 | stable-ts(Python) | 强制对齐文本到音频,生成词级时间戳 |
翻译 | 用户自有 HTTPS LLM API | 字幕+标题翻译 |
B 站投稿 | bilibili-api-python / 直接 HTTP | 视频/字幕/合集操作 |
YouTube 搜索 | YouTube Data API v3 | 频道搜索 |
3.2 B 站鉴权方案:纯 Cookie 方式
经过官方开放平台 API 与非官方 Cookie 方式的对比评估,选择纯 Cookie 方式(决策详情见附录 A1):
决策因素 | 说明 |
|---|---|
入驻门槛 | 官方开放平台需企业资质申请,Cookie 方式零门槛 |
功能完整 | Cookie 方式支持投稿+字幕+合集全部功能;官方 API 缺少 CC 字幕和合集接口 |
自动续期 | 通过 |
稳定性 | 社区逆向 API 成熟(bilibili-API-collect),长期维护 |
4. 核心流程
4.1 流水线执行流程
4.2 触发方式
方式 | 触发源 | 说明 |
|---|---|---|
定时自动 | GitHub Actions cron | 每 4 小时一次(频率可在 |
手动触发 | Web 后台 → Worker → GitHub API | 点击"立即执行",通过 |
GitHub 页面 | workflow_dispatch | 在 GitHub Actions 页面手动运行 |
三种方式启动的是同一个 Workflow,执行逻辑完全一致。Workflow 配置了 concurrency 组,确保同一时刻只有一个流水线在运行,避免 Cookie 续期并发冲突(详见 §8.6)。
4.3 处理数量决定逻辑
手动队列优先:手动队列中的视频不受
MAX_VIDEOS_PER_RUN限制,但手动队列 + RSS 新视频的总处理时长受 GitHub Actions 配置超时(timeout-minutes: 300,即 5 小时)约束。若手动队列积压较多,Runner 会优先处理手动队列,RSS 新视频推迟到下次 cron。动态裁剪:若新视频预估总时长较长(如多个 1 小时视频),Runner 会根据
timeout-minutes: 300的限制动态减少单次处理量,避免超时。长视频(>30 分钟)建议单独串行处理。动态裁剪算法:
Python
5. Web 管理后台
5.1 设计原则
单页配置:所有填写项在同一页面分区块展示,不跳转
搜索代替手填:频道通过搜索添加,合集和分区通过下拉框选择
脱敏回显:Cookie/Key 回显时显示
xxxx****xxxx,不暴露明文状态可视化:处理记录带状态色标(绿=成功,红=失败+原因+中断阶段)
初始化引导:首次访问引导设置管理密码
连通性测试:每个凭证/API 配"测试"按钮,即时验证有效性
密码可重置:忘记密码可通过 wrangler 命令行重置(详见 §5.3)
5.2 页面区块
区块 1:账号凭证
配置项 | 说明 | 必填 |
|---|---|---|
管理密码 | 后台登录密码,首次初始化时设置(bcrypt 哈希存储) | 是 |
B 站 SESSDATA | B 站登录 Cookie | 是 |
B 站 bili_jct | CSRF Token | 是 |
B 站 buvid3 | 设备标识 Cookie | 是 |
B 站 ac_time_value | Cookie 自动续期令牌(来自 LocalStorage,非 Cookie) | 是 |
YouTube API Key | YouTube Data API v3 Key | 否(不用搜索可不填) |
YouTube Cookie | Netscape 格式 Cookie 文件内容 | 否(仅下载受限视频时需要) |
GitHub Token | Fine-grained PAT(仅授权目标仓库的 Actions:write + Metadata:read) | 是 |
GitHub 仓库 | 仓库全名,如 | 是 |
每项凭证旁均有"测试"按钮:B 站 Cookie 测登录态、YouTube API Key 测搜索、GitHub Token 测触发权限。
区块 2:AI 服务接口
配置项 | 说明 | 必填 |
|---|---|---|
语音识别 API 地址 | MiMo ASR 端点(默认 | 是 |
语音识别 API 密钥 | MiMo API Key | 是 |
翻译 API 地址 | LLM 翻译服务 HTTPS 接口 URL | 是 |
翻译 API 密钥 | 翻译服务鉴权 key | 是 |
每项 API 旁均有"测试"按钮:发送小样本请求验证连通性和返回格式。
区块 3:频道管理
方式一:搜索添加(推荐)
若合集下拉框为空,提示"请先到 B 站创作者后台创建合集与小节",并附跳转链接。
方式二:手动添加
每个频道可单独配置不同的合集、分区、标签、投稿类型和字幕模式,可随时启用/停用/删除。
区块 4:运行状态
无需填写,自动展示:
上次运行时间
累计处理视频数
最近处理记录(频道 + 视频标题 + 状态 + 时间 + 失败原因 + 中断阶段)
"立即执行"按钮(手动触发流水线,点击后弹窗提示"已触发,请稍后刷新查看结果")
已处理视频列表(支持删除单条以触发重新处理)
失败通知开关(可选配置 Webhook/Server酱 URL,Cookie 失效或连续失败时主动告警)
区块 5:手动添加视频
除了通过频道订阅自动发现视频外,还可以手动添加特定视频进行处理:
支持的 URL 格式(每行一个):
格式 | 示例 | 说明 |
|---|---|---|
完整 URL |
| 标准格式 |
短链接 |
| YouTube 短链接 |
纯视频 ID |
| 11 位视频 ID,系统自动补全 URL |
带时间戳 |
| 自动去除时间戳参数 |
功能 | 说明 |
|---|---|
批量添加 | 支持多行 URL,每行一个(URL、短链接或纯 ID 均可) |
配置复用 | 可选择已有频道配置,自动继承合集/分区/标签/字幕模式 |
独立配置 | 也可为手动视频单独指定合集/分区/字幕模式 |
优先处理 | 手动队列中的视频在下次流水线执行时优先于 RSS 发现的视频 |
队列管理 | 可查看队列(含状态色标)、删除待处理项、查看已处理结果 |
去重保护 | 手动添加的视频处理后会进入去重表,不会重复处理 |
重新处理 | 已处理视频可通过"删除已处理记录 → 重新添加到手动队列"触发再次处理 |
失败重试 | 处理失败的可重试项自动保留在队列中(最多重试 3 次),详见 §10.3 状态生命周期 |
手动添加的视频不受
MAX_VIDEOS_PER_RUN限制,但受 GitHub Actions 配置超时(timeout-minutes: 300,即 5 小时)约束。建议手动队列不超过 10 个视频,避免单次流水线超时。
5.3 管理密码重置
若忘记管理密码,可通过以下命令重置:
注意:删除
config键会清除所有配置,需重新初始化。建议只修改admin_password字段。
6. 配置项总览
6.1 Web 后台填写(存入 Cloudflare KV config 键)
分类 | 配置项 | 获取方式 | 必填 |
|---|---|---|---|
管理 |
| 自定义(bcrypt 哈希存储) | 是 |
B 站凭证 |
| 浏览器 F12 → Application → Cookies → bilibili.com → SESSDATA | 是 |
B 站凭证 |
| 同上 → bili_jct | 是 |
B 站凭证 |
| 同上 → buvid3 | 是 |
B 站凭证 |
| F12 → Console → 输入 | 是 |
YouTube |
| Google Cloud Console → 启用 YouTube Data API v3 → 创建 API Key | 否 |
YouTube |
| 浏览器扩展(如 "Get cookies.txt")导出 Netscape 格式 | 否 |
GitHub |
| GitHub Settings → Developer settings → Fine-grained PAT → 仅授权目标仓库 Actions:write + Metadata:read | 是 |
GitHub |
| 仓库全名 | 是 |
ASR |
| MiMo ASR 端点: | 是 |
ASR |
| MiMo API Key(控制台 → API Key 管理) | 是 |
翻译 |
| 用户自有翻译服务地址 | 是 |
翻译 |
| 用户自有翻译服务密钥 | 是 |
通知 |
| Server酱/Webhook URL(可选) | 否 |
凭证获取详细教程见 §13.0 前置准备。
6.2 频道配置(每条记录,存入 KV channels 键)
字段 | 说明 | 示例 |
|---|---|---|
| 记录唯一标识(系统自动生成 UUID) |
|
| YouTube 频道 ID |
|
| 频道显示名称 |
|
| B 站合集 ID(下拉框选择) |
|
| 合集小节 ID(下拉框选择) |
|
| B 站投稿分区(下拉框选择) |
|
| 默认标签(逗号分隔) |
|
| 投稿类型:1=自制,2=转载 |
|
| 字幕模式: |
|
| 是否启用 |
|
section_id(频道配置,snake_case)对应 B 站 API 请求中的sectionId(camelCase),代码层做映射。
6.3 GitHub Secrets(仓库设置中填写)
Secret 名称 | 说明 |
|---|---|
| Cloudflare Worker 部署后的域名 |
| Pipeline API 鉴权 Token(后台自动生成,存于 KV |
关系说明:KV 中的
pipeline_token(小写)是后台自动生成的 Token 值;GitHub Secrets 中的PIPELINE_TOKEN(大写)是该值的副本,供 Runner 读取。两者值相同,初始化后需手动复制。
6.4 Cloudflare 控制台操作
操作 | 说明 |
|---|---|
创建 KV 命名空间 | Dashboard → Workers & Pages → KV → 创建,ID 填入 |
设置加密主密钥 | 执行 |
连接 Git 仓库 | Dashboard → Workers → 连接 GitHub 仓库,主分支推送后自动部署 |
6.5 自动生成的项(无需手动填写)
配置项 | 说明 |
|---|---|
| 首次初始化时自动生成(32 字节随机 Token),用于 Runner 鉴权拉取配置。初始化成功页展示一次,后续可在后台"系统设置"中查看或重置 |
已处理视频去重表 | 流水线运行时自动维护 |
6.6 投稿参数来源说明
投稿参数 | 来源 | 说明 |
|---|---|---|
| 按 |
|
| 频道配置 | B 站投稿分区 |
| 频道配置 | 默认标签,逗号分隔 |
| 模板生成 | 含原视频链接、频道名、翻译说明 |
| YouTube 缩略图 |
|
| 频道配置 | 1=自制(公司自有内容),2=转载 |
| YouTube 视频 URL | 转载时填写 |
| 默认 0 | 允许转载 |
| 上传后获得 | 已上传视频文件引用 |
7. B 站 API 接口清单
7.1 鉴权方式
所有接口使用 Cookie 鉴权:
bili_jct 兼作 CSRF Token,POST 请求需在参数或 Header 中携带。
注意:
ac_time_value不是 Cookie,不随 HTTP 请求发送。它存储在浏览器 LocalStorage 中,仅在 Cookie 续期流程中使用(详见 §8)。
7.2 接口列表
操作 | 方法 | URL | 说明 |
|---|---|---|---|
视频上传 | POST |
| 分片上传视频文件 |
稿件提交 | POST |
| 提交标题/分区/标签/简介/封面,返回 bvid/aid/cid |
CC 字幕提交 | POST |
|
|
获取合集列表 | GET |
| 拉取账号下所有合集及小节 |
添加视频到合集 | POST |
| 需要 |
获取分区列表 | GET |
| 拉取可用的投稿分区(Worker 代理,分区列表较少变动可内置静态数据) |
Cookie 刷新 | POST | B 站刷新接口 | 通过 |
免责声明:上述接口为非官方逆向接口,来自 bilibili-API-collect 社区项目。B 站随时可能改版导致接口失效,需以实际抓包验证为准。
7.3 稿件提交参数
copyright:公司自有内容建议设为1(自制),转载内容设为2。该值可在频道配置中设置。videos:视频文件引用,cid在上传完成后由 B 站返回。
7.4 CC 字幕提交参数
from/to为浮点秒数。语言代码zh-Hans表示简体中文(人工上传),区别于ai-zh(AI 自动生成)。
7.5 合集追加参数
URL 参数:csrf = bili_jct
sectionId(camelCase)对应频道配置中的section_id(snake_case)。
8. Cookie 自动续期机制
8.1 原理
B 站 Cookie 刷新依赖 ac_time_value 字段,这是一个特殊的刷新令牌,存储在浏览器 LocalStorage 中(非 Cookie)。当检测到 Cookie 即将过期时,系统自动请求新的会话凭证。
获取方式:在 bilibili.com 登录状态下,按 F12 打开开发者工具 → Console → 输入
window.localStorage.ac_time_value→ 回车复制返回值。
8.2 刷新流程
关键风险:
ac_time_value是一次性令牌,刷新成功后旧凭证立即失效。若回写 KV 失败,新凭证丢失、旧凭证已废,账号将被锁死。因此回写必须带重试和兜底机制(详见 §8.4)。
8.3 集成到流水线
8.4 KV 回写失败处理(关键安全机制)
由于 ac_time_value 刷新后旧凭证立即失效,回写 KV 必须有完善的兜底:
安全提示:
new_cookies.json含 B 站登录凭证明文,GitHub Actions Artifact 在公共仓库中可被任何人下载。因此 仓库必须设为 Private。若确需使用公共仓库,应改为加密存储(如使用gpg加密后存 Artifact,密钥通过 Secret 传入)或取消 Artifact 兜底改为仅通知用户手动处理。
8.5 失效兜底
场景 | 处理 |
|---|---|
| 标记失败,后台标红提示"Cookie 已失效" |
| 同上,记录错误原因 |
KV 回写失败但凭证已刷新 | 新凭证保存到 Artifact,后台标黄提示"需手动恢复 Cookie" |
正常刷新成功 | 静默回写 KV,后台状态页无感知 |
8.6 并发保护
B 站 Cookie 刷新是不可逆操作,多个流水线同时运行会导致凭证冲突。通过 GitHub Actions 的 concurrency 机制确保互斥:
这确保同一时刻只有一个 Workflow 运行,cron 和手动触发不会撞车。
8.7 用户维护频率
填一次 Cookie(4 个字段)后,系统自动续期,通常可维持数周至数月(视账号风控状态而定)。仅在以下情况需要重新填:
B 站修改了登录/刷新机制
账号在其他设备被踢下线
超过刷新令牌自身的有效期
KV 回写全部失败且 Artifact 也丢失
9. GitHub Actions 流水线
9.1 Workflow 触发定义
9.2 执行步骤
变更说明:
显式安装 ffmpeg(yt-dlp 提取音频 + stable-ts 对齐依赖)
使用
actions/cache缓存 Whisper 模型(small约 461MB),避免每次 run 重新下载使用
requirements.txt安装依赖并锁定版本(含 yt-dlp、bilibili-api-python、stable-ts 等)执行
python scripts/main.py(非python main.py)始终上传 Artifact,用于 Cookie 刷新兜底恢复
9.3 环境变量
变量 | 来源 | 说明 |
|---|---|---|
| GitHub Secrets | Worker 域名 |
| GitHub Secrets | Pipeline API 鉴权 Token(通过 |
其余配置(B 站 Cookie、ASR/翻译 API 等)均从 Worker KV 动态拉取,不进 GitHub Secrets。
10. Cloudflare Worker API
10.1 认证方式
接口类型 | 鉴权方式 |
|---|---|
管理接口 | 登录后签发 Session(HttpOnly Cookie),管理操作校验 Session |
Pipeline 接口 |
|
安全改进:Pipeline Token 不再通过 URL Query 传输(避免日志泄露)。管理接口不再每次传明文密码,改用 Session 机制。详见 §17。
10.2 接口列表
管理接口
方法 | 路径 | 说明 | 鉴权 |
|---|---|---|---|
POST |
| 登录验证(返回 Session) | 无 |
POST |
| 首次初始化(设置管理密码) | 无 |
GET |
| 获取配置(脱敏) | Admin |
PUT |
| 更新配置 | Admin |
GET |
| 获取频道列表 | Admin |
POST |
| 添加频道 | Admin |
PUT |
| 更新频道 | Admin |
DELETE |
| 删除频道 | Admin |
GET |
| 代理拉取 B 站合集列表 | Admin |
GET |
| 代理拉取 B 站投稿分区列表 | Admin |
GET |
| 代理搜索 YouTube 频道 | Admin |
GET |
| 获取运行状态 | Admin |
GET |
| 获取已处理视频列表 | Admin |
DELETE |
| 删除单条已处理记录 | Admin |
GET |
| 获取手动视频队列 | Admin |
POST |
| 添加视频到手动队列 | Admin |
DELETE |
| 从手动队列删除视频 | Admin |
POST |
| 触发 GitHub Actions(返回 dispatch 结果) | Admin |
POST |
| 测试 B 站 Cookie 有效性 | Admin |
POST |
| 测试 ASR API 连通性 | Admin |
POST |
| 测试翻译 API 连通性 | Admin |
POST |
| 测试 GitHub Token 权限 | Admin |
Pipeline 接口(供 GitHub Actions 调用)
方法 | 路径 | 说明 | 鉴权 |
|---|---|---|---|
GET |
| 拉取全部配置+频道+去重表+手动队列 | Bearer Token |
POST |
| 回写处理结果(批量),同时自动清理 manual_queue 中已处理项 | Bearer Token |
POST |
| 回写运行状态 | Bearer Token |
POST |
| 回写刷新后的 Cookie | Bearer Token |
手动队列清理机制:Runner 在
POST /api/pipeline/processed回写处理结果时,请求体中包含本批次处理的video_id列表及各自的处理结果。Worker 收到后按结果分类处理:
处理成功:从
manual_queue移除该 video_id(结果已落在processed表)处理失败且不可重试(如视频不存在、Cookie 过期):从
manual_queue移除,记录到processed的 failure 条目处理失败但可重试(如网络超时、ASR 限流):保留在
manual_queue中,status标记为retry,retry_count++,超过 3 次自动移除并记录失败
Pipeline POST 请求体结构
POST /api/pipeline/processed(回写处理结果 + 清理手动队列):
retryable字段决定手动队列清理策略:true= 保留并标记 retry,false= 移除。
POST /api/pipeline/status(回写运行状态):
POST /api/pipeline/cookies(回写刷新后的 Cookie):
10.3 Pipeline Config 响应结构
stage字段标识处理阶段:downloaded/asr/translated/uploaded/subtitled/seasoned/completed。失败时记录中断阶段,便于断点续传。processed_at为 Unix 时间戳,用于裁剪排序。admin_password、gh_token等管理类字段不下发给 Runner。
manual_queue 状态生命周期:
status
含义
流转
pending待处理,等待下次流水线执行
用户添加 →
pending;retry下次执行时重置为pending
processing流水线正在处理中
pending→processing(Runner 拉取 config 时标记)
done处理成功,已从队列移除
processing→ 回写 processed 时自动移除(结果落在processed表)
retry处理失败但可重试
processing→retry(Runner 回写时标记retry_count++),超过 3 次自动移除并记录到processed
failed处理失败且不可重试
processing→failed(从队列移除,记录到processed的 failure 条目)生命周期总览:
pending→processing→done/retry(→pending) /failedprocessing 卡死保护:
processing状态附带processing_since时间戳。若 Runner 在流水线执行中崩溃(未回写结果),该项会卡在processing。Worker 在每次GET /api/pipeline/config请求时检查:若某项processing超过 1 小时(超过单次流水线最大运行时间),自动回退为pending,确保下次流水线能重新处理。
10.4 Status 响应结构
11. Cloudflare KV 存储设计
11.1 KV 限制
维度 | 免费额度 | 说明 |
|---|---|---|
总存储 | 1 GB | 足够使用 |
单个 Value | 25 MB | 足够使用 |
读操作 | 100,000 次/天 | 宽裕 |
写操作 | 1,000 次/天 | 需优化写入策略 |
Worker CPU 时间 | 10ms/请求(免费层) | 后台代理拉取大列表时需注意 |
11.2 Key 设计
Key | 内容 | 写入频率 | 备注 |
|---|---|---|---|
| 全局配置 JSON(含 yt_cookies) | 低(用户修改时 + Cookie 刷新时) | 敏感字段加密存储,管理密码 bcrypt 哈希 |
| 频道列表 JSON 数组 | 低(用户增删时) | |
| 手动添加的视频队列 JSON 数组 | 中(用户添加/处理完毕时) | 每项含 video_id、url、title、channel_config_id、config、added_at、status、retry_count、last_error |
| 已处理视频去重表 JSON | 中(每次执行批量回写1次) | 含裁剪逻辑,保留近500条 |
| 运行状态 JSON | 中(每次执行1次) | 最近100条运行记录 |
统一说明:
yt_cookies存储在configJSON 内(而非独立 Key),与bili_sessdata等字段同级。Pipeline Config 接口统一从config中返回。
11.3 写入优化策略
按 cron 每 4 小时一次(一天 6 次),每天约 14-24 次写入(含 Cookie 刷新、手动队列清理和用户操作),远低于 1,000 次/天限额。
11.4 去重表裁剪逻辑
YouTube RSS 默认返回最近约 15 条视频,去重表只需覆盖这个窗口。保留 500 条记录有充足余量:
12. 约束与限制
12.1 GitHub Actions
约束 | 值 | 影响 |
|---|---|---|
单 Job 执行上限 | 6 小时(360 分钟) | 长视频需控制单次处理数量 |
Workflow 超时 | 300 分钟(配置值) | 留 1 小时余量给网络重试 |
私有仓库免费额度 | 2000 分钟/月 | 约 33 小时计算时长(2000÷60≈33.3) |
cron 精度 | 不保证准时 | 可能延迟 5-15 分钟 |
仓库活跃度 | 长期不提交可能暂停调度 | 定期提交保持活跃 |
Runner 内存 | ~7 GB RAM | 长音频需分段处理 |
提示:若使用公共仓库,Actions 免费额度不受 2000 分钟限制,但配置含敏感信息需评估安全性。
12.2 Cloudflare KV
约束 | 值 | 应对 |
|---|---|---|
写操作 | 1,000 次/天 | 批量回写,每次执行仅 2-3 次写入 |
最终一致性 | 写入后全球同步有延迟(最长数十秒) | 配置更新后等 30 秒再触发流水线;Runner 读 KV 时设 |
Worker CPU | 10ms/请求(免费层) | 重逻辑下放到前端或 Runner |
12.3 YouTube
约束 | 说明 |
|---|---|
RSS 延迟 | 新视频发布后约 15-30 分钟才出现在 RSS |
RSS 范围 | 仅返回最近约 15 条视频(超出窗口的视频可能丢失) |
Cookie 轮换 | 浏览器标签页的 Cookie 频繁轮换,导出时建议用隐私窗口 |
积压风险:若 cron 被跳过且频道在窗口期内发布超过 15 条视频,最旧的会跌出 RSS 窗口。建议定期检查,必要时用 YouTube Data API v3 的
search(按发布时间排序)做补充回扫。
12.4 B 站
约束 | 说明 |
|---|---|
Cookie 有效期 | 约 30 天,配合 ac_time_value 可自动续期 |
非正式会员投稿限制 | 单日最多 5 个稿件(建议使用正式会员账号) |
风控 | 自动化操作可能触发风控,投稿间加随机延迟 5-15 秒 |
合集审核 | 创建合集需人工审核,必须先在 B 站创作者后台创建好合集与小节 |
12.5 YouTube Data API v3
约束 | 值 |
|---|---|
免费额度 | 10,000 units/天 |
搜索一次 | 100 units |
频道详情查询 | 1 unit |
可支持搜索次数/天 | 约 100 次(假设全部配额用于搜索) |
13. 部署指南
13.0 前置准备清单
在开始部署前,请确认已准备好以下账号和服务:
项目 | 获取方式 | 必需 | 难度 |
|---|---|---|---|
GitHub 账号 | github.com 注册 | 是 | 简单 |
Cloudflare 账号 | cloudflare.com 注册 | 是 | 简单 |
Google Cloud 账号 | console.cloud.google.com 注册 | 否(不用搜索可不需要) | 中等 |
B 站账号(正式会员) | bilibili.com 注册 | 是 | 简单 |
ASR 服务 | MiMo 语音识别 API(mimo.mi.com 注册 → 获取 API Key) | 是 | 简单 |
翻译服务 | 用户自备(如 OpenAI GPT API、自部署 LLM 等) | 是 | 视方案 |
凭证获取详细教程:
B 站 Cookie(4 个字段):
在浏览器登录 bilibili.com
按 F12 打开开发者工具
SESSDATA / bili_jct / buvid3:Application → Cookies → bilibili.com → 分别找到这三个字段
ac_time_value:Console → 输入
window.localStorage.ac_time_value→ 回车复制返回值
YouTube API Key:
访问 Google Cloud Console → 创建项目
启用 YouTube Data API v3
凭证 → 创建凭据 → API 密钥
MiMo ASR API Key:
访问 mimo.mi.com → 注册/登录
控制台 → API Key 管理 → 创建 API Key
复制 API Key(用于
asr_key配置项)
翻译服务 API Key:
根据所选翻译服务(如 OpenAI、自部署 LLM 等)获取 API Key
填入后台
translate_api和translate_key
YouTube Cookie(Netscape 格式):
安装浏览器扩展 "Get cookies.txt"(Chrome/Firefox 均有)
在已登录 YouTube 的浏览器标签页中点击扩展
导出 cookies.txt 文件,将内容粘贴到后台
GitHub Fine-grained PAT:
GitHub Settings → Developer settings → Personal access tokens → Fine-grained tokens
创建新 Token,选择目标仓库
权限:Actions: Read and write, Metadata: Read-only
生成后复制 Token
13.1 部署流程(只需做一次)
Cloudflare 免费计划:Workers 免费层(10 万请求/天)和 KV 免费层完全够用。预计日均请求 <100 次。
13.2 本地开发
14. 日常运维
14.1 常见操作指南
日常操作
场景 | 操作 |
|---|---|
Cookie 过期 | 后台状态页标红 → 重新填入新 Cookie(4 个字段) |
添加新频道 | 后台搜索 → 关注 → 选合集 → 选分区 → 填标签 → 保存 |
停止某频道 | 后台频道管理 → 关闭"启用"开关 |
查看处理记录 | 后台状态页自动展示 |
手动触发 | 后台点"立即执行" → 弹窗提示已触发 → 稍后刷新查看 |
重新处理某视频 | 后台已处理列表 → 删除该条 → 下次执行重新处理 |
更改 cron 频率 | 编辑 |
更改单次处理上限 | 编辑 |
更换 ASR/翻译服务 | 后台修改 API 地址和密钥 → 点"测试"验证 |
新建合集 | 在 B 站创作者后台创建 → 等待审核 → 后台频道管理中重新选合集 |
异常处理
场景 | 操作 |
|---|---|
下载失败 | 可能 yt-dlp 版本过旧,在 workflow 中改为 |
投稿失败 -101 | Cookie 已过期,重新填入 |
投稿失败 -509 | 触发风控,降低 cron 频率或增加投稿间隔 |
字幕未挂上 | 检查 ASR/翻译 API 是否正常,查看 Actions 日志 |
状态页无运行记录 | 检查 GitHub Actions(仓库 → Actions 标签 → 查看运行历史) |
"立即执行"无响应 | 检查 GitHub Token 是否过期、仓库是否正确 |
Worker 不可访问 | 检查 Cloudflare Dashboard 中 Worker 状态 |
管理密码忘记 | 使用 wrangler 命令行重置(详见 §5.3) |
14.2 Cookie 失效检测
流水线投稿时若 B 站 API 返回鉴权错误(如 -101 账号未登录):
该视频标记为失败,原因记录"Cookie 可能已过期"
后台状态页该条记录标红显示
若配置了通知 Webhook,自动发送告警
用户看到后重新填入 Cookie 即可恢复
14.3 监控要点
监控项 | 查看位置 | 异常处理 |
|---|---|---|
流水线是否按时执行 | 后台状态页 → 上次运行时间 | 如超 8 小时未运行,检查 GitHub Actions(仓库 → Actions 标签 → 查看是否有失败) |
投稿是否成功 | 后台状态页 → 处理记录 | 红色记录查看失败原因和中断阶段 |
Cookie 是否有效 | 后台状态页 → 标红提示 | 重新填入 Cookie |
KV 写入是否超限 | Cloudflare Dashboard → KV | 如超限,降低 cron 频率 |
GitHub Actions 额度 | GitHub → Settings → Billing | 私有仓库 2000 分钟/月 |
14.4 yt-dlp 时效性维护
YouTube 频繁更新会导致 yt-dlp 失效。pip install yt-dlp 装的是固定版本,失效后需更新:
症状:下载报错
Unable to extract处理:在 workflow 中改为
pip install -U yt-dlp或定期手动 bump 版本
15. 项目目录结构
16. ASR 与翻译 HTTPS 调用详解
本章详细说明流水线中语音识别(ASR)和 LLM 翻译两个环节如何通过 HTTPS API 完成,包括请求格式、响应处理、错误重试等。B 站 API 接口详见 §7。
16.1 整体数据流
时间戳方案:MiMo
mimo-v2.5-asr返回纯文本不含时间戳。系统使用stable-ts的align()函数将文本强制对齐到音频,生成词级时间戳(精度 ±0.2 秒),再按句子分组输出 SRT。相比 ffmpeg 静音分段,精度提升一个数量级。
16.2 ASR(语音识别)调用
本系统采用两阶段方案:先用 MiMo ASR 获取高精度转录文本,再用 stable-ts 强制对齐生成精确时间戳。
16.2.1 阶段 1:MiMo ASR 转录
MiMo ASR 采用 OpenAI Chat Completions 兼容格式,音频以 Base64 编码传入:
参数 | 值 | 说明 |
|---|---|---|
|
| 当前唯一支持的 ASR 模型 |
音频格式 | wav、mp3 | 需 Base64 编码后传入 |
Base64 大小上限 | 10 MB | 超过需分段切分(见 §16.2.4) |
语言参数 |
| 支持 |
认证方式 |
| 非 Bearer Token |
调用代码:
MiMo ASR 响应格式(OpenAI Chat Completions 兼容):
choices[0].message.content为纯文本转录结果,不含时间戳。时间戳由阶段 2 的 stable-ts 对齐生成。
16.2.2 阶段 2:stable-ts 强制对齐生成时间戳
为什么需要强制对齐?
MiMo ASR 返回纯文本,没有时间戳。直接用会产生没有时间轴的字幕,无法用于 CC 字幕。stable-ts 的 align() 函数可以接收已有文本,将其对齐到音频上,生成词级时间戳(精度 ±0.2 秒),再按句子分组输出 SRT。
相比 ffmpeg 静音分段方案(每段一个粗略时间戳),stable-ts 对齐方案的优势:
维度 | ffmpeg 静音分段(旧方案) | stable-ts 强制对齐(新方案) |
|---|---|---|
时间戳精度 | 段级(数秒~数十秒) | 词级(±0.2 秒) |
字幕粒度 | 每段一句话或多句 | 每句一条字幕,可细化到词 |
依赖网络 | 需逐段调用 ASR(段数=API 调用数) | 只调 1 次 ASR + 本地对齐 |
长音频处理 | 需手动分段 + 合并时间戳 | 需手动分段(10MB 限制),stable-ts 自动对齐文本边界 |
10MB 限制 | 每段需单独控制 | 同样需切分(见 §16.2.4),但每段对齐更精确 |
安装:
对齐代码:
注意:stable-ts 的
split_by_length()接受max_chars/max_words参数(非min_dur/max_dur)。时长控制通过clamp_max(max_dur=...)实现。详见 stable-ts 文档。仓库状态:stable-ts GitHub 仓库已归档(Public archive),不再活跃维护。但功能稳定、社区广泛使用。如未来出现问题,可评估迁移到 WhisperX 或 faster-whisper 的
transcribe()带时间戳模式。
输出 SRT:
工作原理:stable-ts 加载 Whisper 模型后,不执行完整转录,而是利用模型的交叉注意力权重(cross-attention weights),通过动态时间规整(DTW)将已有文本的每个词对齐到音频中的精确时间点。这比完整转录快得多,且时间戳精度更高。
16.2.3 对齐参数调优
stable-ts 提供多种字幕分段策略,可根据需要调整:
参数 | 默认值 | 说明 |
|---|---|---|
| 中文 30 / 英文 80 | 每条字幕最多字符数,控制字幕长度 |
| 8.0 秒 | 限制每条字幕最长时长(超过则拆分) |
模型大小 |
|
|
中文特殊处理:中文不按空格分词,stable-ts 按 token/字符对齐。使用 max_chars(而非 max_words)控制中文字幕长度更精确:
CPU 推理注意:GitHub Actions 无 GPU,
small模型在 CPU 上对齐 1 小时音频约需 5-15 分钟(非 GPU 的 2-5 分钟)。如需更快可换base/tiny,但精度会下降。
16.2.4 长音频与 10MB 限制处理
MiMo ASR 的 Base64 编码后大小上限为 10MB(约 7MB 原始 mp3)。对于超长音频,需先切分再分别转录和对齐:
场景 | 处理策略 |
|---|---|
原始音频 < 7MB | 直接调用,无需切分 |
原始音频 > 7MB | ffmpeg 按固定时长切分,分别转录+对齐,合并 SRT |
stable-ts 对齐超时 | 换用更小模型( |
16.2.5 SRT 工具函数
以下函数定义在 scripts/srt_utils.py 中,供 asr.py、translate.py、bilibili.py 共同调用:
16.3 LLM 翻译调用
前置条件:本章翻译流程仅在频道配置的
subtitle_mode为translated或both时执行。当subtitle_mode为original或none时,Runner 跳过翻译步骤,直接使用 ASR 原始文本作为字幕(original)或不生成字幕(none),标题使用 YouTube 原始标题。判断逻辑详见 §4.1 步骤 ③ 和 ⑤。
16.3.1 调用方式
16.3.2 请求
翻译分两部分:字幕翻译和标题翻译。建议合并为一次请求,减少 API 调用次数:
16.3.3 响应格式
OpenAI 兼容格式:若翻译服务使用 OpenAI Chat Completions API,响应格式为
choices[0].message.content(需从中解析出标题和字幕)。translate.py应支持配置响应解析路径。
16.3.4 分批翻译与时间戳保护(关键)
字幕过长可能超出模型上下文窗口,需分批处理。核心原则:时间戳严格保留 ASR 原始值,LLM 仅负责翻译文本,不负责时间戳。
关键安全措施:
翻译后按行号配对,若条数不匹配则自动拆分 batch 重试,仍不匹配才报错,绝不强行拼装
时间戳一律沿用 ASR 原始值,LLM 返回的时间戳被丢弃
上下文同时携带原文+译文,确保术语一致
16.3.5 适配说明
和 ASR 一样,翻译 API 的具体格式取决于用户自有的服务。上例为最常见的自定义格式。translate.py 应设计为可配置:
请求体字段名可通过 KV 配置映射
鉴权方式支持 Bearer Token 和自定义 Header
响应解析路径可配置(如
data.translated_subtitlevschoices[0].message.content)
16.4 错误处理与重试
两个 API 调用都需实现统一的错误处理:
16.5 从 SRT 转为 B 站字幕格式
翻译完成后的 SRT 需转为 B 站 submit_subtitle 接口要求的格式:
语言代码与 subtitle_mode 的对应关系:
subtitle_mode
上传字幕
lan 参数
translated仅中文字幕
"zh-Hans"
original仅原语言字幕
按视频实际语言(
"en"/"ja"/"ko"等)
both原语言 + 中文字幕(两次调用)
第一次
"en"等,第二次"zh-Hans"
none不上传字幕
不调用此函数
时间戳来自 ASR 原始值(翻译过程中不被篡改),确保字幕与口型对齐。
16.6 完整调用链路
16.7 超时与资源规划
环节 | 短视频(~10分钟) | 长视频(~1小时) | 超时设置 | 备注 |
|---|---|---|---|---|
环境安装(pip+ffmpeg) | 60-120 秒 | 60-120 秒 | 180s | PyTorch ~800MB + stable-ts 依赖 |
模型下载(首次) | 30-60 秒 | 30-60 秒 | 120s | small 模型 ~461MB;有 cache 时跳过 |
模型加载 | 5-10 秒 | 5-10 秒 | 30s | 整个流水线只加载一次 |
yt-dlp 下载视频 | 30-60 秒 | 2-5 分钟 | 300s | 取决于网络和视频大小 |
ffmpeg 提取音频 | 5-10 秒 | 20-60 秒 | 60s | 本地操作 |
MiMo ASR 转录 | 30-90 秒 | 2-5 分钟 | (10, 600)s | 1 次 API 调用(长音频分段) |
stable-ts 强制对齐(CPU) | 1-3 分钟 | 5-15 分钟 | 300s | 无 GPU,CPU 推理比 GPU 慢 3-5 倍 |
翻译 API 调用(可选) | 30-90 秒 | 3-10 分钟 | (10, 300)s | 长字幕需分批;subtitle_mode=original/none 时跳过 |
B 站上传+投稿 | 2-5 分钟 | 5-15 分钟 | (10, 600)s | 取决于视频大小 |
单视频总计 | 5-12 分钟 | 20-55 分钟 | - | 不翻译时更快;首次 run 额外 +2 分钟安装 |
短视频:5 个约 25-60 分钟(首次 run 额外 +3 分钟环境安装)
长视频:建议单次处理 2-3 个,约 40-165 分钟
均远低于 GitHub Actions 300 分钟超时
首次 run 注意:无模型缓存时额外增加 30-60 秒下载时间,后续 run 有 cache 则跳过
17. 安全说明
17.1 敏感数据存储
数据 | 存储方式 | 安全措施 |
|---|---|---|
管理密码 | KV | bcrypt 哈希存储,不存明文 |
B 站 Cookie | KV | AES-GCM 加密存储(主密钥放 Worker Secret) |
ASR/翻译 Key | KV | 同上加密 |
GitHub PAT | KV | 同上加密;使用 Fine-grained PAT 最小权限 |
Pipeline Token | KV | 32 字节随机生成,支持后台一键重置 |
17.2 传输安全
接口 | 鉴权方式 | 安全措施 |
|---|---|---|
管理接口 | Session(HttpOnly Cookie) | 登录后签发短期 Session,不每次传密码 |
Pipeline 接口 |
| Token 不走 URL Query,避免日志泄露 |
17.3 访问控制
措施 | 说明 |
|---|---|
登录限流 | 同 IP 连续失败 5 次锁定 15 分钟 |
CSRF 防护 | 管理写操作需携带 CSRF Token |
Worker 暴露面 | 建议绑定自定义域 + Cloudflare Access 策略,或加 IP 白名单 |
17.4 GitHub PAT 最小权限
使用 Fine-grained PAT,仅授权目标仓库的:
Actions: Read and write(触发 workflow)Metadata: Read-only(基础访问)
不使用 Classic PAT(权限过大)。
18. 故障排查
18.1 决策树
18.2 常见错误码
错误码 | 含义 | 处理 |
|---|---|---|
-101 | 账号未登录 | Cookie 过期,重新填入 |
-111 | CSRF 失败 | bili_jct 不正确或已过期 |
-509 | 请求过于频繁 | 降低操作频率,增加延迟 |
-403 | 访问权限不足 | 检查账号状态 |
-795 | 视频审核中 | 等待审核完成后再加合集 |
18.3 查看详细日志
流水线完整日志在 GitHub Actions 中查看:
打开 GitHub 仓库
点击 Actions 标签
点击最近一次运行
点击
processjob展开各步骤查看日志
19. FAQ
Q: 免费额度够用吗? A: 完全够用。Cloudflare Workers 免费层 10 万请求/天,KV 免费 1,000 写/天,GitHub Actions 私有仓库 2,000 分钟/月。日均消耗远低于限额。(详见 §20)
Q: 支持多少个频道? A: 无硬性限制。但每次执行 RSS 发现的新视频最多处理 MAX_VIDEOS_PER_RUN 个(默认 5),手动队列视频不受此限制。频道过多时积压会增大。建议单账号关注不超过 20 个频道。
Q: 视频最长多久? A: 理论上无限制,但 GitHub Actions 配置超时为 300 分钟(5 小时),系统上限 360 分钟(6 小时)。超过 1 小时的长视频建议单独处理,且 ASR 需分段。
Q: 转载还是自制? A: 公司自有内容建议设为 copyright=1(自制),非自有内容设为 copyright=2(转载)。可在频道配置中按频道设置。
Q: 可以不翻译只上传原语言字幕吗? A: 可以。在频道配置中将"字幕模式"设为"上传原语言字幕"即可跳过翻译,直接上传 ASR 生成的原语言字幕。还支持"双字幕"模式同时上传原语言+中文翻译,或"不上传字幕"模式。
Q: 可以手动指定某个视频处理吗? A: 可以。在后台"手动添加视频"区块粘贴 YouTube 视频 URL,选择频道配置或单独指定参数,下次流水线执行时会优先处理手动队列中的视频。
Q: 失败了怎么办? A: 后台状态页会标红显示失败原因和中断阶段。按 §18.1 故障排查决策树处理。配置了通知 Webhook 时会自动告警。
Q: Cookie 多久过期? A: 约 30 天,但 ac_time_value 可自动续期,通常可维持数周至数月。详见 §8.7。
Q: 下载失败怎么办? A: 大概率是 yt-dlp 版本过旧,YouTube 改版导致。在 workflow 中改为 pip install -U yt-dlp 即可。
Q: 可以同时运行多个流水线吗? A: 不可以。Workflow 配置了 concurrency 组确保互斥,避免 Cookie 续期冲突。
20. 成本估算
20.1 免费额度消耗
服务 | 免费额度 | 预计日消耗 | 余量 |
|---|---|---|---|
Cloudflare Workers 请求 | 100,000 次/天 | ~50 次 | 99.95% 余量 |
Cloudflare KV 写操作 | 1,000 次/天 | ~18 次 | 98.2% 余量 |
Cloudflare KV 存储 | 1 GB | <10 MB | 充足 |
GitHub Actions 分钟数 | 2,000 分钟/月(私有) | ~60 分钟/天 ≈ 1,800 分钟/月 | 10% 余量 |
YouTube Data API | 10,000 units/天 | ~100 units(仅搜索) | 99% 余量 |
GitHub Actions 余量提示:私有仓库 2,000 分钟/月,按每 4 小时执行一次、每次 10 分钟计算,月消耗约 1,800 分钟,余量仅 10%。若不够,可改用公共仓库(免费)或降低 cron 频率。
20.2 ASR/翻译 API 成本
ASR 和翻译 API 由用户自备,成本取决于所选方案:
方案 | 预估成本(1 小时音频) |
|---|---|
OpenAI Whisper API | ~$0.36 |
自部署 faster-whisper | 免费(仅服务器成本) |
OpenAI GPT-4o-mini 翻译 | ~$0.01-0.05 |
自部署 LLM 翻译 | 免费(仅服务器成本) |
21. 升级与备份
21.1 升级指南
项目迭代后通过 Git 更新:
版本兼容性:KV 数据结构变更时会在文档和代码中标注。如涉及 config 结构变更,后台会自动迁移。
21.2 备份与恢复
导出 KV 配置:
恢复 KV 配置:
建议定期备份(如每周),尤其在修改配置后。
21.3 回滚
Worker 回滚:Cloudflare Dashboard → Workers → Deployments → 选择历史版本回滚。
Workflow 回滚:git revert 回退代码变更,push 后自动部署。
22. 术语表
术语 | 解释 |
|---|---|
KV | Cloudflare Key-Value 存储,一种简单的 NoSQL 数据库 |
Worker | Cloudflare Workers,边缘 Serverless 计算服务 |
cron | 定时任务调度表达式,如 |
PAT | Personal Access Token,GitHub 个人访问令牌 |
SRT | SubRip 字幕格式,包含序号、时间戳、文本 |
ASR | Automatic Speech Recognition,语音识别 |
stable-ts | Python 库,利用 Whisper 模型进行强制对齐,将文本对齐到音频生成词级时间戳 |
强制对齐 | Forced Alignment,将已有文本对齐到音频中的精确时间点 |
LLM | Large Language Model,大语言模型 |
CSRF | Cross-Site Request Forgery,跨站请求伪造(B 站用 bili_jct 防护) |
Netscape 格式 | Cookie 文件的标准文本格式(cookies.txt) |
repository_dispatch | GitHub Actions 事件类型,通过 API 触发 workflow |
workflow_dispatch | GitHub Actions 手动触发 workflow 的方式 |
ac_time_value | B 站 Cookie 刷新令牌,存储在浏览器 LocalStorage 中 |
bvid | B 站视频唯一标识(BV 开头) |
aid | B 站视频内部 ID(纯数字) |
cid | B 站视频章节 ID(用于字幕挂载) |
tid | B 站投稿分区 ID |
season / section | B 站合集 / 合集内的小节 |
SESSDATA | B 站登录凭证 Cookie |
bili_jct | B 站 CSRF Token Cookie |
buvid3 | B 站设备标识 Cookie |
附录:技术决策记录
A1. 为什么选择纯 Cookie 而非官方开放 API
(详见 §3.2)
维度 | 官方开放 API | 纯 Cookie(最终选择) |
|---|---|---|
入驻门槛 | 需企业资质申请 | 零门槛 |
CC 字幕 | 不提供 | 支持 |
合集管理 | 不提供 | 支持 |
自动续期 | OAuth refresh_token | ac_time_value |
投稿能力 | 完整 | 完整 |
结论:官方 API 缺少 CC 字幕和合集两个核心功能,且需企业入驻。纯 Cookie 方式功能完整、零门槛,配合自动续期足够稳定。
A2. 为什么选择 Cloudflare KV 而非 D1
(详见 §11)
维度 | KV(最终选择) | D1 |
|---|---|---|
写入限制 | 1,000 次/天 | 100,000 次/天 |
当前用量 | 每天 ~18 次 | - |
复杂度 | 简单 Key-Value | 需建表写 SQL |
适用场景 | 配置存储 | 关系型数据 |
结论:当前规模下 KV 写入量极低(优化后每天 ~18 次),简单 Key-Value 足够。如未来规模扩大(日处理上百视频),可迁移到 D1。迁移触发阈值:日写入持续超过 500 次。
A3. 为什么用批量回写而非逐条回写
(详见 §11.3)
KV 免费额度写操作 1,000 次/天
逐条回写:5 个视频 = 5 次写入 + 1 次状态 = 6 次/执行
批量回写:5 个视频本地累积 = 1 次写入 + 1 次状态 = 2 次/执行
按 cron 每 4 小时一次:批量 = 12 次/天,逐条 = 36 次/天
批量回写余量更大,更安全
A4. 为什么不让 LLM 负责时间戳
LLM 翻译时常会合并/拆分条目、改写时间格式、漏掉条目,导致时间轴错位。因此采用"原文 SRT 条目数 = 译文条目数"的强约束:按顺序逐条配对,仅替换 text,时间戳一律沿用 ASR 原始值。若 LLM 返回条目数不匹配则判失败重试,绝不强行拼装。(详见 §16.3.4)
相关文章
暂无相关文章
