## File: README.md

# social-auto-upload

`social-auto-upload` 是一个强大的自动化工具，旨在帮助内容创作者和运营者高效地将视频内容一键发布到多个国内外主流社交媒体平台。
项目实现了对 `抖音`、`Bilibili`、`小红书`、`快手`、`视频号`、`百家号`、`支付宝生活号`、`微博`、`虎扑`、`TikTok` 以及 `YouTube` 等平台的视频上传、定时发布等功能。
结合各平台 `uploader` 模块，您可以轻松配置和扩展支持的平台，并通过示例脚本快速上手。



## 💎 赞助商



|  | 感谢 [DolOffer](https://doloffer.com/) 对本项目的支持！对于做内容矩阵、多平台分发和 AI 自动化运营的创作者来说，ChatGPT、Claude、YouTube Premium、Spotify、Apple Music、Notion、Office 等数字工具往往是长期成本。DolOffer 提供 AI、视频、音乐和效率工具相关的订阅与充值服务，帮助用户更低成本地配置常用数字产品。更多说明可查看 [DolOffer Guide](https://github.com/Doloffer-g/guide)。使用优惠码 `AI8888` 可额外享受 9 折优惠，具体价格和服务规则以官网为准。 |
| --- | --- |
|  | 轻视AI：一句话生产MG动画，适合知识，科普，讲解，教程，介绍等类型视频的低成本制作，视频矩阵，养号等，成本只有seedance等1%。现在[注册](https://chilltion.com/?ref=1y5k5k)送1500积分 |
|  | ClawPower 是一家稳定可靠 AI 大模型中转服务商，提供 Claude、GPT、Gemini 60+ 大模型接入。无论是 OpenClaw、Hermes 智能体自动化场景，Claude Code、Codex 编程工具接入，还是公众号、小红书内容创作；都能获得稳定、顺滑、可长期使用的模型服务体验。低至官方价格的 30%，点击[免费领取 5 刀现金](http://t.clawpower.vip/1005)体验券 |
|  | **成为赞助商**
      如果您有意赞助本项目，请扫描左侧微信二维码（添加时请注明来意：**赞助**）。 |



---


## 目录

- [💡 功能特性](#功能特性)
- [💾 安装指南](#安装指南)
- [🤖 AI Agent](#agent)
- [🏁 快速开始](#快速开始)
- [🗂️ 重构计划](#%EF%B8%8F重构计划)
- [📣 近况说明](#近况说明)
- [🐇 项目背景](#项目背景)
- [📃 详细文档](#详细文档)
- [🐾 交流与支持](#交流与支持)
- [🤝 贡献指南](#贡献指南)
- [📜 许可证](#许可证)
- [⭐ Star History](#star-history)

## 💡功能特性

| 平台 | 登录/账号准备 | 视频上传 | 图文上传 | 定时发布 | CLI | Skill | 说明 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 抖音 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 当前主线重构最完整 |
| Bilibili | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | 运行时自动准备 `biliup` |
| 小红书（浏览器版） | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 浏览器自动化，CLI/Skill 已接入 |
| 快手 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 浏览器自动化，CLI/Skill 初版已接入 |
| 视频号 | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | 浏览器自动化，对应 `tencent_uploader` |
| 百家号 | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | 浏览器自动化 |
| 支付宝生活号 | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | 浏览器自动化，支持生活号视频 |
| 微博 | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | 浏览器自动化，标题最多 30 字 |
| 虎扑 | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | 浏览器自动化，标题 4–40 字 |
| TikTok | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | 当前示例走 Chrome 版实现 |
| YouTube | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | 浏览器自动化（Studio），支持加入播放列表/可见性 |

### AI这么强，为什么还需要这个项目
在你使用AI的能力，browser agent等等，每次都让 agent 重新解析网页、截图理解, 临场判断
该项目经过大量验证，上传这种 高频，重复，无聊的工作交给脚本和程序去执行


## 💾安装指南

### 自己上手使用
如果你只是普通用户，不准备借助 agent 客户端，直接看

安装、更新、环境准备已经统一收敛到文档：

- [安装说明](./docs/install.md)
- [更新说明](./docs/update.md)


### AGENT 

```
AI的发展毋庸置疑，希望你遇到这种安装和使用，不要再怯场，而是交给各种AI Agent来协助你
```

如果你准备把这个仓库直接交给 `OpenClaw`、`Codex`、`Claude Code` 来安装和使用

先把仓库给 agent，再把这份启动提示词一起发给它：

- [Agent Bootstrap Prompt](./docs/agent-bootstrap.md)

这份提示词会引导 agent：

- 优先按当前主线安装项目
- 优先使用 `uv`、`sau` CLI 和 `skills/`
- 先验证 `bilibili`、`douyin`、`kuaishou`、`xiaohongshu` 四个平台入口是否可用


### 补充说明：

- CLI 使用请看：[CLI 使用说明](./docs/CLI.md)
- 如果你准备在 `OpenClaw`、`Codex`、`Claude Code / cc` 里使用本项目，先看：[Agent Bootstrap Prompt](./docs/agent-bootstrap.md)
- agent / skill 请看：[Douyin Upload Skill](./skills/douyin-upload/SKILL.md)
- agent / skill 请看：[Kuaishou Upload Skill](./skills/kuaishou-upload/SKILL.md)
- agent / skill 请看：[Xiaohongshu Upload Skill](./skills/xiaohongshu-upload/SKILL.md)
- agent / skill 请看：[Bilibili Upload Skill](./skills/bilibili-upload/SKILL.md)
- 历史 Web 说明请看：[历史 Web 版本说明](./docs/legacy-web.md)
- 其他单平台 skill 与整合型 skill 仍在开发中
- `requirements.txt` 目前主要用于历史兼容路径，普通用户不需要优先使用它


## 📣近况说明

`2026.03.24`

最近我的重心一直都在创业上，而且手里还有一些项目没完全跑通，所以这个仓库前面有很长一段时间，我确实没有办法投入特别多精力去持续维护。

这个项目不知不觉已经 `9k+ star` 了，社群里也已经有 `2000+` 小伙伴了。看到它真的在持续帮到大家，我心里还是挺开心的，也是真的很感谢大家一直以来的支持、反馈。

所以我想，决定先停一下，抽一段时间出来，把这个项目好好重构和优化一轮。

接下来这段时间，这个仓库应该会进入一个相对密集更新的阶段。我现在最想先做的事情主要有这几件：

1. 使用更隐蔽、更稳定的自动化方案，尽量降低平台检测风险
2. 补齐一些常用平台的图文能力，并逐步完成 CLI 化、Skill 化
3. 陆续测试并上架到更多 skill 平台，让大家的龙虾、螃蟹、毛毛虫都能打通 AI 自媒体的最后一道关

所以如果你之前觉得这个项目更新有点慢，哈哈哈，后面大概率会快很多。也欢迎大家继续关注，最近应该会是一段持续修、持续更、持续重构的阶段。

## 🗂️重构计划

项目正在进行一轮整体重构，当前重构重点是：

- 各平台 uploader 的结构收敛
- CLI 统一接入
- 面向 OpenClaw、Codex、 Claude Code 等工具的 skill 化
- 更换为 `patchright` 驱动，提升兼容性与隐蔽性
- 主线优先围绕无头模式推进

“无头模式（headless）”，指的是浏览器在后台运行，不弹出可见窗口，但自动化流程仍然会照常执行。这样更适合 CLI、服务端、自动任务和 agent 场景。

Web 端相关代码仍然保留，但已经不是当前主线，不保证可直接运行，也不保证与当前 uploader/CLI 完全同步。


## 🏁快速开始

### 方式 1：使用 CLI

当前抖音、快手、小红书、Bilibili、视频号、百家号、支付宝生活号、微博和虎扑已经接入 CLI：

```
/* Detailed source-code truncated for AI context efficiency. */
```

> YouTube 说明：登录是交互式的（Google 账号，浏览器里完成，无二维码）。这里走浏览器自动化而不是官方 API，
> 是因为**未通过 Google 合规审核的 API 项目上传的视频会被强制锁为私享、无法改公开**，对个人/单频道不实用；
> 浏览器自动化没有此限制，可直接发布公开视频，也与本项目其它平台的 cookie 方案一致。
> `--playlist` 适合连载/系列追更；`--visibility` 可选 `public`/`unlisted`/`private`。
> 上传会**等进度到 100% 再点发布**（浏览器上传靠窗口开着传，传一半就发布会被掐断卡在中途）。
> youtube.com 被墙的地区：在 `conf.py` 设 `YT_PROXY = "http://127.0.0.1:7890"`（chromium 不吃系统代理，需显式指定）。

补充说明：

- `creator` 之类的名字只是示例值，真正含义是 `account_name`
- 一个 `account_name` 对应一个账号文件，可以准备多个账号，也可以按账号名并发执行任务
- 抖音视频发布若触发短信二次验证，程序会优先读取项目根目录下的 `verify_code.txt`；如果你是在本地交互式终端手动运行 CLI，也可以直接按终端提示输入验证码
- 浏览器平台统一约定：
- 视频使用 `title + desc + tags`
- 图文使用 `title + note + tags`
- Bilibili CLI 不要求用户手动安装 `biliup`
- 首次运行相关命令时，程序会自动下载 `biliup`
- 后续运行会自动检查上游 release 并更新
- Bilibili 登录建议由用户自己在本地真实终端里执行；如果终端二维码显示不完整，可以直接打开当前目录下的 `qrcode.png` 扫码

### 方式 2：使用 examples

`examples/` 目录里同时存在两类脚本：

- 当前主线 CLI 包装示例
- 历史直连 uploader 示例

对抖音、快手、小红书、Bilibili 来说，当前主线优先使用上面的 `sau ...` CLI。
下面这些脚本主要是历史直连 uploader 示例或调试入口：

- `examples/upload_to_douyin.py`
- `examples/upload_video_to_bilibili.py`
- `examples/upload_to_kuaishou.py`
- `examples/upload_video_to_tencent.py`
- `examples/upload_video_to_baijiahao.py`
- `examples/get_alipay_cookie.py`
- `examples/test_alipay_upload.py`
- `examples/upload_video_to_tiktok.py`
- `examples/upload_video_to_xiaohongshu.py`

## 🐇项目背景

该项目最初是我个人用于自动化管理社交媒体视频发布的工具。我的主要发布策略是提前一天设置定时发布，因此项目中很多定时发布相关的逻辑是基于“第二天”的时间进行计算的。

如果您需要立即发布或其他定制化的发布策略，欢迎研究源码或在社区提问。

## 📃详细文档

已落后，目前在快速重构该项目，当下，你需要做的是把这个仓库，发给你的AI agent：qwen code，codex cc，openclaw等等，让他们帮你安装和使用

更详细的文档和说明，请查看：[social-auto-upload 官方文档](https://sap-doc.nasdaddy.com/)

## 🐾交流与支持

[☕ Donate as u like](https://www.buymeacoffee.com/hysn2001m) - 如果您觉得这个项目对您有帮助，可以考虑赞助。

如果您也是独立开发者、技术爱好者，对 #技术变现 #AI创业 #跨境电商 #自动化工具 #视频创作 等话题感兴趣，欢迎加入社群交流。

### Creator






## 🤝贡献指南

欢迎各种形式的贡献，包括但不限于：

-   提交 Bug报告 和 Feature请求。
-   改进代码、文档。
-   分享使用经验和教程。

如果您希望贡献代码，请遵循以下步骤：

1.  Fork 本仓库。
2.  创建一个新的分支 (`git checkout -b feature/YourFeature` 或 `bugfix/YourBugfix`)。
3.  提交您的更改 (`git commit -m 'Add some feature'`)。
4.  Push到您的分支 (`git push origin feature/YourFeature`)。
5.  创建一个 Pull Request。

提交代码或文档前，请确认您有权提交相关内容，并同意这些贡献按照本项目的 MIT License 发布。提交第三方代码时，请同时说明来源及其适用的许可证。

## 主要贡献者

<a href="https://github.com/dreammis/social-auto-upload/graphs/contributors">
  
</a>


## 🙏致谢

本项目的 Bilibili 上传能力基于开源项目 `biliup` 的能力进行接入与封装。
感谢 `biliup` 项目及其贡献者提供的基础能力：

- https://github.com/biliup/biliup

本项目依赖的第三方组件和运行时工具仍受其各自许可证约束。下游发行或集成本项目时，请同时检查并保留相关第三方组件要求的版权、许可证和 NOTICE 声明。

## 📜许可证

本项目采用 [MIT License](LICENSE) 开源许可证。除第三方组件外，本项目代码可以在遵守该许可证条款的前提下用于商业软件，包括闭源软件。

## ⭐Star-History

> 如果这个项目对您有帮助，请给一个 ⭐ Star 以表示支持！




[](https://star-history.dera.page/#dreammis/social-auto-upload&Date)

---

## File: docs/superpowers/specs/2026-03-25-bilibili-cli-design.md

# Bilibili CLI 设计

日期：2026-03-25

## 概要

这份设计要把 `bilibili` 挂到 `sau` 下面，用户侧体验尽量和现在的 `douyin`、`kuaishou` 保持一致。

核心约束只有两个：

- 用户不需要自己安装 `biliup`
- 外部统一走 `sau bilibili ...`

程序会把 `biliup` 当作内部运行时依赖来处理：

- `sau bilibili ...` 是唯一公开入口
- 本地没有 `biliup` 时自动下载
- 每次运行都检查 GitHub Release 最新版本
- 如果发现有更新，先自动更新，再继续执行当前命令

这份设计刻意保持轻量，不重新发明一套 B 站上传语义，而是直接复用仓库里现有的 B 站上传模型。

## 目标

- 让 `sau bilibili ...` 和 `sau douyin ...`、`sau kuaishou ...` 保持统一心智
- 隐藏 `biliup` 的安装细节，降低用户使用成本
- 复用项目里已经存在的账号文件、`VideoZoneTypes`、定时发布等能力
- 不做过度封装

## 非目标

- 第一版不把 `biliup` 二进制直接提交进仓库
- 第一版不维护本地 release manifest
- 第一版不做 B 站图文发布
- 第一版不重做现有的 B 站上传领域模型

## 当前项目基础

仓库里已经有 B 站上传能力：

- `uploader/bilibili_uploader/main.py` 目前直接封装了 `biliup.plugins.bili_webup`
- `examples/upload_video_to_bilibili.py` 已经在使用现有上传参数
- `utils/constant.py` 已经定义了完整的 `VideoZoneTypes`

也就是说，你现在项目里的 B 站上传语义已经很明确，核心就是：

- `file`
- `title`
- `desc`
- `tid`
- `tags`
- `dtime`

所以第一版 CLI 不需要重新造模型，直接沿用这套。

## 用户侧 CLI 设计

### 支持的命令

- `sau bilibili login`
- `sau bilibili check`
- `sau bilibili upload-video`

### 命令契约

#### `sau bilibili login`

作用：

- 自动准备 `biliup`
- 如果有更新则先升级
- 然后调用 `biliup` 完成登录
- 将账号数据按项目自己的账号文件规则保存下来

第一版行为：

- 本地没有 `biliup` 时自动下载最新 release
- 本地已有但上游有更新时自动升级
- 升级完成后继续执行登录流程

#### `sau bilibili check`

作用：

- 自动准备 `biliup`
- 检查当前账号是否可用

第一版行为：

- 结合本地账号文件存在性和 `biliup` 实际可用性来判断
- 输出风格和其他平台保持一致：
  - `valid`
  - `invalid`

#### `sau bilibili upload-video`

作用：

- 自动准备 `biliup`
- 走项目当前已有的 B 站上传参数体系完成视频上传

第一版参数：

- `--account` 必填
- `--file` 必填
- `--title` 必填
- `--desc` 必填
- `--tid` 必填
- `--tags` 选填
- `--schedule` 选填

明确决定：

- `tid` 在第一版里必须传
- 不给默认分区，避免猜测和隐式错误

## 运行时依赖策略

### 选定方案

`biliup` 不提交进仓库，也不要求用户手工安装。

`sau bilibili ...` 在运行时自动处理它：

1. 查找本地是否已有 `biliup`
2. 检查 GitHub Release 最新版本
3. 如果缺失或过期，则自动下载最新版本
4. 替换本地运行时副本
5. 继续执行本次命令

### 选择这个方案的原因

- 仓库体积更干净
- 用户不需要自己找 release、自己下载
- 对外仍然只有一个统一入口 `sau`
- 不需要使用 `git submodule`

### 接受的代价

这套方案明确接受一个现实：

- 每次运行都会检查上游 release
- 上游如果改 CLI 行为，可能会影响这层适配

所以这里的应对方式不是做重封装，而是保持 wrapper 很薄，减少被动维护成本。

## 存储与解析

`biliup` 应该存放在本地运行时缓存目录中，而不是源码目录中。

缓存目录只需要满足：

- 当前用户可写
- 可跨命令复用
- 不进入 git 管理

解析器的职责应当是：

- 识别当前操作系统
- 选择对应平台的 release asset
- 下载并替换可执行文件
- 返回最终可执行路径

## 轻量封装边界

为了避免过度封装，第一版只建议拆成 3 个很薄的部分。

### 1. Resolver

职责：

- 判断本地是否已有 `biliup`
- 检查 GitHub Release 最新版本
- 下载或更新可执行文件
- 返回最终可执行文件路径

### 2. Runner

职责：

- 调用解析出来的 `biliup`
- 收集退出码、标准输出、标准错误
- 对明显的进程级错误做一层项目内友好的报错转换

### 3. `sau_cli.py` 中的 bilibili 子命令

职责：

- 解析 `sau bilibili ...` 参数
- 把这些参数翻译成底层运行逻辑
- 让帮助信息风格和其他平台一致

第一版不需要更多层，也不需要再抽一套很重的统一框架。

## 与现有项目概念的映射

### 账号文件

B 站也继续沿用现在项目的账号别名机制：

- 用户传 `--account <name>`
- 程序解析成对应的账号文件路径

### 分区

`tid` 保持为一等参数。

`VideoZoneTypes` 继续保留并服务于：

- example
- 文档
- 后续可能的辅助工具

### 定时发布

`--schedule` 保持和当前 `sau` 其他平台一致的使用方式：

- 不传就是立即发布
- 传了就是定时发布

具体如何映射到底层 B 站执行逻辑，由 adapter 负责，不暴露给用户。

## 错误处理

第一版错误处理保持直接，不做花哨包装：

- 下载失败：明确告诉用户自动下载 `biliup` 失败
- 更新失败：明确告诉用户最新 release 准备失败
- 登录失败：保留 `biliup` 登录失败上下文
- 检查失败：输出 `invalid`
- 上传失败：返回非零退出码，并展示上游错误摘要

第一版不追求把所有 `biliup` 错误文本都重新翻译一遍。

## 文档影响范围

实现完成后，至少需要补齐这些地方：

- `README.md`
- `docs/CLI.md`
- 安装与更新文档
- 一套对应的 Bilibili skill
- Bilibili example 脚本

对外表达应当统一成：

- 用户使用的是 `sau bilibili ...`
- `biliup` 由程序自动准备

## 测试策略

第一版最少需要验证这些路径：

- `sau bilibili login --account <name>`
- `sau bilibili check --account <name>`
- `sau bilibili upload-video ...`
- 本地没有 `biliup` 时能自动下载
- 本地已有旧版本时能先升级再执行
- 本地已有最新版本时能直接复用

因为登录和上传涉及真实外部平台，第一版以手工验证为主是可以接受的。

## 推荐实现顺序

1. 在 `sau_cli.py` 中加入 `bilibili` 子命令
2. 增加一个最小可用的 `biliup` resolver
3. 增加一个最小可用的 `biliup` runner
4. 接上 `login / check / upload-video`
5. 补文档、example、skill

## 最终结论

- 对外入口固定为 `sau bilibili ...`
- 第一版支持 `login`、`check`、`upload-video`
- `tid` 必填
- `biliup` 不需要用户手动安装
- 每次运行都检查 GitHub Release
- 有新版本时先自动更新，再继续执行
- 整体实现保持轻量，不做过度封装

---

## File: docs/superpowers/specs/2026-03-25-browser-cli-unification-design.md

# 浏览器平台 CLI 统一与小红书 Skill 设计

日期：2026-03-25

## 概要

这份设计处理三个浏览器自动化平台的主线接口统一：

- 抖音
- 快手
- 小红书

目标不是重写 uploader，也不是再抽一层复杂框架，而是把当前已经存在但不一致的 CLI、skill、文档、示例收口成一套统一契约。

这次设计同时解决两个现实问题：

1. 小红书虽然已经有可用的浏览器 uploader，但还没有接入 `sau` CLI，也没有对应 skill。
2. 抖音、快手当前的 CLI 契约还带着历史字段，比如视频没有单独 `--desc`，而图文正文命名和视频描述语义混杂，不利于三家浏览器平台形成稳定统一的主线接口。

这次统一后的对外入口固定为：

- `sau douyin ...`
- `sau kuaishou ...`
- `sau xiaohongshu ...`

并让三家浏览器平台的视频、图文上传都遵循统一的主线参数模型：

- 视频：`title + desc + tags`
- 图文：`title + note + tags`

## 目标

- 给小红书补齐主线 CLI：
  - `login`
  - `check`
  - `upload-video`
  - `upload-note`
- 统一抖音、快手、小红书三家浏览器平台的 CLI 上传参数模型
- 补齐小红书 skill、示例脚本、README、CLI 文档、安装/更新文档
- 修正抖音、快手现有 CLI 契约里缺失的 `desc` 能力
- 保持现有 uploader 主体逻辑不大改，不做过度封装

## 非目标

- 这次不重构 uploader 架构
- 这次不改 Web 旧路径
- 这次不改 Bilibili 的上传契约
- 这次不做浏览器集成测试
- 这次不保留公开的 `--note` 主契约

## 当前项目基础

### 已有能力

- 抖音、快手已经接入 `sau_cli.py`
- Bilibili 已经接入 CLI 和 skill
- 小红书已经具备：
  - 登录
  - cookie 校验
  - 视频上传
  - 图文上传
  - 定时发布
- 小红书 uploader 内部已经支持：
  - 视频：`title + desc + tags`
  - 图文：`title + desc + tags`
  - 图文里的 `desc` 可选

### 当前不一致点

- 抖音视频 CLI：`--title`、`--tags`，没有 `--desc`
- 快手视频 CLI：`--title`、`--tags`，没有 `--desc`
- 抖音图文 CLI：`--note`、`--tags`
- 快手图文 CLI：`--note`、`--tags`
- 小红书还没有 CLI/skill 接口

也就是说，当前三家浏览器平台的主线能力并不统一，尤其是：

- 视频描述没有统一暴露为 `desc`
- 图文正文是否应该沿用 `note` 语义没有统一

## 统一后的 CLI 设计

### 支持的平台

- `douyin`
- `kuaishou`
- `xiaohongshu`

### 支持的动作

每个平台统一支持：

- `login`
- `check`
- `upload-video`
- `upload-note`

### 统一后的上传参数模型

#### 视频上传

```bash
sau  upload-video \
  --account <account_name> \
  --file <video-path> \
  --title "<title>" \
  [--desc "<description>"] \
  [--tags tag1,tag2] \
  [--schedule "YYYY-MM-DD HH:MM"] \
  [平台特有参数...]
```

统一规则：

- `--title` 必填
- `--desc` 选填
- `--tags` 选填
- `--schedule` 选填

平台特有参数：

- 抖音：
  - `--thumbnail`
  - `--product-link`
  - `--product-title`
- 快手：
  - `--thumbnail`
- 小红书：
  - `--thumbnail`

#### 图文上传

```bash
sau  upload-note \
  --account <account_name> \
  --images  [image-2 ...] \
  --title "<title>" \
  [--note "<content>"] \
  [--tags tag1,tag2] \
  [--schedule "YYYY-MM-DD HH:MM"]
```

统一规则：

- `--images` 必填
- `--title` 必填
- `--note` 选填
- `--tags` 选填
- `--schedule` 选填

明确决定：

- 图文主线正文统一叫 `note`
- 视频主线描述统一叫 `desc`
- 文档、skill、示例统一使用：
  - 视频：`--title + --desc + --tags`
  - 图文：`--title + --note + --tags`

## 数据模型设计

为了让 CLI 层和 uploader 层映射清晰，每个平台都保持各自的 request dataclass，但字段命名统一。

### 视频请求对象

统一字段：

- `account_name`
- `video_file`
- `title`
- `description`
- `tags`
- `publish_date`
- `publish_strategy`
- `debug`
- `headless`

平台特有字段保留：

- 抖音：
  - `thumbnail_file`
  - `product_link`
  - `product_title`
- 快手：
  - `thumbnail_file`
- 小红书：
  - `thumbnail_file`

### 图文请求对象

统一字段：

- `account_name`
- `image_files`
- `title`
- `note`
- `tags`
- `publish_date`
- `publish_strategy`
- `debug`
- `headless`

这里明确保留 `note`，因为它更符合图文正文语义，不应强行复用视频里的 `description / desc` 命名。

## 与现有 uploader 的映射

### 抖音

- 视频上传继续复用 `DouYinVideo`
- 给抖音视频补齐 `desc` 输入映射
- 图文上传改为显式接收 `title + note + tags`
- `note` 在 CLI 层映射到抖音图文正文输入区

### 快手

- 视频上传继续复用 `KSVideo`
- 给快手视频补齐 `desc` 输入映射
- 图文上传改为显式接收 `title + note + tags`

### 小红书

- 登录、校验直接接 `xiaohongshu_setup` / `cookie_auth`
- 视频上传复用 `XiaoHongShuVideo`
- 图文上传复用 `XiaoHongShuNote`
- 因为小红书 uploader 已经支持 `title + desc + tags`，CLI 层把 `note` 稳定映射到图文正文即可

## 兼容与迁移策略

这次采用“直接统一，不保留旧的模糊公开契约”的策略。

具体表现：

- `README.md`
- `docs/CLI.md`
- `docs/install.md`
- `docs/update.md`
- `skills/douyin-upload/...`
- `skills/kuaishou-upload/...`
- 新增 `skills/xiaohongshu-upload/...`
- `scripts/examples/...`

都会在同一轮里切换到新契约，避免出现：

- 一部分文档把图文正文写成 `--note`
- 一部分文档把图文正文写成 `--desc`

这样做的代价是旧示例命令会失效，但换来的是主线契约彻底统一：

- 视频永远是 `desc`
- 图文永远是 `note`

## Skill 设计

新增：

- `skills/xiaohongshu-upload/SKILL.md`
- `skills/xiaohongshu-upload/references/cli-contract.md`
- `skills/xiaohongshu-upload/references/runtime-requirements.md`
- `skills/xiaohongshu-upload/references/troubleshooting.md`
- `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_commands.ps1`
- `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_commands.sh`
- `skills/xiaohongshu-upload/scripts/examples/xiaohongshu_cli_template.py`

并同步更新：

- `skills/douyin-upload/SKILL.md`
- `skills/douyin-upload/references/cli-contract.md`
- `skills/kuaishou-upload/SKILL.md`
- `skills/kuaishou-upload/references/cli-contract.md`

skill 原则继续保持：

- 优先走 `sau`
- agent 不要先读 uploader 源码
- CLI 失败时再看 troubleshooting
- 登录二维码图片优先直接展示给用户扫码

## 文档设计

至少更新：

- `README.md`
- `docs/CLI.md`
- `docs/install.md`
- `docs/update.md`

统一后的表达口径：

- 三家浏览器平台都已经接入 CLI
- 三家浏览器平台都已经接入 skill
- 视频上传统一字段：
  - `title`
  - `desc`
  - `tags`
- 图文上传统一字段：
  - `title`
  - `note`
  - `tags`
- `account_name` 是用户自定义账号名，不是固定只能叫 `creator`
- 一个 `account_name` 对应一个账号文件，可多账号隔离并发

## Example 设计

examples 保留两类路径：

1. CLI 主线示例
2. 历史直连 uploader 示例

小红书需要补到和其他平台同等级的主线表达里：

- `examples/get_xiaohongshu_cookie.py`
- `examples/upload_video_to_xiaohongshu.py`
- 如有必要，补一份更贴近 CLI 契约的调用示例

README 和 docs 中要明确说明：

- 推荐优先使用 `sau xiaohongshu ...`
- 历史直连 uploader 示例只是调试入口

## 错误处理

### 参数级错误

由 CLI parser 负责：

- 文件不存在
- 时间格式非法
- 缺少 `--title`
- 缺少 `--images`

### 业务级错误

由 uploader 和现有校验负责：

- cookie 不存在
- cookie 已失效
- 上传失败
- 页面结构异常

### 二维码口径

三家浏览器平台统一保留这条说明：

- 如果登录流程生成了本地二维码图片，agent 应优先直接展示/发送图片给用户扫码，而不是只返回路径

## 测试策略

这次只做最小但有价值的 CLI 级验证，不做浏览器集成测试。

至少补这些测试：

- parser 能识别 `xiaohongshu`
- 三个平台新契约能正确解析：
  - `upload-video --title --desc --tags`
  - `upload-note --images --title --note --tags`
- dispatch 能正确把参数转成对应 request
- 小红书 `login/check/upload-video/upload-note` 分支能被正确路由

保留现有：

- `tests/test_xiaohongshu_uploader.py`

## 文件影响范围

### 必改

- `sau_cli.py`
- `README.md`
- `docs/CLI.md`
- `docs/install.md`
- `docs/update.md`

### 新增

- `skills/xiaohongshu-upload/` 全套文件
- 对应 CLI 单测文件

### 同步修改

- `skills/douyin-upload/...`
- `skills/kuaishou-upload/...`
- `examples/get_xiaohongshu_cookie.py`
- `examples/upload_video_to_xiaohongshu.py`

## 推荐实现顺序

1. 先改 `sau_cli.py` 和 request 模型
2. 接上小红书 CLI 路由
3. 给抖音、快手补 `desc` / 图文新字段映射
4. 补 CLI 单测
5. 新增小红书 skill
6. 更新抖音、快手 skill 契约
7. 更新 README / CLI / install / update 文档
8. 更新 examples

## 最终结论

- 三家浏览器平台统一成同一套 CLI 动作：
  - `login`
  - `check`
  - `upload-video`
  - `upload-note`
- 三家浏览器平台统一成同一套主线元数据模型：
  - 视频：`title + desc + tags`
  - 图文：`title + note + tags`
- 小红书补齐 CLI 与 skill
- 抖音、快手补齐 `desc` 能力，并统一图文正文字段为 `note`
- 实现保持轻量，不做过度封装

---

## File: docs/superpowers/plans/2026-03-25-bilibili-cli-implementation.md

# 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`，覆盖这些最小路径：

```
/* Detailed source-code truncated for AI context efficiency. */
```

- [ ] **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
    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 <name>`
- `sau bilibili check --account <name>`
- `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"
```

---

## File: docs/superpowers/plans/2026-03-25-browser-cli-unification-implementation.md

# 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
    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
class DouyinNoteUploadRequest:
    title: str
    note: str

class KuaishouVideoUploadRequest:
    title: 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 <account>
sau xiaohongshu check --account <account>
sau xiaohongshu upload-video --account <account> --file <video> --title "<title>" [--desc "..."] [--tags ...]
sau xiaohongshu upload-note --account <account> --images  --title "<title>" [--note "..."] [--tags ...]
```

- [ ] **Step 3: 更新抖音、快手 skill 契约**

要求：

- 视频示例命令补 `--desc`
- 图文示例命令改成 `--title --note`
- 所有模板文件同步更新，不要只改文档不改脚本

- [ ] **Step 4: 做 skill 文件级自检**

Run:

```powershell
Get-ChildItem skills\xiaohongshu-upload -Recurse
Get-Content skills\douyin-upload\references\cli-contract.md
Get-Content skills\kuaishou-upload\references\cli-contract.md
```

Expected:

- 小红书 skill 目录完整
- 抖音、快手 skill 契约都已经切到新参数模型

- [ ] **Step 5: 提交 skill 变更**

```powershell
git add skills/xiaohongshu-upload skills/douyin-upload skills/kuaishou-upload
git commit -m "feat: add xiaohongshu skill and align browser skill contracts"
```

## Task 5: 更新 examples 和 README / docs

**Files:**
- Modify: `examples/get_xiaohongshu_cookie.py`
- Modify: `examples/upload_video_to_xiaohongshu.py`
- Modify: `README.md`
- Modify: `docs/CLI.md`
- Modify: `docs/install.md`
- Modify: `docs/update.md`

- [ ] **Step 1: 改小红书 examples**

要求：

- `examples/get_xiaohongshu_cookie.py` 明确指向 `sau xiaohongshu login --account <account_name>` 这一主线
- `examples/upload_video_to_xiaohongshu.py` 说明当前主线优先走 CLI
- 如果继续保留 uploader 直连示例，注释里标明“调试入口 / 历史直连路径”

- [ ] **Step 2: 更新 README 平台表和快速开始**

README 至少要改这些位置：

- 平台能力表里把小红书改成：
  - `CLI ✅`
  - `Skill ✅`
- 快速开始里的浏览器平台命令改成统一契约
- 抖音、快手图文示例改成：

```bash
sau douyin upload-note --account <account_name> --images videos/1.png videos/2.png --title "图文标题" --note "图文正文"
sau kuaishou upload-note --account <account_name> --images videos/1.png videos/2.png --title "图文标题" --note "图文正文"
sau xiaohongshu upload-note --account <account_name> --images videos/1.png videos/2.png --title "图文标题" --note "图文正文"
```

- [ ] **Step 3: 更新 `docs/CLI.md`**

要求：

- 补 `xiaohongshu` 小节
- 把三家浏览器平台整理成一致说明：
  - 视频：`title + desc + tags`
  - 图文：`title + note + tags`
- 登录二维码说明补小红书

- [ ] **Step 4: 更新 `docs/install.md` 和 `docs/update.md`**

要求：

- 安装文档里补 `sau xiaohongshu --help`
- 更新文档里补小红书自检命令和 skill 路径
- 文档统一写 `account_name`

- [ ] **Step 5: 做文档与示例核对**

Run:

```powershell
Get-Content README.md | Select-String -Pattern "xiaohongshu|upload-note|--note|--desc" -Context 1,2
Get-Content docs\CLI.md | Select-String -Pattern "xiaohongshu|--note|--desc" -Context 1,2
Get-Content docs\install.md | Select-String -Pattern "xiaohongshu" -Context 1,2
Get-Content docs\update.md | Select-String -Pattern "xiaohongshu" -Context 1,2
```

Expected:

- README、CLI、install、update 都出现小红书 CLI
- 图文正文写成 `--note`
- 视频描述写成 `--desc`

- [ ] **Step 6: 跑最终最小验证**

Run:

```powershell
py -3 -m unittest tests.test_sau_browser_cli tests.test_xiaohongshu_uploader -v
py -3 sau_cli.py xiaohongshu --help
py -3 sau_cli.py xiaohongshu upload-video --help
py -3 sau_cli.py xiaohongshu upload-note --help
```

Expected:

- 单测通过
- 小红书 CLI 帮助存在
- 视频命令显示 `--desc`
- 图文命令显示 `--note`

- [ ] **Step 7: 提交收尾**

```powershell
git add examples/get_xiaohongshu_cookie.py examples/upload_video_to_xiaohongshu.py README.md docs/CLI.md docs/install.md docs/update.md
git commit -m "docs: align browser cli docs and examples"
```

---

## File: docs/superpowers/plans/2026-03-25-xiaohongshu-shallow-alignment.md

# Xiaohongshu Shallow Alignment 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:** Align the browser-based Xiaohongshu uploader with the current Douyin/Kuaishou style for login QR flow, patchright usage, and formal video/note entry points without expanding into CLI or docs work.

**Architecture:** Keep the work inside `uploader/xiaohongshu_uploader/main.py` as a shallow refactor. Introduce a thin login flow with QR extraction, cookie validation, and result payloads, then add a shared base uploader plus separate video and note browser flows that reuse common setup.

**Tech Stack:** Python, patchright, async Playwright-compatible browser automation, unittest

---

### Task 1: Lock expected login/setup behavior

**Files:**
- Create: `tests/test_xiaohongshu_uploader.py`
- Modify: `uploader/xiaohongshu_uploader/main.py`

- [ ] Add tests for `xiaohongshu_setup(..., return_detail=True)` invalid-cookie behavior and uploader validation behavior.
- [ ] Run the targeted test file and confirm it fails for the expected missing behavior.
- [ ] Implement the minimal production changes to satisfy those tests.

### Task 2: Refactor Xiaohongshu uploader module

**Files:**
- Modify: `uploader/xiaohongshu_uploader/main.py`

- [ ] Switch the module from `playwright.async_api` to `patchright.async_api`.
- [ ] Replace `page.pause()` login with QR extraction, terminal printing, QR file saving, polling, and cookie persistence.
- [ ] Add a shared base uploader plus formal video and note entry points while keeping legacy public names callable.

### Task 3: Refresh local debug examples

**Files:**
- Modify: `examples/get_xiaohongshu_cookie.py`
- Modify: `examples/upload_video_to_xiaohongshu.py`

- [ ] Update the login example to use the aligned setup entry.
- [ ] Update the upload example to expose direct video/note debug functions.

### Task 4: Verify

**Files:**
- Test: `tests/test_xiaohongshu_uploader.py`

- [ ] Run the targeted unittest file.
- [ ] Run a quick Python syntax/import check for the modified uploader and examples.

---

## File: docs/agent-bootstrap.md

# 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 更稳，也更容易维护。

---

## File: docs/CLI.md

# 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 <account_name>
sau douyin login --account <account_name> --headless
sau douyin check --account <account_name>
sau douyin upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 运动,训练
sau douyin upload-note --account <account_name> --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 <account_name>
sau kuaishou check --account <account_name>
sau kuaishou upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 运动,训练
sau kuaishou upload-note --account <account_name> --images videos/1.png videos/2.png videos/3.png --title "图文标题" --note "图文示例" --tags 图文,测试
```

## 小红书 CLI 子命令

```bash
sau xiaohongshu login --account <account_name>
sau xiaohongshu check --account <account_name>
sau xiaohongshu upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 小红书,视频
sau xiaohongshu upload-note --account <account_name> --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 <account_name>
```

## Bilibili CLI 子命令

```bash
sau bilibili login --account <account_name>
sau bilibili check --account <account_name>
sau bilibili upload-video --account <account_name> --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 <name>` 建议由用户自己在本地真实终端里执行；如果终端里的二维码显示不完整，可直接打开当前目录下的 `qrcode.png` 扫码

## 视频号 CLI 子命令

```bash
sau tencent login --account <account_name>
sau tencent check --account <account_name>
sau tencent upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 视频号,测试
```

视频号支持定时发布、草稿、合集和双比例封面：

```bash
sau tencent upload-video --account <account_name> --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 <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --draft
```

视频号登录和上传依赖浏览器中的登录态。无头模式下如果需要扫码，CLI 会生成临时二维码；需要人工查看页面时可以加 `--headed`。

## 百家号 CLI 子命令

```bash
sau baijiahao login --account <account_name>
sau baijiahao check --account <account_name>
sau baijiahao upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 百家号,测试
```

百家号当前支持登录、账号检查和视频上传；支持 `--thumbnail` 与 `--collection`，暂不支持 `--schedule`。上传前需要先完成百度账号登录并保存账号文件。

## 支付宝生活号 CLI 子命令

```bash
sau alipay login --account <account_name>
sau alipay check --account <account_name>
sau alipay upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 生活号,测试
```

支付宝生活号当前支持登录、账号检查和视频上传；支持 `--thumbnail` 与 `--collection`，暂不支持图文上传和 `--schedule`。首次使用前需要在支付宝内容创作后台完成登录，并确认账号已开通生活号内容创作权限。

## YouTube CLI 子命令

```bash
sau youtube login --account <account_name>
sau youtube check --account <account_name>
sau youtube upload-video --account <account_name> --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 <account_name>
sau weibo check --account <account_name>
sau weibo upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tags 微博,测试 --thumbnail covers/demo.png
```

微博当前支持登录、账号检查和视频上传；标题最多 30 个字，封面图建议小于 5 MB，暂不支持图文上传和 `--schedule`。

## 虎扑 CLI 子命令

```bash
sau hupu login --account <account_name>
sau hupu check --account <account_name>
sau hupu upload-video --account <account_name> --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 <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --schedule "2026-03-24 21:30"
sau douyin upload-note --account <account_name> --images videos/1.png videos/2.png --title "图文标题" --note "图文示例" --schedule "2026-03-24 21:30"
sau kuaishou upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --schedule "2026-03-24 21:30"
sau kuaishou upload-note --account <account_name> --images videos/1.png videos/2.png videos/3.png --title "图文标题" --note "图文示例" --schedule "2026-03-24 21:30"
sau xiaohongshu upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --schedule "2026-03-24 21:30"
sau xiaohongshu upload-note --account <account_name> --images videos/1.png videos/2.png videos/3.png --title "图文标题" --note "图文示例" --schedule "2026-03-24 21:30"
sau bilibili upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介" --tid 249 --schedule "2026-03-24 21:30"
sau tencent upload-video --account <account_name> --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/`。

---

## File: docs/install.md

# 安装说明

这个文档分成两部分：

- `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 <account_name>
sau douyin check --account <account_name>
sau douyin upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介"
图文正文1:
$noteText = @"图文正文"@    
sau douyin upload-note --account <account_name> --images videos/demo1.png videos/demo2.png --title "图文标题" --note $noteText --tags 'tag1,tag2'
图文正文2:
sau douyin upload-note --account <account_name> --images videos/demo1.png videos/demo2.png --title "图文标题" --notef '图文文件路径' --tags 'tag1,tag2'
添加 BGM（可选）:
sau douyin upload-note --account <account_name> --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 <account_name>`
- 检查cookie可用性,执行`sau douyin check --account <account_name>`

### 8. 快手主线示例

```bash
sau kuaishou login --account <account_name>
sau kuaishou check --account <account_name>
sau kuaishou upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介"
sau kuaishou upload-note --account <account_name> --images videos/demo1.png videos/demo2.png videos/demo.png --title "图文标题" --note "图文正文"
```

### 9. 小红书主线示例

```bash
sau xiaohongshu login --account <account_name>
sau xiaohongshu check --account <account_name>
sau xiaohongshu upload-video --account <account_name> --file videos/demo.mp4 --title "示例标题" --desc "示例简介"
sau xiaohongshu upload-note --account <account_name> --images videos/demo1.png videos/demo2.png videos/demo.png --title "图文标题" --note "图文正文"
```

### 10. Bilibili 主线示例

```bash
sau bilibili login --account <account_name>
sau bilibili check --account <account_name>
sau bilibili upload-video --account <account_name> --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 <name>`；如果二维码显示不完整，再提示用户打开 `qrcode.png`
- `requirements.txt` 目前是历史兼容文件，不是主安装入口
- `uploader/` 是核心实现目录
- `sau_cli.py` 是当前 CLI 主入口
- `docs/legacy-web.md` 是历史 Web 版本说明，不保证当前可用
- Bilibili 首次运行时可能自动下载 `biliup`

---

## File: docs/legacy-web.md

# 历史 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`