feat(core): 增强hosts管理功能和自动还原设置

- 添加对hosts文件优选IP记录的检查,避免重复优选。
- 添加禁用自动还原hosts的选项,允许用户自定义设置。
- 更新HostsManager以支持自动还原状态的设置和检查,优化hosts文件的管理逻辑。
This commit is contained in:
hyb-oyqq
2025-08-04 11:44:10 +08:00
parent 19da86c808
commit 98bfddeb04
6 changed files with 237 additions and 3 deletions

View File

@@ -28,6 +28,7 @@ class CloudflareOptimizer:
self.optimization_cancelled = False
self.ip_optimizer_thread = None
self.ipv6_optimizer_thread = None
self.has_optimized_in_session = False # 本次启动是否已执行过优选
def is_optimization_done(self):
"""检查是否已完成优化
@@ -67,6 +68,39 @@ class CloudflareOptimizer:
Args:
url: 用于优化的URL
"""
# 解析域名
hostname = urlparse(url).hostname
# 检查hosts文件中是否已有该域名的IP记录
existing_ips = self.hosts_manager.get_hostname_entries(hostname) if hostname else []
# 判断是否继续优选的逻辑
if existing_ips and self.has_optimized_in_session:
# 如果本次会话中已执行过优选且hosts中存在记录则跳过优选过程
print(f"发现hosts文件中已有域名 {hostname} 的优选IP记录且本次会话已优选过跳过优选过程")
# 设置标记为已优选完成
self.optimization_done = True
self.countdown_finished = True
# 尝试获取现有的IPv4和IPv6地址
ipv4_entries = [ip for ip in existing_ips if ':' not in ip] # IPv4地址不含冒号
ipv6_entries = [ip for ip in existing_ips if ':' in ip] # IPv6地址包含冒号
if ipv4_entries:
self.optimized_ip = ipv4_entries[0]
if ipv6_entries:
self.optimized_ipv6 = ipv6_entries[0]
print(f"使用已存在的优选IP - IPv4: {self.optimized_ip}, IPv6: {self.optimized_ipv6}")
return True
else:
# 如果本次会话尚未优选过或hosts中没有记录则显示优选窗口
if existing_ips:
print(f"发现hosts文件中已有域名 {hostname} 的优选IP记录但本次会话尚未优选过")
# 清理已有的hosts记录准备重新优选
self.hosts_manager.clean_hostname_entries(hostname)
# 创建取消状态标记
self.optimization_cancelled = False
self.countdown_finished = False
@@ -332,6 +366,15 @@ class CloudflareOptimizer:
if ipv6_success:
success = self.hosts_manager.apply_ip(hostname, self.optimized_ipv6, clean=False) or success
# 记录此次优选操作对hosts文件进行了更新
if hasattr(self.main_window, 'config'):
self.main_window.config['last_hosts_optimized_hostname'] = hostname
from utils import save_config
save_config(self.main_window.config)
# 记录本次会话已执行过优选
self.has_optimized_in_session = True
if success:
msg_box = QtWidgets.QMessageBox(self.main_window)
msg_box.setWindowTitle(f"成功 - {self.main_window.APP_NAME}")

View File

@@ -406,6 +406,38 @@ class DownloadManager:
def _show_cloudflare_option(self):
"""显示Cloudflare加速选择对话框"""
# 首先检查队列中第一个URL的域名是否已在hosts中有优选IP
if self.download_queue:
first_url = self.download_queue[0][0]
hostname = urlparse(first_url).hostname
# 检查hosts文件中是否已有该域名的IP记录
if hostname:
existing_ips = self.cloudflare_optimizer.hosts_manager.get_hostname_entries(hostname)
if existing_ips:
print(f"发现hosts文件中已有域名 {hostname} 的优选IP记录跳过询问直接使用")
# 设置标记为已优选完成
self.cloudflare_optimizer.optimization_done = True
self.cloudflare_optimizer.countdown_finished = True
# 尝试获取现有的IPv4和IPv6地址
ipv4_entries = [ip for ip in existing_ips if ':' not in ip]
ipv6_entries = [ip for ip in existing_ips if ':' in ip]
if ipv4_entries:
self.cloudflare_optimizer.optimized_ip = ipv4_entries[0]
if ipv6_entries:
self.cloudflare_optimizer.optimized_ipv6 = ipv6_entries[0]
# 保存当前URL供CloudflareOptimizer使用
self.main_window.current_url = first_url
# 直接开始下载,跳过询问
self.next_download_task()
return
# 临时启用窗口以显示对话框
self.main_window.setEnabled(True)

View File

@@ -341,12 +341,26 @@ class UIManager:
self.clean_hosts_action.setFont(menu_font)
self.clean_hosts_action.triggered.connect(self.clean_hosts_entries)
# 添加禁用自动还原hosts的选项
self.disable_auto_restore_action = QAction("禁用关闭/重启自动还原hosts", self.main_window, checkable=True)
self.disable_auto_restore_action.setFont(menu_font)
# 从配置中读取当前状态
config = getattr(self.main_window, 'config', {})
disable_auto_restore = False
if isinstance(config, dict):
disable_auto_restore = config.get("disable_auto_restore_hosts", False)
self.disable_auto_restore_action.setChecked(disable_auto_restore)
self.disable_auto_restore_action.triggered.connect(self.toggle_disable_auto_restore_hosts)
# 添加打开hosts文件选项
self.open_hosts_action = QAction("打开hosts文件", self.main_window)
self.open_hosts_action.setFont(menu_font)
self.open_hosts_action.triggered.connect(self.open_hosts_file)
# 添加到hosts子菜单
self.hosts_submenu.addAction(self.disable_auto_restore_action)
self.hosts_submenu.addAction(self.restore_hosts_action)
self.hosts_submenu.addAction(self.clean_hosts_action)
self.hosts_submenu.addAction(self.open_hosts_action)
@@ -645,6 +659,54 @@ class UIManager:
msg_box = self._create_message_box("错误", f"\n打开hosts文件时发生错误\n\n{str(e)}\n")
msg_box.exec()
def toggle_disable_auto_restore_hosts(self, checked):
"""切换禁用自动还原hosts的状态
Args:
checked: 是否禁用自动还原
"""
if hasattr(self.main_window, 'download_manager') and hasattr(self.main_window.download_manager, 'hosts_manager'):
try:
# 调用HostsManager的方法设置自动还原标志
result = self.main_window.download_manager.hosts_manager.set_auto_restore_disabled(checked)
if result:
# 同时更新内部配置,确保立即生效
if hasattr(self.main_window, 'config'):
self.main_window.config['disable_auto_restore_hosts'] = checked
# 显示成功提示
status = "禁用" if checked else "启用"
msg_box = self._create_message_box(
"设置已更新",
f"\n{status}关闭/重启时自动还原hosts。\n\n{'hosts将被保留' if checked else 'hosts将在关闭时自动还原'}\n"
)
msg_box.exec()
else:
# 如果设置失败,恢复复选框状态
self.disable_auto_restore_action.setChecked(not checked)
msg_box = self._create_message_box(
"设置失败",
"\n更新设置时发生错误,请稍后再试。\n"
)
msg_box.exec()
except Exception as e:
# 如果发生异常,恢复复选框状态
self.disable_auto_restore_action.setChecked(not checked)
msg_box = self._create_message_box(
"错误",
f"\n更新设置时发生异常:\n\n{str(e)}\n"
)
msg_box.exec()
else:
# 如果hosts管理器不可用恢复复选框状态
self.disable_auto_restore_action.setChecked(not checked)
msg_box = self._create_message_box(
"错误",
"\nhosts管理器不可用无法更新设置。\n"
)
msg_box.exec()
def show_about_dialog(self):
"""显示关于对话框"""
about_text = f"""

View File

@@ -3,7 +3,7 @@ import base64
# 配置信息
app_data = {
"APP_VERSION": "1.3.1",
"APP_VERSION": "1.3.2",
"APP_NAME": "FRAISEMOE Addons Installer NEXT",
"TEMP": "TEMP",
"CACHE": "FRAISEMOE",

View File

@@ -456,10 +456,10 @@ class MainWindow(QMainWindow):
event.ignore()
return
# 恢复hosts文件
# 恢复hosts文件(如果未禁用自动还原)
self.download_manager.hosts_manager.restore()
# 额外检查并清理hosts文件中的残留记录
# 额外检查并清理hosts文件中的残留记录(如果未禁用自动还原)
self.download_manager.hosts_manager.check_and_clean_all_entries()
# 停止日志记录

View File

@@ -273,7 +273,53 @@ class HostsManager:
self.original_content = None
self.modified = False
self.modified_hostnames = set() # 跟踪被修改的主机名
self.auto_restore_disabled = False # 是否禁用自动还原hosts
def get_hostname_entries(self, hostname):
"""获取hosts文件中指定域名的所有IP记录
Args:
hostname: 要查询的域名
Returns:
list: 域名对应的IP地址列表如果未找到则返回空列表
"""
try:
# 如果original_content为空先读取hosts文件
if not self.original_content:
try:
with open(self.hosts_path, 'r', encoding='utf-8') as f:
self.original_content = f.read()
except Exception as e:
print(f"读取hosts文件失败: {e}")
return []
# 解析hosts文件中的每一行
ip_addresses = []
lines = self.original_content.splitlines()
for line in lines:
# 跳过注释和空行
line = line.strip()
if not line or line.startswith('#'):
continue
# 分割行内容获取IP和域名
parts = line.split()
if len(parts) >= 2: # 至少包含IP和一个域名
ip = parts[0]
domains = parts[1:]
# 如果当前行包含目标域名
if hostname in domains:
ip_addresses.append(ip)
return ip_addresses
except Exception as e:
print(f"获取hosts记录失败: {e}")
return []
def backup(self):
if not AdminPrivileges().is_admin():
print("需要管理员权限来备份hosts文件。")
@@ -373,12 +419,58 @@ class HostsManager:
msg_box.exec()
return False
def set_auto_restore_disabled(self, disabled):
"""设置是否禁用自动还原hosts
Args:
disabled: 是否禁用自动还原hosts
Returns:
bool: 操作是否成功
"""
try:
# 更新状态
self.auto_restore_disabled = disabled
# 从配置文件读取当前配置
from utils import load_config, save_config
config = load_config()
# 更新配置
config['disable_auto_restore_hosts'] = disabled
# 保存配置
save_config(config)
print(f"{'禁用' if disabled else '启用'}自动还原hosts")
return True
except Exception as e:
print(f"设置自动还原hosts状态失败: {e}")
return False
def is_auto_restore_disabled(self):
"""检查是否禁用了自动还原hosts
Returns:
bool: 是否禁用自动还原hosts
"""
from utils import load_config
config = load_config()
auto_restore_disabled = config.get('disable_auto_restore_hosts', False)
self.auto_restore_disabled = auto_restore_disabled
return auto_restore_disabled
def check_and_clean_all_entries(self):
"""检查并清理所有由本应用程序添加的hosts记录
Returns:
bool: 清理是否成功
"""
# 如果禁用了自动还原,则不执行清理操作
if self.is_auto_restore_disabled():
print("已禁用自动还原hosts跳过清理操作")
return True
if not AdminPrivileges().is_admin():
print("需要管理员权限来检查和清理hosts文件。")
return False
@@ -423,6 +515,11 @@ class HostsManager:
return False
def restore(self):
# 如果禁用了自动还原,则不执行还原操作
if self.is_auto_restore_disabled():
print("已禁用自动还原hosts跳过还原操作")
return True
if not self.modified:
if os.path.exists(self.backup_path):
try: