Install
openclaw skills install @arvinyin1/ig-link-bili-skill把 Instagram Reel 链接(用户提供)下载、翻译、转载到 B 站。**不做** IG feed/hashtag 自动抓取、**不做**点赞阈值筛选、**不做**去重、**不做**作者黑名单——链接都是用户主动给的,过滤掉反而是 surprise。当用户提供 instagram.com/reel/<code>/ 或 /p/<code>/ 链接并希望转载/搬运/上传到 B 站时激活。
openclaw skills install @arvinyin1/ig-link-bili-skill把用户给的一条(或一批)Instagram Reel/Post 链接下载、翻译、转载到 B 站。
核心约束:链接都是用户主动给的——不做抓取/筛选/去重/黑名单。
编辑风格不写死(v1.5.0):标题、描述、分区(category)、标签(tags)都不固定—— 默认由 agent 按视频内容 + 用户意图临时决定,通过命令行参数传给
upload_one.py。 想给固定频道设默认的,复制config.example.json为config.json填一次即可 (解析优先级:命令行 > config.json > 兜底)。不自动加入任何合集。
⚠️ 撞墙时——先读
references/diagnosis-methodology.md,再读references/pitfalls.md。元归因纪律(裸 curl 验证 ≠ 真实请求形态)比单条 pitfall 更重要。
用户消息里:
/reel/<code>/、/p/<code>/、/tv/<code>/)不触发:
| 工具 | 用途 | 安装 |
|---|---|---|
| Python 3.8+ | 跑上传脚本 | 系统已带 |
httpx aiohttp beautifulsoup4 lxml requests | B 站 API client | pip install -r bilibili_uploader/requirements.txt |
yt-dlp | 公开下载 IG Reel(无需 IG 账号) | brew install yt-dlp 或 pip install yt-dlp |
ffmpeg | 截视频第 1 秒做封面 | brew install ffmpeg |
browser_cookie3 | 从浏览器拉 B 站 cookie(首次必跑) | pip install browser_cookie3 |
| B 站 cookie | 分发包里 credentials.json 是占位模板,首次使用前必须自己刷 | python3 scripts/setup_cookies.py(自动探测浏览器;支持 chrome/edge/brave/arc/vivaldi/firefox/safari 等,不限 Chrome) |
无 WebBridge 也能跑——caption 通过 yt-dlp --write-info-json 拿(fallback)。
对每个 IG 链接串行执行:
解析 shortcode——从 URL 抽 reel/DYyvKNpEdoo/ 的 DYyvKNpEdoo
下载 + 元数据:
./scripts/prepare_media.sh <shortcode> [/tmp/ig_link_bili]
→ 产出 <shortcode>.mp4 + <shortcode>.info.json(含 uploader/like_count/description)+ <shortcode>thumb.jpg
生成标题/描述/分区/标签(agent 脑内,按内容 + 用户意图,不写死):
config.json 指定了固定前缀就用,否则不加。转载来源:Instagram - 原作者:@<uploader>\n\n<1-2 句中文概述>\n\n—— 原简介 ——\n<原文>;不要在简介里写原视频链接;保留 studio 名 / 软件名 / 行业英文术语不译。config.json。config.json。上传 B 站:
python3 ./scripts/upload_one.py <shortcode> "<标题>" "<描述>" --category <TID> --tags 标签1,标签2
--category 必填(命令行或 config.json 二选一);--tags 可选;来源默认自动用该 Reel 的 IG 链接bvid + aid验真(**必做,**B 站接口异步——upload_one.py 返 success 不代表真成功):
sleep 60
python3 ./scripts/verify_upload.py <bvid>
→ "OK " 才是真成功;FAIL/PENDING 要重试或排查
⚠️ 不要跳过这一步——2026-06-05 实测跳过的代价是把 8 个作者错误拉黑。详见 references/upload-verification.md。
撞墙时的诊断顺序(2026-06-07 教训):如果 upload_one.py 抛 Expecting value: line 1 column 1 JSON 解析失败,不要先归因"B 站挂了"——按 references/pitfalls.md §7 决策树跑 Step 1-3。api.bilibili.com/x/web-interface/nav 的 isLogin 字段是判定 cookie 是否真有效的关键。
汇报:返回 B 站视频 URL https://www.bilibili.com/video/<bvid>
ig-link-bili/
├── SKILL.md ← 你正在看的
├── config.example.json ← 可选配置模板(复制为 config.json 设固定的分区/标签/标题前缀)
├── scripts/
│ ├── setup_cookies.py ← 首次必跑:从本机浏览器抓 B 站 cookie 写入 credentials.json(支持多浏览器,自动验真)
│ ├── prepare_media.sh ← 一步:下载 mp4 + 截封面 + 拉元数据 JSON
│ ├── upload_one.py ← 单条上传 wrapper(分区/标签走参数或 config.json,不写死)
│ └── verify_upload.py ← B 站 API 验真(带重试)
├── bilibili_uploader/ ← 自包含 B 站上传库(拷自 wscats/bilibili-all-in-one)
│ ├── main.py
│ ├── src/
│ ├── credentials.json.template ← cookie 模板(真 credentials.json 由 setup_cookies.py 生成,已 .gitignore)
│ └── requirements.txt
├── examples/ ← 几个测试链接
└── references/ ← 已知坑、失败案例
├── pitfalls.md ← cookie 三件套、preupload 403 决策树等
└── upload-verification.md
用户一次贴 N 条链接(比如一个 IG profile 的几个 Reel):
接口立刻返 success: true + bvid,但 api.bilibili.com/x/web-interface/view?bvid=X 真可查可能要等 30s-2min。不要看到 success 就立刻验真——verify_upload.py 默认重试 3 次每次等 30s 兜底。
不用 WebBridge——yt-dlp --write-info-json 拿到的 description 字段就是 caption。
如果 description 是非英文(如俄语/西语)→ agent 翻译。
如果 description 是中文 → 直接用,不翻译。
prepare_media.sh 的封面逻辑是双保险:
yt-dlp --write-thumbnail --convert-thumbnails jpg 拉 IG 官方封面(CDN 单独资源,经常是设计过的宣传图)ffmpeg -ss 00:00:01 -vframes 1 从 mp4 截第 1 秒帧Arvin 偏好 2026-06-07:永远先尝试官方封面——截帧兜底通常拿到的是视频启动瞬间(黑屏/logo),信息量弱。实测:3 条 Reel 复测,2/3 拿到官方宣传封面(设计过的),1/3 自动 fallback 到截帧。
只有一种情况失败:极短视频(<1s)——ffmpeg -ss 00:00:01 抽不到帧——upload_one.py 检测到 cover 缺失会跳过,B 站自动生成默认封面。
症状:upload 失败、verify_upload.py 报 PENDING、preupload 返 403、nav API 报 -101 ——任一出错时,agent 第一反应往往是"B 站挂了"或"接口被风控"。
Arvin 明确反对(2026-06-07 教训):撞墙时先排除自己的问题(cookie / 编码 / shell 引号 / agent 读到的状态过期),再归因上游。
错误示范(2026-06-07 撞过的真实翻车):
正确做法(撞墙时强制顺序):
references/pitfalls.md §7 决策树跑 Step 1-3,至少跑到 Step 3 isLogin 判定Arvin 的明确偏好原话(2026-06-07):"Codex 反例成立之前不要判'B 站挂了'。我们本机实测反例已否定了'风控全量拦截'理论。"
记忆锚点:任何"上游抽风 / 风控 / 服务器挂"的判断,必须有本机近 30 分钟的诊断证据支撑,且没被别的 agent 反例证伪。否则就是脑补。
分发包里的 bilibili_uploader/credentials.json 是占位模板(YOUR_SESSDATA_HERE),直接用必然 403。
首次使用前在某个浏览器登录 bilibili.com,然后跑:
pip install browser_cookie3
python3 scripts/setup_cookies.py # 自动探测;或 --browser firefox 指定
脚本从同一浏览器同一会话取三件套(sessdata+bili_jct+buvid3,缺一或混源必 -101,见 references/pitfalls.md §8)、写入 credentials.json、并验真。过期了重跑同一条命令。
撞墙症状(必认):upload_one.py 抛 Expecting value: line 1 column 1 + curl api.bilibili.com/x/web-interface/nav
返 isLogin: false —— 几乎一定是本机 cookie 失效(不是 B 站上游),先 python3 scripts/setup_cookies.py 重刷再说。
30 秒判定:
SESSDATA=$(python3 -c "import json,pathlib; print(json.loads(pathlib.Path('bilibili_uploader/credentials.json').read_text())['sessdata'])")
curl -sS -m 10 "https://api.bilibili.com/x/web-interface/nav" -b "SESSDATA=$SESSDATA" | python3 -c "import json,sys; print('isLogin:', json.load(sys.stdin)['data']['isLogin'])"
# false → 重刷 cookie;true → 才考虑按 §7 决策树查上游
对公开 Reel,yt-dlp 不需要任何 Instagram 登录态——零封号风险。如果某个 shortcode 公开下载失败(罕见),脚本会原样报错,不会 fallback 到 Cookie 认证。
旧 skill 的"教程/BTS/广告/访谈"4 类排除不在本 skill 范围内。链接都是用户给的,用户已经知道内容。 同样的,本 skill 不做去重——用户重复给链接就重复传(让用户自己发现)。 如果你确实需要过滤,在 agent 调 upload_one.py 之前自己加判断。
| 现象 | 排查 |
|---|---|
yt-dlp 报 HTTP 4xx/5xx | VPN/网络问题,确认能访问 instagram.com |
yt-dlp 报 "Sign in to view" | 该 Reel 是非公开的,换链接 |
upload_one.py 返 "video not found" | 没跑 prepare_media.sh,或 shortcode 拼错 |
upload_one.py 返 "cookie expired" | bilibili_uploader/credentials.json 需要更新——在 Chrome 登录 B 站后用 browser_cookie3 三件套一起提取。详见 references/pitfalls.md §6 §8 |
verify_upload.py 返 PENDING | 正常,等 1-2 分钟再 retry |
verify_upload.py 返 FAIL 多次 | B 站可能真把这条拒收了(站内外重复 / 版权)——别再传,告知用户 |
upload_one.py 抛 Expecting value: line 1 column 1 JSON 解析失败 | preupload 返了 HTML 不是 JSON。先不要判定"CDN 抽风"——按 references/pitfalls.md §7 决策树跑 Step 1-3 诊断:curl preupload 看状态码 + curl api.bilibili.com/x/web-interface/nav 验 isLogin 字段。可能是 SESSDATA 空 / 三件套不配套(§8)/ skill 自带 cookie 是空(§9)/ ig-link-bili 池与主池不同步(见上方"credentials.json 与主池独立"pitfall),不一定都是 B 站上游问题。必须先验登录态再归因。 |
instagram-to-bilibili skill 的关系原 skill(v1.5.0):自动抓 IG feed/hashtag + 阈值筛选 + cron 调度。今天反复撞墙的部分(login wall / yt-dlp 不支持列表 / WebBridge 行为古怪)全在这。
本 skill(v1.1.0):用户给链接,下+译+传+验。不抓取、不筛选。
两者并列存在——根据场景选:
注:
instagram-to-bilibili是作者本机的另一个 skill,分发包里不含它;本节仅说明定位差异。