Files
nanocode/skills/baoyu-post-to-wechat/baoyu_publish.py
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

185 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
baoyu-post-to-wechat 简化版发布脚本
使用 WeWrite 相同的微信账号配置
"""
import os
import json
import requests
import yaml
from pathlib import Path
# 配置文件路径
EXTEND_PATH = "/home/ubuntu/.nanobot/workspace/skills/baoyu-post-to-wechat/EXTEND.md"
WEWRITE_CONFIG = "/home/ubuntu/wewrite/config.yaml"
def load_config():
"""加载配置,优先使用 EXTEND.md,回退到 WeWrite 配置"""
config = {}
# 尝试加载 EXTEND.md
if os.path.exists(EXTEND_PATH):
with open(EXTEND_PATH, 'r', encoding='utf-8') as f:
content = f.read()
# 简单解析 key: value 格式
for line in content.split('\n'):
if ':' in line and not line.strip().startswith('#'):
key, value = line.split(':', 1)
config[key.strip()] = value.strip()
# 如果 EXTEND.md 中没有账号信息,使用 WeWrite 配置
if 'app_id' not in config and os.path.exists(WEWRITE_CONFIG):
with open(WEWRITE_CONFIG, 'r', encoding='utf-8') as f:
wewrite_config = yaml.safe_load(f)
config['app_id'] = wewrite_config['wechat']['appid']
config['app_secret'] = wewrite_config['wechat']['secret']
config['default_author'] = wewrite_config['wechat']['author']
return config
def get_access_token(app_id, app_secret):
"""获取微信 access_token"""
url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={app_id}&secret={app_secret}"
response = requests.get(url)
data = response.json()
if 'access_token' in data:
return data['access_token']
else:
raise Exception(f"获取 access_token 失败: {data}")
def upload_cover_image(image_path, access_token):
"""上传封面图到微信(永久素材)"""
url = f"https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={access_token}&type=image"
with open(image_path, 'rb') as f:
files = {'media': f}
response = requests.post(url, files=files)
data = response.json()
if 'media_id' in data:
return data['media_id']
else:
raise Exception(f"上传封面图失败: {data}")
def create_draft(access_token, title, content, author=None, cover_image_path=None):
"""创建公众号草稿"""
url = f"https://api.weixin.qq.com/cgi-bin/draft/add?access_token={access_token}"
# 上传封面图(如果需要)
thumb_media_id = None
if cover_image_path and os.path.exists(cover_image_path):
thumb_media_id = upload_cover_image(cover_image_path, access_token)
# 构建文章数据
# 微信摘要限制:纯文本,不超过120字
# 先提取纯文本内容
import re
plain_text = re.sub(r'<[^>]+>', '', content) # 移除HTML标签
plain_text = re.sub(r'[#*`\-\[\]>]', '', plain_text) # 移除Markdown标记
plain_text = plain_text.strip()
# 限制摘要长度(微信要求不超过120字)
if len(plain_text) > 120:
digest = plain_text[:117] + "..."
else:
digest = plain_text
article = {
"title": title,
"author": author or "",
"digest": digest,
"content": content,
"show_cover_pic": 0,
"need_open_comment": 1,
"only_fans_can_comment": 0
}
# 如果有封面图,添加thumb_media_id
if thumb_media_id:
article["thumb_media_id"] = thumb_media_id
body = {"articles": [article]}
# 发送请求
headers = {"Content-Type": "application/json; charset=utf-8"}
response = requests.post(url, data=json.dumps(body, ensure_ascii=False).encode('utf-8'), headers=headers)
data = response.json()
if 'media_id' in data:
return data['media_id']
else:
raise Exception(f"创建草稿失败: {data}")
def publish_markdown(markdown_path, title=None, author=None, cover_image_path=None):
"""发布 Markdown 文章"""
config = load_config()
if not os.path.exists(markdown_path):
raise FileNotFoundError(f"Markdown 文件不存在: {markdown_path}")
# 读取 Markdown 内容
with open(markdown_path, 'r', encoding='utf-8') as f:
content = f.read()
# 如果没有提供标题,使用文件名
if not title:
title = Path(markdown_path).stem
# 如果没有提供作者,使用配置中的默认作者
if not author:
author = config.get('default_author', '')
# 如果没有提供封面图,使用默认封面图
if not cover_image_path:
# 检查是否有默认封面图
default_cover = "/home/ubuntu/default_cover.png"
if os.path.exists(default_cover):
cover_image_path = default_cover
else:
# 如果没有默认封面图,尝试使用第一个背景图
bg_dir = "/home/ubuntu/albums/xhs-background"
if os.path.exists(bg_dir):
bg_files = os.listdir(bg_dir)
if bg_files:
cover_image_path = os.path.join(bg_dir, bg_files[0])
# 获取 access_token
access_token = get_access_token(config['app_id'], config['app_secret'])
# 创建草稿
media_id = create_draft(access_token, title, content, author, cover_image_path)
return {
"success": True,
"media_id": media_id,
"title": title,
"author": author,
"cover_image": cover_image_path,
"message": "草稿创建成功"
}
def main():
"""主函数"""
import sys
if len(sys.argv) < 2:
print("用法: python baoyu_publish.py <markdown文件> [标题] [作者]")
sys.exit(1)
markdown_path = sys.argv[1]
title = sys.argv[2] if len(sys.argv) > 2 else None
author = sys.argv[3] if len(sys.argv) > 3 else None
try:
result = publish_markdown(markdown_path, title, author)
print(json.dumps(result, ensure_ascii=False, indent=2))
except Exception as e:
print(json.dumps({
"success": False,
"error": str(e)
}, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()