init
This commit is contained in:
178
step2.py
Normal file
178
step2.py
Normal file
@@ -0,0 +1,178 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from typing import Optional, Callable
|
||||
|
||||
from config_loader import get_config
|
||||
from image_uploader import get_wechat_access_token, process_html_images
|
||||
from md_to_wechat import convert_markdown_to_wechat
|
||||
from wechat_publisher import publish_to_wechat
|
||||
from markdown_editor import WechatMarkdownEditor, ThemeManager
|
||||
|
||||
|
||||
def _now_datestr() -> str:
|
||||
from datetime import datetime
|
||||
return datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
|
||||
def get_clipboard_text() -> str:
|
||||
"""获取剪贴板文本内容"""
|
||||
result = subprocess.run(
|
||||
["powershell", "-command", "Get-Clipboard"],
|
||||
capture_output=True
|
||||
)
|
||||
try:
|
||||
return result.stdout.decode('utf-8').strip()
|
||||
except UnicodeDecodeError:
|
||||
try:
|
||||
return result.stdout.decode('gbk').strip()
|
||||
except UnicodeDecodeError:
|
||||
return result.stdout.decode('gb2312', errors='ignore').strip()
|
||||
|
||||
|
||||
class Step2Converter:
|
||||
"""
|
||||
Step 2: 获取剪贴板内容,转换为公众号格式,推送到草稿箱
|
||||
参考: docs/step2.md
|
||||
"""
|
||||
|
||||
def __init__(self, log_callback: Optional[Callable[[str], None]] = None, css_scheme_id: Optional[str] = None):
|
||||
"""
|
||||
初始化 Step2Converter
|
||||
|
||||
Args:
|
||||
log_callback: 日志回调函数,用于将日志输出到 GUI
|
||||
css_scheme_id: CSS 样式方案 ID,可选
|
||||
"""
|
||||
self.log_callback = log_callback
|
||||
self.css_scheme_id = css_scheme_id
|
||||
self.theme_manager = ThemeManager()
|
||||
|
||||
def _log(self, message: str):
|
||||
"""输出日志,支持回调到 GUI"""
|
||||
print(message)
|
||||
if self.log_callback:
|
||||
self.log_callback(message)
|
||||
|
||||
def run(self) -> bool:
|
||||
"""执行 Step 2 流程,成功返回 True"""
|
||||
|
||||
# 1) 获取剪贴板内容
|
||||
self._log("[Step2] 正在获取剪贴板内容...")
|
||||
md_content = get_clipboard_text()
|
||||
|
||||
if not md_content:
|
||||
self._log("[Step2] 警告:剪贴板为空,无法继续")
|
||||
return False
|
||||
|
||||
self._log(f"[Step2] 获取到 Markdown 内容,长度: {len(md_content)} 字符")
|
||||
|
||||
# 2) 转换为公众号文章格式
|
||||
self._log("[Step2] 正在转换为公众号 HTML 格式...")
|
||||
|
||||
# 如果指定了 CSS 方案,先应用
|
||||
if self.css_scheme_id:
|
||||
scheme = self.theme_manager.get_css_scheme(self.css_scheme_id)
|
||||
if scheme:
|
||||
self._log(f"[Step2] 应用 CSS 方案: {scheme.name}")
|
||||
self.theme_manager.apply_css_scheme(self.css_scheme_id)
|
||||
else:
|
||||
self._log(f"[Step2] 警告:CSS 方案 {self.css_scheme_id} 不存在,使用默认设置")
|
||||
|
||||
# 使用 Markdown 编辑器进行转换(与编辑器中的方式一致)
|
||||
# 创建编辑器实例,它会自动加载当前配置(包括已应用的 CSS 方案)
|
||||
editor = WechatMarkdownEditor()
|
||||
html_content = editor.render(md_content)
|
||||
|
||||
# 提取标题(从 HTML 内容中提取 h1 标签)
|
||||
import re
|
||||
title_match = re.search(r'<h1[^>]*>(.*?)</h1>', html_content)
|
||||
title = title_match.group(1) if title_match else "无标题"
|
||||
|
||||
html_content = re.sub(r'\n\s*\n+', '\n', html_content)
|
||||
html_content = re.sub(r'>\s*\n\s*<', '><', html_content)
|
||||
|
||||
self._log(f"[Step2] 转换完成,标题: {title}")
|
||||
self._log(f"[Step2] HTML 内容长度: {len(html_content)} 字符")
|
||||
|
||||
# 3) 处理图片 - 将外部图片上传到微信并替换 URL
|
||||
cover_image_url: Optional[str] = None
|
||||
config = get_config()
|
||||
if config.wechat_appid and config.wechat_appsecret:
|
||||
self._log("[Step2] 正在处理图片,将外部图片上传到微信服务器...")
|
||||
access_token = get_wechat_access_token(config.wechat_appid, config.wechat_appsecret)
|
||||
if access_token:
|
||||
html_content, cover_image_url = process_html_images(html_content, access_token, external_domain="yidaima.cn")
|
||||
self._log("[Step2] 图片处理完成")
|
||||
if cover_image_url:
|
||||
self._log(f"[Step2] 封面图: {cover_image_url}")
|
||||
else:
|
||||
self._log("[Step2] 警告:无法获取微信 access_token,跳过图片上传")
|
||||
|
||||
# 4) 保存 HTML 到文件
|
||||
html_dir = os.path.join(".", "data", "html")
|
||||
os.makedirs(html_dir, exist_ok=True)
|
||||
html_file = os.path.join(html_dir, "wechat.html")
|
||||
with open(html_file, "w", encoding="utf-8") as f:
|
||||
f.write(html_content)
|
||||
self._log(f"[Step2] HTML 已保存到: {html_file}")
|
||||
|
||||
# 5) 推送到公众号草稿箱
|
||||
self._log("[Step2] 准备推送到公众号草稿箱...")
|
||||
wechat_appid = config.wechat_appid
|
||||
wechat_appsecret = config.wechat_appsecret
|
||||
|
||||
if wechat_appid and wechat_appsecret:
|
||||
self._log("[Step2] 正在推送到公众号草稿箱...")
|
||||
|
||||
# 优先使用第二张图片作为封面,否则使用默认封面
|
||||
if cover_image_url:
|
||||
self._log(f"[Step2] 使用第二张图片作为封面: {cover_image_url}")
|
||||
success = publish_to_wechat(
|
||||
title=title,
|
||||
content=html_content,
|
||||
appid=wechat_appid,
|
||||
appsecret=wechat_appsecret,
|
||||
thumb_image_url=cover_image_url
|
||||
)
|
||||
else:
|
||||
# 使用默认封面图片
|
||||
thumb_path = r"c:\Users\南音\Desktop\yidaima\assets\img\bg.jpg"
|
||||
self._log(f"[Step2] 使用默认封面图片: {thumb_path}")
|
||||
success = publish_to_wechat(
|
||||
title=title,
|
||||
content=html_content,
|
||||
appid=wechat_appid,
|
||||
appsecret=wechat_appsecret,
|
||||
thumb_image_path=thumb_path
|
||||
)
|
||||
if success:
|
||||
self._log("[Step2] 公众号草稿推送成功!")
|
||||
else:
|
||||
self._log("[Step2] 公众号草稿推送失败!")
|
||||
else:
|
||||
self._log("[Step2] 提示:未配置微信公众号,跳过公众号推送")
|
||||
self._log("[Step2] 如需推送,请编辑 config.yaml 文件:")
|
||||
self._log("[Step2] wechat:")
|
||||
self._log("[Step2] appid: \"your_appid\"")
|
||||
self._log("[Step2] appsecret: \"your_appsecret\"")
|
||||
self._log("[Step2] 或使用环境变量覆盖:")
|
||||
self._log("[Step2] set WECHAT_APPID=your_appid")
|
||||
self._log("[Step2] set WECHAT_APPSECRET=your_appsecret")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
"""单独运行 Step2"""
|
||||
step2 = Step2Converter()
|
||||
try:
|
||||
step2.run()
|
||||
print("[INFO] Step2 执行成功!")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Step2 执行失败: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user