mirror of
https://github.com/hyb-oyqq/FRAISEMOE-Addons-Installer-NEXT.git
synced 2026-01-01 11:40:45 +00:00
feat(source): 优化下载功能并添加重试机制
- 移除冗余的 taskkill 导入,直接在需要时导入 subprocess - 调整正则表达式以更好地匹配 aria2c 输出 - 增加重试、跳过和终止选项的图形界面 - 优化下载失败时的错误处理和日志记录 - 改进资源路径获取方法,增加类型注解
This commit is contained in:
@@ -28,7 +28,7 @@ def resource_path(relative_path):
|
|||||||
"""获取资源的绝对路径,适用于开发环境和PyInstaller打包环境"""
|
"""获取资源的绝对路径,适用于开发环境和PyInstaller打包环境"""
|
||||||
try:
|
try:
|
||||||
# PyInstaller创建的临时文件夹
|
# PyInstaller创建的临时文件夹
|
||||||
base_path = sys._MEIPASS
|
base_path = sys._MEIPASS # type: ignore
|
||||||
except Exception:
|
except Exception:
|
||||||
base_path = os.path.dirname(os.path.abspath(__file__))
|
base_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
return os.path.join(base_path, relative_path)
|
return os.path.join(base_path, relative_path)
|
||||||
@@ -289,6 +289,7 @@ class DownloadThread(QThread):
|
|||||||
def stop(self):
|
def stop(self):
|
||||||
if self.process and self.process.poll() is None:
|
if self.process and self.process.poll() is None:
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
|
import subprocess
|
||||||
# 使用 taskkill 强制终止进程及其子进程
|
# 使用 taskkill 强制终止进程及其子进程
|
||||||
subprocess.run(['taskkill', '/F', '/T', '/PID', str(self.process.pid)], check=True)
|
subprocess.run(['taskkill', '/F', '/T', '/PID', str(self.process.pid)], check=True)
|
||||||
self.finished.emit(False, "下载已手动停止。")
|
self.finished.emit(False, "下载已手动停止。")
|
||||||
@@ -323,7 +324,6 @@ class DownloadThread(QThread):
|
|||||||
'--header', 'Sec-Fetch-Mode: cors',
|
'--header', 'Sec-Fetch-Mode: cors',
|
||||||
'--header', 'Sec-Fetch-Site: same-origin',
|
'--header', 'Sec-Fetch-Site: same-origin',
|
||||||
'--http-accept-gzip=true',
|
'--http-accept-gzip=true',
|
||||||
'--min-tls-version=TLSv1.2',
|
|
||||||
'--console-log-level=info',
|
'--console-log-level=info',
|
||||||
'--summary-interval=1',
|
'--summary-interval=1',
|
||||||
'--log-level=info',
|
'--log-level=info',
|
||||||
@@ -333,6 +333,8 @@ class DownloadThread(QThread):
|
|||||||
'--connect-timeout=60',
|
'--connect-timeout=60',
|
||||||
'--timeout=60',
|
'--timeout=60',
|
||||||
'--auto-file-renaming=false',
|
'--auto-file-renaming=false',
|
||||||
|
'--split=16',
|
||||||
|
'--max-connection-per-server=16',
|
||||||
self.url
|
self.url
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -341,12 +343,15 @@ class DownloadThread(QThread):
|
|||||||
|
|
||||||
# 正则表达式用于解析aria2c的输出
|
# 正则表达式用于解析aria2c的输出
|
||||||
# 例如: #1 GID[...]( 5%) CN:1 DL:10.5MiB/s ETA:1m30s
|
# 例如: #1 GID[...]( 5%) CN:1 DL:10.5MiB/s ETA:1m30s
|
||||||
progress_pattern = re.compile(r'\((\d+)%\).*?CN:(\d+).*?DL:([\d\.]+[KMG]?i?B/s).*?ETA:([\w\d]+)')
|
progress_pattern = re.compile(r'\((\d{1,3})%\).*?CN:(\d+).*?DL:\s*([^\s]+).*?ETA:\s*([^\s]+)')
|
||||||
|
|
||||||
full_output = []
|
full_output = []
|
||||||
while self.is_running and self.process.poll() is None:
|
while self.is_running and self.process.poll() is None:
|
||||||
line = self.process.stdout.readline()
|
if self.process.stdout:
|
||||||
if not line:
|
line = self.process.stdout.readline()
|
||||||
|
if not line:
|
||||||
|
break
|
||||||
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
full_output.append(line)
|
full_output.append(line)
|
||||||
@@ -390,9 +395,6 @@ class DownloadThread(QThread):
|
|||||||
|
|
||||||
# 下载进度窗口类
|
# 下载进度窗口类
|
||||||
class ProgressWindow(QDialog):
|
class ProgressWindow(QDialog):
|
||||||
# 添加一个信号,用于通知主窗口下载已停止
|
|
||||||
download_stopped = Signal()
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(ProgressWindow, self).__init__(parent)
|
super(ProgressWindow, self).__init__(parent)
|
||||||
self.setWindowTitle(f"下载进度 {APP_NAME}")
|
self.setWindowTitle(f"下载进度 {APP_NAME}")
|
||||||
@@ -434,11 +436,6 @@ class ProgressWindow(QDialog):
|
|||||||
# 如果需要,可以在这里添加逻辑,例如询问用户是否要停止下载
|
# 如果需要,可以在这里添加逻辑,例如询问用户是否要停止下载
|
||||||
event.ignore()
|
event.ignore()
|
||||||
|
|
||||||
def on_stop_clicked(self):
|
|
||||||
self.stop_button.setEnabled(False)
|
|
||||||
self.stop_button.setText("正在停止...")
|
|
||||||
self.download_stopped.emit()
|
|
||||||
self.reject() # 关闭窗口并返回一个QDialog.Rejected值
|
|
||||||
|
|
||||||
# 主窗口类
|
# 主窗口类
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
@@ -548,6 +545,7 @@ class MainWindow(QMainWindow):
|
|||||||
json_title = "配置文件异常,无法解析错误类型"
|
json_title = "配置文件异常,无法解析错误类型"
|
||||||
json_message = "配置文件异常,无法解析错误信息"
|
json_message = "配置文件异常,无法解析错误信息"
|
||||||
|
|
||||||
|
print(f"获取下载配置时出错: {e}") # 添加详细错误日志
|
||||||
QtWidgets.QMessageBox.critical(
|
QtWidgets.QMessageBox.critical(
|
||||||
self,
|
self,
|
||||||
f"错误 {APP_NAME}",
|
f"错误 {APP_NAME}",
|
||||||
@@ -598,9 +596,6 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# 连接停止按钮的信号
|
# 连接停止按钮的信号
|
||||||
self.progress_window.stop_button.clicked.connect(self.current_download_thread.stop)
|
self.progress_window.stop_button.clicked.connect(self.current_download_thread.stop)
|
||||||
# 连接窗口关闭信号,以处理用户手动停止的情况
|
|
||||||
self.progress_window.download_stopped.connect(self.on_download_stopped)
|
|
||||||
|
|
||||||
self.current_download_thread.start()
|
self.current_download_thread.start()
|
||||||
self.progress_window.exec() # 使用exec()以模态方式显示对话框
|
self.progress_window.exec() # 使用exec()以模态方式显示对话框
|
||||||
|
|
||||||
@@ -615,11 +610,71 @@ class MainWindow(QMainWindow):
|
|||||||
_7z_path,
|
_7z_path,
|
||||||
plugin_path,
|
plugin_path,
|
||||||
):
|
):
|
||||||
if not success and error == "下载已手动停止。":
|
if progress_window.isVisible():
|
||||||
# 用户手动停止了下载,不需要进行后续操作
|
progress_window.reject()
|
||||||
return
|
|
||||||
|
|
||||||
if self.progress_window.isVisible():
|
if not success: # 处理所有失败情况,包括手动停止
|
||||||
|
print(f"--- Download Failed: {game_version} ---")
|
||||||
|
print(error)
|
||||||
|
print("------------------------------------")
|
||||||
|
msg_box = QtWidgets.QMessageBox(self)
|
||||||
|
msg_box.setWindowTitle(f"下载失败 {APP_NAME}")
|
||||||
|
# 如果是手动停止,显示特定信息
|
||||||
|
if error == "下载已手动停止。":
|
||||||
|
msg_box.setText(f"\n下载已手动终止: {game_version}\n\n是否重试?")
|
||||||
|
else:
|
||||||
|
msg_box.setText(f"\n文件获取失败: {game_version}\n\n是否重试?")
|
||||||
|
|
||||||
|
retry_button = msg_box.addButton("重试", QtWidgets.QMessageBox.ButtonRole.YesRole)
|
||||||
|
next_button = msg_box.addButton("下一个", QtWidgets.QMessageBox.ButtonRole.NoRole)
|
||||||
|
end_button = msg_box.addButton("结束", QtWidgets.QMessageBox.ButtonRole.RejectRole)
|
||||||
|
|
||||||
|
icon_data = img_data.get("icon")
|
||||||
|
if icon_data:
|
||||||
|
pixmap = load_base64_image(icon_data)
|
||||||
|
if not pixmap.isNull():
|
||||||
|
msg_box.setWindowIcon(QIcon(pixmap))
|
||||||
|
|
||||||
|
msg_box.exec()
|
||||||
|
clicked_button = msg_box.clickedButton()
|
||||||
|
|
||||||
|
if clicked_button == retry_button:
|
||||||
|
self.download_setting(url, game_folder, game_version, _7z_path, plugin_path)
|
||||||
|
elif clicked_button == next_button:
|
||||||
|
self.next_download_task()
|
||||||
|
else: # End button or closed dialog
|
||||||
|
self.download_queue.clear()
|
||||||
|
self.after_hash_compare(PLUGIN_HASH)
|
||||||
|
return # 确保失败后不再执行成功逻辑
|
||||||
|
|
||||||
|
if success:
|
||||||
|
try:
|
||||||
|
msg_box = self.hash_manager.hash_pop_window()
|
||||||
|
QApplication.processEvents()
|
||||||
|
with py7zr.SevenZipFile(_7z_path, mode="r") as archive:
|
||||||
|
archive.extractall(path=PLUGIN)
|
||||||
|
|
||||||
|
# 创建游戏目录(如果不存在)
|
||||||
|
os.makedirs(game_folder, exist_ok=True)
|
||||||
|
|
||||||
|
# 复制主文件
|
||||||
|
shutil.copy(plugin_path, game_folder)
|
||||||
|
|
||||||
|
# 如果是After版本,还需要复制签名文件
|
||||||
|
if game_version == "NEKOPARA After":
|
||||||
|
sig_path = os.path.join(PLUGIN, GAME_INFO[game_version]["sig_path"])
|
||||||
|
shutil.copy(sig_path, game_folder)
|
||||||
|
|
||||||
|
self.installed_status[game_version] = True
|
||||||
|
except (py7zr.Bad7zFile, FileNotFoundError, Exception) as e:
|
||||||
|
QtWidgets.QMessageBox.critical(
|
||||||
|
self,
|
||||||
|
f"错误 {APP_NAME}",
|
||||||
|
f"\n文件操作失败,请重试\n\n【错误信息】:{e}\n",
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
msg_box.close()
|
||||||
|
self.next_download_task()
|
||||||
self.progress_window.close()
|
self.progress_window.close()
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
|
|||||||
Reference in New Issue
Block a user