diff --git a/app/core/__init__.py b/app/core/__init__.py
index 8a9058d..9240bc7 100644
--- a/app/core/__init__.py
+++ b/app/core/__init__.py
@@ -38,6 +38,7 @@ from .config import (
GeneralSubConfig,
Config,
)
+from .logger import logger
from .main_info_bar import MainInfoBar
from .network import Network
from .sound_player import SoundPlayer
@@ -52,6 +53,7 @@ __all__ = [
"MaaPlanConfig",
"GeneralConfig",
"GeneralSubConfig",
+ "logger",
"MainInfoBar",
"Network",
"SoundPlayer",
diff --git a/app/core/config.py b/app/core/config.py
index fe19472..b57c1a1 100644
--- a/app/core/config.py
+++ b/app/core/config.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtCore import Signal
import argparse
import sqlite3
@@ -53,6 +52,7 @@ from qfluentwidgets import (
from urllib.parse import urlparse
from typing import Union, Dict, List
+from .logger import logger
from .network import Network
@@ -707,7 +707,7 @@ class GeneralSubConfig(LQConfig):
class AppConfig(GlobalConfig):
- VERSION = "4.4.0.0"
+ VERSION = "4.4.1.1"
stage_refreshed = Signal()
PASSWORD_refreshed = Signal()
@@ -717,8 +717,8 @@ class AppConfig(GlobalConfig):
def __init__(self) -> None:
super().__init__()
- self.app_path = Path(sys.argv[0]).resolve().parent # 获取软件根目录
- self.app_path_sys = Path(sys.argv[0]).resolve() # 获取软件自身的路径
+ self.app_path = Path(sys.argv[0]).resolve().parent
+ self.app_path_sys = Path(sys.argv[0]).resolve()
self.log_path = self.app_path / "debug/AUTO_MAA.log"
self.database_path = self.app_path / "data/data.db"
@@ -781,7 +781,7 @@ class AppConfig(GlobalConfig):
self.init_logger()
self.check_data()
- logger.info("程序初始化完成")
+ logger.info("程序初始化完成", module="配置管理")
def init_logger(self) -> None:
"""初始化日志记录器"""
@@ -789,7 +789,7 @@ class AppConfig(GlobalConfig):
logger.add(
sink=self.log_path,
level="DEBUG",
- format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {message}",
+ format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {extra[module]} | {message}",
enqueue=True,
backtrace=True,
diagnose=True,
@@ -797,102 +797,28 @@ class AppConfig(GlobalConfig):
retention="1 month",
compression="zip",
)
- logger.info("")
- logger.info("===================================")
- logger.info("AUTO_MAA 主程序")
- logger.info(f"版本号: v{self.VERSION}")
- logger.info(f"根目录: {self.app_path}")
+ logger.add(
+ sink=sys.stderr,
+ level="DEBUG",
+ format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {extra[module]} | {message}",
+ enqueue=True,
+ backtrace=True,
+ diagnose=True,
+ colorize=True,
+ )
+
+ logger.info("", module="配置管理")
+ logger.info("===================================", module="配置管理")
+ logger.info("AUTO_MAA 主程序", module="配置管理")
+ logger.info(f"版本号: v{self.VERSION}", module="配置管理")
+ logger.info(f"根目录: {self.app_path}", module="配置管理")
logger.info(
- f"运行模式: {'图形化界面' if self.args.mode == 'gui' else '命令行界面'}"
+ f"运行模式: {'图形化界面' if self.args.mode == 'gui' else '命令行界面'}",
+ module="配置管理",
)
- logger.info("===================================")
+ logger.info("===================================", module="配置管理")
- logger.info("日志记录器初始化完成")
-
- def get_stage(self) -> None:
- """从MAA服务器获取活动关卡信息"""
-
- network = Network.add_task(
- mode="get",
- url="https://api.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json",
- )
- network.loop.exec()
- network_result = Network.get_result(network)
- if network_result["status_code"] == 200:
- stage_infos: List[Dict[str, Union[str, Dict[str, Union[str, int]]]]] = (
- network_result["response_json"]["Official"]["sideStoryStage"]
- )
- else:
- logger.warning(
- f"无法从MAA服务器获取活动关卡信息:{network_result['error_message']}"
- )
- stage_infos = []
-
- ss_stage_dict = {"value": [], "text": []}
-
- for stage_info in stage_infos:
-
- if (
- datetime.strptime(
- stage_info["Activity"]["UtcStartTime"], "%Y/%m/%d %H:%M:%S"
- )
- < datetime.now()
- < datetime.strptime(
- stage_info["Activity"]["UtcExpireTime"], "%Y/%m/%d %H:%M:%S"
- )
- ):
- ss_stage_dict["value"].append(stage_info["Value"])
- ss_stage_dict["text"].append(stage_info["Value"])
-
- # 生成每日关卡信息
- stage_daily_info = [
- {"value": "-", "text": "当前/上次", "days": [1, 2, 3, 4, 5, 6, 7]},
- {"value": "1-7", "text": "1-7", "days": [1, 2, 3, 4, 5, 6, 7]},
- {"value": "R8-11", "text": "R8-11", "days": [1, 2, 3, 4, 5, 6, 7]},
- {
- "value": "12-17-HARD",
- "text": "12-17-HARD",
- "days": [1, 2, 3, 4, 5, 6, 7],
- },
- {"value": "CE-6", "text": "龙门币-6/5", "days": [2, 4, 6, 7]},
- {"value": "AP-5", "text": "红票-5", "days": [1, 4, 6, 7]},
- {"value": "CA-5", "text": "技能-5", "days": [2, 3, 5, 7]},
- {"value": "LS-6", "text": "经验-6/5", "days": [1, 2, 3, 4, 5, 6, 7]},
- {"value": "SK-5", "text": "碳-5", "days": [1, 3, 5, 6]},
- {"value": "PR-A-1", "text": "奶/盾芯片", "days": [1, 4, 5, 7]},
- {"value": "PR-A-2", "text": "奶/盾芯片组", "days": [1, 4, 5, 7]},
- {"value": "PR-B-1", "text": "术/狙芯片", "days": [1, 2, 5, 6]},
- {"value": "PR-B-2", "text": "术/狙芯片组", "days": [1, 2, 5, 6]},
- {"value": "PR-C-1", "text": "先/辅芯片", "days": [3, 4, 6, 7]},
- {"value": "PR-C-2", "text": "先/辅芯片组", "days": [3, 4, 6, 7]},
- {"value": "PR-D-1", "text": "近/特芯片", "days": [2, 3, 6, 7]},
- {"value": "PR-D-2", "text": "近/特芯片组", "days": [2, 3, 6, 7]},
- ]
-
- for day in range(0, 8):
-
- today_stage_dict = {"value": [], "text": []}
-
- for stage_info in stage_daily_info:
-
- if day in stage_info["days"] or day == 0:
- today_stage_dict["value"].append(stage_info["value"])
- today_stage_dict["text"].append(stage_info["text"])
-
- self.stage_dict[calendar.day_name[day - 1] if day > 0 else "ALL"] = {
- "value": today_stage_dict["value"] + ss_stage_dict["value"],
- "text": today_stage_dict["text"] + ss_stage_dict["text"],
- }
-
- self.stage_refreshed.emit()
-
- def server_date(self) -> date:
- """获取当前的服务器日期"""
-
- dt = datetime.now()
- if dt.time() < datetime.min.time().replace(hour=4):
- dt = dt - timedelta(days=1)
- return dt.date()
+ logger.info("日志记录器初始化完成", module="配置管理")
def check_data(self) -> None:
"""检查用户数据文件并处理数据文件版本更新"""
@@ -914,11 +840,11 @@ class AppConfig(GlobalConfig):
version = cur.fetchall()
if version[0][0] != "v1.7":
- logger.info("数据文件版本更新开始")
+ logger.info("数据文件版本更新开始", module="配置管理")
if_streaming = False
# v1.4-->v1.5
if version[0][0] == "v1.4" or if_streaming:
- logger.info("数据文件版本更新:v1.4-->v1.5")
+ logger.info("数据文件版本更新:v1.4-->v1.5", module="配置管理")
if_streaming = True
member_dict: Dict[str, Dict[str, Union[str, Path]]] = {}
@@ -1046,7 +972,7 @@ class AppConfig(GlobalConfig):
# v1.5-->v1.6
if version[0][0] == "v1.5" or if_streaming:
- logger.info("数据文件版本更新:v1.5-->v1.6")
+ logger.info("数据文件版本更新:v1.5-->v1.6", module="配置管理")
if_streaming = True
cur.execute("DELETE FROM version WHERE v = ?", ("v1.5",))
cur.execute("INSERT INTO version VALUES(?)", ("v1.6",))
@@ -1078,7 +1004,7 @@ class AppConfig(GlobalConfig):
pass
# v1.6-->v1.7
if version[0][0] == "v1.6" or if_streaming:
- logger.info("数据文件版本更新:v1.6-->v1.7")
+ logger.info("数据文件版本更新:v1.6-->v1.7", module="配置管理")
if_streaming = True
if (self.app_path / "config/MaaConfig").exists():
@@ -1148,11 +1074,106 @@ class AppConfig(GlobalConfig):
cur.close()
db.close()
- logger.info("数据文件版本更新完成")
+ logger.success("数据文件版本更新完成", module="配置管理")
+
+ def get_stage(self) -> None:
+ """从MAA服务器更新活动关卡信息"""
+
+ logger.info("开始获取活动关卡信息", module="配置管理")
+ network = Network.add_task(
+ mode="get",
+ url="https://api.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json",
+ )
+ network.loop.exec()
+ network_result = Network.get_result(network)
+ if network_result["status_code"] == 200:
+ stage_infos: List[Dict[str, Union[str, Dict[str, Union[str, int]]]]] = (
+ network_result["response_json"]["Official"]["sideStoryStage"]
+ )
+ else:
+ logger.warning(
+ f"无法从MAA服务器获取活动关卡信息:{network_result['error_message']}",
+ module="配置管理",
+ )
+ stage_infos = []
+
+ ss_stage_dict = {"value": [], "text": []}
+
+ for stage_info in stage_infos:
+
+ if (
+ datetime.strptime(
+ stage_info["Activity"]["UtcStartTime"], "%Y/%m/%d %H:%M:%S"
+ )
+ < datetime.now()
+ < datetime.strptime(
+ stage_info["Activity"]["UtcExpireTime"], "%Y/%m/%d %H:%M:%S"
+ )
+ ):
+ ss_stage_dict["value"].append(stage_info["Value"])
+ ss_stage_dict["text"].append(stage_info["Value"])
+
+ # 生成每日关卡信息
+ stage_daily_info = [
+ {"value": "-", "text": "当前/上次", "days": [1, 2, 3, 4, 5, 6, 7]},
+ {"value": "1-7", "text": "1-7", "days": [1, 2, 3, 4, 5, 6, 7]},
+ {"value": "R8-11", "text": "R8-11", "days": [1, 2, 3, 4, 5, 6, 7]},
+ {
+ "value": "12-17-HARD",
+ "text": "12-17-HARD",
+ "days": [1, 2, 3, 4, 5, 6, 7],
+ },
+ {"value": "CE-6", "text": "龙门币-6/5", "days": [2, 4, 6, 7]},
+ {"value": "AP-5", "text": "红票-5", "days": [1, 4, 6, 7]},
+ {"value": "CA-5", "text": "技能-5", "days": [2, 3, 5, 7]},
+ {"value": "LS-6", "text": "经验-6/5", "days": [1, 2, 3, 4, 5, 6, 7]},
+ {"value": "SK-5", "text": "碳-5", "days": [1, 3, 5, 6]},
+ {"value": "PR-A-1", "text": "奶/盾芯片", "days": [1, 4, 5, 7]},
+ {"value": "PR-A-2", "text": "奶/盾芯片组", "days": [1, 4, 5, 7]},
+ {"value": "PR-B-1", "text": "术/狙芯片", "days": [1, 2, 5, 6]},
+ {"value": "PR-B-2", "text": "术/狙芯片组", "days": [1, 2, 5, 6]},
+ {"value": "PR-C-1", "text": "先/辅芯片", "days": [3, 4, 6, 7]},
+ {"value": "PR-C-2", "text": "先/辅芯片组", "days": [3, 4, 6, 7]},
+ {"value": "PR-D-1", "text": "近/特芯片", "days": [2, 3, 6, 7]},
+ {"value": "PR-D-2", "text": "近/特芯片组", "days": [2, 3, 6, 7]},
+ ]
+
+ for day in range(0, 8):
+
+ today_stage_dict = {"value": [], "text": []}
+
+ for stage_info in stage_daily_info:
+
+ if day in stage_info["days"] or day == 0:
+ today_stage_dict["value"].append(stage_info["value"])
+ today_stage_dict["text"].append(stage_info["text"])
+
+ self.stage_dict[calendar.day_name[day - 1] if day > 0 else "ALL"] = {
+ "value": today_stage_dict["value"] + ss_stage_dict["value"],
+ "text": today_stage_dict["text"] + ss_stage_dict["text"],
+ }
+
+ self.stage_refreshed.emit()
+
+ logger.success("活动关卡信息更新完成", module="配置管理")
+
+ def server_date(self) -> date:
+ """
+ 获取当前的服务器日期
+
+ :return: 当前的服务器日期
+ :rtype: date
+ """
+
+ dt = datetime.now()
+ if dt.time() < datetime.min.time().replace(hour=4):
+ dt = dt - timedelta(days=1)
+ return dt.date()
def search_member(self) -> None:
- """搜索所有脚本实例"""
+ """更新脚本实例配置信息"""
+ logger.info("开始搜索并读入脚本实例配置", module="配置管理")
self.member_dict: Dict[
str,
Dict[
@@ -1198,7 +1219,20 @@ class AppConfig(GlobalConfig):
sorted(self.member_dict.items(), key=lambda x: int(x[0][3:]))
)
+ logger.success(
+ f"脚本实例配置搜索完成,共找到 {len(self.member_dict)} 个实例",
+ module="配置管理",
+ )
+
def search_maa_user(self, name: str) -> None:
+ """
+ 更新指定 MAA 脚本实例的用户信息
+
+ :param name: 脚本实例名称
+ :type name: str
+ """
+
+ logger.info(f"开始搜索并读入 MAA 脚本实例 {name} 的用户信息", module="配置管理")
user_dict: Dict[str, Dict[str, Union[Path, MaaUserConfig]]] = {}
for user_dir in (Config.member_dict[name]["Path"] / "UserData").iterdir():
@@ -1214,7 +1248,22 @@ class AppConfig(GlobalConfig):
sorted(user_dict.items(), key=lambda x: int(x[0][3:]))
)
+ logger.success(
+ f"MAA 脚本实例 {name} 的用户信息搜索完成,共找到 {len(user_dict)} 个用户",
+ module="配置管理",
+ )
+
def search_general_sub(self, name: str) -> None:
+ """
+ 更新指定通用脚本实例的子配置信息
+
+ :param name: 脚本实例名称
+ :type name: str
+ """
+
+ logger.info(
+ f"开始搜索并读入通用脚本实例 {name} 的子配置信息", module="配置管理"
+ )
user_dict: Dict[str, Dict[str, Union[Path, GeneralSubConfig]]] = {}
for sub_dir in (Config.member_dict[name]["Path"] / "SubData").iterdir():
@@ -1230,8 +1279,15 @@ class AppConfig(GlobalConfig):
sorted(user_dict.items(), key=lambda x: int(x[0][3:]))
)
+ logger.success(
+ f"通用脚本实例 {name} 的子配置信息搜索完成,共找到 {len(user_dict)} 个子配置",
+ module="配置管理",
+ )
+
def search_plan(self) -> None:
- """搜索所有计划表"""
+ """更新计划表配置信息"""
+
+ logger.info("开始搜索并读入计划表配置", module="配置管理")
self.plan_dict: Dict[str, Dict[str, Union[str, Path, MaaPlanConfig]]] = {}
if (self.app_path / "config/MaaPlanConfig").exists():
@@ -1252,8 +1308,15 @@ class AppConfig(GlobalConfig):
sorted(self.plan_dict.items(), key=lambda x: int(x[0][3:]))
)
+ logger.success(
+ f"计划表配置搜索完成,共找到 {len(self.plan_dict)} 个计划表",
+ module="配置管理",
+ )
+
def search_queue(self):
- """搜索所有调度队列实例"""
+ """更新调度队列实例配置信息"""
+
+ logger.info("开始搜索并读入调度队列配置", module="配置管理")
self.queue_dict: Dict[str, Dict[str, Union[Path, QueueConfig]]] = {}
@@ -1273,8 +1336,20 @@ class AppConfig(GlobalConfig):
sorted(self.queue_dict.items(), key=lambda x: int(x[0][5:]))
)
+ logger.success(
+ f"调度队列配置搜索完成,共找到 {len(self.queue_dict)} 个调度队列",
+ module="配置管理",
+ )
+
def change_queue(self, old: str, new: str) -> None:
- """修改调度队列配置文件的队列参数"""
+ """
+ 修改调度队列配置文件的队列参数
+
+ :param old: 旧脚本名
+ :param new: 新脚本名
+ """
+
+ logger.info(f"开始修改调度队列参数:{old} -> {new}", module="配置管理")
for queue in self.queue_dict.values():
@@ -1299,8 +1374,17 @@ class AppConfig(GlobalConfig):
if queue["Config"].get(queue["Config"].queue_Member_10) == old:
queue["Config"].set(queue["Config"].queue_Member_10, new)
+ logger.success(f"调度队列参数修改完成:{old} -> {new}", module="配置管理")
+
def change_plan(self, old: str, new: str) -> None:
- """修改脚本管理所有下属用户的计划表配置参数"""
+ """
+ 修改脚本管理所有下属用户的计划表配置参数
+
+ :param old: 旧计划表名
+ :param new: 新计划表名
+ """
+
+ logger.info(f"开始修改计划表参数:{old} -> {new}", module="配置管理")
for member in self.member_dict.values():
@@ -1309,10 +1393,21 @@ class AppConfig(GlobalConfig):
if user["Config"].get(user["Config"].Info_StageMode) == old:
user["Config"].set(user["Config"].Info_StageMode, new)
+ logger.success(f"计划表参数修改完成:{old} -> {new}", module="配置管理")
+
def change_maa_user_info(
self, name: str, user_data: Dict[str, Dict[str, Union[str, Path, dict]]]
) -> None:
- """代理完成后保存改动的用户信息"""
+ """
+ 保存代理完成后发生改动的用户信息
+
+ :param name: 脚本实例名称
+ :type name: str
+ :param user_data: 用户信息字典,包含用户名称和对应的配置信息
+ :type user_data: Dict[str, Dict[str, Union[str, Path, dict]]]
+ """
+
+ logger.info(f"开始保存 MAA 脚本实例 {name} 的用户信息变动", module="配置管理")
for user, info in user_data.items():
@@ -1345,10 +1440,21 @@ class AppConfig(GlobalConfig):
self.sub_info_changed.emit()
+ logger.success(f"MAA 脚本实例 {name} 的用户信息变动保存完成", module="配置管理")
+
def change_general_sub_info(
self, name: str, sub_data: Dict[str, Dict[str, Union[str, Path, dict]]]
) -> None:
- """代理完成后保存改动的配置信息"""
+ """
+ 保存代理完成后发生改动的配置信息
+
+ :param name: 脚本实例名称
+ :type name: str
+ :param sub_data: 子配置信息字典,包含子配置名称和对应的配置信息
+ :type sub_data: Dict[str, Dict[str, Union[str, Path, dict]]]
+ """
+
+ logger.info(f"开始保存通用脚本实例 {name} 的子配置信息变动", module="配置管理")
for sub, info in sub_data.items():
@@ -1366,27 +1472,62 @@ class AppConfig(GlobalConfig):
self.sub_info_changed.emit()
+ logger.success(
+ f"通用脚本实例 {name} 的子配置信息变动保存完成", module="配置管理"
+ )
+
def set_power_sign(self, sign: str) -> None:
- """设置当前电源状态"""
+ """
+ 设置当前电源状态
+
+ :param sign: 电源状态标志
+ """
self.power_sign = sign
self.power_sign_changed.emit()
+ logger.info(f"电源状态已更改为: {sign}", module="配置管理")
+
def save_history(self, key: str, content: dict) -> None:
- """保存历史记录"""
+ """
+ 保存历史记录
+
+ :param key: 调度队列的键
+ :type key: str
+ :param content: 包含时间和历史记录内容的字典
+ :type content: dict
+ """
if key in self.queue_dict:
+ logger.info(f"保存调度队列 {key} 的历史记录", module="配置管理")
self.queue_dict[key]["Config"].set(
self.queue_dict[key]["Config"].Data_LastProxyTime, content["Time"]
)
self.queue_dict[key]["Config"].set(
self.queue_dict[key]["Config"].Data_LastProxyHistory, content["History"]
)
+ logger.success(f"调度队列 {key} 的历史记录已保存", module="配置管理")
else:
logger.warning(f"保存历史记录时未找到调度队列: {key}")
def save_maa_log(self, log_path: Path, logs: list, maa_result: str) -> bool:
- """保存MAA日志并生成对应统计数据"""
+ """
+ 保存MAA日志并生成对应统计数据
+
+ :param log_path: 日志文件保存路径
+ :type log_path: Path
+ :param logs: 日志内容列表
+ :type logs: list
+ :param maa_result: MAA 结果
+ :type maa_result: str
+ :return: 是否包含6★招募
+ :rtype: bool
+ """
+
+ logger.info(
+ f"开始处理 MAA 日志,日志长度: {len(logs)},日志标记:{maa_result}",
+ module="配置管理",
+ )
data: Dict[str, Union[str, Dict[str, Union[int, dict]]]] = {
"recruit_statistics": defaultdict(int),
@@ -1431,15 +1572,17 @@ class AppConfig(GlobalConfig):
# 查找所有Fight任务的开始和结束位置
fight_tasks = []
for i, line in enumerate(logs):
- if "开始任务: Fight" in line:
+ if "开始任务: Fight" in line or "开始任务: 刷理智" in line:
# 查找对应的任务结束位置
end_index = -1
for j in range(i + 1, len(logs)):
- if "完成任务: Fight" in logs[j]:
+ if "完成任务: Fight" in logs[j] or "完成任务: 刷理智" in logs[j]:
end_index = j
break
# 如果遇到新的Fight任务开始,则当前任务没有正常结束
- if j < len(logs) and "开始任务: Fight" in logs[j]:
+ if j < len(logs) and (
+ "开始任务: Fight" in logs[j] or "开始任务: 刷理智" in logs[j]
+ ):
break
# 如果找到了结束位置,记录这个任务的范围
@@ -1505,12 +1648,23 @@ class AppConfig(GlobalConfig):
with log_path.with_suffix(".json").open("w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
- logger.info(f"处理完成:{log_path}")
+ logger.success(f"MAA 日志统计完成,日志路径:{log_path}", module="配置管理")
return if_six_star
def save_general_log(self, log_path: Path, logs: list, general_result: str) -> None:
- """保存通用日志并生成对应统计数据"""
+ """
+ 保存通用日志并生成对应统计数据
+
+ :param log_path: 日志文件保存路径
+ :param logs: 日志内容列表
+ :param general_result: 待保存的日志结果信息
+ """
+
+ logger.info(
+ f"开始处理通用日志,日志长度: {len(logs)},日志标记:{general_result}",
+ module="配置管理",
+ )
data: Dict[str, str] = {"general_result": general_result}
@@ -1521,10 +1675,23 @@ class AppConfig(GlobalConfig):
with log_path.with_suffix(".json").open("w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
- logger.info(f"处理完成:{log_path}")
+ logger.success(
+ f"通用日志统计完成,日志路径:{log_path.with_suffix('.log')}",
+ module="配置管理",
+ )
def merge_statistic_info(self, statistic_path_list: List[Path]) -> dict:
- """合并指定数据统计信息文件"""
+ """
+ 合并指定数据统计信息文件
+
+ :param statistic_path_list: 需要合并的统计信息文件路径列表
+ :return: 合并后的统计信息字典
+ """
+
+ logger.info(
+ f"开始合并统计信息文件,共计 {len(statistic_path_list)} 个文件",
+ module="配置管理",
+ )
data = {"index": {}}
@@ -1591,12 +1758,28 @@ class AppConfig(GlobalConfig):
data["index"] = [data["index"][_] for _ in sorted(data["index"])]
+ logger.success(
+ f"统计信息合并完成,共计 {len(data['index'])} 条记录", module="配置管理"
+ )
+
return {k: v for k, v in data.items() if v}
def search_history(
self, mode: str, start_date: datetime, end_date: datetime
) -> dict:
- """搜索所有历史记录"""
+ """
+ 搜索指定范围内的历史记录
+
+ :param mode: 合并模式(按日合并、按周合并、按月合并)
+ :param start_date: 开始日期
+ :param end_date: 结束日期
+ :return: 搜索到的历史记录字典
+ """
+
+ logger.info(
+ f"开始搜索历史记录,合并模式:{mode},日期范围:{start_date} 至 {end_date}",
+ module="配置管理",
+ )
history_dict = {}
@@ -1638,10 +1821,43 @@ class AppConfig(GlobalConfig):
except ValueError:
logger.warning(f"非日期格式的目录: {date_folder}")
+ logger.success(
+ f"历史记录搜索完成,共计 {len(history_dict)} 条记录", module="配置管理"
+ )
+
return {
k: v
for k, v in sorted(history_dict.items(), key=lambda x: x[0], reverse=True)
}
+ def clean_old_history(self):
+ """删除超过用户设定天数的历史记录文件(基于目录日期)"""
+
+ if self.get(self.function_HistoryRetentionTime) == 0:
+ logger.info("历史记录永久保留,跳过历史记录清理", module="配置管理")
+ return
+
+ logger.info("开始清理超过设定天数的历史记录", module="配置管理")
+
+ deleted_count = 0
+
+ for date_folder in (self.app_path / "history").iterdir():
+ if not date_folder.is_dir():
+ continue # 只处理日期文件夹
+
+ try:
+ # 只检查 `YYYY-MM-DD` 格式的文件夹
+ folder_date = datetime.strptime(date_folder.name, "%Y-%m-%d")
+ if datetime.now() - folder_date > timedelta(
+ days=self.get(self.function_HistoryRetentionTime)
+ ):
+ shutil.rmtree(date_folder, ignore_errors=True)
+ deleted_count += 1
+ logger.info(f"已删除超期日志目录: {date_folder}", module="配置管理")
+ except ValueError:
+ logger.warning(f"非日期格式的目录: {date_folder}", module="配置管理")
+
+ logger.success(f"清理完成: {deleted_count} 个日期目录", module="配置管理")
+
Config = AppConfig()
diff --git a/app/core/logger.py b/app/core/logger.py
new file mode 100644
index 0000000..aa942dd
--- /dev/null
+++ b/app/core/logger.py
@@ -0,0 +1,34 @@
+# AUTO_MAA:A MAA Multi Account Management and Automation Tool
+# Copyright © 2024-2025 DLmaster361
+
+# This file is part of AUTO_MAA.
+
+# AUTO_MAA is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License,
+# or (at your option) any later version.
+
+# AUTO_MAA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+# the GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with AUTO_MAA. If not, see .
+
+# Contact: DLmaster_361@163.com
+
+"""
+AUTO_MAA
+AUTO_MAA日志组件
+v4.4
+作者:DLmaster_361
+"""
+
+from loguru import logger as _logger
+
+# 设置日志 module 字段默认值
+logger = _logger.patch(
+ lambda record: record["extra"].setdefault("module", "未知模块") or True
+)
+logger.remove(0)
diff --git a/app/core/main_info_bar.py b/app/core/main_info_bar.py
index 715ff25..745050a 100644
--- a/app/core/main_info_bar.py
+++ b/app/core/main_info_bar.py
@@ -25,10 +25,10 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtCore import Qt
from qfluentwidgets import InfoBar, InfoBarPosition
+from .logger import logger
from .config import Config
from .sound_player import SoundPlayer
@@ -46,20 +46,34 @@ class _MainInfoBar:
def push_info_bar(
self, mode: str, title: str, content: str, time: int, if_force: bool = False
- ):
- """推送到信息通知栏"""
+ ) -> None:
+ """
+ 推送消息到吐司通知栏
+
+ :param mode: 通知栏模式,支持 "success", "warning", "error", "info"
+ :param title: 通知栏标题
+ :type title: str
+ :param content: 通知栏内容
+ :type content: str
+ :param time: 显示时长,单位为毫秒
+ :type time: int
+ :param if_force: 是否强制推送
+ :type if_force: bool
+ """
+
if Config.main_window is None:
- logger.error("信息通知栏未设置父窗口")
+ logger.error("信息通知栏未设置父窗口", module="吐司通知栏")
return None
# 根据 mode 获取对应的 InfoBar 方法
info_bar_method = self.mode_mapping.get(mode)
if not info_bar_method:
- logger.error(f"未知的通知栏模式: {mode}")
+ logger.error(f"未知的通知栏模式: {mode}", module="吐司通知栏")
return None
if Config.main_window.isVisible():
+ # 主窗口可见时直接推送通知
info_bar_method(
title=title,
content=content,
@@ -69,6 +83,7 @@ class _MainInfoBar:
duration=time,
parent=Config.main_window,
)
+
elif if_force:
# 如果主窗口不可见且强制推送,则录入消息队列等待窗口显示后推送
info_bar_item = {
@@ -80,6 +95,11 @@ class _MainInfoBar:
if info_bar_item not in Config.info_bar_list:
Config.info_bar_list.append(info_bar_item)
+ logger.info(
+ f"主窗口不可见,已将通知栏消息录入队列: {info_bar_item}",
+ module="吐司通知栏",
+ )
+
if mode == "warning":
SoundPlayer.play("发生异常")
if mode == "error":
diff --git a/app/core/network.py b/app/core/network.py
index 003145a..15211ee 100644
--- a/app/core/network.py
+++ b/app/core/network.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtCore import QObject, QThread, QEventLoop
import re
import time
@@ -33,6 +32,8 @@ import requests
import truststore
from pathlib import Path
+from .logger import logger
+
class NetworkThread(QThread):
"""网络请求线程类"""
@@ -48,6 +49,8 @@ class NetworkThread(QThread):
f"NetworkThread-{mode}-{re.sub(r'(&cdk=)[^&]+(&)', r'\1******\2', url)}"
)
+ logger.info(f"创建网络请求线程: {self.objectName()}", module="网络请求子线程")
+
self.mode = mode
self.url = url
self.path = path
@@ -65,7 +68,7 @@ class NetworkThread(QThread):
self.loop = QEventLoop()
- truststore.inject_into_ssl()
+ truststore.inject_into_ssl() # 信任系统证书
@logger.catch
def run(self) -> None:
@@ -77,7 +80,13 @@ class NetworkThread(QThread):
self.get_file(self.url, self.path)
def get_json(self, url: str) -> None:
- """通过get方法获取json数据"""
+ """
+ 通过get方法获取json数据
+
+ :param url: 请求的URL
+ """
+
+ logger.info(f"子线程 {self.objectName()} 开始网络请求", module="网络请求子线程")
response = None
@@ -92,12 +101,23 @@ class NetworkThread(QThread):
self.status_code = response.status_code if response else None
self.response_json = None
self.error_message = str(e)
+ logger.exception(
+ f"子线程 {self.objectName()} 网络请求失败:{e}",
+ module="网络请求子线程",
+ )
time.sleep(self.backoff_factor)
self.loop.quit()
def get_file(self, url: str, path: Path) -> None:
- """通过get方法下载文件"""
+ """
+ 通过get方法下载文件到指定路径
+
+ :param url: 请求的URL
+ :param path: 下载文件的保存路径
+ """
+
+ logger.info(f"子线程 {self.objectName()} 开始下载文件", module="网络请求子线程")
response = None
@@ -114,12 +134,15 @@ class NetworkThread(QThread):
except Exception as e:
self.status_code = response.status_code if response else None
self.error_message = str(e)
+ logger.exception(
+ f"子线程 {self.objectName()} 网络请求失败:{e}", module="网络请求子线程"
+ )
self.loop.quit()
class _Network(QObject):
- """网络请求线程类"""
+ """网络请求线程管理类"""
def __init__(self) -> None:
super().__init__()
@@ -127,7 +150,16 @@ class _Network(QObject):
self.task_queue = []
def add_task(self, mode: str, url: str, path: Path = None) -> NetworkThread:
- """添加网络请求任务"""
+ """
+ 添加网络请求任务
+
+ :param mode: 请求模式,支持 "get", "get_file"
+ :param url: 请求的URL
+ :param path: 下载文件的保存路径,仅在 mode 为 "get_file" 时有效
+ :return: 返回创建的 NetworkThread 实例
+ """
+
+ logger.info(f"添加网络请求任务: {mode} {url} {path}", module="网络请求")
network_thread = NetworkThread(mode, url, path)
@@ -138,7 +170,12 @@ class _Network(QObject):
return network_thread
def get_result(self, network_thread: NetworkThread) -> dict:
- """获取网络请求结果"""
+ """
+ 获取网络请求结果
+
+ :param network_thread: 网络请求线程实例
+ :return: 包含状态码、响应JSON和错误信息的字典
+ """
result = {
"status_code": network_thread.status_code,
@@ -155,6 +192,11 @@ class _Network(QObject):
self.task_queue.remove(network_thread)
network_thread.deleteLater()
+ logger.info(
+ f"网络请求结果: {result['status_code']},请求子线程已结束",
+ module="网络请求",
+ )
+
return result
diff --git a/app/core/sound_player.py b/app/core/sound_player.py
index 422ae0a..e8f5268 100644
--- a/app/core/sound_player.py
+++ b/app/core/sound_player.py
@@ -25,12 +25,12 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtCore import QObject, QUrl
from PySide6.QtMultimedia import QSoundEffect
from pathlib import Path
+from .logger import logger
from .config import Config
@@ -42,6 +42,11 @@ class _SoundPlayer(QObject):
self.sounds_path = Config.app_path / "resources/sounds"
def play(self, sound_name: str):
+ """
+ 播放指定名称的音效
+
+ :param sound_name: 音效文件名(不带扩展名)
+ """
if not Config.get(Config.voice_Enabled):
return
@@ -59,6 +64,11 @@ class _SoundPlayer(QObject):
)
def play_voice(self, sound_path: Path):
+ """
+ 播放音效文件
+
+ :param sound_path: 音效文件的完整路径
+ """
effect = QSoundEffect(self)
effect.setVolume(1)
diff --git a/app/core/task_manager.py b/app/core/task_manager.py
index 67365b4..566b3ad 100644
--- a/app/core/task_manager.py
+++ b/app/core/task_manager.py
@@ -25,19 +25,18 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtCore import QThread, QObject, Signal
from qfluentwidgets import MessageBox
from datetime import datetime
from packaging import version
from typing import Dict, Union
+from .logger import logger
from .config import Config
from .main_info_bar import MainInfoBar
from .network import Network
from .sound_player import SoundPlayer
from app.models import MaaManager, GeneralManager
-from app.services import System
class Task(QThread):
@@ -77,7 +76,7 @@ class Task(QThread):
if "设置MAA" in self.mode:
- logger.info(f"任务开始:设置{self.name}")
+ logger.info(f"任务开始:设置{self.name}", module=f"业务 {self.name}")
self.push_info_bar.emit("info", "设置MAA", self.name, 3000)
self.task = MaaManager(
@@ -93,12 +92,14 @@ class Task(QThread):
try:
self.task.run()
except Exception as e:
- logger.exception(f"任务异常:{self.name},错误信息:{e}")
+ logger.exception(
+ f"任务异常:{self.name},错误信息:{e}", module=f"业务 {self.name}"
+ )
self.push_info_bar.emit("error", "任务异常", self.name, -1)
elif self.mode == "设置通用脚本":
- logger.info(f"任务开始:设置{self.name}")
+ logger.info(f"任务开始:设置{self.name}", module=f"业务 {self.name}")
self.push_info_bar.emit("info", "设置通用脚本", self.name, 3000)
self.task = GeneralManager(
@@ -113,11 +114,14 @@ class Task(QThread):
try:
self.task.run()
except Exception as e:
- logger.exception(f"任务异常:{self.name},错误信息:{e}")
+ logger.exception(
+ f"任务异常:{self.name},错误信息:{e}", module=f"业务 {self.name}"
+ )
self.push_info_bar.emit("error", "任务异常", self.name, -1)
else:
+ logger.info(f"任务开始:{self.name}", module=f"业务 {self.name}")
self.task_list = [
[
(
@@ -144,16 +148,21 @@ class Task(QThread):
task[1] = "运行"
self.update_task_list.emit(self.task_list)
+ # 检查任务是否在运行列表中
if task[2] in Config.running_list:
task[1] = "跳过"
self.update_task_list.emit(self.task_list)
- logger.info(f"跳过任务:{task[0]}")
+ logger.info(
+ f"跳过任务:{task[0]},该任务已在运行列表中",
+ module=f"业务 {self.name}",
+ )
self.push_info_bar.emit("info", "跳过任务", task[0], 3000)
continue
+ # 标记为运行中
Config.running_list.append(task[2])
- logger.info(f"任务开始:{task[0]}")
+ logger.info(f"任务开始:{task[0]}", module=f"业务 {self.name}")
self.push_info_bar.emit("info", "任务开始", task[0], 3000)
if Config.member_dict[task[2]]["Type"] == "Maa":
@@ -198,11 +207,11 @@ class Task(QThread):
)
try:
- self.task.run()
+ self.task.run() # 运行任务业务
task[1] = "完成"
self.update_task_list.emit(self.task_list)
- logger.info(f"任务完成:{task[0]}")
+ logger.info(f"任务完成:{task[0]}", module=f"业务 {self.name}")
self.push_info_bar.emit("info", "任务完成", task[0], 3000)
except Exception as e:
@@ -217,15 +226,29 @@ class Task(QThread):
task[1] = "异常"
self.update_task_list.emit(self.task_list)
- logger.exception(f"任务异常:{task[0]},错误信息:{e}")
+ logger.exception(
+ f"任务异常:{task[0]},错误信息:{e}",
+ module=f"业务 {self.name}",
+ )
self.push_info_bar.emit("error", "任务异常", task[0], -1)
+ # 任务结束后从运行列表中移除
Config.running_list.remove(task[2])
self.accomplish.emit(self.logs)
def task_accomplish(self, name: str, log: dict):
- """保存任务结果"""
+ """
+ 销毁任务线程并保存任务结果
+
+ :param name: 任务名称
+ :param log: 任务日志记录
+ """
+
+ logger.info(
+ f"任务完成:{name},日志记录:{list(log.values())}",
+ module=f"业务 {self.name}",
+ )
self.logs.append([name, log])
self.task.deleteLater()
@@ -245,7 +268,13 @@ class _TaskManager(QObject):
def add_task(
self, mode: str, name: str, info: Dict[str, Dict[str, Union[str, int, bool]]]
):
- """添加任务"""
+ """
+ 添加任务
+
+ :param mode: 任务模式
+ :param name: 任务名称
+ :param info: 任务信息
+ """
if name in Config.running_list or name in self.task_dict:
@@ -253,11 +282,14 @@ class _TaskManager(QObject):
MainInfoBar.push_info_bar("warning", "任务已存在", name, 5000)
return None
- logger.info(f"任务开始:{name}")
+ logger.info(f"任务开始:{name},模式:{mode}", module="业务调度")
MainInfoBar.push_info_bar("info", "任务开始", name, 3000)
SoundPlayer.play("任务开始")
+ # 标记任务为运行中
Config.running_list.append(name)
+
+ # 创建任务实例并连接信号
self.task_dict[name] = Task(mode, name, info)
self.task_dict[name].check_maa_version.connect(self.check_maa_version)
self.task_dict[name].question.connect(
@@ -273,18 +305,24 @@ class _TaskManager(QObject):
lambda logs: self.remove_task(mode, name, logs)
)
+ # 向UI发送信号以创建或连接GUI
if "新调度台" in mode:
self.create_gui.emit(self.task_dict[name])
elif "主调度台" in mode:
self.connect_gui.emit(self.task_dict[name])
+ # 启动任务线程
self.task_dict[name].start()
- def stop_task(self, name: str):
- """中止任务"""
+ def stop_task(self, name: str) -> None:
+ """
+ 中止任务
- logger.info(f"中止任务:{name}")
+ :param name: 任务名称
+ """
+
+ logger.info(f"中止任务:{name}", module="业务调度")
MainInfoBar.push_info_bar("info", "中止任务", name, 3000)
if name == "ALL":
@@ -303,19 +341,27 @@ class _TaskManager(QObject):
self.task_dict[name].quit()
self.task_dict[name].wait()
- def remove_task(self, mode: str, name: str, logs: list):
- """任务结束后的处理"""
+ def remove_task(self, mode: str, name: str, logs: list) -> None:
+ """
+ 处理任务结束后的收尾工作
- logger.info(f"任务结束:{name}")
+ :param mode: 任务模式
+ :param name: 任务名称
+ :param logs: 任务日志
+ """
+
+ logger.info(f"任务结束:{name}", module="业务调度")
MainInfoBar.push_info_bar("info", "任务结束", name, 3000)
SoundPlayer.play("任务结束")
+ # 删除任务线程,移除运行中标记
self.task_dict[name].deleteLater()
self.task_dict.pop(name)
Config.running_list.remove(name)
if "调度队列" in name and "人工排查" not in mode:
+ # 保存调度队列历史记录
if len(logs) > 0:
time = logs[0][1]["Time"]
history = ""
@@ -331,6 +377,7 @@ class _TaskManager(QObject):
},
)
+ # 根据调度队列情况设置电源状态
if (
Config.queue_dict[name]["Config"].get(
Config.queue_dict[name]["Config"].queueSet_AfterAccomplish
@@ -347,9 +394,14 @@ class _TaskManager(QObject):
if Config.args.mode == "cli" and Config.power_sign == "NoAction":
Config.set_power_sign("KillSelf")
- def check_maa_version(self, v: str):
- """检查MAA版本"""
+ def check_maa_version(self, v: str) -> None:
+ """
+ 检查MAA版本,如果版本过低则推送通知
+ :param v: 当前MAA版本
+ """
+
+ logger.info(f"检查MAA版本:{v}", module="业务调度")
network = Network.add_task(
mode="get",
url="https://mirrorchyan.com/api/resources/MAA/latest?user_agent=AutoMaaGui&os=win&arch=x64&channel=stable",
@@ -359,7 +411,10 @@ class _TaskManager(QObject):
if network_result["status_code"] == 200:
maa_info = network_result["response_json"]
else:
- logger.warning(f"获取MAA版本信息时出错:{network_result['error_message']}")
+ logger.warning(
+ f"获取MAA版本信息时出错:{network_result['error_message']}",
+ module="业务调度",
+ )
MainInfoBar.push_info_bar(
"warning",
"获取MAA版本信息时出错",
@@ -371,7 +426,8 @@ class _TaskManager(QObject):
if version.parse(maa_info["data"]["version_name"]) > version.parse(v):
logger.info(
- f"检测到MAA版本过低:{v},最新版本:{maa_info['data']['version_name']}"
+ f"检测到MAA版本过低:{v},最新版本:{maa_info['data']['version_name']}",
+ module="业务调度",
)
MainInfoBar.push_info_bar(
"info",
@@ -380,8 +436,19 @@ class _TaskManager(QObject):
-1,
)
+ logger.success(
+ f"MAA版本检查完成:{v},最新版本:{maa_info['data']['version_name']}",
+ module="业务调度",
+ )
+
def push_dialog(self, name: str, title: str, content: str):
- """推送对话框"""
+ """
+ 推送来自任务线程的对话框
+
+ :param name: 任务名称
+ :param title: 对话框标题
+ :param content: 对话框内容
+ """
choice = MessageBox(title, content, Config.main_window)
choice.yesButton.setText("是")
diff --git a/app/core/timer.py b/app/core/timer.py
index 4566d4d..537ce09 100644
--- a/app/core/timer.py
+++ b/app/core/timer.py
@@ -25,12 +25,11 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtCore import QObject, QTimer
from datetime import datetime
-from pathlib import Path
import keyboard
+from .logger import logger
from .config import Config
from .task_manager import TaskManager
from app.services import System
@@ -45,14 +44,31 @@ class _MainTimer(QObject):
self.Timer.timeout.connect(self.timed_start)
self.Timer.timeout.connect(self.set_silence)
self.Timer.timeout.connect(self.check_power)
- self.Timer.start(1000)
+
self.LongTimer = QTimer()
self.LongTimer.timeout.connect(self.long_timed_task)
+
+ def start(self):
+ """启动定时器"""
+
+ logger.info("启动主定时器", module="主业务定时器")
+ self.Timer.start(1000)
self.LongTimer.start(3600000)
+ def stop(self):
+ """停止定时器"""
+
+ logger.info("停止主定时器", module="主业务定时器")
+ self.Timer.stop()
+ self.Timer.deleteLater()
+ self.LongTimer.stop()
+ self.LongTimer.deleteLater()
+
def long_timed_task(self):
"""长时间定期检定任务"""
+ logger.info("执行长时间定期检定任务", module="主业务定时器")
+
Config.get_stage()
Config.main_window.setting.show_notice()
if Config.get(Config.update_IfAutoUpdate):
@@ -82,7 +98,7 @@ class _MainTimer(QObject):
and name not in Config.running_list
):
- logger.info(f"定时任务:{name}")
+ logger.info(f"定时唤起任务:{name}。", module="主业务定时器")
TaskManager.add_task("自动代理_新调度台", name, data)
def set_silence(self):
@@ -109,13 +125,20 @@ class _MainTimer(QObject):
for _ in Config.get(Config.function_BossKey).split("+")
)
)
+ logger.info(
+ f"模拟按键:{Config.get(Config.function_BossKey)}",
+ module="主业务定时器",
+ )
except Exception as e:
- logger.error(f"模拟按键时出错:{e}")
+ logger.exception(f"模拟按键时出错:{e}", module="主业务定时器")
def check_power(self):
+ """检查电源操作"""
if Config.power_sign != "NoAction" and not Config.running_list:
+ logger.info(f"触发电源操作:{Config.power_sign}", module="主业务定时器")
+
from app.ui import ProgressRingMessageBox
mode_book = {
@@ -129,9 +152,13 @@ class _MainTimer(QObject):
Config.main_window, f"{mode_book[Config.power_sign]}倒计时"
)
if choice.exec():
+ logger.info(
+ f"确认执行电源操作:{Config.power_sign}", module="主业务定时器"
+ )
System.set_power(Config.power_sign)
Config.set_power_sign("NoAction")
else:
+ logger.info(f"取消电源操作:{Config.power_sign}", module="主业务定时器")
Config.set_power_sign("NoAction")
diff --git a/app/models/MAA.py b/app/models/MAA.py
index 974ba65..3f7c2ef 100644
--- a/app/models/MAA.py
+++ b/app/models/MAA.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtCore import QObject, Signal, QEventLoop, QFileSystemWatcher, QTimer
import json
import subprocess
@@ -38,7 +37,7 @@ from pathlib import Path
from jinja2 import Environment, FileSystemLoader
from typing import Union, List, Dict
-from app.core import Config, MaaConfig, MaaUserConfig
+from app.core import Config, MaaConfig, MaaUserConfig, logger
from app.services import Notify, Crypto, System, skland_sign_in
from app.utils import ProcessManager
@@ -77,19 +76,21 @@ class MaaManager(QObject):
self.user_list = ""
self.mode = mode
self.config_path = config["Path"]
+ self.name = config["Config"].get(config["Config"].MaaSet_Name)
self.user_config_path = user_config_path
self.emulator_process_manager = ProcessManager()
self.maa_process_manager = ProcessManager()
self.log_monitor = QFileSystemWatcher()
+ self.log_monitor.fileChanged.connect(self.check_maa_log)
self.log_monitor_timer = QTimer()
self.log_monitor_timer.timeout.connect(self.refresh_maa_log)
self.monitor_loop = QEventLoop()
+ self.log_start_time = datetime.now()
+ self.log_check_mode = None
- self.maa_process_manager.processClosed.connect(
- lambda: self.log_monitor.fileChanged.emit("进程结束检查")
- )
+ self.maa_process_manager.processClosed.connect(self.check_maa_log)
self.question_loop = QEventLoop()
self.question_response.connect(self.__capture_response)
@@ -118,10 +119,14 @@ class MaaManager(QObject):
self.data = dict(sorted(self.data.items(), key=lambda x: int(x[0][3:])))
+ logger.success(
+ f"MAA控制器初始化完成,当前模式: {self.mode}",
+ module=f"MAA调度器-{self.name}",
+ )
+
def configure(self):
"""提取配置信息"""
- self.name = self.set["MaaSet"]["Name"]
self.maa_root_path = Path(self.set["MaaSet"]["Path"])
self.maa_set_path = self.maa_root_path / "config/gui.json"
self.maa_log_path = self.maa_root_path / "debug/gui.log"
@@ -132,6 +137,8 @@ class MaaManager(QObject):
for i in range(0, 2 * self.set["RunSet"]["ADBSearchRange"])
]
+ logger.success("MAA配置提取完成", module=f"MAA调度器-{self.name}")
+
def run(self):
"""主进程,运行MAA代理进程"""
@@ -143,7 +150,9 @@ class MaaManager(QObject):
# 检查MAA路径是否可用
if not self.maa_exe_path.exists() or not self.maa_set_path.exists():
- logger.error("未正确配置MAA路径,MAA代理进程中止")
+ logger.error(
+ "未正确配置MAA路径,MAA代理进程中止", module=f"MAA调度器-{self.name}"
+ )
self.push_info_bar.emit(
"error", "启动MAA代理进程失败", "您还未正确配置MAA路径!", -1
)
@@ -174,6 +183,11 @@ class MaaManager(QObject):
]
self.create_user_list.emit(self.user_list)
+ logger.info(
+ f"用户列表创建完成,已筛选用户数:{len(self.user_list)}",
+ module=f"MAA调度器-{self.name}",
+ )
+
# 自动代理模式
if self.mode == "自动代理":
@@ -208,7 +222,7 @@ class MaaManager(QObject):
self.update_user_list.emit(self.user_list)
continue
- logger.info(f"{self.name} | 开始代理用户: {user[0]}")
+ logger.info(f"开始代理用户: {user[0]}", module=f"MAA调度器-{self.name}")
# 初始化代理情况记录和模式替换表
run_book = {"Annihilation": False, "Routine": False}
@@ -244,7 +258,8 @@ class MaaManager(QObject):
if type != "总计" and len(user_list) > 0:
logger.info(
- f"{self.name} | 用户: {user[0]} - 森空岛签到{type}: {'、'.join(user_list)}"
+ f"用户: {user[0]} - 森空岛签到{type}: {'、'.join(user_list)}",
+ module=f"MAA调度器-{self.name}",
)
self.push_info_bar.emit(
"info",
@@ -255,10 +270,7 @@ class MaaManager(QObject):
if skland_result["总计"] == 0:
self.push_info_bar.emit(
- "info",
- "森空岛签到失败",
- user[0],
- -1,
+ "info", "森空岛签到失败", user[0], -1
)
if (
@@ -274,7 +286,8 @@ class MaaManager(QObject):
elif user_data["Info"]["IfSkland"]:
logger.warning(
- f"{self.name} | 用户: {user[0]} - 未配置森空岛签到Token,跳过森空岛签到"
+ f"用户: {user[0]} - 未配置森空岛签到Token,跳过森空岛签到",
+ module=f"MAA调度器-{self.name}",
)
self.push_info_bar.emit(
"warning", "森空岛签到失败", "未配置鹰角网络通行证登录凭证", -1
@@ -296,7 +309,8 @@ class MaaManager(QObject):
== datetime.strptime(curdate, "%Y-%m-%d").isocalendar()[:2]
):
logger.info(
- f"{self.name} | 用户: {user_data["Info"]["Name"]} - 本周剿灭模式已达上限,跳过执行剿灭任务"
+ f"用户: {user_data['Info']['Name']} - 本周剿灭模式已达上限,跳过执行剿灭任务",
+ module=f"MAA调度器-{self.name}",
)
run_book[mode] = True
continue
@@ -313,7 +327,8 @@ class MaaManager(QObject):
self.data[user[2]]["Path"] / f"{mode}/gui.json"
).exists():
logger.error(
- f"{self.name} | 用户: {user[0]} - 未找到{mode_book[mode][5:7]}配置文件"
+ f"用户: {user[0]} - 未找到{mode_book[mode][5:7]}配置文件",
+ module=f"MAA调度器-{self.name}",
)
self.push_info_bar.emit(
"error",
@@ -399,6 +414,11 @@ class MaaManager(QObject):
],
}
+ logger.info(
+ f"用户: {user[0]} - 模式: {mode_book[mode]} - 任务列表: {list(self.task_dict.values())}",
+ module=f"MAA调度器-{self.name}",
+ )
+
# 尝试次数循环
for i in range(self.set["RunSet"]["RunTimesLimit"]):
@@ -409,13 +429,13 @@ class MaaManager(QObject):
break
logger.info(
- f"{self.name} | 用户: {user[0]} - 模式: {mode_book[mode]} - 尝试次数: {i + 1}/{self.set["RunSet"]["RunTimesLimit"]}"
+ f"用户: {user[0]} - 模式: {mode_book[mode]} - 尝试次数: {i + 1}/{self.set["RunSet"]["RunTimesLimit"]}"
)
# 配置MAA
set = self.set_maa(mode_book[mode], user[2])
# 记录当前时间
- start_time = datetime.now()
+ self.log_start_time = datetime.now()
# 记录模拟器与ADB路径
self.emulator_path = Path(
@@ -435,8 +455,9 @@ class MaaManager(QObject):
self.emulator_path = Path(shortcut.TargetPath)
self.emulator_arguments = shortcut.Arguments.split()
except Exception as e:
- logger.error(
- f"{self.name} | 解析快捷方式时出现异常:{e}"
+ logger.exception(
+ f"解析快捷方式时出现异常:{e}",
+ module=f"MAA调度器-{self.name}",
)
self.push_info_bar.emit(
"error",
@@ -448,7 +469,8 @@ class MaaManager(QObject):
break
elif not self.emulator_path.exists():
logger.error(
- f"{self.name} | 模拟器快捷方式不存在:{self.emulator_path}"
+ f"模拟器快捷方式不存在:{self.emulator_path}",
+ module=f"MAA调度器-{self.name}",
)
self.push_info_bar.emit(
"error",
@@ -489,16 +511,25 @@ class MaaManager(QObject):
# 任务开始前释放ADB
try:
- logger.info(f"{self.name} | 释放ADB:{self.ADB_address}")
+ logger.info(
+ f"释放ADB:{self.ADB_address}",
+ module=f"MAA调度器-{self.name}",
+ )
subprocess.run(
[self.ADB_path, "disconnect", self.ADB_address],
creationflags=subprocess.CREATE_NO_WINDOW,
)
except subprocess.CalledProcessError as e:
# 忽略错误,因为可能本来就没有连接
- logger.warning(f"{self.name} | 释放ADB时出现异常:{e}")
+ logger.warning(
+ f"释放ADB时出现异常:{e}",
+ module=f"MAA调度器-{self.name}",
+ )
except Exception as e:
- logger.error(f"{self.name} | 释放ADB时出现异常:{e}")
+ logger.exception(
+ f"释放ADB时出现异常:{e}",
+ module=f"MAA调度器-{self.name}",
+ )
self.push_info_bar.emit(
"error",
"释放ADB时出现异常",
@@ -509,13 +540,17 @@ class MaaManager(QObject):
if self.if_open_emulator_process:
try:
logger.info(
- f"{self.name} | 启动模拟器:{self.emulator_path},参数:{self.emulator_arguments}"
+ f"启动模拟器:{self.emulator_path},参数:{self.emulator_arguments}",
+ module=f"MAA调度器-{self.name}",
)
self.emulator_process_manager.open_process(
self.emulator_path, self.emulator_arguments, 0
)
except Exception as e:
- logger.error(f"{self.name} | 启动模拟器时出现异常:{e}")
+ logger.exception(
+ f"启动模拟器时出现异常:{e}",
+ module=f"MAA调度器-{self.name}",
+ )
self.push_info_bar.emit(
"error",
"启动模拟器时出现异常",
@@ -526,14 +561,24 @@ class MaaManager(QObject):
break
# 添加静默进程标记
+ logger.info(
+ f"添加静默进程标记:{self.emulator_path}",
+ module=f"MAA调度器-{self.name}",
+ )
Config.silence_list.append(self.emulator_path)
self.search_ADB_address()
# 创建MAA任务
- self.maa_process_manager.open_process(self.maa_exe_path, [], 10)
+ logger.info(
+ f"启动MAA进程:{self.maa_exe_path}",
+ module=f"MAA调度器-{self.name}",
+ )
+ self.maa_process_manager.open_process(self.maa_exe_path, [], 0)
+
# 监测MAA运行状态
- self.start_monitor(start_time, mode_book[mode])
+ self.log_check_mode = mode_book[mode]
+ self.start_monitor()
if self.maa_result == "Success!":
@@ -541,30 +586,41 @@ class MaaManager(QObject):
run_book[mode] = True
# 从配置文件中解析所需信息
- with self.maa_set_path.open(
- mode="r", encoding="utf-8"
- ) as f:
- data = json.load(f)
+ while not self.isInterruptionRequested:
+ try:
+ with self.maa_set_path.open(
+ mode="r", encoding="utf-8"
+ ) as f:
+ data = json.load(f)
+ break
+ except Exception as e:
+ logger.exception(
+ f"解析MAA配置文件时出现异常:{e}",
+ module=f"MAA调度器-{self.name}",
+ )
+ self.sleep(1)
- # 记录自定义基建索引
- user_data["Data"]["CustomInfrastPlanIndex"] = data[
- "Configurations"
- ]["Default"]["Infrast.CustomInfrastPlanIndex"]
+ if not self.isInterruptionRequested:
+ # 记录自定义基建索引
+ user_data["Data"]["CustomInfrastPlanIndex"] = data[
+ "Configurations"
+ ]["Default"]["Infrast.CustomInfrastPlanIndex"]
- # 记录更新包路径
- if (
- data["Global"]["VersionUpdate.package"]
- and (
- self.maa_root_path
- / data["Global"]["VersionUpdate.package"]
- ).exists()
- ):
- self.maa_update_package = data["Global"][
- "VersionUpdate.package"
- ]
+ # 记录更新包路径
+ if (
+ data["Global"]["VersionUpdate.package"]
+ and (
+ self.maa_root_path
+ / data["Global"]["VersionUpdate.package"]
+ ).exists()
+ ):
+ self.maa_update_package = data["Global"][
+ "VersionUpdate.package"
+ ]
logger.info(
- f"{self.name} | 用户: {user[0]} - MAA进程完成代理任务"
+ f"用户: {user[0]} - MAA进程完成代理任务",
+ module=f"MAA调度器-{self.name}",
)
self.update_log_text.emit(
"检测到MAA进程完成代理任务\n正在等待相关程序结束\n请等待10s"
@@ -573,7 +629,8 @@ class MaaManager(QObject):
self.sleep(10)
else:
logger.error(
- f"{self.name} | 用户: {user[0]} - 代理任务异常: {self.maa_result}"
+ f"用户: {user[0]} - 代理任务异常: {self.maa_result}",
+ module=f"MAA调度器-{self.name}",
)
# 打印中止信息
# 此时,log变量内存储的就是出现异常的日志信息,可以保存或发送用于问题排查
@@ -581,37 +638,55 @@ class MaaManager(QObject):
f"{self.maa_result}\n正在中止相关程序\n请等待10s"
)
# 无命令行中止MAA与其子程序
+ logger.info(
+ f"中止MAA进程:{self.maa_exe_path}",
+ module=f"MAA调度器-{self.name}",
+ )
self.maa_process_manager.kill(if_force=True)
System.kill_process(self.maa_exe_path)
# 中止模拟器进程
+ logger.info(
+ f"中止模拟器进程:{list(self.emulator_process_manager.tracked_pids)}",
+ module=f"MAA调度器-{self.name}",
+ )
self.emulator_process_manager.kill()
self.if_open_emulator = True
# 从配置文件中解析所需信息
- with self.maa_set_path.open(
- mode="r", encoding="utf-8"
- ) as f:
- data = json.load(f)
+ while not self.isInterruptionRequested:
+ try:
+ with self.maa_set_path.open(
+ mode="r", encoding="utf-8"
+ ) as f:
+ data = json.load(f)
+ break
+ except Exception as e:
+ logger.exception(
+ f"解析MAA配置文件时出现异常:{e}",
+ module=f"MAA调度器-{self.name}",
+ )
+ self.sleep(1)
- # 记录自定义基建索引
- if self.task_dict["Base"] == "False":
- user_data["Data"]["CustomInfrastPlanIndex"] = data[
- "Configurations"
- ]["Default"]["Infrast.CustomInfrastPlanIndex"]
+ if not self.isInterruptionRequested:
+ # 记录自定义基建索引
+ if self.task_dict["Base"] == "False":
+ user_data["Data"]["CustomInfrastPlanIndex"] = data[
+ "Configurations"
+ ]["Default"]["Infrast.CustomInfrastPlanIndex"]
- # 记录更新包路径
- if (
- data["Global"]["VersionUpdate.package"]
- and (
- self.maa_root_path
- / data["Global"]["VersionUpdate.package"]
- ).exists()
- ):
- self.maa_update_package = data["Global"][
- "VersionUpdate.package"
- ]
+ # 记录更新包路径
+ if (
+ data["Global"]["VersionUpdate.package"]
+ and (
+ self.maa_root_path
+ / data["Global"]["VersionUpdate.package"]
+ ).exists()
+ ):
+ self.maa_update_package = data["Global"][
+ "VersionUpdate.package"
+ ]
# 推送异常通知
Notify.push_plyer(
@@ -628,16 +703,25 @@ class MaaManager(QObject):
# 任务结束后释放ADB
try:
- logger.info(f"{self.name} | 释放ADB:{self.ADB_address}")
+ logger.info(
+ f"释放ADB:{self.ADB_address}",
+ module=f"MAA调度器-{self.name}",
+ )
subprocess.run(
[self.ADB_path, "disconnect", self.ADB_address],
creationflags=subprocess.CREATE_NO_WINDOW,
)
except subprocess.CalledProcessError as e:
# 忽略错误,因为可能本来就没有连接
- logger.warning(f"{self.name} | 释放ADB时出现异常:{e}")
+ logger.warning(
+ f"释放ADB时出现异常:{e}",
+ module=f"MAA调度器-{self.name}",
+ )
except Exception as e:
- logger.error(f"{self.name} | 释放ADB时出现异常:{e}")
+ logger.exception(
+ f"释放ADB时出现异常:{e}",
+ module=f"MAA调度器-{self.name}",
+ )
self.push_info_bar.emit(
"error",
"释放ADB时出现异常",
@@ -646,6 +730,10 @@ class MaaManager(QObject):
)
# 任务结束后再次手动中止模拟器进程,防止退出不彻底
if self.if_kill_emulator:
+ logger.info(
+ f"任务结束后再次中止模拟器进程:{list(self.emulator_process_manager.tracked_pids)}",
+ module=f"MAA调度器-{self.name}",
+ )
self.emulator_process_manager.kill()
self.if_open_emulator = True
@@ -658,13 +746,13 @@ class MaaManager(QObject):
# 保存运行日志以及统计信息
if_six_star = Config.save_maa_log(
Config.app_path
- / f"history/{curdate}/{user_data["Info"]["Name"]}/{start_time.strftime("%H-%M-%S")}.log",
- self.check_maa_log(start_time, mode_book[mode]),
+ / f"history/{curdate}/{user_data["Info"]["Name"]}/{self.log_start_time.strftime("%H-%M-%S")}.log",
+ self.check_maa_log(),
self.maa_result,
)
user_logs_list.append(
Config.app_path
- / f"history/{curdate}/{user_data["Info"]["Name"]}/{start_time.strftime("%H-%M-%S")}.json",
+ / f"history/{curdate}/{user_data["Info"]["Name"]}/{self.log_start_time.strftime("%H-%M-%S")}.json",
)
if if_six_star:
self.push_notification(
@@ -681,7 +769,8 @@ class MaaManager(QObject):
if self.maa_update_package:
logger.info(
- f"{self.name} | 检测到MAA更新,正在执行更新动作"
+ f"检测到MAA更新,正在执行更新动作",
+ module=f"MAA调度器-{self.name}",
)
self.update_log_text.emit(
@@ -698,7 +787,9 @@ class MaaManager(QObject):
self.maa_update_package = ""
- logger.info(f"{self.name} | 更新动作结束")
+ logger.info(
+ f"更新动作结束", module=f"MAA调度器-{self.name}"
+ )
# 发送统计信息
statistics = Config.merge_statistic_info(user_logs_list)
@@ -727,6 +818,10 @@ class MaaManager(QObject):
user_data["Info"]["RemainedDay"] -= 1
user_data["Data"]["ProxyTimes"] += 1
user[1] = "完成"
+ logger.success(
+ f"用户 {user[0]} 的自动代理任务已完成",
+ module=f"MAA调度器-{self.name}",
+ )
Notify.push_plyer(
"成功完成一个自动代理任务!",
f"已完成用户 {user[0].replace("_", " 今天的")}任务",
@@ -735,6 +830,10 @@ class MaaManager(QObject):
)
else:
# 录入代理失败的用户
+ logger.error(
+ f"用户 {user[0]} 的自动代理任务未完成",
+ module=f"MAA调度器-{self.name}",
+ )
user[1] = "异常"
self.update_user_list.emit(self.user_list)
@@ -743,6 +842,9 @@ class MaaManager(QObject):
elif self.mode == "人工排查":
# 人工排查时,屏蔽静默操作
+ logger.info(
+ "人工排查任务开始,屏蔽静默操作", module=f"MAA调度器-{self.name}"
+ )
Config.if_ignore_silence = True
# 标记是否需要启动模拟器
@@ -759,7 +861,7 @@ class MaaManager(QObject):
if self.isInterruptionRequested:
break
- logger.info(f"{self.name} | 开始排查用户: {user[0]}")
+ logger.info(f"开始排查用户: {user[0]}", module=f"MAA调度器-{self.name}")
user[1] = "运行"
self.update_user_list.emit(self.user_list)
@@ -776,27 +878,38 @@ class MaaManager(QObject):
self.set_maa("人工排查", user[2])
# 记录当前时间
- start_time = datetime.now()
+ self.log_start_time = datetime.now()
# 创建MAA任务
- self.maa_process_manager.open_process(self.maa_exe_path, [], 10)
+ logger.info(
+ f"启动MAA进程:{self.maa_exe_path}",
+ module=f"MAA调度器-{self.name}",
+ )
+ self.maa_process_manager.open_process(self.maa_exe_path, [], 0)
# 监测MAA运行状态
- self.start_monitor(start_time, "人工排查")
+ self.log_check_mode = "人工排查"
+ self.start_monitor()
if self.maa_result == "Success!":
logger.info(
- f"{self.name} | 用户: {user[0]} - MAA进程成功登录PRTS"
+ f"用户: {user[0]} - MAA进程成功登录PRTS",
+ module=f"MAA调度器-{self.name}",
)
run_book[0] = True
self.update_log_text.emit("检测到MAA进程成功登录PRTS")
else:
logger.error(
- f"{self.name} | 用户: {user[0]} - MAA未能正确登录到PRTS: {self.maa_result}"
+ f"用户: {user[0]} - MAA未能正确登录到PRTS: {self.maa_result}",
+ module=f"MAA调度器-{self.name}",
)
self.update_log_text.emit(
f"{self.maa_result}\n正在中止相关程序\n请等待10s"
)
# 无命令行中止MAA与其子程序
+ logger.info(
+ f"中止MAA进程:{self.maa_exe_path}",
+ module=f"MAA调度器-{self.name}",
+ )
self.maa_process_manager.kill(if_force=True)
System.kill_process(self.maa_exe_path)
self.if_open_emulator = True
@@ -825,17 +938,25 @@ class MaaManager(QObject):
# 结果录入
if run_book[0] and run_book[1]:
- logger.info(f"{self.name} | 用户 {user[0]} 通过人工排查")
+ logger.info(
+ f"用户 {user[0]} 通过人工排查", module=f"MAA调度器-{self.name}"
+ )
user_data["Data"]["IfPassCheck"] = True
user[1] = "完成"
else:
- logger.info(f"{self.name} | 用户 {user[0]} 未通过人工排查")
+ logger.info(
+ f"用户 {user[0]} 未通过人工排查",
+ module=f"MAA调度器-{self.name}",
+ )
user_data["Data"]["IfPassCheck"] = False
user[1] = "异常"
self.update_user_list.emit(self.user_list)
# 解除静默操作屏蔽
+ logger.info(
+ "人工排查任务结束,解除静默操作屏蔽", module=f"MAA调度器-{self.name}"
+ )
Config.if_ignore_silence = False
# 设置MAA模式
@@ -844,20 +965,32 @@ class MaaManager(QObject):
# 配置MAA
self.set_maa(self.mode, "")
# 创建MAA任务
- self.maa_process_manager.open_process(self.maa_exe_path, [], 10)
+ logger.info(
+ f"启动MAA进程:{self.maa_exe_path}", module=f"MAA调度器-{self.name}"
+ )
+ self.maa_process_manager.open_process(self.maa_exe_path, [], 0)
# 记录当前时间
- start_time = datetime.now()
+ self.log_start_time = datetime.now()
# 监测MAA运行状态
- self.start_monitor(start_time, "设置MAA")
+ self.log_check_mode = "设置MAA"
+ self.start_monitor()
if "全局" in self.mode:
(self.config_path / "Default").mkdir(parents=True, exist_ok=True)
shutil.copy(self.maa_set_path, self.config_path / "Default")
+ logger.success(
+ f"全局MAA配置文件已保存到 {self.config_path / 'Default/gui.json'}",
+ module=f"MAA调度器-{self.name}",
+ )
elif "用户" in self.mode:
self.user_config_path.mkdir(parents=True, exist_ok=True)
shutil.copy(self.maa_set_path, self.user_config_path)
+ logger.success(
+ f"用户MAA配置文件已保存到 {self.user_config_path}",
+ module=f"MAA调度器-{self.name}",
+ )
result_text = ""
@@ -866,10 +999,18 @@ class MaaManager(QObject):
# 关闭可能未正常退出的MAA进程
if self.isInterruptionRequested:
+ logger.info(
+ f"关闭可能未正常退出的MAA进程:{self.maa_exe_path}",
+ module=f"MAA调度器-{self.name}",
+ )
self.maa_process_manager.kill(if_force=True)
System.kill_process(self.maa_exe_path)
# 复原MAA配置文件
+ logger.info(
+ f"复原MAA配置文件:{self.maa_set_path}",
+ module=f"MAA调度器-{self.name}",
+ )
shutil.copy(self.config_path / "Default/gui.json", self.maa_set_path)
# 更新用户数据
@@ -930,7 +1071,9 @@ class MaaManager(QObject):
self.accomplish.emit({"Time": begin_time, "History": result_text})
def requestInterruption(self) -> None:
- logger.info(f"{self.name} | 收到任务中止申请")
+ """请求中止任务"""
+
+ logger.info(f"收到任务中止申请", module=f"MAA调度器-{self.name}")
if len(self.log_monitor.files()) != 0:
self.interrupt.emit()
@@ -940,17 +1083,25 @@ class MaaManager(QObject):
self.wait_loop.quit()
def push_question(self, title: str, message: str) -> bool:
+ """推送询问窗口"""
+
+ logger.info(
+ f"推送询问窗口:{title} - {message}", module=f"MAA调度器-{self.name}"
+ )
self.question.emit(title, message)
self.question_loop.exec()
return self.response
def __capture_response(self, response: bool) -> None:
+ """捕获询问窗口的响应"""
+ logger.info(f"捕获询问窗口响应:{response}", module=f"MAA调度器-{self.name}")
self.response = response
def sleep(self, time: int) -> None:
"""非阻塞型等待"""
+ logger.info(f"等待 {time} 秒", module=f"MAA调度器-{self.name}")
QTimer.singleShot(time * 1000, self.wait_loop.quit)
self.wait_loop.exec()
@@ -970,6 +1121,10 @@ class MaaManager(QObject):
QTimer.singleShot(
10000, partial(Config.silence_list.remove, self.emulator_path)
)
+ logger.info(
+ f"10s后移除静默进程标记:{self.emulator_path}",
+ module=f"MAA调度器-{self.name}",
+ )
if "-" in self.ADB_address:
ADB_ip = f"{self.ADB_address.split("-")[0]}-"
@@ -980,7 +1135,8 @@ class MaaManager(QObject):
ADB_port = int(self.ADB_address.split(":")[1])
logger.info(
- f"{self.name} | 正在搜索ADB实际地址,ADB前缀:{ADB_ip},初始端口:{ADB_port},搜索范围:{self.port_range}"
+ f"正在搜索ADB实际地址,ADB前缀:{ADB_ip},初始端口:{ADB_port},搜索范围:{self.port_range}",
+ module=f"MAA调度器-{self.name}",
)
for port in self.port_range:
@@ -1010,9 +1166,14 @@ class MaaManager(QObject):
)
if ADB_address in devices_result.stdout:
- logger.info(f"{self.name} | ADB实际地址:{ADB_address}")
+ logger.info(
+ f"ADB实际地址:{ADB_address}", module=f"MAA调度器-{self.name}"
+ )
# 断开连接
+ logger.info(
+ f"断开ADB连接:{ADB_address}", module=f"MAA调度器-{self.name}"
+ )
subprocess.run(
[self.ADB_path, "disconnect", ADB_address],
creationflags=subprocess.CREATE_NO_WINDOW,
@@ -1021,6 +1182,10 @@ class MaaManager(QObject):
self.ADB_address = ADB_address
# 覆写当前ADB地址
+ logger.info(
+ f"开始使用实际 ADB 地址覆写:{self.ADB_address}",
+ module=f"MAA调度器-{self.name}",
+ )
self.maa_process_manager.kill(if_force=True)
System.kill_process(self.maa_exe_path)
with self.maa_set_path.open(mode="r", encoding="utf-8") as f:
@@ -1036,9 +1201,14 @@ class MaaManager(QObject):
return None
else:
- logger.info(f"{self.name} | 无法连接到ADB地址:{ADB_address}")
+ logger.info(
+ f"无法连接到ADB地址:{ADB_address}",
+ module=f"MAA调度器-{self.name}",
+ )
else:
- logger.info(f"{self.name} | 无法连接到ADB地址:{ADB_address}")
+ logger.info(
+ f"无法连接到ADB地址:{ADB_address}", module=f"MAA调度器-{self.name}"
+ )
if not self.isInterruptionRequested:
self.play_sound.emit("ADB失败")
@@ -1046,14 +1216,19 @@ class MaaManager(QObject):
def refresh_maa_log(self) -> None:
"""刷新MAA日志"""
+ logger.debug(
+ f"刷新MAA日志:{self.maa_log_path}", module=f"MAA调度器-{self.name}"
+ )
+
with self.maa_log_path.open(mode="r", encoding="utf-8") as f:
pass
# 一分钟内未执行日志变化检查,强制检查一次
if datetime.now() - self.last_check_time > timedelta(minutes=1):
- self.log_monitor.fileChanged.emit("1分钟超时检查")
+ logger.info("触发 1 分钟超时检查", module=f"MAA调度器-{self.name}")
+ self.check_maa_log()
- def check_maa_log(self, start_time: datetime, mode: str) -> list:
+ def check_maa_log(self) -> list:
"""获取MAA日志并检查以判断MAA程序运行状态"""
self.last_check_time = datetime.now()
@@ -1066,7 +1241,7 @@ class MaaManager(QObject):
if not if_log_start:
try:
entry_time = datetime.strptime(entry[1:20], "%Y-%m-%d %H:%M:%S")
- if entry_time > start_time:
+ if entry_time > self.log_start_time:
if_log_start = True
logs.append(entry)
except ValueError:
@@ -1093,11 +1268,15 @@ class MaaManager(QObject):
if version_match:
self.maa_version = f"v{version_match.group(1)}"
self.check_maa_version.emit(self.maa_version)
+ logger.info(
+ f"检测到MAA版本:{self.maa_version}",
+ module=f"MAA调度器-{self.name}",
+ )
- if "自动代理" in mode:
+ if "自动代理" in self.log_check_mode:
# 获取最近一条日志的时间
- latest_time = start_time
+ latest_time = self.log_start_time
for _ in logs[::-1]:
try:
if "如果长时间无进一步日志更新,可能需要手动干预。" in _:
@@ -1107,12 +1286,16 @@ class MaaManager(QObject):
except ValueError:
pass
+ logger.info(
+ f"MAA最近一条日志时间:{latest_time}", module=f"MAA调度器-{self.name}"
+ )
+
time_book = {
"自动代理_剿灭": "AnnihilationTimeLimit",
"自动代理_日常": "RoutineTimeLimit",
}
- if mode == "自动代理_剿灭" and "剿灭任务失败" in log:
+ if self.log_check_mode == "自动代理_剿灭" and "剿灭任务失败" in log:
self.weekly_annihilation_limit_reached = True
else:
self.weekly_annihilation_limit_reached = False
@@ -1164,7 +1347,7 @@ class MaaManager(QObject):
self.maa_result = "MAA在完成任务前退出"
elif datetime.now() - latest_time > timedelta(
- minutes=self.set["RunSet"][time_book[mode]]
+ minutes=self.set["RunSet"][time_book[self.log_check_mode]]
):
self.maa_result = "MAA进程超时"
@@ -1174,7 +1357,7 @@ class MaaManager(QObject):
else:
self.maa_result = "Wait"
- elif mode == "人工排查":
+ elif self.log_check_mode == "人工排查":
if "完成任务: StartUp" in log or "完成任务: 开始唤醒" in log:
self.maa_result = "Success!"
elif "请 「检查连接设置」 → 「尝试重启模拟器与 ADB」 → 「重启电脑」" in log:
@@ -1193,7 +1376,7 @@ class MaaManager(QObject):
else:
self.maa_result = "Wait"
- elif mode == "设置MAA":
+ elif self.log_check_mode == "设置MAA":
if (
"MaaAssistantArknights GUI exited" in log
or not self.maa_process_manager.is_running()
@@ -1202,20 +1385,24 @@ class MaaManager(QObject):
else:
self.maa_result = "Wait"
+ logger.info(
+ f"MAA日志分析结果:{self.maa_result}", module=f"MAA调度器-{self.name}"
+ )
+
if self.maa_result != "Wait":
self.quit_monitor()
return logs
- def start_monitor(self, start_time: datetime, mode: str) -> None:
+ def start_monitor(self) -> None:
"""开始监视MAA日志"""
- logger.info(f"{self.name} | 开始监视MAA日志")
- self.log_monitor.addPath(str(self.maa_log_path))
- self.log_monitor.fileChanged.connect(
- lambda: self.check_maa_log(start_time, mode)
+ logger.info(
+ f"开始监视MAA日志,路径:{self.maa_log_path},日志起始时间:{self.log_start_time},模式:{self.log_check_mode}",
+ module=f"MAA调度器-{self.name}",
)
+ self.log_monitor.addPath(str(self.maa_log_path))
self.log_monitor_timer.start(1000)
self.last_check_time = datetime.now()
self.monitor_loop.exec()
@@ -1225,16 +1412,29 @@ class MaaManager(QObject):
if len(self.log_monitor.files()) != 0:
- logger.info(f"{self.name} | 退出MAA日志监视")
+ logger.info(
+ f"MAA日志监视器移除路径:{self.maa_log_path}",
+ module=f"MAA调度器-{self.name}",
+ )
self.log_monitor.removePath(str(self.maa_log_path))
- self.log_monitor.fileChanged.disconnect()
- self.log_monitor_timer.stop()
- self.last_check_time = None
- self.monitor_loop.quit()
+
+ else:
+ logger.warning(
+ f"MAA日志监视器没有正在监看的路径:{self.log_monitor.files()}",
+ module=f"MAA调度器-{self.name}",
+ )
+
+ self.log_monitor_timer.stop()
+ self.last_check_time = None
+ self.monitor_loop.quit()
+
+ logger.info("MAA日志监视锁已释放", module=f"MAA调度器-{self.name}")
def set_maa(self, mode, index) -> dict:
"""配置MAA运行参数"""
- logger.info(f"{self.name} | 配置MAA运行参数: {mode}/{index}")
+ logger.info(
+ f"开始配置MAA运行参数: {mode}/{index}", module=f"MAA调度器-{self.name}"
+ )
if "设置MAA" not in self.mode and "更新MAA" not in mode:
user_data = self.data[index]["Config"]
@@ -1804,12 +2004,17 @@ class MaaManager(QObject):
with self.maa_set_path.open(mode="w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
+ logger.success(
+ f"MAA运行参数配置完成: {mode}/{index}", module=f"MAA调度器-{self.name}"
+ )
+
return data
def agree_bilibili(self, if_agree):
"""向MAA写入Bilibili协议相关任务"""
logger.info(
- f"{self.name} | Bilibili协议相关任务状态: {"启用" if if_agree else "禁用"}"
+ f"Bilibili协议相关任务状态: {'启用' if if_agree else '禁用'}",
+ module=f"MAA调度器-{self.name}",
)
with self.maa_tasks_path.open(mode="r", encoding="utf-8") as f:
@@ -1843,6 +2048,10 @@ class MaaManager(QObject):
user_data: Dict[str, Dict[str, Union[str, int, bool]]] = None,
) -> None:
"""通过所有渠道推送通知"""
+ logger.info(
+ f"开始推送通知,模式:{mode},标题:{title}",
+ module=f"MAA调度器-{self.name}",
+ )
env = Environment(
loader=FileSystemLoader(str(Config.app_path / "resources/html"))
@@ -1971,9 +2180,7 @@ class MaaManager(QObject):
user_data["Notify"]["ToAddress"],
)
else:
- logger.error(
- f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知"
- )
+ logger.error(f"用户邮箱地址为空,无法发送用户单独的邮件通知")
# 发送ServerChan通知
if user_data["Notify"]["IfServerChan"]:
@@ -2051,9 +2258,7 @@ class MaaManager(QObject):
user_data["Notify"]["ToAddress"],
)
else:
- logger.error(
- f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知"
- )
+ logger.error(f"用户邮箱地址为空,无法发送用户单独的邮件通知")
# 发送ServerChan通知
if user_data["Notify"]["IfServerChan"]:
diff --git a/app/models/general.py b/app/models/general.py
index 5966bb2..17e21cc 100644
--- a/app/models/general.py
+++ b/app/models/general.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtCore import QObject, Signal, QEventLoop, QFileSystemWatcher, QTimer
import os
import sys
@@ -37,7 +36,7 @@ from pathlib import Path
from jinja2 import Environment, FileSystemLoader
from typing import Union, List, Dict
-from app.core import Config, GeneralConfig, GeneralSubConfig
+from app.core import Config, GeneralConfig, GeneralSubConfig, logger
from app.services import Notify, System
from app.utils import ProcessManager
@@ -75,19 +74,20 @@ class GeneralManager(QObject):
self.sub_list = []
self.mode = mode
self.config_path = config["Path"]
+ self.name = config["Config"].get(config["Config"].Script_Name)
self.sub_config_path = sub_config_path
self.game_process_manager = ProcessManager()
self.script_process_manager = ProcessManager()
self.log_monitor = QFileSystemWatcher()
+ self.log_monitor.fileChanged.connect(self.check_script_log)
self.log_monitor_timer = QTimer()
self.log_monitor_timer.timeout.connect(self.refresh_log)
self.monitor_loop = QEventLoop()
+ self.loge_start_time = datetime.now()
- self.script_process_manager.processClosed.connect(
- lambda: self.log_monitor.fileChanged.emit("进程结束检查")
- )
+ self.script_process_manager.processClosed.connect(self.check_script_log)
self.question_loop = QEventLoop()
self.question_response.connect(self.__capture_response)
@@ -111,6 +111,10 @@ class GeneralManager(QObject):
self.data = dict(sorted(self.data.items(), key=lambda x: int(x[0][3:])))
+ logger.success(
+ f"初始化通用调度器,模式:{self.mode}", module=f"通用调度器-{self.name}"
+ )
+
def check_config_info(self) -> bool:
"""检查配置完整性"""
@@ -124,7 +128,7 @@ class GeneralManager(QObject):
) or (
self.set["Game"]["Enabled"] and not Path(self.set["Game"]["Path"]).exists()
):
- logger.error("脚本配置缺失")
+ logger.error("脚本配置缺失", module=f"通用调度器-{self.name}")
self.push_info_bar.emit("error", "脚本配置缺失", "请检查脚本配置!", -1)
return False
@@ -133,7 +137,6 @@ class GeneralManager(QObject):
def configure(self):
"""提取配置信息"""
- self.name = self.set["Script"]["Name"]
self.script_root_path = Path(self.set["Script"]["RootPath"])
self.script_exe_path = Path(self.set["Script"]["ScriptPath"])
self.script_config_path = Path(self.set["Script"]["ConfigPath"])
@@ -166,9 +169,23 @@ class GeneralManager(QObject):
curdate = Config.server_date().strftime("%Y-%m-%d")
begin_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ if self.mode == "人工排查":
+
+ logger.error("通用脚本不支持人工排查模式", module=f"通用调度器-{self.name}")
+ self.accomplish.emit(
+ {
+ "Time": begin_time,
+ "History": "通用脚本不支持人工排查模式,通用代理进程中止",
+ }
+ )
+ return None
+
# 检查配置完整性
if not self.check_config_info():
+ logger.error(
+ "配置不完整,无法启动通用代理进程", module=f"通用调度器-{self.name}"
+ )
self.accomplish.emit(
{"Time": begin_time, "History": "由于配置不完整,通用代理进程中止"}
)
@@ -190,6 +207,11 @@ class GeneralManager(QObject):
]
self.create_user_list.emit(self.sub_list)
+ logger.info(
+ f"配置列表创建完成,已筛选子配置数:{len(self.sub_list)}",
+ module=f"通用调度器-{self.name}",
+ )
+
# 自动代理模式
if self.mode == "自动代理":
@@ -222,14 +244,17 @@ class GeneralManager(QObject):
self.update_user_list.emit(self.sub_list)
continue
- logger.info(f"{self.name} | 开始代理配置: {sub[0]}")
+ logger.info(f"开始代理配置: {sub[0]}", module=f"通用调度器-{self.name}")
sub_start_time = datetime.now()
run_book = False
if not (self.data[sub[2]]["Path"] / "ConfigFiles").exists():
- logger.error(f"{self.name} | 配置: {sub[0]} - 未找到配置文件")
+ logger.error(
+ f"配置: {sub[0]} - 未找到配置文件",
+ module=f"通用调度器-{self.name}",
+ )
self.push_info_bar.emit(
"error",
"启动通用代理进程失败",
@@ -246,11 +271,12 @@ class GeneralManager(QObject):
break
logger.info(
- f"{self.name} | 用户: {sub[0]} - 尝试次数: {i + 1}/{self.set['Run']['RunTimesLimit']}"
+ f"用户: {sub[0]} - 尝试次数: {i + 1}/{self.set['Run']['RunTimesLimit']}",
+ module=f"通用调度器-{self.name}",
)
# 记录当前时间
- start_time = datetime.now()
+ self.log_start_time = datetime.now()
# 配置脚本
self.set_sub(sub[2])
# 执行任务前脚本
@@ -267,7 +293,8 @@ class GeneralManager(QObject):
try:
logger.info(
- f"{self.name} | 启动游戏/模拟器:{self.game_path},参数:{self.set['Game']['Arguments']}"
+ f"启动游戏/模拟器:{self.game_path},参数:{self.set['Game']['Arguments']}",
+ module=f"通用调度器-{self.name}",
)
self.game_process_manager.open_process(
self.game_path,
@@ -275,8 +302,9 @@ class GeneralManager(QObject):
0,
)
except Exception as e:
- logger.error(
- f"{self.name} | 启动游戏/模拟器时出现异常:{e}"
+ logger.exception(
+ f"启动游戏/模拟器时出现异常:{e}",
+ module=f"通用调度器-{self.name}",
)
self.push_info_bar.emit(
"error",
@@ -289,6 +317,10 @@ class GeneralManager(QObject):
# 添加静默进程标记
if self.set["Game"]["Style"] == "Emulator":
+ logger.info(
+ f"添加静默进程标记:{self.game_path}",
+ module=f"通用调度器-{self.name}",
+ )
Config.silence_list.append(self.game_path)
self.update_log_text.emit(
@@ -299,6 +331,10 @@ class GeneralManager(QObject):
# 10s后移除静默进程标记
if self.set["Game"]["Style"] == "Emulator":
+ logger.info(
+ f"10s后移除静默进程标记:{self.game_path}",
+ module=f"通用调度器-{self.name}",
+ )
QTimer.singleShot(
10000,
partial(Config.silence_list.remove, self.game_path),
@@ -306,7 +342,8 @@ class GeneralManager(QObject):
# 运行脚本任务
logger.info(
- f"{self.name} | 运行脚本任务:{self.script_exe_path},参数:{self.set['Script']['Arguments']}"
+ f"运行脚本任务:{self.script_exe_path},参数:{self.set['Script']['Arguments']}",
+ module=f"通用调度器-{self.name}",
)
self.script_process_manager.open_process(
self.script_exe_path,
@@ -315,7 +352,7 @@ class GeneralManager(QObject):
)
# 监测运行状态
- self.start_monitor(start_time)
+ self.start_monitor()
if self.script_result == "Success!":
@@ -323,15 +360,24 @@ class GeneralManager(QObject):
run_book = True
# 中止相关程序
+ logger.info(
+ f"中止相关程序:{self.script_exe_path}",
+ module=f"通用调度器-{self.name}",
+ )
self.script_process_manager.kill()
System.kill_process(self.script_exe_path)
if self.set["Game"]["Enabled"]:
+ logger.info(
+ f"中止游戏/模拟器进程:{list(self.game_process_manager.tracked_pids)}",
+ module=f"通用调度器-{self.name}",
+ )
self.game_process_manager.kill()
if self.set["Game"]["IfForceClose"]:
System.kill_process(self.game_path)
logger.info(
- f"{self.name} | 配置: {sub[0]} - 通用脚本进程完成代理任务"
+ f"配置: {sub[0]} - 通用脚本进程完成代理任务",
+ module=f"通用调度器-{self.name}",
)
self.update_log_text.emit(
"检测到通用脚本进程完成代理任务\n正在等待相关程序结束\n请等待10s"
@@ -340,7 +386,8 @@ class GeneralManager(QObject):
self.sleep(10)
else:
logger.error(
- f"{self.name} | 配置: {sub[0]} - 代理任务异常: {self.script_result}"
+ f"配置: {sub[0]} - 代理任务异常: {self.script_result}",
+ module=f"通用调度器-{self.name}",
)
# 打印中止信息
# 此时,log变量内存储的就是出现异常的日志信息,可以保存或发送用于问题排查
@@ -349,8 +396,16 @@ class GeneralManager(QObject):
)
# 中止相关程序
+ logger.info(
+ f"中止相关程序:{self.script_exe_path}",
+ module=f"通用调度器-{self.name}",
+ )
self.script_process_manager.kill()
if self.set["Game"]["Enabled"]:
+ logger.info(
+ f"中止游戏/模拟器进程:{list(self.game_process_manager.tracked_pids)}",
+ module=f"通用调度器-{self.name}",
+ )
self.game_process_manager.kill()
if self.set["Game"]["IfForceClose"]:
System.kill_process(self.game_path)
@@ -380,8 +435,8 @@ class GeneralManager(QObject):
# 保存运行日志以及统计信息
Config.save_general_log(
Config.app_path
- / f"history/{curdate}/{sub_data['Info']['Name']}/{start_time.strftime("%H-%M-%S")}.log",
- self.check_script_log(start_time),
+ / f"history/{curdate}/{sub_data['Info']['Name']}/{self.log_start_time.strftime("%H-%M-%S")}.log",
+ self.check_script_log(),
self.script_result,
)
@@ -409,6 +464,10 @@ class GeneralManager(QObject):
sub_data["Info"]["RemainedDay"] -= 1
sub_data["Data"]["ProxyTimes"] += 1
sub[1] = "完成"
+ logger.success(
+ f"配置: {sub[0]} - 代理任务完成",
+ module=f"通用调度器-{self.name}",
+ )
Notify.push_plyer(
"成功完成一个自动代理任务!",
f"已完成配置 {sub[0].replace("_", " 今天的")}任务",
@@ -418,6 +477,10 @@ class GeneralManager(QObject):
else:
# 录入代理失败的用户
sub[1] = "异常"
+ logger.error(
+ f"配置: {sub[0]} - 代理任务异常: {self.script_result}",
+ module=f"通用调度器-{self.name}",
+ )
self.update_user_list.emit(self.sub_list)
@@ -429,17 +492,20 @@ class GeneralManager(QObject):
try:
# 创建通用脚本任务
- logger.info(f"{self.name} | 无参数启动通用脚本:{self.script_exe_path}")
+ logger.info(
+ f"无参数启动通用脚本:{self.script_exe_path}",
+ module=f"通用调度器-{self.name}",
+ )
self.script_process_manager.open_process(
self.script_exe_path,
tracking_time=60 if self.set["Script"]["IfTrackProcess"] else 0,
)
# 记录当前时间
- start_time = datetime.now()
+ self.log_start_time = datetime.now()
# 监测通用脚本运行状态
- self.start_monitor(start_time)
+ self.start_monitor()
self.sub_config_path.mkdir(parents=True, exist_ok=True)
if self.set["Script"]["ConfigPathMode"] == "文件夹":
@@ -448,16 +514,23 @@ class GeneralManager(QObject):
self.sub_config_path,
dirs_exist_ok=True,
)
+ logger.success(
+ f"通用脚本配置已保存到:{self.sub_config_path}",
+ module=f"通用调度器-{self.name}",
+ )
else:
shutil.copy(self.script_config_path, self.sub_config_path)
+ logger.success(
+ f"通用脚本配置已保存到:{self.sub_config_path}",
+ module=f"通用调度器-{self.name}",
+ )
except Exception as e:
- logger.error(f"{self.name} | 启动通用脚本时出现异常:{e}")
+ logger.exception(
+ f"启动通用脚本时出现异常:{e}", module=f"通用调度器-{self.name}"
+ )
self.push_info_bar.emit(
- "error",
- "启动通用脚本时出现异常",
- "请检查相关设置",
- -1,
+ "error", "启动通用脚本时出现异常", "请检查相关设置", -1
)
result_text = ""
@@ -467,9 +540,17 @@ class GeneralManager(QObject):
# 关闭可能未正常退出的通用脚本进程
if self.isInterruptionRequested:
+ logger.info(
+ f"关闭可能未正常退出的通用脚本进程:{self.script_exe_path}",
+ module=f"通用调度器-{self.name}",
+ )
self.script_process_manager.kill(if_force=True)
System.kill_process(self.script_exe_path)
if self.set["Game"]["Enabled"]:
+ logger.info(
+ f"关闭可能未正常退出的游戏/模拟器进程:{list(self.game_process_manager.tracked_pids)}",
+ module=f"通用调度器-{self.name}",
+ )
self.game_process_manager.kill(if_force=True)
if self.set["Game"]["IfForceClose"]:
System.kill_process(self.game_path)
@@ -527,7 +608,9 @@ class GeneralManager(QObject):
self.accomplish.emit({"Time": begin_time, "History": result_text})
def requestInterruption(self) -> None:
- logger.info(f"{self.name} | 收到任务中止申请")
+ """请求中止通用脚本任务"""
+
+ logger.info(f"收到任务中止申请", module=f"通用调度器-{self.name}")
if len(self.log_monitor.files()) != 0:
self.interrupt.emit()
@@ -537,29 +620,45 @@ class GeneralManager(QObject):
self.wait_loop.quit()
def push_question(self, title: str, message: str) -> bool:
+ """推送问题询问"""
+
+ logger.info(
+ f"推送问题询问:{title} - {message}", module=f"通用调度器-{self.name}"
+ )
self.question.emit(title, message)
self.question_loop.exec()
return self.response
def __capture_response(self, response: bool) -> None:
+ """捕获问题询问的响应"""
+
+ logger.info(f"捕获问题询问的响应:{response}", module=f"通用调度器-{self.name}")
self.response = response
def sleep(self, time: int) -> None:
"""非阻塞型等待"""
+ logger.info(f"等待 {time} 秒", module=f"通用调度器-{self.name}")
+
QTimer.singleShot(time * 1000, self.wait_loop.quit)
self.wait_loop.exec()
def refresh_log(self) -> None:
"""刷新脚本日志"""
+ logger.debug(
+ f"刷新通用脚本日志:{self.script_log_path}",
+ module=f"通用调度器-{self.name}",
+ )
+
with self.script_log_path.open(mode="r", encoding="utf-8") as f:
pass
# 一分钟内未执行日志变化检查,强制检查一次
if (datetime.now() - self.last_check_time).total_seconds() > 60:
- self.log_monitor.fileChanged.emit("1分钟超时检查")
+ logger.info("触发 1 分钟超时检查", module=f"通用调度器-{self.name}")
+ self.check_script_log()
def strptime(
self, date_string: str, format: str, default_date: datetime
@@ -589,7 +688,7 @@ class GeneralManager(QObject):
return datetime(**datetime_kwargs)
- def check_script_log(self, start_time: datetime) -> list:
+ def check_script_log(self) -> list:
"""获取脚本日志并检查以判断脚本程序运行状态"""
self.last_check_time = datetime.now()
@@ -607,7 +706,7 @@ class GeneralManager(QObject):
self.last_check_time,
)
- if entry_time > start_time:
+ if entry_time > self.log_start_time:
if_log_start = True
logs.append(entry)
except ValueError:
@@ -625,7 +724,7 @@ class GeneralManager(QObject):
if "自动代理" in self.mode:
# 获取最近一条日志的时间
- latest_time = start_time
+ latest_time = self.log_start_time
for _ in logs[::-1]:
try:
latest_time = self.strptime(
@@ -637,6 +736,11 @@ class GeneralManager(QObject):
except ValueError:
pass
+ logger.info(
+ f"通用脚本最近一条日志时间:{latest_time}",
+ module=f"通用调度器-{self.name}",
+ )
+
for success_sign in self.success_log:
if success_sign in log:
self.script_result = "Success!"
@@ -668,18 +772,25 @@ class GeneralManager(QObject):
else:
self.script_result = "Success!"
+ logger.info(
+ f"通用脚本日志分析结果:{self.script_result}",
+ module=f"通用调度器-{self.name}",
+ )
+
if self.script_result != "Wait":
self.quit_monitor()
return logs
- def start_monitor(self, start_time: datetime) -> None:
+ def start_monitor(self) -> None:
"""开始监视通用脚本日志"""
- logger.info(f"{self.name} | 开始监视通用脚本日志")
+ logger.info(
+ f"开始监视通用脚本日志,路径:{self.script_log_path},日志起始时间:{self.log_start_time}",
+ module=f"通用调度器-{self.name}",
+ )
self.log_monitor.addPath(str(self.script_log_path))
- self.log_monitor.fileChanged.connect(lambda: self.check_script_log(start_time))
self.log_monitor_timer.start(1000)
self.last_check_time = datetime.now()
self.monitor_loop.exec()
@@ -689,16 +800,27 @@ class GeneralManager(QObject):
if len(self.log_monitor.files()) != 0:
- logger.info(f"{self.name} | 退出通用脚本日志监视")
+ logger.info(
+ f"通用脚本日志监视器移除路径:{self.script_log_path}",
+ module=f"通用调度器-{self.name}",
+ )
self.log_monitor.removePath(str(self.script_log_path))
- self.log_monitor.fileChanged.disconnect()
- self.log_monitor_timer.stop()
- self.last_check_time = None
- self.monitor_loop.quit()
+
+ else:
+ logger.warning(
+ f"通用脚本日志监视器没有正在监看的路径:{self.log_monitor.files()}",
+ module=f"通用调度器-{self.name}",
+ )
+
+ self.log_monitor_timer.stop()
+ self.last_check_time = None
+ self.monitor_loop.quit()
+
+ logger.info("通用脚本日志监视锁已释放", module=f"通用调度器-{self.name}")
def set_sub(self, index: str = "") -> dict:
"""配置通用脚本运行参数"""
- logger.info(f"{self.name} | 配置脚本运行参数: {index}")
+ logger.info(f"开始配置脚本运行参数:{index}", module=f"通用调度器-{self.name}")
# 配置前关闭可能未正常退出的脚本进程
System.kill_process(self.script_exe_path)
@@ -732,11 +854,15 @@ class GeneralManager(QObject):
self.script_config_path,
)
+ logger.info(f"脚本运行参数配置完成:{index}", module=f"通用调度器-{self.name}")
+
def execute_script_task(self, script_path: Path, task_name: str) -> bool:
"""执行脚本任务并等待结束"""
try:
- logger.info(f"{self.name} | 开始执行{task_name}: {script_path}")
+ logger.info(
+ f"开始执行{task_name}: {script_path}", module=f"通用调度器-{self.name}"
+ )
# 根据文件类型选择执行方式
if script_path.suffix.lower() == ".py":
@@ -744,7 +870,10 @@ class GeneralManager(QObject):
elif script_path.suffix.lower() in [".bat", ".cmd", ".exe"]:
cmd = [str(script_path)]
elif script_path.suffix.lower() == "":
- logger.warning(f"{self.name} | {task_name}脚本没有指定后缀名,无法执行")
+ logger.warning(
+ f"{task_name}脚本没有指定后缀名,无法执行",
+ module=f"通用调度器-{self.name}",
+ )
return False
else:
# 使用系统默认程序打开
@@ -767,23 +896,32 @@ class GeneralManager(QObject):
)
if result.returncode == 0:
- logger.info(f"{self.name} | {task_name}执行成功")
+ logger.info(f"{task_name}执行成功", module=f"通用调度器-{self.name}")
if result.stdout.strip():
- logger.info(f"{self.name} | {task_name}输出: {result.stdout}")
+ logger.info(
+ f"{task_name}输出: {result.stdout}",
+ module=f"通用调度器-{self.name}",
+ )
return True
else:
logger.error(
- f"{self.name} | {task_name}执行失败,返回码: {result.returncode}"
+ f"{task_name}执行失败,返回码: {result.returncode}",
+ module=f"通用调度器-{self.name}",
)
if result.stderr.strip():
- logger.error(f"{self.name} | {task_name}错误输出: {result.stderr}")
+ logger.error(
+ f"{task_name}错误输出: {result.stderr}",
+ module=f"通用调度器-{self.name}",
+ )
return False
except subprocess.TimeoutExpired:
- logger.error(f"{self.name} | {task_name}执行超时")
+ logger.error(f"{task_name}执行超时", module=f"通用调度器-{self.name}")
return False
except Exception as e:
- logger.exception(f"{self.name} | 执行{task_name}时出现异常: {e}")
+ logger.exception(
+ f"执行{task_name}时出现异常: {e}", module=f"通用调度器-{self.name}"
+ )
return False
def push_notification(
@@ -795,6 +933,11 @@ class GeneralManager(QObject):
) -> None:
"""通过所有渠道推送通知"""
+ logger.info(
+ f"开始推送通知,模式:{mode},标题:{title}",
+ module=f"通用调度器-{self.name}",
+ )
+
env = Environment(
loader=FileSystemLoader(str(Config.app_path / "resources/html"))
)
@@ -902,9 +1045,7 @@ class GeneralManager(QObject):
sub_data["Notify"]["ToAddress"],
)
else:
- logger.error(
- f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知"
- )
+ logger.error(f"用户邮箱地址为空,无法发送用户单独的邮件通知")
# 发送ServerChan通知
if sub_data["Notify"]["IfServerChan"]:
diff --git a/app/services/notification.py b/app/services/notification.py
index 56ddf04..0fd13f4 100644
--- a/app/services/notification.py
+++ b/app/services/notification.py
@@ -33,13 +33,14 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr
from pathlib import Path
+from typing import Union
import requests
from PySide6.QtCore import QObject, Signal
-from loguru import logger
+
from plyer import notification
-from app.core import Config
+from app.core import Config, logger
from app.services.security import Crypto
from app.utils.ImageUtils import ImageUtils
@@ -51,11 +52,21 @@ class Notification(QObject):
def __init__(self, parent=None):
super().__init__(parent)
- def push_plyer(self, title, message, ticker, t):
- """推送系统通知"""
+ def push_plyer(self, title, message, ticker, t) -> bool:
+ """
+ 推送系统通知
+
+ :param title: 通知标题
+ :param message: 通知内容
+ :param ticker: 通知横幅
+ :param t: 通知持续时间
+ :return: bool
+ """
if Config.get(Config.notify_IfPushPlyer):
+ logger.info(f"推送系统通知:{title}", module="通知服务")
+
notification.notify(
title=title,
message=message,
@@ -69,7 +80,15 @@ class Notification(QObject):
return True
def send_mail(self, mode, title, content, to_address) -> None:
- """推送邮件通知"""
+ """
+ 推送邮件通知
+
+ :param mode: 邮件内容模式,支持 "文本" 和 "网页"
+ :param title: 邮件标题
+ :param content: 邮件内容
+ :param to_address: 收件人地址
+ """
+
if (
Config.get(Config.notify_SMTPServerAddress) == ""
or Config.get(Config.notify_AuthorizationCode) == ""
@@ -87,7 +106,8 @@ class Notification(QObject):
)
):
logger.error(
- "请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址"
+ "请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址",
+ module="通知服务",
)
self.push_info_bar.emit(
"error",
@@ -110,42 +130,43 @@ class Notification(QObject):
)
) # 发件人显示的名字
message["To"] = formataddr(
- (
- Header("AUTO_MAA用户", "utf-8").encode(),
- to_address,
- )
+ (Header("AUTO_MAA用户", "utf-8").encode(), to_address)
) # 收件人显示的名字
message["Subject"] = Header(title, "utf-8")
if mode == "网页":
message.attach(MIMEText(content, "html", "utf-8"))
- smtpObj = smtplib.SMTP_SSL(
- Config.get(Config.notify_SMTPServerAddress),
- 465,
- )
+ smtpObj = smtplib.SMTP_SSL(Config.get(Config.notify_SMTPServerAddress), 465)
smtpObj.login(
Config.get(Config.notify_FromAddress),
Crypto.win_decryptor(Config.get(Config.notify_AuthorizationCode)),
)
smtpObj.sendmail(
- Config.get(Config.notify_FromAddress),
- to_address,
- message.as_string(),
+ Config.get(Config.notify_FromAddress), to_address, message.as_string()
)
smtpObj.quit()
- logger.success("邮件发送成功")
- return None
+ logger.success(f"邮件发送成功:{title}", module="通知服务")
except Exception as e:
- logger.error(f"发送邮件时出错:\n{e}")
+ logger.exception(f"发送邮件时出错:{e}", module="通知服务")
self.push_info_bar.emit("error", "发送邮件时出错", f"{e}", -1)
- return None
- return None
- def ServerChanPush(self, title, content, send_key, tag, channel):
- """使用Server酱推送通知"""
+ def ServerChanPush(
+ self, title, content, send_key, tag, channel
+ ) -> Union[bool, str]:
+ """
+ 使用Server酱推送通知
+
+ :param title: 通知标题
+ :param content: 通知内容
+ :param send_key: Server酱的SendKey
+ :param tag: 通知标签
+ :param channel: 通知频道
+ :return: bool or str
+ """
+
if not send_key:
- logger.error("请正确设置Server酱的SendKey")
+ logger.error("请正确设置Server酱的SendKey", module="通知服务")
self.push_info_bar.emit(
"error", "Server酱通知推送异常", "请正确设置Server酱的SendKey", -1
)
@@ -176,7 +197,7 @@ class Notification(QObject):
if is_valid(tags):
options["tags"] = tags
else:
- logger.warning("Server酱 Tag 配置不正确,将被忽略")
+ logger.warning("Server酱 Tag 配置不正确,将被忽略", module="通知服务")
self.push_info_bar.emit(
"warning",
"Server酱通知推送异常",
@@ -187,7 +208,9 @@ class Notification(QObject):
if is_valid(channels):
options["channel"] = channels
else:
- logger.warning("Server酱 Channel 配置不正确,将被忽略")
+ logger.warning(
+ "Server酱 Channel 配置不正确,将被忽略", module="通知服务"
+ )
self.push_info_bar.emit(
"warning",
"Server酱通知推送异常",
@@ -212,18 +235,20 @@ class Notification(QObject):
result = response.json()
if result.get("code") == 0:
- logger.info("Server酱推送通知成功")
+ logger.success(f"Server酱推送通知成功:{title}", module="通知服务")
return True
else:
error_code = result.get("code", "-1")
- logger.error(f"Server酱通知推送失败:响应码:{error_code}")
+ logger.exception(
+ f"Server酱通知推送失败:响应码:{error_code}", module="通知服务"
+ )
self.push_info_bar.emit(
"error", "Server酱通知推送失败", f"响应码:{error_code}", -1
)
return f"Server酱通知推送失败:{error_code}"
except Exception as e:
- logger.exception("Server酱通知推送异常")
+ logger.exception(f"Server酱通知推送异常:{e}", module="通知服务")
self.push_info_bar.emit(
"error",
"Server酱通知推送异常",
@@ -232,10 +257,18 @@ class Notification(QObject):
)
return f"Server酱通知推送异常:{str(e)}"
- def CompanyWebHookBotPush(self, title, content, webhook_url):
- """使用企业微信群机器人推送通知"""
+ def CompanyWebHookBotPush(self, title, content, webhook_url) -> Union[bool, str]:
+ """
+ 使用企业微信群机器人推送通知
+
+ :param title: 通知标题
+ :param content: 通知内容
+ :param webhook_url: 企业微信群机器人的WebHook地址
+ :return: bool or str
+ """
+
if webhook_url == "":
- logger.error("请正确设置企业微信群机器人的WebHook地址")
+ logger.error("请正确设置企业微信群机器人的WebHook地址", module="通知服务")
self.push_info_bar.emit(
"error",
"企业微信群机器人通知推送异常",
@@ -264,7 +297,7 @@ class Notification(QObject):
err = e
time.sleep(0.1)
else:
- logger.error(f"推送企业微信群机器人时出错:{err}")
+ logger.error(f"推送企业微信群机器人时出错:{err}", module="通知服务")
self.push_info_bar.emit(
"error",
"企业微信群机器人通知推送失败",
@@ -274,10 +307,10 @@ class Notification(QObject):
return None
if info["errcode"] == 0:
- logger.info("企业微信群机器人推送通知成功")
+ logger.success(f"企业微信群机器人推送通知成功:{title}", module="通知服务")
return True
else:
- logger.error(f"企业微信群机器人推送通知失败:{info}")
+ logger.error(f"企业微信群机器人推送通知失败:{info}", module="通知服务")
self.push_info_bar.emit(
"error",
"企业微信群机器人通知推送失败",
@@ -287,7 +320,14 @@ class Notification(QObject):
return f"使用企业微信群机器人推送通知时出错:{err}"
def CompanyWebHookBotPushImage(self, image_path: Path, webhook_url: str) -> bool:
- """使用企业微信群机器人推送图片通知"""
+ """
+ 使用企业微信群机器人推送图片通知
+
+ :param image_path: 图片文件路径
+ :param webhook_url: 企业微信群机器人的WebHook地址
+ :return: bool
+ """
+
try:
# 压缩图片
ImageUtils.compress_image_if_needed(image_path)
@@ -295,7 +335,8 @@ class Notification(QObject):
# 检查图片是否存在
if not image_path.exists():
logger.error(
- "图片推送异常 | 图片不存在或者压缩失败,请检查图片路径是否正确"
+ "图片推送异常 | 图片不存在或者压缩失败,请检查图片路径是否正确",
+ module="通知服务",
)
self.push_info_bar.emit(
"error",
@@ -306,7 +347,9 @@ class Notification(QObject):
return False
if not webhook_url:
- logger.error("请正确设置企业微信群机器人的WebHook地址")
+ logger.error(
+ "请正确设置企业微信群机器人的WebHook地址", module="通知服务"
+ )
self.push_info_bar.emit(
"error",
"企业微信群机器人通知推送异常",
@@ -320,7 +363,7 @@ class Notification(QObject):
image_base64 = ImageUtils.get_base64_from_file(str(image_path))
image_md5 = ImageUtils.calculate_md5_from_file(str(image_path))
except Exception as e:
- logger.exception(f"图片编码或MD5计算失败:{e}")
+ logger.exception(f"图片编码或MD5计算失败:{e}", module="通知服务")
self.push_info_bar.emit(
"error",
"企业微信群机器人通知推送异常",
@@ -349,10 +392,12 @@ class Notification(QObject):
break
except requests.RequestException as e:
err = e
- logger.warning(f"推送企业微信群机器人图片第{_+1}次失败:{e}")
+ logger.exception(
+ f"推送企业微信群机器人图片第{_+1}次失败:{e}", module="通知服务"
+ )
time.sleep(0.1)
else:
- logger.error(f"推送企业微信群机器人图片时出错:{err}")
+ logger.error("推送企业微信群机器人图片时出错", module="通知服务")
self.push_info_bar.emit(
"error",
"企业微信群机器人图片推送失败",
@@ -362,10 +407,13 @@ class Notification(QObject):
return False
if info.get("errcode") == 0:
- logger.info("企业微信群机器人推送图片成功")
+ logger.success(
+ f"企业微信群机器人推送图片成功:{image_path.name}",
+ module="通知服务",
+ )
return True
else:
- logger.error(f"企业微信群机器人推送图片失败:{info}")
+ logger.error(f"企业微信群机器人推送图片失败:{info}", module="通知服务")
self.push_info_bar.emit(
"error",
"企业微信群机器人图片推送失败",
@@ -386,6 +434,9 @@ class Notification(QObject):
def send_test_notification(self):
"""发送测试通知到所有已启用的通知渠道"""
+
+ logger.info("发送测试通知到所有已启用的通知渠道", module="通知服务")
+
# 发送系统通知
self.push_plyer(
"测试通知",
@@ -425,6 +476,8 @@ class Notification(QObject):
Config.get(Config.notify_CompanyWebHookBotUrl),
)
+ logger.info("测试通知发送完成", module="通知服务")
+
return True
diff --git a/app/services/security.py b/app/services/security.py
index b7bcc1a..b811f95 100644
--- a/app/services/security.py
+++ b/app/services/security.py
@@ -25,18 +25,15 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
import hashlib
import random
import secrets
import base64
import win32crypt
-from pathlib import Path
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Util.Padding import pad, unpad
-from typing import List, Dict, Union
from app.core import Config
@@ -44,7 +41,12 @@ from app.core import Config
class CryptoHandler:
def get_PASSWORD(self, PASSWORD: str) -> None:
- """配置管理密钥"""
+ """
+ 配置管理密钥
+
+ :param PASSWORD: 管理密钥
+ :type PASSWORD: str
+ """
# 生成目录
Config.key_path.mkdir(parents=True, exist_ok=True)
@@ -85,7 +87,12 @@ class CryptoHandler:
(Config.app_path / "data/key/private_key.bin").write_bytes(private_key_local)
def AUTO_encryptor(self, note: str) -> str:
- """使用AUTO_MAA的算法加密数据"""
+ """
+ 使用AUTO_MAA的算法加密数据
+
+ :param note: 数据明文
+ :type note: str
+ """
if note == "":
return ""
@@ -100,7 +107,16 @@ class CryptoHandler:
return base64.b64encode(encrypted).decode("utf-8")
def AUTO_decryptor(self, note: str, PASSWORD: str) -> str:
- """使用AUTO_MAA的算法解密数据"""
+ """
+ 使用AUTO_MAA的算法解密数据
+
+ :param note: 数据密文
+ :type note: str
+ :param PASSWORD: 管理密钥
+ :type PASSWORD: str
+ :return: 解密后的明文
+ :rtype: str
+ """
if note == "":
return ""
@@ -142,7 +158,14 @@ class CryptoHandler:
return note
def change_PASSWORD(self, PASSWORD_old: str, PASSWORD_new: str) -> None:
- """修改管理密钥"""
+ """
+ 修改管理密钥
+
+ :param PASSWORD_old: 旧管理密钥
+ :type PASSWORD_old: str
+ :param PASSWORD_new: 新管理密钥
+ :type PASSWORD_new: str
+ """
for member in Config.member_dict.values():
@@ -168,7 +191,12 @@ class CryptoHandler:
del user["Password"]
def reset_PASSWORD(self, PASSWORD_new: str) -> None:
- """重置管理密钥"""
+ """
+ 重置管理密钥
+
+ :param PASSWORD_new: 新管理密钥
+ :type PASSWORD_new: str
+ """
self.get_PASSWORD(PASSWORD_new)
@@ -176,12 +204,25 @@ class CryptoHandler:
if member["Type"] == "Maa":
for user in member["UserData"].values():
- user["Config"].set(user["Config"].Info_Password, "")
+ user["Config"].set(
+ user["Config"].Info_Password, self.AUTO_encryptor("数据已重置")
+ )
def win_encryptor(
self, note: str, description: str = None, entropy: bytes = None
) -> str:
- """使用Windows DPAPI加密数据"""
+ """
+ 使用Windows DPAPI加密数据
+
+ :param note: 数据明文
+ :type note: str
+ :param description: 描述信息
+ :type description: str
+ :param entropy: 随机熵
+ :type entropy: bytes
+ :return: 加密后的数据
+ :rtype: str
+ """
if note == "":
return ""
@@ -192,7 +233,16 @@ class CryptoHandler:
return base64.b64encode(encrypted).decode("utf-8")
def win_decryptor(self, note: str, entropy: bytes = None) -> str:
- """使用Windows DPAPI解密数据"""
+ """
+ 使用Windows DPAPI解密数据
+
+ :param note: 数据密文
+ :type note: str
+ :param entropy: 随机熵
+ :type entropy: bytes
+ :return: 解密后的明文
+ :rtype: str
+ """
if note == "":
return ""
@@ -202,21 +252,15 @@ class CryptoHandler:
)
return decrypted[1].decode("utf-8")
- def search_member(self) -> List[Dict[str, Union[Path, list]]]:
- """搜索所有脚本实例及其用户数据库路径"""
-
- member_list = []
-
- if (Config.app_path / "config/MaaConfig").exists():
- for subdir in (Config.app_path / "config/MaaConfig").iterdir():
- if subdir.is_dir():
-
- member_list.append({"Path": subdir / "user_data.db"})
-
- return member_list
-
def check_PASSWORD(self, PASSWORD: str) -> bool:
- """验证管理密钥"""
+ """
+ 验证管理密钥
+
+ :param PASSWORD: 管理密钥
+ :type PASSWORD: str
+ :return: 是否验证通过
+ :rtype: bool
+ """
return bool(
self.AUTO_decryptor(self.AUTO_encryptor("-"), PASSWORD) != "管理密钥错误"
diff --git a/app/services/skland.py b/app/services/skland.py
index d752662..901a352 100644
--- a/app/services/skland.py
+++ b/app/services/skland.py
@@ -32,7 +32,6 @@ v4.4
作者:DLmaster_361、ClozyA
"""
-from loguru import logger
import time
import json
import hmac
@@ -40,7 +39,7 @@ import hashlib
import requests
from urllib import parse
-from app.core import Config
+from app.core import Config, logger
def skland_sign_in(token) -> dict:
@@ -71,15 +70,16 @@ def skland_sign_in(token) -> dict:
"vName": "1.5.1",
}
- # 生成签名
def generate_signature(token_for_sign: str, path, body_or_query):
"""
生成请求签名
+
:param token_for_sign: 用于加密的token
:param path: 请求路径(如 /api/v1/game/player/binding)
:param body_or_query: GET用query字符串,POST用body字符串
:return: (sign, 新的header_for_sign字典)
"""
+
t = str(int(time.time()) - 2) # 时间戳,-2秒以防服务器时间不一致
token_bytes = token_for_sign.encode("utf-8")
header_ca = dict(header_for_sign)
@@ -91,10 +91,10 @@ def skland_sign_in(token) -> dict:
md5 = hashlib.md5(hex_s.encode("utf-8")).hexdigest()
return md5, header_ca
- # 获取带签名的header
def get_sign_header(url: str, method, body, old_header, sign_token):
"""
获取带签名的请求头
+
:param url: 请求完整url
:param method: 请求方式 GET/POST
:param body: POST请求体或GET时为None
@@ -102,6 +102,7 @@ def skland_sign_in(token) -> dict:
:param sign_token: 当前会话的签名token
:return: 新请求头
"""
+
h = json.loads(json.dumps(old_header))
p = parse.urlparse(url)
if method.lower() == "get":
@@ -115,15 +116,21 @@ def skland_sign_in(token) -> dict:
h[i] = header_ca[i]
return h
- # 复制请求头并添加cred
def copy_header(cred):
+ """
+ 复制请求头并添加cred
+
+ :param cred: 当前会话的cred
+ :return: 新的请求头
+ """
v = json.loads(json.dumps(header))
v["cred"] = cred
return v
- # 使用token一步步拿到cred和sign_token
def login_by_token(token_code):
"""
+ 使用token一步步拿到cred和sign_token
+
:param token_code: 你的skyland token
:return: (cred, sign_token)
"""
@@ -136,8 +143,14 @@ def skland_sign_in(token) -> dict:
grant_code = get_grant_code(token_code)
return get_cred(grant_code)
- # 通过grant code换cred和sign_token
def get_cred(grant):
+ """
+ 通过grant code获取cred和sign_token
+
+ :param grant: grant code
+ :return: (cred, sign_token)
+ """
+
rsp = requests.post(
cred_code_url,
json={"code": grant, "kind": 1},
@@ -153,8 +166,13 @@ def skland_sign_in(token) -> dict:
cred = rsp["data"]["cred"]
return cred, sign_token
- # 通过token换grant code
def get_grant_code(token):
+ """
+ 通过token获取grant code
+
+ :param token: 你的skyland token
+ :return: grant code
+ """
rsp = requests.post(
grant_code_url,
json={"appCode": app_code, "token": token, "type": 0},
@@ -170,10 +188,10 @@ def skland_sign_in(token) -> dict:
)
return rsp["data"]["code"]
- # 获取已绑定的角色列表
def get_binding_list(cred, sign_token):
"""
- 查询绑定的角色
+ 查询已绑定的角色列表
+
:param cred: 当前cred
:param sign_token: 当前sign_token
:return: 角色列表
@@ -190,9 +208,15 @@ def skland_sign_in(token) -> dict:
},
).json()
if rsp["code"] != 0:
- logger.error(f"森空岛服务 | 请求角色列表出现问题:{rsp['message']}")
+ logger.error(
+ f"森空岛服务 | 请求角色列表出现问题:{rsp['message']}",
+ module="森空岛签到",
+ )
if rsp.get("message") == "用户未登录":
- logger.error(f"森空岛服务 | 用户登录可能失效了,请重新登录!")
+ logger.error(
+ f"森空岛服务 | 用户登录可能失效了,请重新登录!",
+ module="森空岛签到",
+ )
return v
# 只取明日方舟(arknights)的绑定账号
for i in rsp["data"]["list"]:
@@ -201,10 +225,10 @@ def skland_sign_in(token) -> dict:
v.extend(i.get("bindingList"))
return v
- # 执行签到
def do_sign(cred, sign_token) -> dict:
"""
对所有绑定的角色进行签到
+
:param cred: 当前cred
:param sign_token: 当前sign_token
:return: 签到结果字典
@@ -257,5 +281,5 @@ def skland_sign_in(token) -> dict:
# 依次签到
return do_sign(cred, sign_token)
except Exception as e:
- logger.error(f"森空岛服务 | 森空岛签到失败: {e}")
+ logger.exception(f"森空岛服务 | 森空岛签到失败: {e}", module="森空岛签到")
return {"成功": [], "重复": [], "失败": [], "总计": 0}
diff --git a/app/services/system.py b/app/services/system.py
index e856061..734cda1 100644
--- a/app/services/system.py
+++ b/app/services/system.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import QApplication
import sys
import ctypes
@@ -38,7 +37,7 @@ import getpass
from datetime import datetime
from pathlib import Path
-from app.core import Config
+from app.core import Config, logger
class _SystemHandler:
@@ -147,9 +146,15 @@ class _SystemHandler:
)
if result.returncode == 0:
- logger.info(f"任务计划程序自启动已创建: {Config.app_path_sys}")
+ logger.success(
+ f"程序自启动任务计划已创建: {Config.app_path_sys}",
+ module="系统服务",
+ )
else:
- logger.error(f"创建任务计划失败: {result.stderr}")
+ logger.error(
+ f"程序自启动任务计划创建失败: {result.stderr}",
+ module="系统服务",
+ )
finally:
# 删除临时文件
@@ -159,7 +164,7 @@ class _SystemHandler:
pass
except Exception as e:
- logger.exception(f"设置任务计划程序自启动失败: {e}")
+ logger.exception(f"程序自启动任务计划创建失败: {e}", module="系统服务")
elif not Config.get(Config.start_IfSelfStart) and self.is_startup():
@@ -174,40 +179,49 @@ class _SystemHandler:
)
if result.returncode == 0:
- logger.info("任务计划程序自启动已删除")
+ logger.success("程序自启动任务计划已删除", module="系统服务")
else:
- logger.error(f"删除任务计划失败: {result.stderr}")
+ logger.error(
+ f"程序自启动任务计划删除失败: {result.stderr}",
+ module="系统服务",
+ )
except Exception as e:
- logger.exception(f"删除任务计划程序自启动失败: {e}")
+ logger.exception(f"程序自启动任务计划删除失败: {e}", module="系统服务")
def set_power(self, mode) -> None:
+ """
+ 执行系统电源操作
+
+ :param mode: 电源操作模式,支持 "NoAction", "Shutdown", "Hibernate", "Sleep", "KillSelf"
+ """
if sys.platform.startswith("win"):
if mode == "NoAction":
- logger.info("不执行系统电源操作")
+ logger.info("不执行系统电源操作", module="系统服务")
elif mode == "Shutdown":
- logger.info("执行关机操作")
+ logger.info("执行关机操作", module="系统服务")
subprocess.run(["shutdown", "/s", "/t", "0"])
elif mode == "Hibernate":
- logger.info("执行休眠操作")
+ logger.info("执行休眠操作", module="系统服务")
subprocess.run(["shutdown", "/h"])
elif mode == "Sleep":
- logger.info("执行睡眠操作")
+ logger.info("执行睡眠操作", module="系统服务")
subprocess.run(
["rundll32.exe", "powrprof.dll,SetSuspendState", "0,1,0"]
)
elif mode == "KillSelf":
+ logger.info("执行退出主程序操作", module="系统服务")
Config.main_window.close()
QApplication.quit()
sys.exit(0)
@@ -216,25 +230,26 @@ class _SystemHandler:
if mode == "NoAction":
- logger.info("不执行系统电源操作")
+ logger.info("不执行系统电源操作", module="系统服务")
elif mode == "Shutdown":
- logger.info("执行关机操作")
+ logger.info("执行关机操作", module="系统服务")
subprocess.run(["shutdown", "-h", "now"])
elif mode == "Hibernate":
- logger.info("执行休眠操作")
+ logger.info("执行休眠操作", module="系统服务")
subprocess.run(["systemctl", "hibernate"])
elif mode == "Sleep":
- logger.info("执行睡眠操作")
+ logger.info("执行睡眠操作", module="系统服务")
subprocess.run(["systemctl", "suspend"])
elif mode == "KillSelf":
+ logger.info("执行退出主程序操作", module="系统服务")
Config.main_window.close()
QApplication.quit()
sys.exit(0)
@@ -252,11 +267,11 @@ class _SystemHandler:
)
return result.returncode == 0
except Exception as e:
- logger.error(f"检查任务计划程序失败: {e}")
+ logger.exception(f"检查任务计划程序失败: {e}", module="系统服务")
return False
def get_window_info(self) -> list:
- """获取当前窗口信息"""
+ """获取当前前台窗口信息"""
def callback(hwnd, window_info):
if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowText(hwnd):
@@ -270,7 +285,13 @@ class _SystemHandler:
return window_info
def kill_process(self, path: Path) -> None:
- """根据路径中止进程"""
+ """
+ 根据路径中止进程
+
+ :param path: 进程路径
+ """
+
+ logger.info(f"开始中止进程: {path}", module="系统服务")
for pid in self.search_pids(path):
killprocess = subprocess.Popen(
@@ -280,8 +301,17 @@ class _SystemHandler:
)
killprocess.wait()
+ logger.success(f"进程已中止: {path}", module="系统服务")
+
def search_pids(self, path: Path) -> list:
- """根据路径查找进程PID"""
+ """
+ 根据路径查找进程PID
+
+ :param path: 进程路径
+ :return: 匹配的进程PID列表
+ """
+
+ logger.info(f"开始查找进程 PID: {path}", module="系统服务")
pids = []
for proc in psutil.process_iter(["pid", "exe"]):
diff --git a/app/ui/dispatch_center.py b/app/ui/dispatch_center.py
index d216411..1d9d531 100644
--- a/app/ui/dispatch_center.py
+++ b/app/ui/dispatch_center.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import (
QWidget,
QVBoxLayout,
@@ -48,7 +47,7 @@ from PySide6.QtGui import QTextCursor
from typing import List, Dict
-from app.core import Config, TaskManager, Task, MainInfoBar, SoundPlayer
+from app.core import Config, TaskManager, Task, MainInfoBar, logger
from .Widget import StatefulItemCard, ComboBoxMessageBox, PivotArea
@@ -59,10 +58,12 @@ class DispatchCenter(QWidget):
self.setObjectName("调度中枢")
+ # 添加任务按钮
self.multi_button = PushButton(FluentIcon.ADD, "添加任务", self)
self.multi_button.setToolTip("添加任务")
self.multi_button.clicked.connect(self.start_multi_task)
+ # 电源动作设置组件
self.power_combox = ComboBox()
self.power_combox.addItem("无动作", userData="NoAction")
self.power_combox.addItem("退出软件", userData="KillSelf")
@@ -72,15 +73,18 @@ class DispatchCenter(QWidget):
self.power_combox.setCurrentText("无动作")
self.power_combox.currentIndexChanged.connect(self.set_power_sign)
+ # 导航栏
self.pivotArea = PivotArea(self)
self.pivot = self.pivotArea.pivot
+ # 导航页面组
self.stackedWidget = QStackedWidget(self)
self.stackedWidget.setContentsMargins(0, 0, 0, 0)
self.stackedWidget.setStyleSheet("background: transparent; border: none;")
self.script_list: Dict[str, DispatchCenter.DispatchBox] = {}
+ # 添加主调度台
dispatch_box = self.DispatchBox("主调度台", self)
self.script_list["主调度台"] = dispatch_box
self.stackedWidget.addWidget(self.script_list["主调度台"])
@@ -91,6 +95,7 @@ class DispatchCenter(QWidget):
icon=FluentIcon.CAFE,
)
+ # 顶栏组合
h_layout = QHBoxLayout()
h_layout.addWidget(self.multi_button)
h_layout.addWidget(self.pivotArea)
@@ -108,7 +113,13 @@ class DispatchCenter(QWidget):
)
def add_board(self, task: Task) -> None:
- """添加一个调度台界面"""
+ """
+ 为任务添加一个调度台界面并绑定信号
+
+ :param task: 任务对象
+ """
+
+ logger.info(f"添加调度台:{task.name}", module="调度中枢")
dispatch_box = self.DispatchBox(task.name, self)
@@ -129,19 +140,36 @@ class DispatchCenter(QWidget):
self.pivot.addItem(routeKey=f"调度台_{task.name}", text=f"调度台 {task.name}")
+ logger.success(f"调度台 {task.name} 添加成功", module="调度中枢")
+
def del_board(self, name: str) -> None:
- """删除指定子界面"""
+ """
+ 删除指定子界面
+
+ :param name: 子界面名称
+ """
+
+ logger.info(f"删除调度台:{name}", module="调度中枢")
self.pivot.setCurrentItem("主调度台")
self.stackedWidget.removeWidget(self.script_list[name])
self.script_list[name].deleteLater()
+ self.script_list.pop(name)
self.pivot.removeWidget(name)
+ logger.success(f"调度台 {name} 删除成功", module="调度中枢")
+
def connect_main_board(self, task: Task) -> None:
- """连接主调度台"""
+ """
+ 将任务连接到主调度台
+
+ :param task: 任务对象
+ """
+
+ logger.info(f"主调度台载入任务:{task.name}", module="调度中枢")
self.script_list["主调度台"].top_bar.Lable.setText(
- f"{task.name} - {task.mode.replace("_主调度台","")}模式"
+ f"{task.name} - {task.mode.replace('_主调度台','')}模式"
)
self.script_list["主调度台"].top_bar.Lable.show()
self.script_list["主调度台"].top_bar.object.hide()
@@ -170,8 +198,17 @@ class DispatchCenter(QWidget):
lambda logs: self.disconnect_main_board(task.name, logs)
)
+ logger.success(f"主调度台成功载入:{task.name} ", module="调度中枢")
+
def disconnect_main_board(self, name: str, logs: list) -> None:
- """断开主调度台"""
+ """
+ 断开主调度台
+
+ :param name: 任务名称
+ :param logs: 任务日志列表
+ """
+
+ logger.info(f"主调度台断开任务:{name}", module="调度中枢")
self.script_list["主调度台"].top_bar.Lable.hide()
self.script_list["主调度台"].top_bar.object.show()
@@ -191,6 +228,8 @@ class DispatchCenter(QWidget):
else:
self.script_list["主调度台"].info.log_text.text.setText("没有任务被执行")
+ logger.success(f"主调度台成功断开:{name}", module="调度中枢")
+
def update_top_bar(self):
"""更新顶栏"""
@@ -253,10 +292,7 @@ class DispatchCenter(QWidget):
self.power_combox.currentIndexChanged.connect(self.set_power_sign)
logger.warning("没有正在运行的任务,无法设置任务完成后动作")
MainInfoBar.push_info_bar(
- "warning",
- "没有正在运行的任务",
- "无法设置任务完成后动作",
- 5000,
+ "warning", "没有正在运行的任务", "无法设置任务完成后动作", 5000
)
else:
@@ -264,7 +300,7 @@ class DispatchCenter(QWidget):
Config.set_power_sign(self.power_combox.currentData())
def start_multi_task(self) -> None:
- """开始任务"""
+ """开始多开任务"""
# 获取所有可用的队列和实例
text_list = []
@@ -300,7 +336,9 @@ class DispatchCenter(QWidget):
if choice.exec() and choice.input[0].currentIndex() != -1:
if choice.input[0].currentData() in Config.running_list:
- logger.warning(f"任务已存在:{choice.input[0].currentData()}")
+ logger.warning(
+ f"任务已存在:{choice.input[0].currentData()}", module="调度中枢"
+ )
MainInfoBar.push_info_bar(
"warning", "任务已存在", choice.input[0].currentData(), 5000
)
@@ -308,7 +346,9 @@ class DispatchCenter(QWidget):
if "调度队列" in choice.input[0].currentData():
- logger.info(f"用户添加任务:{choice.input[0].currentData()}")
+ logger.info(
+ f"用户添加任务:{choice.input[0].currentData()}", module="调度中枢"
+ )
TaskManager.add_task(
"自动代理_新调度台",
choice.input[0].currentData(),
@@ -317,7 +357,9 @@ class DispatchCenter(QWidget):
elif "脚本" in choice.input[0].currentData():
- logger.info(f"用户添加任务:{choice.input[0].currentData()}")
+ logger.info(
+ f"用户添加任务:{choice.input[0].currentData()}", module="调度中枢"
+ )
TaskManager.add_task(
"自动代理_新调度台",
f"自定义队列 - {choice.input[0].currentData()}",
@@ -384,24 +426,26 @@ class DispatchCenter(QWidget):
Layout.addWidget(self.main_button)
def start_main_task(self):
- """开始任务"""
+ """从主调度台开始任务"""
if self.object.currentIndex() == -1:
- logger.warning("未选择调度对象")
+ logger.warning("未选择调度对象", module="调度中枢")
MainInfoBar.push_info_bar(
"warning", "未选择调度对象", "请选择后再开始任务", 5000
)
return None
if self.mode.currentIndex() == -1:
- logger.warning("未选择调度模式")
+ logger.warning("未选择调度模式", module="调度中枢")
MainInfoBar.push_info_bar(
"warning", "未选择调度模式", "请选择后再开始任务", 5000
)
return None
if self.object.currentData() in Config.running_list:
- logger.warning(f"任务已存在:{self.object.currentData()}")
+ logger.warning(
+ f"任务已存在:{self.object.currentData()}", module="调度中枢"
+ )
MainInfoBar.push_info_bar(
"warning", "任务已存在", self.object.currentData(), 5000
)
@@ -413,7 +457,7 @@ class DispatchCenter(QWidget):
== "General"
and self.mode.currentData() == "人工排查"
):
- logger.warning("通用脚本类型不存在人工排查功能")
+ logger.warning("通用脚本类型不存在人工排查功能", module="调度中枢")
MainInfoBar.push_info_bar(
"warning", "不支持的任务", "通用脚本无人工排查功能", 5000
)
@@ -421,7 +465,9 @@ class DispatchCenter(QWidget):
if "调度队列" in self.object.currentData():
- logger.info(f"用户添加任务:{self.object.currentData()}")
+ logger.info(
+ f"用户添加任务:{self.object.currentData()}", module="调度中枢"
+ )
TaskManager.add_task(
f"{self.mode.currentText()}_主调度台",
self.object.currentData(),
@@ -430,7 +476,9 @@ class DispatchCenter(QWidget):
elif "脚本" in self.object.currentData():
- logger.info(f"用户添加任务:{self.object.currentData()}")
+ logger.info(
+ f"用户添加任务:{self.object.currentData()}", module="调度中枢"
+ )
TaskManager.add_task(
f"{self.mode.currentText()}_主调度台",
"自定义队列",
@@ -476,7 +524,11 @@ class DispatchCenter(QWidget):
self.task_cards: List[StatefulItemCard] = []
def create_task(self, task_list: list):
- """创建任务队列"""
+ """
+ 创建任务队列
+
+ :param task_list: 包含任务信息的任务列表
+ """
while self.Layout.count() > 0:
item = self.Layout.takeAt(0)
@@ -495,7 +547,11 @@ class DispatchCenter(QWidget):
self.Layout.addStretch(1)
def update_task(self, task_list: list):
- """更新任务队列"""
+ """
+ 更新任务队列信息
+
+ :param task_list: 包含任务信息的任务列表
+ """
for i in range(len(task_list)):
@@ -514,7 +570,11 @@ class DispatchCenter(QWidget):
self.user_cards: List[StatefulItemCard] = []
def create_user(self, user_list: list):
- """创建用户队列"""
+ """
+ 创建用户队列
+
+ :param user_list: 包含用户信息的用户列表
+ """
while self.Layout.count() > 0:
item = self.Layout.takeAt(0)
@@ -533,7 +593,11 @@ class DispatchCenter(QWidget):
self.Layout.addStretch(1)
def update_user(self, user_list: list):
- """更新用户队列"""
+ """
+ 更新用户队列信息
+
+ :param user_list: 包含用户信息的用户列表
+ """
for i in range(len(user_list)):
diff --git a/app/ui/downloader.py b/app/ui/downloader.py
index ae3aac1..17e7920 100644
--- a/app/ui/downloader.py
+++ b/app/ui/downloader.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
import zipfile
import requests
import subprocess
@@ -46,7 +45,7 @@ from PySide6.QtCore import QThread, Signal, QTimer, QEventLoop
from typing import List, Dict, Union
-from app.core import Config
+from app.core import Config, logger
from app.services import System
@@ -83,6 +82,8 @@ class DownloadProcess(QThread):
self.setObjectName(f"DownloadProcess-{url}-{start_byte}-{end_byte}")
+ logger.info(f"创建下载子线程:{self.objectName()}", module="下载子线程")
+
self.url = url
self.start_byte = start_byte
self.end_byte = end_byte
@@ -97,7 +98,8 @@ class DownloadProcess(QThread):
self.download_path.unlink()
logger.info(
- f"开始下载:{self.url},范围:{self.start_byte}-{self.end_byte},存储地址:{self.download_path}"
+ f"开始下载:{self.url},范围:{self.start_byte}-{self.end_byte},存储地址:{self.download_path}",
+ module="下载子线程",
)
headers = (
@@ -129,13 +131,17 @@ class DownloadProcess(QThread):
self.check_times -= 1
logger.error(
- f"连接失败:{self.url},状态码:{response.status_code},剩余重试次数:{self.check_times}"
+ f"连接失败:{self.url},状态码:{response.status_code},剩余重试次数:{self.check_times}",
+ module="下载子线程",
)
time.sleep(1)
continue
- logger.info(f"连接成功:{self.url},状态码:{response.status_code}")
+ logger.info(
+ f"连接成功:{self.url},状态码:{response.status_code}",
+ module="下载子线程",
+ )
downloaded_size = 0
with self.download_path.open(mode="wb") as f:
@@ -155,13 +161,14 @@ class DownloadProcess(QThread):
if self.download_path.exists():
self.download_path.unlink()
self.accomplish.emit(0)
- logger.info(f"下载中止:{self.url}")
+ logger.info(f"下载中止:{self.url}", module="下载子线程")
else:
self.accomplish.emit(time.time() - start_time)
logger.success(
- f"下载完成:{self.url},实际下载大小:{downloaded_size} 字节,耗时:{time.time() - start_time:.2f} 秒"
+ f"下载完成:{self.url},实际下载大小:{downloaded_size} 字节,耗时:{time.time() - start_time:.2f} 秒",
+ module="下载子线程",
)
break
@@ -172,7 +179,8 @@ class DownloadProcess(QThread):
self.check_times -= 1
logger.exception(
- f"下载出错:{self.url},错误信息:{e},剩余重试次数:{self.check_times}"
+ f"下载出错:{self.url},错误信息:{e},剩余重试次数:{self.check_times}",
+ module="下载子线程",
)
time.sleep(1)
@@ -181,7 +189,7 @@ class DownloadProcess(QThread):
if self.download_path.exists():
self.download_path.unlink()
self.accomplish.emit(0)
- logger.error(f"下载失败:{self.url}")
+ logger.error(f"下载失败:{self.url}", module="下载子线程")
class ZipExtractProcess(QThread):
@@ -195,6 +203,8 @@ class ZipExtractProcess(QThread):
self.setObjectName(f"ZipExtractProcess-{name}")
+ logger.info(f"创建解压子线程:{self.objectName()}", module="解压子线程")
+
self.name = name
self.app_path = app_path
self.download_path = download_path
@@ -204,7 +214,10 @@ class ZipExtractProcess(QThread):
try:
- logger.info(f"开始解压:{self.download_path} 到 {self.app_path}")
+ logger.info(
+ f"开始解压:{self.download_path} 到 {self.app_path}",
+ module="解压子线程",
+ )
while True:
@@ -215,7 +228,10 @@ class ZipExtractProcess(QThread):
with zipfile.ZipFile(self.download_path, "r") as zip_ref:
zip_ref.extractall(self.app_path)
self.accomplish.emit()
- logger.success(f"解压完成:{self.download_path} 到 {self.app_path}")
+ logger.success(
+ f"解压完成:{self.download_path} 到 {self.app_path}",
+ module="解压子线程",
+ )
break
except PermissionError:
if self.name == "AUTO_MAA":
@@ -223,7 +239,10 @@ class ZipExtractProcess(QThread):
System.kill_process(self.app_path / "AUTO_MAA.exe")
else:
self.info.emit(f"解压出错:{self.name}正在运行,正在等待其关闭")
- logger.warning(f"解压出错:{self.name}正在运行,正在等待其关闭")
+ logger.warning(
+ f"解压出错:{self.name}正在运行,正在等待其关闭",
+ module="解压子线程",
+ )
time.sleep(1)
except Exception as e:
@@ -231,7 +250,7 @@ class ZipExtractProcess(QThread):
e = str(e)
e = "\n".join([e[_ : _ + 75] for _ in range(0, len(e), 75)])
self.info.emit(f"解压更新时出错:\n{e}")
- logger.exception(f"解压更新时出错:{e}")
+ logger.exception(f"解压更新时出错:{e}", module="解压子线程")
return None
@@ -277,17 +296,27 @@ class DownloadManager(QDialog):
def run(self) -> None:
+ logger.info(
+ f"开始执行下载任务:{self.name},版本:{version_text(self.version)}",
+ module="下载管理器",
+ )
+
if self.name == "AUTO_MAA":
if self.config["mode"] == "Proxy":
- self.test_speed_task1()
- self.speed_test_accomplish.connect(self.download_task1)
+ self.start_test_speed()
+ self.speed_test_accomplish.connect(self.start_download)
elif self.config["mode"] == "MirrorChyan":
- self.download_task1()
+ self.start_download()
elif self.config["mode"] == "MirrorChyan":
- self.download_task1()
+ self.start_download()
def get_download_url(self, mode: str) -> Union[str, Dict[str, str]]:
- """获取下载链接"""
+ """
+ 生成下载链接
+
+ :param mode: "测速" 或 "下载"
+ :return: 测速模式返回 url 字典,下载模式返回 url 字符串
+ """
url_dict = {}
@@ -362,7 +391,8 @@ class DownloadManager(QDialog):
if response.status_code == 200:
return response.url
- def test_speed_task1(self) -> None:
+ def start_test_speed(self) -> None:
+ """启动测速任务,下载4MB文件以测试下载速度"""
if self.isInterruptionRequested:
return None
@@ -370,7 +400,7 @@ class DownloadManager(QDialog):
url_dict = self.get_download_url("测速")
self.test_speed_result: Dict[str, float] = {}
- logger.info(f"测速链接:{url_dict}")
+ logger.info(f"开始测速任务,链接:{url_dict}", module="下载管理器")
for name, url in url_dict.items():
@@ -387,10 +417,11 @@ class DownloadManager(QDialog):
)
self.test_speed_result[name] = -1
self.download_process_dict[name].accomplish.connect(
- partial(self.test_speed_task2, name)
+ partial(self.check_test_speed, name)
)
-
self.download_process_dict[name].start()
+
+ # 创建防超时定时器,30秒后强制停止测速
timer = QTimer(self)
timer.setSingleShot(True)
timer.timeout.connect(partial(self.kill_speed_test, name))
@@ -401,11 +432,22 @@ class DownloadManager(QDialog):
self.update_progress(0, 1, 0)
def kill_speed_test(self, name: str) -> None:
+ """
+ 强制停止测速任务
+
+ :param name: 测速任务的名称
+ """
if name in self.download_process_dict:
self.download_process_dict[name].requestInterruption()
- def test_speed_task2(self, name: str, t: float) -> None:
+ def check_test_speed(self, name: str, t: float) -> None:
+ """
+ 更新测速子任务wc信息,并检查测速任务是否允许结束
+
+ :param name: 测速任务的名称
+ :param t: 测速任务的耗时
+ """
# 计算下载速度
if self.isInterruptionRequested:
@@ -453,12 +495,13 @@ class DownloadManager(QDialog):
# 保存测速结果
self.config["speed_result"] = self.test_speed_result
- logger.info(f"测速结果:{self.test_speed_result}")
+ logger.success(f"测速完成,结果:{self.test_speed_result}", module="下载管理器")
self.update_info("测速完成!")
self.speed_test_accomplish.emit()
- def download_task1(self) -> None:
+ def start_download(self) -> None:
+ """开始下载任务"""
if self.isInterruptionRequested:
return None
@@ -466,6 +509,8 @@ class DownloadManager(QDialog):
url = self.get_download_url("下载")
self.downloaded_size_list: List[List[int, bool]] = []
+ logger.info(f"开始下载任务,链接:{url}", module="下载管理器")
+
response = requests.head(
url,
timeout=10,
@@ -506,20 +551,27 @@ class DownloadManager(QDialog):
)
self.downloaded_size_list.append([0, False])
self.download_process_dict[f"part{i}"].progress.connect(
- partial(self.download_task2, i)
+ partial(self.update_download, i)
)
self.download_process_dict[f"part{i}"].accomplish.connect(
- partial(self.download_task3, i)
+ partial(self.check_download, i)
)
self.download_process_dict[f"part{i}"].start()
- def download_task2(self, index: str, current: int) -> None:
- """更新下载进度"""
+ def update_download(self, index: str, current: int) -> None:
+ """
+ 更新子任务下载进度,将信息更新到 UI 上
+ :param index: 下载任务的索引
+ :param current: 当前下载大小
+ """
+
+ # 更新指定线程的下载进度
self.downloaded_size_list[index][0] = current
self.downloaded_size = sum([_[0] for _ in self.downloaded_size_list])
self.update_progress(0, self.file_size, self.downloaded_size)
+ # 速度每秒更新一次
if time.time() - self.last_time >= 1.0:
self.speed = (
(self.downloaded_size - self.last_download_size)
@@ -538,7 +590,13 @@ class DownloadManager(QDialog):
f"正在下载:{self.name} 已下载:{self.downloaded_size / 1048576:.2f}/{self.file_size / 1048576:.2f} MB ({self.downloaded_size / self.file_size * 100:.2f}%) 下载速度:{self.speed:.2f} KB/s",
)
- def download_task3(self, index: str, t: float) -> None:
+ def check_download(self, index: str, t: float) -> None:
+ """
+ 更新下载子任务完成信息,检查下载任务是否完成,完成后自动执行后续处理任务
+
+ :param index: 下载任务的索引
+ :param t: 下载任务的耗时
+ """
# 标记下载线程完成
self.downloaded_size_list[index][1] = True
@@ -560,7 +618,8 @@ class DownloadManager(QDialog):
# 合并下载的分段文件
logger.info(
- f"所有分段下载完成:{self.name},开始合并分段文件到 {self.download_path}"
+ f"所有分段下载完成:{self.name},开始合并分段文件到 {self.download_path}",
+ module="下载管理器",
)
with self.download_path.open(mode="wb") as outfile:
for i in range(self.config["thread_numb"]):
@@ -571,7 +630,8 @@ class DownloadManager(QDialog):
self.download_path.with_suffix(f".part{i}").unlink()
logger.success(
- f"合并完成:{self.name},下载文件大小:{self.download_path.stat().st_size} 字节"
+ f"合并完成:{self.name},下载文件大小:{self.download_path.stat().st_size} 字节",
+ module="下载管理器",
)
self.update_info("正在解压更新文件")
@@ -610,9 +670,21 @@ class DownloadManager(QDialog):
self.download_accomplish.emit()
def update_info(self, text: str) -> None:
+ """
+ 更新信息文本
+
+ :param text: 要显示的信息文本
+ """
self.info.setText(text)
def update_progress(self, begin: int, end: int, current: int) -> None:
+ """
+ 更新进度条
+
+ :param begin: 进度条起始值
+ :param end: 进度条结束值
+ :param current: 进度条当前值
+ """
if begin == 0 and end == 0:
self.progress_2.setVisible(False)
@@ -626,7 +698,7 @@ class DownloadManager(QDialog):
def requestInterruption(self) -> None:
"""请求中断下载任务"""
- logger.info("收到下载任务中止请求")
+ logger.info("收到下载任务中止请求", module="下载管理器")
self.isInterruptionRequested = True
diff --git a/app/ui/history.py b/app/ui/history.py
index b253f1d..d0d45b3 100644
--- a/app/ui/history.py
+++ b/app/ui/history.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import (
QWidget,
QVBoxLayout,
@@ -51,11 +50,12 @@ from pathlib import Path
from typing import List, Dict
-from app.core import Config, SoundPlayer
+from app.core import Config, SoundPlayer, logger
from .Widget import StatefulItemCard, QuantifiedItemCard, QuickExpandGroupCard
class History(QWidget):
+ """历史记录界面"""
def __init__(self, parent=None):
super().__init__(parent)
@@ -81,10 +81,21 @@ class History(QWidget):
self.history_card_list = []
def reload_history(self, mode: str, start_date: QDate, end_date: QDate) -> None:
- """加载历史记录界面"""
+ """
+ 加载历史记录界面
+ :param mode: 查询模式
+ :param start_date: 查询范围起始日期
+ :param end_date: 查询范围结束日期
+ """
+
+ logger.info(
+ f"查询历史记录: {mode}, {start_date.toString()}, {end_date.toString()}",
+ module="历史记录",
+ )
SoundPlayer.play("历史记录查询")
+ # 清空已有的历史记录卡片
while self.content_layout.count() > 0:
item = self.content_layout.takeAt(0)
if item.spacerItem():
@@ -100,6 +111,7 @@ class History(QWidget):
datetime(end_date.year(), end_date.month(), end_date.day()),
)
+ # 生成历史记录卡片并添加到布局中
for date, user_dict in history_dict.items():
self.history_card_list.append(self.HistoryCard(date, user_dict, self))
@@ -154,7 +166,13 @@ class History(QWidget):
Layout.addWidget(self.search)
def select_date(self, date: str) -> None:
- """选中最近一段时间并启动查询"""
+ """
+ 选中最近一段时间并启动查询
+
+ :param date: 选择的时间段("week" 或 "month")
+ """
+
+ logger.info(f"选择最近{date}的记录并开始查询", module="历史记录")
server_date = Config.server_date()
if date == "week":
@@ -187,6 +205,7 @@ class History(QWidget):
self.user_history_card_list = []
+ # 生成用户历史记录卡片并添加到布局中
for user, info in user_dict.items():
self.user_history_card_list.append(
self.UserHistoryCard(user, info, self)
@@ -219,7 +238,12 @@ class History(QWidget):
self.update_info("数据总览")
def get_statistics(self, mode: str) -> dict:
- """生成GUI相应结构化统计数据"""
+ """
+ 生成GUI相应结构化统计数据
+
+ :param mode: 查询模式
+ :return: 结构化统计数据
+ """
history_info = Config.merge_statistic_info(
self.user_history if mode == "数据总览" else [Path(mode)]
@@ -244,7 +268,11 @@ class History(QWidget):
return statistics_info
def update_info(self, index: str) -> None:
- """更新信息"""
+ """
+ 更新信息到UI界面
+
+ :param index: 选择的索引
+ """
# 移除已有统计信息UI组件
while self.statistics_card.count() > 0:
@@ -254,8 +282,10 @@ class History(QWidget):
elif item.widget():
item.widget().deleteLater()
+ # 统计信息上传至 UI
if index == "数据总览":
+ # 生成数据统计信息卡片组
for name, item_list in self.get_statistics("数据总览").items():
statistics_card = self.StatisticsCard(name, item_list, self)
@@ -268,10 +298,12 @@ class History(QWidget):
single_history = self.get_statistics(index)
log_path = Path(index).with_suffix(".log")
+ # 生成单个历史记录的统计信息卡片组
for name, item_list in single_history.items():
statistics_card = self.StatisticsCard(name, item_list, self)
self.statistics_card.addWidget(statistics_card)
+ # 显示日志信息并绑定点击事件
with log_path.open("r", encoding="utf-8") as f:
log = f.read()
@@ -291,6 +323,7 @@ class History(QWidget):
self.setMinimumHeight(300)
class IndexCard(HeaderCardWidget):
+ """历史记录索引卡片组"""
index_changed = Signal(str)
@@ -304,9 +337,11 @@ class History(QWidget):
self.index_cards: List[StatefulItemCard] = []
+ # 生成索引卡片信息
index_list = Config.merge_statistic_info(history_list)["index"]
index_list.insert(0, ["数据总览", "运行", "数据总览"])
+ # 生成索引卡片组件并绑定点击事件
for index in index_list:
self.index_cards.append(StatefulItemCard(index[:2]))
@@ -318,6 +353,7 @@ class History(QWidget):
self.Layout.addStretch(1)
class StatisticsCard(HeaderCardWidget):
+ """历史记录统计信息卡片组"""
def __init__(self, name: str, item_list: list, parent=None):
super().__init__(parent)
@@ -340,6 +376,7 @@ class History(QWidget):
self.Layout.addStretch(1)
class LogCard(HeaderCardWidget):
+ """历史记录日志卡片"""
def __init__(self, parent=None):
super().__init__(parent)
diff --git a/app/ui/home.py b/app/ui/home.py
index fa3dba5..0e332f7 100644
--- a/app/ui/home.py
+++ b/app/ui/home.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import (
QWidget,
QVBoxLayout,
@@ -49,7 +48,7 @@ import json
from datetime import datetime
from pathlib import Path
-from app.core import Config, MainInfoBar, Network
+from app.core import Config, MainInfoBar, Network, logger
from .Widget import Banner, IconButton
@@ -160,8 +159,12 @@ class Home(QWidget):
def get_home_image(self) -> None:
"""获取主页图片"""
+ logger.info("获取主页图片", module="主页")
+
if Config.get(Config.function_HomeImageMode) == "默认":
- pass
+
+ logger.info("使用默认主页图片", module="主页")
+
elif Config.get(Config.function_HomeImageMode) == "自定义":
file_path, _ = QFileDialog.getOpenFileName(
@@ -180,7 +183,7 @@ class Home(QWidget):
/ f"resources/images/Home/BannerCustomize{Path(file_path).suffix}",
)
- logger.info(f"自定义主页图片更换成功:{file_path}")
+ logger.info(f"自定义主页图片更换成功:{file_path}", module="主页")
MainInfoBar.push_info_bar(
"success",
"主页图片更换成功",
@@ -189,7 +192,7 @@ class Home(QWidget):
)
else:
- logger.warning("自定义主页图片更换失败:未选择图片文件")
+ logger.warning("自定义主页图片更换失败:未选择图片文件", module="主页")
MainInfoBar.push_info_bar(
"warning",
"主页图片更换失败",
@@ -198,7 +201,7 @@ class Home(QWidget):
)
elif Config.get(Config.function_HomeImageMode) == "主题图像":
- # 从远程服务器获取最新主题图像
+ # 从远程服务器获取最新主题图像信息
network = Network.add_task(
mode="get",
url="https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/theme_image.json",
@@ -209,7 +212,8 @@ class Home(QWidget):
theme_image = network_result["response_json"]
else:
logger.warning(
- f"获取最新主题图像时出错:{network_result['error_message']}"
+ f"获取最新主题图像时出错:{network_result['error_message']}",
+ module="主页",
)
MainInfoBar.push_info_bar(
"warning",
@@ -230,6 +234,7 @@ class Home(QWidget):
else:
time_local = datetime.strptime("2000-01-01 00:00", "%Y-%m-%d %H:%M")
+ # 检查主题图像是否需要更新
if not (
Config.app_path / "resources/images/Home/BannerTheme.jpg"
).exists() or (
@@ -253,7 +258,9 @@ class Home(QWidget):
) as f:
json.dump(theme_image, f, ensure_ascii=False, indent=4)
- logger.success(f"主题图像「{theme_image["name"]}」下载成功")
+ logger.success(
+ f"主题图像「{theme_image["name"]}」下载成功", module="主页"
+ )
MainInfoBar.push_info_bar(
"success",
"主题图像下载成功",
@@ -264,7 +271,8 @@ class Home(QWidget):
else:
logger.warning(
- f"下载最新主题图像时出错:{network_result['error_message']}"
+ f"下载最新主题图像时出错:{network_result['error_message']}",
+ module="主页",
)
MainInfoBar.push_info_bar(
"warning",
@@ -275,18 +283,16 @@ class Home(QWidget):
else:
- logger.info("主题图像已是最新")
+ logger.info("主题图像已是最新", module="主页")
MainInfoBar.push_info_bar(
- "info",
- "主题图像已是最新",
- "主题图像已是最新!",
- 3000,
+ "info", "主题图像已是最新", "主题图像已是最新!", 3000
)
self.set_banner()
def set_banner(self):
"""设置主页图像"""
+
if Config.get(Config.function_HomeImageMode) == "默认":
self.banner.set_banner_image(
str(Config.app_path / "resources/images/Home/BannerDefault.png")
@@ -366,7 +372,7 @@ class ButtonGroup(SimpleCardWidget):
doc_button = IconButton(
FluentIcon.CHAT.icon(color=QColor("#fff")),
tip_title="官方社群",
- tip_content="加入官方群聊【AUTO_MAA绝赞DeBug中!】",
+ tip_content="加入官方群聊「AUTO_MAA绝赞DeBug中!」",
isTooltip=True,
)
doc_button.setIconSize(QSize(32, 32))
diff --git a/app/ui/main_window.py b/app/ui/main_window.py
index 3a97d12..3f37120 100644
--- a/app/ui/main_window.py
+++ b/app/ui/main_window.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import QApplication, QSystemTrayIcon
from qfluentwidgets import (
Action,
@@ -45,7 +44,7 @@ from datetime import datetime, timedelta
import shutil
import darkdetect
-from app.core import Config, TaskManager, MainTimer, MainInfoBar, SoundPlayer
+from app.core import Config, logger, TaskManager, MainTimer, MainInfoBar, SoundPlayer
from app.services import Notify, Crypto, System
from .home import Home
from .member_manager import MemberManager
@@ -57,6 +56,7 @@ from .setting import Setting
class AUTO_MAA(MSFluentWindow):
+ """AUTO_MAA主界面"""
def __init__(self):
super().__init__()
@@ -77,9 +77,11 @@ class AUTO_MAA(MSFluentWindow):
self.splashScreen = SplashScreen(self.windowIcon(), self)
self.show_ui("显示主窗口", if_quick=True)
+ # 设置主窗口的引用,便于各组件访问
Config.main_window = self.window()
- # 创建主窗口
+ # 创建各子窗口
+ logger.info("正在创建各子窗口", module="主窗口")
self.home = Home(self)
self.plan_manager = PlanManager(self)
self.member_manager = MemberManager(self)
@@ -138,8 +140,10 @@ class AUTO_MAA(MSFluentWindow):
NavigationItemPosition.BOTTOM,
)
self.stackedWidget.currentChanged.connect(self.__currentChanged)
+ logger.success("各子窗口创建完成", module="主窗口")
# 创建系统托盘及其菜单
+ logger.info("正在创建系统托盘", module="主窗口")
self.tray = QSystemTrayIcon(
QIcon(str(Config.app_path / "resources/icons/AUTO_MAA.ico")), self
)
@@ -181,9 +185,11 @@ class AUTO_MAA(MSFluentWindow):
# 设置托盘菜单
self.tray.setContextMenu(self.tray_menu)
self.tray.activated.connect(self.on_tray_activated)
+ logger.success("系统托盘创建完成", module="主窗口")
self.set_min_method()
+ # 绑定各组件信号
Config.sub_info_changed.connect(self.member_manager.refresh_dashboard)
Config.power_sign_changed.connect(self.dispatch_center.update_power_sign)
TaskManager.create_gui.connect(self.dispatch_center.add_board)
@@ -205,6 +211,8 @@ class AUTO_MAA(MSFluentWindow):
self.themeListener.systemThemeChanged.connect(self.switch_theme)
self.themeListener.start()
+ logger.success("AUTO_MAA主程序初始化完成", module="主窗口")
+
def switch_theme(self) -> None:
"""切换主题"""
@@ -348,8 +356,10 @@ class AUTO_MAA(MSFluentWindow):
def start_up_task(self) -> None:
"""启动时任务"""
- # 清理旧日志
- self.clean_old_logs()
+ logger.info("开始执行启动时任务", module="主窗口")
+
+ # 清理旧历史记录
+ Config.clean_old_history()
# 清理安装包
if (Config.app_path / "AUTO_MAA-Setup.exe").exists():
@@ -373,6 +383,9 @@ class AUTO_MAA(MSFluentWindow):
self.start_main_task()
+ # 启动定时器
+ MainTimer.start()
+
# 获取公告
self.setting.show_notice(if_first=True)
@@ -420,41 +433,16 @@ class AUTO_MAA(MSFluentWindow):
)
System.set_power("KillSelf")
- def clean_old_logs(self):
- """
- 删除超过用户设定天数的日志文件(基于目录日期)
- """
-
- if Config.get(Config.function_HistoryRetentionTime) == 0:
- logger.info("由于用户设置日志永久保留,跳过日志清理")
- return
-
- deleted_count = 0
-
- for date_folder in (Config.app_path / "history").iterdir():
- if not date_folder.is_dir():
- continue # 只处理日期文件夹
-
- try:
- # 只检查 `YYYY-MM-DD` 格式的文件夹
- folder_date = datetime.strptime(date_folder.name, "%Y-%m-%d")
- if datetime.now() - folder_date > timedelta(
- days=Config.get(Config.function_HistoryRetentionTime)
- ):
- shutil.rmtree(date_folder, ignore_errors=True)
- deleted_count += 1
- logger.info(f"已删除超期日志目录: {date_folder}")
- except ValueError:
- logger.warning(f"非日期格式的目录: {date_folder}")
-
- logger.info(f"清理完成: {deleted_count} 个日期目录")
+ logger.success("启动时任务执行完成", module="主窗口")
def start_main_task(self) -> None:
"""启动主任务"""
+ logger.info("正在启动主任务", module="主窗口")
+
if "调度队列_1" in Config.queue_dict:
- logger.info("自动添加任务:调度队列_1")
+ logger.info("自动添加任务:调度队列_1", module="主窗口")
TaskManager.add_task(
"自动代理_主调度台",
"调度队列_1",
@@ -463,18 +451,22 @@ class AUTO_MAA(MSFluentWindow):
elif "脚本_1" in Config.member_dict:
- logger.info("自动添加任务:脚本_1")
+ logger.info("自动添加任务:脚本_1", module="主窗口")
TaskManager.add_task(
"自动代理_主调度台", "自定义队列", {"Queue": {"Member_1": "脚本_1"}}
)
else:
- logger.warning("启动主任务失败:未找到有效的主任务配置文件")
+ logger.warning(
+ "启动主任务失败:未找到有效的主任务配置文件", module="主窗口"
+ )
MainInfoBar.push_info_bar(
"warning", "启动主任务失败", "「调度队列_1」与「脚本_1」均不存在", -1
)
+ logger.success("主任务启动完成", module="主窗口")
+
def __currentChanged(self, index: int) -> None:
"""切换界面时任务"""
@@ -489,20 +481,18 @@ class AUTO_MAA(MSFluentWindow):
def closeEvent(self, event: QCloseEvent):
"""清理残余进程"""
+ logger.info("保存窗口位置与大小信息", module="主窗口")
self.show_ui("隐藏到托盘", if_quick=True)
# 清理各功能线程
- MainTimer.Timer.stop()
- MainTimer.Timer.deleteLater()
- MainTimer.LongTimer.stop()
- MainTimer.LongTimer.deleteLater()
+ MainTimer.stop()
TaskManager.stop_task("ALL")
# 关闭主题监听
self.themeListener.terminate()
self.themeListener.deleteLater()
- logger.info("AUTO_MAA主程序关闭")
- logger.info("----------------END----------------")
+ logger.info("AUTO_MAA主程序关闭", module="主窗口")
+ logger.info("----------------END----------------", module="主窗口")
event.accept()
diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py
index 13d5f07..3fa4146 100644
--- a/app/ui/member_manager.py
+++ b/app/ui/member_manager.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import (
QWidget,
QFileDialog,
@@ -61,6 +60,7 @@ import json
from app.core import (
Config,
+ logger,
MainInfoBar,
TaskManager,
MaaConfig,
@@ -109,31 +109,22 @@ class MemberManager(QWidget):
layout = QVBoxLayout(self)
self.tools = CommandBar()
-
self.member_manager = self.MemberSettingBox(self)
# 逐个添加动作
self.tools.addActions(
[
+ Action(FluentIcon.ADD_TO, "新建脚本实例", triggered=self.add_member),
Action(
- FluentIcon.ADD_TO, "新建脚本实例", triggered=self.add_setting_box
- ),
- Action(
- FluentIcon.REMOVE_FROM,
- "删除脚本实例",
- triggered=self.del_setting_box,
+ FluentIcon.REMOVE_FROM, "删除脚本实例", triggered=self.del_member
),
]
)
self.tools.addSeparator()
self.tools.addActions(
[
- Action(
- FluentIcon.LEFT_ARROW, "向左移动", triggered=self.left_setting_box
- ),
- Action(
- FluentIcon.RIGHT_ARROW, "向右移动", triggered=self.right_setting_box
- ),
+ Action(FluentIcon.LEFT_ARROW, "向左移动", triggered=self.left_member),
+ Action(FluentIcon.RIGHT_ARROW, "向右移动", triggered=self.right_member),
]
)
self.tools.addSeparator()
@@ -156,7 +147,7 @@ class MemberManager(QWidget):
layout.addWidget(self.tools)
layout.addWidget(self.member_manager)
- def add_setting_box(self):
+ def add_member(self):
"""添加一个脚本实例"""
choice = ComboBoxMessageBox(
@@ -167,10 +158,15 @@ class MemberManager(QWidget):
)
if choice.exec() and choice.input[0].currentIndex() != -1:
+ logger.info(
+ f"添加脚本实例: {choice.input[0].currentText()}", module="脚本管理"
+ )
+
if choice.input[0].currentText() == "MAA":
index = len(Config.member_dict) + 1
+ # 初始化 MAA 配置
maa_config = MaaConfig()
maa_config.load(
Config.app_path / f"config/MaaConfig/脚本_{index}/config.json",
@@ -188,12 +184,13 @@ class MemberManager(QWidget):
"UserData": {},
}
+ # 添加 MAA 实例设置界面
self.member_manager.add_SettingBox(
index, self.MemberSettingBox.MaaSettingBox
)
self.member_manager.switch_SettingBox(index)
- logger.success(f"MAA实例 脚本_{index} 添加成功")
+ logger.success(f"MAA实例 脚本_{index} 添加成功", module="脚本管理")
MainInfoBar.push_info_bar(
"success", "操作成功", f"添加 MAA 实例 脚本_{index}", 3000
)
@@ -203,6 +200,7 @@ class MemberManager(QWidget):
index = len(Config.member_dict) + 1
+ # 初始化通用配置
general_config = GeneralConfig()
general_config.load(
Config.app_path / f"config/GeneralConfig/脚本_{index}/config.json",
@@ -220,31 +218,32 @@ class MemberManager(QWidget):
"SubData": {},
}
+ # 添加通用实例设置界面
self.member_manager.add_SettingBox(
index, self.MemberSettingBox.GeneralSettingBox
)
self.member_manager.switch_SettingBox(index)
- logger.success(f"通用实例 脚本_{index} 添加成功")
+ logger.success(f"通用实例 脚本_{index} 添加成功", module="脚本管理")
MainInfoBar.push_info_bar(
"success", "操作成功", f"添加通用实例 脚本_{index}", 3000
)
SoundPlayer.play("添加脚本实例")
- def del_setting_box(self):
+ def del_member(self):
"""删除一个脚本实例"""
name = self.member_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("删除脚本实例时未选择脚本实例")
+ logger.warning("删除脚本实例时未选择脚本实例", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择脚本实例", "请选择一个脚本实例", 5000
)
return None
if len(Config.running_list) > 0:
- logger.warning("删除脚本实例时调度队列未停止运行")
+ logger.warning("删除脚本实例时调度队列未停止运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000
)
@@ -253,8 +252,11 @@ class MemberManager(QWidget):
choice = MessageBox("确认", f"确定要删除 {name} 实例吗?", self.window())
if choice.exec():
+ logger.info(f"正在删除脚本实例: {name}", module="脚本管理")
+
self.member_manager.clear_SettingBox()
+ # 删除脚本实例的配置文件并同步修改相应配置项
shutil.rmtree(Config.member_dict[name]["Path"])
Config.change_queue(name, "禁用")
for i in range(int(name[3:]) + 1, len(Config.member_dict) + 1):
@@ -266,19 +268,19 @@ class MemberManager(QWidget):
self.member_manager.show_SettingBox(max(int(name[3:]) - 1, 1))
- logger.success(f"脚本实例 {name} 删除成功")
+ logger.success(f"脚本实例 {name} 删除成功", module="脚本管理")
MainInfoBar.push_info_bar(
"success", "操作成功", f"删除脚本实例 {name}", 3000
)
SoundPlayer.play("删除脚本实例")
- def left_setting_box(self):
+ def left_member(self):
"""向左移动脚本实例"""
name = self.member_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("向左移动脚本实例时未选择脚本实例")
+ logger.warning("向左移动脚本实例时未选择脚本实例", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择脚本实例", "请选择一个脚本实例", 5000
)
@@ -287,21 +289,24 @@ class MemberManager(QWidget):
index = int(name[3:])
if index == 1:
- logger.warning("向左移动脚本实例时已到达最左端")
+ logger.warning("向左移动脚本实例时已到达最左端", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "已经是第一个脚本实例", "无法向左移动", 5000
)
return None
if len(Config.running_list) > 0:
- logger.warning("向左移动脚本实例时调度队列未停止运行")
+ logger.warning("向左移动脚本实例时调度队列未停止运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000
)
return None
+ logger.info(f"正在向左移动脚本实例: {name}", module="脚本管理")
+
self.member_manager.clear_SettingBox()
+ # 移动脚本实例配置文件并同步修改配置项
Config.member_dict[name]["Path"].rename(
Config.member_dict[name]["Path"].with_name("脚本_0")
)
@@ -317,16 +322,16 @@ class MemberManager(QWidget):
self.member_manager.show_SettingBox(index - 1)
- logger.success(f"脚本实例 {name} 左移成功")
+ logger.success(f"脚本实例 {name} 左移成功", module="脚本管理")
MainInfoBar.push_info_bar("success", "操作成功", f"左移脚本实例 {name}", 3000)
- def right_setting_box(self):
+ def right_member(self):
"""向右移动脚本实例"""
name = self.member_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("向右移动脚本实例时未选择脚本实例")
+ logger.warning("向右移动脚本实例时未选择脚本实例", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择脚本实例", "请选择一个脚本实例", 5000
)
@@ -335,21 +340,24 @@ class MemberManager(QWidget):
index = int(name[3:])
if index == len(Config.member_dict):
- logger.warning("向右移动脚本实例时已到达最右端")
+ logger.warning("向右移动脚本实例时已到达最右端", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "已经是最后一个脚本实例", "无法向右移动", 5000
)
return None
if len(Config.running_list) > 0:
- logger.warning("向右移动脚本实例时调度队列未停止运行")
+ logger.warning("向右移动脚本实例时调度队列未停止运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000
)
return None
+ logger.info(f"正在向右移动脚本实例: {name}", module="脚本管理")
+
self.member_manager.clear_SettingBox()
+ # 移动脚本实例配置文件并同步修改配置项
Config.member_dict[name]["Path"].rename(
Config.member_dict[name]["Path"].with_name("脚本_0")
)
@@ -365,7 +373,7 @@ class MemberManager(QWidget):
self.member_manager.show_SettingBox(index + 1)
- logger.success(f"脚本实例 {name} 右移成功")
+ logger.success(f"脚本实例 {name} 右移成功", module="脚本管理")
MainInfoBar.push_info_bar("success", "操作成功", f"右移脚本实例 {name}", 3000)
def member_downloader(self):
@@ -373,7 +381,7 @@ class MemberManager(QWidget):
if not Config.get(Config.update_MirrorChyanCDK):
- logger.warning("脚本下载器未设置CDK")
+ logger.warning("脚本下载器未设置CDK", module="脚本管理")
MainInfoBar.push_info_bar(
"warning",
"未设置Mirror酱CDK",
@@ -392,7 +400,10 @@ class MemberManager(QWidget):
if network_result["status_code"] == 200:
apps_info = network_result["response_json"]
else:
- logger.warning(f"获取应用列表时出错:{network_result['error_message']}")
+ logger.warning(
+ f"获取应用列表时出错:{network_result['error_message']}",
+ module="脚本管理",
+ )
MainInfoBar.push_info_bar(
"warning",
"获取应用列表时出错",
@@ -419,7 +430,9 @@ class MemberManager(QWidget):
str(Config.app_path / f"script/{app_rid}"),
)
if not folder:
- logger.warning(f"选择{app_name}下载目录时未选择文件夹")
+ logger.warning(
+ f"选择{app_name}下载目录时未选择文件夹", module="脚本管理"
+ )
MainInfoBar.push_info_bar(
"warning", "警告", f"未选择{app_name}下载目录", 5000
)
@@ -442,7 +455,10 @@ class MemberManager(QWidget):
if app_info["code"] != 0:
- logger.error(f"获取版本信息时出错:{app_info["msg"]}")
+ logger.error(
+ f"获取应用版本信息时出错:{app_info["msg"]}",
+ module="脚本管理",
+ )
error_remark_dict = {
1001: "获取版本信息的URL参数不正确",
@@ -475,7 +491,10 @@ class MemberManager(QWidget):
return None
- logger.warning(f"获取版本信息时出错:{network_result['error_message']}")
+ logger.warning(
+ f"获取版本信息时出错:{network_result['error_message']}",
+ module="脚本管理",
+ )
MainInfoBar.push_info_bar(
"warning",
"获取版本信息时出错",
@@ -484,6 +503,8 @@ class MemberManager(QWidget):
)
return None
+ # 创建下载管理器并开始下载
+ logger.info(f"开始下载{app_name},下载目录:{folder}", module="脚本管理")
self.downloader = DownloadManager(
Path(folder),
app_rid,
@@ -502,6 +523,7 @@ class MemberManager(QWidget):
self.downloader.run()
def show_password(self):
+ """显示或隐藏密码"""
if Config.PASSWORD == "":
choice = LineEditMessageBox(
@@ -529,6 +551,7 @@ class MemberManager(QWidget):
def reload_plan_name(self):
"""刷新计划表名称"""
+ # 生成计划列表信息
plan_list = [
["固定"] + [_ for _ in Config.plan_dict.keys()],
["固定"]
@@ -541,6 +564,8 @@ class MemberManager(QWidget):
for k, v in Config.plan_dict.items()
],
]
+
+ # 刷新所有脚本实例的计划表名称
for member in self.member_manager.script_list:
if isinstance(member, MemberManager.MemberSettingBox.MaaSettingBox):
@@ -616,7 +641,12 @@ class MemberManager(QWidget):
self.show_SettingBox(1)
def show_SettingBox(self, index) -> None:
- """加载所有子界面"""
+ """
+ 加载所有子界面并切换到指定子界面
+
+ :param index: 要切换到的子界面索引
+ :type index: int
+ """
Config.search_member()
@@ -629,7 +659,14 @@ class MemberManager(QWidget):
self.switch_SettingBox(index)
def switch_SettingBox(self, index: int, if_chang_pivot: bool = True) -> None:
- """切换到指定的子界面"""
+ """
+ 切换到指定的子界面
+
+ :param index: 要切换到的子界面索引
+ :type index: int
+ :param if_chang_pivot: 是否更改导航栏的当前项
+ :type if_chang_pivot: bool
+ """
if len(Config.member_dict) == 0:
return None
@@ -666,7 +703,14 @@ class MemberManager(QWidget):
self.pivot.clear()
def add_SettingBox(self, uid: int, type: Type) -> None:
- """添加指定类型设置子界面"""
+ """
+ 添加指定类型设置子界面
+
+ :param uid: 脚本实例的唯一标识符
+ :type uid: int
+ :param type: 要添加的设置子界面类型
+ :type type: Type
+ """
if type == self.MaaSettingBox:
setting_box = self.MaaSettingBox(uid, self)
@@ -762,6 +806,7 @@ class MemberManager(QWidget):
self.viewLayout.addLayout(Layout)
def PathClicked(self):
+ """选择MAA目录并验证"""
folder = QFileDialog.getExistingDirectory(
self,
@@ -769,7 +814,9 @@ class MemberManager(QWidget):
self.config.get(self.config.MaaSet_Path),
)
if not folder or self.config.get(self.config.MaaSet_Path) == folder:
- logger.warning("选择MAA目录时未选择文件夹或未更改文件夹")
+ logger.warning(
+ "选择MAA目录时未选择文件夹或未更改文件夹", module="脚本管理"
+ )
MainInfoBar.push_info_bar(
"warning", "警告", "未选择文件夹或未更改文件夹", 5000
)
@@ -778,7 +825,9 @@ class MemberManager(QWidget):
not (Path(folder) / "config/gui.json").exists()
or not (Path(folder) / "MAA.exe").exists()
):
- logger.warning("选择MAA目录时未找到MAA程序或配置文件")
+ logger.warning(
+ "选择MAA目录时未找到MAA程序或配置文件", module="脚本管理"
+ )
MainInfoBar.push_info_bar(
"warning", "警告", "未找到MAA程序或配置文件", 5000
)
@@ -938,6 +987,9 @@ class MemberManager(QWidget):
index = len(Config.member_dict[self.name]["UserData"]) + 1
+ logger.info(f"正在添加 {self.name} 用户_{index}", module="脚本管理")
+
+ # 初始化用户配置信息
user_config = MaaUserConfig()
user_config.load(
Config.member_dict[self.name]["Path"]
@@ -952,10 +1004,13 @@ class MemberManager(QWidget):
"Config": user_config,
}
+ # 添加用户设置面板
self.user_manager.add_userSettingBox(index)
self.user_manager.switch_SettingBox(f"用户_{index}")
- logger.success(f"{self.name} 用户_{index} 添加成功")
+ logger.success(
+ f"{self.name} 用户_{index} 添加成功", module="脚本管理"
+ )
MainInfoBar.push_info_bar(
"success", "操作成功", f"{self.name} 添加 用户_{index}", 3000
)
@@ -967,20 +1022,20 @@ class MemberManager(QWidget):
name = self.user_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择用户")
+ logger.warning("未选择用户", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择用户", "请先选择一个用户", 5000
)
return None
if name == "用户仪表盘":
- logger.warning("试图删除用户仪表盘")
+ logger.warning("试图删除用户仪表盘", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择用户", "请勿尝试删除用户仪表盘", 5000
)
return None
if self.name in Config.running_list:
- logger.warning("所属脚本正在运行")
+ logger.warning("所属脚本正在运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "所属脚本正在运行", "请先停止任务", 5000
)
@@ -991,8 +1046,11 @@ class MemberManager(QWidget):
)
if choice.exec():
+ logger.info(f"正在删除 {self.name} {name}", module="脚本管理")
+
self.user_manager.clear_SettingBox()
+ # 删除用户配置文件并同步修改相应配置项
shutil.rmtree(
Config.member_dict[self.name]["UserData"][name]["Path"]
)
@@ -1015,7 +1073,9 @@ class MemberManager(QWidget):
f"用户_{max(int(name[3:]) - 1, 1)}"
)
- logger.success(f"{self.name} {name} 删除成功")
+ logger.success(
+ f"{self.name} {name} 删除成功", module="脚本管理"
+ )
MainInfoBar.push_info_bar(
"success", "操作成功", f"{self.name} 删除 {name}", 3000
)
@@ -1027,13 +1087,13 @@ class MemberManager(QWidget):
name = self.user_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择用户")
+ logger.warning("未选择用户", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择用户", "请先选择一个用户", 5000
)
return None
if name == "用户仪表盘":
- logger.warning("试图移动用户仪表盘")
+ logger.warning("试图移动用户仪表盘", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择用户", "请勿尝试移动用户仪表盘", 5000
)
@@ -1042,21 +1102,24 @@ class MemberManager(QWidget):
index = int(name[3:])
if index == 1:
- logger.warning("向前移动用户时已到达最左端")
+ logger.warning("向前移动用户时已到达最左端", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "已经是第一个用户", "无法向前移动", 5000
)
return None
if self.name in Config.running_list:
- logger.warning("所属脚本正在运行")
+ logger.warning("所属脚本正在运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "所属脚本正在运行", "请先停止任务", 5000
)
return None
+ logger.info(f"正在向前移动 {self.name} {name}", module="脚本管理")
+
self.user_manager.clear_SettingBox()
+ # 移动用户配置文件并同步修改配置项
Config.member_dict[self.name]["UserData"][name]["Path"].rename(
Config.member_dict[self.name]["UserData"][name][
"Path"
@@ -1075,7 +1138,7 @@ class MemberManager(QWidget):
self.user_manager.show_SettingBox(f"用户_{index - 1}")
- logger.success(f"{self.name} {name} 前移成功")
+ logger.success(f"{self.name} {name} 前移成功", module="脚本管理")
MainInfoBar.push_info_bar(
"success", "操作成功", f"{self.name} 前移 {name}", 3000
)
@@ -1086,13 +1149,13 @@ class MemberManager(QWidget):
name = self.user_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择用户")
+ logger.warning("未选择用户", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择用户", "请先选择一个用户", 5000
)
return None
if name == "用户仪表盘":
- logger.warning("试图删除用户仪表盘")
+ logger.warning("试图删除用户仪表盘", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择用户", "请勿尝试移动用户仪表盘", 5000
)
@@ -1101,19 +1164,21 @@ class MemberManager(QWidget):
index = int(name[3:])
if index == len(Config.member_dict[self.name]["UserData"]):
- logger.warning("向后移动用户时已到达最右端")
+ logger.warning("向后移动用户时已到达最右端", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "已经是最后一个用户", "无法向后移动", 5000
)
return None
if self.name in Config.running_list:
- logger.warning("所属脚本正在运行")
+ logger.warning("所属脚本正在运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "所属脚本正在运行", "请先停止任务", 5000
)
return None
+ logger.info(f"正在向后移动 {self.name} {name}", module="脚本管理")
+
self.user_manager.clear_SettingBox()
Config.member_dict[self.name]["UserData"][name]["Path"].rename(
@@ -1134,7 +1199,7 @@ class MemberManager(QWidget):
self.user_manager.show_SettingBox(f"用户_{index + 1}")
- logger.success(f"{self.name} {name} 后移成功")
+ logger.success(f"{self.name} {name} 后移成功", module="脚本管理")
MainInfoBar.push_info_bar(
"success", "操作成功", f"{self.name} 后移 {name}", 3000
)
@@ -1180,7 +1245,12 @@ class MemberManager(QWidget):
self.show_SettingBox("用户仪表盘")
def show_SettingBox(self, index: str) -> None:
- """加载所有子界面"""
+ """
+ 加载所有子界面并切换到指定子界面
+
+ :param index: 要切换到的子界面索引或名称
+ :type index: str
+ """
Config.search_maa_user(self.name)
@@ -1192,7 +1262,14 @@ class MemberManager(QWidget):
def switch_SettingBox(
self, index: str, if_change_pivot: bool = True
) -> None:
- """切换到指定的子界面"""
+ """
+ 切换到指定的子界面
+
+ :param index: 要切换到的子界面索引或名称
+ :type index: str
+ :param if_change_pivot: 是否更改导航栏的当前项
+ :type if_change_pivot: bool
+ """
if len(Config.member_dict[self.name]["UserData"]) == 0:
index = "用户仪表盘"
@@ -1214,7 +1291,7 @@ class MemberManager(QWidget):
)
def clear_SettingBox(self) -> None:
- """清空所有子界面"""
+ """清空除用户仪表盘外所有子界面"""
for sub_interface in self.script_list:
Config.stage_refreshed.disconnect(
@@ -1232,7 +1309,12 @@ class MemberManager(QWidget):
self.pivot.addItem(routeKey="用户仪表盘", text="用户仪表盘")
def add_userSettingBox(self, uid: int) -> None:
- """添加一个用户设置界面"""
+ """
+ 添加一个用户设置界面
+
+ :param uid: 用户的唯一标识符
+ :type uid: int
+ """
setting_box = self.UserMemberSettingBox(self.name, uid, self)
@@ -1292,6 +1374,12 @@ class MemberManager(QWidget):
Config.PASSWORD_refreshed.connect(self.load_info)
def load_info(self):
+ """加载用户信息到仪表盘"""
+
+ logger.info(
+ f"正在加载 {self.name} 用户信息到仪表盘",
+ module="脚本管理",
+ )
self.user_data = Config.member_dict[self.name]["UserData"]
@@ -1452,6 +1540,10 @@ class MemberManager(QWidget):
int(name[3:]) - 1, 11, button
)
+ logger.success(
+ f"{self.name} 用户仪表盘成功加载信息", module="脚本管理"
+ )
+
class UserMemberSettingBox(HeaderCardWidget):
"""用户管理子页面"""
@@ -1915,6 +2007,7 @@ class MemberManager(QWidget):
self.switch_infrastructure()
def switch_mode(self) -> None:
+ """切换用户配置模式"""
if self.config.get(self.config.Info_Mode) == "简洁":
@@ -1931,6 +2024,7 @@ class MemberManager(QWidget):
self.card_Routine.setVisible(True)
def switch_stage_mode(self) -> None:
+ """切换关卡配置模式"""
for card, name in zip(
[
@@ -1967,6 +2061,7 @@ class MemberManager(QWidget):
)
def switch_infrastructure(self) -> None:
+ """切换基建配置模式"""
if (
self.config.get(self.config.Info_InfrastMode)
@@ -1988,6 +2083,7 @@ class MemberManager(QWidget):
)
def refresh_stage(self):
+ """刷新关卡配置"""
self.card_Stage.reLoadOptions(
Config.stage_dict["ALL"]["value"],
@@ -2011,6 +2107,7 @@ class MemberManager(QWidget):
)
def refresh_password(self):
+ """刷新密码配置"""
self.card_Password.setValue(
self.card_Password.qconfig.get(
@@ -2054,7 +2151,7 @@ class MemberManager(QWidget):
"""配置MAA子配置"""
if self.name in Config.running_list:
- logger.warning("所属脚本正在运行")
+ logger.warning("所属脚本正在运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "所属脚本正在运行", "请先停止任务", 5000
)
@@ -2463,7 +2560,12 @@ class MemberManager(QWidget):
self.addGroupWidget(widget)
def change_path(self, old_path: Path, new_path: Path) -> None:
- """根据脚本根目录重新计算配置文件路径"""
+ """
+ 根据脚本根目录重新计算配置文件路径
+
+ :param old_path: 旧路径
+ :param new_path: 新路径
+ """
path_list = [
self.config.Script_ScriptPath,
@@ -2491,7 +2593,8 @@ class MemberManager(QWidget):
self.config.set(configItem, str(old_path))
logger.warning(
- f"配置路径 {new_path} 不在脚本根目录下,已重置为 {old_path}"
+ f"配置路径 {new_path} 不在脚本根目录下,已重置为 {old_path}",
+ module="脚本管理",
)
MainInfoBar.push_info_bar(
"warning", "路径异常", "所选路径不在脚本根目录下", 5000
@@ -2738,6 +2841,11 @@ class MemberManager(QWidget):
index = len(Config.member_dict[self.name]["SubData"]) + 1
+ logger.info(
+ f"正在添加 {self.name} 的配置_{index}", module="脚本管理"
+ )
+
+ # 初始化通用配置
sub_config = GeneralSubConfig()
sub_config.load(
Config.member_dict[self.name]["Path"]
@@ -2752,10 +2860,13 @@ class MemberManager(QWidget):
"Config": sub_config,
}
+ # 添加通用配置页面
self.sub_manager.add_SettingBox(index)
self.sub_manager.switch_SettingBox(f"配置_{index}")
- logger.success(f"{self.name} 配置_{index} 添加成功")
+ logger.success(
+ f"{self.name} 配置_{index} 添加成功", module="脚本管理"
+ )
MainInfoBar.push_info_bar(
"success", "操作成功", f"{self.name} 添加 配置_{index}", 3000
)
@@ -2767,20 +2878,20 @@ class MemberManager(QWidget):
name = self.sub_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择配置")
+ logger.warning("未选择配置", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择配置", "请先选择一个配置", 5000
)
return None
if name == "配置仪表盘":
- logger.warning("试图删除配置仪表盘")
+ logger.warning("试图删除配置仪表盘", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择配置", "请勿尝试删除配置仪表盘", 5000
)
return None
if self.name in Config.running_list:
- logger.warning("所属脚本正在运行")
+ logger.warning("所属脚本正在运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "所属脚本正在运行", "请先停止任务", 5000
)
@@ -2791,8 +2902,13 @@ class MemberManager(QWidget):
)
if choice.exec():
+ logger.info(
+ f"正在删除 {self.name} 的配置_{name}", module="脚本管理"
+ )
+
self.sub_manager.clear_SettingBox()
+ # 删除配置文件并同步到相关配置项
shutil.rmtree(
Config.member_dict[self.name]["SubData"][name]["Path"]
)
@@ -2815,7 +2931,9 @@ class MemberManager(QWidget):
f"配置_{max(int(name[3:]) - 1, 1)}"
)
- logger.success(f"{self.name} {name} 删除成功")
+ logger.success(
+ f"{self.name} {name} 删除成功", module="脚本管理"
+ )
MainInfoBar.push_info_bar(
"success", "操作成功", f"{self.name} 删除 {name}", 3000
)
@@ -2827,13 +2945,13 @@ class MemberManager(QWidget):
name = self.sub_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择配置")
+ logger.warning("未选择配置", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择配置", "请先选择一个配置", 5000
)
return None
if name == "配置仪表盘":
- logger.warning("试图移动配置仪表盘")
+ logger.warning("试图移动配置仪表盘", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择配置", "请勿尝试移动配置仪表盘", 5000
)
@@ -2842,21 +2960,26 @@ class MemberManager(QWidget):
index = int(name[3:])
if index == 1:
- logger.warning("向前移动配置时已到达最左端")
+ logger.warning("向前移动配置时已到达最左端", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "已经是第一个配置", "无法向前移动", 5000
)
return None
if self.name in Config.running_list:
- logger.warning("所属脚本正在运行")
+ logger.warning("所属脚本正在运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "所属脚本正在运行", "请先停止任务", 5000
)
return None
+ logger.info(
+ f"正在将 {self.name} 的配置_{name} 前移", module="脚本管理"
+ )
+
self.sub_manager.clear_SettingBox()
+ # 移动配置文件并同步到相关配置项
Config.member_dict[self.name]["SubData"][name]["Path"].rename(
Config.member_dict[self.name]["SubData"][name][
"Path"
@@ -2875,7 +2998,7 @@ class MemberManager(QWidget):
self.sub_manager.show_SettingBox(f"配置_{index - 1}")
- logger.success(f"{self.name} {name} 前移成功")
+ logger.success(f"{self.name} {name} 前移成功", module="脚本管理")
MainInfoBar.push_info_bar(
"success", "操作成功", f"{self.name} 前移 {name}", 3000
)
@@ -2886,13 +3009,13 @@ class MemberManager(QWidget):
name = self.sub_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择配置")
+ logger.warning("未选择配置", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择配置", "请先选择一个配置", 5000
)
return None
if name == "配置仪表盘":
- logger.warning("试图删除配置仪表盘")
+ logger.warning("试图删除配置仪表盘", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "未选择配置", "请勿尝试移动配置仪表盘", 5000
)
@@ -2901,21 +3024,26 @@ class MemberManager(QWidget):
index = int(name[3:])
if index == len(Config.member_dict[self.name]["SubData"]):
- logger.warning("向后移动配置时已到达最右端")
+ logger.warning("向后移动配置时已到达最右端", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "已经是最后一个配置", "无法向后移动", 5000
)
return None
if self.name in Config.running_list:
- logger.warning("所属脚本正在运行")
+ logger.warning("所属脚本正在运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "所属脚本正在运行", "请先停止任务", 5000
)
return None
+ logger.info(
+ f"正在将 {self.name} 的配置_{name} 后移", module="脚本管理"
+ )
+
self.sub_manager.clear_SettingBox()
+ # 移动配置文件并同步到相关配置项
Config.member_dict[self.name]["SubData"][name]["Path"].rename(
Config.member_dict[self.name]["SubData"][name][
"Path"
@@ -2934,7 +3062,7 @@ class MemberManager(QWidget):
self.sub_manager.show_SettingBox(f"配置_{index + 1}")
- logger.success(f"{self.name} {name} 后移成功")
+ logger.success(f"{self.name} {name} 后移成功", module="脚本管理")
MainInfoBar.push_info_bar(
"success", "操作成功", f"{self.name} 后移 {name}", 3000
)
@@ -2980,7 +3108,11 @@ class MemberManager(QWidget):
self.show_SettingBox("配置仪表盘")
def show_SettingBox(self, index: str) -> None:
- """加载所有子界面"""
+ """
+ 加载所有子界面
+
+ :param index: 要显示的子界面索引
+ """
Config.search_general_sub(self.name)
@@ -2992,7 +3124,12 @@ class MemberManager(QWidget):
def switch_SettingBox(
self, index: str, if_change_pivot: bool = True
) -> None:
- """切换到指定的子界面"""
+ """
+ 切换到指定的子界面
+
+ :param index: 要切换到的子界面索引
+ :param if_change_pivot: 是否更改 pivot 的当前项
+ """
if len(Config.member_dict[self.name]["SubData"]) == 0:
index = "配置仪表盘"
@@ -3026,7 +3163,11 @@ class MemberManager(QWidget):
self.pivot.addItem(routeKey="配置仪表盘", text="配置仪表盘")
def add_SettingBox(self, uid: int) -> None:
- """添加一个配置设置界面"""
+ """
+ 添加一个配置设置界面
+
+ :param uid: 配置的唯一标识符
+ """
setting_box = self.SubMemberSettingBox(self.name, uid, self)
@@ -3073,6 +3214,12 @@ class MemberManager(QWidget):
Config.PASSWORD_refreshed.connect(self.load_info)
def load_info(self):
+ """加载配置仪表盘信息"""
+
+ logger.info(
+ f"正在加载 {self.name} 的配置仪表盘信息",
+ module="脚本管理",
+ )
self.sub_data = Config.member_dict[self.name]["SubData"]
@@ -3127,6 +3274,10 @@ class MemberManager(QWidget):
int(name[3:]) - 1, 4, button
)
+ logger.success(
+ f"{self.name} 配置仪表盘信息加载成功", module="脚本管理"
+ )
+
class SubMemberSettingBox(HeaderCardWidget):
"""配置管理子页面"""
@@ -3302,7 +3453,7 @@ class MemberManager(QWidget):
"""配置子配置"""
if self.name in Config.running_list:
- logger.warning("所属脚本正在运行")
+ logger.warning("所属脚本正在运行", module="脚本管理")
MainInfoBar.push_info_bar(
"warning", "所属脚本正在运行", "请先停止任务", 5000
)
diff --git a/app/ui/plan_manager.py b/app/ui/plan_manager.py
index 5c6c84d..3ee8cc0 100644
--- a/app/ui/plan_manager.py
+++ b/app/ui/plan_manager.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import (
QWidget,
QVBoxLayout,
@@ -43,7 +42,7 @@ from qfluentwidgets import (
from typing import List, Dict, Union
import shutil
-from app.core import Config, MainInfoBar, MaaPlanConfig, SoundPlayer
+from app.core import Config, MainInfoBar, MaaPlanConfig, SoundPlayer, logger
from .Widget import (
ComboBoxMessageBox,
LineEditSettingCard,
@@ -66,27 +65,20 @@ class PlanManager(QWidget):
layout = QVBoxLayout(self)
self.tools = CommandBar()
-
self.plan_manager = self.PlanSettingBox(self)
# 逐个添加动作
self.tools.addActions(
[
- Action(FluentIcon.ADD_TO, "新建计划表", triggered=self.add_setting_box),
- Action(
- FluentIcon.REMOVE_FROM, "删除计划表", triggered=self.del_setting_box
- ),
+ Action(FluentIcon.ADD_TO, "新建计划表", triggered=self.add_plan),
+ Action(FluentIcon.REMOVE_FROM, "删除计划表", triggered=self.del_plan),
]
)
self.tools.addSeparator()
self.tools.addActions(
[
- Action(
- FluentIcon.LEFT_ARROW, "向左移动", triggered=self.left_setting_box
- ),
- Action(
- FluentIcon.RIGHT_ARROW, "向右移动", triggered=self.right_setting_box
- ),
+ Action(FluentIcon.LEFT_ARROW, "向左移动", triggered=self.left_plan),
+ Action(FluentIcon.RIGHT_ARROW, "向右移动", triggered=self.right_plan),
]
)
self.tools.addSeparator()
@@ -94,7 +86,7 @@ class PlanManager(QWidget):
layout.addWidget(self.tools)
layout.addWidget(self.plan_manager)
- def add_setting_box(self):
+ def add_plan(self):
"""添加一个计划表"""
choice = ComboBoxMessageBox(
@@ -109,6 +101,7 @@ class PlanManager(QWidget):
index = len(Config.plan_dict) + 1
+ # 初始化 MaaPlanConfig
maa_plan_config = MaaPlanConfig()
maa_plan_config.load(
Config.app_path / f"config/MaaPlanConfig/计划_{index}/config.json",
@@ -122,29 +115,30 @@ class PlanManager(QWidget):
"Config": maa_plan_config,
}
+ # 添加计划表到界面
self.plan_manager.add_MaaPlanSettingBox(index)
self.plan_manager.switch_SettingBox(index)
- logger.success(f"计划管理 计划_{index} 添加成功")
+ logger.success(f"计划管理 计划_{index} 添加成功", module="计划管理")
MainInfoBar.push_info_bar(
"success", "操作成功", f"添加计划表 计划_{index}", 3000
)
SoundPlayer.play("添加计划表")
- def del_setting_box(self):
+ def del_plan(self):
"""删除一个计划表"""
name = self.plan_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("删除计划表时未选择计划表")
+ logger.warning("删除计划表时未选择计划表", module="计划管理")
MainInfoBar.push_info_bar(
"warning", "未选择计划表", "请选择一个计划表", 5000
)
return None
if len(Config.running_list) > 0:
- logger.warning("删除计划表时调度队列未停止运行")
+ logger.warning("删除计划表时调度队列未停止运行", module="计划管理")
MainInfoBar.push_info_bar(
"warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000
)
@@ -153,8 +147,11 @@ class PlanManager(QWidget):
choice = MessageBox("确认", f"确定要删除 {name} 吗?", self.window())
if choice.exec():
+ logger.info(f"正在删除计划表 {name}", module="计划管理")
+
self.plan_manager.clear_SettingBox()
+ # 删除计划表配置文件并同步到相关配置项
shutil.rmtree(Config.plan_dict[name]["Path"])
Config.change_plan(name, "固定")
for i in range(int(name[3:]) + 1, len(Config.plan_dict) + 1):
@@ -166,17 +163,17 @@ class PlanManager(QWidget):
self.plan_manager.show_SettingBox(max(int(name[3:]) - 1, 1))
- logger.success(f"计划表 {name} 删除成功")
+ logger.success(f"计划表 {name} 删除成功", module="计划管理")
MainInfoBar.push_info_bar("success", "操作成功", f"删除计划表 {name}", 3000)
SoundPlayer.play("删除计划表")
- def left_setting_box(self):
+ def left_plan(self):
"""向左移动计划表"""
name = self.plan_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("向左移动计划表时未选择计划表")
+ logger.warning("向左移动计划表时未选择计划表", module="计划管理")
MainInfoBar.push_info_bar(
"warning", "未选择计划表", "请选择一个计划表", 5000
)
@@ -185,21 +182,24 @@ class PlanManager(QWidget):
index = int(name[3:])
if index == 1:
- logger.warning("向左移动计划表时已到达最左端")
+ logger.warning("向左移动计划表时已到达最左端", module="计划管理")
MainInfoBar.push_info_bar(
"warning", "已经是第一个计划表", "无法向左移动", 5000
)
return None
if len(Config.running_list) > 0:
- logger.warning("向左移动计划表时调度队列未停止运行")
+ logger.warning("向左移动计划表时调度队列未停止运行", module="计划管理")
MainInfoBar.push_info_bar(
"warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000
)
return None
+ logger.info(f"正在左移计划表 {name}", module="计划管理")
+
self.plan_manager.clear_SettingBox()
+ # 移动配置文件并同步到相关配置项
Config.plan_dict[name]["Path"].rename(
Config.plan_dict[name]["Path"].with_name("计划_0")
)
@@ -215,16 +215,16 @@ class PlanManager(QWidget):
self.plan_manager.show_SettingBox(index - 1)
- logger.success(f"计划表 {name} 左移成功")
+ logger.success(f"计划表 {name} 左移成功", module="计划管理")
MainInfoBar.push_info_bar("success", "操作成功", f"左移计划表 {name}", 3000)
- def right_setting_box(self):
+ def right_plan(self):
"""向右移动计划表"""
name = self.plan_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("向右移动计划表时未选择计划表")
+ logger.warning("向右移动计划表时未选择计划表", module="计划管理")
MainInfoBar.push_info_bar(
"warning", "未选择计划表", "请选择一个计划表", 5000
)
@@ -233,21 +233,24 @@ class PlanManager(QWidget):
index = int(name[3:])
if index == len(Config.plan_dict):
- logger.warning("向右移动计划表时已到达最右端")
+ logger.warning("向右移动计划表时已到达最右端", module="计划管理")
MainInfoBar.push_info_bar(
"warning", "已经是最后一个计划表", "无法向右移动", 5000
)
return None
if len(Config.running_list) > 0:
- logger.warning("向右移动计划表时调度队列未停止运行")
+ logger.warning("向右移动计划表时调度队列未停止运行", module="计划管理")
MainInfoBar.push_info_bar(
"warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000
)
return None
+ logger.info(f"正在右移计划表 {name}", module="计划管理")
+
self.plan_manager.clear_SettingBox()
+ # 移动配置文件并同步到相关配置项
Config.plan_dict[name]["Path"].rename(
Config.plan_dict[name]["Path"].with_name("计划_0")
)
@@ -263,7 +266,7 @@ class PlanManager(QWidget):
self.plan_manager.show_SettingBox(index + 1)
- logger.success(f"计划表 {name} 右移成功")
+ logger.success(f"计划表 {name} 右移成功", module="计划管理")
MainInfoBar.push_info_bar("success", "操作成功", f"右移计划表 {name}", 3000)
class PlanSettingBox(QWidget):
@@ -297,7 +300,11 @@ class PlanManager(QWidget):
self.show_SettingBox(1)
def show_SettingBox(self, index) -> None:
- """加载所有子界面"""
+ """
+ 加载所有子界面并切换到指定的子界面
+
+ :param index: 要显示的子界面索引
+ """
Config.search_plan()
@@ -308,7 +315,12 @@ class PlanManager(QWidget):
self.switch_SettingBox(index)
def switch_SettingBox(self, index: int, if_chang_pivot: bool = True) -> None:
- """切换到指定的子界面"""
+ """
+ 切换到指定的子界面
+
+ :param index: 要切换到的子界面索引
+ :param if_chang_pivot: 是否更改 pivot 的当前项
+ """
if len(Config.plan_dict) == 0:
return None
@@ -331,7 +343,11 @@ class PlanManager(QWidget):
self.pivot.clear()
def add_MaaPlanSettingBox(self, uid: int) -> None:
- """添加一个MAA设置界面"""
+ """
+ 添加一个MAA设置界面
+
+ :param uid: MAA计划表的唯一标识符
+ """
maa_plan_setting_box = self.MaaPlanSettingBox(uid, self)
@@ -475,6 +491,7 @@ class PlanManager(QWidget):
)
def refresh_stage(self):
+ """刷新关卡列表"""
for group, name_dict in self.item_dict.items():
diff --git a/app/ui/queue_manager.py b/app/ui/queue_manager.py
index 303edda..a022abd 100644
--- a/app/ui/queue_manager.py
+++ b/app/ui/queue_manager.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import (
QWidget,
QVBoxLayout,
@@ -42,7 +41,7 @@ from qfluentwidgets import (
)
from typing import List
-from app.core import QueueConfig, Config, MainInfoBar, SoundPlayer
+from app.core import QueueConfig, Config, MainInfoBar, SoundPlayer, logger
from .Widget import (
SwitchSettingCard,
ComboBoxSettingCard,
@@ -70,36 +69,31 @@ class QueueManager(QWidget):
# 逐个添加动作
self.tools.addActions(
[
+ Action(FluentIcon.ADD_TO, "新建调度队列", triggered=self.add_queue),
Action(
- FluentIcon.ADD_TO, "新建调度队列", triggered=self.add_setting_box
- ),
- Action(
- FluentIcon.REMOVE_FROM,
- "删除调度队列",
- triggered=self.del_setting_box,
+ FluentIcon.REMOVE_FROM, "删除调度队列", triggered=self.del_queue
),
]
)
self.tools.addSeparator()
self.tools.addActions(
[
- Action(
- FluentIcon.LEFT_ARROW, "向左移动", triggered=self.left_setting_box
- ),
- Action(
- FluentIcon.RIGHT_ARROW, "向右移动", triggered=self.right_setting_box
- ),
+ Action(FluentIcon.LEFT_ARROW, "向左移动", triggered=self.left_queue),
+ Action(FluentIcon.RIGHT_ARROW, "向右移动", triggered=self.right_queue),
]
)
layout.addWidget(self.tools)
layout.addWidget(self.queue_manager)
- def add_setting_box(self):
+ def add_queue(self):
"""添加一个调度队列"""
index = len(Config.queue_dict) + 1
+ logger.info(f"正在添加调度队列_{index}", module="队列管理")
+
+ # 初始化队列配置
queue_config = QueueConfig()
queue_config.load(
Config.app_path / f"config/QueueConfig/调度队列_{index}.json", queue_config
@@ -111,27 +105,28 @@ class QueueManager(QWidget):
"Config": queue_config,
}
+ # 添加到配置界面
self.queue_manager.add_SettingBox(index)
self.queue_manager.switch_SettingBox(index)
- logger.success(f"调度队列_{index} 添加成功")
+ logger.success(f"调度队列_{index} 添加成功", module="队列管理")
MainInfoBar.push_info_bar("success", "操作成功", f"添加 调度队列_{index}", 3000)
SoundPlayer.play("添加调度队列")
- def del_setting_box(self):
+ def del_queue(self):
"""删除一个调度队列实例"""
name = self.queue_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择调度队列")
+ logger.warning("未选择调度队列", module="队列管理")
MainInfoBar.push_info_bar(
"warning", "未选择调度队列", "请先选择一个调度队列", 5000
)
return None
if name in Config.running_list:
- logger.warning("调度队列正在运行")
+ logger.warning("调度队列正在运行", module="队列管理")
MainInfoBar.push_info_bar(
"warning", "调度队列正在运行", "请先停止调度队列", 5000
)
@@ -140,8 +135,11 @@ class QueueManager(QWidget):
choice = MessageBox("确认", f"确定要删除 {name} 吗?", self.window())
if choice.exec():
+ logger.info(f"正在删除调度队列 {name}", module="队列管理")
+
self.queue_manager.clear_SettingBox()
+ # 删除队列配置文件并同步到相关配置项
Config.queue_dict[name]["Path"].unlink()
for i in range(int(name[5:]) + 1, len(Config.queue_dict) + 1):
if Config.queue_dict[f"调度队列_{i}"]["Path"].exists():
@@ -153,17 +151,17 @@ class QueueManager(QWidget):
self.queue_manager.show_SettingBox(max(int(name[5:]) - 1, 1))
- logger.success(f"{name} 删除成功")
+ logger.success(f"{name} 删除成功", module="队列管理")
MainInfoBar.push_info_bar("success", "操作成功", f"删除 {name}", 3000)
SoundPlayer.play("删除调度队列")
- def left_setting_box(self):
+ def left_queue(self):
"""向左移动调度队列实例"""
name = self.queue_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择调度队列")
+ logger.warning("未选择调度队列", module="队列管理")
MainInfoBar.push_info_bar(
"warning", "未选择调度队列", "请先选择一个调度队列", 5000
)
@@ -172,21 +170,24 @@ class QueueManager(QWidget):
index = int(name[5:])
if index == 1:
- logger.warning("向左移动调度队列时已到达最左端")
+ logger.warning("向左移动调度队列时已到达最左端", module="队列管理")
MainInfoBar.push_info_bar(
"warning", "已经是第一个调度队列", "无法向左移动", 5000
)
return None
if name in Config.running_list or f"调度队列_{index-1}" in Config.running_list:
- logger.warning("相关调度队列正在运行")
+ logger.warning("相关调度队列正在运行", module="队列管理")
MainInfoBar.push_info_bar(
"warning", "相关调度队列正在运行", "请先停止调度队列", 5000
)
return None
+ logger.info(f"正在左移调度队列 {name}", module="队列管理")
+
self.queue_manager.clear_SettingBox()
+ # 移动配置文件并同步到相关配置项
Config.queue_dict[name]["Path"].rename(
Config.queue_dict[name]["Path"].with_name("调度队列_0.json")
)
@@ -199,16 +200,16 @@ class QueueManager(QWidget):
self.queue_manager.show_SettingBox(index - 1)
- logger.success(f"{name} 左移成功")
+ logger.success(f"{name} 左移成功", module="队列管理")
MainInfoBar.push_info_bar("success", "操作成功", f"左移 {name}", 3000)
- def right_setting_box(self):
+ def right_queue(self):
"""向右移动调度队列实例"""
name = self.queue_manager.pivot.currentRouteKey()
if name is None:
- logger.warning("未选择调度队列")
+ logger.warning("未选择调度队列", module="队列管理")
MainInfoBar.push_info_bar(
"warning", "未选择调度队列", "请先选择一个调度队列", 5000
)
@@ -217,21 +218,24 @@ class QueueManager(QWidget):
index = int(name[5:])
if index == len(Config.queue_dict):
- logger.warning("向右移动调度队列时已到达最右端")
+ logger.warning("向右移动调度队列时已到达最右端", module="队列管理")
MainInfoBar.push_info_bar(
"warning", "已经是最后一个调度队列", "无法向右移动", 5000
)
return None
if name in Config.running_list or f"调度队列_{index+1}" in Config.running_list:
- logger.warning("相关调度队列正在运行")
+ logger.warning("相关调度队列正在运行", module="队列管理")
MainInfoBar.push_info_bar(
"warning", "相关调度队列正在运行", "请先停止调度队列", 5000
)
return None
+ logger.info(f"正在右移调度队列 {name}", module="队列管理")
+
self.queue_manager.clear_SettingBox()
+ # 移动配置文件并同步到相关配置项
Config.queue_dict[name]["Path"].rename(
Config.queue_dict[name]["Path"].with_name("调度队列_0.json")
)
@@ -244,12 +248,13 @@ class QueueManager(QWidget):
self.queue_manager.show_SettingBox(index + 1)
- logger.success(f"{name} 右移成功")
+ logger.success(f"{name} 右移成功", module="队列管理")
MainInfoBar.push_info_bar("success", "操作成功", f"右移 {name}", 3000)
def reload_member_name(self):
"""刷新调度队列成员"""
+ # 获取成员列表
member_list = [
["禁用"] + [_ for _ in Config.member_dict.keys()],
["未启用"]
@@ -337,7 +342,12 @@ class QueueManager(QWidget):
self.switch_SettingBox(index)
def switch_SettingBox(self, index: int, if_change_pivot: bool = True) -> None:
- """切换到指定的子界面"""
+ """
+ 切换到指定的子界面并切换到指定的子页面
+
+ :param index: 要切换到的子界面索引
+ :param if_change_pivot: 是否更改导航栏当前项
+ """
if len(Config.queue_dict) == 0:
return None
diff --git a/app/ui/setting.py b/app/ui/setting.py
index 71c35c7..cada615 100644
--- a/app/ui/setting.py
+++ b/app/ui/setting.py
@@ -25,7 +25,6 @@ v4.4
作者:DLmaster_361
"""
-from loguru import logger
from PySide6.QtWidgets import QWidget, QVBoxLayout
from PySide6.QtGui import QIcon
from PySide6.QtCore import Qt
@@ -49,7 +48,7 @@ from packaging import version
from pathlib import Path
from typing import Dict, Union
-from app.core import Config, MainInfoBar, Network, SoundPlayer
+from app.core import Config, MainInfoBar, Network, SoundPlayer, logger
from app.services import Crypto, System, Notify
from .downloader import DownloadManager
from .Widget import (
@@ -124,7 +123,7 @@ class Setting(QWidget):
self.window(),
)
if choice.exec():
- logger.success("确认授权bilibili游戏隐私政策")
+ logger.success("确认授权bilibili游戏隐私政策", module="设置界面")
MainInfoBar.push_info_bar(
"success", "操作成功", "已确认授权bilibili游戏隐私政策", 3000
)
@@ -132,7 +131,7 @@ class Setting(QWidget):
Config.set(Config.function_IfAgreeBilibili, False)
else:
- logger.info("取消授权bilibili游戏隐私政策")
+ logger.info("取消授权bilibili游戏隐私政策", module="设置界面")
MainInfoBar.push_info_bar(
"info", "操作成功", "已取消授权bilibili游戏隐私政策", 3000
)
@@ -158,7 +157,7 @@ class Setting(QWidget):
MuMu_splash_ads_path.touch()
- logger.success("开启跳过MuMu启动广告功能")
+ logger.success("开启跳过MuMu启动广告功能", module="设置界面")
MainInfoBar.push_info_bar(
"success", "操作成功", "已开启跳过MuMu启动广告功能", 3000
)
@@ -170,7 +169,7 @@ class Setting(QWidget):
if MuMu_splash_ads_path.exists() and MuMu_splash_ads_path.is_file():
MuMu_splash_ads_path.unlink()
- logger.info("关闭跳过MuMu启动广告功能")
+ logger.info("关闭跳过MuMu启动广告功能", module="设置界面")
MainInfoBar.push_info_bar(
"info", "操作成功", "已关闭跳过MuMu启动广告功能", 3000
)
@@ -181,6 +180,8 @@ class Setting(QWidget):
if Config.key_path.exists():
return None
+ logger.info("未设置管理密钥,开始要求用户进行设置", module="设置界面")
+
while True:
choice = LineEditMessageBox(
@@ -188,6 +189,7 @@ class Setting(QWidget):
)
if choice.exec() and choice.input.text() != "":
Crypto.get_PASSWORD(choice.input.text())
+ logger.success("成功设置管理密钥", module="设置界面")
break
else:
choice = MessageBox(
@@ -207,10 +209,7 @@ class Setting(QWidget):
while if_change:
choice = LineEditMessageBox(
- self.window(),
- "请输入旧的管理密钥",
- "旧管理密钥",
- "密码",
+ self.window(), "请输入旧的管理密钥", "旧管理密钥", "密码"
)
if choice.exec() and choice.input.text() != "":
@@ -231,6 +230,7 @@ class Setting(QWidget):
# 修改管理密钥
Crypto.change_PASSWORD(PASSWORD_old, choice.input.text())
+ logger.success("成功修改管理密钥", module="设置界面")
MainInfoBar.push_info_bar(
"success", "操作成功", "管理密钥修改成功", 3000
)
@@ -291,6 +291,7 @@ class Setting(QWidget):
# 重置管理密钥
Crypto.reset_PASSWORD(choice.input.text())
+ logger.success("成功重置管理密钥", module="设置界面")
MainInfoBar.push_info_bar(
"success", "操作成功", "管理密钥重置成功", 3000
)
@@ -316,7 +317,12 @@ class Setting(QWidget):
)
def check_update(self, if_show: bool = False, if_first: bool = False) -> None:
- """检查版本更新,调起文件下载进程"""
+ """
+ 检查版本更新,调起更新线程
+
+ :param if_show: 是否显示更新信息
+ :param if_first: 是否为启动时检查更新
+ """
current_version = list(map(int, Config.VERSION.split(".")))
@@ -339,7 +345,9 @@ class Setting(QWidget):
if version_info["code"] != 0:
- logger.error(f"获取版本信息时出错:{version_info['msg']}")
+ logger.error(
+ f"获取版本信息时出错:{version_info['msg']}", module="设置界面"
+ )
error_remark_dict = {
1001: "获取版本信息的URL参数不正确",
@@ -372,7 +380,10 @@ class Setting(QWidget):
return None
- logger.warning(f"获取版本信息时出错:{network_result['error_message']}")
+ logger.warning(
+ f"获取版本信息时出错:{network_result['error_message']}",
+ module="设置界面",
+ )
MainInfoBar.push_info_bar(
"warning",
"获取版本信息时出错",
@@ -470,11 +481,12 @@ class Setting(QWidget):
download_info = network_result["response_json"]
else:
logger.warning(
- f"获取应用列表时出错:{network_result['error_message']}"
+ f"获取下载信息时出错:{network_result['error_message']}",
+ module="设置界面",
)
MainInfoBar.push_info_bar(
"warning",
- "获取应用列表时出错",
+ "获取下载信息时出错",
f"网络错误:{network_result['status_code']}",
5000,
)
@@ -492,6 +504,8 @@ class Setting(QWidget):
"download_dict": download_info["download_dict"],
}
+ logger.info("开始执行更新任务", module="设置界面")
+
self.downloader = DownloadManager(
Config.app_path, "AUTO_MAA", remote_version, download_config
)
@@ -526,6 +540,9 @@ class Setting(QWidget):
SoundPlayer.play("无新版本")
def start_setup(self) -> None:
+ """启动安装程序"""
+
+ logger.info("启动安装程序", module="设置界面")
subprocess.Popen(
[
Config.app_path / "AUTO_MAA-Setup.exe",
@@ -555,7 +572,10 @@ class Setting(QWidget):
if network_result["status_code"] == 200:
notice = network_result["response_json"]
else:
- logger.warning(f"获取最新公告时出错:{network_result['error_message']}")
+ logger.warning(
+ f"获取最新公告时出错:{network_result['error_message']}",
+ module="设置界面",
+ )
MainInfoBar.push_info_bar(
"warning",
"获取最新公告时出错",
diff --git a/app/utils/ProcessManager.py b/app/utils/ProcessManager.py
index c06d21f..a57406d 100644
--- a/app/utils/ProcessManager.py
+++ b/app/utils/ProcessManager.py
@@ -48,12 +48,7 @@ class ProcessManager(QObject):
self.check_timer = QTimer()
self.check_timer.timeout.connect(self.check_processes)
- def open_process(
- self,
- path: Path,
- args: list = [],
- tracking_time: int = 60,
- ) -> int:
+ def open_process(self, path: Path, args: list = [], tracking_time: int = 60) -> int:
"""
启动一个新进程并返回其pid,并开始监视该进程
@@ -89,7 +84,7 @@ class ProcessManager(QObject):
# 扫描并记录所有相关进程
try:
- # 获取主进程及其子进程
+ # 获取主进程
main_proc = psutil.Process(self.main_pid)
self.tracked_pids.add(self.main_pid)
diff --git a/main.py b/main.py
index 85e963b..49bc0f7 100644
--- a/main.py
+++ b/main.py
@@ -44,10 +44,10 @@ def no_print(*args, **kwargs):
builtins.print = no_print
-from loguru import logger
import os
import sys
import ctypes
+import traceback
from PySide6.QtWidgets import QApplication
from qfluentwidgets import FluentTranslator
@@ -60,28 +60,214 @@ def is_admin() -> bool:
return False
-@logger.catch
+def show_system_error(title: str, message: str, detailed_error: str = None):
+ """使用系统级消息框显示错误"""
+ try:
+ # Windows系统消息框
+ if sys.platform == "win32":
+ # 组合完整的错误信息
+ full_message = message
+ if detailed_error:
+ # 限制详细错误信息长度,避免消息框过大
+ if len(detailed_error) > 2000:
+ detailed_error = (
+ detailed_error[:2000] + "\n\n... (错误信息过长已截断)"
+ )
+ full_message += f"\n\n详细错误信息:\n{detailed_error}"
+
+ # 使用ctypes调用Windows API
+ ctypes.windll.user32.MessageBoxW(
+ 0, # 父窗口句柄
+ full_message, # 消息内容
+ title, # 标题
+ 0x10 | 0x0, # MB_ICONERROR | MB_OK
+ )
+
+ # Linux系统 - 尝试使用zenity或kdialog
+ elif sys.platform.startswith("linux"):
+ full_message = message
+ if detailed_error:
+ full_message += f"\n\n详细错误:\n{detailed_error[:1000]}"
+
+ try:
+ # 尝试zenity (GNOME)
+ os.system(
+ f'zenity --error --title="{title}" --text="{full_message}" 2>/dev/null'
+ )
+ except:
+ try:
+ # 尝试kdialog (KDE)
+ os.system(
+ f'kdialog --error "{full_message}" --title "{title}" 2>/dev/null'
+ )
+ except:
+ # 降级到控制台输出
+ print(f"错误: {title}")
+ print(f"消息: {message}")
+ if detailed_error:
+ print(f"详细信息:\n{detailed_error}")
+
+ # macOS系统
+ elif sys.platform == "darwin":
+ full_message = message
+ if detailed_error:
+ full_message += f"\n\n详细错误:\n{detailed_error[:1000]}"
+
+ try:
+ os.system(
+ f'osascript -e \'display alert "{title}" message "{full_message}" as critical\''
+ )
+ except:
+ print(f"错误: {title}")
+ print(f"消息: {message}")
+ if detailed_error:
+ print(f"详细信息:\n{detailed_error}")
+
+ else:
+ # 其他系统降级到控制台输出
+ print(f"错误: {title}")
+ print(f"消息: {message}")
+ if detailed_error:
+ print(f"详细信息:\n{detailed_error}")
+
+ except Exception as e:
+ # 如果连系统消息框都失败了,输出到控制台
+ print(f"无法显示错误对话框: {e}")
+ print(f"原始错误: {title} - {message}")
+ if detailed_error:
+ print(f"详细错误信息:\n{detailed_error}")
+
+
+def save_error_log(error_info: str):
+ """保存错误日志到文件"""
+ try:
+ import datetime
+
+ timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
+ log_dir = os.path.join(os.path.dirname(__file__), "debug")
+ os.makedirs(log_dir, exist_ok=True)
+
+ log_file = os.path.join(log_dir, f"crash_{timestamp}.log")
+ with open(log_file, "w", encoding="utf-8") as f:
+ f.write(f"AUTO_MAA 崩溃日志\n")
+ f.write(f"时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
+ f.write(f"Python版本: {sys.version}\n")
+ f.write(f"平台: {sys.platform}\n")
+ f.write(f"工作目录: {os.getcwd()}\n")
+ f.write("=" * 50 + "\n")
+ f.write(error_info)
+
+ return log_file
+ except:
+ return None
+
+
def main():
+ """主程序入口"""
+ application = None
- application = QApplication(sys.argv)
+ try:
+ # 创建QApplication
+ application = QApplication(sys.argv)
- translator = FluentTranslator()
- application.installTranslator(translator)
+ # 安装翻译器
+ translator = FluentTranslator()
+ application.installTranslator(translator)
- from app.ui.main_window import AUTO_MAA
+ try:
+ # 导入主窗口模块
+ from app.ui.main_window import AUTO_MAA
- window = AUTO_MAA()
- window.show_ui("显示主窗口", if_start=True)
- window.start_up_task()
- sys.exit(application.exec())
+ # 创建主窗口
+ window = AUTO_MAA()
+ window.show_ui("显示主窗口", if_start=True)
+ window.start_up_task()
+
+ except ImportError as e:
+ error_msg = f"模块导入失败: {str(e)}"
+ detailed_error = traceback.format_exc()
+ log_file = save_error_log(f"{error_msg}\n\n{detailed_error}")
+
+ if log_file:
+ error_msg += f"\n\n错误日志已保存到: {log_file}"
+
+ show_system_error("模块导入错误", error_msg, detailed_error)
+ return
+
+ except Exception as e:
+ error_msg = f"主窗口创建失败: {str(e)}"
+ detailed_error = traceback.format_exc()
+ log_file = save_error_log(f"{error_msg}\n\n{detailed_error}")
+
+ if log_file:
+ error_msg += f"\n\n错误日志已保存到: {log_file}"
+
+ show_system_error("窗口创建错误", error_msg, detailed_error)
+ return
+
+ # 启动事件循环
+ sys.exit(application.exec())
+
+ except Exception as e:
+ error_msg = f"应用程序启动失败: {str(e)}"
+ detailed_error = traceback.format_exc()
+ log_file = save_error_log(f"{error_msg}\n\n{detailed_error}")
+
+ if log_file:
+ error_msg += f"\n\n错误日志已保存到: {log_file}"
+
+ # 尝试显示错误对话框
+ show_system_error("应用程序启动错误", error_msg, detailed_error)
+
+ # 如果有应用程序实例,确保正确退出
+ if application:
+ try:
+ application.quit()
+ except:
+ pass
+
+ sys.exit(1)
+
+
+def handle_exception(exc_type, exc_value, exc_traceback):
+ """全局异常处理器"""
+ if issubclass(exc_type, KeyboardInterrupt):
+ sys.__excepthook__(exc_type, exc_value, exc_traceback)
+ return
+
+ error_msg = f"未处理的异常: {exc_type.__name__}: {str(exc_value)}"
+ detailed_error = "".join(
+ traceback.format_exception(exc_type, exc_value, exc_traceback)
+ )
+ log_file = save_error_log(f"{error_msg}\n\n{detailed_error}")
+
+ if log_file:
+ error_msg += f"\n\n错误日志已保存到: {log_file}"
+
+ show_system_error("程序异常", error_msg, detailed_error)
+
+
+# 设置全局异常处理器
+sys.excepthook = handle_exception
if __name__ == "__main__":
- if is_admin():
- main()
- else:
- ctypes.windll.shell32.ShellExecuteW(
- None, "runas", sys.executable, os.path.realpath(sys.argv[0]), None, 1
- )
- sys.exit(0)
+ try:
+ if is_admin():
+ main()
+ else:
+ ctypes.windll.shell32.ShellExecuteW(
+ None, "runas", sys.executable, os.path.realpath(sys.argv[0]), None, 1
+ )
+ sys.exit(0)
+ except Exception as e:
+ error_msg = f"程序启动失败: {str(e)}"
+ detailed_error = traceback.format_exc()
+ log_file = save_error_log(f"{error_msg}\n\n{detailed_error}")
+
+ if log_file:
+ error_msg += f"\n\n错误日志已保存到: {log_file}"
+
+ show_system_error("启动错误", error_msg, detailed_error)
+ sys.exit(1)
diff --git a/resources/version.json b/resources/version.json
index b32de3f..56670bf 100644
--- a/resources/version.json
+++ b/resources/version.json
@@ -1,60 +1,14 @@
{
- "main_version": "4.4.0.0",
+ "main_version": "4.4.1.1",
"version_info": {
- "4.4.0.0": {
- "新增功能": [
- "通用配置模式接入日志系统"
- ],
+ "4.4.1.1": {
"修复BUG": [
- "信任系统证书,并添加网络代理地址配置项 #50",
- "适配 MAA 任务及基建设施日志翻译"
+ "修复MAA掉落物统计功能",
+ "修复模拟器界面被异常关闭且无法重新打开的问题"
],
"程序优化": [
- "重构历史记录保存与载入逻辑"
- ]
- },
- "4.4.0.5": {
- "新增功能": [
- "添加导入导出通用配置功能"
- ],
- "修复BUG": [
- "修复开机自启相关功能"
- ]
- },
- "4.4.0.4": {
- "新增功能": [
- "添加重置管理密钥功能"
- ],
- "修复BUG": [
- "修复无计划表时数据系统无法正常升级到v1.7的问题"
- ]
- },
- "4.4.0.3": {
- "修复BUG": [
- "适配 MAA 备选关卡字段修改",
- "修复无成功日志时的脚本判定逻辑"
- ],
- "程序优化": [
- "`GameId`字段改为 `Stage`,与 MAA 保持一致"
- ]
- },
- "4.4.0.2": {
- "新增功能": [
- "进一步适配三月七相关配置项"
- ],
- "修复BUG": [
- "适配 Mirror 酱 平台下载策略调整"
- ]
- },
- "4.4.0.1": {
- "新增功能": [
- "初步完成通用调度模块"
- ],
- "修复BUG": [
- "修复了程序BUG较少的BUG"
- ],
- "程序优化": [
- "子线程卡死不再阻塞调度任务"
+ "重构日志记录,载入更多日志记录项",
+ "优化日志监看启停逻辑"
]
}
}