feat: 新增 API 获取内容方式并优化微信发布流程

This commit is contained in:
王鹏
2026-04-13 15:41:39 +08:00
parent 165b32f74a
commit 245f9cdf41
4 changed files with 106 additions and 23 deletions

File diff suppressed because one or more lines are too long

74
gui.py
View File

@@ -5,6 +5,7 @@ from tkinter import ttk, messagebox, scrolledtext
import threading import threading
import sys import sys
import os import os
import subprocess
# 添加当前目录到路径 # 添加当前目录到路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
@@ -137,6 +138,14 @@ class YidaimaGUI:
# 刷新按钮 # 刷新按钮
ttk.Button(scheme_frame, text="刷新", command=self.refresh_css_schemes, width=8).grid(row=0, column=1, padx=(5, 0)) ttk.Button(scheme_frame, text="刷新", command=self.refresh_css_schemes, width=8).grid(row=0, column=1, padx=(5, 0))
# 调用API方式选项
self.use_api_var = tk.BooleanVar(value=False)
ttk.Checkbutton(
config_frame,
text="调用API方式 (跳过浏览器自动化直接调用API获取文章内容)",
variable=self.use_api_var
).grid(row=2, column=0, columnspan=2, sticky=tk.W, pady=(10, 0))
# === 操作按钮区域 === # === 操作按钮区域 ===
button_frame = ttk.Frame(self.tab_publish) button_frame = ttk.Frame(self.tab_publish)
button_frame.grid(row=1, column=0, pady=(10, 10)) button_frame.grid(row=1, column=0, pady=(10, 10))
@@ -414,25 +423,62 @@ class YidaimaGUI:
self.root.after(0, lambda: self.log("=" * 50)) self.root.after(0, lambda: self.log("=" * 50))
self.root.after(0, lambda: self.log("开始运行完整流程...")) self.root.after(0, lambda: self.log("开始运行完整流程..."))
self.root.after(0, lambda: self.log("=" * 50)) self.root.after(0, lambda: self.log("=" * 50))
# 获取配置(从配置文件读取) # 获取配置(从配置文件读取)
chrome_path = self.config.get("chrome.path", "") chrome_path = self.config.get("chrome.path", "")
username = self.config.get("step1.username", "") username = self.config.get("step1.username", "")
password = self.config.get("step1.password", "") password = self.config.get("step1.password", "")
project_name = self.project_name_var.get() project_name = self.project_name_var.get()
use_api = self.use_api_var.get()
# Step 1 # Step 1
self.root.after(0, lambda: self.log("\n[Step 1] 开始执行...")) self.root.after(0, lambda: self.log("\n[Step 1] 开始执行..."))
# 定义日志回调函数,将 step1 的日志输出到 GUI if use_api:
def step1_log_callback(message: str): # API 方式获取内容
self.root.after(0, lambda msg=message: self.log(msg)) self.root.after(0, lambda: self.log("[Step 1] 使用 API 方式获取文章内容..."))
import requests
step1 = Step1FeastCoding(chrome_path, username, password, log_callback=step1_log_callback) import re
step1.project_name = project_name # 设置项目名称 # 项目名称中提取编号,如"【A167】" -> "A167"
step1.run() match = re.search(r'【(.+?)】', project_name)
code_name = match.group(1) if match else project_name
api_url = "https://feast.yidaima.cn/prod-api/office/copyTemplate/open/generate"
params = {
"templateName": "FeastCoding",
"codeName": code_name
}
try:
response = requests.get(api_url, params=params, timeout=30)
response.raise_for_status()
json_data = response.json()
# 从 JSON 中提取 msg 字段内容
content = json_data.get("msg", "")
# 将 \\n 替换为空行
content = content.replace("\\n", "\n")
# 设置剪贴板内容
subprocess.run(
["powershell", "-command", f"Set-Clipboard -Value '{content.replace(chr(39), chr(39)+chr(39))}'"],
capture_output=True
)
self.root.after(0, lambda: self.log(f"[Step 1] API 调用成功,已复制到剪贴板,内容长度: {len(content)} 字符"))
except Exception as e:
self.root.after(0, lambda: self.log(f"[Step 1] API 调用失败: {e}"))
raise
else:
# 浏览器方式
self.root.after(0, lambda: self.log("[Step 1] 使用浏览器方式获取文章内容..."))
# 定义日志回调函数,将 step1 的日志输出到 GUI
def step1_log_callback(message: str):
self.root.after(0, lambda msg=message: self.log(msg))
step1 = Step1FeastCoding(chrome_path, username, password, log_callback=step1_log_callback)
step1.project_name = project_name # 设置项目名称
step1.run()
self.root.after(0, lambda: self.log("[Step 1] 浏览器方式执行完成!"))
self.root.after(0, lambda: self.log("[Step 1] 执行完成!")) self.root.after(0, lambda: self.log("[Step 1] 执行完成!"))
# Step 2 # Step 2
self.root.after(0, lambda: self.log("\n[Step 2] 开始执行...")) self.root.after(0, lambda: self.log("\n[Step 2] 开始执行..."))
@@ -444,15 +490,15 @@ class YidaimaGUI:
scheme_name = self.css_scheme_var.get() scheme_name = self.css_scheme_var.get()
css_scheme_id = self._get_scheme_id_by_name(scheme_name) css_scheme_id = self._get_scheme_id_by_name(scheme_name)
step2 = Step2Converter(log_callback=log_callback, css_scheme_id=css_scheme_id) step2 = Step2Converter(log_callback=log_callback, css_scheme_id=css_scheme_id, project_name=project_name)
step2.run() step2.run()
self.root.after(0, lambda: self.log("[Step 2] 执行完成!")) self.root.after(0, lambda: self.log("[Step 2] 执行完成!"))
self.root.after(0, lambda: self.log("\n" + "=" * 50)) self.root.after(0, lambda: self.log("\n" + "=" * 50))
self.root.after(0, lambda: self.log("完整流程执行成功!")) self.root.after(0, lambda: self.log("完整流程执行成功!"))
self.root.after(0, lambda: self.log("=" * 50)) self.root.after(0, lambda: self.log("=" * 50))
self.root.after(0, lambda: messagebox.showinfo("成功", "完整流程执行成功!")) self.root.after(0, lambda: messagebox.showinfo("成功", "完整流程执行成功!"))
except Exception as e: except Exception as e:
error_msg = str(e) error_msg = str(e)
self.root.after(0, lambda: self.log(f"\n[ERROR] {error_msg}")) self.root.after(0, lambda: self.log(f"\n[ERROR] {error_msg}"))

View File

@@ -37,16 +37,18 @@ class Step2Converter:
参考: docs/step2.md 参考: docs/step2.md
""" """
def __init__(self, log_callback: Optional[Callable[[str], None]] = None, css_scheme_id: Optional[str] = None): def __init__(self, log_callback: Optional[Callable[[str], None]] = None, css_scheme_id: Optional[str] = None, project_name: Optional[str] = None):
""" """
初始化 Step2Converter 初始化 Step2Converter
Args: Args:
log_callback: 日志回调函数,用于将日志输出到 GUI log_callback: 日志回调函数,用于将日志输出到 GUI
css_scheme_id: CSS 样式方案 ID可选 css_scheme_id: CSS 样式方案 ID可选
project_name: 项目名称,可选,用于生成文章标题
""" """
self.log_callback = log_callback self.log_callback = log_callback
self.css_scheme_id = css_scheme_id self.css_scheme_id = css_scheme_id
self.project_name = project_name
self.theme_manager = ThemeManager() self.theme_manager = ThemeManager()
def _log(self, message: str): def _log(self, message: str):
@@ -84,12 +86,22 @@ class Step2Converter:
# 创建编辑器实例,它会自动加载当前配置(包括已应用的 CSS 方案) # 创建编辑器实例,它会自动加载当前配置(包括已应用的 CSS 方案)
editor = WechatMarkdownEditor() editor = WechatMarkdownEditor()
html_content = editor.render(md_content) html_content = editor.render(md_content)
# 提取标题(从 HTML 内容中提取 h1 标签) # 提取标题(从 HTML 内容中提取 h1 标签)
import re import re
title_match = re.search(r'<h1[^>]*>(.*?)</h1>', html_content) title_match = re.search(r'<h1[^>]*>(.*?)</h1>', html_content)
title = title_match.group(1) if title_match else "无标题" title = title_match.group(1) if title_match else "无标题"
# 如果提供了项目名称,使用项目名称去掉编号作为标题,并添加作者
if self.project_name:
# 去掉编号,如"【A167】xxx" -> "xxx"
match = re.search(r'】(.+)', self.project_name)
if match:
title = match.group(1)
else:
title = self.project_name
# 添加作者 - 通过 publish_to_wechat 传入
html_content = re.sub(r'\n\s*\n+', '\n', html_content) html_content = re.sub(r'\n\s*\n+', '\n', html_content)
html_content = re.sub(r'>\s*\n\s*<', '><', html_content) html_content = re.sub(r'>\s*\n\s*<', '><', html_content)
@@ -134,7 +146,8 @@ class Step2Converter:
content=html_content, content=html_content,
appid=wechat_appid, appid=wechat_appid,
appsecret=wechat_appsecret, appsecret=wechat_appsecret,
thumb_image_url=cover_image_url thumb_image_url=cover_image_url,
author="南音"
) )
else: else:
# 使用默认封面图片 # 使用默认封面图片
@@ -145,7 +158,8 @@ class Step2Converter:
content=html_content, content=html_content,
appid=wechat_appid, appid=wechat_appid,
appsecret=wechat_appsecret, appsecret=wechat_appsecret,
thumb_image_path=thumb_path thumb_image_path=thumb_path,
author="南音"
) )
if success: if success:
self._log("[Step2] 公众号草稿推送成功!") self._log("[Step2] 公众号草稿推送成功!")

View File

@@ -184,7 +184,8 @@ def publish_to_wechat(
appid: str, appid: str,
appsecret: str, appsecret: str,
thumb_image_path: Optional[str] = None, thumb_image_path: Optional[str] = None,
thumb_image_url: Optional[str] = None thumb_image_url: Optional[str] = None,
author: str = ""
) -> bool: ) -> bool:
""" """
便捷函数:发布文章到微信公众号草稿箱 便捷函数:发布文章到微信公众号草稿箱
@@ -196,6 +197,7 @@ def publish_to_wechat(
appsecret: 微信公众号 AppSecret appsecret: 微信公众号 AppSecret
thumb_image_path: 封面图片本地路径(可选,与 thumb_image_url 二选一) thumb_image_path: 封面图片本地路径(可选,与 thumb_image_url 二选一)
thumb_image_url: 封面图片URL可选与 thumb_image_path 二选一) thumb_image_url: 封面图片URL可选与 thumb_image_path 二选一)
author: 作者
Returns: Returns:
是否成功 是否成功
@@ -219,7 +221,8 @@ def publish_to_wechat(
result = publisher.add_draft( result = publisher.add_draft(
title=title, title=title,
content=content, content=content,
thumb_media_id=thumb_media_id thumb_media_id=thumb_media_id,
author=author
) )
print(f"[WeChat] 草稿添加成功media_id: {result.get('media_id')}") print(f"[WeChat] 草稿添加成功media_id: {result.get('media_id')}")