chore: karuo-party 分平台 SKILL + 多平台分发更新;db handler 调整

Made-with: Cursor
This commit is contained in:
卡若
2026-03-24 12:00:04 +08:00
parent 1d56d0336c
commit 70b83fdb25
7 changed files with 294 additions and 33 deletions

View File

@@ -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 v2msg_type 必填) |
| 1.0 | 2026-03-20 | 初版:整合运营报表、视频切片、多平台分发、飞书视频文字下载 4 大技能,统一凭证管理 |

View File

@@ -7,14 +7,14 @@ description: >
triggers: 多平台分发、一键分发、全平台发布、批量分发、视频分发
owner: 木叶
group: 木
version: "4.4"
updated: "2026-03-23"
version: "4.5"
updated: "2026-03-24"
---
# 多平台分发 Skillv4.4
# 多平台分发 Skillv4.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 条立即;间隔与总跨度随条数自适应;本地 07 点尽量挪到午间(`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

View 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"
---
# 平台子SkillB站发布
## 一、强制规则
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
```

View 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
```

View 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
```

View 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
```

View File

@@ -47,6 +47,92 @@ func parseConfigBool(v interface{}) bool {
}
}
// isLikelyWxMiniProgramAppID 判断是否为微信小程序 AppID 常见形态wx + 16 位十六进制(共 18 字符)。
// 后台「链接标签」若 type=miniprogram 且在此列直接填真实 AppIDC 端会把该值当作 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 需要 typeminiprogram 类型 mpKey,用 key 查 linkedMiniprograms 得 appId
// 链接标签列表(小程序 onLinkTagTapminiprogram 类型下发 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"])