初始化提交:contentm_agent 工作区全量快照

内容分四块:
1、产品规划产出 —— MCN 短视频整合营销工作台的①段五份(1a 需求/1b 竞品/1c 画像/1d 策略/1e 场景)、②段两份(2a 功能/2b 布局)、③段界面(DESIGN.md 契约与令牌表 + mcn-workbench.html 原型 + 实测/会诊/审查三份 + 23 张闸门截图)。
2、开源竞品调研 —— 5 个内容工作台项目的取证原始件与 1b 系列分析文档。
3、参考资料 —— 竞品视频抽帧 1145 张 + 2 个源视频 + 功能点截图。
4、机制侧 —— 协作脚本与状态台账、工作区记忆日志、抽帧/OCR 脚本。

.gitignore 只排运行时日志、脚本备份副本与一次性探针输出,其余按原样入库。
This commit is contained in:
WorkBuddy committed 2026-10-08 08:13:02 +08:00
commit df56c2c137
1773 files changed
+205840

No files matched your search

@@ -0,0 +1,50 @@
# scripts 目录说明
辅助脚本清单与用法。
## check_env.py
投放环境检查:POSTIZ_API_KEY、sau 命令、Python 版本、requests 库。
```bash
python check_env.py
```
返回码:0=双通道就绪,1=有缺失项。投放流程步骤 3 开始时运行。
## postiz_client.py
Postiz REST API 封装(标准库 + requests),用于海外投放:
```bash
# 列出已连接渠道(取 integration id)
python postiz_client.py integrations
# 上传视频文件(返回 URL)
python postiz_client.py upload D:/videos/demo.mp4
# 创建/排期/发布(请求体为 JSON 文件)
python postiz_client.py posts post_body.json
# 查询时间段内帖子
python postiz_client.py query 2026-08-30T00:00:00.000Z 2026-08-31T00:00:00.000Z
```
**凭证**:环境变量 `POSTIZ_API_KEY`(必填),`POSTIZ_API_BASE` 可覆盖(自托管实例)。
post_body.json 示例:
```json
{
"type": "now",
"posts": [
{
"integration": {"id": "yt-integration-id"},
"value": [{"content": "视频简介", "image": []}],
"settings": {"__type": "youtube", "title": "视频标题", "type": "public"}
}
]
}
```
> 依赖安装:`pip install requests`(upload 子命令需要)。
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""投放环境检查脚本:检查海外(Postiz)与国内(SAU)通道依赖。
用法:python check_env.py
"""
import os
import shutil
import sys
GREEN = "\033[32m"
YELLOW = "\033[33m"
RED = "\033[31m"
RESET = "\033[0m"
def check(label, ok, detail=""):
if ok:
print(f" {GREEN}[OK]{RESET} {label} {detail}")
else:
print(f" {RED}[X ]{RESET} {label} {detail}")
return ok
def main():
print("=== 社媒视频多平台投放 - 环境检查 ===\n")
# Python
py_ok = sys.version_info >= (3, 10)
check("Python >= 3.10", py_ok, sys.version.split()[0])
# 海外通道:Postiz
print("\n[海外通道 Postiz]")
key = os.environ.get("POSTIZ_API_KEY", "").strip()
check("POSTIZ_API_KEY 已设置", bool(key), "" if key else "→ postiz.com → Settings → Developers → Public API 生成")
# 国内通道:SAU
print("\n[国内通道 social-auto-upload]")
sau = shutil.which("sau")
check("sau 命令可用", sau is not None, f"({sau})" if sau else "→ git clone github.com/dreammis/social-auto-upload && pip install -r requirements.txt")
# 辅助脚本依赖
print("\n[脚本依赖]")
try:
import requests # noqa
check("requests 库", True)
except ImportError:
check("requests 库", False, "→ pip install requests(postiz_client.py upload 需要)")
print("\n=== 结论 ===")
missing = []
if not key:
missing.append("海外通道:配置 POSTIZ_API_KEY")
if sau is None:
missing.append("国内通道:安装 social-auto-upload")
if missing:
print(f" {YELLOW}需处理{RESET}:")
for m in missing:
print(f" - {m}")
else:
print(f" {GREEN}双通道就绪,可进行投放{RESET}")
return 0 if not missing else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Postiz REST API 客户端封装(海外投放通道)。
依赖:requests(pip install requests)
凭证:环境变量 POSTIZ_API_KEY(禁止硬编码)
用法:
python postiz_client.py integrations # 列出已连接渠道
python postiz_client.py upload <video_path> # 上传视频,返回 URL
python postiz_client.py posts <json_file> # 创建/排期/发布(JSON 文件为请求体)
python postiz_client.py query <start> <end> # 查询时间段帖子(ISO UTC)
"""
import json
import os
import sys
import urllib.request
import urllib.error
BASE = os.environ.get("POSTIZ_API_BASE", "https://api.postiz.com/public/v1")
def get_key():
key = os.environ.get("POSTIZ_API_KEY", "").strip()
if not key:
print("ERROR: 环境变量 POSTIZ_API_KEY 未设置。请在 postiz.com → Settings → Developers → Public API 生成后配置。")
sys.exit(2)
return key
def request(method, path, body=None):
key = get_key()
url = BASE + path
data = json.dumps(body).encode("utf-8") if body is not None else None
req = urllib.request.Request(url, data=data, method=method)
req.add_header("Authorization", key)
if data:
req.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(req) as resp:
return resp.status, json.loads(resp.read().decode("utf-8") or "null")
except urllib.error.HTTPError as e:
detail = e.read().decode("utf-8", "ignore")[:500]
return e.code, {"error": detail}
def cmd_integrations():
status, data = request("GET", "/integrations")
print(f"[{status}]")
if isinstance(data, list):
for it in data:
print(f" {it.get('id', '?')} | {it.get('name', it.get('provider', '?'))}")
else:
print(json.dumps(data, ensure_ascii=False, indent=2)[:2000])
def cmd_upload(path):
if not os.path.exists(path):
print(f"ERROR: 文件不存在: {path}")
sys.exit(3)
# 上传走 multipart;此处用 requests 更稳,urllib 需要手写 multipart。
# 建议使用 requests 库:
try:
import requests # noqa
except ImportError:
print("ERROR: 需要 requests 库:pip install requests")
sys.exit(2)
key = get_key()
with open(path, "rb") as f:
resp = requests.post(
BASE + "/upload",
headers={"Authorization": key},
files={"file": (os.path.basename(path), f)},
timeout=600,
)
print(f"[{resp.status_code}]")
print(resp.text[:2000])
def cmd_posts(json_file):
if not os.path.exists(json_file):
print(f"ERROR: 请求体文件不存在: {json_file}")
sys.exit(3)
with open(json_file, "r", encoding="utf-8") as f:
body = json.load(f)
status, data = request("POST", "/posts", body)
print(f"[{status}]")
print(json.dumps(data, ensure_ascii=False, indent=2)[:3000])
def cmd_query(start, end):
status, data = request("GET", f"/posts?startDate={start}&endDate={end}")
print(f"[{status}]")
print(json.dumps(data, ensure_ascii=False, indent=2)[:3000])
def main():
args = sys.argv[1:]
if not args:
print(__doc__)
sys.exit(0)
cmd, rest = args[0], args[1:]
if cmd == "integrations":
cmd_integrations()
elif cmd == "upload" and rest:
cmd_upload(rest[0])
elif cmd == "posts" and rest:
cmd_posts(rest[0])
elif cmd == "query" and len(rest) >= 2:
cmd_query(rest[0], rest[1])
else:
print(__doc__)
sys.exit(1)
if __name__ == "__main__":
main()