🔄 卡若AI 同步 2026-03-10 15:02 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个
This commit is contained in:
@@ -15,7 +15,7 @@ COOKIE_FILE = SCRIPT_DIR / "bilibili_storage_state.json"
|
||||
VIDEO_DIR = Path("/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片")
|
||||
|
||||
sys.path.insert(0, str(SCRIPT_DIR.parent.parent / "多平台分发" / "脚本"))
|
||||
from publish_result import PublishResult
|
||||
from publish_result import PublishResult, is_published
|
||||
|
||||
UA = (
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||
@@ -264,13 +264,18 @@ async def _playwright_publish(video_path: str, title: str) -> PublishResult:
|
||||
)
|
||||
|
||||
|
||||
async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1) -> PublishResult:
|
||||
async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1, skip_dedup: bool = False) -> PublishResult:
|
||||
"""API 优先 → Playwright 兜底"""
|
||||
fname = Path(video_path).name
|
||||
fsize = Path(video_path).stat().st_size
|
||||
print(f"\n[{idx}/{total}] {fname} ({fsize/1024/1024:.1f}MB)", flush=True)
|
||||
print(f" 标题: {title[:60]}", flush=True)
|
||||
|
||||
if not skip_dedup and is_published("B站", video_path):
|
||||
print(f" [跳过] 该视频已发布到B站", flush=True)
|
||||
return PublishResult(platform="B站", video_path=video_path, title=title,
|
||||
success=True, status="skipped", message="去重跳过(已发布)")
|
||||
|
||||
if not COOKIE_FILE.exists():
|
||||
return PublishResult(
|
||||
platform="B站", video_path=video_path, title=title,
|
||||
|
||||
@@ -5,3 +5,17 @@
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/早起不是为了开派对,是不吵老婆睡觉.mp4", "title": "每天6点起床不是因为自律,是因为老婆还在睡 #Soul派对 #创业日记", "success": true, "status": "reviewing", "message": "已提交,请确认截图", "screenshot": "/tmp/xhs_result.png", "elapsed_sec": 33.28828287124634, "timestamp": "2026-03-10 14:17:35"}
|
||||
{"platform": "快手", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/早起不是为了开派对,是不吵老婆睡觉.mp4", "title": "每天6点起床不是因为自律,是因为老婆还在睡 #Soul派对 #创业日记", "success": true, "status": "published", "message": "发布成功", "screenshot": "/tmp/kuaishou_result.png", "elapsed_sec": 41.6892192363739, "timestamp": "2026-03-10 14:17:43"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/早起不是为了开派对,是不吵老婆睡觉.mp4", "title": "每天6点起床不是因为自律,是因为老婆还在睡 #Soul派对 #创业日记", "success": true, "status": "reviewing", "message": "已跳转到内容管理(发表成功)", "screenshot": "/tmp/channels_result.png", "elapsed_sec": 25.486361026763916, "timestamp": "2026-03-10 14:17:27"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/ICU出来一年多 活着要在互联网上留下东西.mp4", "title": "ICU出来一年多,活着就要在互联网上留下东西 #人生感悟 #创业觉醒", "success": true, "status": "published", "message": "页面已重置(发布成功)", "screenshot": "/tmp/xhs_result.png", "elapsed_sec": 23.01875376701355, "timestamp": "2026-03-10 15:00:58"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/MBTI疗愈SOUL 年轻人测MBTI,40到60岁走五行八卦.mp4", "title": "20岁测MBTI,40岁该学五行八卦了 #MBTI #认知觉醒", "success": true, "status": "reviewing", "message": "已提交,请确认截图", "screenshot": "/tmp/xhs_result.png", "elapsed_sec": 22.772515773773193, "timestamp": "2026-03-10 15:01:24"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/Soul业务模型 派对+切片+小程序全链路.mp4", "title": "派对获客→AI切片→小程序变现,全链路拆解 #商业模式 #一人公司", "success": false, "status": "error", "message": "异常: [Errno 32] Broken pipe", "elapsed_sec": 13.620775938034058, "timestamp": "2026-03-10 15:01:41"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/Soul切片30秒到8分钟 AI半小时能剪10到30个.mp4", "title": "AI剪辑半小时出10到30条切片,内容工厂效率密码 #AI剪辑 #内容效率", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:01:44"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/初期团队先找两个IS,比钱好使 ENFJ链接人,ENTJ指挥.mp4", "title": "创业初期先找两个IS型人格,比融资好使十倍 #MBTI创业 #团队搭建", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:01:47"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/刷牙听业务逻辑 Soul切片变现怎么跑.mp4", "title": "刷牙3分钟听完一套变现逻辑 #碎片创业 #副业逻辑", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:01:50"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/国学易经怎么学 两小时七七八八,召唤作者对话.mp4", "title": "易经两小时学个七七八八,关键是跟古人对话 #国学 #易经入门", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:01:53"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/广点通能投Soul了,1000曝光6到10块.mp4", "title": "广点通能投Soul了!1000曝光只要6到10块 #广点通 #低成本获客", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:01:56"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/建立信任不是求来的 卖外挂发邮件三个月拿下德国总代.mp4", "title": "信任不是求来的,发三个月邮件拿下德国总代理 #销售思维 #信任建立", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:01:59"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/懒人的活法 动作简单有利可图正反馈.mp4", "title": "懒人也能赚钱?动作简单、有利可图、正反馈 #Soul派对 #副业思维", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:02:02"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/核心就两个字 筛选。能开派对坚持7天的人再谈.mp4", "title": "核心就两个字:筛选。能坚持7天的人才值得深聊 #筛选思维 #创业认知", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:02:05"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/睡眠不好?每天放下一件事,做减法.mp4", "title": "睡不好不是太累,是脑子装太多,每天做减法 #做减法 #心理健康", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:02:08"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/这套体系花了170万,但前端几十块就能参与.mp4", "title": "后端花170万搭体系,前端几十块就能参与 #商业认知 #体系思维", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:02:11"}
|
||||
{"platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 119场 20260309_output/成片/金融AI获客体系 后端30人沉淀12年,前端丢手机.mp4", "title": "后端30人沉淀12年,前端就丢个手机号 #AI获客 #系统思维", "success": false, "status": "error", "message": "[Errno 32] Broken pipe", "elapsed_sec": 0.0, "timestamp": "2026-03-10 15:02:14"}
|
||||
|
||||
@@ -62,6 +62,12 @@ def load_published_set() -> set[tuple[str, str]]:
|
||||
return published
|
||||
|
||||
|
||||
def is_published(platform: str, video_path: str) -> bool:
|
||||
"""检查某条视频是否已成功发布到某平台(供各平台脚本直接调用)"""
|
||||
fname = Path(video_path).name
|
||||
return (platform, fname) in load_published_set()
|
||||
|
||||
|
||||
def load_failed_tasks() -> list[dict]:
|
||||
"""加载失败任务列表(用于重试)"""
|
||||
failed = []
|
||||
|
||||
@@ -54,8 +54,9 @@ TITLES = {
|
||||
}
|
||||
|
||||
|
||||
async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1) -> PublishResult:
|
||||
async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1, skip_dedup: bool = False) -> PublishResult:
|
||||
from playwright.async_api import async_playwright
|
||||
from publish_result import is_published
|
||||
|
||||
fname = Path(video_path).name
|
||||
fsize = Path(video_path).stat().st_size
|
||||
@@ -63,6 +64,11 @@ async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1)
|
||||
print(f"\n[{idx}/{total}] {fname} ({fsize/1024/1024:.1f}MB)", flush=True)
|
||||
print(f" 标题: {title[:60]}", flush=True)
|
||||
|
||||
if not skip_dedup and is_published("小红书", video_path):
|
||||
print(f" [跳过] 该视频已发布到小红书", flush=True)
|
||||
return PublishResult(platform="小红书", video_path=video_path, title=title,
|
||||
success=True, status="skipped", message="去重跳过(已发布)")
|
||||
|
||||
if not COOKIE_FILE.exists():
|
||||
return PublishResult(platform="小红书", video_path=video_path, title=title,
|
||||
success=False, status="error", message="Cookie 不存在")
|
||||
@@ -217,6 +223,8 @@ async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1)
|
||||
|
||||
|
||||
async def main():
|
||||
from publish_result import print_summary, save_results
|
||||
|
||||
if not COOKIE_FILE.exists():
|
||||
print("[✗] Cookie 不存在")
|
||||
return 1
|
||||
@@ -227,17 +235,19 @@ async def main():
|
||||
return 1
|
||||
print(f"共 {len(videos)} 条视频\n")
|
||||
|
||||
ok_count = 0
|
||||
results = []
|
||||
for i, vp in enumerate(videos):
|
||||
t = TITLES.get(vp.name, f"{vp.stem} #Soul派对 #创业日记")
|
||||
ok = await publish_one(str(vp), t, i + 1, len(videos))
|
||||
if ok:
|
||||
ok_count += 1
|
||||
r = await publish_one(str(vp), t, i + 1, len(videos))
|
||||
results.append(r)
|
||||
if i < len(videos) - 1:
|
||||
await asyncio.sleep(5)
|
||||
|
||||
print(f"\n成功: {ok_count}/{len(videos)}")
|
||||
return 0 if ok_count == len(videos) else 1
|
||||
actual = [r for r in results if r.status != "skipped"]
|
||||
print_summary(actual)
|
||||
save_results(actual)
|
||||
ok = sum(1 for r in actual if r.success)
|
||||
return 0 if ok == len(actual) else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -54,8 +54,9 @@ TITLES = {
|
||||
}
|
||||
|
||||
|
||||
async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1) -> PublishResult:
|
||||
async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1, skip_dedup: bool = False) -> PublishResult:
|
||||
from playwright.async_api import async_playwright
|
||||
from publish_result import is_published
|
||||
|
||||
fname = Path(video_path).name
|
||||
fsize = Path(video_path).stat().st_size
|
||||
@@ -63,6 +64,11 @@ async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1)
|
||||
print(f"\n[{idx}/{total}] {fname} ({fsize/1024/1024:.1f}MB)", flush=True)
|
||||
print(f" 标题: {title[:60]}", flush=True)
|
||||
|
||||
if not skip_dedup and is_published("快手", video_path):
|
||||
print(f" [跳过] 该视频已发布到快手", flush=True)
|
||||
return PublishResult(platform="快手", video_path=video_path, title=title,
|
||||
success=True, status="skipped", message="去重跳过(已发布)")
|
||||
|
||||
if not COOKIE_FILE.exists():
|
||||
return PublishResult(platform="快手", video_path=video_path, title=title,
|
||||
success=False, status="error", message="Cookie 不存在")
|
||||
@@ -207,6 +213,8 @@ async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1)
|
||||
|
||||
|
||||
async def main():
|
||||
from publish_result import print_summary, save_results
|
||||
|
||||
if not COOKIE_FILE.exists():
|
||||
print("[✗] Cookie 不存在")
|
||||
return 1
|
||||
@@ -217,17 +225,19 @@ async def main():
|
||||
return 1
|
||||
print(f"共 {len(videos)} 条视频\n")
|
||||
|
||||
ok_count = 0
|
||||
results = []
|
||||
for i, vp in enumerate(videos):
|
||||
t = TITLES.get(vp.name, f"{vp.stem} #Soul派对 #创业日记")
|
||||
ok = await publish_one(str(vp), t, i + 1, len(videos))
|
||||
if ok:
|
||||
ok_count += 1
|
||||
r = await publish_one(str(vp), t, i + 1, len(videos))
|
||||
results.append(r)
|
||||
if i < len(videos) - 1:
|
||||
await asyncio.sleep(5)
|
||||
|
||||
print(f"\n成功: {ok_count}/{len(videos)}")
|
||||
return 0 if ok_count == len(videos) else 1
|
||||
actual = [r for r in results if r.status != "skipped"]
|
||||
print_summary(actual)
|
||||
save_results(actual)
|
||||
ok = sum(1 for r in actual if r.success)
|
||||
return 0 if ok == len(actual) else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -54,8 +54,9 @@ TITLES = {
|
||||
}
|
||||
|
||||
|
||||
async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1) -> PublishResult:
|
||||
async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1, skip_dedup: bool = False) -> PublishResult:
|
||||
from playwright.async_api import async_playwright
|
||||
from publish_result import is_published
|
||||
|
||||
fname = Path(video_path).name
|
||||
fsize = Path(video_path).stat().st_size
|
||||
@@ -63,6 +64,11 @@ async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1)
|
||||
print(f"\n[{idx}/{total}] {fname} ({fsize/1024/1024:.1f}MB)", flush=True)
|
||||
print(f" 标题: {title[:60]}", flush=True)
|
||||
|
||||
if not skip_dedup and is_published("视频号", video_path):
|
||||
print(f" [跳过] 该视频已发布到视频号", flush=True)
|
||||
return PublishResult(platform="视频号", video_path=video_path, title=title,
|
||||
success=True, status="skipped", message="去重跳过(已发布)")
|
||||
|
||||
if not COOKIE_FILE.exists():
|
||||
return PublishResult(platform="视频号", video_path=video_path, title=title,
|
||||
success=False, status="error", message="Cookie 不存在")
|
||||
@@ -199,6 +205,8 @@ async def publish_one(video_path: str, title: str, idx: int = 1, total: int = 1)
|
||||
|
||||
|
||||
async def main():
|
||||
from publish_result import print_summary, save_results
|
||||
|
||||
if not COOKIE_FILE.exists():
|
||||
print("[✗] Cookie 不存在")
|
||||
return 1
|
||||
@@ -209,17 +217,19 @@ async def main():
|
||||
return 1
|
||||
print(f"共 {len(videos)} 条视频\n")
|
||||
|
||||
ok_count = 0
|
||||
results = []
|
||||
for i, vp in enumerate(videos):
|
||||
t = TITLES.get(vp.name, f"{vp.stem} #Soul派对 #创业日记")
|
||||
ok = await publish_one(str(vp), t, i + 1, len(videos))
|
||||
if ok:
|
||||
ok_count += 1
|
||||
r = await publish_one(str(vp), t, i + 1, len(videos))
|
||||
results.append(r)
|
||||
if i < len(videos) - 1:
|
||||
await asyncio.sleep(5)
|
||||
|
||||
print(f"\n成功: {ok_count}/{len(videos)}")
|
||||
return 0 if ok_count == len(videos) else 1
|
||||
actual = [r for r in results if r.status != "skipped"]
|
||||
print_summary(actual)
|
||||
save_results(actual)
|
||||
ok = sum(1 for r in actual if r.success)
|
||||
return 0 if ok == len(actual) else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -261,3 +261,4 @@
|
||||
| 2026-03-10 12:54:57 | 🔄 卡若AI 同步 2026-03-10 12:54 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-10 13:34:41 | 🔄 卡若AI 同步 2026-03-10 13:34 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-10 13:48:50 | 🔄 卡若AI 同步 2026-03-10 13:48 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-10 14:18:01 | 🔄 卡若AI 同步 2026-03-10 14:17 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
|
||||
@@ -264,3 +264,4 @@
|
||||
| 2026-03-10 12:54:57 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-10 12:54 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-10 13:34:41 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-10 13:34 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-10 13:48:50 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-10 13:48 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-10 14:18:01 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-10 14:17 | 更新:卡木、运营中枢工作台 | 排除 >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