#!/usr/bin/env python3 """ 多平台内容发布脚本 将「待发布」的文章发布到各平台(知乎/公众号/小红书/B站/头条号) 支持单个 topic 生成发布包模式(--topic-id) """ import json, datetime, logging, sys, subprocess, time from pathlib import Path from typing import Dict, List import argparse PROJECT_ROOT = Path('/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran') sys.path.insert(0, str(PROJECT_ROOT)) DATA_DIR = PROJECT_ROOT / "automation" / "data" TOPICS_FILE = DATA_DIR / "sustainability_topics.json" RELEASES_DIR = DATA_DIR / "releases" LOGS_DIR = PROJECT_ROOT / "automation" / "logs" TODAY = datetime.datetime.now().strftime("%Y-%m-%d") logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler(LOGS_DIR / f"publisher_{TODAY}.log"), logging.StreamHandler() ] ) logger = logging.getLogger(__name__) # 命令行参数 parser = argparse.ArgumentParser(description='发布管理脚本') parser.add_argument('--topic-id', help='仅处理指定 topic ID') args = parser.parse_args() # 平台配置 PLATFORMS = { "zhihu": {"name": "知乎", "enabled": True, "template": "zhihu.html"}, "wechat": {"name": "微信公众号", "enabled": False, "template": "wechat.html"}, # 需手动授权 "xiaohongshu": {"name": "小红书", "enabled": True, "template": "xiaohongshu.html"}, "bilibili": {"name": "B站", "enabled": False, "template": "bilibili.html"}, # 规划中 "toutiao": {"name": "头条号", "enabled": False, "template": "toutiao.html"} # 规划中 } def load_topics() -> List[Dict]: with open(TOPICS_FILE, 'r', encoding='utf-8') as f: return json.load(f) def save_topics(topics: List[Dict]): with open(TOPICS_FILE, 'w', encoding='utf-8') as f: json.dump(topics, f, ensure_ascii=False, indent=2) def get_ready_topics() -> List[Dict]: topics = load_topics() ready = [t for t in topics if t.get('status') == '待发布'] ready.sort(key=lambda t: t.get('ready_at', ''), reverse=True) # 优先最新 return ready, topics def publish_to_xiaohongshu(html_path: Path, topic: Dict) -> bool: """小红书:复制HTML到发布目录(供手动发布)""" logger.info(f"准备小红书发布: {topic['id']}") try: publish_base = PROJECT_ROOT / "content" / "published" dest_dir = publish_base / topic['id'] / "手动发布" / "小红书" dest_dir.mkdir(parents=True, exist_ok=True) dest_html = dest_dir / "文章.html" import shutil shutil.copy2(html_path, dest_html) logger.info(f"✅ 小红书发布包就绪: {dest_dir}") return True, str(dest_dir) except Exception as e: logger.error(f"小红书发布准备失败: {e}") return False, None def publish_to_zhihu(html_path: Path, topic: Dict) -> bool: """知乎:复制HTML到发布目录""" logger.info(f"准备知乎发布: {topic['id']}") try: publish_base = PROJECT_ROOT / "content" / "published" dest_dir = publish_base / topic['id'] / "手动发布" / "知乎" dest_dir.mkdir(parents=True, exist_ok=True) dest_html = dest_dir / "文章.html" import shutil shutil.copy2(html_path, dest_html) logger.info(f"✅ 知乎发布包就绪: {dest_dir}") return True, str(dest_dir) except Exception as e: logger.error(f"知乎发布准备失败: {e}") return False, None def publish_to_wechat(html_path: Path, topic: Dict) -> bool: """微信公众号:复制HTML到发布目录""" logger.info(f"准备微信公众号发布: {topic['id']}") try: publish_base = PROJECT_ROOT / "content" / "published" dest_dir = publish_base / topic['id'] / "手动发布" / "微信公众号" dest_dir.mkdir(parents=True, exist_ok=True) dest_html = dest_dir / "文章.html" import shutil shutil.copy2(html_path, dest_html) logger.info(f"✅ 微信公众号发布包就绪: {dest_dir}") return True, str(dest_dir) except Exception as e: logger.error(f"微信公众号发布准备失败: {e}") return False, None def publish_to_platform(platform: str, html_path: Path, topic: Dict) -> (bool, str): """生成平台发布包(人工发布)""" if platform == "xiaohongshu": return publish_to_xiaohongshu(html_path, topic) elif platform == "zhihu": return publish_to_zhihu(html_path, topic) elif platform == "wechat": return publish_to_wechat(html_path, topic) else: logger.warning(f"平台 {platform} 暂未支持") return False, None def main(): logger.info("=== 多平台内容发布包生成开始 ===") ready, all_topics = get_ready_topics() if not ready: logger.info("没有待发布内容") sys.exit(0) # 如果指定了 topic-id,只处理该选题 if args.topic_id: ready = [t for t in ready if t['id'] == args.topic_id] if not ready: logger.info(f"未找到指定 topic ID: {args.topic_id}") sys.exit(0) results = [] for topic in ready: tid = topic['id'] title = topic.get('title', '')[:50] release_date = topic.get('ready_at', TODAY) release_dir = RELEASES_DIR / release_date platform_urls = topic.get('platform_urls', {}) for platform, config in PLATFORMS.items(): if not config['enabled']: continue # 检查是否已发布过 if platform in platform_urls and platform_urls[platform]: logger.info(f"跳过已发布: {tid} - {platform}") continue html_file = release_dir / platform / f"{platform}_{tid}_{platform}.html" if not html_file.exists(): logger.warning(f"HTML文件不存在: {html_file}") continue # 生成发布包(不自动发布) success, info = publish_to_platform(platform, html_file, topic) if success: results.append((tid, platform, info)) logger.info(f"✅ {tid} 发布包已准备: {platform}") else: logger.error(f"❌ {tid} 发布包准备失败: {platform}") # 汇总报告 summary_file = LOGS_DIR / f"publisher_summary_{TODAY}.json" summary = { "date": TODAY, "total_ready": len(ready), "packages_generated": len(results), "details": [{"topic_id": r[0], "platform": r[1], "path": r[2]} for r in results] } with open(summary_file, 'w', encoding='utf-8') as f: json.dump(summary, f, ensure_ascii=False, indent=2) logger.info(f"📦 发布包生成完成: {len(results)} 个平台发布包已就绪") print(f"PUBLISH_PACKAGES_READY: {len(results)} packages generated") sys.exit(0) if __name__ == "__main__": main()