mirror of
https://github.com/hyb-oyqq/FRAISEMOE-Addons-Installer-NEXT.git
synced 2025-12-20 05:48:35 +00:00
refactor(source): 重构 cloudflare优化器并改进下载功能
- 重构 IpOptimizer 类,优化 CloudflareSpeedTest 工具的调用和处理 - 改进下载功能,包括手动停止下载、错误处理和日志记录 - 更新配置文件,增加日志文件路径和用户代理模板
This commit is contained in:
222
source/utils.py
222
source/utils.py
@@ -4,19 +4,21 @@ import base64
|
||||
import hashlib
|
||||
import concurrent.futures
|
||||
import ctypes
|
||||
import json
|
||||
import psutil
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
import re
|
||||
from PySide6.QtGui import QIcon, QPixmap
|
||||
from pic_data import img_data
|
||||
from config import APP_NAME
|
||||
from config import APP_NAME, CONFIG_FILE
|
||||
|
||||
def resource_path(relative_path):
|
||||
"""获取资源的绝对路径,适用于开发环境和PyInstaller打包环境"""
|
||||
if getattr(sys, 'frozen', False):
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
base_path = sys._MEIPASS # type: ignore
|
||||
else:
|
||||
base_path = os.path.dirname(sys.executable)
|
||||
# PyInstaller创建的临时文件夹,并将路径存储在_MEIPASS中
|
||||
base_path = getattr(sys, '_MEIPASS', os.path.dirname(sys.executable))
|
||||
else:
|
||||
# 在开发环境中运行
|
||||
base_path = os.path.dirname(os.path.abspath(__file__))
|
||||
return os.path.join(base_path, relative_path)
|
||||
|
||||
@@ -35,7 +37,7 @@ def msgbox_frame(title, text, buttons=QtWidgets.QMessageBox.StandardButton.NoBut
|
||||
pixmap = load_base64_image(icon_data)
|
||||
if not pixmap.isNull():
|
||||
msg_box.setWindowIcon(QIcon(pixmap))
|
||||
msg_box.setIconPixmap(pixmap.scaled(64, 64, QtCore.Qt.AspectRatioMode.KeepAspectRatio))
|
||||
msg_box.setIconPixmap(pixmap.scaled(64, 64, QtCore.Qt.AspectRatioMode.KeepAspectRatio, QtCore.Qt.TransformationMode.SmoothTransformation))
|
||||
else:
|
||||
msg_box.setIcon(QtWidgets.QMessageBox.Icon.Information)
|
||||
|
||||
@@ -43,6 +45,24 @@ def msgbox_frame(title, text, buttons=QtWidgets.QMessageBox.StandardButton.NoBut
|
||||
msg_box.setStandardButtons(buttons)
|
||||
return msg_box
|
||||
|
||||
def load_config():
|
||||
if not os.path.exists(CONFIG_FILE):
|
||||
return {}
|
||||
try:
|
||||
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except (json.JSONDecodeError, IOError):
|
||||
return {}
|
||||
|
||||
def save_config(config):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True)
|
||||
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(config, f, indent=4)
|
||||
except IOError as e:
|
||||
print(f"Error saving config: {e}")
|
||||
|
||||
|
||||
class HashManager:
|
||||
def __init__(self, HASH_SIZE):
|
||||
self.HASH_SIZE = HASH_SIZE
|
||||
@@ -65,13 +85,8 @@ class HashManager:
|
||||
try:
|
||||
results[file_path] = future.result()
|
||||
except Exception as e:
|
||||
results[file_path] = None
|
||||
msg_box = msgbox_frame(
|
||||
f"错误 - {APP_NAME}",
|
||||
f"\n文件哈希值计算失败\n\n【错误信息】:{e}\n",
|
||||
QtWidgets.QMessageBox.StandardButton.Ok,
|
||||
)
|
||||
msg_box.exec()
|
||||
results[file_path] = None # Mark as failed
|
||||
print(f"Error calculating hash for {file_path}: {e}")
|
||||
return results
|
||||
|
||||
def hash_pop_window(self):
|
||||
@@ -80,26 +95,26 @@ class HashManager:
|
||||
QtWidgets.QApplication.processEvents()
|
||||
return msg_box
|
||||
|
||||
def cfg_pre_hash_compare(self, install_path, game_version, plugin_hash, installed_status):
|
||||
if not os.path.exists(install_path):
|
||||
installed_status[game_version] = False
|
||||
return
|
||||
file_hash = self.hash_calculate(install_path)
|
||||
if file_hash == plugin_hash[game_version]:
|
||||
installed_status[game_version] = True
|
||||
else:
|
||||
reply = msgbox_frame(
|
||||
f"文件校验 - {APP_NAME}",
|
||||
f"\n检测到 {game_version} 的文件哈希值不匹配,是否重新安装?\n",
|
||||
QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No,
|
||||
).exec()
|
||||
if reply == QtWidgets.QMessageBox.StandardButton.Yes:
|
||||
installed_status[game_version] = False
|
||||
else:
|
||||
installed_status[game_version] = True
|
||||
def cfg_pre_hash_compare(self, install_paths, plugin_hash, installed_status):
|
||||
status_copy = installed_status.copy()
|
||||
|
||||
for game_version, install_path in install_paths.items():
|
||||
if not os.path.exists(install_path):
|
||||
status_copy[game_version] = False
|
||||
continue
|
||||
|
||||
try:
|
||||
file_hash = self.hash_calculate(install_path)
|
||||
if file_hash == plugin_hash.get(game_version):
|
||||
status_copy[game_version] = True
|
||||
else:
|
||||
status_copy[game_version] = False
|
||||
except Exception:
|
||||
status_copy[game_version] = False
|
||||
|
||||
return status_copy
|
||||
|
||||
def cfg_after_hash_compare(self, install_paths, plugin_hash, installed_status):
|
||||
passed = True
|
||||
file_paths = [
|
||||
install_paths[game] for game in plugin_hash if installed_status.get(game)
|
||||
]
|
||||
@@ -107,18 +122,25 @@ class HashManager:
|
||||
|
||||
for game, hash_value in plugin_hash.items():
|
||||
if installed_status.get(game):
|
||||
file_hash = hash_results.get(install_paths[game])
|
||||
if file_hash != hash_value:
|
||||
msg_box = msgbox_frame(
|
||||
f"文件校验 - {APP_NAME}",
|
||||
f"\n检测到 {game} 的文件哈希值不匹配\n",
|
||||
QtWidgets.QMessageBox.StandardButton.Ok,
|
||||
)
|
||||
msg_box.exec()
|
||||
file_path = install_paths[game]
|
||||
file_hash = hash_results.get(file_path)
|
||||
|
||||
if file_hash is None:
|
||||
installed_status[game] = False
|
||||
passed = False
|
||||
break
|
||||
return passed
|
||||
return {
|
||||
"passed": False,
|
||||
"game": game,
|
||||
"message": f"\n无法计算 {game} 的文件哈希值,文件可能已损坏或被占用。\n"
|
||||
}
|
||||
|
||||
if file_hash != hash_value:
|
||||
installed_status[game] = False
|
||||
return {
|
||||
"passed": False,
|
||||
"game": game,
|
||||
"message": f"\n检测到 {game} 的文件哈希值不匹配。\n"
|
||||
}
|
||||
return {"passed": True}
|
||||
|
||||
class AdminPrivileges:
|
||||
def __init__(self):
|
||||
@@ -194,4 +216,118 @@ class AdminPrivileges:
|
||||
QtWidgets.QMessageBox.StandardButton.Ok,
|
||||
)
|
||||
msg_box.exec()
|
||||
sys.exit(1)
|
||||
sys.exit(1)
|
||||
|
||||
class HostsManager:
|
||||
def __init__(self):
|
||||
self.hosts_path = os.path.join(os.environ['SystemRoot'], 'System32', 'drivers', 'etc', 'hosts')
|
||||
self.backup_path = os.path.join(os.path.dirname(self.hosts_path), f'hosts.bak.{APP_NAME}')
|
||||
self.original_content = None
|
||||
self.modified = False
|
||||
|
||||
def backup(self):
|
||||
if not AdminPrivileges().is_admin():
|
||||
print("需要管理员权限来备份hosts文件。")
|
||||
return False
|
||||
try:
|
||||
with open(self.hosts_path, 'r', encoding='utf-8') as f:
|
||||
self.original_content = f.read()
|
||||
with open(self.backup_path, 'w', encoding='utf-8') as f:
|
||||
f.write(self.original_content)
|
||||
print(f"Hosts文件已备份到: {self.backup_path}")
|
||||
return True
|
||||
except IOError as e:
|
||||
print(f"备份hosts文件失败: {e}")
|
||||
msg_box = msgbox_frame(f"错误 - {APP_NAME}", f"\n无法备份hosts文件,请检查权限。\n\n【错误信息】:{e}\n", QtWidgets.QMessageBox.StandardButton.Ok)
|
||||
msg_box.exec()
|
||||
return False
|
||||
|
||||
def apply_ip(self, hostname, ip_address):
|
||||
if not self.original_content:
|
||||
if not self.backup():
|
||||
return False
|
||||
|
||||
if not self.original_content: # 再次检查,确保backup成功
|
||||
print("无法读取hosts文件内容,操作中止。")
|
||||
return False
|
||||
|
||||
if not AdminPrivileges().is_admin():
|
||||
print("需要管理员权限来修改hosts文件。")
|
||||
return False
|
||||
|
||||
try:
|
||||
lines = self.original_content.splitlines()
|
||||
new_lines = [line for line in lines if not (hostname in line and line.strip().startswith(ip_address))]
|
||||
|
||||
new_entry = f"{ip_address}\t{hostname}"
|
||||
new_lines.append(f"\n# Added by {APP_NAME}")
|
||||
new_lines.append(new_entry)
|
||||
|
||||
with open(self.hosts_path, 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(new_lines))
|
||||
|
||||
self.modified = True
|
||||
print(f"Hosts文件已更新: {new_entry}")
|
||||
return True
|
||||
except IOError as e:
|
||||
print(f"修改hosts文件失败: {e}")
|
||||
msg_box = msgbox_frame(f"错误 - {APP_NAME}", f"\n无法修改hosts文件,请检查权限。\n\n【错误信息】:{e}\n", QtWidgets.QMessageBox.StandardButton.Ok)
|
||||
msg_box.exec()
|
||||
return False
|
||||
|
||||
def restore(self):
|
||||
if not self.modified:
|
||||
if os.path.exists(self.backup_path):
|
||||
try:
|
||||
os.remove(self.backup_path)
|
||||
except OSError:
|
||||
pass
|
||||
return True
|
||||
|
||||
if not AdminPrivileges().is_admin():
|
||||
print("需要管理员权限来恢复hosts文件。")
|
||||
return False
|
||||
|
||||
if self.original_content:
|
||||
try:
|
||||
with open(self.hosts_path, 'w', encoding='utf-8') as f:
|
||||
f.write(self.original_content)
|
||||
self.modified = False
|
||||
print("Hosts文件已从内存恢复。")
|
||||
if os.path.exists(self.backup_path):
|
||||
try:
|
||||
os.remove(self.backup_path)
|
||||
except OSError:
|
||||
pass
|
||||
return True
|
||||
except IOError as e:
|
||||
print(f"从内存恢复hosts文件失败: {e}")
|
||||
return self.restore_from_backup_file()
|
||||
else:
|
||||
return self.restore_from_backup_file()
|
||||
|
||||
def restore_from_backup_file(self):
|
||||
if not os.path.exists(self.backup_path):
|
||||
print("未找到hosts备份文件,无法恢复。")
|
||||
return False
|
||||
try:
|
||||
with open(self.backup_path, 'r', encoding='utf-8') as bf:
|
||||
backup_content = bf.read()
|
||||
with open(self.hosts_path, 'w', encoding='utf-8') as hf:
|
||||
hf.write(backup_content)
|
||||
os.remove(self.backup_path)
|
||||
self.modified = False
|
||||
print("Hosts文件已从备份文件恢复。")
|
||||
return True
|
||||
except (IOError, OSError) as e:
|
||||
print(f"从备份文件恢复hosts失败: {e}")
|
||||
msg_box = msgbox_frame(f"警告 - {APP_NAME}", f"\n自动恢复hosts文件失败,请手动从 {self.backup_path} 恢复。\n\n【错误信息】:{e}\n", QtWidgets.QMessageBox.StandardButton.Ok)
|
||||
msg_box.exec()
|
||||
return False
|
||||
|
||||
def censor_url(text):
|
||||
"""Censors URLs in a given text string."""
|
||||
if not isinstance(text, str):
|
||||
text = str(text)
|
||||
url_pattern = re.compile(r'https?://[^\s/$.?#].[^\s]*')
|
||||
return url_pattern.sub('***URL HIDDEN***', text)
|
||||
Reference in New Issue
Block a user