diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index d1c7448..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -# These are supported funding model platforms - -github: dreammis diff --git a/docs/CLI.md b/docs/CLI.md deleted file mode 100644 index c8df454..0000000 --- a/docs/CLI.md +++ /dev/null @@ -1,283 +0,0 @@ -# CLI 使用说明 - -项目现在提供一个统一的 CLI 入口 `sau`,当前主线已经接入: - -- `douyin` -- `kuaishou` -- `xiaohongshu` -- `bilibili` -- `tencent` -- `baijiahao` -- `alipay` -- `weibo` -- `hupu` -- `youtube` - -实现说明: - -- `sau_cli.py` 是当前 CLI 的主入口和唯一主要实现文件 -- `sau.exe` 是安装后在 Windows 虚拟环境里自动生成的命令入口,本质上还是调用 `sau_cli.py` -- 如果需要给 OpenClaw、Codex 等 agent 使用,可参考仓库内 skill: - - `skills/douyin-upload/` - - `skills/kuaishou-upload/` - - `skills/xiaohongshu-upload/` - - `skills/bilibili-upload/` - -视频号、百家号和支付宝生活号目前只有 CLI 入口,暂未提供对应的 skill。 - -## 安装 CLI 入口 - -如果你希望直接使用 `sau` 命令,而不是手动执行 `python sau_cli.py`,先在项目根目录安装一次: - -```bash -uv pip install -e . -``` - -安装后就可以直接使用: - -```bash -sau douyin --help -sau kuaishou --help -sau xiaohongshu --help -sau bilibili --help -sau tencent --help -sau baijiahao --help -sau alipay --help -sau weibo --help -sau hupu --help -sau youtube --help -``` - -## 安装 patchright 浏览器 - -Windows 下推荐先指定镜像,再安装 Chromium: - -```powershell -$env:PLAYWRIGHT_DOWNLOAD_HOST="https://npmmirror.com/mirrors/playwright"; patchright install chromium -``` - -## 抖音 CLI 子命令 - -```bash -sau douyin login --account -sau douyin login --account --headless -sau douyin check --account -sau douyin upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 运动,训练 -sau douyin upload-note --account --images videos/1.png videos/2.png --title "图文标题" --note "图文示例" --tags 图文,测试 -``` - -抖音短信验证码补充说明: - -- 视频发布过程中如果触发短信二次验证,CLI 会优先读取项目根目录下的 `verify_code.txt` -- 如果未找到 `verify_code.txt`,并且当前命令是在交互式终端中手动运行,CLI 会直接在终端提示输入验证码 -- 对 agent、自动任务、远程桥接这类场景,仍然可以继续用写入 `verify_code.txt` 的方式喂验证码 -- 验证通过后,程序会自动清理 `verify_code.txt` - -## 快手 CLI 子命令 - -```bash -sau kuaishou login --account -sau kuaishou check --account -sau kuaishou upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 运动,训练 -sau kuaishou upload-note --account --images videos/1.png videos/2.png videos/3.png --title "图文标题" --note "图文示例" --tags 图文,测试 -``` - -## 小红书 CLI 子命令 - -```bash -sau xiaohongshu login --account -sau xiaohongshu check --account -sau xiaohongshu upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 小红书,视频 -sau xiaohongshu upload-note --account --images videos/1.png videos/2.png videos/3.png --title "图文标题" --note "图文示例" --tags 图文,测试 -``` - -海外环境如果无法登录默认创作者后台,可以通过环境变量切换到 RedNote 域名。该设置同时作用于登录、cookie 校验、视频发布和图文发布: - -```bash -SAU_XHS_CREATOR_BASE_URL=https://creator.rednote.com sau xiaohongshu login --account -``` - -## Bilibili CLI 子命令 - -```bash -sau bilibili login --account -sau bilibili check --account -sau bilibili upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tid 249 --tags 足球,测试 --thumbnail covers/demo.png -``` - -补充说明: - -- `creator` 之类的名字只是示例值,真正传的是用户自定义的 `account_name` -- 一个 `account_name` 对应一个账号文件,可以准备多个账号并发使用 -- 浏览器平台统一元数据约定: -- 视频使用 `title + desc + tags` -- 图文使用 `title + note + tags` -- `sau bilibili ...` 会自动准备 `biliup` -- 如果本地没有 `biliup`,第一次运行会自动下载 -- 如果上游 GitHub Release 有更新,运行时会先自动更新 -- `sau bilibili login --account ` 建议由用户自己在本地真实终端里执行;如果终端里的二维码显示不完整,可直接打开当前目录下的 `qrcode.png` 扫码 - -## 视频号 CLI 子命令 - -```bash -sau tencent login --account -sau tencent check --account -sau tencent upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 视频号,测试 -``` - -视频号支持定时发布、草稿、合集和双比例封面: - -```bash -sau tencent upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --schedule "2026-03-24 21:30" --thumbnail-landscape covers/landscape.png --thumbnail-portrait covers/portrait.png --collection "我的合集" -sau tencent upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --draft -``` - -视频号登录和上传依赖浏览器中的登录态。无头模式下如果需要扫码,CLI 会生成临时二维码;需要人工查看页面时可以加 `--headed`。 - -## 百家号 CLI 子命令 - -```bash -sau baijiahao login --account -sau baijiahao check --account -sau baijiahao upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 百家号,测试 -``` - -百家号当前支持登录、账号检查和视频上传;支持 `--thumbnail` 与 `--collection`,暂不支持 `--schedule`。上传前需要先完成百度账号登录并保存账号文件。 - -## 支付宝生活号 CLI 子命令 - -```bash -sau alipay login --account -sau alipay check --account -sau alipay upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 生活号,测试 -``` - -支付宝生活号当前支持登录、账号检查和视频上传;支持 `--thumbnail` 与 `--collection`,暂不支持图文上传和 `--schedule`。首次使用前需要在支付宝内容创作后台完成登录,并确认账号已开通生活号内容创作权限。 - -## YouTube CLI 子命令 - -```bash -sau youtube login --account -sau youtube check --account -sau youtube upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags tag1,tag2 --playlist "我的系列" --visibility public -``` - -YouTube 登录需要在浏览器中完成 Google 账号登录,不使用二维码。`--visibility` 可选 `public`、`unlisted` 或 `private`,`--playlist` 可选。 - -## 微博 CLI 子命令 - -```bash -sau weibo login --account -sau weibo check --account -sau weibo upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 微博,测试 --thumbnail covers/demo.png -``` - -微博当前支持登录、账号检查和视频上传;标题最多 30 个字,封面图建议小于 5 MB,暂不支持图文上传和 `--schedule`。 - -## 虎扑 CLI 子命令 - -```bash -sau hupu login --account -sau hupu check --account -sau hupu upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 虎扑,测试 --thumbnail covers/demo.png -``` - -虎扑当前支持登录、账号检查和视频上传;标题长度要求为 4–40 个字,暂不支持图文上传和 `--schedule`。虎扑登录可能需要在浏览器中完成 QQ 或手机号登录,需要人工查看页面时可以加 `--headed`。 - -## 登录二维码说明 - -- 抖音、快手、小红书、视频号、百家号、支付宝生活号、微博和虎扑登录过程中,CLI / uploader 可能会生成临时二维码图片 -- 对普通用户来说,可以直接打开该图片扫码 -- 对可操作本地文件的 agent 来说,不要只把图片路径告诉用户 -- 这类二维码图片本身就是给用户扫码的,agent 应优先直接展示/发送本地图片给用户 -- Bilibili 和 YouTube 当前不走这套本地二维码图片托管链路,登录按上面的平台说明处理即可 - -## 定时发布 - -抖音、快手、小红书、视频号的图文或视频上传,以及 Bilibili 的视频上传支持 `--schedule`。只要传了 `--schedule`,CLI 就会自动切换到对应平台的定时发布策略;不传则默认立即发布。百家号、支付宝生活号、微博和虎扑当前不支持 `--schedule`。 - -```bash -sau douyin upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --schedule "2026-03-24 21:30" -sau douyin upload-note --account --images videos/1.png videos/2.png --title "图文标题" --note "图文示例" --schedule "2026-03-24 21:30" -sau kuaishou upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --schedule "2026-03-24 21:30" -sau kuaishou upload-note --account --images videos/1.png videos/2.png videos/3.png --title "图文标题" --note "图文示例" --schedule "2026-03-24 21:30" -sau xiaohongshu upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --schedule "2026-03-24 21:30" -sau xiaohongshu upload-note --account --images videos/1.png videos/2.png videos/3.png --title "图文标题" --note "图文示例" --schedule "2026-03-24 21:30" -sau bilibili upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tid 249 --schedule "2026-03-24 21:30" -sau tencent upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --schedule "2026-03-24 21:30" -``` - -## 运行时参数 - -CLI 将 `debug` 和 `headless` 拆成了两个独立维度: - -```bash ---debug ---headless ---headed -``` - -- `--debug`: 打开调试行为,例如失败时保留更多调试信息 -- `--headless`: 无头模式运行 -- `--headed`: 有头模式运行 - -如果都不传,CLI 当前默认按 `headless=True` 运行。 - -补充: - -- 抖音和快手的 CLI 默认都是无头模式 -- 如果用户明确要求可见浏览器窗口,或确实需要人工看页面,再显式传 `--headed` - -## 视频上传参数 - -```bash ---file videos/demo.mp4 ---title "示例标题" ---desc "示例简介" ---tags 运动,训练 ---thumbnail videos/demo.png ---thumbnail-landscape videos/cover-4x3.png ---thumbnail-portrait videos/cover-3x4.png -``` - -抖音和视频号支持同时设置两种比例的封面图: - -- `--thumbnail-landscape`: 4:3 横版封面 -- `--thumbnail-portrait`: 3:4 竖版封面 -- `--thumbnail`: 兼容旧参数,等同于 3:4 竖版封面 - -视频号、百家号和支付宝生活号支持使用 `--collection` 指定已有合集;百家号和支付宝生活号还支持 `--thumbnail` 指定封面图。 - -抖音额外支持: - -```bash ---product-link https://example.com/item ---product-title 示例商品 -``` - -Bilibili 额外要求: - -```bash ---tid 249 -``` - -- `--tid` 第一版是必填 -- `--tags` 会映射到 `biliup upload --tag` -- `--schedule` 会映射到 Bilibili 所需的时间戳参数 - -## 图文上传参数 - -```bash ---images videos/1.png videos/2.png videos/3.png ---title "图文标题" ---note "图文内容" ---tags 图文,测试 -``` - -图文上传当前限制: - -- 抖音:最多 35 张图片,不支持 GIF -- 快手:支持多张图片,建议传真实不同文件,不要把同一路径重复多次 -- 小红书:支持多张图片,正文 `--note` 可选,但 `--title` 建议始终显式传入 - -后续维护 CLI 时,优先看 `sau_cli.py`、`uploader/` 和 `skills/`。 diff --git a/docs/agent-bootstrap.md b/docs/agent-bootstrap.md deleted file mode 100644 index b1d33db..0000000 --- a/docs/agent-bootstrap.md +++ /dev/null @@ -1,148 +0,0 @@ -# Agent Bootstrap Prompt - -这份文档是写给 `OpenClaw`、`Codex`、`Claude Code / cc` 这类 agent 客户端用户的。 - -目标不是让 agent 先通读整个仓库,而是先把 `social-auto-upload` 安装到可运行、可验证、可继续执行任务的状态。 - -当前主线已接入的平台: - -- `bilibili` -- `douyin` -- `kuaishou` -- `xiaohongshu` - -## 这份文档解决什么问题 - -现在仓库里已经有: - -- 安装说明 -- CLI 文档 -- 平台 skill - -但这些内容更偏向“agent 进入仓库之后怎么执行”。 - -这份文档补的是“用户第一次把仓库交给 agent 客户端时,应该怎么说”。 - -## 推荐使用方式 - -1. 把整个仓库给你的 agent 客户端。 -2. 把下面这段启动提示词完整发给它。 -3. 等 agent 完成安装和 CLI 验证后,再继续给它下达登录、上传、定时发布等任务。 - -## 通用启动提示词 - -复制下面整段,发给你的 agent: - -```text -你现在在一个名为 `social-auto-upload` 的仓库中工作。 - -这是一个多平台社交媒体自动发布项目。当前主线已经接入: - -- bilibili -- douyin -- kuaishou -- xiaohongshu - -你的第一目标不是通读全部源码,也不是优先运行历史 examples,而是先把项目安装到“可运行、可验证、可继续执行任务”的状态。 - -请遵守以下规则: - -1. 默认把仓库根目录视为当前工作目录。 -2. 优先使用 `uv` 管理 Python 环境,不要默认回退到旧的 `requirements.txt`。 -3. 优先使用当前主线 CLI:`sau`。 -4. 优先参考这些文档: - - `docs/install.md` - - `docs/CLI.md` - - `docs/update.md` -5. 如果需要平台级操作,优先参考这些 skill: - - `skills/douyin-upload/` - - `skills/kuaishou-upload/` - - `skills/xiaohongshu-upload/` - - `skills/bilibili-upload/` -6. 不要默认走历史 `examples/` 和旧 Web 路径,除非当前 CLI 主线不可用。 -7. 如果登录流程生成二维码图片,不要只返回图片路径;请直接展示图片,或者明确告诉我该打开哪个本地图片文件扫码。 -8. 如果是 Bilibili 登录,不要在非交互环境里强行代跑;应改为指导我在本地真实终端执行。 -9. 安装完成后,请优先验证以下命令: - - `sau --help` - - `sau douyin --help` - - `sau kuaishou --help` - - `sau xiaohongshu --help` - - `sau bilibili --help` -10. 完成后,请明确输出: - - 你实际执行了哪些命令 - - 哪些验证通过了 - - 当前项目是否已经进入“可继续登录/上传”的状态 - - 推荐我下一步执行什么 - -如果过程中遇到错误,不要跳过,请先说明错误,再给出你准备采取的下一步动作。 -``` - -## 安装完成后,你可以继续怎么说 - -下面这些是你可以继续发给 agent 的任务示例。 - -### 做一次平台登录 - -```text -请继续帮我登录小红书账号,使用有头模式,账号名用 `creator`。 -``` - -```text -请继续帮我登录抖音账号,使用无头模式,账号名用 `creator`。 -``` - -### 做一次 CLI 可用性检查 - -```text -请检查 bilibili、douyin、kuaishou、xiaohongshu 四个平台的 CLI 入口是否都可用,并告诉我缺什么依赖。 -``` - -### 做一次真实上传 - -```text -请使用 xiaohongshu CLI,帮我上传一个图文草稿,使用定时发布,不要立即发布。 -``` - -```text -请使用 douyin CLI,帮我上传一个视频,优先走当前主线,不要走历史 example。 -``` - -## OpenClaw / Codex / Claude Code 使用建议 - -### OpenClaw - -- 适合直接粘贴上面的完整启动提示词 -- 如果支持把仓库作为工作目录挂载进去,优先先挂载仓库,再发提示词 -- 如果支持本地文件展示,登录二维码应让 agent 直接展示图片 - -### Codex - -- 建议先让它完成 bootstrap,再继续发平台任务 -- 让它优先使用 `docs/install.md`、`docs/CLI.md` 和 `skills/` -- 不要让它一开始自由探索整个仓库,否则容易走到历史路径 - -### Claude Code / cc - -- 建议先让仓库成为当前 workspace -- 再发完整启动提示词 -- 后续按“安装 -> 验证 -> 登录 -> 上传”顺序继续给任务 - -## 为什么不按平台拆四套提示词 - -因为这个项目现在已经有统一的 CLI 主线。 - -用户第一次把仓库交给 agent 时,更需要的是: - -- agent 知道主入口是什么 -- agent 知道应该优先走哪条路径 -- agent 知道哪些是历史路径 -- agent 安装完成后先给出明确验收结果 - -等进入执行阶段,再让 agent 根据你的实际目标去选择: - -- `bilibili` -- `douyin` -- `kuaishou` -- `xiaohongshu` - -这样比给用户准备四套平台 prompt 更稳,也更容易维护。 diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index d2079f1..0000000 --- a/docs/install.md +++ /dev/null @@ -1,251 +0,0 @@ -# 安装说明 - -这个文档分成两部分: - -- `For Humans`:给正常使用仓库的开发者、创作者、CLI 用户看 -- `For AI Agents`:给 OpenClaw、Codex、Claude Code 一类 agent 看 - -如果你是“正在使用 agent 客户端的人”,想先给 agent 一段启动提示词,而不是直接阅读下面的执行细节,先看: - -- [Agent Bootstrap Prompt](./agent-bootstrap.md) - -## For Humans - -### 1. 克隆项目 - -```bash -git clone https://github.com/dreammis/social-auto-upload.git -cd social-auto-upload -``` - -### 2. 创建虚拟环境 - -推荐使用 `uv`: - -Windows PowerShell: - -```powershell -uv venv -.venv\Scripts\activate -``` - -Linux / macOS: - -```bash -uv venv -source .venv/bin/activate -``` - -### 3. 安装主线依赖 - -当前主线依赖已经放到 `pyproject.toml`,推荐直接执行: - -```bash -uv pip install -e . -``` - -安装完成后,会注册 `sau` 命令。 - -### 4. 安装 patchright Chromium - -当前主线使用 `patchright` 驱动浏览器。 - -国内用户推荐先指定镜像,再安装 Chromium。 - -Windows PowerShell: - -```powershell -$env:PLAYWRIGHT_DOWNLOAD_HOST="https://npmmirror.com/mirrors/playwright"; patchright install chromium -``` - -Linux / macOS: - -```bash -PLAYWRIGHT_DOWNLOAD_HOST="https://npmmirror.com/mirrors/playwright" patchright install chromium -``` - -### 5. 配置 conf.py - -复制一份配置: - -```bash -cp conf.example.py conf.py -``` - -Windows 也可以直接手动复制并重命名。 - -当前通常还会用到这些配置项: - -- `LOCAL_CHROME_PATH` -- `LOCAL_CHROME_HEADLESS` -- `DEBUG_MODE` - -`XHS_SERVER` 目前只和小红书旧流程相关。 - -### 6. 验证 CLI 是否可用 - -```bash -sau --help -sau douyin --help -sau kuaishou --help -sau xiaohongshu --help -sau bilibili --help -``` - -如果命令找不到,优先确认: - -- 当前虚拟环境是否已激活 -- 是否执行过 `uv pip install -e .` - -### 7. 抖音主线示例 - -```bash -sau douyin login --account -sau douyin check --account -sau douyin upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" -图文正文1: -$noteText = @"图文正文"@ -sau douyin upload-note --account --images videos/demo1.png videos/demo2.png --title "图文标题" --note $noteText --tags 'tag1,tag2' -图文正文2: -sau douyin upload-note --account --images videos/demo1.png videos/demo2.png --title "图文标题" --notef '图文文件路径' --tags 'tag1,tag2' -添加 BGM(可选): -sau douyin upload-note --account --images videos/demo1.png videos/demo2.png --title "图文标题" --note $noteText --tags 'tag1,tag2' --bgm '音乐名称' -``` - -抖音短信验证码补充说明: - -- 视频发布过程中如果触发短信二次验证,程序会优先读取项目根目录下的 `verify_code.txt` -- 如果当前是你手动运行的交互式终端,没提供 `verify_code.txt` 时,CLI 会直接提示你在终端输入验证码 -- 如果是 agent 或自动化桥接场景,仍然可以继续通过写入 `verify_code.txt` 来提供验证码 -- 验证通过后,程序会自动删除 `verify_code.txt` - -抖音卡login手动获取cookie: - -- 目标服务器使用vnc -- 浏览器登录抖音创作者中心https://creator.douyin.com/ -- 执行`bash export_douyin_cookie.sh --account ` -- 检查cookie可用性,执行`sau douyin check --account ` - -### 8. 快手主线示例 - -```bash -sau kuaishou login --account -sau kuaishou check --account -sau kuaishou upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" -sau kuaishou upload-note --account --images videos/demo1.png videos/demo2.png videos/demo.png --title "图文标题" --note "图文正文" -``` - -### 9. 小红书主线示例 - -```bash -sau xiaohongshu login --account -sau xiaohongshu check --account -sau xiaohongshu upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" -sau xiaohongshu upload-note --account --images videos/demo1.png videos/demo2.png videos/demo.png --title "图文标题" --note "图文正文" -``` - -### 10. Bilibili 主线示例 - -```bash -sau bilibili login --account -sau bilibili check --account -sau bilibili upload-video --account --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tid 249 -``` - -补充说明: - -- `creator` 之类的名字只是示例值,真正传的是用户自定义的 `account_name` -- 一个 `account_name` 对应一个账号文件,可以准备多个账号并发使用 -- 浏览器平台统一元数据约定: -- 视频使用 `title + desc + tags` -- 图文使用 `title + note + tags` -- 用户不需要手动安装 `biliup` -- 首次运行 Bilibili 相关命令时,程序会自动下载 `biliup` -- 后续运行会自动检查上游 release 并自动更新 -- Bilibili 登录建议由用户自己在本地真实终端里执行;如果终端里的二维码显示不完整,可直接打开当前目录下的 `qrcode.png` 扫码 -- 如果国内网络访问 GitHub Release 较慢,可先用 `https://gh-proxy.com/` 或 `https://gh-proxy.org/` 辅助访问对应 release 地址排障 -- 示例: - - `https://gh-proxy.org/https://github.com/biliup/biliup/releases/download/v1.1.29/biliupR-v1.1.29-aarch64-linux.tar.xz` - -## For AI Agents - -如果你是一个可执行命令的 agent,请优先按下面顺序处理: - -1. 先假设仓库根目录就是当前工作目录 -2. 优先使用 `uv` 管理环境,不要默认回退到旧的 `requirements.txt` -3. 安装命令优先使用: - -```bash -uv pip install -e . -``` - -4. 如需浏览器驱动,优先使用: - -Windows PowerShell: - -```powershell -$env:PLAYWRIGHT_DOWNLOAD_HOST="https://npmmirror.com/mirrors/playwright"; patchright install chromium -``` - -Linux / macOS: - -```bash -PLAYWRIGHT_DOWNLOAD_HOST="https://npmmirror.com/mirrors/playwright" patchright install chromium -``` - -5. 安装完成后,优先检查: - -```bash -sau --help -sau douyin --help -sau kuaishou --help -sau xiaohongshu --help -sau bilibili --help -``` - -6. 如果用户的目标是抖音或快手的登录、cookie 校验、视频上传、图文上传,优先走 CLI: - -```bash -sau douyin login -sau douyin check -sau douyin upload-video -sau douyin upload-note - -sau kuaishou login -sau kuaishou check -sau kuaishou upload-video -sau kuaishou upload-note - -sau xiaohongshu login -sau xiaohongshu check -sau xiaohongshu upload-video -sau xiaohongshu upload-note - -sau bilibili login -sau bilibili check -sau bilibili upload-video -``` - -7. 如果用户明确在使用 skill 系统,再引导其阅读: - -- `skills/douyin-upload/SKILL.md` -- `skills/douyin-upload/references/cli-contract.md` -- `skills/kuaishou-upload/SKILL.md` -- `skills/kuaishou-upload/references/cli-contract.md` -- `skills/xiaohongshu-upload/SKILL.md` -- `skills/xiaohongshu-upload/references/cli-contract.md` -- `skills/bilibili-upload/SKILL.md` -- `skills/bilibili-upload/references/cli-contract.md` - -### 对 agent 的额外说明 - -- 当登录流程生成本地二维码图片时,不要只把图片路径发给用户 -- 这类二维码图片本身就是给用户扫码的,agent 应优先直接展示/发送本地图片给用户扫码 -- 如果环境支持查看本地图片,优先用查看图片能力把二维码展示出来;路径只作为补充信息 -- Bilibili 登录当前不建议 agent 在非交互环境里直接代跑 -- 正确做法是让用户自己在本地终端执行 `sau bilibili login --account `;如果二维码显示不完整,再提示用户打开 `qrcode.png` -- `requirements.txt` 目前是历史兼容文件,不是主安装入口 -- `uploader/` 是核心实现目录 -- `sau_cli.py` 是当前 CLI 主入口 -- `docs/legacy-web.md` 是历史 Web 版本说明,不保证当前可用 -- Bilibili 首次运行时可能自动下载 `biliup` diff --git a/docs/legacy-web.md b/docs/legacy-web.md deleted file mode 100644 index 7b83305..0000000 --- a/docs/legacy-web.md +++ /dev/null @@ -1,49 +0,0 @@ -# 历史 Web 版本说明 - -这套 Web 相关代码主要包括: - -- `sau_backend.py` -- `sau_backend/` -- `sau_frontend/` - -它们属于项目过去阶段的实现,当前已经不是主线维护方向。 - -## 当前定位 - -- 作为历史版本保留 -- 作为过去 API / Web 封装思路的参考 -- 不承诺当前一定可直接运行 -- 不承诺和当前 `uploader/`、`sau_cli.py` 的最新实现完全同步 - -## 为什么单独拆出来说明 - -当前工程正在整体重构,主线已经切到: - -- `uploader/`:核心平台实现 -- `sau_cli.py`:CLI 主入口 -- `skills/`:面向 agent 的 skill - -所以 README 不再把 Web 版本当成主入口来介绍,避免让新用户误以为这是当前最稳定的使用方式。 - -## 如果你仍然想研究这套历史 Web 版本 - -可以参考这些文件: - -- `sau_backend/README.md` -- `sau_frontend/README.md` -- `sau_backend.py` - -但请预期: - -- 接口契约可能与当前主线不一致 -- 平台能力覆盖可能落后于当前 `uploader/` -- 依赖和运行方式可能需要自行排障 - -## 当前推荐入口 - -如果你要使用当前主线能力,优先看: - -- `uploader/` -- `sau_cli.py` -- `docs/CLI.md` -- `skills/douyin-upload/SKILL.md` diff --git a/docs/skill-distribution.md b/docs/skill-distribution.md deleted file mode 100644 index eff978b..0000000 --- a/docs/skill-distribution.md +++ /dev/null @@ -1,286 +0,0 @@ -# Skill 分发与发布说明 - -这份文档是给 `social-auto-upload` 后续做独立 skill 分发时用的。 - -当前仓库已经具备两层能力: - -- 一个可安装的 CLI:`sau` -- 一个可被安装到 Codex 的内置 skill:`douyin-cli` - -后续当主流程和 bug 修复完成后,可以再继续做 PyPI 发布、安装优化、以及更多平台的独立 skill。 - -## 先说结论 - -`skill` 不一定必须是一个 Python 包。 - -它可以是: - -- 一个 skill 目录 -- 一个独立仓库 -- 一个安装器脚本 -- 一个 Docker 镜像 -- 一个包管理器可安装的分发物 - -但从“别人最快安装和使用”的角度看,最常见、最省事的仍然是: - -1. 用一个安装包分发真正的运行能力 -2. 用一个 skill 安装动作把 skill 放到 AI 工具的技能目录 - -对这个项目来说,最推荐的形式是: - -- Python 包负责提供 `sau` 命令 -- `sau skill install` 负责把 skill 安装到 `~/.codex/skills/` - -也就是: - -```bash -pip install social-auto-upload -sau skill install -``` - -## skill 一定要是包吗 - -不是。 - -### 1. skill 只是一个目录 - -这是最原始也最常见的形式。 - -通常内容是: - -- `SKILL.md` -- `agents/openai.yaml` -- `references/` -- `scripts/` - -这种形式本身已经是一个可用 skill 了,不一定需要打包。 - -问题在于: - -- 用户要知道把它复制到哪里 -- 用户要手动安装 -- skill 如果依赖额外脚本或运行时,安装体验会比较差 - -适合: - -- 内部团队 -- 仓库内开发规范 -- 还在快速迭代的 skill - -### 2. skill 是一个独立仓库 - -这也完全成立。 - -例如: - -- 一个仓库专门放 `SKILL.md` -- 附带 `scripts/install.py` -- 或者 README 教用户复制到 `~/.codex/skills/` - -这种模式的优点是: - -- skill 自己独立版本管理 -- 不依赖主业务仓库 -- 可以公开发布 - -缺点是: - -- 用户还是可能要 clone -- 或者还需要执行安装脚本 - -适合: - -- 想把 skill 当产品独立维护 -- skill 和业务代码已经明显拆开 - -### 3. skill 跟随一个包分发 - -这是当前这个项目最适合的方向。 - -思路是: - -- Python 包里内置一份 skill 资源 -- 安装包后即可执行 `sau skill install` -- CLI 和 skill 一起发版 - -优点是: - -- 用户体验最好 -- skill 和实际命令保持一致 -- 版本对应关系清晰 -- 不需要用户 clone 仓库 - -适合: - -- skill 背后有真实 CLI/SDK/工具 -- 用户最终是要“使用能力”而不只是“阅读说明” - -### 4. skill 用 Docker 交付 - -也可以。 - -常见方式是: - -- Docker 里装好运行环境 -- skill 告诉 AI 通过 `docker run ...` 去执行命令 - -优点是: - -- 环境一致性很好 -- 本地依赖复杂时特别有用 - -缺点是: - -- 用户必须先装 Docker -- 浏览器自动化、桌面登录、cookie、本地文件挂载都会更复杂 -- 对抖音这种需要本地浏览器交互的流程不一定更友好 - -对当前项目来说,Docker 更适合: - -- 后端服务 -- 批处理任务 -- 服务器环境 - -不太适合作为“普通用户首次使用抖音登录 skill”的唯一交付方式。 - -## AI 安装环境、启动脚本、仓库,这些算不算 skill - -算,但要区分“skill 本体”和“skill 的安装/运行载体”。 - -可以这样理解: - -- `SKILL.md` 是 skill 本体 -- 仓库、包、Docker、安装脚本,是 skill 的分发和运行载体 - -所以: - -- skill 可以住在仓库里 -- skill 可以被包一起带出去 -- skill 也可以借助 Docker 运行它依赖的环境 - -只要最终用户能: - -1. 安装它 -2. 让 AI 发现它 -3. 真正调用它依赖的能力 - -那它就是成立的。 - -## 对这个项目最合适的方案 - -### 当前推荐方案 - -第一阶段: - -- 继续在这个仓库里修主流程和 bug -- 保持 `sau` 命令稳定 -- 保持包内 skill 与 CLI 契约一致 - -第二阶段: - -- 打包并发布到 PyPI -- 用户通过 `pip install social-auto-upload` 安装 -- 用户执行 `sau skill install` - -第三阶段: - -- 根据需要把更多平台拆成独立 skill -- 例如 `douyin-cli`、`tencent-cli`、`tiktok-cli` - -### 为什么现在不优先做“独立 skill 仓库” - -因为当前最核心的问题还不是“skill 放哪”,而是: - -- 上传流程是否稳定 -- CLI 契约是否稳定 -- 实际用户安装后能不能跑通 - -在这些都还在收敛的阶段,先让 skill 随包分发是最稳妥的。 - -## 未来可选的三种正式发布路线 - -### 路线 A:PyPI 包 + 包内 skill - -用户安装: - -```bash -pip install social-auto-upload -sau skill install -``` - -优点: - -- 最容易传播 -- 安装简单 -- 版本管理清晰 - -这是当前首选路线。 - -### 路线 B:独立 skill 仓库 + PyPI 包 - -用户安装能力: - -```bash -pip install social-auto-upload -``` - -用户安装 skill: - -- clone skill 仓库 -- 或跑 skill 仓库提供的安装脚本 - -优点: - -- skill 可以单独演进 -- 可以给不同 AI 工具维护不同 metadata - -缺点: - -- 安装链路更长 - -### 路线 C:Docker + skill - -用户: - -- 安装 Docker -- 拉镜像 -- 安装 skill -- skill 内部调用 docker 命令 - -优点: - -- 依赖环境最稳定 - -缺点: - -- 对本地浏览器自动化和交互式登录不够友好 - -更适合服务端任务,不是当前首选。 - -## 当前项目的发布建议 - -当主流程稳定后,建议按这个顺序走: - -1. 先保证 `sau douyin login/check/upload` 真机可用 -2. 验证 `sau skill install` 安装后的 skill 可以被 Codex 正常识别 -3. 本地打 wheel 做一次冷启动安装测试 -4. 再发布 PyPI - -建议的最终用户路径是: - -```bash -pip install social-auto-upload -playwright install chromium -sau skill install -sau douyin login --account my-account -``` - -## 一句话回答 - -`skill` 不是必须做成包,但如果你想让别人“最快安装、最少理解成本、最少手工操作”,那就最好让“运行能力”走包分发,让 `skill` 跟着包一起被安装。 - -对这个项目来说,最佳落地方案不是“只发一个 skill 仓库”,而是: - -- `social-auto-upload` 作为可安装包 -- `douyin-cli` 作为包内 skill -- `sau skill install` 作为安装桥梁 diff --git a/docs/superpowers/plans/2026-03-25-bilibili-cli-implementation.md b/docs/superpowers/plans/2026-03-25-bilibili-cli-implementation.md deleted file mode 100644 index 379675a..0000000 --- a/docs/superpowers/plans/2026-03-25-bilibili-cli-implementation.md +++ /dev/null @@ -1,458 +0,0 @@ -# Bilibili CLI Implementation Plan - -> **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. - -**Goal:** 为 Bilibili 补齐和抖音、快手同层级的 `sau` CLI、自动更新 `biliup` 的运行时机制、对应 skill,以及完整文档与上游致谢说明。 - -**Architecture:** 保持轻量,不新建大而全框架。新增一个 Bilibili 运行时模块负责检查 GitHub Release、下载/更新 `biliup`、执行命令;`sau_cli.py` 仅补 `bilibili` 子命令和参数映射;skill、example、README/CLI/install/update 文档按现有 Douyin/Kuaishou 结构对齐。 - -**Tech Stack:** Python 3.10+, `requests`, `argparse`, `asyncio`, `subprocess`, `pathlib`, `unittest`, GitHub Releases, existing `biliup` integration - ---- - -## File Structure - -### New files - -- `uploader/bilibili_uploader/runtime.py` - - Bilibili 运行时入口 - - 负责 `biliup` 自动检查、自动下载、自动更新、执行命令 -- `tests/__init__.py` - - 测试包初始化 -- `tests/test_bilibili_runtime.py` - - 测试自动更新、下载、缓存复用、执行器行为 -- `tests/test_sau_bilibili_cli.py` - - 测试 `sau bilibili` parser 和 dispatch 行为 -- `skills/bilibili-upload/SKILL.md` - - Bilibili CLI skill 主说明 -- `skills/bilibili-upload/references/runtime-requirements.md` - - 运行前提和自动下载说明 -- `skills/bilibili-upload/references/cli-contract.md` - - `sau bilibili ...` 命令契约 -- `skills/bilibili-upload/references/troubleshooting.md` - - 常见问题与排障 -- `skills/bilibili-upload/scripts/examples/bilibili_commands.ps1` - - PowerShell 示例命令 -- `skills/bilibili-upload/scripts/examples/bilibili_commands.sh` - - shell 示例命令 -- `skills/bilibili-upload/scripts/examples/bilibili_cli_template.py` - - Python 调用模板 - -### Modified files - -- `sau_cli.py` - - 补 `bilibili` 子命令 - - 复用现有 `resolve_account_file()`、`parse_tags()`、`parse_schedule()` -- `examples/get_bilibili_cookie.py` - - 对齐新的 `sau bilibili login` 用法 -- `examples/upload_video_to_bilibili.py` - - 对齐新的 CLI/账号文件约定 -- `README.md` - - 补 Bilibili CLI 用法、自动下载说明、致谢说明 -- `docs/CLI.md` - - 补 `sau bilibili login/check/upload-video` -- `docs/install.md` - - 补 Bilibili 自动下载/首次运行说明 -- `docs/update.md` - - 补 Bilibili 自动更新行为说明 - -## Task 1: Bilibili 自动更新运行时 - -**Files:** -- Create: `uploader/bilibili_uploader/runtime.py` -- Create: `tests/__init__.py` -- Create: `tests/test_bilibili_runtime.py` - -- [ ] **Step 1: 写 Bilibili 运行时测试** - -使用 `unittest`,覆盖这些最小路径: - -```python -import unittest -from pathlib import Path -from unittest.mock import Mock, patch - -from uploader.bilibili_uploader.runtime import ( - build_biliup_runtime_path, - ensure_biliup_binary, - run_biliup_command, -) - - -class BiliupRuntimeTests(unittest.TestCase): - def test_build_biliup_runtime_path_returns_platform_path(self): - path = build_biliup_runtime_path("Windows") - self.assertTrue(str(path).endswith("biliup.exe")) - - @patch("uploader.bilibili_uploader.runtime.fetch_latest_release") - def test_ensure_biliup_binary_downloads_when_missing(self, mock_release): - mock_release.return_value = { - "tag_name": "v1.0.0", - "asset_url": "https://example.invalid/biliup.exe", - "asset_name": "biliup.exe", - } - with patch("uploader.bilibili_uploader.runtime.download_biliup_asset") as mock_download: - ensure_biliup_binary(force_check=True) - mock_download.assert_called_once() - - @patch("uploader.bilibili_uploader.runtime.fetch_latest_release") - def test_ensure_biliup_binary_reuses_local_when_up_to_date(self, mock_release): - mock_release.return_value = { - "tag_name": "v1.0.0", - "asset_url": "https://example.invalid/biliup.exe", - "asset_name": "biliup.exe", - } - with patch("uploader.bilibili_uploader.runtime.read_local_biliup_version", return_value="v1.0.0"): - with patch("uploader.bilibili_uploader.runtime.download_biliup_asset") as mock_download: - ensure_biliup_binary(force_check=True) - mock_download.assert_not_called() - - @patch("uploader.bilibili_uploader.runtime.subprocess.run") - def test_run_biliup_command_returns_completed_process(self, mock_run): - mock_run.return_value = Mock(returncode=0, stdout="ok", stderr="") - result = run_biliup_command(["login"]) - self.assertEqual(result.returncode, 0) -``` - -- [ ] **Step 2: 运行测试,确认先失败** - -Run: - -```powershell -.\.venv\Scripts\python.exe -m unittest tests.test_bilibili_runtime -v -``` - -Expected: - -- 因为 `uploader.bilibili_uploader.runtime` 还不存在而失败 - -- [ ] **Step 3: 写最小运行时实现** - -在 `uploader/bilibili_uploader/runtime.py` 里先补这些最小函数: - -```python -def get_biliup_runtime_root() -> Path: ... -def build_biliup_runtime_path(system_name: str | None = None) -> Path: ... -def fetch_latest_release() -> dict: ... -def read_local_biliup_version() -> str | None: ... -def write_local_biliup_version(version: str) -> None: ... -def download_biliup_asset(release: dict, destination: Path) -> Path: ... -def ensure_biliup_binary(force_check: bool = True) -> Path: ... -def run_biliup_command(arguments: list[str]) -> subprocess.CompletedProcess[str]: ... -``` - -约束: - -- 不引入复杂 manifest -- 直接面向 GitHub Release 最新版本 -- 本地只保存当前版本字符串和二进制 -- 保持简单的路径/网络/替换逻辑 - -- [ ] **Step 4: 再跑运行时测试,确认通过** - -Run: - -```powershell -.\.venv\Scripts\python.exe -m unittest tests.test_bilibili_runtime -v -``` - -Expected: - -- 所有 `BiliupRuntimeTests` 通过 - -- [ ] **Step 5: 提交这一小步** - -```powershell -git add uploader/bilibili_uploader/runtime.py tests/__init__.py tests/test_bilibili_runtime.py -git commit -m "feat: add biliup runtime bootstrap" -``` - -## Task 2: 接入 `sau bilibili` CLI - -**Files:** -- Modify: `sau_cli.py` -- Create: `tests/test_sau_bilibili_cli.py` -- Reference: `uploader/bilibili_uploader/main.py` -- Reference: `utils/constant.py` - -- [ ] **Step 1: 写 CLI parser 和 dispatch 测试** - -在 `tests/test_sau_bilibili_cli.py` 中覆盖: - -```python -import unittest -from argparse import Namespace -from pathlib import Path -from unittest.mock import AsyncMock, patch - -import sau_cli - - -class BilibiliCliTests(unittest.TestCase): - def test_build_parser_accepts_bilibili_login(self): - parser = sau_cli.build_parser() - args = parser.parse_args(["bilibili", "login", "--account", "creator"]) - self.assertEqual(args.platform, "bilibili") - self.assertEqual(args.action, "login") - - def test_build_parser_requires_tid_for_upload_video(self): - parser = sau_cli.build_parser() - with self.assertRaises(SystemExit): - parser.parse_args([ - "bilibili", "upload-video", - "--account", "creator", - "--file", "demo.mp4", - "--title", "hello", - "--desc", "hello", - ]) - - def test_dispatch_bilibili_check_prints_valid(self): - args = Namespace(platform="bilibili", action="check", account="creator") - with patch("sau_cli.check_bilibili_account", new=AsyncMock(return_value=True)): - code = asyncio.run(sau_cli.dispatch(args)) - self.assertEqual(code, 0) -``` - -- [ ] **Step 2: 运行测试,确认先失败** - -Run: - -```powershell -.\.venv\Scripts\python.exe -m unittest tests.test_sau_bilibili_cli -v -``` - -Expected: - -- 因为 `sau_cli.py` 里还没有 `bilibili` parser/dispatch 分支而失败 - -- [ ] **Step 3: 在 `sau_cli.py` 中补 Bilibili 请求模型和命令** - -只做最小接入,保持和 Douyin/Kuaishou 同风格: - -```python -@dataclass(slots=True) -class BilibiliVideoUploadRequest: - account_name: str - video_file: Path - title: str - description: str - tid: int - tags: list[str] - publish_date: datetime | int - debug: bool = True - - -async def login_bilibili_account(account_name: str) -> dict: ... -async def check_bilibili_account(account_name: str) -> bool: ... -async def upload_bilibili_video(request: BilibiliVideoUploadRequest) -> Path: ... -``` - -Parser 最小要求: - -- `sau bilibili login --account ` -- `sau bilibili check --account ` -- `sau bilibili upload-video --account ... --file ... --title ... --desc ... --tid ... [--tags] [--schedule]` - -Dispatch 最小要求: - -- 和其他平台一样输出 `valid` / `invalid` -- 上传成功后打印简洁摘要 - -- [ ] **Step 4: 复用现有 B 站参数语义** - -在 Bilibili wrapper 中直接沿用现有工程概念: - -- `tid` 必填 -- `tags` 用现有 `parse_tags()` -- `schedule` 沿用现有 `parse_schedule()` -- `account` 仍通过 `resolve_account_file("bilibili", account_name)` 得到项目内账号路径 - -- [ ] **Step 5: 再跑 CLI 测试,确认通过** - -Run: - -```powershell -.\.venv\Scripts\python.exe -m unittest tests.test_sau_bilibili_cli -v -``` - -Expected: - -- `BilibiliCliTests` 通过 - -- [ ] **Step 6: 做一次联测** - -Run: - -```powershell -.\.venv\Scripts\python.exe sau_cli.py bilibili --help -.\.venv\Scripts\python.exe sau_cli.py bilibili upload-video --help -``` - -Expected: - -- 能看到 `login` / `check` / `upload-video` -- `upload-video` 中 `--tid` 显示为必填 - -- [ ] **Step 7: 提交这一小步** - -```powershell -git add sau_cli.py tests/test_sau_bilibili_cli.py -git commit -m "feat: add bilibili cli commands" -``` - -## Task 3: 补 skill 和 example - -**Files:** -- Create: `skills/bilibili-upload/SKILL.md` -- Create: `skills/bilibili-upload/references/runtime-requirements.md` -- Create: `skills/bilibili-upload/references/cli-contract.md` -- Create: `skills/bilibili-upload/references/troubleshooting.md` -- Create: `skills/bilibili-upload/scripts/examples/bilibili_commands.ps1` -- Create: `skills/bilibili-upload/scripts/examples/bilibili_commands.sh` -- Create: `skills/bilibili-upload/scripts/examples/bilibili_cli_template.py` -- Modify: `examples/get_bilibili_cookie.py` -- Modify: `examples/upload_video_to_bilibili.py` - -- [ ] **Step 1: 参考 Douyin/Kuaishou skill 结构搭出 Bilibili skill** - -要求: - -- `SKILL.md` 风格和现有两个 skill 对齐 -- 默认优先用 `sau bilibili ...` -- 明确写“程序会自动准备 `biliup`” - -- [ ] **Step 2: 写示例命令文件** - -示例命令至少包括: - -```powershell -sau bilibili login --account creator -sau bilibili check --account creator -sau bilibili upload-video --account creator --file .\videos\demo.mp4 --title "demo" --desc "demo" --tid 249 --tags 足球,测试 -``` - -- [ ] **Step 3: 修改本地 example** - -让以下 example 明确转向新入口或新约定: - -- `examples/get_bilibili_cookie.py` -- `examples/upload_video_to_bilibili.py` - -要求: - -- 不再让用户手动猜 `biliup.exe` 路径 -- 明确说明现在推荐走 `sau bilibili ...` -- 继续保留 `VideoZoneTypes` 的使用示例 - -- [ ] **Step 4: 做一次文件级自检** - -Run: - -```powershell -Get-ChildItem skills\bilibili-upload -Recurse -Get-Content examples\get_bilibili_cookie.py -Get-Content examples\upload_video_to_bilibili.py -``` - -Expected: - -- Bilibili skill 目录完整 -- example 内容已切到新的 CLI/说明 - -- [ ] **Step 5: 提交这一小步** - -```powershell -git add skills/bilibili-upload examples/get_bilibili_cookie.py examples/upload_video_to_bilibili.py -git commit -m "feat: add bilibili upload skill" -``` - -## Task 4: 补文档与上游致谢 - -**Files:** -- Modify: `README.md` -- Modify: `docs/CLI.md` -- Modify: `docs/install.md` -- Modify: `docs/update.md` - -- [ ] **Step 1: 在 README 中补 Bilibili CLI 用法** - -至少写清: - -- `sau bilibili login` -- `sau bilibili check` -- `sau bilibili upload-video` -- 自动下载/自动更新 `biliup` - -- [ ] **Step 2: 在 CLI 文档中补命令契约** - -把 Bilibili 一节写成和 Douyin/Kuaishou 同风格: - -- 参数表 -- `tid` 必填 -- `schedule` 的行为 - -- [ ] **Step 3: 在安装/更新文档中写清自动下载机制** - -至少补这些说明: - -- 用户不需要自己安装 `biliup` -- 第一次运行会自动下载 -- 后续运行会自动检查更新 - -- [ ] **Step 4: 在文档中加入对上游项目的感谢与借用说明** - -至少在 README 中补一段明确说明: - -- Bilibili 能力基于 `biliup` -- 感谢/借用上游项目 -- 给出项目地址 - -建议文案: - -```markdown -## 致谢 - -本项目的 Bilibili 上传能力基于开源项目 `biliup` 的能力进行接入与封装。 -感谢 `biliup` 项目及其贡献者提供的基础能力: - -- https://github.com/biliup/biliup -``` - -- [ ] **Step 5: 做一次文档核对** - -Run: - -```powershell -Get-Content README.md | Select-String -Pattern "bilibili|biliup|致谢" -Context 1,2 -Get-Content docs\CLI.md | Select-String -Pattern "bilibili" -Context 1,3 -Get-Content docs\install.md | Select-String -Pattern "bilibili|biliup" -Context 1,2 -Get-Content docs\update.md | Select-String -Pattern "bilibili|biliup" -Context 1,2 -``` - -Expected: - -- README、CLI、install、update 都出现 Bilibili 新内容 -- README 里有明确的上游致谢 - -- [ ] **Step 6: 跑最终验证** - -Run: - -```powershell -.\.venv\Scripts\python.exe -m unittest tests.test_bilibili_runtime tests.test_sau_bilibili_cli -v -.\.venv\Scripts\python.exe sau_cli.py bilibili --help -.\.venv\Scripts\python.exe sau_cli.py bilibili upload-video --help -``` - -Expected: - -- 单元测试通过 -- Bilibili CLI 帮助可用 -- `upload-video` 显示必填 `--tid` - -- [ ] **Step 7: 提交收尾** - -```powershell -git add README.md docs/CLI.md docs/install.md docs/update.md -git commit -m "docs: add bilibili cli guidance and attribution" -``` diff --git a/docs/superpowers/plans/2026-03-25-browser-cli-unification-implementation.md b/docs/superpowers/plans/2026-03-25-browser-cli-unification-implementation.md deleted file mode 100644 index 07b626b..0000000 --- a/docs/superpowers/plans/2026-03-25-browser-cli-unification-implementation.md +++ /dev/null @@ -1,583 +0,0 @@ -# Browser CLI Unification Implementation Plan - -> **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. - -**Goal:** 为抖音、快手、小红书三家浏览器平台统一 `sau` CLI 契约,补齐小红书 CLI/skill,并把视频正文统一为 `desc`、图文正文统一为 `note`。 - -**Architecture:** 保持现有 `sau_cli.py` 单文件主入口,不引入新的 CLI 框架。`sau_cli.py` 负责 parser、request dataclass、dispatch 和账号文件解析;各平台 uploader 只做最小字段接线;skill、README、CLI/install/update 文档、examples 同步切到统一契约,避免对外同时暴露多套命名。 - -**Tech Stack:** Python 3.10+, `argparse`, `asyncio`, `dataclasses`, `pathlib`, `unittest`, existing Patchright-based uploaders, repository markdown docs - ---- - -## File Structure - -### New files - -- `tests/test_sau_browser_cli.py` - - 覆盖三家浏览器平台统一 CLI parser / dispatch / request 映射 -- `skills/xiaohongshu-upload/SKILL.md` - - 小红书 CLI skill 主说明 -- `skills/xiaohongshu-upload/references/runtime-requirements.md` - - 小红书运行前提 -- `skills/xiaohongshu-upload/references/cli-contract.md` - - 小红书 CLI 契约 -- `skills/xiaohongshu-upload/references/troubleshooting.md` - - 小红书排障文档 -- `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_commands.ps1` - - PowerShell 示例命令 -- `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_commands.sh` - - shell 示例命令 -- `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_cli_template.py` - - Python 命令模板 - -### Modified files - -- `sau_cli.py` - - 新增 `xiaohongshu` parser / dispatch - - 改造抖音、快手 request dataclass 和参数模型 -- `uploader/douyin_uploader/main.py` - - 给视频接入 `desc` - - 给图文接入 `title + note` -- `uploader/ks_uploader/main.py` - - 给视频接入 `desc` - - 给图文接入 `title + note` -- `uploader/xiaohongshu_uploader/main.py` - - 只补 CLI 接线所需的最小字段适配 -- `README.md` - - 补小红书 CLI / skill,并统一三家参数说明 -- `docs/CLI.md` - - 统一三家浏览器平台命令契约 -- `docs/install.md` - - 补小红书 CLI 示例和统一参数说明 -- `docs/update.md` - - 补小红书检查项与 skill 路径 -- `skills/douyin-upload/SKILL.md` -- `skills/douyin-upload/references/cli-contract.md` -- `skills/douyin-upload/scripts/examples/douyin_commands.ps1` -- `skills/douyin-upload/scripts/examples/douyin_commands.sh` -- `skills/douyin-upload/scripts/examples/douyin_cli_template.py` -- `skills/kuaishou-upload/SKILL.md` -- `skills/kuaishou-upload/references/cli-contract.md` -- `skills/kuaishou-upload/scripts/examples/kuaishou_commands.ps1` -- `skills/kuaishou-upload/scripts/examples/kuaishou_commands.sh` -- `skills/kuaishou-upload/scripts/examples/kuaishou_cli_template.py` -- `examples/get_xiaohongshu_cookie.py` -- `examples/upload_video_to_xiaohongshu.py` - -## Task 1: 用测试锁定统一 CLI 契约 - -**Files:** -- Create: `tests/test_sau_browser_cli.py` -- Reference: `sau_cli.py` - -- [ ] **Step 1: 写统一 CLI parser 测试** - -在 `tests/test_sau_browser_cli.py` 里覆盖最小命令契约: - -```python -import asyncio -import unittest -from argparse import Namespace -from pathlib import Path -from unittest.mock import AsyncMock, patch - -import sau_cli - - -class BrowserCliParserTests(unittest.TestCase): - def test_build_parser_accepts_xiaohongshu_login(self): - parser = sau_cli.build_parser() - args = parser.parse_args(["xiaohongshu", "login", "--account", "creator"]) - self.assertEqual(args.platform, "xiaohongshu") - self.assertEqual(args.action, "login") - - def test_douyin_upload_video_accepts_desc(self): - parser = sau_cli.build_parser() - args = parser.parse_args([ - "douyin", "upload-video", - "--account", "creator", - "--file", "demo.mp4", - "--title", "标题", - "--desc", "视频简介", - ]) - self.assertEqual(args.desc, "视频简介") - - def test_kuaishou_upload_note_accepts_title_and_note(self): - parser = sau_cli.build_parser() - args = parser.parse_args([ - "kuaishou", "upload-note", - "--account", "creator", - "--images", "1.png", - "--title", "图文标题", - "--note", "图文正文", - ]) - self.assertEqual(args.title, "图文标题") - self.assertEqual(args.note, "图文正文") -``` - -- [ ] **Step 2: 写 dispatch 路由测试** - -继续在 `tests/test_sau_browser_cli.py` 中补最小 dispatch 验证: - -```python -class BrowserCliDispatchTests(unittest.TestCase): - def test_dispatch_xiaohongshu_check_prints_valid(self): - args = Namespace(platform="xiaohongshu", action="check", account="creator") - with patch("sau_cli.check_xiaohongshu_account", new=AsyncMock(return_value=True)): - code = asyncio.run(sau_cli.dispatch(args)) - self.assertEqual(code, 0) - - def test_dispatch_douyin_upload_note_uses_new_request_fields(self): - args = Namespace( - platform="douyin", - action="upload-note", - account="creator", - images=[Path("1.png")], - title="图文标题", - note="图文正文", - tags="测试,图文", - schedule=0, - debug=False, - headless=True, - ) - with patch("sau_cli.upload_note", new=AsyncMock()) as mock_upload: - asyncio.run(sau_cli.dispatch(args)) - request = mock_upload.await_args.args[0] - self.assertEqual(request.title, "图文标题") - self.assertEqual(request.note, "图文正文") -``` - -- [ ] **Step 3: 先跑测试确认失败** - -Run: - -```powershell -py -3 -m unittest tests.test_sau_browser_cli -v -``` - -Expected: - -- 因为 `sau_cli.py` 还没有 `xiaohongshu` 分支和统一字段而失败 - -- [ ] **Step 4: 提交测试脚手架** - -```powershell -git add tests/test_sau_browser_cli.py -git commit -m "test: define browser cli unification contract" -``` - -## Task 2: 改 `sau_cli.py`,补齐统一参数与小红书路由 - -**Files:** -- Modify: `sau_cli.py` -- Reference: `uploader/xiaohongshu_uploader/main.py` -- Reference: `uploader/douyin_uploader/main.py` -- Reference: `uploader/ks_uploader/main.py` - -- [ ] **Step 1: 增加小红书 request dataclass** - -在 `sau_cli.py` 中新增: - -```python -@dataclass(slots=True) -class XiaohongshuVideoUploadRequest: - account_name: str - video_file: Path - title: str - description: str - tags: list[str] - publish_date: datetime | int - thumbnail_file: Path | None = None - publish_strategy: str = XIAOHONGSHU_PUBLISH_STRATEGY_IMMEDIATE - debug: bool = True - headless: bool = True - - -@dataclass(slots=True) -class XiaohongshuNoteUploadRequest: - account_name: str - image_files: list[Path] - title: str - note: str - tags: list[str] - publish_date: datetime | int - publish_strategy: str = XIAOHONGSHU_PUBLISH_STRATEGY_IMMEDIATE - debug: bool = True - headless: bool = True -``` - -- [ ] **Step 2: 改造抖音、快手 request dataclass** - -把字段统一到以下模型: - -```python -class DouyinVideoUploadRequest: - title: str - description: str - -class DouyinNoteUploadRequest: - title: str - note: str - -class KuaishouVideoUploadRequest: - title: str - description: str - -class KuaishouNoteUploadRequest: - title: str - note: str -``` - -要求: - -- 视频用 `description` -- 图文用 `note` -- 不再把图文 request 设计成只有历史 `note` 语义但没有 `title` - -- [ ] **Step 3: 改 parser** - -在 `build_parser()` 里完成: - -- `douyin upload-video` 增加 `--desc` -- `kuaishou upload-video` 增加 `--desc` -- `douyin upload-note` 改成 `--title --note` -- `kuaishou upload-note` 改成 `--title --note` -- 新增整套 `xiaohongshu`: - - `login` - - `check` - - `upload-video --title --desc --tags --thumbnail` - - `upload-note --images --title --note --tags` - -- [ ] **Step 4: 补小红书账号操作函数** - -在 `sau_cli.py` 中新增: - -```python -async def login_xiaohongshu_account(account_name: str, headless: bool = True) -> dict: ... -async def check_xiaohongshu_account(account_name: str) -> bool: ... -async def upload_xiaohongshu_video(request: XiaohongshuVideoUploadRequest) -> Path: ... -async def upload_xiaohongshu_note(request: XiaohongshuNoteUploadRequest) -> Path: ... -``` - -要求: - -- 账号路径继续走 `resolve_account_file("xiaohongshu", account_name)` -- 登录 / 检查分别复用 `xiaohongshu_setup` 与 `cookie_auth` -- 上传前先做 `setup(handle=False)` 校验 - -- [ ] **Step 5: 改 dispatch** - -要求: - -- 三家浏览器平台都统一输出: - - `login` 成功时打印账号文件路径 - - `check` 输出 `valid` / `invalid` - - `upload-video` 打印简洁摘要 - - `upload-note` 打印图片数量摘要 -- request 构造统一映射: - - 视频:`title + description` - - 图文:`title + note` - -- [ ] **Step 6: 跑 CLI 测试确认通过** - -Run: - -```powershell -py -3 -m unittest tests.test_sau_browser_cli -v -``` - -Expected: - -- `BrowserCliParserTests` -- `BrowserCliDispatchTests` - -全部通过 - -- [ ] **Step 7: 跑最小 help 自检** - -Run: - -```powershell -py -3 sau_cli.py douyin --help -py -3 sau_cli.py kuaishou --help -py -3 sau_cli.py xiaohongshu --help -py -3 sau_cli.py xiaohongshu upload-note --help -``` - -Expected: - -- 小红书子命令存在 -- 图文命令展示 `--title`、`--note` -- 视频命令展示 `--desc` - -- [ ] **Step 8: 提交 CLI 主线** - -```powershell -git add sau_cli.py tests/test_sau_browser_cli.py -git commit -m "feat: unify browser cli contracts" -``` - -## Task 3: 给 uploader 做最小字段接线 - -**Files:** -- Modify: `uploader/douyin_uploader/main.py` -- Modify: `uploader/ks_uploader/main.py` -- Modify: `uploader/xiaohongshu_uploader/main.py` -- Modify: `tests/test_xiaohongshu_uploader.py` - -- [ ] **Step 1: 给抖音视频接入 `desc`** - -在 `DouYinVideo.__init__()` 中补 `desc` 参数和 `self.desc`,并把发布页填写逻辑改成: - -```python -await self.fill_title_and_description(page, self.title, self.desc or self.title, self.tags) -``` - -- [ ] **Step 2: 给抖音图文接入 `title + note`** - -在 `DouYinNote.__init__()` 中补 `title` 参数,保留 `note` 作为图文正文,发布页填写改成: - -```python -await self.fill_title_and_description(page, self.title, self.note, self.tags) -``` - -要求: - -- `title` 必填 -- `note` 可选但建议非空;如果现有逻辑要求非空,就继续保留校验 - -- [ ] **Step 3: 给快手视频接入 `desc`** - -在 `KSVideo.__init__()` 中补 `desc` 参数和 `self.desc`,填写“描述”区域时改成: - -```python -await page.keyboard.type(self.desc or self.title) -``` - -- [ ] **Step 4: 给快手图文接入 `title + note`** - -在 `KSNote.__init__()` 中补 `title` 参数与 `self.title`,保留 `self.note` 作为正文。 - -要求: - -- 图文上传校验里增加 `title` 必填 -- 如果页面当前只有正文输入区,没有独立标题区,仍然要在 CLI / request / 构造函数层保持 `title` 字段,以便后续平台对齐 - -- [ ] **Step 5: 检查小红书 CLI 接线是否需要补充适配** - -确认 `XiaoHongShuVideo` / `XiaoHongShuNote` 只需要以下映射即可: - -```python -title=request.title -desc=request.description # 视频 -desc=request.note # 图文 -``` - -如果 `XiaoHongShuNote` 里还保留历史 `note` 兼容,不要删,只保持 CLI 层优先走 `title + note + tags`。 - -- [ ] **Step 6: 补一条小红书映射测试** - -在 `tests/test_xiaohongshu_uploader.py` 中增加最小断言: - -```python -def test_note_title_defaults_do_not_override_explicit_title(self): - app = xhs_main.XiaoHongShuNote( - image_paths=["a.png"], - note="正文", - tags=[], - publish_date=0, - account_file="account.json", - title="显式标题", - desc="图文正文", - ) - self.assertEqual(app.title, "显式标题") - self.assertEqual(app.desc, "图文正文") -``` - -- [ ] **Step 7: 跑 uploader 相关测试** - -Run: - -```powershell -py -3 -m unittest tests.test_xiaohongshu_uploader -v -``` - -Expected: - -- 小红书 uploader 相关单测通过 - -- [ ] **Step 8: 提交 uploader 接线** - -```powershell -git add uploader/douyin_uploader/main.py uploader/ks_uploader/main.py uploader/xiaohongshu_uploader/main.py tests/test_xiaohongshu_uploader.py -git commit -m "feat: align browser uploader metadata fields" -``` - -## Task 4: 新增小红书 skill,并同步更新抖音、快手 skill - -**Files:** -- Create: `skills/xiaohongshu-upload/SKILL.md` -- Create: `skills/xiaohongshu-upload/references/runtime-requirements.md` -- Create: `skills/xiaohongshu-upload/references/cli-contract.md` -- Create: `skills/xiaohongshu-upload/references/troubleshooting.md` -- Create: `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_commands.ps1` -- Create: `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_commands.sh` -- Create: `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_cli_template.py` -- Modify: `skills/douyin-upload/SKILL.md` -- Modify: `skills/douyin-upload/references/cli-contract.md` -- Modify: `skills/douyin-upload/scripts/examples/douyin_commands.ps1` -- Modify: `skills/douyin-upload/scripts/examples/douyin_commands.sh` -- Modify: `skills/douyin-upload/scripts/examples/douyin_cli_template.py` -- Modify: `skills/kuaishou-upload/SKILL.md` -- Modify: `skills/kuaishou-upload/references/cli-contract.md` -- Modify: `skills/kuaishou-upload/scripts/examples/kuaishou_commands.ps1` -- Modify: `skills/kuaishou-upload/scripts/examples/kuaishou_commands.sh` -- Modify: `skills/kuaishou-upload/scripts/examples/kuaishou_cli_template.py` - -- [ ] **Step 1: 复制现有 skill 目录结构作为小红书骨架** - -要求: - -- 风格对齐 `skills/douyin-upload/` -- 默认优先走 `sau xiaohongshu ...` -- 明确小红书支持: - - `login` - - `check` - - `upload-video` - - `upload-note` - -- [ ] **Step 2: 写小红书 CLI 契约** - -至少写清: - -```bash -sau xiaohongshu login --account -sau xiaohongshu check --account -sau xiaohongshu upload-video --account --file