@iducky/media-agent 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/SHA256SUMS +94 -0
- package/bin/media-agent.mjs +89 -0
- package/docs/guides/capabilities.md +103 -0
- package/docs/guides/image-text-publishing.md +81 -0
- package/docs/guides/installation.md +103 -0
- package/docs/guides/runtime.md +13 -0
- package/manifest.json +382 -0
- package/package.json +42 -0
- package/pyproject.toml +20 -0
- package/resources/capabilities.json +34 -0
- package/resources/configs/accounts.yaml +21 -0
- package/resources/configs/profile.template.json +20 -0
- package/resources/configs/ranking-profiles.yaml +21 -0
- package/resources/configs/toutiao-profile.template.json +22 -0
- package/resources/configs/xiaohongshu-profile.template.json +27 -0
- package/resources/data/industry-taxonomy.yaml +326 -0
- package/skills/douyin-competitor-collect/SKILL.md +177 -0
- package/skills/douyin-competitor-collect/agents/openai.yaml +4 -0
- package/skills/douyin-competitor-collect/references/output-schema.md +178 -0
- package/skills/douyin-creator-image-text-publish/SKILL.md +44 -0
- package/skills/douyin-creator-image-text-publish/agents/openai.yaml +4 -0
- package/skills/douyin-creator-image-text-publish/references/LICENSE.social-auto-upload +21 -0
- package/skills/douyin-creator-image-text-publish/references/execution-contract.md +46 -0
- package/skills/douyin-creator-image-text-publish/references/upstream.md +30 -0
- package/skills/douyin-creator-index/SKILL.md +32 -0
- package/skills/douyin-creator-index/agents/openai.yaml +4 -0
- package/skills/douyin-creator-login/SKILL.md +58 -0
- package/skills/douyin-creator-login/agents/openai.yaml +4 -0
- package/skills/douyin-creator-publish/SKILL.md +56 -0
- package/skills/douyin-creator-publish/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-leads/SKILL.md +26 -0
- package/skills/douyin-enterprise-leads/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-leads-login/SKILL.md +36 -0
- package/skills/douyin-enterprise-leads-login/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-short-video-export/SKILL.md +29 -0
- package/skills/douyin-enterprise-short-video-export/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-video-rankings/SKILL.md +51 -0
- package/skills/douyin-enterprise-video-rankings/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-video-rankings/references/industry-taxonomy.md +29 -0
- package/skills/douyin-web-login/SKILL.md +102 -0
- package/skills/douyin-web-login/agents/openai.yaml +4 -0
- package/skills/toutiao-creator-article-draft/SKILL.md +154 -0
- package/skills/toutiao-creator-article-draft/agents/openai.yaml +4 -0
- package/skills/toutiao-web-login/SKILL.md +96 -0
- package/skills/toutiao-web-login/agents/openai.yaml +4 -0
- package/skills/xiaohongshu-creator-image-text-publish/SKILL.md +46 -0
- package/skills/xiaohongshu-creator-image-text-publish/agents/openai.yaml +4 -0
- package/skills/xiaohongshu-creator-image-text-publish/references/LICENSE.social-auto-upload +21 -0
- package/skills/xiaohongshu-creator-image-text-publish/references/execution-contract.md +46 -0
- package/skills/xiaohongshu-creator-image-text-publish/references/upstream.md +31 -0
- package/skills/xiaohongshu-creator-login/SKILL.md +106 -0
- package/skills/xiaohongshu-creator-login/agents/openai.yaml +4 -0
- package/skills/xiaohongshu-creator-publish/SKILL.md +153 -0
- package/skills/xiaohongshu-creator-publish/agents/openai.yaml +4 -0
- package/src/media_agent/__init__.py +1 -0
- package/src/media_agent/cli.py +28 -0
- package/src/media_agent/commands.sh +436 -0
- package/src/media_agent/platforms/__init__.py +1 -0
- package/src/media_agent/platforms/douyin/__init__.py +1 -0
- package/src/media_agent/platforms/douyin/check_login.py +196 -0
- package/src/media_agent/platforms/douyin/collect_industry_taxonomy.py +184 -0
- package/src/media_agent/platforms/douyin/collect_video_rankings.py +352 -0
- package/src/media_agent/platforms/douyin/douyin_full_login.py +391 -0
- package/src/media_agent/platforms/douyin/douyin_hotspot_v2.py +454 -0
- package/src/media_agent/platforms/douyin/douyin_publish.py +1135 -0
- package/src/media_agent/platforms/douyin/enterprise_login.py +128 -0
- package/src/media_agent/platforms/douyin/export_short_video.py +70 -0
- package/src/media_agent/platforms/douyin/login_controller.py +508 -0
- package/src/media_agent/platforms/douyin/validate_industry_taxonomy.py +152 -0
- package/src/media_agent/platforms/douyin/validate_rankings.py +254 -0
- package/src/media_agent/platforms/toutiao/__init__.py +1 -0
- package/src/media_agent/platforms/toutiao/toutiao_check_login.py +54 -0
- package/src/media_agent/platforms/toutiao/toutiao_login_controller.py +250 -0
- package/src/media_agent/platforms/toutiao/toutiao_login_evidence.py +50 -0
- package/src/media_agent/platforms/toutiao/toutiao_login_ipc.py +70 -0
- package/src/media_agent/platforms/xiaohongshu/__init__.py +1 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_check_login.py +189 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_controller.py +449 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_evidence.py +64 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_ipc.py +120 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_publish.py +925 -0
- package/src/media_agent/runtime/__init__.py +1 -0
- package/src/media_agent/runtime/account_manager.py +672 -0
- package/src/media_agent/runtime/browser.py +5 -0
- package/src/media_agent/runtime/paths.py +7 -0
- package/src/media_agent/script_map.json +23 -0
- package/src/node/config.mjs +48 -0
- package/src/node/integrity.mjs +34 -0
- package/src/node/skills.mjs +85 -0
- package/tools/archive_releases.py +83 -0
- package/tools/artifacts.py +56 -0
- package/tools/build_release.py +82 -0
- package/tools/check_catalog.py +23 -0
- package/tools/install_runtime.py +144 -0
- package/tools/run_tests.py +21 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 提取来源与适配差异
|
|
2
|
+
|
|
3
|
+
- 上游:[dreammis/social-auto-upload](https://github.com/dreammis/social-auto-upload)
|
|
4
|
+
- 固定提交:`0012d2c355f88f683cc38dde2a2db209e14091bc`,提取日期:2026-09-23。
|
|
5
|
+
- [上游 Skill](https://github.com/dreammis/social-auto-upload/blob/0012d2c355f88f683cc38dde2a2db209e14091bc/skills/xiaohongshu-upload/SKILL.md)
|
|
6
|
+
- [上游 CLI 契约](https://github.com/dreammis/social-auto-upload/blob/0012d2c355f88f683cc38dde2a2db209e14091bc/skills/xiaohongshu-upload/references/cli-contract.md)
|
|
7
|
+
- [上游代码](https://github.com/dreammis/social-auto-upload/blob/0012d2c355f88f683cc38dde2a2db209e14091bc/uploader/xiaohongshu_uploader/main.py):`XiaoHongShuNote.validate_upload_args`、`upload_note_content`、`XiaoHongShuBaseUploader.fill_meta`。
|
|
8
|
+
- 来源材料采用 MIT;版权与许可全文随 Skill 保存在 [LICENSE.social-auto-upload](LICENSE.social-auto-upload)。本地内容是图文流程的适配文档,不是原版 Skill 或完整上游运行时。
|
|
9
|
+
|
|
10
|
+
## 提取的页面线索
|
|
11
|
+
|
|
12
|
+
| 步骤 | 固定版本中的线索 | 本项目采用条件 |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| 入口 | `/publish/publish?from=homepage&target=image` | 当前可见入口及图片标签确认,旧 URL 失效时不盲猜 |
|
|
15
|
+
| 上传 | `input[type="file"][accept*="image"]` | 在图文面板内唯一匹配 |
|
|
16
|
+
| 上游备用 input | `div[class^='upload-content'] input[class='upload-input']` | 只作定位线索,不误选视频 input |
|
|
17
|
+
| 标题 | `input[placeholder*="填写标题"]` | 标题框可见不等于图片全部上传 |
|
|
18
|
+
| 正文 | `p[data-placeholder*="输入正文描述"]` | 核验该节点所属的真实 contenteditable 编辑器 |
|
|
19
|
+
| 话题 | `#creator-editor-topic-container .item` | 选择准确匹配项,不默认选择第一项 |
|
|
20
|
+
| 发布 | `button:has-text("发布")` | 改为唯一精确匹配,避开“定时发布”等按钮 |
|
|
21
|
+
| 结果 | 成功页 URL | 同时核验成功文字,再到“笔记管理 → 全部”核验 |
|
|
22
|
+
|
|
23
|
+
上游代码将标题截取为 20 字符,话题最多取前 10 个;这些是实现行为,不是可直接套用的页面规则。本项目从当前页面获取限制,超限返回错误,不截断用户成稿或丢弃话题。图片上限与格式也以当前页面为准,不把抖音的 35 张限制套到小红书。
|
|
24
|
+
|
|
25
|
+
## 适配范围
|
|
26
|
+
|
|
27
|
+
保留用户输入 `images + title + note + tags` 的图文流程,将 `note` 映射为本项目 `body`。用户正文和本地图片原样使用。
|
|
28
|
+
|
|
29
|
+
上游 CLI 同时支持 `--headless` / `--headed`;这里不直接调用 CLI。上游 `upload()` 会 launch 浏览器、new_context 并载入 `storage_state`;本 Skill 改为操作本项目现有可见持久化会话。
|
|
30
|
+
|
|
31
|
+
不提取上游 Cookie 登录/导出、位置权限、默认转载声明、定时、标题回退生成、文字截断、话题静默跳过和发布循环。上游图文提交在 `while True` 中点击发布并等待 URL,超时可能再次点击;本项目以先记录提交意图、单次点击和列表核验替换。选择器只用于辅助 Agent 识别当前页面,不是线上已验收的保证。
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: xiaohongshu-creator-login
|
|
3
|
+
description: 登录小红书创作服务平台并固化浏览器会话。用于访问 creator.xiaohongshu.com、切换到二维码登录、等待用户用小红书 App 扫码确认、判断是否进入创作服务平台首页,以及通过同一持久化 Profile 重启验证免扫码登录;也用于检查已有小红书 Creator Profile 是否仍处于登录状态。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 小红书创作服务平台登录
|
|
7
|
+
|
|
8
|
+
仅处理登录、登录状态检查和会话持久化验证。不要在此流程中发布、编辑或删除笔记。
|
|
9
|
+
|
|
10
|
+
## 前置约束
|
|
11
|
+
|
|
12
|
+
- 使用支持持久化用户数据目录的可见浏览器;不要使用无痕或临时 context。
|
|
13
|
+
- 为每个小红书账号分配独立 `profile_id`、`browser_data`、固定指纹和 lock。禁止跨账号复制或共用状态。
|
|
14
|
+
- 复用已存在的 Profile 时,保持 locale、timezone、viewport、指纹 seed 和启动参数不变。
|
|
15
|
+
- 先获取 Profile lock。若 owner 进程仍存活,返回 `PROFILE_LOCKED`,不要启动第二个浏览器。
|
|
16
|
+
- 保持扫码页面和浏览器控制器存活,直到用户扫码、平台完成跳转或用户取消。
|
|
17
|
+
- 不读取、不导出、不回显 Cookie、token、Local Storage 值或二维码原始内容。
|
|
18
|
+
|
|
19
|
+
## 状态机
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
INIT
|
|
23
|
+
→ CHECKING_SESSION
|
|
24
|
+
→ LOGGED_IN
|
|
25
|
+
或
|
|
26
|
+
→ WAIT_QR_MODE
|
|
27
|
+
→ WAIT_QR_SCAN
|
|
28
|
+
→ VERIFYING_LOGIN
|
|
29
|
+
→ LOGGED_IN
|
|
30
|
+
→ SAVING_PROFILE
|
|
31
|
+
→ VERIFYING_PERSISTENCE
|
|
32
|
+
→ COMPLETE
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 运行命令
|
|
36
|
+
|
|
37
|
+
从 `~/.media-agent/social-accounts` 执行,并以安装机器上的
|
|
38
|
+
`media-agent --help` 为准:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
media-agent xhs-login-start <profile_id>
|
|
42
|
+
media-agent xhs-login-status <profile_id>
|
|
43
|
+
media-agent xhs-login-scan-done <profile_id>
|
|
44
|
+
media-agent xhs-login-refresh-qr <profile_id>
|
|
45
|
+
media-agent xhs-login-close <profile_id>
|
|
46
|
+
media-agent xhs-check-login <profile_id>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`xhs-login-scan-done` 通过带 `request_id` 的现有 Unix Socket 等待原
|
|
50
|
+
controller 返回,禁止用旧响应文件代替当前扫码结果。
|
|
51
|
+
|
|
52
|
+
二维码失效时在原页面刷新二维码并回到 `WAIT_QR_SCAN`。证据冲突时进入 `INDETERMINATE` 并继续短轮询,不要重启浏览器。
|
|
53
|
+
|
|
54
|
+
## 执行登录
|
|
55
|
+
|
|
56
|
+
1. 使用目标账号的持久化 Profile 打开 `https://creator.xiaohongshu.com/`。
|
|
57
|
+
2. 等待页面稳定;若已出现创作服务平台后台,直接进入登录成功判断。
|
|
58
|
+
3. 若跳转至 `/login` 且登录卡片标题为“短信登录”,定位卡片右上角折角中的二维码图标并点击一次。
|
|
59
|
+
4. 确认卡片切换为“APP扫一扫登录”,页面出现二维码和“可用小红书扫码”提示。不要把短信登录输入框误当作扫码入口。
|
|
60
|
+
5. 将可见二维码呈现给用户,返回 `WAIT_QR_SCAN`,明确要求用户使用小红书 App 扫码并在手机端确认。
|
|
61
|
+
6. 用户确认后,在原 page 上按 2 秒间隔轮询,通常约 10 秒会自动跳转;最多等待 60 秒。不要仅使用固定 `sleep(10)` 作为成功判断。
|
|
62
|
+
7. 若二维码过期,只操作原二维码区域的“刷新/重新获取”控件;不要新建页面、清空 Profile、整页重开或创建第二个 controller。
|
|
63
|
+
|
|
64
|
+
## 判断登录成功
|
|
65
|
+
|
|
66
|
+
综合使用以下证据,禁止只凭单一 Cookie 或一次 URL 读数:
|
|
67
|
+
|
|
68
|
+
- URL 进入 `https://creator.xiaohongshu.com/new/home` 或同域的已认证后台路由。
|
|
69
|
+
- 页面标题或页头出现“创作服务平台”。
|
|
70
|
+
- 左侧出现“首页”“笔记管理”“数据看板”等后台导航。
|
|
71
|
+
- 页面出现账号头像或账号名称。
|
|
72
|
+
- “短信登录”“APP扫一扫登录”和二维码均不可见。
|
|
73
|
+
|
|
74
|
+
满足后台路由且至少一项后台 DOM 证据,或满足至少三项后台 DOM 证据且登录表单消失时,判定 `LOGGED_IN`。后台与登录表单同时存在时返回 `INDETERMINATE`,继续轮询 2–5 秒;不要误报成功。
|
|
75
|
+
|
|
76
|
+
## 固化并验证登录状态
|
|
77
|
+
|
|
78
|
+
1. 确认 `LOGGED_IN` 后停止扫码、刷新和重复点击。
|
|
79
|
+
2. 记录非敏感结果:`profile_id`、当前后台 URL、账号显示名(如可见)、登录时间和证据摘要。不要记录身份凭据。
|
|
80
|
+
3. 通过浏览器框架正常关闭 page/context/browser,使 Cookie、IndexedDB 和 Local Storage 写入该 Profile 的 `browser_data`。
|
|
81
|
+
4. 等待至少 10 秒,并确认原浏览器进程已退出后释放 lock。禁止使用 `kill`、`pkill` 或批量结束浏览器。
|
|
82
|
+
5. 使用完全相同的 Profile、`browser_data`、指纹和启动参数重新打开 `https://creator.xiaohongshu.com/`。
|
|
83
|
+
6. 最多等待 60 秒,再次执行登录成功判断。无需扫码进入后台时设置 `persistence_verified=true`。
|
|
84
|
+
7. 若重新出现 `/login` 或二维码,设置 `persistence_verified=false` 和 `LOGIN_REQUIRED`;保留 Profile 供排查,不要删除或覆盖。
|
|
85
|
+
8. 验证结束后再次正常关闭并释放 lock。
|
|
86
|
+
|
|
87
|
+
## 返回结果
|
|
88
|
+
|
|
89
|
+
至少返回:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
profile_id=<非敏感 Profile 标识>
|
|
93
|
+
login_status=logged_in|login_required|indeterminate
|
|
94
|
+
current_url=<不含敏感查询参数的 URL>
|
|
95
|
+
account_name=<页面可见名称或 unknown>
|
|
96
|
+
persistence_verified=true|false|not_run
|
|
97
|
+
relogin_qr_required=true|false|unknown
|
|
98
|
+
browser_process_remaining=<数量或 unknown>
|
|
99
|
+
lock_remaining=true|false|unknown
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
只有完成“正常关闭 → 等待至少 10 秒 → 同 Profile 重开 → 后台证据复核”,才能报告登录状态已固化。若尚未由用户完成扫码,停在 `WAIT_QR_SCAN`,不要声称登录完成。
|
|
103
|
+
|
|
104
|
+
## 项目兼容边界
|
|
105
|
+
|
|
106
|
+
`media-agent-capabilities-v1.0.4` 提供独立的账号中立小红书控制器、状态检查器、证据分类器和 IPC 客户端。不要把抖音的 `login-start` 或 `check-login` 当作小红书实现;必须使用上述 `xhs-*` 命令。既有 v1.0.1、v1.0.2 和 v1.0.3 归档保持不可变。
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: xiaohongshu-creator-publish
|
|
3
|
+
description: 在小红书创作服务平台上传、填写标题、发布并核验视频笔记。用于 creator.xiaohongshu.com 的“发布视频笔记”任务,包括先关闭进入上传页时自动弹出的原生文件选择器及权限弹窗、选择本地 MP4/MOV 视频、等待上传和平台处理、根据视频内容生成真实简洁的标题、单次点击发布、识别发布成功页、等待约 10 秒,并在“笔记管理 → 全部”核验作品状态;也用于发布后只读查询。不要用于登录、图文笔记发布、删除作品或编辑既有作品。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 小红书创作服务平台视频发布
|
|
7
|
+
|
|
8
|
+
只处理单个视频笔记的上传、发布和落地核验。登录或会话失效时,改用 `xiaohongshu-creator-login`,不要在发布流程中临时扫码。
|
|
9
|
+
|
|
10
|
+
## 执行边界
|
|
11
|
+
|
|
12
|
+
- 使用目标账号原有的可见持久化 Profile、固定指纹和唯一 lock;不要新建临时 context、复制 Profile 或并发控制同一账号。
|
|
13
|
+
- 先核对目标账号和视频绝对路径。素材必须是稳定的普通文件;不存在、仍在写入或格式不受支持时停止。
|
|
14
|
+
- 将“发布这个视频”等明确指令视为本次任务的发布授权。只有“上传看看”“准备草稿”“检查页面”等指令时,仅准备并回报,不点击“发布”。
|
|
15
|
+
- 最终“发布”最多点击一次。提交结果不确定时禁止重发,也不要更换标题后再次提交。
|
|
16
|
+
- 默认不改封面、原创声明、内容类型、地点、群聊、引用、路线、活动、合集、公开范围和定时发布。只有用户明确指定时才更改。
|
|
17
|
+
- 不读取、导出或回显 Cookie、token、Local Storage、Profile 内容或其他登录凭据。
|
|
18
|
+
|
|
19
|
+
## CLI 命令(v1.0.10 起)
|
|
20
|
+
|
|
21
|
+
发布流程由 `media-agent` 的五个 `xhs-publish-*` 命令驱动(脚本 `src/media_agent/platforms/xiaohongshu/xiaohongshu_publish.py`),对齐抖音发布五阶段模式:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
media-agent xhs-publish-dry-run <profile_id> --media-path <path> # 素材校验 + SHA-256 账本去重,不开浏览器
|
|
25
|
+
media-agent xhs-publish-prepare <profile_id> --media-path <path> --title <标题> # 上传、填标题并读回、写账本、保持浏览器
|
|
26
|
+
media-agent xhs-publish-confirm <profile_id> # 单次真实点击“发布”
|
|
27
|
+
media-agent xhs-publish-status <profile_id> [--task-id <id>] # 查询发布/审核状态
|
|
28
|
+
media-agent xhs-publish-close <profile_id> # 正常关闭浏览器并释放 lock
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
约束:
|
|
32
|
+
|
|
33
|
+
- capability 门禁 `creator_publish`;退出码 2=LOGIN_REQUIRED、3=PROFILE_LOCKED、4=NO_CAPABILITY、8=DUPLICATE_BLOCKED。
|
|
34
|
+
- 标题由 Agent 根据实际视频画面生成后通过 `--title` 传入,CLI 只负责填写与页面读回校验。
|
|
35
|
+
- CLI 路径直接进入视频发布页并对 file input 设置路径,不触发也不操作原生文件选择器;Agent 驱动路径的原生选择器/截图门禁仍适用于非 CLI 执行方式。
|
|
36
|
+
- 成功页只能进入 `SUBMITTED`/`VERIFYING_NOTE`;只有“笔记管理 → 全部”核验才能给出 `PUBLISHED`/`REJECTED`/`REVIEWING`;轮询 5 分钟仍未找到时返回 `PUBLISH_INDETERMINATE` 并禁止重发。
|
|
37
|
+
- 浏览器自动化部分为 IMPLEMENTED_UNVERIFIED(v1.0.10 首次入包,实现依据本 Skill 与交接文档的实测流程,尚未经真实账号 Level 2 在线实测固化);账本去重、素材校验、门禁和退出码已经离线契约测试验证。在线实测通过前沿用本 Skill 的 Agent 驱动流程作为权威。
|
|
38
|
+
|
|
39
|
+
## 状态机
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
INIT → CHECK_LOGIN → SELECT_VIDEO → UPLOADING → READY_TO_PUBLISH
|
|
43
|
+
→ SUBMITTING → SUCCESS_PAGE → VERIFYING_NOTE
|
|
44
|
+
→ SUBMITTED | REVIEWING | PUBLISHED | REJECTED | PUBLISH_INDETERMINATE
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 进入视频发布页
|
|
48
|
+
|
|
49
|
+
1. 打开 `https://creator.xiaohongshu.com/`,等待后台稳定并确认“创作服务平台”及账号信息可见。
|
|
50
|
+
2. 若出现登录表单、二维码或无法确认账号,返回 `LOGIN_REQUIRED` 并停止。
|
|
51
|
+
3. 点击“发布笔记”的下拉入口并选择“发布视频笔记”,或点击首页的“发布视频笔记”卡片。
|
|
52
|
+
4. 确认进入视频上传页:顶部选中“上传视频”,页面存在“上传视频”控件。
|
|
53
|
+
5. 入口会立即打开 macOS 原生文件选择器。必须先真实点击右下角“取消”,或让该窗口获得焦点后按一次 `Escape`;不要直接在这个自动弹出的选择器里挑选素材。
|
|
54
|
+
|
|
55
|
+
优先按可见文本、role、label 和 DOM 关系定位,禁止依赖截图绝对坐标。
|
|
56
|
+
|
|
57
|
+
## 关闭默认文件选择器和弹窗
|
|
58
|
+
|
|
59
|
+
1. 关闭自动弹出的文件选择器后,获取一张新的完整桌面截图,确认整个原生窗口确实消失。自动化调用返回成功不能代替视觉证据。
|
|
60
|
+
2. 文件选择器仍存在时继续处理它,不得上传、返回 `WAIT_PUBLISH_CONFIRM`、点击发布或声称窗口已关闭。
|
|
61
|
+
3. 位置权限弹窗选择“一律不允许”。“要恢复页面吗?”提示点击右上角 `×`,不得点击“恢复”。
|
|
62
|
+
4. 确认文件选择器、位置权限和恢复页面提示均不可见后,才开始设置目标视频文件。
|
|
63
|
+
5. 弹窗处理期间保持当前 browser、controller、page、持久化 Profile 和 lock;禁止 `kill`、关闭、重启或创建第二个浏览器。
|
|
64
|
+
|
|
65
|
+
## 选择并上传视频
|
|
66
|
+
|
|
67
|
+
1. 关闭默认文件选择器后,优先使用浏览器自动化框架的 file input 能力(例如 `input[type="file"]` 的 `set_input_files`)将已核对的绝对路径直接赋给上传控件,不要再次打开原生文件选择器。
|
|
68
|
+
2. 若必须操作原生文件选择器,只选择该绝对路径对应的单个文件;不要选择整个文件夹或最近使用项。
|
|
69
|
+
3. 处理位置权限等非必要弹窗时选择“不允许”或关闭;不要授予发布任务不需要的权限。
|
|
70
|
+
4. 上传开始后记录页面显示的文件名,并观察进度、剩余时间和错误提示。不要用固定睡眠代替状态判断。
|
|
71
|
+
5. 等待进度达到 100%,且页面不再显示“上传中/视频上传中”。同时确认至少一项处理完成证据:视频预览可播放、智能推荐封面出现、发布按钮启用或页面明确显示上传完成。
|
|
72
|
+
6. 上传失败时保留现场并报告页面错误。除非页面明确表示从未接收文件且用户仍授权发布,否则不要自动重新选择或重传。
|
|
73
|
+
|
|
74
|
+
## 生成并填写标题
|
|
75
|
+
|
|
76
|
+
1. 根据视频预览、画面、文件名和用户提供的上下文生成标题;不得编造画面中无法确认的人物、地点、品牌、事件或体验。
|
|
77
|
+
2. 标题使用自然中文,准确描述核心画面,优先 8–20 个汉字;不要使用标题党、虚假承诺、重复 emoji 或无关热门词。
|
|
78
|
+
3. 没有足够语义时使用保守的可见事实标题,例如“窗外的云海”或“今天看到的晚霞”,不要猜测具体航线或城市。
|
|
79
|
+
4. 将标题填入“填写标题会有更多赞哦”对应输入框。正文不是必填项时保持为空,除非用户提供或明确要求生成正文。
|
|
80
|
+
5. 从页面读回标题,确认非空且无截断、重复粘贴或输入法残留。
|
|
81
|
+
|
|
82
|
+
## 发布门禁与单次提交
|
|
83
|
+
|
|
84
|
+
点击前同时确认:
|
|
85
|
+
|
|
86
|
+
- 当前账号与目标账号一致;
|
|
87
|
+
- 页面显示的文件名与目标素材一致;
|
|
88
|
+
- 上传和平台处理已完成;
|
|
89
|
+
- 标题读回正确;
|
|
90
|
+
- 底部红色“发布”按钮唯一、可见且启用;
|
|
91
|
+
- 当前任务具有明确发布授权。
|
|
92
|
+
|
|
93
|
+
满足门禁后使用真实 locator/pointer click 点击一次“发布”,立即进入 `SUBMITTING`。点击后:
|
|
94
|
+
|
|
95
|
+
- 禁止再次点击、刷新、后退或主动打开第二个发布页;
|
|
96
|
+
- 等待同一页面跳转,最长 180 秒;
|
|
97
|
+
- 若出现错误提示,记录原文并进入 `INDETERMINATE` 或 `REJECTED`,不要自动重发。
|
|
98
|
+
|
|
99
|
+
## 识别发布成功
|
|
100
|
+
|
|
101
|
+
以下组合才构成平台接收证据:
|
|
102
|
+
|
|
103
|
+
- URL 进入同域 `/publish/success`,且页面可见“发布成功”;或
|
|
104
|
+
- 页面明确显示“发布成功”及“数秒后将返回发布页/立即返回”。
|
|
105
|
+
|
|
106
|
+
“按钮消失”“页面空白”“URL 变化”或本地点击成功都不能单独证明发布成功。成功页通常约 2 秒后自动回到视频上传页;不要因此把返回后的空上传页误判为提交失败。
|
|
107
|
+
|
|
108
|
+
看到发布成功证据后只进入 `SUBMITTED` / `VERIFYING_NOTE`,禁止立即返回 `PUBLISHED`。保持浏览器和 lock,等待约 10 秒让作品列表同步;等待期间禁止重复点击发布、刷新成功页、后退或关闭浏览器。随后必须执行笔记管理核验。
|
|
109
|
+
|
|
110
|
+
## 在笔记管理中核验
|
|
111
|
+
|
|
112
|
+
1. 取得成功证据并等待约 10 秒后,点击左侧“笔记管理”,进入 `/new/note-manager`,明确打开“全部”栏目。
|
|
113
|
+
2. 在“全部”中查找刚发布的作品。优先匹配完整标题,再结合发布时间、视频时长、缩略图和本次提交时间消除同名歧义。
|
|
114
|
+
3. 目标卡片出现即证明作品已落地。读取卡片附近的状态:
|
|
115
|
+
- 显示“审核中”:返回 `REVIEWING`;
|
|
116
|
+
- 状态标签消失且作品出现在“已发布”,或页面明确显示已发布:返回 `PUBLISHED`;
|
|
117
|
+
- 显示“未通过”或明确违规/拒绝原因:返回 `REJECTED`。
|
|
118
|
+
4. 正常情况下审核可能在 1–2 分钟内完成。按 15–20 秒间隔刷新或重新读取列表,最多等待 5 分钟;一旦 `PUBLISHED` 或 `REJECTED` 即停止。
|
|
119
|
+
5. 超过 5 分钟仍为“审核中”时,保留 `REVIEWING`,说明审核尚未结束;这不是发布失败。成功页出现但列表暂未找到时,同样最多轮询 5 分钟,然后返回 `PUBLISH_INDETERMINATE`,禁止重发。
|
|
120
|
+
6. 只有在“笔记管理 → 全部”找到目标卡片后才能报告 `note_found=true`;只有页面真实状态为“已发布”才能返回 `PUBLISHED`。
|
|
121
|
+
|
|
122
|
+
## Computer Use 临时失败
|
|
123
|
+
|
|
124
|
+
1. `computer_use` 单次提示会话失效时,保持当前发布现场,暂停数秒后直接重试同一操作。
|
|
125
|
+
2. 禁止因一次失败关闭浏览器、`kill` controller、释放 lock,或建议不存在的 `hermes computer-use restart`。
|
|
126
|
+
3. 连续重试仍失败时返回 `CUA_SESSION_FAILED` 并保留现场;发布任务进行中不得升级或重装 CuaDriver。
|
|
127
|
+
|
|
128
|
+
## 返回结果
|
|
129
|
+
|
|
130
|
+
至少返回:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
state=prepared|submitted|reviewing|published|rejected|publish_indeterminate
|
|
134
|
+
task_id=<稳定任务标识>
|
|
135
|
+
profile_id=<非敏感 Profile 标识>
|
|
136
|
+
account_name=<页面可见名称或 unknown>
|
|
137
|
+
media_path=<目标素材路径或经用户允许的简化名称>
|
|
138
|
+
media_filename=<页面读回文件名>
|
|
139
|
+
title=<页面读回标题>
|
|
140
|
+
submit_clicked=true|false
|
|
141
|
+
success_page_seen=true|false
|
|
142
|
+
note_found=true|false
|
|
143
|
+
section=笔记管理/全部|not_run
|
|
144
|
+
note_status=prepared|submitted|reviewing|published|rejected|publish_indeterminate
|
|
145
|
+
status_evidence=<可见文本、时间、时长等非敏感摘要>
|
|
146
|
+
current_url=<移除敏感查询参数后的 URL>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
只有看到成功页且在笔记管理中找到目标卡片,才能报告“作品已提交并落地”。只有状态为 `PUBLISHED`,才能报告“审核通过、作品发布完毕”。若最终仍为 `REVIEWING`,应准确说明“已提交,仍在审核中”。
|
|
150
|
+
|
|
151
|
+
## 收尾
|
|
152
|
+
|
|
153
|
+
成功、拒绝或只读查询结束后正常关闭 page/context/browser 并释放 lock,让 Profile 正常写盘。`PUBLISH_INDETERMINATE` 默认保留现场供人工检查。禁止使用 `kill`、`pkill`、清空 `browser_data`、删除作品或自动重复提交。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Media Agent capabilities."""
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Python execution entry point; internal execution bridge for the media-agent command."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import runpy
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(argv=None):
|
|
11
|
+
args = list(sys.argv[1:] if argv is None else argv)
|
|
12
|
+
package = Path(__file__).resolve().parent
|
|
13
|
+
if args and args[0] == 'run-script':
|
|
14
|
+
mapping = json.loads((package / 'script_map.json').read_text())
|
|
15
|
+
name = args[1].removesuffix('.py') if len(args) > 1 else ''
|
|
16
|
+
if name not in mapping:
|
|
17
|
+
print('ERROR: unknown script', name, file=sys.stderr)
|
|
18
|
+
return 2
|
|
19
|
+
sys.argv = [name + '.py', *args[2:]]
|
|
20
|
+
runpy.run_module(mapping[name], run_name='__main__')
|
|
21
|
+
return 0
|
|
22
|
+
env = dict(os.environ, MEDIA_AGENT_PYTHON=sys.executable)
|
|
23
|
+
env['PYTHONPATH'] = str(package.parent) + os.pathsep + env.get('PYTHONPATH', '')
|
|
24
|
+
return subprocess.call(['bash', str(package / 'commands.sh'), *args], env=env)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == '__main__':
|
|
28
|
+
raise SystemExit(main())
|