Skip to main content
Glama


为 ai 而生的哔哩哔哩

bili-ai

B 站客户端的 headless 内核 + 双前端:AI 走 MCP / CLI / HTTP 操控,人看可视化后台。 无窗口、无 Electron、无 Rust、无 Node,主体是 Python 标准库。

不接大模型、不需要任何 API Key——项目只负责"把 B 站的数据与动作变成 AI 可读可写的接口", 读什么、写什么由调用它的 AI 决定。

License: MIT Python MCP No API Key

git clone https://github.com/wjw-exe/bili-ai.git
cd bili-ai                       # 必须在项目根目录运行,bili 是包
python -m venv .venv
.venv\Scripts\activate           # PowerShell: .\.venv\Scripts\Activate.ps1
python -m pip install -U pip
python -m pip install -r requirements.txt
python main.py serve             # → http://127.0.0.1:8770

装完先跑一次 python main.py selftest 验证链路,再开后台。装不上/起不来的对号入座见 安装 与 启动不起来?。

        ┌──────────── MCP(35 工具) / CLI / HTTP ────────────┐
        │                                                     ▼
   AI 客户端 ──► core.execute(name, args) ───────────► StateStore(唯一真相源)
                                                             │
                       可视化后台(浏览器) ◄── SSE 0.35s ────┘
                                ▲
                                │ 同一份 store / 同一套 execute
              inbox.py(回复我 / @我)· roam.py(巡览取片 → 读字幕 → 待评论任务)

Related MCP server: Bilibili API MCP Server

它解决什么问题

B 站的开放能力是按"人点按钮"设计的:接口分散、风控隐晦、状态在页面里。 对 AI 来说,难点不是"能不能调接口",而是能不能拿到稳定可读的状态、并且知道自己下一步能做什么。

bili-ai 的三条设计原则:

  • 单一真相源:搜索结果、当前视频、播放进度、字幕、评论、互动状态、命令日志全在 store.py, MCP / CLI / Web 三个前端都从它渲染,不靠 DOM 反推,也不各自维护副本。

  • 紧凑文本协议:MCP 工具只返回纯文本,一行一条、短键、稳定 bvid,不返回 JSON—— 不让模型把 token 花在括号和字段名上;每条输出末行 actions: 告诉 AI 下一步能发什么命令,避免瞎试。

  • 写操作显式、可审计:点赞 / 投币 / 收藏 / 发评论 / 回消息都是真实写账号的行为, 未登录统一返回 ERR_NEED_LOGIN 阻断,绝不静默失败;自动回复与巡览都先生成任务、再等文案回填, 项目内部不生成任何文案、不自动群发。

功能一览

分类

能力

状态

浏览

关键词搜索(分页 / 总量 / 时长 / 播放量 / UP)

已实现

浏览

视频详情、多 P 分 P 信息

已实现

播放

逻辑播放器:play / pause / resume / seek(绝对或相对)

已实现

评论

读评论(热门 / 时间)、分页

已实现

评论

发评论、回复某条评论(root / parent)

已实现

互动

点赞 / 投币(1~2)/ 收藏 / 取消收藏 / 列收藏夹

已实现

弹幕

读当前 P 弹幕(全量 / 按时间窗口)、分页

已实现

弹幕

发弹幕(danmaku,默认 dry-run,confirm=true 才真发)

已实现

字幕

列 CC / AI 字幕轨、分页读正文、导出 srt / txt / md

已实现

消息

收件箱:别人回复我 / @我 的评论,去重、去已回复

已实现

消息

用外部 AI 给的文案回复某条消息,并记账防重复

已实现

巡览

定时自动挑视频 → 读字幕 → 生成待评论任务(无字幕不发)

已实现

巡览

取任务(含字幕正文)→ 回填文案发布 / 跳过,受每日上限约束

已实现

投稿

查分区 tid、我的稿件与审核状态

已实现

投稿

上传本地视频并提交审核(upload,默认 dry-run,confirm=true 才真发)

已实现

登录

后台扫码 / 命令行扫码 / 粘贴 Cookie,登录态热重载

已实现

浏览

真实取流 playurl、删评论

未实现

目录

文件

职责

main.py

入口:serve / mcp / cli / login / status / logout / selftest

bili/sign.py

wbi 签名(mixin key 换表 + 参数排序)

bili/http.py

HTTP 层:cookie 罐(登录态持久化 + mtime 热重载)、暖机、风控识别与退避

bili/auth.py

登录:分步扫码(申请 / 出图 / 轮询)/ Cookie 导入 / nav 校验

bili/api.py

B 站 Web 接口封装:warmup / search / hot_videos / view / subtitles / comments / comment_add / msgfeed / 互动 / danmaku(读 list.so + 发 dm/post)

bili/store.py

StateStore + 逻辑播放器(时钟推进)+ 评论 / 字幕 / 互动 / 收件箱 / 巡览状态

bili/fmt.py

文本展现层(表格化紧凑输出)

bili/core.py

命令总线,MCP / Web / CLI 共用同一 execute

bili/upload.py

投稿链路:preupload → upos 分片上传 / 合并 → 封面上传 → web add 提交审核

bili/mcp_server.py

MCP stdio 层,35 个工具

bili/inbox.py

消息收件箱:拉 msgfeed/reply + msgfeed/at、归一化、baseline、回复记账

bili/llm.py

外部大模型接入(可选):base_url / model / api_key 配置与连通性测试,供自动回复 / 巡览拟稿调用

bili/autoreply.py

自动回复:后台轮询收件箱 → 取待回消息 → 大模型拟稿 → 回填 / 发送(默认关闭)

bili/roam.py

AI 巡览:取片 → 过滤已见 → 读字幕 → 落 waiting 任务 → 发布 / 跳过

bili/web.py

FastAPI 后台 + SSE + 图床代理 + 扫码登录 + 收件箱 / 巡览 / 大模型接口

static/index.html

单文件前端,零资源依赖

tests/

离线回归测试(pytest tests -q,不联网、不依赖登录态)

skills/bili-ai/SKILL.md

给 AI 客户端读的接入说明(唯一副本,根目录不再保留同名文件)

环境要求

项

要求

说明

Python

3.10+(实测 3.11)

代码用了 X | None 与内置泛型注解,3.9 及以下会报 TypeError

mcp

1.2 ≤ 版本 < 3

1.x 服务端类叫 FastMCP,2.x 改名 MCPServer,本项目两者都兼容;区间外直接 ImportError

fastapi / uvicorn

已列入 requirements

只有 serve、以及 mcp 附带的浏览器后台需要;mcp --no-web 纯 stdio 也仍会 import

Node / Rust / Electron

不需要

前端是单文件 static/index.html,零构建

网络

能访问 bilibili.com

首次运行会暖机拿 Cookie,跨境网络可能触发风控 v_voucher

安装

cd D:\projects\bili-ai          # 你的项目目录,必须是 main.py 所在层
python -m venv .venv
.\.venv\Scripts\Activate.ps1    # cmd 用 .venv\Scripts\activate.bat;Git Bash 用 source .venv/Scripts/activate
python -m pip install -U pip
python -m pip install -r requirements.txt

四条硬性注意:

  1. 必须在项目根目录执行。bili/ 是包,main.py 用相对导入;在别的目录 python D:\projects\bili-ai\main.py 会 ModuleNotFoundError: No module named 'bili'。

  2. 用 python -m pip,不要裸 pip。机器上常有多套 Python,裸 pip 可能装到另一个解释器,启动时照样报缺包。

  3. mcp 版本按区间装。requirements.txt 已写 mcp>=1.2,<3;若你曾手动 pip install mcp 装到旧版或未来的大版本,先 python -m pip install -U "mcp>=1.2,<3"。

  4. 升级依赖别整套 overwrite。已经有环境时只 python -m pip install -r requirements.txt,不要 pip freeze > requirements.txt 反向覆盖。

安装完成的判定(三条都应通过):

python -V                                            # 3.10 以上
python -c "import fastapi, uvicorn, httpx, segno"     # 无输出即通过
python -c "import bili.mcp_server as m; print(m.SERVER_API)"   # 打印 fastmcp (mcp 1.x) 或 mcpserver (mcp 2.x)

最后一条能打出 SERVER_API,说明 MCP 层和当前 mcp 版本对上了——这是"按 README 装完却起不来"最常见的一环。

运行

所有命令都在项目根目录执行。

python main.py serve                # 人看的后台 http://127.0.0.1:8770
python main.py serve --port 8772    # 换端口
python main.py mcp                  # MCP stdio(同时起后台,可扫码登录)
python main.py mcp --no-web         # 纯 MCP
python main.py cli search 猫 --limit 5
python main.py cli open_video BV1GJ411x7h7
python main.py cli inbox --kind reply
python main.py selftest             # 联网全链路自检

启动不起来?

按现象对号入座,前三条覆盖了绝大多数情况:

现象

原因

处理

ModuleNotFoundError: No module named 'bili'

当前目录不是项目根目录,或 IDE 里直接运行了 bili/ 下的文件

cd 到 main.py 所在目录再执行;IDE 的运行配置把 Working directory 指向项目根

ModuleNotFoundError: No module named 'fastapi'(或 uvicorn / httpx / segno)

依赖装进了另一套 Python,或 venv 没激活

激活 venv 后 python -m pip install -r requirements.txt;用 python -V 和 python -m pip -V 确认两者路径一致

ImportError: 未找到 MCP 服务端类:需要 mcp>=1.2

mcp 版本低于 1.2 或 ≥3,1.x / 2.x 类名都对不上

python -m pip install -U "mcp>=1.2,<3"

AttributeError / TypeError: run() got an unexpected keyword argument 'transport'

mcp 版本与启动签名不匹配

同上拉开到 1.2~2.x;本项目 run() 已按 transport= 与位置参数两种写法自适应

OSError: [Errno 10048] error while attempting to bind 127.0.0.1:8770

8770 被占(上一次进程没退干净)

python main.py serve --port 8772;或先 Get-NetTCPConnection -LocalPort 8770 找到进程结束

UnicodeEncodeError: 'gbk' codec can't encode

Windows 控制台默认 GBK

chcp 65001,或 $env:PYTHONUTF8=1 后重开

python : 无法将“python”项识别为

Python 未装或没进 PATH

装 3.10+ 并勾选 Add to PATH;或用 py -3 main.py serve

后台能打开但一片空白 / 接口 500

前端在 static/index.html,缺文件或 cwd 不对

确认从项目根启动;python main.py selftest 看具体断点

启动成功的样子:

INFO:     Uvicorn running on http://127.0.0.1:8770 (Press CTRL+C to quit)

浏览器打开 http://127.0.0.1:8770 能看到三栏后台(Now Playing / 搜索·评论·字幕 / Command Log)即正常。 MCP 侧另测一条:python main.py mcp --no-web 后由客户端 initialize + tools/list 应返回 35 个工具。

接到 MCP 客户端

{
  "mcpServers": {
    "bili": {
      "command": "python",
      "args": ["D:\\projects\\bili-ai\\main.py", "mcp"],
      "cwd": "D:\\projects\\bili-ai"
    }
  }
}

此时后台会自动起在 8770。后台拥有自己的 Core 实例(避免跨线程操作主 loop 的连接池), 按钮可点、可扫码登录;两边共用同一个 StateStore,所以 AI 的每一步与人的每次点击 都会实时反映到同一份快照上。mcp --no-web 时不起后台,纯 stdio 工具服务。

用 venv 装的依赖,command 要写 venv 里的解释器绝对路径,否则客户端会用系统 Python 启动而报缺包: "command": "D:\\projects\\bili-ai\\.venv\\Scripts\\python.exe"。cwd 必须保留,bili 是包。

三个 AI 闭环

A. AI 替我写评论(先读懂,再写)

search "编译器原理" → open_video BV1xx → subtitle --lang ai-zh --limit 200
   → (AI 阅读字幕并撰写)→ comment --message "……"

B. 有人回复我,AI 代写回复

inbox --kind reply            # 只检测:列出谁回了什么、我在原评论说了什么
   → (AI 依据上下文生成文案)→ reply --msg-id 1184712873918478 --message "……"

inbox 只做检测、不发任何东西;reply 必填文案,缺了直接 ERR_NEED_TEXT。 已回复的消息写入 .data/inbox.json 记账,only_unreplied=true 时不再出现,天然防重复。

C. AI 自己巡览 B 站(不预设文案,先读后写)

roam --on --interval 1800 --max-per-day 5 --source hot
   ↓ 后台每 30 分钟:热门榜挑片 → 查字幕轨 → 拉正文
   ↓ 无字幕 / 空正文 / 轨锁定 → 记 skipped,绝不发评论
roam_next                     # 取一个 waiting 任务:视频信息 + 前 2000 字字幕正文
   → (AI 阅读后写评论)→ roam_comment --task-id T20261024xxxx --message "……"
roam_status                   # 开关 / 频率 / 今日已发 / 最近任务及跳过原因
  • 每个 bvid 只处理一次(seen_bvid,上限 3000 条滚动淘汰);

  • 频率硬下限 120 秒(小于一律收敛),默认 30 分钟;每日发布上限默认 5,0 表示不限;

  • 来源 hot(综合热门)或 search(关键词轮询,默认 科技, 数码, 编程,可自定义);

  • 文案一律由调用方传入,服务端只负责"发"与"记账"。

命令协议

MCP 工具、main.py cli <cmd>、POST /api/cmd 三者参数完全一致。

命令

参数

说明

search

keyword page=1 limit=10

关键词搜索,写入列表状态

open_video

bvid

打开详情并设为播放目标

play

bvid="" at=0

开始逻辑播放,传 bvid 则先打开

pause / resume

—

冻结 / 续播

seek

to

绝对 "120",相对 "+15" / "-30"

state

—

完整状态:视图 + 数据 + 进度 + 可用动作

status

—

只读一行进度,最省 token

comments

bvid="" page=1 limit=20 mode=3

读评论,mode 3=热门 2=时间;真分页(limit 夹在 1–20),置顶条目带 top=true 且只在首页出现,翻页自动去重

comment

message bvid="" root=0 parent=0

发评论(真实写),root/parent 非 0 为回复;需登录

like

bvid="" on=true

点赞 / 取消点赞

coin

bvid="" n=1 also_like=false

投币,n ∈ {1,2}

fav

bvid="" folder=""

收藏,folder 可填 id 或名称,留空收进第一个夹

unfav

bvid="" folder=""

取消收藏,留空 = 从所有夹移除

folders

—

列收藏夹(id / 名称 / 条目数)

subtitles

bvid="" page=1

列出字幕轨(lan / 语言 / 是否 AI / 是否需解锁)

subtitle

bvid="" lang="" page=1 offset=0 limit=200 export=""

读字幕正文(按句分页,limit 上限 500),export=txt/srt/md 落盘

me

—

当前登录账号,并刷新后台账号显示

inbox

kind=all limit=20 only_unreplied=true

收件箱:all / reply / at,只检测不发送

reply

msg_id message

按 msg_id 回复该条消息,文案必填,上限 1000 字;需登录

roam

on/off interval max_per_day source keyword llm_draft llm_publish

巡览配置;interval 秒(下限 120),后两个开关控制是否让大模型拟稿 / 直接发

roam_status

—

巡览运行状态:开关 / 频率 / 每日上限 / 计数 / 最近任务(含 skipped 原因)

roam_list

status="" limit=20

列巡览任务(waiting / sent / skipped / failed)

roam_check

count=1

立刻跑一轮取片,只落任务、不发评论

roam_next

task_id=""

取 waiting 任务:视频信息 + 前 2000 字字幕正文

roam_draft

task_id="" publish=null force=false

让内置大模型拟稿(只写草稿,默认不发);publish 切换该任务是否直接发

roam_draft_set

task_id text by="agent"

把外部 AI 写好的文案存成草稿,by 记录来源(agent / llm),只存不发

roam_send

task_id=""

发布已有草稿(真实写、不可撤回、受每日上限);留空取最早一个带草稿的任务

roam_comment

task_id message

发布巡览评论(真实写,不可撤回,受每日上限)

roam_skip

task_id reason=manual

跳过某任务并记原因

llm

—

外部大模型配置与用量(llm_status 同源):模型、Key 掩码、今日拟稿 / 发送数、最近错误

llm_configure

api_key="" base_url="" model="" roam_prompt="" prompt="" clear_key=null

配置 OpenAI 兼容大模型;Key 只落本地 .data,永不明文回显

llm_test

—

真打一次上游接口验证 Key / 地址 / 模型,不写任何 B 站数据

upload_zones

top=0

列投稿分区(父分区 → tid 子分区),选 tid 用

upload

file title tid desc="" tag="" cover="" copyright=1 source="" confirm=false

投稿视频:默认 dry-run 只预检,confirm=true 才真上传 + 提交审核

upload_list

pn=1 ps=10

我的稿件与审核状态(state_desc)

like / coin / fav / unfav / folders / comment / reply / roam_comment / roam_send / upload / upload_list / upload_zones 需要登录态,未登录返回 ERR_NEED_LOGIN(提示去后台扫码),不会静默失败。

输出示例:

view=search q="猫" page=1 total=1000 shown=2
#1  BV1Uqpk64EaL    2:18  play=   1.3万  up=橘猫黄小胖  打预防针
#2  BV1WxHA6BESP    1:15  play=   2088  up=人生说明书16888  猫贩子第十集
next: search --keyword "猫" --page 2

收件箱输出示例:

inbox: 2 条  kind=reply  only_unreplied=1  fetched=46  replied=7
- msg_id=1184712873918478  [reply]  某UP(123456)  status=new  视频 BV1xx411c7mD  《标题》
  他说: 你上次说的那个方案能详细讲讲吗
  我: 第三段的思路挺关键的
actions: [reply --msg-id <id> --message "<AI 生成的文案>"]

投稿(发视频)

upload 是全链路投稿:本地预检 → preupload 申请线路 → upos 分片上传(默认 3 线程、分片重试)→ 合并分片 → 可选封面上传(PIL 在则裁 16:10)→ x/vu/web/add 提交审核。

python main.py cli upload_zones                                   # 先挑分区 tid
python main.py cli upload --file D:\a.mp4 --title "标题" --tid 21 --tag 编程,自制   # 只预检(dry-run)
python main.py cli upload --file D:\a.mp4 --title "标题" --tid 21 --tag 编程,自制 --confirm
python main.py cli upload_list                                    # 看审核状态

MCP 侧同名工具:upload_zones / upload_video / upload_list;upload_video 的 confirm 默认 false,只回投稿计划、不上传任何字节。

注意几条:

  • 投稿是真实发布,过审后公开可见、不可撤回,所以 confirm 必须显式给;先 dry-run 看清标题/分区/标签。

  • 标题 ≤ 80 字;单文件 ≤ 8G,支持 mp4/flv/mov/mkv/avi/wmv/webm/m4v;copyright=1 自制、2 转载(转载必须给 source 原地址)。

  • 分片大小以 preupload 返回的 chunk_size 为准(实测 10MB),不是本地写死。

  • 提交返回码会翻成人话:21001 参数/分区错、21564 投稿频率限制、21540 需网页端人工过校。

  • 新版分区体系要 tid_v2:默认可不填,出现 21001 时程序会用投稿预接口反查一次并自动重提;也可手动传 tid_v2。

  • 别拿无效参数试探提交接口:每发一次 /x/vu/web/add 都算一次投稿,连续几次就会吃 21564(24 小时级频率限制), 严重时 preupload 直接 403、SESSDATA 被失效,需要重新扫码登录。预检一律走 upload(省掉 --confirm),它不发任何请求。

  • 稿件 ID 从 upload_list 或 state(upload.last)拿;刚提交时 state=0 之前是审核中,属正常。

字幕(外部 CC,不含画面内嵌字幕)

B 站的 AI 字幕 / 人工字幕都属于外挂轨,可通过 player/wbi/v2 拿到 subtitle_url 再拉正文; 画面里烧死的硬字幕没有对应数据,取不到,本项目也不做 OCR。

subtitles                                        # 列轨:lan=ai-zh 中文 ai=1 lock=0
subtitle --lang ai-zh --offset 300 --limit 200   # 分页读正文,末行 next: 给下一页
subtitle --lang ai-zh --export srt               # 导出到 .data/subs/BVxxx_ai-zh.srt

输出是便于 AI 阅读的逐句文本,时间码 [mm:ss] 便于定位:

view=subtitle  bvid=BV1zNoVB1EWb  lan=ai-zh  中文  ai=1  cues=4709  chars=49592  offset=300 limit=4
[11:39] 啊就那时候口气很大啊
[11:41] 这是哪一年时候
next: subtitle --offset 304 --limit 4
  • 字幕正文进程内缓存(同一 bvid+lang 只拉一次),翻页不重复请求。

  • subtitle_url 带签名参数,拉取时不能再加普通参数,否则 403——http.get_raw_json 专为此实现。

  • 后台第三个 Tab「字幕」可视化同一份数据:自动选 ai-zh、每页 300 句、可「加载更多」、可导出 txt。

  • 该视频没有字幕轨时返回 tracks=0 明确提示,而不是空正文——巡览器据此判定"跳过、不发评论"。

登录

登录态统一落在 .data/cookie.json(权限 0600,仅存 bilibili 域 cookie),进程启动时自动装载, serve / mcp / cli 共用。

方式一:后台扫码(推荐,图形界面)

python main.py serve 打开 http://127.0.0.1:8770,点右上角**扫码登录**:

  1. 后台申请二维码,弹层里直接出图(/api/auth/qr + /api/auth/qr.png);

  2. 前端每 1.6 秒轮询 /api/auth/poll,扫码后提示「已扫码,请在手机上确认」;

  3. 确认成功后自动落盘 cookie.json,右上角变成头像 + 昵称,退出按钮可清态。

登录成功后无需重启进程:http.py 的 sync_from_disk() 会在每次请求前比对 cookie.json 的 mtime, 后台写入的新 cookie 会被 MCP / CLI 侧自动热重载。

方式二:命令行扫码

python main.py login

流程:申请二维码 → 渲染成 .data/login_qr.png 并自动打开 → 手机 B 站客户端「扫一扫」→ 手机端点确认 → 自动写入 cookie 并回验昵称。默认 180 秒超时,可 --timeout 60 调整,--no-open 不自动弹图。

浏览器登录 bilibili.com → F12 → Application → Cookies → https://www.bilibili.com, 取 SESSDATA、bili_jct、DedeUserID 三项:

python main.py login --import-cookie "SESSDATA=xxx; bili_jct=yyy; DedeUserID=123"

也支持直接传 Cookie JSON。等价于把这三个键手写进 .data/cookie.json。

查看与退出

python main.py status   # 调 nav 接口真实验证,打印昵称 / mid / 大会员
python main.py logout   # 删除本地 cookie.json

mcp / serve 是常驻进程,cookie 只在启动时装载一次。后台扫码登录无需重启(每次请求前自动热重载); 命令行 login 写入后同样会被热重载,但 MCP 客户端缓存的连接若要立刻生效,最稳妥仍是重启。

后台界面

三栏:左「Now Playing」、中「搜索结果 / 评论 / 字幕」三 Tab、右「Command Log」。

  • 播放器下四个按钮:点赞 / 投币 / 收藏 / 评论,状态与 store.inter 同步 (liked / coins / favoured;未登录时三者均为 null,按钮变灰)。

  • 收藏点开后拉 /api/folders 选夹;已收藏再点即取消收藏。

  • 评论 Tab 顶部可切来源:热门 / 最新 / 回复我的 / @我的。后两者即收件箱视图, 每条显示对方说了什么、我的原评论、来源视频,可直接在输入框写回复发出(发出后标记已回复)。

  • 评论 Tab 上方是 AI 巡览条:开关、频率(分钟)、每日上限、来源(热门 / 关键词)、关键词、 「立即巡览」按钮;展开后每个任务卡带视频信息、字幕摘要、评论输入框与「跳过」。 这里的人工输入与 MCP 侧 roam_comment 走同一个发布函数,同样受每日上限约束。

  • 未登录点互动按钮 → 顶部 toast 显示 ERR_NEED_LOGIN,不会无声失败。

HTTP API

方法

路径

用途

GET

/api/state

当前完整快照

GET

/api/events

SSE 推送(约 0.35s 一次,仅变化时发)

POST

/api/cmd

执行白名单内命令:{"name": "...", "args": {...}}(29 个名字,含 inbox / reply / roam / llm 系列)

GET

/api/inbox

收件箱:kind / only_unreplied / limit

POST

/api/reply

回复某条消息:msg_id + message

GET

/api/folders

收藏夹列表

GET

/api/roam

巡览状态 + 任务列表

POST

/api/roam/set

改配置:开关 / 频率 / 上限 / 来源 / 关键词

POST

/api/roam/check

立即跑一轮取片

POST

/api/roam/next

取一个 waiting 任务

POST

/api/roam/comment

回填并发布评论

POST

/api/roam/skip

跳过任务

GET

/api/thumb

封面图代理(绕过 B 站 referer 限制)

POST

/api/auth/qr /api/auth/poll /api/auth/logout

扫码登录三件套

数据文件

全部在 .data/,已被 .gitignore 排除(含登录态,绝不入库):

文件

内容

cookie.json

登录态(仅 bilibili 域,权限 0600)

inbox.json

收件箱 baseline + 已回复记账(防重复回同一条)

roam.json

巡览配置、seen_bvid、任务列表、统计(picked / sent / skipped / failed / today_sent)

subs/

subtitle --export 导出的字幕文件

inbox.json / roam.json 同时被 store 镜像,因此 MCP 侧发的回复、网页侧点的按钮, 两边看到的是同一份进度,不会互相覆盖。

风控

未登录调搜索接口会被 B 站拦(返回 code=0 但 data 里只有 v_voucher)。http.py 已内置:

  1. 先访问 https://www.bilibili.com 暖机拿 b_nut / buvid3 等 Cookie;

  2. 搜索参数只保留最小集 keyword / search_type / page,多带即被拦;

  3. Referer 必须为 https://search.bilibili.com/all?keyword=<编码>;

  4. 命中 v_voucher 则丢弃 buvid3 / buvid4 / b_nut、退避 6 秒、重新暖机后重试一次。

巡览器另有自己的节流:频率硬下限 120 秒、一轮最多试 8 个候选、每片只处理一次, 避免"自动化"把账号跑进风控。

安全与边界

  • 写操作是真实的:点赞、投币、收藏、发评论、回消息都会改写你的 B 站账号, 调用即产生副作用(投币不可撤回)。工具描述里逐条标注「需要登录态」,未登录一律阻断。

  • 不生成文案:inbox / roam_next 只提供素材(谁说了什么、字幕正文), 文案由调用方 AI 或人在输入框里给,项目内没有任何"自动回话"的隐藏逻辑。

  • 不会群发:收件箱有 baseline + 已回复记账,巡览有 seen_bvid + 每日上限, 重复调用不会把历史消息重发一遍。

  • 不碰验证码:扫码登录依赖你手机上的确认,项目不做任何绕过。

已知限制

  • 已实现接口:search / hot_videos / view / pages / comments / comment / like / coin / fav / unfav / folders / subtitles / subtitle / nav(me) / msgfeed(reply, at) / danmaku_list / danmaku(post)。 未实现:高码率 playurl(真实取流)、删评论。

  • 弹幕读取上限:danmaku_list 走 x/v1/dm/list.so,返回的是接口可见的那部分弹幕(单 P 常见 1000~6000 条),不等于视频页显示的「弹幕总数」,输出里记为 visible=;要按时间看氛围用 around + window 只取窗口内。

  • 弹幕发送不可撤回:danmaku 与投稿同样默认 dry-run,只有显式 confirm=true(CLI --confirm) 才会真发;发出后公开可见、无法删除,短时间连发会被风控直接抛错,本端不重试。

  • 时长秒位:搜索接口对部分视频返回的 duration 本身是 16:0 这种缺位值,前端原样显示,不补零 ——补零等于伪造数据。open_video 后拿到的 dur 是精确秒数。

  • 逻辑播放:不对接真实播放器,t 是客户端时钟推算值,不是解码进度。

  • 巡览只处理有字幕的视频:没字幕就看不懂内容,宁可不发也不硬凑;这类视频只记 skipped 并进 seen。

  • 单进程单账号:一份 .data/ 对应一个登录态,多账号请复制项目目录或改 DATA_DIR。

自检

python main.py selftest

依次跑 warmup → search → open_video → play/seek/pause → comments + 写操作守卫 → subtitles → 弹幕列表 + 弹幕 dry-run → state,任一环节风控或报文异常会打印错误码。写操作守卫用非法 bvid 测试, 弹幕环节只 dry-run,不会真的点赞或发出弹幕。

版本

版本

内容

v0.1.x

搜索 / 详情 / 逻辑播放 / 评论 / 点赞投币收藏

v0.2.0

CC / AI 字幕读取与导出

v0.3.0

消息收件箱(回复我 / @我)、AI 代写回复、AI 巡览;后台改浅色中性主题

v0.3.1

修正安装说明:新增环境要求 / 安装判定 / 启动排错;requirements.txt 锁定 mcp>=1.2,<3;MCP 层兼容 mcp 1.x FastMCP 与 2.x MCPServer 两种类名及 run() 签名

v0.4.0

投稿(发视频):upload / upload_zones / upload_list;upos 分片上传(多线程、分片重试、合并重试)+ 封面上传(16:10 裁剪)+ web add 提交;默认 dry-run 安全阀

v0.4.1

评论真分页:/x/v2/reply(pn/ps)→ /x/v2/reply/wbi/main 游标 → plain main 三级降级;置顶只在首页保留并去重(字段 top,后台显示「置顶」标);深翻页空列表收口 is_end;新增 tests/ 离线回归(7 例)

v0.6.0

弹幕:danmaku_list(读当前 P 弹幕,around + window 时间窗、分页游标)、danmaku(发弹幕,100 字 / 滚动·顶部·底部 / #RRGGBB 颜色,默认 dry-run,confirm=true 才发);后台新增「弹幕」面板(时间轴列表 + 发送条,发送前二次确认);离线回归新增 13 例;MCP 工具由 33 增至 35

v0.5.0

接入外部大模型(OpenAI 兼容,Key 只落本地):llm / llm_configure / llm_test;收件箱自动回复轮询(填 Key 即用,默认关闭);巡览拟稿 roam_draft / roam_draft_set / roam_send,草稿来源隔离与跨进程并发仲裁;MCP 工具由 26 增至 33

License

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with Bilibili (哔哩哔哩) through its API, supporting video search and recommendations, user search, dynamic feeds, video collections, and danmaku retrieval through natural language.
    5
    -
  • A
    license
    A
    quality
    B
    maintenance
    Enables agents to search, explore trending content, retrieve video metadata and hot comments, and obtain subtitle transcripts for summarisation on Bilibili, with an anonymous tier and an optional account tier for personalized feeds.
    10
    3
    MIT