chore: karuo-party 分平台 SKILL + 多平台分发更新;db handler 调整
Made-with: Cursor
This commit is contained in:
@@ -7,8 +7,8 @@ description: >
|
||||
triggers: 运营报表、视频切片、多平台分发、飞书视频下载、派对运营、卡若创业派对、派对填表、视频剪辑、一键分发、妙记下载
|
||||
owner: 水岸
|
||||
group: 运营
|
||||
version: "1.2"
|
||||
updated: "2026-03-23"
|
||||
version: "1.3"
|
||||
updated: "2026-03-24"
|
||||
---
|
||||
|
||||
# 卡若创业派对运营 Skill 包
|
||||
@@ -29,7 +29,7 @@ updated: "2026-03-23"
|
||||
|
||||
## 一、技能包组成
|
||||
|
||||
本技能包包含以下 4 个核心子技能:
|
||||
本技能包包含以下 8 个核心子技能:
|
||||
|
||||
| # | 技能名 | 文件路径 | 触发词 | 用途 |
|
||||
|:--|:---|:---|:---|:---|
|
||||
@@ -37,6 +37,10 @@ updated: "2026-03-23"
|
||||
| ② | 飞书视频文字下载 | `skills/飞书视频文字下载_SKILL.md` | 妙记下载、飞书视频、飞书妙记 | 文字+视频→本地 |
|
||||
| ③ | 视频切片 | `skills/视频切片_SKILL.md` | 视频剪辑、切片发布 | 原视频→转录→高光→成片 |
|
||||
| ④ | 多平台分发 | `skills/多平台分发_SKILL.md` | 一键分发、全平台发布 | 成片→抖音/B站/视频号/小红书/快手 |
|
||||
| ⑤ | 视频号发布 | `skills/平台_视频号_SKILL.md` | 视频号发布、视频号重传 | 账号校验→清理→定时发布 |
|
||||
| ⑥ | B站发布 | `skills/平台_B站_SKILL.md` | B站发布、B站补发 | API优先→兜底→定时 |
|
||||
| ⑦ | 小红书发布 | `skills/平台_小红书_SKILL.md` | 小红书发布、小红书补发 | UI自动化定时发布 |
|
||||
| ⑧ | 抖音发布 | `skills/平台_抖音_SKILL.md` | 抖音发布、抖音补发 | API定时发布+失败重登 |
|
||||
|
||||
---
|
||||
|
||||
@@ -131,6 +135,13 @@ python3 "$DIST_SCRIPT/distribute_all.py" --now
|
||||
2. **线上失败/重复清理**:先查 `post_list`,删除失败条目;同标题仅保留最新一条(去重后再补发)。
|
||||
3. **仅定时发布**:禁止立即发布;若页面定时控件失效,使用 `post_create` 注入定时参数并拦截立即发布。
|
||||
|
||||
#### 分发统一总规则(强制)
|
||||
|
||||
1. **间隔规则**:按“每一条相邻发布时间”计算,必须在 **10 分钟到 120 分钟** 之间。
|
||||
2. **账号状态规则**:发布前做账号可用性检查;若出现封禁/登录失效/鉴权失败,先执行重登,再重试失败条。
|
||||
3. **平台分治规则**:先按平台触发对应子 Skill,再执行发布命令,不混用平台规则。
|
||||
4. **收敛规则**:每轮结束输出成功/失败清单 + 重登命令;失败条必须可继续重试直到收敛。
|
||||
|
||||
---
|
||||
|
||||
## 四、完整流程(派对结束后)
|
||||
@@ -287,6 +298,7 @@ curl -sS -X POST -H "Content-Type: application/json" -d "$TEXT" "$FEISHU_PARTY_C
|
||||
|
||||
| 版本 | 日期 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| 1.3 | 2026-03-24 | 升级为“总规则+平台子Skill”;统一相邻间隔 10~120 分钟;新增账号封禁/重登/重试收敛规则 |
|
||||
| 1.2 | 2026-03-23 | 新增视频号发布前置三步:头像昵称校验、失败/重复清理、强制定时发布(含请求注入兜底) |
|
||||
| 1.1 | 2026-03-21 | 新增 §九 闭环复盘发群:卡若五块复盘 + 飞书 Webhook v2(msg_type 必填) |
|
||||
| 1.0 | 2026-03-20 | 初版:整合运营报表、视频切片、多平台分发、飞书视频文字下载 4 大技能,统一凭证管理 |
|
||||
|
||||
@@ -7,14 +7,14 @@ description: >
|
||||
triggers: 多平台分发、一键分发、全平台发布、批量分发、视频分发
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "4.4"
|
||||
updated: "2026-03-23"
|
||||
version: "4.5"
|
||||
updated: "2026-03-24"
|
||||
---
|
||||
|
||||
# 多平台分发 Skill(v4.4)
|
||||
# 多平台分发 Skill(v4.5)
|
||||
|
||||
> **核心原则**:API 发布为主,Playwright 为辅。确保确定性地分发到各平台。
|
||||
> **v4.4**:视频号新增发前强制检查(头像昵称校验、失败清理、同标题去重)与“仅定时发布(请求注入兜底)”。**v4.3**:默认静默登录。
|
||||
> **v4.5**:统一改为“按相邻条目”间隔控制,默认区间 **10~120 分钟**;并要求按平台子 Skill 执行对应规则后再发布。
|
||||
|
||||
## 〇、执行原则(第一性原理)
|
||||
|
||||
@@ -51,10 +51,10 @@ cd /Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容
|
||||
# 默认智能错峰排期
|
||||
python3 distribute_all.py
|
||||
|
||||
# 旧版随机间隔
|
||||
python3 distribute_all.py --legacy-schedule
|
||||
# 规则间隔(推荐,按相邻条目 10~120 分钟)
|
||||
python3 distribute_all.py --legacy-schedule --min-gap 10 --max-gap 120
|
||||
|
||||
# 立即全部发布
|
||||
# 立即全部发布(仅在明确要求时)
|
||||
python3 distribute_all.py --now
|
||||
|
||||
# 只发指定平台
|
||||
@@ -71,6 +71,10 @@ python3 distribute_all.py --retry
|
||||
python3 distribute_all.py --platforms 视频号 --auto-channels-login --video-dir "/path/to/成片"
|
||||
# 独立 channels_api_publish 允许自动登录:CHANNELS_AUTO_LOGIN=1
|
||||
# 强制永不自动登录:NO_AUTO_CHANNELS_LOGIN=1
|
||||
|
||||
# 平台站点上传 CLI(平台级,含账号检测+自动重登+重试)
|
||||
python3 site_upload_cli.py check --platforms 抖音 B站 小红书 快手
|
||||
python3 site_upload_cli.py publish --platforms 抖音 B站 小红书 --video-dir "/path/to/成片" --min-gap 10 --max-gap 120 --until-success
|
||||
```
|
||||
|
||||
---
|
||||
@@ -79,7 +83,7 @@ python3 distribute_all.py --platforms 视频号 --auto-channels-login --video-di
|
||||
|
||||
### 3.1 默认(`generate_smart_schedule`)
|
||||
- 第 1 条立即;间隔与总跨度随条数自适应;本地 0–7 点尽量挪到午间(`SCHEDULE_NO_NIGHT_REFINE=1` 关闭)
|
||||
- `--legacy-schedule` + `--min-gap` / `--max-gap` / `--max-hours` 为旧逻辑
|
||||
- `--legacy-schedule` + `--min-gap` / `--max-gap` / `--max-hours` 为固定区间逻辑(建议 `10~120`)
|
||||
- 去重时排期与目录列表下标对齐
|
||||
|
||||
### 3.2 独立 `channels_api_publish.py`:同上智能排期转 Unix
|
||||
@@ -159,6 +163,26 @@ meta.hashtags("视频号") # … + #小程序卡若创业派对 #公众号卡
|
||||
|
||||
---
|
||||
|
||||
## 六点六、账号异常自动处理(强制)
|
||||
|
||||
1. 发布前先执行 `--check`;若平台 Cookie 无效,先走对应登录脚本。
|
||||
2. 发布中若出现封禁/风控/鉴权失败,立即输出处理建议与重登命令。
|
||||
3. 重登完成后优先执行 `--retry`,只重试失败条,不重复成功条。
|
||||
4. 失败超过 2 轮仍未收敛时,输出平台级阻塞原因并停止盲目重试。
|
||||
|
||||
---
|
||||
|
||||
## 六点七、平台子Skill分流(强制)
|
||||
|
||||
- 视频号:按 `平台_视频号_SKILL.md` 执行。
|
||||
- B站:按 `平台_B站_SKILL.md` 执行。
|
||||
- 小红书:按 `平台_小红书_SKILL.md` 执行。
|
||||
- 抖音:按 `平台_抖音_SKILL.md` 执行。
|
||||
|
||||
多平台联发时,先加载各平台子Skill,再统一调度 `distribute_all.py`。
|
||||
|
||||
---
|
||||
|
||||
## 七、去重机制
|
||||
|
||||
- 日志:`publish_log.json`(JSON Lines)
|
||||
|
||||
34
.cursor/skills/karuo-party/skills/平台_B站_SKILL.md
Normal file
34
.cursor/skills/karuo-party/skills/平台_B站_SKILL.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: 平台_B站发布
|
||||
description: B站发布专用规则。API优先,失败降级 Playwright,按相邻间隔 10~120 分钟定时发布。
|
||||
triggers: B站发布、B站补发、B站重试
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "1.0"
|
||||
updated: "2026-03-24"
|
||||
---
|
||||
|
||||
# 平台子Skill:B站发布
|
||||
|
||||
## 一、强制规则
|
||||
|
||||
1. 默认 API 投稿,失败才降级 Playwright。
|
||||
2. 发布间隔按相邻条目控制在 `10~120` 分钟。
|
||||
3. 出现 406/超时等异常时先重试失败条,不重复成功条。
|
||||
|
||||
## 二、标准命令
|
||||
|
||||
```bash
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/多平台分发/脚本/distribute_all.py" \
|
||||
--platforms B站 \
|
||||
--video-dir "<成片目录>" \
|
||||
--legacy-schedule --min-gap 10 --max-gap 120
|
||||
```
|
||||
|
||||
## 三、登录异常处理
|
||||
|
||||
```bash
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/B站发布/脚本/bilibili_login.py"
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/多平台分发/脚本/distribute_all.py" --retry
|
||||
```
|
||||
|
||||
34
.cursor/skills/karuo-party/skills/平台_小红书_SKILL.md
Normal file
34
.cursor/skills/karuo-party/skills/平台_小红书_SKILL.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: 平台_小红书发布
|
||||
description: 小红书发布专用规则。UI自动化定时发布,按相邻间隔 10~120 分钟执行。
|
||||
triggers: 小红书发布、小红书补发
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "1.0"
|
||||
updated: "2026-03-24"
|
||||
---
|
||||
|
||||
# 平台子Skill:小红书发布
|
||||
|
||||
## 一、强制规则
|
||||
|
||||
1. 逐条定时发布,禁止批量立即发布。
|
||||
2. 相邻发布时间间隔必须在 `10~120` 分钟。
|
||||
3. 若仅返回 likely_published,需在下一轮巡检确认状态。
|
||||
|
||||
## 二、标准命令
|
||||
|
||||
```bash
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/多平台分发/脚本/distribute_all.py" \
|
||||
--platforms 小红书 \
|
||||
--video-dir "<成片目录>" \
|
||||
--legacy-schedule --min-gap 10 --max-gap 120
|
||||
```
|
||||
|
||||
## 三、登录异常处理
|
||||
|
||||
```bash
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/小红书发布/脚本/xiaohongshu_login.py"
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/多平台分发/脚本/distribute_all.py" --retry
|
||||
```
|
||||
|
||||
34
.cursor/skills/karuo-party/skills/平台_抖音_SKILL.md
Normal file
34
.cursor/skills/karuo-party/skills/平台_抖音_SKILL.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: 平台_抖音发布
|
||||
description: 抖音发布专用规则。API定时发布,按相邻间隔 10~120 分钟;遇风控/封禁优先账号处理。
|
||||
triggers: 抖音发布、抖音补发、抖音重试
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "1.0"
|
||||
updated: "2026-03-24"
|
||||
---
|
||||
|
||||
# 平台子Skill:抖音发布
|
||||
|
||||
## 一、强制规则
|
||||
|
||||
1. 仅按定时发布,不做整批立即。
|
||||
2. 相邻发布时间间隔 `10~120` 分钟。
|
||||
3. 若出现封禁/风控提示,立刻停止盲目重试并提示账号处理。
|
||||
|
||||
## 二、标准命令
|
||||
|
||||
```bash
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/多平台分发/脚本/distribute_all.py" \
|
||||
--platforms 抖音 \
|
||||
--video-dir "<成片目录>" \
|
||||
--legacy-schedule --min-gap 10 --max-gap 120
|
||||
```
|
||||
|
||||
## 三、登录异常处理
|
||||
|
||||
```bash
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/抖音发布/脚本/douyin_login.py"
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/多平台分发/脚本/distribute_all.py" --retry
|
||||
```
|
||||
|
||||
38
.cursor/skills/karuo-party/skills/平台_视频号_SKILL.md
Normal file
38
.cursor/skills/karuo-party/skills/平台_视频号_SKILL.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: 平台_视频号发布
|
||||
description: 视频号发布专用规则。发布前校验账号,清理密集/失败条目,按相邻间隔 10~120 分钟定时发布。
|
||||
triggers: 视频号发布、视频号重传、视频号补发
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "1.0"
|
||||
updated: "2026-03-24"
|
||||
---
|
||||
|
||||
# 平台子Skill:视频号发布
|
||||
|
||||
## 一、强制规则
|
||||
|
||||
1. 发布前必须校验 `auth_data`(昵称、头像、登录态)。
|
||||
2. 发布前必须检查 `post_list`:失败条目删除、同标题去重。
|
||||
3. 仅允许定时发布,按相邻条目间隔 `10~120` 分钟。
|
||||
4. 定时控件失败时允许请求注入;注入失败则中止该条,禁止误发立即。
|
||||
|
||||
## 二、标准命令
|
||||
|
||||
```bash
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/视频号发布/脚本/channels_web_cli.py" \
|
||||
publish-dir \
|
||||
--video-dir "<成片目录>" \
|
||||
--legacy-schedule --min-gap 10 --max-gap 120 \
|
||||
--start-after-min 10
|
||||
```
|
||||
|
||||
## 三、登录异常处理
|
||||
|
||||
- 若出现 `300334` / `300002` / `finder_raw` 缺失:立即执行重登。
|
||||
- 重登命令:
|
||||
|
||||
```bash
|
||||
python3 "/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/视频号发布/脚本/channels_login.py" --playwright-only
|
||||
```
|
||||
|
||||
@@ -47,6 +47,92 @@ func parseConfigBool(v interface{}) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// isLikelyWxMiniProgramAppID 判断是否为微信小程序 AppID 常见形态:wx + 16 位十六进制(共 18 字符)。
|
||||
// 后台「链接标签」若 type=miniprogram 且在此列直接填真实 AppID,C 端会把该值当作 mpKey 去 linkedMiniprograms 里匹配 key;
|
||||
// 若未单独配置 linked_miniprograms,会提示「未找到关联小程序配置」。mergeDirectMiniProgramLinksFromLinkTags 会据此自动补全映射。
|
||||
func isLikelyWxMiniProgramAppID(s string) bool {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) != 18 || !strings.HasPrefix(s, "wx") {
|
||||
return false
|
||||
}
|
||||
for i := 2; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') {
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func linkedMiniprogramItemKey(item gin.H) string {
|
||||
if v, ok := item["key"]; ok && v != nil {
|
||||
if s, ok := v.(string); ok {
|
||||
return strings.TrimSpace(s)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func linkedMiniprogramItemAppIDEmpty(item gin.H) bool {
|
||||
v, ok := item["appId"]
|
||||
if !ok || v == nil {
|
||||
return true
|
||||
}
|
||||
s, ok := v.(string)
|
||||
return !ok || strings.TrimSpace(s) == ""
|
||||
}
|
||||
|
||||
func linkedMiniprogramItemPathEmpty(item gin.H) bool {
|
||||
v, ok := item["path"]
|
||||
if !ok || v == nil {
|
||||
return true
|
||||
}
|
||||
s, ok := v.(string)
|
||||
return !ok || strings.TrimSpace(s) == ""
|
||||
}
|
||||
|
||||
// mergeDirectMiniProgramLinksFromLinkTags 将「直接填写微信 AppID」的链接标签并入 linkedMiniprograms,兼容现有小程序 navigateToMiniProgram 查表逻辑(不改 C 端)。
|
||||
func mergeDirectMiniProgramLinksFromLinkTags(linked *[]gin.H, tags []model.LinkTag) {
|
||||
if linked == nil {
|
||||
return
|
||||
}
|
||||
byKey := make(map[string]int)
|
||||
for i := range *linked {
|
||||
k := linkedMiniprogramItemKey((*linked)[i])
|
||||
if k != "" {
|
||||
byKey[k] = i
|
||||
}
|
||||
}
|
||||
for _, t := range tags {
|
||||
if strings.TrimSpace(strings.ToLower(t.Type)) != "miniprogram" {
|
||||
continue
|
||||
}
|
||||
app := strings.TrimSpace(t.AppID)
|
||||
if app == "" || !isLikelyWxMiniProgramAppID(app) {
|
||||
continue
|
||||
}
|
||||
path := strings.TrimSpace(t.PagePath)
|
||||
if idx, ok := byKey[app]; ok {
|
||||
item := (*linked)[idx]
|
||||
if linkedMiniprogramItemAppIDEmpty(item) {
|
||||
item["appId"] = app
|
||||
}
|
||||
if path != "" && linkedMiniprogramItemPathEmpty(item) {
|
||||
item["path"] = path
|
||||
}
|
||||
(*linked)[idx] = item
|
||||
continue
|
||||
}
|
||||
entry := gin.H{"key": app, "appId": app}
|
||||
if path != "" {
|
||||
entry["path"] = path
|
||||
}
|
||||
*linked = append(*linked, entry)
|
||||
byKey[app] = len(*linked) - 1
|
||||
}
|
||||
}
|
||||
|
||||
// defaultMpUi 小程序文案与导航默认值,存于 mp_config.mpUi;管理端系统设置可部分覆盖(深合并)
|
||||
func defaultMpUi() gin.H {
|
||||
return gin.H{
|
||||
@@ -226,35 +312,34 @@ func buildMiniprogramConfig() gin.H {
|
||||
if _, has := out["userDiscount"]; !has {
|
||||
out["userDiscount"] = float64(5)
|
||||
}
|
||||
// 链接标签列表(小程序 onLinkTagTap 需要 type;miniprogram 类型存 mpKey,用 key 查 linkedMiniprograms 得 appId)
|
||||
// 链接标签列表(小程序 onLinkTagTap:miniprogram 类型下发 mpKey=C 端用其匹配 linkedMiniprograms[].key;历史设计为「密钥→appId」,现支持 app_id 列直接填微信 AppID 并由下方 merge 自动补 linkedMiniprograms)
|
||||
var linkTagRows []model.LinkTag
|
||||
if err := db.Order("label ASC").Find(&linkTagRows).Error; err == nil {
|
||||
tags := make([]gin.H, 0, len(linkTagRows))
|
||||
for _, t := range linkTagRows {
|
||||
h := gin.H{"tagId": t.TagID, "label": t.Label, "url": t.URL, "type": t.Type, "pagePath": t.PagePath}
|
||||
if t.Type == "miniprogram" {
|
||||
h["mpKey"] = t.AppID // miniprogram 类型时 AppID 列存的是密钥
|
||||
} else {
|
||||
h["appId"] = t.AppID
|
||||
}
|
||||
tags = append(tags, h)
|
||||
_ = db.Order("label ASC").Find(&linkTagRows).Error
|
||||
tags := make([]gin.H, 0, len(linkTagRows))
|
||||
for _, t := range linkTagRows {
|
||||
h := gin.H{"tagId": t.TagID, "label": t.Label, "url": t.URL, "type": t.Type, "pagePath": t.PagePath}
|
||||
if t.Type == "miniprogram" {
|
||||
h["mpKey"] = t.AppID // 可为「关联表 key」或「直接 wx AppID」;后者由 mergeDirectMiniProgramLinksFromLinkTags 补全 linkedMiniprograms
|
||||
} else {
|
||||
h["appId"] = t.AppID
|
||||
}
|
||||
out["linkTags"] = tags
|
||||
tags = append(tags, h)
|
||||
}
|
||||
// 关联小程序列表(key 为 32 位密钥,小程序用 key 查 appId 后 wx.navigateToMiniProgram)
|
||||
out["linkTags"] = tags
|
||||
|
||||
// 关联小程序列表(小程序:find(m => m.key === mpKey) → navigateToMiniProgram)
|
||||
var linkedList []gin.H
|
||||
var linkedMpRow model.SystemConfig
|
||||
if err := db.Where("config_key = ?", "linked_miniprograms").First(&linkedMpRow).Error; err == nil && len(linkedMpRow.ConfigValue) > 0 {
|
||||
var linkedList []gin.H
|
||||
if err := json.Unmarshal(linkedMpRow.ConfigValue, &linkedList); err == nil && len(linkedList) > 0 {
|
||||
out["linkedMiniprograms"] = linkedList
|
||||
} else {
|
||||
// JSON解析失败,使用空数组
|
||||
out["linkedMiniprograms"] = []gin.H{}
|
||||
if err := json.Unmarshal(linkedMpRow.ConfigValue, &linkedList); err != nil {
|
||||
linkedList = nil
|
||||
}
|
||||
} else {
|
||||
// 未找到配置或查询失败,使用空数组作为默认值
|
||||
out["linkedMiniprograms"] = []gin.H{}
|
||||
}
|
||||
if linkedList == nil {
|
||||
linkedList = []gin.H{}
|
||||
}
|
||||
mergeDirectMiniProgramLinksFromLinkTags(&linkedList, linkTagRows)
|
||||
out["linkedMiniprograms"] = linkedList
|
||||
// 归一化 auditMode(兼容历史 bool / 字符串 / 数字)
|
||||
if mp, ok := out["mpConfig"].(gin.H); ok {
|
||||
mp["auditMode"] = parseConfigBool(mp["auditMode"])
|
||||
|
||||
Reference in New Issue
Block a user