🔄 卡若AI 同步 2026-03-11 15:07 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个
This commit is contained in:
@@ -76,23 +76,11 @@ async def _api_publish(video_path: str, title: str, scheduled_time=None) -> Publ
|
||||
cover_path = extract_cover(video_path)
|
||||
print(f" [API] 封面已提取: {cover_path}", flush=True)
|
||||
|
||||
tags = "Soul派对,创业,认知觉醒,副业,商业思维"
|
||||
meta = {
|
||||
"copyright": 1,
|
||||
"source": "",
|
||||
"desc": title,
|
||||
"desc_format_id": 0,
|
||||
"dynamic": "",
|
||||
"interactive": 0,
|
||||
"open_elec": 0,
|
||||
"no_reprint": 1,
|
||||
"subtitles": {"lan": "", "open": 0},
|
||||
"tag": tags,
|
||||
"tid": 160, # 生活 > 日常
|
||||
"title": title[:80],
|
||||
"up_close_danmaku": False,
|
||||
"up_close_reply": False,
|
||||
}
|
||||
from video_metadata import VideoMeta
|
||||
vmeta = VideoMeta.from_filename(video_path)
|
||||
meta = vmeta.bilibili_meta()
|
||||
meta["title"] = title[:80]
|
||||
meta["desc"] = vmeta.description("B站")
|
||||
|
||||
if scheduled_time:
|
||||
dtime = int(scheduled_time.timestamp())
|
||||
|
||||
@@ -2,33 +2,31 @@
|
||||
name: 多平台分发
|
||||
description: >
|
||||
一键将视频分发到 5 个平台(抖音、B站、视频号、小红书、快手)。
|
||||
支持定时排期(30-120分钟随机间隔)、并行分发、去重、失败自动重试。
|
||||
封面统一用视频第一帧,Cookie 统一管理防重复获取。
|
||||
API 优先策略:视频号纯 API、B站 bilibili-api-python、抖音纯 API。
|
||||
支持定时排期(第1条立即发,后续 30-120 分钟随机间隔)、并行分发、去重、失败自动重试。
|
||||
triggers: 多平台分发、一键分发、全平台发布、批量分发、视频分发
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "3.1"
|
||||
updated: "2026-03-10"
|
||||
version: "4.0"
|
||||
updated: "2026-03-11"
|
||||
---
|
||||
|
||||
# 多平台分发 Skill(v3.1)
|
||||
# 多平台分发 Skill(v4.0)
|
||||
|
||||
> **核心能力**:一条命令将成片目录下的所有视频同时发布到 5 个主流平台。
|
||||
> **平台覆盖**:抖音、B站、视频号、小红书、快手。
|
||||
> **技术路线**:抖音纯 API(逆向 VOD),B站 bilibili-api-python API,视频号/小红书/快手 Playwright 自动化。
|
||||
> **全链路**:定时排期 → 并行分发 → 去重 → 失败重试 → Cookie 预警 → 结果日志。
|
||||
> **核心原则**:API 发布为主,Playwright 为辅。确保确定性地分发到各平台。
|
||||
> **v4.0 变更**:视频号已切换为纯 API、统一元数据生成器、定时排期优化、简介/标签/分区自动填充。
|
||||
|
||||
---
|
||||
|
||||
## 一、平台与实现方式
|
||||
|
||||
| 平台 | 实现方式 | 定时发布 | Cookie 有效期 | 119 场实测 |
|
||||
| 平台 | 实现方式 | 定时发布 | Cookie 有效期 | 120 场实测 |
|
||||
|------|----------|----------|---------------|------------|
|
||||
| **抖音** | 纯 API(VOD + bd-ticket-guard) | API timing_ts | ~2-4h | 账号封禁,预检拦截 |
|
||||
| **B站** | bilibili-api-python API 优先 → Playwright 兜底 | API dtime | ~6 个月 | 15/15 成功 |
|
||||
| **视频号** | Playwright headless 自动化 | UI 定时(降级立即) | ~24-48h | 15/15 成功 |
|
||||
| **小红书** | Playwright headless v2 自动化 | UI 定时(降级立即) | ~1-3 天 | 15/15 成功(修复后) |
|
||||
| **快手** | Playwright headless 自动化 | UI 定时成功 | ~7-30 天 | 15/15 成功(含重试) |
|
||||
| **视频号** | **纯 API**(DFS 上传 + post_create) | API 原生支持 | ~24-48h | 12/12 成功 |
|
||||
| **B站** | **bilibili-api-python** API 优先 → Playwright 兜底 | API `dtime` | ~6 个月 | 12/12 成功 |
|
||||
| **小红书** | Playwright headless 自动化 | UI 定时(降级立即) | ~1-3 天 | 12/12 成功 |
|
||||
| **快手** | Playwright headless 自动化 | UI 定时 | ~7-30 天 | Cookie 过期 |
|
||||
| **抖音** | 纯 API(VOD + bd-ticket-guard) | API `timing_ts` | ~2-4h | 账号封禁中 |
|
||||
|
||||
---
|
||||
|
||||
@@ -37,132 +35,100 @@ updated: "2026-03-10"
|
||||
```bash
|
||||
cd /Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/多平台分发/脚本
|
||||
|
||||
# 定时排期并行分发(默认 30-120 分钟随机间隔)
|
||||
# 定时排期:第1条立即,后续 30-120min 随机间隔
|
||||
python3 distribute_all.py
|
||||
|
||||
# 立即发布(不排期)
|
||||
# 立即全部发布
|
||||
python3 distribute_all.py --now
|
||||
|
||||
# 自定义排期间隔
|
||||
python3 distribute_all.py --min-gap 30 --max-gap 120 --max-hours 24
|
||||
|
||||
# 只发指定平台
|
||||
python3 distribute_all.py --platforms 抖音 B站
|
||||
python3 distribute_all.py --platforms 视频号 B站
|
||||
|
||||
# 检查 Cookie + 重试失败
|
||||
python3 distribute_all.py --check
|
||||
python3 distribute_all.py --retry
|
||||
|
||||
# 分发单条 / 自定义目录
|
||||
python3 distribute_all.py --video "/path/to/video.mp4"
|
||||
# 自定义视频目录
|
||||
python3 distribute_all.py --video-dir "/path/to/videos/"
|
||||
|
||||
# 跳过去重 / 串行调试
|
||||
python3 distribute_all.py --no-dedup
|
||||
python3 distribute_all.py --serial
|
||||
# 检查 Cookie / 重试失败
|
||||
python3 distribute_all.py --check
|
||||
python3 distribute_all.py --retry
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、首次使用流程
|
||||
## 三、定时排期(v4.0 优化)
|
||||
|
||||
```
|
||||
1. 安装依赖
|
||||
pip3 install httpx playwright cryptography Pillow
|
||||
playwright install chromium
|
||||
### 3.1 排期规则
|
||||
- **第 1 条**:立即发布(`first_delay=0`)
|
||||
- **第 2 条起**:前一条 + random(30, 120) 分钟
|
||||
- 若总跨度 > 24h,自动按比例压缩
|
||||
- 12 条视频典型跨度 ~10-14h
|
||||
|
||||
2. 逐个平台登录(只需首次)
|
||||
python3 ../抖音发布/脚本/douyin_login.py
|
||||
python3 ../B站发布/脚本/bilibili_login.py
|
||||
python3 ../视频号发布/脚本/channels_login.py
|
||||
python3 ../小红书发布/脚本/xiaohongshu_login.py
|
||||
python3 ../快手发布/脚本/kuaishou_login.py
|
||||
### 3.2 各平台定时实现
|
||||
|
||||
3. 检查 Cookie 状态
|
||||
python3 distribute_all.py --check
|
||||
|
||||
4. 一键分发
|
||||
python3 distribute_all.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、Cookie 管理
|
||||
|
||||
### 4.1 统一管理器
|
||||
|
||||
`cookie_manager.py` 提供:
|
||||
- 加载 Playwright storage_state.json
|
||||
- 检查 Cookie 有效期(ok / warning / expiring_soon / expired)
|
||||
- 提供 cookie_str / cookie_dict
|
||||
- 批量检查所有平台状态
|
||||
|
||||
### 4.2 有效期对比
|
||||
|
||||
| 平台 | Cookie 有效期 | 建议刷新频率 |
|
||||
|------|-------------|-------------|
|
||||
| 抖音 | ~2-4h | 每次使用前 |
|
||||
| B站 | ~6 个月 | 半年一次 |
|
||||
| 视频号 | ~24-48h | 每天 |
|
||||
| 小红书 | ~1-3 天 | 2-3 天 |
|
||||
| 快手 | ~7-30 天 | 每周 |
|
||||
|
||||
### 4.3 防重复获取
|
||||
|
||||
Cookie 文件保存后自动记录时间戳,`cookie_manager.py` 通过文件修改时间判断年龄。
|
||||
若 Cookie 仍有效,不会触发重新登录。
|
||||
|
||||
---
|
||||
|
||||
## 五、视频处理
|
||||
|
||||
### 5.1 封面提取
|
||||
|
||||
`video_utils.py` 使用 ffmpeg 提取视频第一帧(0.5s 处)作为封面:
|
||||
|
||||
```python
|
||||
from video_utils import extract_cover
|
||||
cover_path = extract_cover("/path/to/video.mp4")
|
||||
```
|
||||
|
||||
### 5.2 视频元数据
|
||||
|
||||
```python
|
||||
from video_utils import get_video_info
|
||||
info = get_video_info("/path/to/video.mp4")
|
||||
# {'duration': 180.5, 'width': 1080, 'height': 1920, ...}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、定时排期
|
||||
|
||||
### 6.1 排期逻辑(schedule_generator.py)
|
||||
- 相邻视频随机间隔 30-120 分钟
|
||||
- 若总跨度 > 24h,按比例自动压缩
|
||||
- 15 条视频典型跨度 ~16-18h
|
||||
|
||||
### 6.2 各平台定时支持
|
||||
|
||||
| 平台 | 定时方式 | 状态 |
|
||||
| 平台 | 定时方式 | 参数 |
|
||||
|------|----------|------|
|
||||
| 抖音 | API `timing_ts`(Unix 时间戳) | 已实现 |
|
||||
| B站 | API `dtime`(Unix 时间戳) | 已实现 |
|
||||
| 快手 | Playwright UI「定时发布」 | 已实现,成功率高 |
|
||||
| 视频号 | Playwright UI「定时发布」 | 已实现,UI 匹配待优化 |
|
||||
| 小红书 | Playwright UI「定时发布」 | 已实现,UI 匹配待优化 |
|
||||
| B站 | API `meta.dtime` | Unix 时间戳(秒) |
|
||||
| 视频号 | API 暂不支持原生定时 | 描述中标注时间/手动设置 |
|
||||
| 抖音 | API `timing_ts` | Unix 时间戳 |
|
||||
| 快手 | Playwright UI | `schedule_helper.py` |
|
||||
| 小红书 | Playwright UI | `schedule_helper.py` |
|
||||
|
||||
定时失败时自动降级为立即发布,不影响视频发出。
|
||||
---
|
||||
|
||||
## 四、元数据自动生成(v4.0 新增)
|
||||
|
||||
`video_metadata.py` 根据文件名自动生成各平台差异化内容:
|
||||
|
||||
```python
|
||||
from video_metadata import VideoMeta
|
||||
meta = VideoMeta.from_filename("AI最大的缺点是上下文太短.mp4")
|
||||
|
||||
meta.title("B站") # 优化后的标题
|
||||
meta.description("B站") # 标题 + 标签 + 品牌标记
|
||||
meta.tags_str("B站") # AI工具,效率提升,Soul派对,...
|
||||
meta.bilibili_meta() # B站投稿完整 meta(含 tid/tag/desc)
|
||||
meta.title_short() # 小红书短标题(≤20字)
|
||||
meta.hashtags("视频号") # #AI工具 #效率提升 ... #小程序 卡若创业派对
|
||||
```
|
||||
|
||||
### 4.1 内容结构
|
||||
- **标题**:手工优化标题库优先,否则从文件名智能提取
|
||||
- **简介**:标题 + 换行 + 话题标签 + `#小程序 卡若创业派对`
|
||||
- **标签**:基于关键词匹配(AI/创业/副业/Soul 等 12 类)+ 通用标签
|
||||
- **分区**:B站 tid=160(生活>日常)
|
||||
- **风控过滤**:`content_filter.py` 自动替换敏感词(70+ 映射,严格/宽松分级)
|
||||
|
||||
---
|
||||
|
||||
## 五、商品链接/小黄车(调研结果)
|
||||
|
||||
| 平台 | 功能 | 实现方式 | 状态 |
|
||||
|------|------|----------|------|
|
||||
| B站 | 花火计划商品链接 | 需企业认证 + 品牌合作授权 | 需手动配置 |
|
||||
| 视频号 | 挂小程序 | 视频号主页 > 设置 > 服务菜单 > 小程序 | 需手动配置 |
|
||||
| 抖音 | 小黄车 | 需开通橱窗(粉丝 ≥1000) | 账号封禁 |
|
||||
| 快手 | 商品卡片 | 需开通快手小店 | 需手动配置 |
|
||||
| 小红书 | 商品笔记 | 需开通小红书店铺 | 需手动配置 |
|
||||
|
||||
**当前做法**:在描述中统一添加 `#小程序 卡若创业派对` 引导用户搜索。
|
||||
|
||||
---
|
||||
|
||||
## 六、Cookie 管理
|
||||
|
||||
`cookie_manager.py` 统一管理:
|
||||
- 中央存储:`多平台分发/cookies/{平台}_cookies.json`
|
||||
- 自动迁移:旧路径 → 中央存储(首次使用时)
|
||||
- API 预检:5 平台各自 auth API 校验有效性
|
||||
- 防重复登录:有效 Cookie 不触发重新获取
|
||||
|
||||
---
|
||||
|
||||
## 七、去重机制
|
||||
|
||||
- 基于 `publish_log.json`(JSON Lines 格式)记录每次发布结果
|
||||
- 日志:`publish_log.json`(JSON Lines)
|
||||
- 去重键:`(平台名, 视频文件名)`
|
||||
- 双保险:调度器层(distribute_all.py)+ 平台层(各 publish_one)
|
||||
- 独立运行单平台脚本也有去重
|
||||
- `--no-dedup` 跳过去重,`--retry` 重跑失败任务
|
||||
- 双保险:调度器层 + 平台层
|
||||
- `--no-dedup` 跳过,`--retry` 重跑失败
|
||||
|
||||
---
|
||||
|
||||
@@ -170,143 +136,31 @@ info = get_video_info("/path/to/video.mp4")
|
||||
|
||||
```
|
||||
木叶_视频内容/
|
||||
├── 多平台分发/ ← 本 Skill(调度器 + 共享工具)
|
||||
├── 多平台分发/ ← 本 Skill(调度器 + 共享工具)
|
||||
│ ├── SKILL.md
|
||||
│ └── 脚本/
|
||||
│ ├── distribute_all.py # 主调度器 v3
|
||||
│ ├── schedule_generator.py # 定时排期生成器
|
||||
│ ├── schedule_helper.py # Playwright 定时发布辅助
|
||||
│ ├── publish_result.py # 统一发布结果 + 去重
|
||||
│ ├── title_generator.py # 智能标题生成
|
||||
│ ├── cookie_manager.py # Cookie 统一管理
|
||||
│ ├── distribute_all.py # 主调度器 v4
|
||||
│ ├── video_metadata.py # 统一元数据生成器(v4 新增)
|
||||
│ ├── schedule_generator.py # 定时排期(v4: 第1条立即发)
|
||||
│ ├── schedule_helper.py # Playwright 定时 UI 辅助
|
||||
│ ├── publish_result.py # 统一 PublishResult + 去重
|
||||
│ ├── title_generator.py # 标题生成(被 video_metadata 取代)
|
||||
│ ├── content_filter.py # 敏感词过滤(70+ 映射)
|
||||
│ ├── cookie_manager.py # Cookie 统一管理(5 平台 API 预检)
|
||||
│ ├── video_utils.py # 视频处理(封面、元数据)
|
||||
│ └── publish_log.json # 发布结果日志(自动生成)
|
||||
├── 抖音发布/ ← 纯 API(VOD + bd-ticket-guard)
|
||||
├── B站发布/ ← bilibili-api-python API + Playwright 兜底
|
||||
├── 视频号发布/ ← Playwright headless
|
||||
├── 小红书发布/ ← Playwright headless
|
||||
└── 快手发布/ ← Playwright headless
|
||||
│ └── publish_log.json # 发布日志
|
||||
├── 抖音发布/ ← 纯 API(账号封禁中)
|
||||
├── B站发布/ ← bilibili-api-python API
|
||||
├── 视频号发布/ ← 纯 API(DFS 协议,v5)
|
||||
├── 小红书发布/ ← Playwright headless
|
||||
└── 快手发布/ ← Playwright headless
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、相关文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `脚本/distribute_all.py` | **主调度器 v3**:定时排期 + 并行分发 + 去重 + 重试 |
|
||||
| `脚本/schedule_generator.py` | 排期生成(30-120min 间隔,超 24h 压缩) |
|
||||
| `脚本/schedule_helper.py` | Playwright 定时发布 UI 交互辅助 |
|
||||
| `脚本/publish_result.py` | 统一 PublishResult + 日志 + 去重 |
|
||||
| `脚本/title_generator.py` | 智能标题(字典优先 → 文件名自动) |
|
||||
| `脚本/cookie_manager.py` | Cookie 统一管理(有效期检查、API 预检 5 平台) |
|
||||
| `脚本/content_filter.py` | 敏感词/风控词过滤(政治、金融、医疗、平台词,70+ 替换映射) |
|
||||
| `脚本/video_utils.py` | 视频处理(封面提取、元数据) |
|
||||
|
||||
---
|
||||
|
||||
## 十、踩坑经验(119 场全量分发)
|
||||
|
||||
### 10.1 视频号/小红书定时发布 UI 匹配失败
|
||||
- **现象**:`schedule_helper.py` 找到了「定时发布」文字但日期时间 input 未匹配到
|
||||
- **原因**:这两个平台的日期选择器是自定义组件(非原生 `input[type="date"]`),需要点击日历格子
|
||||
- **影响**:定时功能降级为立即发布,视频仍正常发出
|
||||
- **待优化**:研究各平台 datepicker 的具体 DOM 结构,用 JS 直接操作 React state
|
||||
|
||||
### 10.2 快手「未找到上传控件」
|
||||
- **现象**:部分视频上传时 `input[type="file"]` 元素未出现
|
||||
- **原因**:快手页面加载时偶发 JS 渲染延迟,或上次草稿弹窗阻塞了上传区
|
||||
- **解决**:脚本已加「放弃草稿」逻辑,重试后全部成功
|
||||
|
||||
### 10.3 B站 API 偶发超时后 Playwright 兜底也失败
|
||||
- **现象**:2 条视频 API 超时后降级到 Playwright,但 Playwright 也找不到上传控件
|
||||
- **原因**:B站创作中心在短时间内连续打开浏览器可能触发人机验证
|
||||
- **解决**:重试时纯 API 直接成功(5.3-5.7s),Playwright 只在 API 彻底不可用时才需要
|
||||
|
||||
### 10.4 抖音 Cookie 过期(全局)
|
||||
- **现象**:Cookie 检查显示有效(expiry > now),但 API 返回「Cookie 已过期」
|
||||
- **原因**:抖音 API 的 `user_info` 接口在 Cookie 过期前约 1-2h 就开始拒绝
|
||||
- **解决**:重新运行 `python3 douyin_login.py` 扫码登录
|
||||
|
||||
### 10.5 并行分发的 Playwright 资源竞争
|
||||
- **现象**:多个 Playwright 同时运行时 CPU 飙高、偶发超时
|
||||
- **影响**:视频号/小红书/快手 三路 Playwright 并行,部分上传时间从 2s 涨到 5s
|
||||
- **建议**:服务器部署时限制并发数(如最多 3 个 Playwright 同时)
|
||||
|
||||
### 10.6 小红书发布按钮点击不生效(119场)
|
||||
- **现象**:脚本日志声称 15/15 成功,实际只有 4 条到达平台
|
||||
- **根因**:初版 `pub.click(force=True)` 失败率高达 ~70%,且成功判定逻辑过于宽松(默认 status="reviewing")
|
||||
- **修复**:
|
||||
1. JS 精准点击红色发布按钮(用 `getComputedStyle` 筛选 backgroundColor 含 255 的 button)
|
||||
2. Playwright `force-click` 兜底
|
||||
3. 处理二次确认弹窗
|
||||
4. 未检测到明确成功信号时,跳转到笔记管理页二次验证
|
||||
5. 连续 3 次失败自动熔断(防封号)
|
||||
- **成功率**:修复后 10/10(100%)
|
||||
|
||||
### 10.7 小红书假成功日志污染去重(119场)
|
||||
- **现象**:publish_log.json 记录 15 条 success=True,导致去重跳过,不会重试
|
||||
- **根因**:旧版 success 判定将所有未报错的提交都标记为 success
|
||||
- **修复**:
|
||||
1. 清理 publish_log.json 中的虚假记录
|
||||
2. 只有明确的成功信号(页面重置、URL 跳转、"发布成功"文本)才标记 success=True
|
||||
3. 不确定时走笔记管理页验证
|
||||
|
||||
### 10.8 视频号描述写入空白(119场)
|
||||
- **现象**:所有视频发布后描述为空,视频号使用 Wujie 微前端框架
|
||||
- **根因**:`.input-editor` 在 Shadow DOM 内,常规 `.fill()` 无法写入
|
||||
- **修复**:clipboard/insertText 方式注入,先 focus → selectAll → insertText
|
||||
|
||||
### 10.9 抖音账号投稿功能封禁
|
||||
- **现象**:API 返回 status_code=-20 "视频投稿功能已封禁"
|
||||
- **影响**:所有视频无法发布到抖音
|
||||
- **处理**:预检时明确提示封禁状态,跳过抖音
|
||||
|
||||
### 10.10 账号预检机制(v3.1 新增)
|
||||
- **所有平台发布前统一调用 `cookie_manager.check_cookie_valid()`**
|
||||
- 视频号:POST auth_data API
|
||||
- B站:GET /x/web-interface/nav
|
||||
- 快手:GET cp.kuaishou.com/rest/pc/user/myInfo
|
||||
- 小红书:GET creator.xiaohongshu.com/api/galaxy/user/info
|
||||
- 抖音:GET /web/api/media/user_info/
|
||||
- 预检不通过则终止发布,避免浪费时间上传后才发现 Cookie 过期
|
||||
|
||||
---
|
||||
|
||||
## 十一、万推(Web 版视频分发系统)
|
||||
|
||||
卡若AI 的多平台分发能力已整合到万推项目(`/Users/karuo/Documents/开发/3、自营项目/万推/`),提供 Web GUI + API 接口:
|
||||
|
||||
| 组件 | 说明 |
|
||||
|------|------|
|
||||
| **万推后端** | FastAPI,`backend/main.py`,端口 8000 |
|
||||
| **万推前端** | Vue 3 毛玻璃风格,`frontend/index.html` |
|
||||
| **直连发布器** | `backend/direct_publisher.py`,Playwright 操作 5 平台创作者中心 |
|
||||
| **uploader 体系** | `backend/uploader/` 下 5 平台独立 uploader |
|
||||
| **Cookie 自动获取** | `backend/cookie_fetcher.py`,打开浏览器让用户扫码 |
|
||||
|
||||
### 启动万推
|
||||
|
||||
```bash
|
||||
cd /Users/karuo/Documents/开发/3、自营项目/万推/backend
|
||||
pip3 install -r requirements.txt
|
||||
playwright install chromium
|
||||
python3 main.py
|
||||
# 访问 http://localhost:8000
|
||||
```
|
||||
|
||||
### 万推与卡若AI脚本的关系
|
||||
|
||||
- 卡若AI `distribute_all.py`:命令行一键分发,适合自动化流水线
|
||||
- 万推 Web 界面:用户手动管理账号和分发,适合日常运营
|
||||
- 两者共享 Playwright + Cookie 方案,互为补充
|
||||
|
||||
---
|
||||
|
||||
## 九、依赖
|
||||
|
||||
- Python 3.10+
|
||||
- httpx, playwright, playwright-stealth, cryptography, Pillow
|
||||
- biliup(B站上传 API)
|
||||
- httpx, bilibili-api-python, playwright, Pillow
|
||||
- ffmpeg/ffprobe(系统已安装)
|
||||
- Playwright chromium(`playwright install chromium`)
|
||||
- `playwright install chromium`
|
||||
|
||||
@@ -38,6 +38,7 @@ from publish_result import (PublishResult, print_summary, save_results,
|
||||
load_published_set, load_failed_tasks)
|
||||
from title_generator import generate_title
|
||||
from schedule_generator import generate_schedule, format_schedule
|
||||
from video_metadata import VideoMeta
|
||||
|
||||
PLATFORM_CONFIG = {
|
||||
"抖音": {
|
||||
@@ -190,7 +191,8 @@ async def distribute_to_platform(
|
||||
total = len(to_publish)
|
||||
pub_fn = getattr(module, "publish_one_compat", None) or module.publish_one
|
||||
for i, vp in enumerate(to_publish):
|
||||
title = generate_title(vp.name, titles_dict)
|
||||
vmeta = VideoMeta.from_filename(str(vp))
|
||||
title = vmeta.title(platform)
|
||||
stime = publish_schedule[i] if publish_schedule else None
|
||||
try:
|
||||
r = await pub_fn(str(vp), title, i + 1, total, scheduled_time=stime)
|
||||
|
||||
@@ -128,3 +128,15 @@
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/深度AI模型对比 哪个才是真正的AI不是语言模型.mp4", "title": "深度AI模型对比 哪个才是真正的AI不是语言模型 #Soul派对 #创业日记", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.2712419033050537, "timestamp": "2026-03-11 12:13:53"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/疗愈师配AI助手能收多少钱 一个小团队5万到10万.mp4", "title": "疗愈师配AI助手能收多少钱 一个小团队5万到10万 #Soul派对 #创业日记", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.2667992115020752, "timestamp": "2026-03-11 12:13:56"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/赚钱没那么复杂,自信心才是核心问题.mp4", "title": "赚钱没那么复杂,自信心才是核心问题 #Soul派对 #创业日记", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.2669076919555664, "timestamp": "2026-03-11 12:14:00"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/AI最大的缺点是上下文太短,这样来解决.mp4", "title": "AI的短板是记忆太短,上下文一长就废了,这个方法能解决", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 2.443204164505005, "timestamp": "2026-03-11 15:07:02"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/AI每天剪1000个视频 M4电脑24T素材库全网分发.mp4", "title": "M4芯片+24T素材库,AI每天剪1000条视频自动全网分发", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.1888279914855957, "timestamp": "2026-03-11 15:07:05"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/Soul派对变现全链路 发视频就有钱,后端全解决.mp4", "title": "Soul派对怎么商业转化?发视频就有收益,后端体系全部搞定", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.1997511386871338, "timestamp": "2026-03-11 15:07:08"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/从0到切片发布 AI自动完成每天副业30条视频.mp4", "title": "从零到切片发布,AI全自动完成,每天副业产出30条视频", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.19605207443237305, "timestamp": "2026-03-11 15:07:11"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/做副业的基本条件 苹果电脑和特殊访问工具.mp4", "title": "做副业的两个基本条件:一台Mac和一个上网工具", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.19453787803649902, "timestamp": "2026-03-11 15:07:15"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/切片分发全自动化 从视频到发布一键完成.mp4", "title": "从录制到发布全自动化,一键切片分发五大平台", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.19373202323913574, "timestamp": "2026-03-11 15:07:18"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/创业团队4人平分25有啥危险 先跑钱再谈股权.mp4", "title": "创业团队4人平分25%股权有啥风险?先跑出收入再谈分配", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.2604191303253174, "timestamp": "2026-03-11 15:07:21"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/坚持到120场是什么感觉 方向越确定执行越坚决.mp4", "title": "坚持到第120场派对是什么感觉?方向越清晰执行越坚决", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.28436827659606934, "timestamp": "2026-03-11 15:07:24"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/帮人装AI一单300到1000块,传统行业也能做.mp4", "title": "帮传统行业的人装AI工具,一单收300到1000块,简单好做", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.20317912101745605, "timestamp": "2026-03-11 15:07:28"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/深度AI模型对比 哪个才是真正的AI不是语言模型.mp4", "title": "深度对比各大AI模型,哪个才是真正的智能而不只是语言模型", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.33212804794311523, "timestamp": "2026-03-11 15:07:31"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/疗愈师配AI助手能收多少钱 一个小团队5万到10万.mp4", "title": "疗愈师+AI助手组合,一个小团队月收5万到10万", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.2739429473876953, "timestamp": "2026-03-11 15:07:34"}
|
||||
{"platform": "抖音", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片/赚钱没那么复杂,自信心才是核心问题.mp4", "title": "获得收益真没那么复杂,自信心才是卡住你的核心问题", "success": false, "status": "error", "message": "Cookie 已过期", "elapsed_sec": 0.27978515625, "timestamp": "2026-03-11 15:07:38"}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
定时排期生成器 — 为 N 条视频生成发布时间表
|
||||
定时排期生成器 v2
|
||||
规则:
|
||||
1. 相邻视频间隔 30-120 分钟(随机)
|
||||
2. 若总时长 > max_hours,按比例压缩至 max_hours 内
|
||||
3. 第一条视频在 first_delay 分钟后发布
|
||||
1. 第一条视频 **立即发布**(first_delay=0)
|
||||
2. 第二条起,每条间隔 30~120 分钟(随机)
|
||||
3. 若总时长超过 max_hours,按比例压缩
|
||||
4. 支持各平台原生定时 API 所需的 datetime 对象
|
||||
"""
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
@@ -15,16 +16,19 @@ def generate_schedule(
|
||||
min_gap: int = 30,
|
||||
max_gap: int = 120,
|
||||
max_hours: float = 24.0,
|
||||
first_delay: int = 125,
|
||||
first_delay: int = 0,
|
||||
start_time: datetime = None,
|
||||
) -> list[datetime]:
|
||||
"""
|
||||
返回 n 个 datetime,每个对应一条视频的定时发布时间。
|
||||
返回 n 个 datetime:
|
||||
- times[0] = now + first_delay(默认 0 = 立即)
|
||||
- times[1..] = 前一条 + random(min_gap, max_gap) 分钟
|
||||
"""
|
||||
if n <= 0:
|
||||
return []
|
||||
|
||||
base = start_time or datetime.now()
|
||||
|
||||
if n == 1:
|
||||
return [base + timedelta(minutes=first_delay)]
|
||||
|
||||
@@ -34,8 +38,8 @@ def generate_schedule(
|
||||
|
||||
if total_min > max_min:
|
||||
ratio = max_min / total_min
|
||||
first_delay = int(first_delay * ratio)
|
||||
gaps = [max(1, int(g * ratio)) for g in gaps]
|
||||
first_delay = max(0, int(first_delay * ratio))
|
||||
gaps = [max(5, int(g * ratio)) for g in gaps]
|
||||
|
||||
times = []
|
||||
cur = base + timedelta(minutes=first_delay)
|
||||
@@ -48,11 +52,11 @@ def generate_schedule(
|
||||
|
||||
|
||||
def format_schedule(videos: list[str], times: list[datetime]) -> str:
|
||||
"""格式化排期表用于打印"""
|
||||
"""格式化排期表"""
|
||||
lines = [" 序号 | 发布时间 | 间隔 | 视频"]
|
||||
lines.append(" " + "-" * 70)
|
||||
for i, (v, t) in enumerate(zip(videos, times)):
|
||||
gap = ""
|
||||
gap = "立即" if i == 0 else ""
|
||||
if i > 0:
|
||||
delta = (t - times[i - 1]).total_seconds() / 60
|
||||
gap = f"{delta:.0f}min"
|
||||
@@ -61,11 +65,11 @@ def format_schedule(videos: list[str], times: list[datetime]) -> str:
|
||||
|
||||
total = (times[-1] - times[0]).total_seconds() / 3600 if len(times) > 1 else 0
|
||||
lines.append(" " + "-" * 70)
|
||||
lines.append(f" 总跨度: {total:.1f}h | 首条: {times[0].strftime('%H:%M')} | 末条: {times[-1].strftime('%H:%M')}")
|
||||
lines.append(f" 总跨度: {total:.1f}h | 首条: {times[0].strftime('%H:%M')}(立即) | 末条: {times[-1].strftime('%H:%M')}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
schedule = generate_schedule(15)
|
||||
names = [f"视频_{i+1}.mp4" for i in range(15)]
|
||||
schedule = generate_schedule(12)
|
||||
names = [f"视频_{i+1}.mp4" for i in range(12)]
|
||||
print(format_schedule(names, schedule))
|
||||
|
||||
209
03_卡木(木)/木叶_视频内容/多平台分发/脚本/video_metadata.py
Normal file
209
03_卡木(木)/木叶_视频内容/多平台分发/脚本/video_metadata.py
Normal file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
统一视频元数据生成器 v1
|
||||
根据视频文件名自动生成:标题、简介、标签、分区
|
||||
支持各平台差异化输出(B站/视频号/小红书/快手/抖音)
|
||||
|
||||
用法:
|
||||
meta = VideoMeta.from_filename("AI最大的缺点是上下文太短,这样来解决.mp4")
|
||||
print(meta.title("B站"))
|
||||
print(meta.description("B站"))
|
||||
print(meta.tags("B站"))
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
from content_filter import filter_for_platform
|
||||
|
||||
BRAND_TAG = "#卡若创业派对"
|
||||
MINI_PROGRAM = "#小程序 卡若创业派对"
|
||||
|
||||
PLATFORM_CATEGORIES = {
|
||||
"B站": {"tid": 160, "name": "生活 > 日常"},
|
||||
"视频号": {"category": "科技数码"},
|
||||
"小红书": {"category": "科技数码"},
|
||||
"快手": {"category": "生活"},
|
||||
"抖音": {"category": "科技"},
|
||||
}
|
||||
|
||||
COMMON_TAGS = ["Soul派对", "创业", "认知觉醒", "副业", "商业思维"]
|
||||
|
||||
KEYWORD_TAGS = {
|
||||
"AI": ["AI工具", "人工智能", "效率提升"],
|
||||
"副业": ["副业", "副业入门", "副业收入"],
|
||||
"创业": ["创业", "创业心态", "创业故事"],
|
||||
"Soul": ["Soul派对", "Soul创业"],
|
||||
"切片": ["切片分发", "自动化", "内容分发"],
|
||||
"股权": ["创业股权", "团队管理"],
|
||||
"疗愈": ["疗愈", "AI赋能", "疗愈商业"],
|
||||
"模型": ["AI对比", "深度思考", "AI模型"],
|
||||
"赚钱": ["创业心态", "商业思维"],
|
||||
"装AI": ["AI服务", "传统行业"],
|
||||
"坚持": ["坚持的力量", "自律"],
|
||||
"视频": ["内容创作", "视频分发"],
|
||||
}
|
||||
|
||||
CURATED_TITLES: dict[str, dict] = {
|
||||
"AI最大的缺点是上下文太短,这样来解决.mp4": {
|
||||
"title": "AI的短板是记忆太短,上下文一长就废了,这个方法能解决",
|
||||
"tags_extra": ["AI工具", "效率提升"],
|
||||
},
|
||||
"AI每天剪1000个视频 M4电脑24T素材库全网分发.mp4": {
|
||||
"title": "M4芯片+24T素材库,AI每天剪1000条视频自动全网分发",
|
||||
"tags_extra": ["AI剪辑", "内容工厂"],
|
||||
},
|
||||
"Soul派对变现全链路 发视频就有钱,后端全解决.mp4": {
|
||||
"title": "Soul派对怎么变现?发视频就有收益,后端体系全部搞定",
|
||||
"tags_extra": ["Soul派对", "副业收入"],
|
||||
},
|
||||
"从0到切片发布 AI自动完成每天副业30条视频.mp4": {
|
||||
"title": "从零到切片发布,AI全自动完成,每天副业产出30条视频",
|
||||
"tags_extra": ["AI副业", "切片分发"],
|
||||
},
|
||||
"做副业的基本条件 苹果电脑和特殊访问工具.mp4": {
|
||||
"title": "做副业的两个基本条件:一台Mac和一个上网工具",
|
||||
"tags_extra": ["副业入门", "工具推荐"],
|
||||
},
|
||||
"切片分发全自动化 从视频到发布一键完成.mp4": {
|
||||
"title": "从录制到发布全自动化,一键切片分发五大平台",
|
||||
"tags_extra": ["自动化", "内容分发"],
|
||||
},
|
||||
"创业团队4人平分25有啥危险 先跑钱再谈股权.mp4": {
|
||||
"title": "创业团队4人平分25%股权有啥风险?先跑出收入再谈分配",
|
||||
"tags_extra": ["创业股权", "团队管理"],
|
||||
},
|
||||
"坚持到120场是什么感觉 方向越确定执行越坚决.mp4": {
|
||||
"title": "坚持到第120场派对是什么感觉?方向越清晰执行越坚决",
|
||||
"tags_extra": ["Soul派对", "坚持的力量"],
|
||||
},
|
||||
"帮人装AI一单300到1000块,传统行业也能做.mp4": {
|
||||
"title": "帮传统行业的人装AI工具,一单收300到1000块,简单好做",
|
||||
"tags_extra": ["AI服务", "传统行业"],
|
||||
},
|
||||
"深度AI模型对比 哪个才是真正的AI不是语言模型.mp4": {
|
||||
"title": "深度对比各大AI模型,哪个才是真正的智能而不只是语言模型",
|
||||
"tags_extra": ["AI对比", "深度思考"],
|
||||
},
|
||||
"疗愈师配AI助手能收多少钱 一个小团队5万到10万.mp4": {
|
||||
"title": "疗愈师+AI助手组合,一个小团队月收5万到10万",
|
||||
"tags_extra": ["AI赋能", "疗愈商业"],
|
||||
},
|
||||
"赚钱没那么复杂,自信心才是核心问题.mp4": {
|
||||
"title": "赚钱真没那么复杂,自信心才是卡住你的核心问题",
|
||||
"tags_extra": ["创业心态", "自信"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class VideoMeta:
|
||||
"""单条视频的元数据"""
|
||||
filename: str
|
||||
base_title: str
|
||||
tags_extra: list[str] = field(default_factory=list)
|
||||
|
||||
@classmethod
|
||||
def from_filename(cls, filename: str) -> VideoMeta:
|
||||
fname = Path(filename).name
|
||||
curated = CURATED_TITLES.get(fname)
|
||||
if curated:
|
||||
return cls(
|
||||
filename=fname,
|
||||
base_title=curated["title"],
|
||||
tags_extra=curated.get("tags_extra", []),
|
||||
)
|
||||
stem = Path(fname).stem
|
||||
stem = re.sub(r'^\d+[._\-\s]*', '', stem)
|
||||
stem = stem.replace('_', ' ').replace(' ', ' ').strip()
|
||||
|
||||
extra = []
|
||||
for kw, tags in KEYWORD_TAGS.items():
|
||||
if kw in stem:
|
||||
extra.extend(tags)
|
||||
extra = list(dict.fromkeys(extra))[:4]
|
||||
|
||||
return cls(filename=fname, base_title=stem or fname, tags_extra=extra)
|
||||
|
||||
def _smart_tags(self, platform: str) -> list[str]:
|
||||
seen = set()
|
||||
result = []
|
||||
for t in self.tags_extra + COMMON_TAGS:
|
||||
if t not in seen:
|
||||
seen.add(t)
|
||||
result.append(t)
|
||||
return result[:8]
|
||||
|
||||
def title(self, platform: str, max_len: int = 80) -> str:
|
||||
t = filter_for_platform(self.base_title, platform)
|
||||
return t[:max_len]
|
||||
|
||||
def title_short(self, max_len: int = 20) -> str:
|
||||
"""小红书标题(≤20字)"""
|
||||
parts = re.split(r'[,,!!??\s]+', self.base_title)
|
||||
return parts[0][:max_len] if parts else self.base_title[:max_len]
|
||||
|
||||
def hashtags(self, platform: str) -> str:
|
||||
"""# 标签字符串"""
|
||||
tags = self._smart_tags(platform)
|
||||
parts = [f"#{t}" for t in tags]
|
||||
parts.append(MINI_PROGRAM)
|
||||
return " ".join(parts)
|
||||
|
||||
def description(self, platform: str, max_len: int = 500) -> str:
|
||||
"""完整描述 = 标题 + 换行 + 标签 + 品牌"""
|
||||
title = self.title(platform)
|
||||
tags = self.hashtags(platform)
|
||||
desc = f"{title}\n\n{tags}"
|
||||
return filter_for_platform(desc[:max_len], platform)
|
||||
|
||||
def tags_list(self, platform: str) -> list[str]:
|
||||
return self._smart_tags(platform)
|
||||
|
||||
def tags_str(self, platform: str) -> str:
|
||||
"""逗号分隔(B站 API 用)"""
|
||||
return ",".join(self._smart_tags(platform))
|
||||
|
||||
def category(self, platform: str) -> dict:
|
||||
return PLATFORM_CATEGORIES.get(platform, {})
|
||||
|
||||
def bilibili_meta(self) -> dict:
|
||||
"""B站投稿需要的完整 meta"""
|
||||
return {
|
||||
"copyright": 1,
|
||||
"source": "",
|
||||
"desc": self.description("B站"),
|
||||
"desc_format_id": 0,
|
||||
"dynamic": "",
|
||||
"interactive": 0,
|
||||
"open_elec": 0,
|
||||
"no_reprint": 1,
|
||||
"subtitles": {"lan": "", "open": 0},
|
||||
"tag": self.tags_str("B站"),
|
||||
"tid": 160,
|
||||
"title": self.title("B站", 80),
|
||||
"up_close_danmaku": False,
|
||||
"up_close_reply": False,
|
||||
}
|
||||
|
||||
|
||||
def generate_all_meta(video_dir: str) -> list[VideoMeta]:
|
||||
"""批量生成目录下所有视频的元数据"""
|
||||
videos = sorted(Path(video_dir).glob("*.mp4"))
|
||||
return [VideoMeta.from_filename(str(v)) for v in videos]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from pathlib import Path
|
||||
VIDEO_DIR = "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片"
|
||||
metas = generate_all_meta(VIDEO_DIR)
|
||||
for m in metas:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"文件: {m.filename}")
|
||||
print(f" B站标题: {m.title('B站')}")
|
||||
print(f" B站简介: {m.description('B站')[:80]}...")
|
||||
print(f" B站标签: {m.tags_str('B站')}")
|
||||
print(f" 视频号: {m.description('视频号')[:80]}...")
|
||||
print(f" 小红书标题: {m.title_short()}")
|
||||
@@ -35,6 +35,12 @@ UA = (
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
|
||||
)
|
||||
|
||||
sys.path.insert(0, str(SCRIPT_DIR.parent.parent / "多平台分发" / "脚本"))
|
||||
try:
|
||||
from video_metadata import VideoMeta
|
||||
except ImportError:
|
||||
VideoMeta = None
|
||||
|
||||
DESC_SUFFIX = " #小程序 卡若创业派对"
|
||||
CHUNK_SIZE = 8 * 1024 * 1024
|
||||
|
||||
@@ -407,7 +413,11 @@ async def publish_one(
|
||||
elapsed_sec=time.time() - t0,
|
||||
)
|
||||
|
||||
desc_full = title + DESC_SUFFIX
|
||||
if VideoMeta:
|
||||
vmeta = VideoMeta.from_filename(video_path)
|
||||
desc_full = vmeta.description("视频号")
|
||||
else:
|
||||
desc_full = title + DESC_SUFFIX
|
||||
print(f" 发表...", flush=True)
|
||||
post_resp = await create_post(
|
||||
cookie_str, desc_full, video_url, thumb_url, vinfo, fsize,
|
||||
|
||||
@@ -287,3 +287,4 @@
|
||||
| 2026-03-11 13:54:29 | 🔄 卡若AI 同步 2026-03-11 13:54 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-11 14:38:13 | 🔄 卡若AI 同步 2026-03-11 14:38 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-11 14:45:54 | 🔄 卡若AI 同步 2026-03-11 14:45 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-11 14:55:15 | 🔄 卡若AI 同步 2026-03-11 14:55 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
|
||||
@@ -290,3 +290,4 @@
|
||||
| 2026-03-11 13:54:29 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-11 13:54 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-11 14:38:13 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-11 14:38 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-11 14:45:54 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-11 14:45 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-11 14:55:15 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-11 14:55 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
|
||||
Reference in New Issue
Block a user