feat(core): 增强离线模式支持和版本管理

- 在主窗口中添加离线模式管理器,支持自动切换到离线模式。
- 更新下载管理器以处理离线模式下的下载逻辑,确保用户体验流畅。
- 添加版本警告机制,提示用户在版本过低时的操作选项。
- 优化配置管理器,确保在离线模式下仍可使用相关功能。
- 更新UI管理器以反映当前工作模式,提升用户界面友好性。
This commit is contained in:
hyb-oyqq
2025-08-06 15:22:44 +08:00
parent b18f4a276c
commit 7befe19f30
17 changed files with 1707 additions and 148 deletions

View File

@@ -100,7 +100,9 @@ class DownloadManager:
raise ValueError("未能获取或解析配置数据")
if self.is_debug_mode():
print(f"DEBUG: Parsed JSON data: {json.dumps(config_data, indent=2)}")
# 创建安全版本的配置数据用于调试输出
safe_config = self._create_safe_config_for_logging(config_data)
print(f"DEBUG: Parsed JSON data: {json.dumps(safe_config, indent=2)}")
urls = {}
for i in range(4):
@@ -125,7 +127,18 @@ class DownloadManager:
raise ValueError(f"配置文件缺少必要的键: {', '.join(missing_original_keys)}")
if self.is_debug_mode():
print(f"DEBUG: Extracted URLs: {urls}")
# 创建安全版本的URL字典用于调试输出
safe_urls = {}
for key, url in urls.items():
# 保留域名部分,隐藏路径
import re
domain_match = re.match(r'(https?://[^/]+)/.*', url)
if domain_match:
domain = domain_match.group(1)
safe_urls[key] = f"{domain}/***隐藏URL路径***"
else:
safe_urls[key] = "***隐藏URL***"
print(f"DEBUG: Extracted URLs: {safe_urls}")
print("--- Finished getting download URL successfully ---")
return urls
@@ -158,11 +171,41 @@ class DownloadManager:
f"\n配置文件格式异常\n\n【错误信息】:{e}\n",
)
return {}
def _create_safe_config_for_logging(self, config_data):
"""创建用于日志记录的安全配置副本隐藏敏感URL
Args:
config_data: 原始配置数据
Returns:
dict: 安全的配置数据副本
"""
if not config_data or not isinstance(config_data, dict):
return config_data
# 创建深拷贝,避免修改原始数据
import copy
safe_config = copy.deepcopy(config_data)
# 隐藏敏感URL
for key in safe_config:
if isinstance(safe_config[key], dict) and "url" in safe_config[key]:
# 完全隐藏URL
safe_config[key]["url"] = "***URL protection***"
return safe_config
def download_action(self):
"""开始下载流程"""
self.main_window.download_queue_history = []
# 清除游戏检测器的目录缓存,确保获取最新的目录状态
if hasattr(self.main_window, 'game_detector') and hasattr(self.main_window.game_detector, 'clear_directory_cache'):
self.main_window.game_detector.clear_directory_cache()
if self.is_debug_mode():
print("DEBUG: 已清除游戏目录缓存,确保获取最新状态")
game_dirs = self.main_window.game_detector.identify_game_directories_improved(self.selected_folder)
debug_mode = self.is_debug_mode()
@@ -182,7 +225,7 @@ class DownloadManager:
self.main_window.ui.start_install_text.setText("开始安装")
return
self.main_window.hash_msg_box = self.main_window.hash_manager.hash_pop_window(check_type="pre")
self.main_window.hash_msg_box = self.main_window.hash_manager.hash_pop_window(check_type="pre", is_offline=False)
install_paths = self.get_install_paths()
@@ -345,22 +388,38 @@ class DownloadManager:
self.main_window.setEnabled(False)
config = self.get_download_url()
if not config:
QtWidgets.QMessageBox.critical(
self.main_window, f"错误 - {APP_NAME}", "\n网络状态异常或服务器故障,请重试\n"
)
self.main_window.setEnabled(True)
self.main_window.ui.start_install_text.setText("开始安装")
return
# 检查是否处于离线模式
is_offline_mode = False
if hasattr(self.main_window, 'offline_mode_manager'):
is_offline_mode = self.main_window.offline_mode_manager.is_in_offline_mode()
if is_offline_mode:
if debug_mode:
print("DEBUG: 使用离线模式,跳过网络配置获取")
self._fill_offline_download_queue(selected_game_dirs)
else:
config = self.get_download_url()
if not config:
QtWidgets.QMessageBox.critical(
self.main_window, f"错误 - {APP_NAME}", "\n网络状态异常或服务器故障,请重试\n"
)
self.main_window.setEnabled(True)
self.main_window.ui.start_install_text.setText("开始安装")
return
self._fill_download_queue(config, selected_game_dirs)
self._fill_download_queue(config, selected_game_dirs)
if not self.download_queue:
self.main_window.after_hash_compare()
return
self._show_cloudflare_option()
# 如果是离线模式,直接开始下一个下载任务
if is_offline_mode:
if debug_mode:
print("DEBUG: 离线模式跳过Cloudflare优化")
self.next_download_task()
else:
self._show_cloudflare_option()
def _fill_download_queue(self, config, game_dirs):
"""填充下载队列
@@ -406,6 +465,68 @@ class DownloadManager:
self.download_queue.append((url, game_folder, game_version, _7z_path, plugin_path))
self.main_window.download_queue_history.append(game_version)
def _fill_offline_download_queue(self, game_dirs):
"""填充离线模式下的下载队列
Args:
game_dirs: 包含游戏文件夹路径的字典
"""
self.download_queue.clear()
if not hasattr(self.main_window, 'download_queue_history'):
self.main_window.download_queue_history = []
debug_mode = self.is_debug_mode()
if debug_mode:
print(f"DEBUG: 填充离线下载队列, 游戏目录: {game_dirs}")
# 检查是否有离线模式管理器
if not hasattr(self.main_window, 'offline_mode_manager'):
if debug_mode:
print("DEBUG: 离线模式管理器未初始化,无法使用离线模式")
return
for i in range(1, 5):
game_version = f"NEKOPARA Vol.{i}"
if game_version in game_dirs and not self.main_window.installed_status.get(game_version, False):
# 获取离线补丁文件路径
offline_patch_path = self.main_window.offline_mode_manager.get_offline_patch_path(game_version)
if not offline_patch_path:
if debug_mode:
print(f"DEBUG: 未找到 {game_version} 的离线补丁文件,跳过")
continue
game_folder = game_dirs[game_version]
if debug_mode:
print(f"DEBUG: 使用识别到的游戏目录 {game_version}: {game_folder}")
print(f"DEBUG: 使用离线补丁文件: {offline_patch_path}")
_7z_path = os.path.join(PLUGIN, f"vol.{i}.7z")
plugin_path = os.path.join(PLUGIN, GAME_INFO[game_version]["plugin_path"])
# 将本地文件路径作为URL添加到下载队列
self.download_queue.append((offline_patch_path, game_folder, game_version, _7z_path, plugin_path))
self.main_window.download_queue_history.append(game_version)
game_version = "NEKOPARA After"
if game_version in game_dirs and not self.main_window.installed_status.get(game_version, False):
# 获取离线补丁文件路径
offline_patch_path = self.main_window.offline_mode_manager.get_offline_patch_path(game_version)
if offline_patch_path:
game_folder = game_dirs[game_version]
if debug_mode:
print(f"DEBUG: 使用识别到的游戏目录 {game_version}: {game_folder}")
print(f"DEBUG: 使用离线补丁文件: {offline_patch_path}")
_7z_path = os.path.join(PLUGIN, "after.7z")
plugin_path = os.path.join(PLUGIN, GAME_INFO[game_version]["plugin_path"])
# 将本地文件路径作为URL添加到下载队列
self.download_queue.append((offline_patch_path, game_folder, game_version, _7z_path, plugin_path))
self.main_window.download_queue_history.append(game_version)
elif debug_mode:
print(f"DEBUG: 未找到 {game_version} 的离线补丁文件,跳过")
def _show_cloudflare_option(self):
"""显示Cloudflare加速选择对话框"""
if self.download_queue:
@@ -498,7 +619,7 @@ class DownloadManager:
"""准备下载特定游戏版本
Args:
url: 下载URL
url: 下载URL或本地文件路径
game_folder: 游戏文件夹路径
game_version: 游戏版本名称
_7z_path: 7z文件保存路径
@@ -511,6 +632,10 @@ class DownloadManager:
print(f"DEBUG: 准备下载游戏 {game_version}")
print(f"DEBUG: 游戏文件夹: {game_folder}")
# 隐藏敏感URL
safe_url = "***URL protection***" # 完全隐藏URL
print(f"DEBUG: 下载URL: {safe_url}")
game_exe_exists = True
if (
@@ -525,15 +650,76 @@ class DownloadManager:
self.next_download_task()
return
self.main_window.progress_window = self.main_window.create_progress_window()
# 检查是否处于离线模式
is_offline_mode = False
if hasattr(self.main_window, 'offline_mode_manager'):
is_offline_mode = self.main_window.offline_mode_manager.is_in_offline_mode()
self.optimized_ip = self.cloudflare_optimizer.get_optimized_ip()
if self.optimized_ip:
print(f"已为 {game_version} 获取到优选IP: {self.optimized_ip}")
# 如果是离线模式且URL是本地文件路径
if is_offline_mode and os.path.isfile(url):
if debug_mode:
print(f"DEBUG: 离线模式,复制本地补丁文件 {url}{_7z_path}")
try:
# 确保目标目录存在
os.makedirs(os.path.dirname(_7z_path), exist_ok=True)
# 复制文件
import shutil
shutil.copy2(url, _7z_path)
# 验证文件哈希
hash_valid = False
if hasattr(self.main_window, 'offline_mode_manager'):
if debug_mode:
print(f"DEBUG: 开始验证补丁文件哈希: {_7z_path}")
hash_valid = self.main_window.offline_mode_manager.verify_patch_hash(game_version, _7z_path)
if debug_mode:
print(f"DEBUG: 补丁文件哈希验证结果: {'成功' if hash_valid else '失败'}")
else:
if debug_mode:
print("DEBUG: 离线模式管理器不可用,跳过哈希验证")
hash_valid = True # 如果没有离线模式管理器,假设验证成功
if hash_valid:
if debug_mode:
print(f"DEBUG: 成功复制并验证补丁文件 {_7z_path}")
# 直接进入解压阶段
self.main_window.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:
if debug_mode:
print(f"DEBUG: 补丁文件哈希验证失败")
# 显示错误消息
QtWidgets.QMessageBox.critical(
self.main_window,
f"错误 - {APP_NAME}",
f"\n补丁文件校验失败: {game_version}\n\n文件可能已损坏或被篡改,请重新获取补丁文件。\n"
)
# 继续下一个任务
self.next_download_task()
except Exception as e:
if debug_mode:
print(f"DEBUG: 复制补丁文件失败: {e}")
# 显示错误消息
QtWidgets.QMessageBox.critical(
self.main_window,
f"错误 - {APP_NAME}",
f"\n复制补丁文件失败: {game_version}\n错误: {e}\n"
)
# 继续下一个任务
self.next_download_task()
else:
print(f"未能为 {game_version} 获取优选IP将使用默认线路。")
# 在线模式,正常下载
self.main_window.progress_window = self.main_window.create_progress_window()
self.optimized_ip = self.cloudflare_optimizer.get_optimized_ip()
if self.optimized_ip:
print(f"已为 {game_version} 获取到优选IP: {self.optimized_ip}")
else:
print(f"未能为 {game_version} 获取优选IP将使用默认线路。")
self.download_task_manager.start_download(url, _7z_path, game_version, game_folder, plugin_path)
self.download_task_manager.start_download(url, _7z_path, game_version, game_folder, plugin_path)
def on_download_finished(self, success, error, url, game_folder, game_version, _7z_path, plugin_path):
"""下载完成后的处理