185 lines
6.1 KiB
Python
Executable File
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() |