feat: 添加依赖自动检测与安装、选项记忆、KDocs登录优化
- 新增依赖检测模块:启动时自动检测wkhtmltoimage和Playwright Chromium - 新增依赖安装对话框:缺失时提示用户一键下载安装 - 修复选项记忆功能:浏览类型、自动截图、自动上传选项现在会保存 - 优化KDocs登录检测:未登录时自动切换到金山文档页面并显示二维码 - 简化日志输出:移除debug信息,保留用户友好的状态提示 - 新增账号变化信号:账号管理页面的修改会自动同步到浏览任务页面 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
228
utils/dependency_installer.py
Normal file
228
utils/dependency_installer.py
Normal file
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
依赖检测和安装模块
|
||||
检测 wkhtmltoimage 和 Playwright Chromium 是否已安装
|
||||
如果缺失则从直链下载安装
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from typing import Optional, Callable, Dict, Tuple
|
||||
|
||||
# 直链下载地址
|
||||
DOWNLOAD_URLS = {
|
||||
"wkhtmltopdf": "http://by.haory.cn/3/1223/wkhtmltox.exe",
|
||||
"chromium": "http://by.haory.cn/3/1223/chromium-win64.zip",
|
||||
}
|
||||
|
||||
# Playwright chromium 版本目录名(与 playwright 1.57.0 对应)
|
||||
CHROMIUM_VERSION_DIR = "chromium-1200"
|
||||
|
||||
|
||||
def check_wkhtmltoimage() -> bool:
|
||||
"""检测 wkhtmltoimage 是否已安装"""
|
||||
# 先检查 PATH
|
||||
if shutil.which("wkhtmltoimage"):
|
||||
return True
|
||||
|
||||
# 检查默认安装路径
|
||||
default_paths = [
|
||||
r"C:\Program Files\wkhtmltopdf\bin\wkhtmltoimage.exe",
|
||||
r"C:\Program Files (x86)\wkhtmltopdf\bin\wkhtmltoimage.exe",
|
||||
]
|
||||
for p in default_paths:
|
||||
if os.path.exists(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_playwright_chromium() -> bool:
|
||||
"""检测 Playwright Chromium 浏览器是否已安装"""
|
||||
local_appdata = os.environ.get("LOCALAPPDATA", "")
|
||||
if not local_appdata:
|
||||
return False
|
||||
|
||||
chromium_path = Path(local_appdata) / "ms-playwright" / CHROMIUM_VERSION_DIR
|
||||
|
||||
# 检查目录是否存在且包含chrome.exe
|
||||
if chromium_path.exists():
|
||||
chrome_exe = chromium_path / "chrome-win" / "chrome.exe"
|
||||
if chrome_exe.exists():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_missing_dependencies() -> Dict[str, bool]:
|
||||
"""获取缺失的依赖列表"""
|
||||
return {
|
||||
"wkhtmltoimage": not check_wkhtmltoimage(),
|
||||
"chromium": not check_playwright_chromium(),
|
||||
}
|
||||
|
||||
|
||||
def download_file(url: str, dest_path: str, progress_callback: Optional[Callable] = None) -> bool:
|
||||
"""
|
||||
下载文件
|
||||
|
||||
Args:
|
||||
url: 下载地址
|
||||
dest_path: 保存路径
|
||||
progress_callback: 进度回调 (downloaded_bytes, total_bytes)
|
||||
|
||||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
import urllib.request
|
||||
|
||||
try:
|
||||
def report_progress(block_num, block_size, total_size):
|
||||
if progress_callback:
|
||||
downloaded = block_num * block_size
|
||||
progress_callback(downloaded, total_size)
|
||||
|
||||
urllib.request.urlretrieve(url, dest_path, reporthook=report_progress)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"下载失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def install_wkhtmltopdf(installer_path: str, log_callback: Optional[Callable] = None) -> bool:
|
||||
"""
|
||||
安装 wkhtmltopdf
|
||||
|
||||
Args:
|
||||
installer_path: 安装包路径
|
||||
log_callback: 日志回调
|
||||
|
||||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
def log(msg):
|
||||
if log_callback:
|
||||
log_callback(msg)
|
||||
|
||||
try:
|
||||
log("正在启动 wkhtmltopdf 安装程序...")
|
||||
# 启动安装程序(需要用户手动完成安装向导)
|
||||
subprocess.Popen([installer_path], shell=True)
|
||||
log("请在安装向导中完成安装(建议保持默认路径)")
|
||||
return True
|
||||
except Exception as e:
|
||||
log(f"启动安装程序失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def install_playwright_chromium(zip_path: str, log_callback: Optional[Callable] = None) -> bool:
|
||||
"""
|
||||
安装 Playwright Chromium 浏览器
|
||||
|
||||
Args:
|
||||
zip_path: zip包路径
|
||||
log_callback: 日志回调
|
||||
|
||||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
def log(msg):
|
||||
if log_callback:
|
||||
log_callback(msg)
|
||||
|
||||
try:
|
||||
local_appdata = os.environ.get("LOCALAPPDATA", "")
|
||||
if not local_appdata:
|
||||
log("无法获取 LOCALAPPDATA 路径")
|
||||
return False
|
||||
|
||||
# 目标目录
|
||||
playwright_dir = Path(local_appdata) / "ms-playwright"
|
||||
chromium_dir = playwright_dir / CHROMIUM_VERSION_DIR
|
||||
|
||||
# 创建目录
|
||||
playwright_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
log("正在解压 Chromium 浏览器...")
|
||||
|
||||
# 解压
|
||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(chromium_dir)
|
||||
|
||||
# 创建标记文件(Playwright需要这些文件来确认安装完成)
|
||||
(chromium_dir / "INSTALLATION_COMPLETE").touch()
|
||||
(chromium_dir / "DEPENDENCIES_VALIDATED").touch()
|
||||
|
||||
log("Chromium 浏览器安装成功")
|
||||
return True
|
||||
except Exception as e:
|
||||
log(f"安装 Chromium 失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def download_and_install_dependency(
|
||||
dep_name: str,
|
||||
progress_callback: Optional[Callable] = None,
|
||||
log_callback: Optional[Callable] = None
|
||||
) -> Tuple[bool, str]:
|
||||
"""
|
||||
下载并安装指定依赖
|
||||
|
||||
Args:
|
||||
dep_name: 依赖名称 ("wkhtmltoimage" 或 "chromium")
|
||||
progress_callback: 下载进度回调
|
||||
log_callback: 日志回调
|
||||
|
||||
Returns:
|
||||
(是否成功, 错误信息)
|
||||
"""
|
||||
def log(msg):
|
||||
if log_callback:
|
||||
log_callback(msg)
|
||||
|
||||
# 获取下载地址
|
||||
if dep_name == "wkhtmltoimage":
|
||||
url = DOWNLOAD_URLS["wkhtmltopdf"]
|
||||
filename = "wkhtmltox_installer.exe"
|
||||
elif dep_name == "chromium":
|
||||
url = DOWNLOAD_URLS["chromium"]
|
||||
filename = "chromium-win64.zip"
|
||||
else:
|
||||
return False, f"未知依赖: {dep_name}"
|
||||
|
||||
# 下载到临时目录
|
||||
temp_dir = tempfile.gettempdir()
|
||||
download_path = os.path.join(temp_dir, filename)
|
||||
|
||||
log(f"正在下载 {dep_name}...")
|
||||
|
||||
if not download_file(url, download_path, progress_callback):
|
||||
return False, "下载失败"
|
||||
|
||||
log("下载完成,正在安装...")
|
||||
|
||||
# 安装
|
||||
if dep_name == "wkhtmltoimage":
|
||||
success = install_wkhtmltopdf(download_path, log_callback)
|
||||
if success:
|
||||
return True, "安装程序已启动,请完成安装向导"
|
||||
else:
|
||||
return False, "启动安装程序失败"
|
||||
elif dep_name == "chromium":
|
||||
success = install_playwright_chromium(download_path, log_callback)
|
||||
# 清理下载的zip文件
|
||||
try:
|
||||
os.remove(download_path)
|
||||
except:
|
||||
pass
|
||||
if success:
|
||||
return True, ""
|
||||
else:
|
||||
return False, "安装失败"
|
||||
|
||||
return False, "未知错误"
|
||||
Reference in New Issue
Block a user