返回 Social Auto Upload
2026-03-25-bilibili-cli-implementation.md
根目录 / docs / superpowers / plans / 2026-03-25-bilibili-cli-implementation.md
1 # Bilibili CLI Implementation Plan
2
3 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
5 **Goal:** 为 Bilibili 补齐和抖音、快手同层级的 `sau` CLI、自动更新 `biliup` 的运行时机制、对应 skill,以及完整文档与上游致谢说明。
6
7 **Architecture:** 保持轻量,不新建大而全框架。新增一个 Bilibili 运行时模块负责检查 GitHub Release、下载/更新 `biliup`、执行命令;`sau_cli.py` 仅补 `bilibili` 子命令和参数映射;skill、example、README/CLI/install/update 文档按现有 Douyin/Kuaishou 结构对齐。
8
9 **Tech Stack:** Python 3.10+, `requests`, `argparse`, `asyncio`, `subprocess`, `pathlib`, `unittest`, GitHub Releases, existing `biliup` integration
10
11 ---
12
13 ## File Structure
14
15 ### New files
16
17 - `uploader/bilibili_uploader/runtime.py`
18 - Bilibili 运行时入口
19 - 负责 `biliup` 自动检查、自动下载、自动更新、执行命令
20 - `tests/__init__.py`
21 - 测试包初始化
22 - `tests/test_bilibili_runtime.py`
23 - 测试自动更新、下载、缓存复用、执行器行为
24 - `tests/test_sau_bilibili_cli.py`
25 - 测试 `sau bilibili` parser 和 dispatch 行为
26 - `skills/bilibili-upload/SKILL.md`
27 - Bilibili CLI skill 主说明
28 - `skills/bilibili-upload/references/runtime-requirements.md`
29 - 运行前提和自动下载说明
30 - `skills/bilibili-upload/references/cli-contract.md`
31 - `sau bilibili ...` 命令契约
32 - `skills/bilibili-upload/references/troubleshooting.md`
33 - 常见问题与排障
34 - `skills/bilibili-upload/scripts/examples/bilibili_commands.ps1`
35 - PowerShell 示例命令
36 - `skills/bilibili-upload/scripts/examples/bilibili_commands.sh`
37 - shell 示例命令
38 - `skills/bilibili-upload/scripts/examples/bilibili_cli_template.py`
39 - Python 调用模板
40
41 ### Modified files
42
43 - `sau_cli.py`
44 - 补 `bilibili` 子命令
45 - 复用现有 `resolve_account_file()`、`parse_tags()`、`parse_schedule()`
46 - `examples/get_bilibili_cookie.py`
47 - 对齐新的 `sau bilibili login` 用法
48 - `examples/upload_video_to_bilibili.py`
49 - 对齐新的 CLI/账号文件约定
50 - `README.md`
51 - 补 Bilibili CLI 用法、自动下载说明、致谢说明
52 - `docs/CLI.md`
53 - 补 `sau bilibili login/check/upload-video`
54 - `docs/install.md`
55 - 补 Bilibili 自动下载/首次运行说明
56 - `docs/update.md`
57 - 补 Bilibili 自动更新行为说明
58
59 ## Task 1: Bilibili 自动更新运行时
60
61 **Files:**
62 - Create: `uploader/bilibili_uploader/runtime.py`
63 - Create: `tests/__init__.py`
64 - Create: `tests/test_bilibili_runtime.py`
65
66 - [ ] **Step 1: 写 Bilibili 运行时测试**
67
68 使用 `unittest`,覆盖这些最小路径:
69
70 ```python
71 import unittest
72 from pathlib import Path
73 from unittest.mock import Mock, patch
74
75 from uploader.bilibili_uploader.runtime import (
76 build_biliup_runtime_path,
77 ensure_biliup_binary,
78 run_biliup_command,
79 )
80
81
82 class BiliupRuntimeTests(unittest.TestCase):
83 def test_build_biliup_runtime_path_returns_platform_path(self):
84 path = build_biliup_runtime_path("Windows")
85 self.assertTrue(str(path).endswith("biliup.exe"))
86
87 @patch("uploader.bilibili_uploader.runtime.fetch_latest_release")
88 def test_ensure_biliup_binary_downloads_when_missing(self, mock_release):
89 mock_release.return_value = {
90 "tag_name": "v1.0.0",
91 "asset_url": "https://example.invalid/biliup.exe",
92 "asset_name": "biliup.exe",
93 }
94 with patch("uploader.bilibili_uploader.runtime.download_biliup_asset") as mock_download:
95 ensure_biliup_binary(force_check=True)
96 mock_download.assert_called_once()
97
98 @patch("uploader.bilibili_uploader.runtime.fetch_latest_release")
99 def test_ensure_biliup_binary_reuses_local_when_up_to_date(self, mock_release):
100 mock_release.return_value = {
101 "tag_name": "v1.0.0",
102 "asset_url": "https://example.invalid/biliup.exe",
103 "asset_name": "biliup.exe",
104 }
105 with patch("uploader.bilibili_uploader.runtime.read_local_biliup_version", return_value="v1.0.0"):
106 with patch("uploader.bilibili_uploader.runtime.download_biliup_asset") as mock_download:
107 ensure_biliup_binary(force_check=True)
108 mock_download.assert_not_called()
109
110 @patch("uploader.bilibili_uploader.runtime.subprocess.run")
111 def test_run_biliup_command_returns_completed_process(self, mock_run):
112 mock_run.return_value = Mock(returncode=0, stdout="ok", stderr="")
113 result = run_biliup_command(["login"])
114 self.assertEqual(result.returncode, 0)
115 ```
116
117 - [ ] **Step 2: 运行测试,确认先失败**
118
119 Run:
120
121 ```powershell
122 .\.venv\Scripts\python.exe -m unittest tests.test_bilibili_runtime -v
123 ```
124
125 Expected:
126
127 - 因为 `uploader.bilibili_uploader.runtime` 还不存在而失败
128
129 - [ ] **Step 3: 写最小运行时实现**
130
131 在 `uploader/bilibili_uploader/runtime.py` 里先补这些最小函数:
132
133 ```python
134 def get_biliup_runtime_root() -> Path: ...
135 def build_biliup_runtime_path(system_name: str | None = None) -> Path: ...
136 def fetch_latest_release() -> dict: ...
137 def read_local_biliup_version() -> str | None: ...
138 def write_local_biliup_version(version: str) -> None: ...
139 def download_biliup_asset(release: dict, destination: Path) -> Path: ...
140 def ensure_biliup_binary(force_check: bool = True) -> Path: ...
141 def run_biliup_command(arguments: list[str]) -> subprocess.CompletedProcess[str]: ...
142 ```
143
144 约束:
145
146 - 不引入复杂 manifest
147 - 直接面向 GitHub Release 最新版本
148 - 本地只保存当前版本字符串和二进制
149 - 保持简单的路径/网络/替换逻辑
150
151 - [ ] **Step 4: 再跑运行时测试,确认通过**
152
153 Run:
154
155 ```powershell
156 .\.venv\Scripts\python.exe -m unittest tests.test_bilibili_runtime -v
157 ```
158
159 Expected:
160
161 - 所有 `BiliupRuntimeTests` 通过
162
163 - [ ] **Step 5: 提交这一小步**
164
165 ```powershell
166 git add uploader/bilibili_uploader/runtime.py tests/__init__.py tests/test_bilibili_runtime.py
167 git commit -m "feat: add biliup runtime bootstrap"
168 ```
169
170 ## Task 2: 接入 `sau bilibili` CLI
171
172 **Files:**
173 - Modify: `sau_cli.py`
174 - Create: `tests/test_sau_bilibili_cli.py`
175 - Reference: `uploader/bilibili_uploader/main.py`
176 - Reference: `utils/constant.py`
177
178 - [ ] **Step 1: 写 CLI parser 和 dispatch 测试**
179
180 在 `tests/test_sau_bilibili_cli.py` 中覆盖:
181
182 ```python
183 import unittest
184 from argparse import Namespace
185 from pathlib import Path
186 from unittest.mock import AsyncMock, patch
187
188 import sau_cli
189
190
191 class BilibiliCliTests(unittest.TestCase):
192 def test_build_parser_accepts_bilibili_login(self):
193 parser = sau_cli.build_parser()
194 args = parser.parse_args(["bilibili", "login", "--account", "creator"])
195 self.assertEqual(args.platform, "bilibili")
196 self.assertEqual(args.action, "login")
197
198 def test_build_parser_requires_tid_for_upload_video(self):
199 parser = sau_cli.build_parser()
200 with self.assertRaises(SystemExit):
201 parser.parse_args([
202 "bilibili", "upload-video",
203 "--account", "creator",
204 "--file", "demo.mp4",
205 "--title", "hello",
206 "--desc", "hello",
207 ])
208
209 def test_dispatch_bilibili_check_prints_valid(self):
210 args = Namespace(platform="bilibili", action="check", account="creator")
211 with patch("sau_cli.check_bilibili_account", new=AsyncMock(return_value=True)):
212 code = asyncio.run(sau_cli.dispatch(args))
213 self.assertEqual(code, 0)
214 ```
215
216 - [ ] **Step 2: 运行测试,确认先失败**
217
218 Run:
219
220 ```powershell
221 .\.venv\Scripts\python.exe -m unittest tests.test_sau_bilibili_cli -v
222 ```
223
224 Expected:
225
226 - 因为 `sau_cli.py` 里还没有 `bilibili` parser/dispatch 分支而失败
227
228 - [ ] **Step 3: 在 `sau_cli.py` 中补 Bilibili 请求模型和命令**
229
230 只做最小接入,保持和 Douyin/Kuaishou 同风格:
231
232 ```python
233 @dataclass(slots=True)
234 class BilibiliVideoUploadRequest:
235 account_name: str
236 video_file: Path
237 title: str
238 description: str
239 tid: int
240 tags: list[str]
241 publish_date: datetime | int
242 debug: bool = True
243
244
245 async def login_bilibili_account(account_name: str) -> dict: ...
246 async def check_bilibili_account(account_name: str) -> bool: ...
247 async def upload_bilibili_video(request: BilibiliVideoUploadRequest) -> Path: ...
248 ```
249
250 Parser 最小要求:
251
252 - `sau bilibili login --account <name>`
253 - `sau bilibili check --account <name>`
254 - `sau bilibili upload-video --account ... --file ... --title ... --desc ... --tid ... [--tags] [--schedule]`
255
256 Dispatch 最小要求:
257
258 - 和其他平台一样输出 `valid` / `invalid`
259 - 上传成功后打印简洁摘要
260
261 - [ ] **Step 4: 复用现有 B 站参数语义**
262
263 在 Bilibili wrapper 中直接沿用现有工程概念:
264
265 - `tid` 必填
266 - `tags` 用现有 `parse_tags()`
267 - `schedule` 沿用现有 `parse_schedule()`
268 - `account` 仍通过 `resolve_account_file("bilibili", account_name)` 得到项目内账号路径
269
270 - [ ] **Step 5: 再跑 CLI 测试,确认通过**
271
272 Run:
273
274 ```powershell
275 .\.venv\Scripts\python.exe -m unittest tests.test_sau_bilibili_cli -v
276 ```
277
278 Expected:
279
280 - `BilibiliCliTests` 通过
281
282 - [ ] **Step 6: 做一次联测**
283
284 Run:
285
286 ```powershell
287 .\.venv\Scripts\python.exe sau_cli.py bilibili --help
288 .\.venv\Scripts\python.exe sau_cli.py bilibili upload-video --help
289 ```
290
291 Expected:
292
293 - 能看到 `login` / `check` / `upload-video`
294 - `upload-video` 中 `--tid` 显示为必填
295
296 - [ ] **Step 7: 提交这一小步**
297
298 ```powershell
299 git add sau_cli.py tests/test_sau_bilibili_cli.py
300 git commit -m "feat: add bilibili cli commands"
301 ```
302
303 ## Task 3: 补 skill 和 example
304
305 **Files:**
306 - Create: `skills/bilibili-upload/SKILL.md`
307 - Create: `skills/bilibili-upload/references/runtime-requirements.md`
308 - Create: `skills/bilibili-upload/references/cli-contract.md`
309 - Create: `skills/bilibili-upload/references/troubleshooting.md`
310 - Create: `skills/bilibili-upload/scripts/examples/bilibili_commands.ps1`
311 - Create: `skills/bilibili-upload/scripts/examples/bilibili_commands.sh`
312 - Create: `skills/bilibili-upload/scripts/examples/bilibili_cli_template.py`
313 - Modify: `examples/get_bilibili_cookie.py`
314 - Modify: `examples/upload_video_to_bilibili.py`
315
316 - [ ] **Step 1: 参考 Douyin/Kuaishou skill 结构搭出 Bilibili skill**
317
318 要求:
319
320 - `SKILL.md` 风格和现有两个 skill 对齐
321 - 默认优先用 `sau bilibili ...`
322 - 明确写“程序会自动准备 `biliup`”
323
324 - [ ] **Step 2: 写示例命令文件**
325
326 示例命令至少包括:
327
328 ```powershell
329 sau bilibili login --account creator
330 sau bilibili check --account creator
331 sau bilibili upload-video --account creator --file .\videos\demo.mp4 --title "demo" --desc "demo" --tid 249 --tags 足球,测试
332 ```
333
334 - [ ] **Step 3: 修改本地 example**
335
336 让以下 example 明确转向新入口或新约定:
337
338 - `examples/get_bilibili_cookie.py`
339 - `examples/upload_video_to_bilibili.py`
340
341 要求:
342
343 - 不再让用户手动猜 `biliup.exe` 路径
344 - 明确说明现在推荐走 `sau bilibili ...`
345 - 继续保留 `VideoZoneTypes` 的使用示例
346
347 - [ ] **Step 4: 做一次文件级自检**
348
349 Run:
350
351 ```powershell
352 Get-ChildItem skills\bilibili-upload -Recurse
353 Get-Content examples\get_bilibili_cookie.py
354 Get-Content examples\upload_video_to_bilibili.py
355 ```
356
357 Expected:
358
359 - Bilibili skill 目录完整
360 - example 内容已切到新的 CLI/说明
361
362 - [ ] **Step 5: 提交这一小步**
363
364 ```powershell
365 git add skills/bilibili-upload examples/get_bilibili_cookie.py examples/upload_video_to_bilibili.py
366 git commit -m "feat: add bilibili upload skill"
367 ```
368
369 ## Task 4: 补文档与上游致谢
370
371 **Files:**
372 - Modify: `README.md`
373 - Modify: `docs/CLI.md`
374 - Modify: `docs/install.md`
375 - Modify: `docs/update.md`
376
377 - [ ] **Step 1: 在 README 中补 Bilibili CLI 用法**
378
379 至少写清:
380
381 - `sau bilibili login`
382 - `sau bilibili check`
383 - `sau bilibili upload-video`
384 - 自动下载/自动更新 `biliup`
385
386 - [ ] **Step 2: 在 CLI 文档中补命令契约**
387
388 把 Bilibili 一节写成和 Douyin/Kuaishou 同风格:
389
390 - 参数表
391 - `tid` 必填
392 - `schedule` 的行为
393
394 - [ ] **Step 3: 在安装/更新文档中写清自动下载机制**
395
396 至少补这些说明:
397
398 - 用户不需要自己安装 `biliup`
399 - 第一次运行会自动下载
400 - 后续运行会自动检查更新
401
402 - [ ] **Step 4: 在文档中加入对上游项目的感谢与借用说明**
403
404 至少在 README 中补一段明确说明:
405
406 - Bilibili 能力基于 `biliup`
407 - 感谢/借用上游项目
408 - 给出项目地址
409
410 建议文案:
411
412 ```markdown
413 ## 致谢
414
415 本项目的 Bilibili 上传能力基于开源项目 `biliup` 的能力进行接入与封装。
416 感谢 `biliup` 项目及其贡献者提供的基础能力:
417
418 - https://github.com/biliup/biliup
419 ```
420
421 - [ ] **Step 5: 做一次文档核对**
422
423 Run:
424
425 ```powershell
426 Get-Content README.md | Select-String -Pattern "bilibili|biliup|致谢" -Context 1,2
427 Get-Content docs\CLI.md | Select-String -Pattern "bilibili" -Context 1,3
428 Get-Content docs\install.md | Select-String -Pattern "bilibili|biliup" -Context 1,2
429 Get-Content docs\update.md | Select-String -Pattern "bilibili|biliup" -Context 1,2
430 ```
431
432 Expected:
433
434 - README、CLI、install、update 都出现 Bilibili 新内容
435 - README 里有明确的上游致谢
436
437 - [ ] **Step 6: 跑最终验证**
438
439 Run:
440
441 ```powershell
442 .\.venv\Scripts\python.exe -m unittest tests.test_bilibili_runtime tests.test_sau_bilibili_cli -v
443 .\.venv\Scripts\python.exe sau_cli.py bilibili --help
444 .\.venv\Scripts\python.exe sau_cli.py bilibili upload-video --help
445 ```
446
447 Expected:
448
449 - 单元测试通过
450 - Bilibili CLI 帮助可用
451 - `upload-video` 显示必填 `--tid`
452
453 - [ ] **Step 7: 提交收尾**
454
455 ```powershell
456 git add README.md docs/CLI.md docs/install.md docs/update.md
457 git commit -m "docs: add bilibili cli guidance and attribution"
458 ```
459
459 lines MARKDOWN