🔄 卡若AI 同步 2026-03-23 13:49 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个

This commit is contained in:
2026-03-23 13:49:28 +08:00
parent cd15f98449
commit 9a0e32812d
12 changed files with 181 additions and 29 deletions

View File

@@ -1,7 +1,15 @@
{
"updated": "2026-03-23T01:48:25.039999+00:00",
"updated": "2026-03-23T05:45:13.875278+00:00",
"conversations": [
{
"对话ID": "aa70825b-eec2-4373-8c0f-86d550114599",
"名称": "下载视频号助手 macbook",
"项目": "微信管理",
"首条消息": "下载视频号助手 macbook",
"创建时间": "2026-03-23T05:43:55.225000+00:00",
"消息数量": 16
},
{
"对话ID": "98abcf81-b237-44b7-af5a-dfe6d5bcb0ed",
"名称": "卡路亚复盘推送功能讨论",
"项目": "飞书",

View File

@@ -73,8 +73,8 @@ ROWS = {
'129': [ 'AI手机金融坏账投流', 200, 0, 250, 14, 187, 4, 561, 21, 31 ],
# 130场 2026-03-21视频号直播结束页 02:25:49≈146min观众总数2278、最高在线355、新增关注4、总热度3、送礼1Soul推流无截图数据填0→脚本跳过第5行保留空
'130': [ 'Soul爆量脸视频号问微信', 146, 0, 2278, 0, 3, 1, 3, 4, 355 ],
# 131场 2026-03-23结束页 02:05:55≈126min观众总数1144、最高在线75、新增关注4点赞1595+评论498+分享12=2105;礼物/灵魂力/人均未给填0Soul推流无填0→跳过第5行
'131': [ '视频号中枢Soul哨兵', 126, 0, 1144, 0, 2105, 0, 0, 4, 75 ],
# 131场 2026-03-23文章口径场观2580/进房328/128min视频号结束页补关注4、最高在线75、点赞评论分享计互动;礼物灵魂力无截图填0
'131': [ '视频号中枢Soul哨兵', 128, 2580, 328, 0, 2105, 0, 0, 4, 75 ],
}
# 场次→按日期列填写时的日期(表头为当月日期 1~31
SESSION_DATE_COLUMN = {'105': '20', '106': '21', '107': '23', '113': '2', '114': '3', '115': '4', '116': '5', '117': '6', '118': '7', '119': '8', '124': '14', '126': '17', '127': '18', '128': '19', '129': '20', '130': '21', '131': '23'}
@@ -96,6 +96,8 @@ PARTY_VIDEO_LINKS = {
'127': 'https://cunkebao.feishu.cn/minutes/obcnhybw322112tad6916v8r',
'129': 'https://cunkebao.feishu.cn/minutes/obcnjb994323l12lhl448177',
'130': 'https://cunkebao.feishu.cn/minutes/obcnj1y95z73n53e8m6m1s3j',
# 131场urls_soul_party.txt 中紧接 130 的新妙记
'131': 'https://cunkebao.feishu.cn/minutes/obcnjzx7dyxco67btud7y8gz',
}
# 团队会议(飞书妙记)链接:场次 → 完整 URL填表时写入「团队会议」行对应列row 31
@@ -110,6 +112,7 @@ TEAM_MEETING_LINKS = {
'126': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcng991jg3114b2nj99548d',
'127': 'https://cunkebao.feishu.cn/minutes/obcnhxs8usi8c7n27a9f66ux',
'129': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcnjbn178iy6919od4119ww',
'131': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcnjzx7dyxco67btud7y8gz',
}
# 小程序当日运营数据:日期号 → {访问次数, 访客, 交易金额},填表时自动写入对应日期列

View File

@@ -1,11 +1,16 @@
#!/usr/bin/env python3
"""B站 Cookie 获取 - Playwright 扫码登录 → 保存 storage_state"""
import asyncio
import sys
from pathlib import Path
from playwright.async_api import async_playwright
COOKIE_FILE = Path(__file__).parent / "bilibili_storage_state.json"
LOGIN_URL = "https://passport.bilibili.com/login"
PROFILE_PLATFORM = "B站"
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "多平台分发" / "脚本"))
from browser_profile import get_browser_profile_dir
UA = (
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
@@ -14,14 +19,20 @@ UA = (
async def main():
profile_dir = get_browser_profile_dir(PROFILE_PLATFORM)
print("即将弹出浏览器,请用 B站 APP 扫码登录。")
print(f"固定浏览器目录: {profile_dir}")
print("登录成功后(看到创作中心页面),按 Enter 或在 Inspector 点绿色 ▶。\n")
async with async_playwright() as pw:
browser = await pw.chromium.launch(headless=False)
context = await browser.new_context(user_agent=UA, viewport={"width": 1280, "height": 720})
context = await pw.chromium.launch_persistent_context(
str(profile_dir),
headless=False,
user_agent=UA,
viewport={"width": 1280, "height": 720},
)
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
page = await context.new_page()
page = context.pages[0] if context.pages else await context.new_page()
await page.goto(LOGIN_URL, timeout=60000)
print("等待登录完成...")
@@ -33,7 +44,6 @@ async def main():
await context.storage_state(path=str(COOKIE_FILE))
await context.close()
await browser.close()
print(f"\n[✓] B站 Cookie 已保存: {COOKIE_FILE}")
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""多平台分发统一浏览器配置。"""
from __future__ import annotations
import os
from pathlib import Path
PROFILE_ROOT = Path(
os.environ.get("SOUL_DISTRIBUTION_BROWSER_ROOT", "~/.soul-distribution-browser")
).expanduser()
_PLATFORM_DIR = {
"视频号": "channels",
"抖音": "douyin",
"B站": "bilibili",
"小红书": "xiaohongshu",
"快手": "kuaishou",
}
def get_browser_profile_dir(platform: str) -> Path:
"""返回平台固定 Profile 目录(自动创建)。"""
name = _PLATFORM_DIR.get(platform, platform)
p = PROFILE_ROOT / name
p.mkdir(parents=True, exist_ok=True)
return p
def profile_root_str() -> str:
return str(PROFILE_ROOT)

View File

@@ -50,8 +50,70 @@ from schedule_generator import (
format_schedule,
)
from video_metadata import VideoMeta
from browser_profile import get_browser_profile_dir, profile_root_str
CHANNELS_LOGIN_SCRIPT = BASE_DIR / "视频号发布" / "脚本" / "channels_login.py"
LOGIN_COMMANDS = {
"抖音": f'python3 "{BASE_DIR / "抖音发布" / "脚本" / "douyin_login.py"}"',
"B站": f'python3 "{BASE_DIR / "B站发布" / "脚本" / "bilibili_login.py"}"',
"视频号": f'python3 "{BASE_DIR / "视频号发布" / "脚本" / "channels_login.py"} --playwright-only"',
"小红书": f'python3 "{BASE_DIR / "小红书发布" / "脚本" / "xiaohongshu_login.py"}"',
"快手": f'python3 "{BASE_DIR / "快手发布" / "脚本" / "kuaishou_login.py"}"',
}
BAN_KEYWORDS = ("封禁", "封号", "禁止", "冻结", "suspend", "banned", "risk", "风控", "限制")
def _print_unified_browser_profiles() -> None:
print(f"\n 统一浏览器根目录: {profile_root_str()}")
for p in PLATFORM_CONFIG:
print(f" - {p}: {get_browser_profile_dir(p)}")
def _classify_platform_status(
platform: str,
platform_results: list[PublishResult],
) -> tuple[str, str]:
if not platform_results:
ok, msg = check_cookie_valid(platform)
if ok:
return "空闲/未执行", "本轮未执行该平台发布"
return "需重登", f"Cookie 无效:{msg}"
successes = [r for r in platform_results if r.success]
failures = [r for r in platform_results if not r.success]
failure_msgs = " | ".join((r.message or "").lower() for r in failures)
if any(k in failure_msgs for k in BAN_KEYWORDS):
return "疑似封禁/风控", "失败信息包含封禁/风控关键词"
if successes and not failures:
return "正常", f"成功 {len(successes)}/{len(platform_results)}"
if failures and not successes:
ok, msg = check_cookie_valid(platform)
if not ok:
return "需重登", f"Cookie 无效:{msg}"
return "持续失败", f"失败 {len(failures)} 条,需人工排查平台侧限制"
if failures:
return "部分失败", f"成功 {len(successes)} / 失败 {len(failures)}"
return "正常", f"成功 {len(successes)}/{len(platform_results)}"
def print_platform_account_status(all_results: list[PublishResult], targets: list[str]) -> None:
print(f"\n{'=' * 60}")
print(" 平台账号状态复盘")
print(f"{'=' * 60}")
regroup: dict[str, list[PublishResult]] = {p: [] for p in targets}
for r in all_results:
if r.platform in regroup and r.status != "skipped":
regroup[r.platform].append(r)
for p in targets:
status, detail = _classify_platform_status(p, regroup[p])
print(f" [{p}] {status} | {detail}")
if status in ("需重登", "持续失败", "疑似封禁/风控"):
cmd = LOGIN_COMMANDS.get(p, "")
if cmd:
print(f" 重登命令: {cmd}")
print(f"{'=' * 60}\n")
def _ensure_channels_cookie_or_login(*, auto_login: bool) -> None:
@@ -433,6 +495,8 @@ async def main():
)
args = parser.parse_args()
_print_unified_browser_profiles()
if not args.allow_ui_browser:
os.environ.setdefault("PUBLISH_PLAYWRIGHT_HEADLESS", "1")
@@ -525,9 +589,8 @@ async def _publish_one_round(args: argparse.Namespace) -> tuple[int, int]:
if not available:
print("\n[✗] 没有可用平台,请先登录:")
for p, c in PLATFORM_CONFIG.items():
login = str(c["script"]).replace("publish", "login").replace("pure_api", "login")
print(f" {p}: python3 {login}")
for p in PLATFORM_CONFIG:
print(f" {p}: {LOGIN_COMMANDS.get(p, '(未配置)')}")
return 1, 9999
targets = args.platforms if args.platforms else available
@@ -613,6 +676,7 @@ async def _publish_one_round(args: argparse.Namespace) -> tuple[int, int]:
print(f"\n{failed_count} 条失败,可执行: python3 distribute_all.py --retry")
failed_non_success = sum(1 for r in actual_results if not r.success)
print_platform_account_status(actual_results, targets)
return (0 if ok == total else 1), failed_non_success

View File

@@ -17,6 +17,9 @@ import time
from pathlib import Path
BASE = Path("/Users/karuo/Documents/个人/卡若AI/03_卡木/木叶_视频内容")
sys.path.insert(0, str(BASE / "多平台分发" / "脚本"))
from browser_profile import get_browser_profile_dir
UA = (
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"
@@ -96,14 +99,13 @@ async def headless_login(platform: str) -> bool:
print(f"{'='*60}")
async with async_playwright() as pw:
browser = await pw.chromium.launch(
context = await pw.chromium.launch_persistent_context(
str(get_browser_profile_dir(platform)),
headless=True,
args=["--disable-blink-features=AutomationControlled"],
)
context = await browser.new_context(
user_agent=UA,
viewport={"width": 1280, "height": 900},
locale="zh-CN",
args=["--disable-blink-features=AutomationControlled"],
)
await context.add_init_script(
"Object.defineProperty(navigator,'webdriver',{get:()=>undefined})"
@@ -189,7 +191,7 @@ async def headless_login(platform: str) -> bool:
await context.storage_state(path=str(cookie_file))
size = cookie_file.stat().st_size
await browser.close()
await context.close()
# API 验证
print(f" [4] API 验证 Cookie...", flush=True)
@@ -203,7 +205,7 @@ async def headless_login(platform: str) -> bool:
else:
print(f" [✗] {platform} 登录超时5分钟", flush=True)
await page.screenshot(path=f"/tmp/login_timeout_{platform}.png")
await browser.close()
await context.close()
return False

View File

@@ -1,11 +1,16 @@
#!/usr/bin/env python3
"""小红书 Cookie 获取 - Playwright 登录 → 保存 storage_state"""
import asyncio
import sys
from pathlib import Path
from playwright.async_api import async_playwright
COOKIE_FILE = Path(__file__).parent / "xiaohongshu_storage_state.json"
LOGIN_URL = "https://creator.xiaohongshu.com/login"
PROFILE_PLATFORM = "小红书"
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "多平台分发" / "脚本"))
from browser_profile import get_browser_profile_dir
UA = (
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
@@ -14,15 +19,21 @@ UA = (
async def main():
profile_dir = get_browser_profile_dir(PROFILE_PLATFORM)
print("即将弹出浏览器,请登录小红书创作者中心。")
print("支持扫码或手机号+验证码登录。")
print(f"固定浏览器目录: {profile_dir}")
print("登录成功后(看到创作者中心主页),按 Enter 或在 Inspector 点绿色 ▶。\n")
async with async_playwright() as pw:
browser = await pw.chromium.launch(headless=False)
context = await browser.new_context(user_agent=UA, viewport={"width": 1280, "height": 720})
context = await pw.chromium.launch_persistent_context(
str(profile_dir),
headless=False,
user_agent=UA,
viewport={"width": 1280, "height": 720},
)
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
page = await context.new_page()
page = context.pages[0] if context.pages else await context.new_page()
await page.goto(LOGIN_URL, timeout=60000)
print("等待登录完成...")
@@ -35,7 +46,6 @@ async def main():
await context.storage_state(path=str(COOKIE_FILE))
await context.close()
await browser.close()
print(f"\n[✓] 小红书 Cookie 已保存: {COOKIE_FILE}")
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")

View File

@@ -1,11 +1,16 @@
#!/usr/bin/env python3
"""快手 Cookie 获取 - Playwright 扫码登录 → 保存 storage_state"""
import asyncio
import sys
from pathlib import Path
from playwright.async_api import async_playwright
COOKIE_FILE = Path(__file__).parent / "kuaishou_storage_state.json"
LOGIN_URL = "https://cp.kuaishou.com/article/publish/video"
PROFILE_PLATFORM = "快手"
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "多平台分发" / "脚本"))
from browser_profile import get_browser_profile_dir
UA = (
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
@@ -14,14 +19,20 @@ UA = (
async def main():
profile_dir = get_browser_profile_dir(PROFILE_PLATFORM)
print("即将弹出浏览器,请用快手 APP 扫码登录创作者服务平台。")
print(f"固定浏览器目录: {profile_dir}")
print("登录成功后(看到创作中心页面),按 Enter 或在 Inspector 点绿色 ▶。\n")
async with async_playwright() as pw:
browser = await pw.chromium.launch(headless=False)
context = await browser.new_context(user_agent=UA, viewport={"width": 1280, "height": 720})
context = await pw.chromium.launch_persistent_context(
str(profile_dir),
headless=False,
user_agent=UA,
viewport={"width": 1280, "height": 720},
)
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
page = await context.new_page()
page = context.pages[0] if context.pages else await context.new_page()
await page.goto(LOGIN_URL, timeout=60000)
print("等待扫码登录...\n")
@@ -49,7 +60,6 @@ async def main():
await context.storage_state(path=str(COOKIE_FILE))
await context.close()
await browser.close()
print(f"\n[✓] 快手 Cookie 已保存: {COOKIE_FILE}")
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")

View File

@@ -4,19 +4,27 @@
扫码后无需手动操作,脚本自动检测登录状态并保存。
"""
import asyncio
import sys
from pathlib import Path
from playwright.async_api import async_playwright
COOKIE_FILE = Path(__file__).parent / "douyin_storage_state.json"
PROFILE_PLATFORM = "抖音"
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "多平台分发" / "脚本"))
from browser_profile import get_browser_profile_dir
async def main():
profile_dir = get_browser_profile_dir(PROFILE_PLATFORM)
print("即将弹出浏览器,请用抖音 APP 扫码登录。")
print(f"固定浏览器目录: {profile_dir}")
print("登录成功后脚本会自动保存 Cookie无需手动操作。\n")
async with async_playwright() as pw:
browser = await pw.chromium.launch(headless=False)
context = await browser.new_context(
context = await pw.chromium.launch_persistent_context(
str(profile_dir),
headless=False,
user_agent=(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
@@ -27,7 +35,7 @@ async def main():
await context.add_init_script("""
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
""")
page = await context.new_page()
page = context.pages[0] if context.pages else await context.new_page()
await page.goto("https://creator.douyin.com/", timeout=60000)
print("[i] 等待扫码登录... (最长等待 120 秒)")
@@ -56,7 +64,6 @@ async def main():
await asyncio.sleep(2)
await context.storage_state(path=str(COOKIE_FILE))
await context.close()
await browser.close()
print(f"\n[✓] Cookie 已保存到: {COOKIE_FILE}")
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")

View File

@@ -22,8 +22,14 @@ QR_SCREENSHOT = Path("/tmp/channels_qr.png")
DEFAULT_CDP = os.environ.get("CHANNELS_CDP_URL", "http://127.0.0.1:9223")
# 持久化 Chromium同目录保留登录态显著减少重复扫码腾讯侧过期/风控时仍需重登)
sys.path.insert(0, str(SCRIPT_DIR.parent.parent / "多平台分发" / "脚本"))
from browser_profile import get_browser_profile_dir
PERSISTENT_PROFILE_DIR = Path(
os.environ.get("CHANNELS_CHROMIUM_USER_DATA", str(Path.home() / ".soul-channels-playwright-profile"))
os.environ.get(
"CHANNELS_CHROMIUM_USER_DATA",
str(get_browser_profile_dir("视频号")),
)
)
UA = (

View File

@@ -422,3 +422,4 @@
| 2026-03-22 14:38:11 | 🔄 卡若AI 同步 2026-03-22 14:38 | 更新Cursor规则、金仓、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 |
| 2026-03-22 21:22:06 | 🔄 卡若AI 同步 2026-03-22 21:22 | 更新Cursor规则、金仓、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 |
| 2026-03-23 09:48:42 | [强制] 🔄 卡若AI 同步 2026-03-23 09:48 | 更新Cursor规则、金仓、水桥平台对接、卡木、火炬、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 |
| 2026-03-23 13:36:13 | [强制] 🔄 卡若AI 同步 2026-03-23 13:35 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 |

View File

@@ -425,3 +425,4 @@
| 2026-03-22 14:38:11 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-22 14:38 | 更新Cursor规则、金仓、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-03-22 21:22:06 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-22 21:22 | 更新Cursor规则、金仓、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-03-23 09:48:42 | 成功(强制) | 成功 | 🔄 卡若AI 同步 2026-03-23 09:48 | 更新Cursor规则、金仓、水桥平台对接、卡木、火炬、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-03-23 13:36:13 | 成功(强制) | 成功 | 🔄 卡若AI 同步 2026-03-23 13:35 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |