feat(core): 优化主窗口信号连接和状态管理

- 更新主窗口信号连接,使用私有方法处理关闭和最小化按钮点击事件,增强代码可读性。
- 根据离线模式和配置状态统一管理开始安装按钮的状态,简化逻辑。
- 增强日志记录,确保在用户操作时提供详细的调试信息,便于后续排查和用户反馈。
- 优化卸载处理程序的日志记录,提升用户体验和系统稳定性。
This commit is contained in:
hyb-oyqq
2025-08-12 18:02:10 +08:00
parent 4f2217ca95
commit a97cdf4c23
7 changed files with 135 additions and 122 deletions

View File

@@ -73,7 +73,7 @@ class UninstallHandler(QObject):
logger.info(f"用户选择了目录: {selected_folder}") logger.info(f"用户选择了目录: {selected_folder}")
if debug_mode: if debug_mode:
logger.debug(f"DEBUG: 卸载功能 - 用户选择了目录: {selected_folder}") logger.debug(f"卸载功能 - 用户选择了目录: {selected_folder}")
# 使用UI管理器显示加载对话框 # 使用UI管理器显示加载对话框
if hasattr(self.main_window, 'ui_manager'): if hasattr(self.main_window, 'ui_manager'):
@@ -191,7 +191,7 @@ class UninstallHandler(QObject):
logger.info(f"用户选择了以下游戏: {selected_games}") logger.info(f"用户选择了以下游戏: {selected_games}")
if debug_mode: if debug_mode:
logger.debug(f"DEBUG: 卸载功能 - 用户选择了以下游戏: {selected_games}") logger.debug(f"卸载功能 - 用户选择了以下游戏: {selected_games}")
# 过滤game_dirs只保留选中的游戏 # 过滤game_dirs只保留选中的游戏
selected_game_dirs = {game: games_with_patch[game] for game in selected_games if game in games_with_patch} selected_game_dirs = {game: games_with_patch[game] for game in selected_games if game in games_with_patch}

View File

@@ -794,7 +794,6 @@ class DownloadManager:
logger.info(f"DEBUG: 成功复制并验证补丁文件 {_7z_path}") logger.info(f"DEBUG: 成功复制并验证补丁文件 {_7z_path}")
# 直接进入解压阶段 # 直接进入解压阶段
self.extraction_handler.start_extraction(_7z_path, game_folder, plugin_path, game_version) self.extraction_handler.start_extraction(_7z_path, game_folder, plugin_path, game_version)
self.main_window.extraction_handler.extraction_finished.connect(self.on_extraction_finished)
else: else:
if debug_mode: if debug_mode:
logger.warning(f"DEBUG: 补丁文件哈希验证失败") logger.warning(f"DEBUG: 补丁文件哈希验证失败")
@@ -910,7 +909,6 @@ class DownloadManager:
# 直接进入解压阶段 # 直接进入解压阶段
self.extraction_handler.start_extraction(_7z_path, game_folder, plugin_path, game_version) self.extraction_handler.start_extraction(_7z_path, game_folder, plugin_path, game_version)
self.main_window.extraction_handler.extraction_finished.connect(self.on_extraction_finished)
def on_extraction_finished(self, continue_download): def on_extraction_finished(self, continue_download):
"""解压完成后的回调,决定是否继续下载队列 """解压完成后的回调,决定是否继续下载队列

View File

@@ -5,6 +5,7 @@ from PySide6.QtGui import QFont
from config.config import DOWNLOAD_THREADS from config.config import DOWNLOAD_THREADS
from workers.download import DownloadThread from workers.download import DownloadThread
from utils.logger import setup_logger
class DownloadTaskManager: class DownloadTaskManager:
@@ -53,7 +54,7 @@ class DownloadTaskManager:
self.main_window.progress_window.stop_button.clicked.connect(self.main_window.download_manager.on_download_stopped) self.main_window.progress_window.stop_button.clicked.connect(self.main_window.download_manager.on_download_stopped)
# 连接暂停/恢复按钮 # 连接暂停/恢复按钮
self.main_window.progress_window.pause_resume_button.clicked.connect(self.toggle_download_pause) self.main_window.progress_window.pause_resume_button.clicked.connect(self._on_pause_resume_clicked)
# 启动线程和显示进度窗口 # 启动线程和显示进度窗口
self.current_download_thread.start() self.current_download_thread.start()
@@ -61,6 +62,8 @@ class DownloadTaskManager:
def toggle_download_pause(self): def toggle_download_pause(self):
"""切换下载的暂停/恢复状态""" """切换下载的暂停/恢复状态"""
logger = setup_logger("download_task_manager")
logger.debug("执行暂停/恢复下载操作")
if not self.current_download_thread: if not self.current_download_thread:
return return
@@ -112,6 +115,8 @@ class DownloadTaskManager:
def show_download_thread_settings(self): def show_download_thread_settings(self):
"""显示下载线程设置对话框""" """显示下载线程设置对话框"""
logger = setup_logger("download_task_manager")
logger.info("用户打开下载线程数设置对话框")
# 创建对话框 # 创建对话框
dialog = QDialog(self.main_window) dialog = QDialog(self.main_window)
dialog.setWindowTitle(f"下载线程设置 - {self.APP_NAME}") dialog.setWindowTitle(f"下载线程设置 - {self.APP_NAME}")
@@ -179,6 +184,7 @@ class DownloadTaskManager:
break break
if selected_level: if selected_level:
old_level = self.download_thread_level
# 为极速和狂暴模式显示警告 # 为极速和狂暴模式显示警告
if selected_level in ["extreme", "insane"]: if selected_level in ["extreme", "insane"]:
warning_result = QtWidgets.QMessageBox.warning( warning_result = QtWidgets.QMessageBox.warning(
@@ -194,6 +200,9 @@ class DownloadTaskManager:
success = self.set_download_thread_level(selected_level) success = self.set_download_thread_level(selected_level)
logger.info(f"用户修改下载线程数设置: {old_level} -> {selected_level}")
logger.debug(f"对应线程数: {DOWNLOAD_THREADS[old_level]} -> {DOWNLOAD_THREADS[selected_level]}")
if success: if success:
# 显示设置成功消息 # 显示设置成功消息
thread_count = DOWNLOAD_THREADS[selected_level] thread_count = DOWNLOAD_THREADS[selected_level]
@@ -215,8 +224,19 @@ class DownloadTaskManager:
def stop_download(self): def stop_download(self):
"""停止当前下载线程""" """停止当前下载线程"""
logger = setup_logger("download_task_manager")
logger.info("用户点击停止下载按钮")
if self.current_download_thread and self.current_download_thread.isRunning(): if self.current_download_thread and self.current_download_thread.isRunning():
self.current_download_thread.stop() self.current_download_thread.stop()
self.current_download_thread.wait() # 等待线程完全终止 self.current_download_thread.wait() # 等待线程完全终止
return True return True
return False return False
def _on_pause_resume_clicked(self):
"""处理暂停/恢复按钮点击"""
logger = setup_logger("download_task_manager")
logger.info("用户点击暂停/恢复下载按钮")
self.toggle_download_pause()
def toggle_download_pause(self):
"""切换下载暂停/恢复状态"""

View File

@@ -9,6 +9,7 @@ import traceback
from utils import load_base64_image, msgbox_frame, resource_path from utils import load_base64_image, msgbox_frame, resource_path
from config.config import APP_NAME, APP_VERSION, LOG_FILE from config.config import APP_NAME, APP_VERSION, LOG_FILE
from core.managers.ipv6_manager import IPv6Manager # 导入新的IPv6Manager类 from core.managers.ipv6_manager import IPv6Manager # 导入新的IPv6Manager类
from workers.download import ProgressWindow
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -1025,6 +1026,11 @@ class UIManager:
Returns: Returns:
QDialog: 配置好的进度窗口实例. QDialog: 配置好的进度窗口实例.
""" """
# 如果是下载进度窗口使用专用的ProgressWindow类
if "下载" in title:
return ProgressWindow(self.main_window)
# 其他情况使用基本的进度窗口
progress_window = QDialog(self.main_window) progress_window = QDialog(self.main_window)
progress_window.setWindowTitle(f"{title} - {APP_NAME}") progress_window.setWindowTitle(f"{title} - {APP_NAME}")
progress_window.setFixedSize(400, 150) progress_window.setFixedSize(400, 150)

View File

@@ -250,9 +250,9 @@ class MainWindow(QMainWindow):
def _connect_signals(self): def _connect_signals(self):
"""连接UI组件的信号到相应的槽函数.""" """连接UI组件的信号到相应的槽函数."""
if hasattr(self.ui, 'close_btn'): if hasattr(self.ui, 'close_btn'):
self.ui.close_btn.clicked.connect(self.close) self.ui.close_btn.clicked.connect(self._on_close_clicked)
if hasattr(self.ui, 'minimize_btn'): if hasattr(self.ui, 'minimize_btn'):
self.ui.minimize_btn.clicked.connect(self.showMinimized) self.ui.minimize_btn.clicked.connect(self._on_minimize_clicked)
self.ui.start_install_btn.clicked.connect(self.handle_install_button_click) self.ui.start_install_btn.clicked.connect(self.handle_install_button_click)
self.ui.uninstall_btn.clicked.connect(self.uninstall_handler.handle_uninstall_button_click) self.ui.uninstall_btn.clicked.connect(self.uninstall_handler.handle_uninstall_button_click)
@@ -337,14 +337,11 @@ class MainWindow(QMainWindow):
if hasattr(self, 'offline_mode_manager'): if hasattr(self, 'offline_mode_manager'):
is_offline_mode = self.offline_mode_manager.is_in_offline_mode() is_offline_mode = self.offline_mode_manager.is_in_offline_mode()
# 如果是离线模式,始终启用开始安装按钮 # 根据离线模式和配置状态设置按钮
if is_offline_mode: if is_offline_mode or self.config_valid:
self.set_start_button_enabled(True) self.window_manager.change_window_state(self.window_manager.STATE_READY)
# 否则,只有在配置有效时才启用开始安装按钮
elif self.config_valid:
self.set_start_button_enabled(True)
else: else:
self.set_start_button_enabled(False) self.window_manager.change_window_state(self.window_manager.STATE_ERROR)
def set_start_button_enabled(self, enabled, installing=False): def set_start_button_enabled(self, enabled, installing=False):
"""[过渡方法] 设置按钮状态将调用委托给WindowManager """[过渡方法] 设置按钮状态将调用委托给WindowManager
@@ -379,6 +376,11 @@ class MainWindow(QMainWindow):
# 处理返回结果 # 处理返回结果
result = self.config_manager.on_config_fetched(data, error_message) result = self.config_manager.on_config_fetched(data, error_message)
# 先同步状态
self.cloud_config = self.config_manager.get_cloud_config()
self.config_valid = self.config_manager.is_config_valid()
self.last_error_message = self.config_manager.get_last_error()
# 根据返回的操作执行相应动作 # 根据返回的操作执行相应动作
if result and "action" in result: if result and "action" in result:
if result["action"] == "exit": if result["action"] == "exit":
@@ -386,21 +388,16 @@ class MainWindow(QMainWindow):
self.shutdown_app(force_exit=True) self.shutdown_app(force_exit=True)
elif result["action"] == "disable_button": elif result["action"] == "disable_button":
# 禁用开始安装按钮 # 禁用开始安装按钮
self.set_start_button_enabled(False) self.window_manager.change_window_state(self.window_manager.STATE_ERROR)
elif result["action"] == "enable_button": elif result["action"] == "enable_button":
# 启用开始安装按钮 # 启用开始安装按钮
self.set_start_button_enabled(True) self.window_manager.change_window_state(self.window_manager.STATE_READY)
# 检查是否需要记录版本警告 # 检查是否需要记录版本警告
if "version_warning" in result and result["version_warning"]: if "version_warning" in result and result["version_warning"]:
self.version_warning = True self.version_warning = True
else: else:
self.version_warning = False self.version_warning = False
# 同步状态
self.cloud_config = self.config_manager.get_cloud_config()
self.config_valid = self.config_manager.is_config_valid()
self.last_error_message = self.config_manager.get_last_error()
# 重新启用窗口,恢复用户交互 # 重新启用窗口,恢复用户交互
self.setEnabled(True) self.setEnabled(True)
@@ -430,6 +427,10 @@ class MainWindow(QMainWindow):
def shutdown_app(self, event=None, force_exit=False): def shutdown_app(self, event=None, force_exit=False):
"""关闭应用程序""" """关闭应用程序"""
logger = setup_logger("main_window")
logger.info("用户点击退出按钮")
logger.debug("开始关闭应用程序")
if hasattr(self, 'animation_in_progress') and self.animation_in_progress and not force_exit: if hasattr(self, 'animation_in_progress') and self.animation_in_progress and not force_exit:
if event: if event:
event.ignore() event.ignore()
@@ -482,6 +483,9 @@ class MainWindow(QMainWindow):
"""处理安装按钮点击事件 """处理安装按钮点击事件
根据按钮当前状态决定是显示错误还是执行安装 根据按钮当前状态决定是显示错误还是执行安装
""" """
logger = setup_logger("main_window")
logger.info("用户点击开始安装按钮")
logger.debug("开始处理安装按钮点击事件")
# 检查是否处于离线模式 # 检查是否处于离线模式
is_offline_mode = False is_offline_mode = False
if hasattr(self, 'offline_mode_manager'): if hasattr(self, 'offline_mode_manager'):
@@ -728,6 +732,18 @@ class MainWindow(QMainWindow):
""" """
self.ui_manager.show_loading_dialog(message) self.ui_manager.show_loading_dialog(message)
def _on_close_clicked(self):
"""处理关闭按钮点击"""
logger = setup_logger("main_window")
logger.info("用户点击关闭按钮")
self.close()
def _on_minimize_clicked(self):
"""处理最小化按钮点击"""
logger = setup_logger("main_window")
logger.info("用户点击最小化按钮")
self.showMinimized()
def hide_loading_dialog(self): def hide_loading_dialog(self):
"""隐藏加载对话框""" """隐藏加载对话框"""
self.ui_manager.hide_loading_dialog() self.ui_manager.hide_loading_dialog()

View File

@@ -102,10 +102,10 @@ class ExtractionThread(QThread):
file_list = archive.getnames() file_list = archive.getnames()
# 详细记录压缩包中的所有文件 # 详细记录压缩包中的所有文件
debug_logger.info(f"压缩包内容分析:") debug_logger.debug(f"压缩包内容分析:")
debug_logger.info(f"- 文件总数: {len(file_list)}") debug_logger.debug(f"- 文件总数: {len(file_list)}")
for i, f in enumerate(file_list): for i, f in enumerate(file_list):
debug_logger.info(f" {i+1}. {f} - 类型: {'文件夹' if f.endswith('/') or f.endswith('\\') else '文件'}") debug_logger.debug(f" {i+1}. {f} - 类型: {'文件夹' if f.endswith('/') or f.endswith('\\') else '文件'}")
update_progress(20, f"正在分析 {self.game_version} 的补丁文件...") update_progress(20, f"正在分析 {self.game_version} 的补丁文件...")
@@ -114,9 +114,15 @@ class ExtractionThread(QThread):
with tempfile.TemporaryDirectory() as temp_dir: with tempfile.TemporaryDirectory() as temp_dir:
# 查找主补丁文件和签名文件 # 查找主补丁文件和签名文件
target_filename = os.path.basename(self.plugin_path) target_filename = os.path.basename(self.plugin_path)
# 只有NEKOPARA After版本才需要查找签名文件
if self.game_version == "NEKOPARA After":
sig_filename = target_filename + ".sig" # 签名文件名 sig_filename = target_filename + ".sig" # 签名文件名
debug_logger.info(f"查找主补丁文件: {target_filename}") debug_logger.debug(f"查找主补丁文件: {target_filename}")
debug_logger.info(f"查找签名文件: {sig_filename}") debug_logger.debug(f"查找签名文件: {sig_filename}")
else:
sig_filename = None
debug_logger.debug(f"查找主补丁文件: {target_filename}")
debug_logger.debug(f"{self.game_version} 不需要签名文件")
target_file_in_archive = None target_file_in_archive = None
sig_file_in_archive = None sig_file_in_archive = None
@@ -124,7 +130,7 @@ class ExtractionThread(QThread):
# 对于NEKOPARA After增加特殊处理 # 对于NEKOPARA After增加特殊处理
if self.game_version == "NEKOPARA After": if self.game_version == "NEKOPARA After":
# 增加专门的检查,同时识别主补丁和签名文件 # 增加专门的检查,同时识别主补丁和签名文件
debug_logger.info("执行NEKOPARA After特殊补丁文件识别") debug_logger.debug("执行NEKOPARA After特殊补丁文件识别")
# 查找主补丁和签名文件 # 查找主补丁和签名文件
for file_path in file_list: for file_path in file_list:
@@ -133,19 +139,19 @@ class ExtractionThread(QThread):
# 查找主补丁文件 # 查找主补丁文件
if basename == "afteradult.xp3" and not basename.endswith('.sig'): if basename == "afteradult.xp3" and not basename.endswith('.sig'):
target_file_in_archive = file_path target_file_in_archive = file_path
debug_logger.info(f"找到精确匹配的After主补丁文件: {target_file_in_archive}") debug_logger.debug(f"找到精确匹配的After主补丁文件: {target_file_in_archive}")
# 查找签名文件 # 查找签名文件
elif basename == "afteradult.xp3.sig" or basename.endswith('.sig'): elif basename == "afteradult.xp3.sig" or basename.endswith('.sig'):
sig_file_in_archive = file_path sig_file_in_archive = file_path
debug_logger.info(f"找到After签名文件: {sig_file_in_archive}") debug_logger.debug(f"找到After签名文件: {sig_file_in_archive}")
# 如果没找到主补丁文件,寻找可能的替代文件 # 如果没找到主补丁文件,寻找可能的替代文件
if not target_file_in_archive: if not target_file_in_archive:
for file_path in file_list: for file_path in file_list:
if "afteradult.xp3" in file_path and not file_path.endswith('.sig'): if "afteradult.xp3" in file_path and not file_path.endswith('.sig'):
target_file_in_archive = file_path target_file_in_archive = file_path
debug_logger.info(f"找到备选After主补丁文件: {target_file_in_archive}") debug_logger.debug(f"找到备选After主补丁文件: {target_file_in_archive}")
break break
else: else:
# 标准处理逻辑 # 标准处理逻辑
@@ -155,12 +161,12 @@ class ExtractionThread(QThread):
# 查找主补丁文件 # 查找主补丁文件
if basename == target_filename and not basename.endswith('.sig'): if basename == target_filename and not basename.endswith('.sig'):
target_file_in_archive = file_path target_file_in_archive = file_path
debug_logger.info(f"在压缩包中找到主补丁文件: {target_file_in_archive}") debug_logger.debug(f"在压缩包中找到主补丁文件: {target_file_in_archive}")
# 查找签名文件 # 查找签名文件
elif basename == sig_filename: elif basename == sig_filename:
sig_file_in_archive = file_path sig_file_in_archive = file_path
debug_logger.info(f"在压缩包中找到签名文件: {sig_file_in_archive}") debug_logger.debug(f"在压缩包中找到签名文件: {sig_file_in_archive}")
# 如果没有找到精确匹配的主补丁文件,使用更宽松的搜索 # 如果没有找到精确匹配的主补丁文件,使用更宽松的搜索
if not target_file_in_archive: if not target_file_in_archive:
@@ -178,7 +184,7 @@ class ExtractionThread(QThread):
# 提取所有文件到临时目录 # 提取所有文件到临时目录
update_progress(30, f"正在解压所有文件...") update_progress(30, f"正在解压所有文件...")
archive.extractall(path=temp_dir) archive.extractall(path=temp_dir)
debug_logger.info(f"已提取所有文件到临时目录") debug_logger.debug(f"已提取所有文件到临时目录")
# 在提取的文件中查找主补丁文件和签名文件 # 在提取的文件中查找主补丁文件和签名文件
found_main = False found_main = False
@@ -190,29 +196,29 @@ class ExtractionThread(QThread):
if file == target_filename and not file.endswith('.sig'): if file == target_filename and not file.endswith('.sig'):
extracted_file_path = os.path.join(root, file) extracted_file_path = os.path.join(root, file)
file_size = os.path.getsize(extracted_file_path) file_size = os.path.getsize(extracted_file_path)
debug_logger.info(f"在提取的文件中找到主补丁文件: {extracted_file_path}, 大小: {file_size} 字节") debug_logger.debug(f"在提取的文件中找到主补丁文件: {extracted_file_path}, 大小: {file_size} 字节")
# 复制到目标位置 # 复制到目标位置
target_path = os.path.join(self.game_folder, target_filename) target_path = os.path.join(self.game_folder, target_filename)
shutil.copy2(extracted_file_path, target_path) shutil.copy2(extracted_file_path, target_path)
debug_logger.info(f"已复制主补丁文件到: {target_path}") debug_logger.debug(f"已复制主补丁文件到: {target_path}")
found_main = True found_main = True
# 查找签名文件 # 查找签名文件
elif file == sig_filename or file.endswith('.sig'): elif file == sig_filename or file.endswith('.sig'):
extracted_sig_path = os.path.join(root, file) extracted_sig_path = os.path.join(root, file)
sig_size = os.path.getsize(extracted_sig_path) sig_size = os.path.getsize(extracted_sig_path)
debug_logger.info(f"在提取的文件中找到签名文件: {extracted_sig_path}, 大小: {sig_size} 字节") debug_logger.debug(f"在提取的文件中找到签名文件: {extracted_sig_path}, 大小: {sig_size} 字节")
# 复制到目标位置 # 复制到目标位置
sig_target = os.path.join(self.game_folder, sig_filename) sig_target = os.path.join(self.game_folder, sig_filename)
shutil.copy2(extracted_sig_path, sig_target) shutil.copy2(extracted_sig_path, sig_target)
debug_logger.info(f"已复制签名文件到: {sig_target}") debug_logger.debug(f"已复制签名文件到: {sig_target}")
found_sig = True found_sig = True
# 如果两个文件都找到,可以停止遍历 # 如果两个文件都找到,可以停止遍历
if found_main and found_sig: if found_main and found_sig:
debug_logger.info("已找到所有需要的文件,停止遍历") debug_logger.debug("已找到所有需要的文件,停止遍历")
break break
if found_main and found_sig: if found_main and found_sig:
@@ -222,26 +228,29 @@ class ExtractionThread(QThread):
debug_logger.error(f"无法找到主补丁文件,安装失败") debug_logger.error(f"无法找到主补丁文件,安装失败")
raise FileNotFoundError(f"在压缩包中未找到主补丁文件 {target_filename}") raise FileNotFoundError(f"在压缩包中未找到主补丁文件 {target_filename}")
# 只有NEKOPARA After版本才需要处理签名文件
if self.game_version == "NEKOPARA After":
# 签名文件没找到不影响主流程,但记录警告 # 签名文件没找到不影响主流程,但记录警告
if not found_sig: if not found_sig:
debug_logger.warning(f"未找到签名文件 {sig_filename}将尝试使用内置签名文件") debug_logger.warning(f"未找到签名文件 {sig_filename}但继续安装主补丁文件")
# 尝试使用内置签名文件 else:
self._try_use_builtin_signature(sig_filename, debug_logger, update_progress) debug_logger.info(f"{self.game_version} 不需要签名文件,跳过签名文件处理")
else: else:
# 准备要解压的文件列表 # 准备要解压的文件列表
files_to_extract = [target_file_in_archive] files_to_extract = [target_file_in_archive]
if sig_file_in_archive: # 只有NEKOPARA After版本才需要解压签名文件
if self.game_version == "NEKOPARA After" and sig_file_in_archive:
files_to_extract.append(sig_file_in_archive) files_to_extract.append(sig_file_in_archive)
debug_logger.info(f"将同时解压主补丁文件和签名文件: {files_to_extract}") debug_logger.debug(f"将同时解压主补丁文件和签名文件: {files_to_extract}")
else: else:
debug_logger.info(f"将仅解压主补丁文件: {files_to_extract}") debug_logger.debug(f"将仅解压主补丁文件: {files_to_extract}")
# 解压选定的文件到临时目录 # 解压选定的文件到临时目录
debug_logger.info(f"开始解压选定文件到临时目录: {temp_dir}") debug_logger.debug(f"开始解压选定文件到临时目录: {temp_dir}")
# 设置解压超时时间(秒) # 设置解压超时时间(秒)
extract_timeout = 180 # 3分钟超时 extract_timeout = 180 # 3分钟超时
debug_logger.info(f"设置解压超时: {extract_timeout}") debug_logger.debug(f"设置解压超时: {extract_timeout}")
# 创建子线程执行解压 # 创建子线程执行解压
import threading import threading
@@ -280,7 +289,7 @@ class ExtractionThread(QThread):
debug_logger.error(f"解压错误: {error}") debug_logger.error(f"解压错误: {error}")
raise error raise error
debug_logger.info(f"文件解压完成") debug_logger.debug(f"文件解压完成")
update_progress(60, f"正在复制 {self.game_version} 的补丁文件...") update_progress(60, f"正在复制 {self.game_version} 的补丁文件...")
@@ -290,24 +299,26 @@ class ExtractionThread(QThread):
# 检查解压后的文件是否存在及其大小 # 检查解压后的文件是否存在及其大小
if os.path.exists(extracted_file_path): if os.path.exists(extracted_file_path):
file_size = os.path.getsize(extracted_file_path) file_size = os.path.getsize(extracted_file_path)
debug_logger.info(f"解压后的主补丁文件存在: {extracted_file_path}, 大小: {file_size} 字节") debug_logger.debug(f"解压后的主补丁文件存在: {extracted_file_path}, 大小: {file_size} 字节")
else: else:
debug_logger.error(f"解压后的主补丁文件不存在: {extracted_file_path}") debug_logger.error(f"解压后的主补丁文件不存在: {extracted_file_path}")
raise FileNotFoundError(f"解压后的文件不存在: {extracted_file_path}") raise FileNotFoundError(f"解压后的文件不存在: {extracted_file_path}")
# 构建目标路径并复制 # 构建目标路径并复制
target_path = os.path.join(self.game_folder, target_filename) target_path = os.path.join(self.game_folder, target_filename)
debug_logger.info(f"复制主补丁文件: {extracted_file_path}{target_path}") debug_logger.debug(f"复制主补丁文件: {extracted_file_path}{target_path}")
shutil.copy2(extracted_file_path, target_path) shutil.copy2(extracted_file_path, target_path)
# 验证主补丁文件是否成功复制 # 验证主补丁文件是否成功复制
if os.path.exists(target_path): if os.path.exists(target_path):
target_size = os.path.getsize(target_path) target_size = os.path.getsize(target_path)
debug_logger.info(f"主补丁文件成功复制: {target_path}, 大小: {target_size} 字节") debug_logger.debug(f"主补丁文件成功复制: {target_path}, 大小: {target_size} 字节")
else: else:
debug_logger.error(f"主补丁文件复制失败: {target_path}") debug_logger.error(f"主补丁文件复制失败: {target_path}")
raise FileNotFoundError(f"目标文件复制失败: {target_path}") raise FileNotFoundError(f"目标文件复制失败: {target_path}")
# 只有NEKOPARA After版本才需要处理签名文件
if self.game_version == "NEKOPARA After":
# 如果有找到签名文件,也复制它 # 如果有找到签名文件,也复制它
if sig_file_in_archive: if sig_file_in_archive:
update_progress(80, f"正在复制签名文件...") update_progress(80, f"正在复制签名文件...")
@@ -315,20 +326,18 @@ class ExtractionThread(QThread):
if os.path.exists(extracted_sig_path): if os.path.exists(extracted_sig_path):
sig_size = os.path.getsize(extracted_sig_path) sig_size = os.path.getsize(extracted_sig_path)
debug_logger.info(f"解压后的签名文件存在: {extracted_sig_path}, 大小: {sig_size} 字节") debug_logger.debug(f"解压后的签名文件存在: {extracted_sig_path}, 大小: {sig_size} 字节")
# 复制签名文件到游戏目录 # 复制签名文件到游戏目录
sig_target = os.path.join(self.game_folder, sig_filename) sig_target = os.path.join(self.game_folder, sig_filename)
shutil.copy2(extracted_sig_path, sig_target) shutil.copy2(extracted_sig_path, sig_target)
debug_logger.info(f"签名文件成功复制: {sig_target}") debug_logger.debug(f"签名文件成功复制: {sig_target}")
else: else:
debug_logger.warning(f"解压后的签名文件不存在: {extracted_sig_path}") debug_logger.warning(f"解压后的签名文件不存在: {extracted_sig_path}")
# 尝试使用内置签名文件
self._try_use_builtin_signature(sig_filename, debug_logger, update_progress)
else: else:
debug_logger.warning(f"没有找到签名文件,尝试使用内置签名文件") debug_logger.warning(f"压缩包中没有找到签名文件,但继续安装主补丁文件")
# 尝试使用内置签名文件 else:
self._try_use_builtin_signature(sig_filename, debug_logger, update_progress) debug_logger.info(f"{self.game_version} 不需要签名文件,跳过签名文件处理")
update_progress(100, f"{self.game_version} 补丁文件解压完成") update_progress(100, f"{self.game_version} 补丁文件解压完成")
self.finished.emit(True, "", self.game_version) self.finished.emit(True, "", self.game_version)
@@ -339,42 +348,4 @@ class ExtractionThread(QThread):
pass pass
self.finished.emit(False, f"\n文件操作失败,请重试\n\n【错误信息】:{e}\n", self.game_version) self.finished.emit(False, f"\n文件操作失败,请重试\n\n【错误信息】:{e}\n", self.game_version)
# 添加一个新的辅助方法用于使用内置签名文件
def _try_use_builtin_signature(self, sig_filename, debug_logger, update_progress):
"""尝试使用内置的签名文件"""
try:
# 如果签名文件不在压缩包中,则尝试使用原始路径
update_progress(85, f"尝试使用内置签名文件...")
sig_path = os.path.join(PLUGIN, GAME_INFO[self.game_version]["sig_path"])
debug_logger.info(f"内置签名文件路径: {sig_path}")
if os.path.exists(sig_path):
sig_size = os.path.getsize(sig_path)
debug_logger.info(f"内置签名文件存在,大小: {sig_size} 字节")
# 确保使用正确的签名文件名
sig_target = os.path.join(self.game_folder, sig_filename)
debug_logger.info(f"目标签名文件路径: {sig_target}")
# 增加异常处理
try:
shutil.copy2(sig_path, sig_target)
if os.path.exists(sig_target):
target_sig_size = os.path.getsize(sig_target)
debug_logger.info(f"内置签名文件成功复制到目标位置,大小: {target_sig_size} 字节")
else:
debug_logger.error(f"内置签名文件复制失败,目标文件不存在: {sig_target}")
except Exception as copy_err:
debug_logger.error(f"复制内置签名文件时出错: {str(copy_err)}")
debug_logger.error(f"错误详情: {traceback.format_exc()}")
update_progress(90, f"使用内置签名文件完成")
else:
debug_logger.warning(f"内置签名文件不存在: {sig_path}")
update_progress(85, f"未找到内置签名文件,继续安装主补丁文件")
except Exception as sig_err:
# 签名文件处理失败时记录错误但不中断主流程
debug_logger.error(f"内置签名文件处理异常: {str(sig_err)}")
debug_logger.error(f"异常详情: {traceback.format_exc()}")
update_progress(85, f"内置签名文件处理失败: {str(sig_err)}")

View File

@@ -147,12 +147,13 @@ class HashThread(QThread):
# 记录文件大小信息 # 记录文件大小信息
file_size = os.path.getsize(install_path) file_size = os.path.getsize(install_path)
logger.info(f"正在校验 {game_version} 补丁文件: {install_path}, 文件大小: {file_size} 字节") logger.info(f"开始校验 {game_version} 补丁文件")
logger.debug(f"文件路径: {install_path}, 文件大小: {file_size} 字节")
# 增加块大小,提高大文件处理性能 # 增加块大小,提高大文件处理性能
# 文件越大块越大最大256MB # 文件越大块越大最大256MB
chunk_size = min(256 * 1024 * 1024, max(16 * 1024 * 1024, file_size // 20)) chunk_size = min(256 * 1024 * 1024, max(16 * 1024 * 1024, file_size // 20))
logger.info(f" 使用块大小: {chunk_size // (1024 * 1024)}MB") logger.debug(f"使用块大小: {chunk_size // (1024 * 1024)}MB")
# 分块读取,避免大文件一次性读取内存 # 分块读取,避免大文件一次性读取内存
hash_obj = hashlib.sha256() hash_obj = hashlib.sha256()
@@ -182,7 +183,7 @@ class HashThread(QThread):
progress = bytes_read / file_size * 100 progress = bytes_read / file_size * 100
elapsed = current_time - start_time elapsed = current_time - start_time
speed = bytes_read / (elapsed if elapsed > 0 else 1) / (1024 * 1024) # MB/s speed = bytes_read / (elapsed if elapsed > 0 else 1) / (1024 * 1024) # MB/s
logger.info(f" 进度: {progress:.1f}% - 已处理: {bytes_read/(1024*1024):.1f}MB/{file_size/(1024*1024):.1f}MB - 速度: {speed:.1f}MB/s") logger.debug(f"哈希计算进度: {progress:.1f}% - 已处理: {bytes_read/(1024*1024):.1f}MB/{file_size/(1024*1024):.1f}MB - 速度: {speed:.1f}MB/s")
last_progress_time = current_time last_progress_time = current_time
# 计算最终的哈希值 # 计算最终的哈希值
@@ -190,15 +191,16 @@ class HashThread(QThread):
# 记录总用时 # 记录总用时
total_time = time.time() - start_time total_time = time.time() - start_time
logger.info(f" 哈希计算完成,耗时: {total_time:.1f}秒,平均速度: {file_size/(total_time*1024*1024):.1f}MB/s") logger.debug(f"哈希计算完成,耗时: {total_time:.1f}秒,平均速度: {file_size/(total_time*1024*1024):.1f}MB/s")
# 详细记录哈希比较结果 # 记录哈希比较结果
logger.info(f"哈希校验结果 - {game_version}:") is_valid = file_hash == expected_hash
logger.info(f" 文件: {install_path}") logger.info(f"{game_version} 哈希校验{'通过' if is_valid else '失败'}")
logger.info(f" 读取字节数: {bytes_read} / {file_size}") logger.debug(f"哈希校验详情 - {game_version}:")
logger.info(f" 预期哈希: {expected_hash}") logger.debug(f" 文件: {install_path}")
logger.info(f" 实际哈希: {file_hash}") logger.debug(f" 读取字节数: {bytes_read} / {file_size}")
logger.info(f" 匹配结果: {file_hash == expected_hash}") logger.debug(f" 预期哈希: {expected_hash}")
logger.debug(f" 实际哈希: {file_hash}")
if debug_mode: if debug_mode:
logger.debug(f"DEBUG: 哈希后检查 - {game_version}") logger.debug(f"DEBUG: 哈希后检查 - {game_version}")