feat: 添加依赖自动检测与安装、选项记忆、KDocs登录优化

- 新增依赖检测模块:启动时自动检测wkhtmltoimage和Playwright Chromium
- 新增依赖安装对话框:缺失时提示用户一键下载安装
- 修复选项记忆功能:浏览类型、自动截图、自动上传选项现在会保存
- 优化KDocs登录检测:未登录时自动切换到金山文档页面并显示二维码
- 简化日志输出:移除debug信息,保留用户友好的状态提示
- 新增账号变化信号:账号管理页面的修改会自动同步到浏览任务页面

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-19 01:28:06 +08:00
parent 83fef6dff2
commit 9743186a9e
11 changed files with 713 additions and 506 deletions

View File

@@ -107,10 +107,10 @@ class APIBrowser:
except Exception as e:
last_error = e
if attempt < max_retries:
self.log(f"[API] 请求超时,{retry_delay}秒后重试 ({attempt}/{max_retries})...")
self.log(f" 请求超时,{retry_delay}秒后重试 ({attempt}/{max_retries})...")
time.sleep(retry_delay)
else:
self.log(f"[API] 请求失败,已重试{max_retries}次: {str(e)}")
self.log(f" 请求失败,已重试{max_retries}次: {str(e)}")
raise last_error
@@ -125,7 +125,7 @@ class APIBrowser:
def login(self, username: str, password: str) -> bool:
"""登录"""
self.log(f"[API] 登录: {username}")
self.log(f" 登录: {username}")
self._username = username
try:
@@ -152,17 +152,17 @@ class APIBrowser:
if self.index_url_pattern in resp.url:
self.logged_in = True
self.log(f"[API] 登录成功")
self.log(f" 登录成功")
return True
else:
soup = BeautifulSoup(resp.text, "html.parser")
error = soup.find(id="lblMsg")
error_msg = error.get_text().strip() if error else "未知错误"
self.log(f"[API] 登录失败: {error_msg}")
self.log(f" 登录失败: {error_msg}")
return False
except Exception as e:
self.log(f"[API] 登录异常: {str(e)}")
self.log(f" 登录异常: {str(e)}")
return False
def get_real_name(self) -> Optional[str]:
@@ -217,10 +217,10 @@ class APIBrowser:
with open(cookies_path, "w", encoding="utf-8") as f:
f.write("\n".join(lines) + "\n")
self.log(f"[API] Cookies已保存供截图使用")
self.log(f" Cookies已保存供截图使用")
return True
except Exception as e:
self.log(f"[API] 保存cookies失败: {e}")
self.log(f" 保存cookies失败: {e}")
return False
def get_article_list_page(self, bz: int = 0, page: int = 1) -> tuple:
@@ -377,7 +377,7 @@ class APIBrowser:
# 根据浏览类型确定bz参数网站更新后 bz=0 为应读)
bz = 0
self.log(f"[API] 开始浏览 '{browse_type}' (bz={bz})...")
self.log(f" 开始浏览 '{browse_type}' (bz={bz})...")
try:
total_items = 0
@@ -387,12 +387,12 @@ class APIBrowser:
articles, total_pages, _ = self.get_article_list_page(bz, 1)
if not articles:
self.log(f"[API] '{browse_type}' 没有待处理内容")
self.log(f" '{browse_type}' 没有待处理内容")
result.success = True
return result
total_records = self.last_total_records
self.log(f"[API]{total_records} 条记录,开始处理...")
self.log(f"{total_records} 条记录,开始处理...")
# 上报初始进度
if progress_callback:
@@ -404,7 +404,7 @@ class APIBrowser:
for iteration in range(max_iterations):
if should_stop_callback and should_stop_callback():
self.log("[API] 收到停止信号")
self.log(" 收到停止信号")
break
if not articles:
@@ -428,7 +428,7 @@ class APIBrowser:
try:
attachments, article_info = self.get_article_attachments(article_href)
except Exception as e:
self.log(f"[API] 获取文章失败: {title} | {str(e)}")
self.log(f" 获取文章失败: {title} | {str(e)}")
continue
total_items += 1
@@ -446,10 +446,10 @@ class APIBrowser:
for attach in attachments:
if self.mark_attachment_read(attach["id"], attach["channel_id"]):
total_attachments += 1
self.log(f"[API] [{total_items}] {title} - {len(attachments)}个附件")
self.log(f" [{total_items}] {title} - {len(attachments)}个附件")
else:
status = "已标记" if article_marked else "标记失败"
self.log(f"[API] [{total_items}] {title} - 无附件({status})")
self.log(f" [{total_items}] {title} - 无附件({status})")
# 上报进度
if progress_callback:
@@ -472,10 +472,10 @@ class APIBrowser:
if new_total_pages > 0:
total_pages = new_total_pages
except Exception as e:
self.log(f"[API] 获取第{current_page}页列表失败: {str(e)}")
self.log(f" 获取第{current_page}页列表失败: {str(e)}")
break
self.log(f"[API] 浏览完成: {total_items} 条内容,{total_attachments} 个附件")
self.log(f" 浏览完成: {total_items} 条内容,{total_attachments} 个附件")
result.success = True
result.total_items = total_items
result.total_attachments = total_attachments
@@ -483,7 +483,7 @@ class APIBrowser:
except Exception as e:
result.error_message = str(e)
self.log(f"[API] 浏览出错: {str(e)}")
self.log(f" 浏览出错: {str(e)}")
return result
def close(self):