feat: 新增 API 获取内容方式并优化微信发布流程
This commit is contained in:
File diff suppressed because one or more lines are too long
74
gui.py
74
gui.py
@@ -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}"))
|
||||||
|
|||||||
24
step2.py
24
step2.py
@@ -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] 公众号草稿推送成功!")
|
||||||
|
|||||||
@@ -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')}")
|
||||||
|
|||||||
Reference in New Issue
Block a user