fix: 主要核心后端添加报错捕获机制

This commit is contained in:
DLmaster361
2025-09-28 20:38:54 +08:00
parent dfc403733f
commit 06770eb3cc
36 changed files with 357 additions and 264 deletions

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -44,9 +45,9 @@ async def get_git_version() -> VersionOut:
status="error", status="error",
message=f"{type(e).__name__}: {str(e)}", message=f"{type(e).__name__}: {str(e)}",
if_need_update=False, if_need_update=False,
current_hash="", current_hash="unknown",
current_time="", current_time="unknown",
current_version="", current_version=Config.version(),
) )
return VersionOut( return VersionOut(
if_need_update=not is_latest, if_need_update=not is_latest,

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -55,7 +56,7 @@ async def add_script(script: ScriptCreateIn = Body(...)) -> ScriptCreateOut:
@router.post( @router.post(
"/get", summary="查询脚本配置信息", response_model=ScriptGetOut, status_code=200 "/get", summary="查询脚本配置信息", response_model=ScriptGetOut, status_code=200
) )
async def get_scripts(script: ScriptGetIn = Body(...)) -> ScriptGetOut: async def get_script(script: ScriptGetIn = Body(...)) -> ScriptGetOut:
try: try:
index, data = await Config.get_script(script.scriptId) index, data = await Config.get_script(script.scriptId)

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -99,15 +100,18 @@ async def test_notify() -> OutBase:
@router.post( @router.post(
"/webhook/create", summary="创建自定义Webhook", response_model=OutBase, status_code=200 "/webhook/create",
summary="创建自定义Webhook",
response_model=OutBase,
status_code=200,
) )
async def create_webhook(webhook_data: dict = Body(...)) -> OutBase: async def create_webhook(webhook_data: dict = Body(...)) -> OutBase:
"""创建自定义Webhook""" """创建自定义Webhook"""
try: try:
# 生成唯一ID # 生成唯一ID
webhook_id = str(uuid.uuid4()) webhook_id = str(uuid.uuid4())
# 创建webhook配置 # 创建webhook配置
webhook_config = { webhook_config = {
"id": webhook_id, "id": webhook_id,
@@ -116,26 +120,22 @@ async def create_webhook(webhook_data: dict = Body(...)) -> OutBase:
"template": webhook_data.get("template", ""), "template": webhook_data.get("template", ""),
"enabled": webhook_data.get("enabled", True), "enabled": webhook_data.get("enabled", True),
"headers": webhook_data.get("headers", {}), "headers": webhook_data.get("headers", {}),
"method": webhook_data.get("method", "POST") "method": webhook_data.get("method", "POST"),
} }
# 获取当前配置 # 获取当前配置
current_config = await Config.get_setting() current_config = await Config.get_setting()
custom_webhooks = current_config.get("Notify", {}).get("CustomWebhooks", []) custom_webhooks = current_config.get("Notify", {}).get("CustomWebhooks", [])
# 添加新webhook # 添加新webhook
custom_webhooks.append(webhook_config) custom_webhooks.append(webhook_config)
# 更新配置 # 更新配置
update_data = { update_data = {"Notify": {"CustomWebhooks": custom_webhooks}}
"Notify": {
"CustomWebhooks": custom_webhooks
}
}
await Config.update_setting(update_data) await Config.update_setting(update_data)
return OutBase(message=f"Webhook '{webhook_config['name']}' 创建成功") return OutBase(message=f"Webhook '{webhook_config['name']}' 创建成功")
except Exception as e: except Exception as e:
return OutBase( return OutBase(
code=500, status="error", message=f"{type(e).__name__}: {str(e)}" code=500, status="error", message=f"{type(e).__name__}: {str(e)}"
@@ -143,48 +143,57 @@ async def create_webhook(webhook_data: dict = Body(...)) -> OutBase:
@router.post( @router.post(
"/webhook/update", summary="更新自定义Webhook", response_model=OutBase, status_code=200 "/webhook/update",
summary="更新自定义Webhook",
response_model=OutBase,
status_code=200,
) )
async def update_webhook(webhook_data: dict = Body(...)) -> OutBase: async def update_webhook(webhook_data: dict = Body(...)) -> OutBase:
"""更新自定义Webhook""" """更新自定义Webhook"""
try: try:
webhook_id = webhook_data.get("id") webhook_id = webhook_data.get("id")
if not webhook_id: if not webhook_id:
return OutBase(code=400, status="error", message="缺少Webhook ID") return OutBase(code=400, status="error", message="缺少Webhook ID")
# 获取当前配置 # 获取当前配置
current_config = await Config.get_setting() current_config = await Config.get_setting()
custom_webhooks = current_config.get("Notify", {}).get("CustomWebhooks", []) custom_webhooks = current_config.get("Notify", {}).get("CustomWebhooks", [])
# 查找并更新webhook # 查找并更新webhook
updated = False updated = False
for i, webhook in enumerate(custom_webhooks): for i, webhook in enumerate(custom_webhooks):
if webhook.get("id") == webhook_id: if webhook.get("id") == webhook_id:
custom_webhooks[i].update({ custom_webhooks[i].update(
"name": webhook_data.get("name", webhook.get("name", "")), {
"url": webhook_data.get("url", webhook.get("url", "")), "name": webhook_data.get("name", webhook.get("name", "")),
"template": webhook_data.get("template", webhook.get("template", "")), "url": webhook_data.get("url", webhook.get("url", "")),
"enabled": webhook_data.get("enabled", webhook.get("enabled", True)), "template": webhook_data.get(
"headers": webhook_data.get("headers", webhook.get("headers", {})), "template", webhook.get("template", "")
"method": webhook_data.get("method", webhook.get("method", "POST")) ),
}) "enabled": webhook_data.get(
"enabled", webhook.get("enabled", True)
),
"headers": webhook_data.get(
"headers", webhook.get("headers", {})
),
"method": webhook_data.get(
"method", webhook.get("method", "POST")
),
}
)
updated = True updated = True
break break
if not updated: if not updated:
return OutBase(code=404, status="error", message="Webhook不存在") return OutBase(code=404, status="error", message="Webhook不存在")
# 更新配置 # 更新配置
update_data = { update_data = {"Notify": {"CustomWebhooks": custom_webhooks}}
"Notify": {
"CustomWebhooks": custom_webhooks
}
}
await Config.update_setting(update_data) await Config.update_setting(update_data)
return OutBase(message="Webhook更新成功") return OutBase(message="Webhook更新成功")
except Exception as e: except Exception as e:
return OutBase( return OutBase(
code=500, status="error", message=f"{type(e).__name__}: {str(e)}" code=500, status="error", message=f"{type(e).__name__}: {str(e)}"
@@ -192,37 +201,36 @@ async def update_webhook(webhook_data: dict = Body(...)) -> OutBase:
@router.post( @router.post(
"/webhook/delete", summary="删除自定义Webhook", response_model=OutBase, status_code=200 "/webhook/delete",
summary="删除自定义Webhook",
response_model=OutBase,
status_code=200,
) )
async def delete_webhook(webhook_data: dict = Body(...)) -> OutBase: async def delete_webhook(webhook_data: dict = Body(...)) -> OutBase:
"""删除自定义Webhook""" """删除自定义Webhook"""
try: try:
webhook_id = webhook_data.get("id") webhook_id = webhook_data.get("id")
if not webhook_id: if not webhook_id:
return OutBase(code=400, status="error", message="缺少Webhook ID") return OutBase(code=400, status="error", message="缺少Webhook ID")
# 获取当前配置 # 获取当前配置
current_config = await Config.get_setting() current_config = await Config.get_setting()
custom_webhooks = current_config.get("Notify", {}).get("CustomWebhooks", []) custom_webhooks = current_config.get("Notify", {}).get("CustomWebhooks", [])
# 查找并删除webhook # 查找并删除webhook
original_length = len(custom_webhooks) original_length = len(custom_webhooks)
custom_webhooks = [w for w in custom_webhooks if w.get("id") != webhook_id] custom_webhooks = [w for w in custom_webhooks if w.get("id") != webhook_id]
if len(custom_webhooks) == original_length: if len(custom_webhooks) == original_length:
return OutBase(code=404, status="error", message="Webhook不存在") return OutBase(code=404, status="error", message="Webhook不存在")
# 更新配置 # 更新配置
update_data = { update_data = {"Notify": {"CustomWebhooks": custom_webhooks}}
"Notify": {
"CustomWebhooks": custom_webhooks
}
}
await Config.update_setting(update_data) await Config.update_setting(update_data)
return OutBase(message="Webhook删除成功") return OutBase(message="Webhook删除成功")
except Exception as e: except Exception as e:
return OutBase( return OutBase(
code=500, status="error", message=f"{type(e).__name__}: {str(e)}" code=500, status="error", message=f"{type(e).__name__}: {str(e)}"
@@ -230,11 +238,14 @@ async def delete_webhook(webhook_data: dict = Body(...)) -> OutBase:
@router.post( @router.post(
"/webhook/test", summary="测试自定义Webhook", response_model=OutBase, status_code=200 "/webhook/test",
summary="测试自定义Webhook",
response_model=OutBase,
status_code=200,
) )
async def test_webhook(webhook_data: dict = Body(...)) -> OutBase: async def test_webhook(webhook_data: dict = Body(...)) -> OutBase:
"""测试自定义Webhook""" """测试自定义Webhook"""
try: try:
webhook_config = { webhook_config = {
"name": webhook_data.get("name", "测试Webhook"), "name": webhook_data.get("name", "测试Webhook"),
@@ -242,18 +253,16 @@ async def test_webhook(webhook_data: dict = Body(...)) -> OutBase:
"template": webhook_data.get("template", ""), "template": webhook_data.get("template", ""),
"enabled": True, "enabled": True,
"headers": webhook_data.get("headers", {}), "headers": webhook_data.get("headers", {}),
"method": webhook_data.get("method", "POST") "method": webhook_data.get("method", "POST"),
} }
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
"AUTO-MAS Webhook测试", "AUTO-MAS Webhook测试",
"这是一条测试消息如果您收到此消息说明Webhook配置正确", "这是一条测试消息如果您收到此消息说明Webhook配置正确",
webhook_config webhook_config,
) )
return OutBase(message="Webhook测试成功") return OutBase(message="Webhook测试成功")
except Exception as e: except Exception as e:
return OutBase( return OutBase(code=500, status="error", message=f"Webhook测试失败: {str(e)}")
code=500, status="error", message=f"Webhook测试失败: {str(e)}"
)

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -974,27 +975,23 @@ class AppConfig(GlobalConfig):
logger.warning("Git仓库不可用返回默认版本信息") logger.warning("Git仓库不可用返回默认版本信息")
return False, "unknown", "unknown" return False, "unknown", "unknown"
try: # 获取当前 commit
# 获取当前 commit current_commit = self.repo.head.commit
current_commit = self.repo.head.commit
# 获取 commit 哈希 # 获取 commit 哈希
commit_hash = current_commit.hexsha commit_hash = current_commit.hexsha
# 获取 commit 时间 # 获取 commit 时间
commit_time = datetime.fromtimestamp(current_commit.committed_date) commit_time = datetime.fromtimestamp(current_commit.committed_date)
# 检查是否为最新 commit # 检查是否为最新 commit
# 获取远程分支的最新 commit # 获取远程分支的最新 commit
origin = self.repo.remotes.origin origin = self.repo.remotes.origin
origin.fetch() # 拉取最新信息 origin.fetch() # 拉取最新信息
remote_commit = self.repo.commit(f"origin/{self.repo.active_branch.name}") remote_commit = self.repo.commit(f"origin/{self.repo.active_branch.name}")
is_latest = bool(current_commit.hexsha == remote_commit.hexsha) is_latest = bool(current_commit.hexsha == remote_commit.hexsha)
return is_latest, commit_hash, commit_time.strftime("%Y-%m-%d %H:%M:%S") return is_latest, commit_hash, commit_time.strftime("%Y-%m-%d %H:%M:%S")
except Exception as e:
logger.warning(f"获取Git版本信息失败: {e}")
return False, "error", "error"
async def add_script( async def add_script(
self, script: Literal["MAA", "General"] self, script: Literal["MAA", "General"]
@@ -1864,7 +1861,7 @@ class AppConfig(GlobalConfig):
async def get_script_combox(self): async def get_script_combox(self):
"""获取脚本下拉框信息""" """获取脚本下拉框信息"""
logger.info("Getting script combo box information...") logger.info("开始获取脚本下拉框信息")
data = [{"label": "未选择", "value": "-"}] data = [{"label": "未选择", "value": "-"}]
for uid, script in self.ScriptConfig.items(): for uid, script in self.ScriptConfig.items():
data.append( data.append(
@@ -1873,7 +1870,7 @@ class AppConfig(GlobalConfig):
"value": str(uid), "value": str(uid),
} }
) )
logger.success("Script combo box information retrieved successfully.") logger.success("脚本下拉框信息获取成功")
return data return data
@@ -2040,7 +2037,10 @@ class AppConfig(GlobalConfig):
data["sanity"] = int(sanity_match.group(1)) data["sanity"] = int(sanity_match.group(1))
# 提取理智回满时间:理智将在 2025-09-26 18:57 回满。(17h 29m 后) # 提取理智回满时间:理智将在 2025-09-26 18:57 回满。(17h 29m 后)
sanity_full_match = re.search(r"(理智将在\s*\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s*回满。\(\d+h\s+\d+m\s+后\))", log_line) sanity_full_match = re.search(
r"(理智将在\s*\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s*回满。\(\d+h\s+\d+m\s+后\))",
log_line,
)
if sanity_full_match: if sanity_full_match:
data["sanity_full_at"] = sanity_full_match.group(1) data["sanity_full_at"] = sanity_full_match.group(1)
@@ -2150,11 +2150,11 @@ class AppConfig(GlobalConfig):
# 保存日志 # 保存日志
log_path.parent.mkdir(parents=True, exist_ok=True) log_path.parent.mkdir(parents=True, exist_ok=True)
with log_path.open("w", encoding="utf-8") as f: log_path.write_text("\n".join(logs), encoding="utf-8")
f.writelines(logs)
# 保存统计数据 # 保存统计数据
with log_path.with_suffix(".json").open("w", encoding="utf-8") as f: log_path.with_suffix(".json").write_text(
json.dump(data, f, ensure_ascii=False, indent=4) json.dumps(data, ensure_ascii=False, index=4), encoding="utf-8"
)
logger.success(f"MAA 日志统计完成, 日志路径: {log_path}") logger.success(f"MAA 日志统计完成, 日志路径: {log_path}")
@@ -2179,10 +2179,10 @@ class AppConfig(GlobalConfig):
# 保存日志 # 保存日志
log_path.parent.mkdir(parents=True, exist_ok=True) log_path.parent.mkdir(parents=True, exist_ok=True)
with log_path.with_suffix(".log").open("w", encoding="utf-8") as f: log_path.with_suffix(".log").write_text("\n".join(logs), encoding="utf-8")
f.writelines(logs) log_path.with_suffix(".json").write_text(
with log_path.with_suffix(".json").open("w", encoding="utf-8") as f: json.dumps(data, ensure_ascii=False, indent=4), encoding="utf-8"
json.dump(data, f, ensure_ascii=False, indent=4) )
logger.success(f"通用日志统计完成, 日志路径: {log_path.with_suffix('.log')}") logger.success(f"通用日志统计完成, 日志路径: {log_path.with_suffix('.log')}")
@@ -2200,8 +2200,13 @@ class AppConfig(GlobalConfig):
for json_file in statistic_path_list: for json_file in statistic_path_list:
with json_file.open("r", encoding="utf-8") as f: try:
single_data = json.load(f) single_data = json.loads(json_file.read_text(encoding="utf-8"))
except Exception as e:
logger.warning(
f"无法解析文件 {json_file}, 错误信息: {type(e).__name__}: {str(e)}"
)
continue
for key in single_data.keys(): for key in single_data.keys():

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -92,7 +93,7 @@ class _TaskManager:
return task_id return task_id
# @logger.catch @logger.catch
async def run_task( async def run_task(
self, mode: str, task_id: uuid.UUID, actual_id: Optional[uuid.UUID] self, mode: str, task_id: uuid.UUID, actual_id: Optional[uuid.UUID]
): ):
@@ -124,7 +125,17 @@ class _TaskManager:
lambda t: asyncio.create_task(task_item.final_task(t)) lambda t: asyncio.create_task(task_item.final_task(t))
) )
self.task_dict[uid].add_done_callback(partial(self.task_dict.pop, uid)) self.task_dict[uid].add_done_callback(partial(self.task_dict.pop, uid))
await self.task_dict[uid] try:
await self.task_dict[uid]
except Exception as e:
logger.error(f"任务 {task_id} 运行出错: {type(e).__name__}: {str(e)}")
await Config.send_json(
WebSocketMessage(
id=str(task_id),
type="Info",
data={"Error": f"任务运行时出错 {type(e).__name__}: {str(e)}"},
).model_dump()
)
else: else:
@@ -262,8 +273,23 @@ class _TaskManager:
self.task_dict[script_id].add_done_callback( self.task_dict[script_id].add_done_callback(
partial(self.task_dict.pop, script_id) partial(self.task_dict.pop, script_id)
) )
await self.task_dict[script_id] try:
task["status"] = "完成" await self.task_dict[script_id]
task["status"] = "完成"
except Exception as e:
logger.error(
f"任务 {script_id} 运行出错: {type(e).__name__}: {str(e)}"
)
await Config.send_json(
WebSocketMessage(
id=str(task_id),
type="Info",
data={
"Error": f"任务运行时出错 {type(e).__name__}: {str(e)}"
},
).model_dump()
)
task["status"] = "异常"
await Config.send_json( await Config.send_json(
WebSocketMessage( WebSocketMessage(
id=str(task_id), id=str(task_id),
@@ -287,7 +313,7 @@ class _TaskManager:
else: else:
uid = uuid.UUID(task_id) uid = uuid.UUID(task_id)
if uid not in self.task_dict: if uid not in self.task_dict:
raise ValueError(f"任务 {uid} 未在运行") raise ValueError("任务未在运行")
self.task_dict[uid].cancel() self.task_dict[uid].cancel()
async def remove_task( async def remove_task(

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -108,6 +109,7 @@ class _MainTimer:
).model_dump() ).model_dump()
) )
@logger.catch()
async def set_silence(self): async def set_silence(self):
"""静默模式通过模拟老板键来隐藏模拟器窗口""" """静默模式通过模拟老板键来隐藏模拟器窗口"""

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -385,11 +386,10 @@ class ConfigBase:
self.file.parent.mkdir(parents=True, exist_ok=True) self.file.parent.mkdir(parents=True, exist_ok=True)
self.file.touch() self.file.touch()
with self.file.open("r", encoding="utf-8") as f: try:
try: data = json.loads(self.file.read_text(encoding="utf-8"))
data = json.load(f) except json.JSONDecodeError:
except json.JSONDecodeError: data = {}
data = {}
await self.load(data) await self.load(data)
@@ -499,13 +499,14 @@ class ConfigBase:
raise ValueError("文件路径未设置, 请先调用 `connect` 方法连接配置文件") raise ValueError("文件路径未设置, 请先调用 `connect` 方法连接配置文件")
self.file.parent.mkdir(parents=True, exist_ok=True) self.file.parent.mkdir(parents=True, exist_ok=True)
with self.file.open("w", encoding="utf-8") as f: self.file.write_text(
json.dump( json.dumps(
await self.toDict(not self.if_save_multi_config, if_decrypt=False), await self.toDict(not self.if_save_multi_config, if_decrypt=False),
f,
ensure_ascii=False, ensure_ascii=False,
indent=4, indent=4,
) ),
encoding="utf-8",
)
async def lock(self): async def lock(self):
""" """
@@ -610,11 +611,10 @@ class MultipleConfig:
self.file.parent.mkdir(parents=True, exist_ok=True) self.file.parent.mkdir(parents=True, exist_ok=True)
self.file.touch() self.file.touch()
with self.file.open("r", encoding="utf-8") as f: try:
try: data = json.loads(self.file.read_text(encoding="utf-8"))
data = json.load(f) except json.JSONDecodeError:
except json.JSONDecodeError: data = {}
data = {}
await self.load(data) await self.load(data)
@@ -716,8 +716,10 @@ class MultipleConfig:
raise ValueError("文件路径未设置, 请先调用 `connect` 方法连接配置文件") raise ValueError("文件路径未设置, 请先调用 `connect` 方法连接配置文件")
self.file.parent.mkdir(parents=True, exist_ok=True) self.file.parent.mkdir(parents=True, exist_ok=True)
with self.file.open("w", encoding="utf-8") as f: self.file.write_text(
json.dump(await self.toDict(), f, ensure_ascii=False, indent=4) json.dumps(await self.toDict(), ensure_ascii=False, indent=4),
encoding="utf-8",
)
async def add(self, config_type: type) -> tuple[uuid.UUID, ConfigBase]: async def add(self, config_type: type) -> tuple[uuid.UUID, ConfigBase]:
""" """

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -117,7 +118,9 @@ class CustomWebhook(BaseModel):
template: str = Field(..., description="消息模板") template: str = Field(..., description="消息模板")
enabled: bool = Field(default=True, description="是否启用") enabled: bool = Field(default=True, description="是否启用")
headers: Optional[Dict[str, str]] = Field(default=None, description="自定义请求头") headers: Optional[Dict[str, str]] = Field(default=None, description="自定义请求头")
method: Optional[Literal["POST", "GET"]] = Field(default="POST", description="请求方法") method: Optional[Literal["POST", "GET"]] = Field(
default="POST", description="请求方法"
)
class GlobalConfig_Notify(BaseModel): class GlobalConfig_Notify(BaseModel):

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -23,7 +24,6 @@ import asyncio
import aiohttp import aiohttp
import json import json
import uuid import uuid
import psutil
import platform import platform
import time import time
from typing import Dict, Any, Optional from typing import Dict, Any, Optional

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -178,39 +179,43 @@ class Notification:
:param content: 通知内容 :param content: 通知内容
:param webhook_config: Webhook配置对象 :param webhook_config: Webhook配置对象
""" """
if not webhook_config.get("url"): if not webhook_config.get("url"):
raise ValueError("Webhook URL 不能为空") raise ValueError("Webhook URL 不能为空")
if not webhook_config.get("enabled", True): if not webhook_config.get("enabled", True):
logger.info(f"Webhook {webhook_config.get('name', 'Unknown')} 已禁用,跳过推送") logger.info(
f"Webhook {webhook_config.get('name', 'Unknown')} 已禁用,跳过推送"
)
return return
# 解析模板 # 解析模板
template = webhook_config.get("template", '{"title": "{title}", "content": "{content}"}') template = webhook_config.get(
"template", '{"title": "{title}", "content": "{content}"}'
)
# 替换模板变量 # 替换模板变量
try: try:
import json import json
from datetime import datetime from datetime import datetime
# 准备模板变量 # 准备模板变量
template_vars = { template_vars = {
"title": title, "title": title,
"content": content, "content": content,
"datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"date": datetime.now().strftime("%Y-%m-%d"), "date": datetime.now().strftime("%Y-%m-%d"),
"time": datetime.now().strftime("%H:%M:%S") "time": datetime.now().strftime("%H:%M:%S"),
} }
logger.debug(f"原始模板: {template}") logger.debug(f"原始模板: {template}")
logger.debug(f"模板变量: {template_vars}") logger.debug(f"模板变量: {template_vars}")
# 先尝试作为JSON模板处理 # 先尝试作为JSON模板处理
try: try:
# 解析模板为JSON对象然后替换其中的变量 # 解析模板为JSON对象然后替换其中的变量
template_obj = json.loads(template) template_obj = json.loads(template)
# 递归替换JSON对象中的变量 # 递归替换JSON对象中的变量
def replace_variables(obj): def replace_variables(obj):
if isinstance(obj, dict): if isinstance(obj, dict):
@@ -224,19 +229,26 @@ class Notification:
return result return result
else: else:
return obj return obj
data = replace_variables(template_obj) data = replace_variables(template_obj)
logger.debug(f"成功解析JSON模板: {data}") logger.debug(f"成功解析JSON模板: {data}")
except json.JSONDecodeError: except json.JSONDecodeError:
# 如果不是有效的JSON作为字符串模板处理 # 如果不是有效的JSON作为字符串模板处理
logger.debug("模板不是有效JSON作为字符串模板处理") logger.debug("模板不是有效JSON作为字符串模板处理")
formatted_template = template formatted_template = template
for key, value in template_vars.items(): for key, value in template_vars.items():
# 转义特殊字符以避免JSON解析错误 # 转义特殊字符以避免JSON解析错误
safe_value = str(value).replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') safe_value = (
formatted_template = formatted_template.replace(f"{{{key}}}", safe_value) str(value)
.replace('"', '\\"')
.replace("\n", "\\n")
.replace("\r", "\\r")
)
formatted_template = formatted_template.replace(
f"{{{key}}}", safe_value
)
# 再次尝试解析为JSON # 再次尝试解析为JSON
try: try:
data = json.loads(formatted_template) data = json.loads(formatted_template)
@@ -245,7 +257,7 @@ class Notification:
# 最终作为纯文本发送 # 最终作为纯文本发送
data = formatted_template data = formatted_template
logger.debug(f"作为纯文本发送: {data}") logger.debug(f"作为纯文本发送: {data}")
except Exception as e: except Exception as e:
logger.warning(f"模板解析失败,使用默认格式: {e}") logger.warning(f"模板解析失败,使用默认格式: {e}")
data = {"title": title, "content": content} data = {"title": title, "content": content}
@@ -257,43 +269,47 @@ class Notification:
# 发送请求 # 发送请求
method = webhook_config.get("method", "POST").upper() method = webhook_config.get("method", "POST").upper()
try: try:
if method == "POST": if method == "POST":
if isinstance(data, dict): if isinstance(data, dict):
response = requests.post( response = requests.post(
url=webhook_config["url"], url=webhook_config["url"],
json=data, json=data,
headers=headers, headers=headers,
timeout=10, timeout=10,
proxies=Config.get_proxies() proxies=Config.get_proxies(),
) )
else: else:
response = requests.post( response = requests.post(
url=webhook_config["url"], url=webhook_config["url"],
data=data, data=data,
headers=headers, headers=headers,
timeout=10, timeout=10,
proxies=Config.get_proxies() proxies=Config.get_proxies(),
) )
else: # GET else: # GET
params = data if isinstance(data, dict) else {"message": data} params = data if isinstance(data, dict) else {"message": data}
response = requests.get( response = requests.get(
url=webhook_config["url"], url=webhook_config["url"],
params=params, params=params,
headers=headers, headers=headers,
timeout=10, timeout=10,
proxies=Config.get_proxies() proxies=Config.get_proxies(),
) )
# 检查响应 # 检查响应
if response.status_code == 200: if response.status_code == 200:
logger.success(f"自定义Webhook推送成功: {webhook_config.get('name', 'Unknown')} - {title}") logger.success(
f"自定义Webhook推送成功: {webhook_config.get('name', 'Unknown')} - {title}"
)
else: else:
raise Exception(f"HTTP {response.status_code}: {response.text}") raise Exception(f"HTTP {response.status_code}: {response.text}")
except Exception as e: except Exception as e:
raise Exception(f"自定义Webhook推送失败 ({webhook_config.get('name', 'Unknown')}): {str(e)}") raise Exception(
f"自定义Webhook推送失败 ({webhook_config.get('name', 'Unknown')}): {str(e)}"
)
async def WebHookPush(self, title, content, webhook_url) -> None: async def WebHookPush(self, title, content, webhook_url) -> None:
""" """
@@ -401,10 +417,12 @@ class Notification:
await self.CustomWebhookPush( await self.CustomWebhookPush(
"AUTO-MAS测试通知", "AUTO-MAS测试通知",
"这是 AUTO-MAS 外部通知测试信息。如果你看到了这段内容, 说明 AUTO-MAS 的通知功能已经正确配置且可以正常工作!", "这是 AUTO-MAS 外部通知测试信息。如果你看到了这段内容, 说明 AUTO-MAS 的通知功能已经正确配置且可以正常工作!",
webhook webhook,
) )
except Exception as e: except Exception as e:
logger.error(f"自定义Webhook测试失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"自定义Webhook测试失败 ({webhook.get('name', 'Unknown')}): {e}"
)
logger.success("测试通知发送完成") logger.success("测试通知发送完成")

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -47,7 +48,7 @@ class MaaManager:
"""MAA控制器""" """MAA控制器"""
def __init__( def __init__(
self, mode: str, script_id: uuid.UUID, user_id: Optional[uuid.UUID], ws_id: str self, mode: str, script_id: uuid.UUID, user_id: Optional[uuid.UUID], ws_id: str
): ):
super().__init__() super().__init__()
@@ -100,7 +101,7 @@ class MaaManager:
if not self.maa_set_path.exists(): if not self.maa_set_path.exists():
return "MAA配置文件不存在, 请检查MAA路径设置" return "MAA配置文件不存在, 请检查MAA路径设置"
if (self.mode != "设置脚本" or self.user_id is not None) and not ( if (self.mode != "设置脚本" or self.user_id is not None) and not (
Path.cwd() / f"data/{self.script_id}/Default/ConfigFile/gui.json" Path.cwd() / f"data/{self.script_id}/Default/ConfigFile/gui.json"
).exists(): ).exists():
return "未完成 MAA 全局设置, 请先设置 MAA" return "未完成 MAA 全局设置, 请先设置 MAA"
return "Success!" return "Success!"
@@ -141,7 +142,7 @@ class MaaManager:
} }
for uid, config in self.user_config.items() for uid, config in self.user_config.items()
if config.get("Info", "Status") if config.get("Info", "Status")
and config.get("Info", "RemainedDay") != 0 and config.get("Info", "RemainedDay") != 0
] ]
self.user_list = sorted( self.user_list = sorted(
self.user_list, self.user_list,
@@ -160,10 +161,10 @@ class MaaManager:
# # 执行情况预处理 # # 执行情况预处理
for _ in self.user_list: for _ in self.user_list:
if ( if (
self.user_config[uuid.UUID(_["user_id"])].get( self.user_config[uuid.UUID(_["user_id"])].get(
"Data", "LastProxyDate" "Data", "LastProxyDate"
) )
!= self.curdate != self.curdate
): ):
await self.user_config[uuid.UUID(_["user_id"])].set( await self.user_config[uuid.UUID(_["user_id"])].set(
"Data", "LastProxyDate", self.curdate "Data", "LastProxyDate", self.curdate
@@ -178,8 +179,8 @@ class MaaManager:
self.cur_user_data = self.user_config[uuid.UUID(user["user_id"])] self.cur_user_data = self.user_config[uuid.UUID(user["user_id"])]
if (self.script_config.get("Run", "ProxyTimesLimit") == 0) or ( if (self.script_config.get("Run", "ProxyTimesLimit") == 0) or (
self.cur_user_data.get("Data", "ProxyTimes") self.cur_user_data.get("Data", "ProxyTimes")
< self.script_config.get("Run", "ProxyTimesLimit") < self.script_config.get("Run", "ProxyTimesLimit")
): ):
user["status"] = "运行" user["status"] = "运行"
await Config.send_json( await Config.send_json(
@@ -212,18 +213,18 @@ class MaaManager:
self.cur_user_data.get("Info", "Annihilation") == "Close" self.cur_user_data.get("Info", "Annihilation") == "Close"
), ),
"Routine": self.cur_user_data.get("Info", "Mode") == "复杂" "Routine": self.cur_user_data.get("Info", "Mode") == "复杂"
and not self.cur_user_data.get("Info", "Routine"), and not self.cur_user_data.get("Info", "Routine"),
} }
self.user_logs_list = [] self.user_logs_list = []
self.user_start_time = datetime.now() self.user_start_time = datetime.now()
if self.cur_user_data.get( if self.cur_user_data.get(
"Info", "IfSkland" "Info", "IfSkland"
) and self.cur_user_data.get("Info", "SklandToken"): ) and self.cur_user_data.get("Info", "SklandToken"):
if self.cur_user_data.get( if self.cur_user_data.get(
"Data", "LastSklandDate" "Data", "LastSklandDate"
) != datetime.now().strftime("%Y-%m-%d"): ) != datetime.now().strftime("%Y-%m-%d"):
await Config.send_json( await Config.send_json(
@@ -268,8 +269,8 @@ class MaaManager:
) )
if ( if (
skland_result["总计"] > 0 skland_result["总计"] > 0
and len(skland_result["失败"]) == 0 and len(skland_result["失败"]) == 0
): ):
await self.cur_user_data.set( await self.cur_user_data.set(
"Data", "Data",
@@ -299,13 +300,13 @@ class MaaManager:
# 剿灭模式;满足条件跳过剿灭 # 剿灭模式;满足条件跳过剿灭
if ( if (
mode == "Annihilation" mode == "Annihilation"
and self.script_config.get("Run", "AnnihilationWeeklyLimit") and self.script_config.get("Run", "AnnihilationWeeklyLimit")
and datetime.strptime( and datetime.strptime(
self.cur_user_data.get("Data", "LastAnnihilationDate"), self.cur_user_data.get("Data", "LastAnnihilationDate"),
"%Y-%m-%d", "%Y-%m-%d",
).isocalendar()[:2] ).isocalendar()[:2]
== datetime.strptime(self.curdate, "%Y-%m-%d").isocalendar()[:2] == datetime.strptime(self.curdate, "%Y-%m-%d").isocalendar()[:2]
): ):
logger.info( logger.info(
f"用户: {user['user_id']} - 本周剿灭模式已达上限, 跳过执行剿灭任务" f"用户: {user['user_id']} - 本周剿灭模式已达上限, 跳过执行剿灭任务"
@@ -316,11 +317,11 @@ class MaaManager:
self.weekly_annihilation_limit_reached = False self.weekly_annihilation_limit_reached = False
if ( if (
self.cur_user_data.get("Info", "Mode") == "详细" self.cur_user_data.get("Info", "Mode") == "详细"
and not ( and not (
Path.cwd() Path.cwd()
/ f"data/{self.script_id}/{user['user_id']}/ConfigFile/gui.json" / f"data/{self.script_id}/{user['user_id']}/ConfigFile/gui.json"
).exists() ).exists()
): ):
logger.error( logger.error(
f"用户: {user['user_id']} - 未找到日常详细配置文件" f"用户: {user['user_id']} - 未找到日常详细配置文件"
@@ -410,8 +411,8 @@ class MaaManager:
].split() ].split()
# 如果是快捷方式, 进行解析 # 如果是快捷方式, 进行解析
if ( if (
self.emulator_path.suffix == ".lnk" self.emulator_path.suffix == ".lnk"
and self.emulator_path.exists() and self.emulator_path.exists()
): ):
try: try:
shell = win32com.client.Dispatch("WScript.Shell") shell = win32com.client.Dispatch("WScript.Shell")
@@ -520,7 +521,7 @@ class MaaManager:
f"更新静默进程标记: {self.emulator_path}, 标记有效时间: {datetime.now() + timedelta(seconds=self.wait_time + 10)}" f"更新静默进程标记: {self.emulator_path}, 标记有效时间: {datetime.now() + timedelta(seconds=self.wait_time + 10)}"
) )
Config.silence_dict[self.emulator_path] = ( Config.silence_dict[self.emulator_path] = (
datetime.now() + timedelta(seconds=self.wait_time + 10) datetime.now() + timedelta(seconds=self.wait_time + 10)
) )
await self.search_ADB_address() await self.search_ADB_address()
@@ -641,11 +642,11 @@ class MaaManager:
# 记录更新包路径 # 记录更新包路径
if ( if (
data["Global"]["VersionUpdate.package"] data["Global"]["VersionUpdate.package"]
and ( and (
self.maa_root_path self.maa_root_path
/ data["Global"]["VersionUpdate.package"] / data["Global"]["VersionUpdate.package"]
).exists() ).exists()
): ):
self.maa_update_package = data["Global"][ self.maa_update_package = data["Global"][
"VersionUpdate.package" "VersionUpdate.package"
@@ -653,8 +654,8 @@ class MaaManager:
# 记录剿灭情况 # 记录剿灭情况
if ( if (
mode == "Annihilation" mode == "Annihilation"
and self.weekly_annihilation_limit_reached and self.weekly_annihilation_limit_reached
): ):
await self.cur_user_data.set( await self.cur_user_data.set(
"Data", "LastAnnihilationDate", self.curdate "Data", "LastAnnihilationDate", self.curdate
@@ -887,8 +888,8 @@ class MaaManager:
if self.run_book["Annihilation"] and self.run_book["Routine"]: if self.run_book["Annihilation"] and self.run_book["Routine"]:
# 成功完成代理的用户修改相关参数 # 成功完成代理的用户修改相关参数
if ( if (
self.cur_user_data.get("Data", "ProxyTimes") == 0 self.cur_user_data.get("Data", "ProxyTimes") == 0
and self.cur_user_data.get("Info", "RemainedDay") != -1 and self.cur_user_data.get("Info", "RemainedDay") != -1
): ):
await self.cur_user_data.set( await self.cur_user_data.set(
"Info", "Info",
@@ -967,9 +968,9 @@ class MaaManager:
Config.if_ignore_silence.remove(self.script_id) Config.if_ignore_silence.remove(self.script_id)
if ( if (
self.mode == "自动代理" self.mode == "自动代理"
and hasattr(self, "index") and hasattr(self, "index")
and self.user_list[self.index]["status"] == "运行" and self.user_list[self.index]["status"] == "运行"
): ):
if not self.maa_update_package: if not self.maa_update_package:
@@ -999,9 +1000,9 @@ class MaaManager:
await self.result_record() await self.result_record()
elif ( elif (
self.mode == "人工排查" self.mode == "人工排查"
and hasattr(self, "index") and hasattr(self, "index")
and self.user_list[self.index]["status"] == "运行" and self.user_list[self.index]["status"] == "运行"
): ):
await self.result_record() await self.result_record()
@@ -1063,14 +1064,14 @@ class MaaManager:
elif self.mode == "设置脚本": elif self.mode == "设置脚本":
( (
Path.cwd() Path.cwd()
/ f"data/{self.script_id}/{self.user_id if self.user_id else 'Default'}/ConfigFile" / f"data/{self.script_id}/{self.user_id if self.user_id else 'Default'}/ConfigFile"
).mkdir(parents=True, exist_ok=True) ).mkdir(parents=True, exist_ok=True)
shutil.copy( shutil.copy(
self.maa_set_path, self.maa_set_path,
( (
Path.cwd() Path.cwd()
/ f"data/{self.script_id}/{self.user_id if self.user_id else 'Default'}/ConfigFile/gui.json" / f"data/{self.script_id}/{self.user_id if self.user_id else 'Default'}/ConfigFile/gui.json"
), ),
) )
@@ -1232,12 +1233,12 @@ class MaaManager:
if "完成任务: Infrast" in log or "完成任务: 基建换班" in log: if "完成任务: Infrast" in log or "完成任务: 基建换班" in log:
self.task_dict["Base"] = "False" self.task_dict["Base"] = "False"
if ( if (
"完成任务: Fight" in log "完成任务: Fight" in log
or "完成任务: 刷理智" in log or "完成任务: 刷理智" in log
or ( or (
self.log_check_mode == "Annihilation" self.log_check_mode == "Annihilation"
and "任务出错: 刷理智" in log and "任务出错: 刷理智" in log
) )
): ):
self.task_dict["Combat"] = "False" self.task_dict["Combat"] = "False"
if "完成任务: Mall" in log or "完成任务: 获取信用及购物" in log: if "完成任务: Mall" in log or "完成任务: 获取信用及购物" in log:
@@ -1264,13 +1265,13 @@ class MaaManager:
self.maa_result = "MAA在完成任务前中止" self.maa_result = "MAA在完成任务前中止"
elif ( elif (
"MaaAssistantArknights GUI exited" in log "MaaAssistantArknights GUI exited" in log
or not await self.maa_process_manager.is_running() or not await self.maa_process_manager.is_running()
): ):
self.maa_result = "MAA在完成任务前退出" self.maa_result = "MAA在完成任务前退出"
elif datetime.now() - latest_time > timedelta( elif datetime.now() - latest_time > timedelta(
minutes=self.script_config.get("Run", f"{self.log_check_mode}TimeLimit") minutes=self.script_config.get("Run", f"{self.log_check_mode}TimeLimit")
): ):
self.maa_result = "MAA进程超时" self.maa_result = "MAA进程超时"
@@ -1287,8 +1288,8 @@ class MaaManager:
elif "已停止" in log: elif "已停止" in log:
self.maa_result = "MAA在完成任务前中止" self.maa_result = "MAA在完成任务前中止"
elif ( elif (
"MaaAssistantArknights GUI exited" in log "MaaAssistantArknights GUI exited" in log
or not await self.maa_process_manager.is_running() or not await self.maa_process_manager.is_running()
): ):
self.maa_result = "MAA在完成任务前退出" self.maa_result = "MAA在完成任务前退出"
else: else:
@@ -1325,17 +1326,17 @@ class MaaManager:
elif self.cur_user_data.get("Info", "Mode") == "详细": elif self.cur_user_data.get("Info", "Mode") == "详细":
shutil.copy( shutil.copy(
( (
Path.cwd() Path.cwd()
/ f"data/{self.script_id}/{self.user_list[self.index]['user_id']}/ConfigFile/gui.json" / f"data/{self.script_id}/{self.user_list[self.index]['user_id']}/ConfigFile/gui.json"
), ),
self.maa_set_path, self.maa_set_path,
) )
elif self.mode == "设置脚本": elif self.mode == "设置脚本":
if ( if (
self.user_id is None self.user_id is None
and ( and (
Path.cwd() / f"data/{self.script_id}/Default/ConfigFile/gui.json" Path.cwd() / f"data/{self.script_id}/Default/ConfigFile/gui.json"
).exists() ).exists()
): ):
shutil.copy( shutil.copy(
(Path.cwd() / f"data/{self.script_id}/Default/ConfigFile/gui.json"), (Path.cwd() / f"data/{self.script_id}/Default/ConfigFile/gui.json"),
@@ -1343,21 +1344,21 @@ class MaaManager:
) )
elif self.user_id is not None: elif self.user_id is not None:
if ( if (
Path.cwd() Path.cwd()
/ f"data/{self.script_id}/{self.user_id}/ConfigFile/gui.json" / f"data/{self.script_id}/{self.user_id}/ConfigFile/gui.json"
).exists(): ).exists():
shutil.copy( shutil.copy(
( (
Path.cwd() Path.cwd()
/ f"data/{self.script_id}/{self.user_id}/ConfigFile/gui.json" / f"data/{self.script_id}/{self.user_id}/ConfigFile/gui.json"
), ),
self.maa_set_path, self.maa_set_path,
) )
else: else:
shutil.copy( shutil.copy(
( (
Path.cwd() Path.cwd()
/ f"data/{self.script_id}/Default/ConfigFile/gui.json" / f"data/{self.script_id}/Default/ConfigFile/gui.json"
), ),
self.maa_set_path, self.maa_set_path,
) )
@@ -1378,10 +1379,10 @@ class MaaManager:
if self.mode == "自动代理" and mode in ["Annihilation", "Routine"]: if self.mode == "自动代理" and mode in ["Annihilation", "Routine"]:
if (self.index == len(self.user_list) - 1) or ( if (self.index == len(self.user_list) - 1) or (
self.user_config[ self.user_config[
uuid.UUID(self.user_list[self.index + 1]["user_id"]) uuid.UUID(self.user_list[self.index + 1]["user_id"])
].get("Info", "Mode") ].get("Info", "Mode")
== "详细" == "详细"
): ):
data["Configurations"]["Default"][ data["Configurations"]["Default"][
"MainFunction.PostActions" "MainFunction.PostActions"
@@ -1459,8 +1460,8 @@ class MaaManager:
# 整理任务顺序 # 整理任务顺序
if ( if (
mode == "Annihilation" mode == "Annihilation"
or self.cur_user_data.get("Info", "Mode") == "简洁" or self.cur_user_data.get("Info", "Mode") == "简洁"
): ):
data["Configurations"]["Default"]["TaskQueue.Order.WakeUp"] = "0" data["Configurations"]["Default"]["TaskQueue.Order.WakeUp"] = "0"
data["Configurations"]["Default"]["TaskQueue.Order.Recruiting"] = "1" data["Configurations"]["Default"]["TaskQueue.Order.Recruiting"] = "1"
@@ -1581,8 +1582,8 @@ class MaaManager:
if self.cur_user_data.get("Info", "InfrastMode") == "Custom": if self.cur_user_data.get("Info", "InfrastMode") == "Custom":
if ( if (
Path.cwd() Path.cwd()
/ f"data/{self.script_id}/{self.user_list[self.index]['user_id']}/Infrastructure/infrastructure.json" / f"data/{self.script_id}/{self.user_list[self.index]['user_id']}/Infrastructure/infrastructure.json"
).exists(): ).exists():
data["Configurations"]["Default"][ data["Configurations"]["Default"][
@@ -1630,8 +1631,8 @@ class MaaManager:
# 基建模式 # 基建模式
if ( if (
data["Configurations"]["Default"]["Infrast.InfrastMode"] data["Configurations"]["Default"]["Infrast.InfrastMode"]
== "Custom" == "Custom"
): ):
data["Configurations"]["Default"][ data["Configurations"]["Default"][
"Infrast.CustomInfrastPlanIndex" "Infrast.CustomInfrastPlanIndex"
@@ -1856,11 +1857,11 @@ class MaaManager:
env = Environment(loader=FileSystemLoader(str(Path.cwd() / "res/html"))) env = Environment(loader=FileSystemLoader(str(Path.cwd() / "res/html")))
if mode == "代理结果" and ( if mode == "代理结果" and (
Config.get("Notify", "SendTaskResultTime") == "任何时刻" Config.get("Notify", "SendTaskResultTime") == "任何时刻"
or ( or (
Config.get("Notify", "SendTaskResultTime") == "仅失败时" Config.get("Notify", "SendTaskResultTime") == "仅失败时"
and message["uncompleted_count"] != 0 and message["uncompleted_count"] != 0
) )
): ):
# 生成文本通知内容 # 生成文本通知内容
message_text = ( message_text = (
@@ -1907,12 +1908,12 @@ class MaaManager:
if webhook.get("enabled", True): if webhook.get("enabled", True):
try: try:
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
title, title, f"{message_text}\n\nAUTO-MAS 敬上", webhook
f"{message_text}\n\nAUTO-MAS 敬上",
webhook
) )
except Exception as e: except Exception as e:
logger.error(f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}"
)
elif mode == "统计信息": elif mode == "统计信息":
@@ -1973,16 +1974,16 @@ class MaaManager:
if webhook.get("enabled", True): if webhook.get("enabled", True):
try: try:
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
title, title, f"{message_text}\n\nAUTO-MAS 敬上", webhook
f"{message_text}\n\nAUTO-MAS 敬上",
webhook
) )
except Exception as e: except Exception as e:
logger.error(f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}"
)
# 发送用户单独通知 # 发送用户单独通知
if self.cur_user_data.get("Notify", "Enabled") and self.cur_user_data.get( if self.cur_user_data.get("Notify", "Enabled") and self.cur_user_data.get(
"Notify", "IfSendStatistic" "Notify", "IfSendStatistic"
): ):
# 发送邮件通知 # 发送邮件通知
@@ -2023,12 +2024,12 @@ class MaaManager:
if webhook.get("enabled", True): if webhook.get("enabled", True):
try: try:
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
title, title, f"{message_text}\n\nAUTO-MAS 敬上", webhook
f"{message_text}\n\nAUTO-MAS 敬上",
webhook
) )
except Exception as e: except Exception as e:
logger.error(f"用户自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"用户自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}"
)
else: else:
logger.error( logger.error(
"用户CompanyWebHookBot密钥为空, 无法发送用户单独的CompanyWebHookBot通知" "用户CompanyWebHookBot密钥为空, 无法发送用户单独的CompanyWebHookBot通知"
@@ -2066,16 +2067,16 @@ class MaaManager:
if webhook.get("enabled", True): if webhook.get("enabled", True):
try: try:
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
title, title, "好羡慕~\n\nAUTO-MAS 敬上", webhook
"好羡慕~\n\nAUTO-MAS 敬上",
webhook
) )
except Exception as e: except Exception as e:
logger.error(f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}"
)
# 发送用户单独通知 # 发送用户单独通知
if self.cur_user_data.get("Notify", "Enabled") and self.cur_user_data.get( if self.cur_user_data.get("Notify", "Enabled") and self.cur_user_data.get(
"Notify", "IfSendSixStar" "Notify", "IfSendSixStar"
): ):
# 发送邮件通知 # 发送邮件通知
@@ -2117,12 +2118,12 @@ class MaaManager:
if webhook.get("enabled", True): if webhook.get("enabled", True):
try: try:
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
title, title, "好羡慕~\n\nAUTO-MAS 敬上", webhook
"好羡慕~\n\nAUTO-MAS 敬上",
webhook
) )
except Exception as e: except Exception as e:
logger.error(f"用户自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"用户自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}"
)
else: else:
logger.error( logger.error(
"用户CompanyWebHookBot密钥为空, 无法发送用户单独的CompanyWebHookBot通知" "用户CompanyWebHookBot密钥为空, 无法发送用户单独的CompanyWebHookBot通知"

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -992,12 +993,12 @@ class GeneralManager:
if webhook.get("enabled", True): if webhook.get("enabled", True):
try: try:
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
title, title, f"{message_text}\n\nAUTO-MAS 敬上", webhook
f"{message_text}\n\nAUTO-MAS 敬上",
webhook
) )
except Exception as e: except Exception as e:
logger.error(f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}"
)
elif mode == "统计信息": elif mode == "统计信息":
@@ -1039,12 +1040,12 @@ class GeneralManager:
if webhook.get("enabled", True): if webhook.get("enabled", True):
try: try:
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
title, title, f"{message_text}\n\nAUTO-MAS 敬上", webhook
f"{message_text}\n\nAUTO-MAS 敬上",
webhook
) )
except Exception as e: except Exception as e:
logger.error(f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}"
)
# 发送用户单独通知 # 发送用户单独通知
if self.cur_user_data.get("Notify", "Enabled") and self.cur_user_data.get( if self.cur_user_data.get("Notify", "Enabled") and self.cur_user_data.get(
@@ -1078,18 +1079,18 @@ class GeneralManager:
# 推送CompanyWebHookBot通知 # 推送CompanyWebHookBot通知
# 发送用户自定义Webhook通知 # 发送用户自定义Webhook通知
user_webhooks = self.cur_user_data.get("Notify", {}).get("CustomWebhooks", []) user_webhooks = self.cur_user_data.get("Notify", "CustomWebhooks")
if user_webhooks: if user_webhooks:
for webhook in user_webhooks: for webhook in user_webhooks:
if webhook.get("enabled", True): if webhook.get("enabled", True):
try: try:
await Notify.CustomWebhookPush( await Notify.CustomWebhookPush(
title, title, f"{message_text}\n\nAUTO-MAS 敬上", webhook
f"{message_text}\n\nAUTO-MAS 敬上",
webhook
) )
except Exception as e: except Exception as e:
logger.error(f"用户自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}") logger.error(
f"用户自定义Webhook推送失败 ({webhook.get('name', 'Unknown')}): {e}"
)
else: else:
logger.error( logger.error(
"用户CompanyWebHookBot密钥为空, 无法发送用户单独的CompanyWebHookBot通知" "用户CompanyWebHookBot密钥为空, 无法发送用户单独的CompanyWebHookBot通知"

View File

@@ -7,6 +7,7 @@
# #
# skland-checkin-ghaction Copyright © 2023 Yanstory # skland-checkin-ghaction Copyright © 2023 Yanstory
# https://github.com/Yanstory/skland-checkin-ghaction # https://github.com/Yanstory/skland-checkin-ghaction
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2025 ClozyA # Copyright © 2025 ClozyA
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 ClozyA # Copyright © 2025 ClozyA
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,5 +1,6 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.

View File

@@ -1,6 +1,7 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software # AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2024-2025 DLmaster361 # Copyright © 2024-2025 DLmaster361
# Copyright © 2025 MoeSnowyFox # Copyright © 2025 MoeSnowyFox
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS. # This file is part of AUTO-MAS.
@@ -61,7 +62,7 @@ def is_admin() -> bool:
return False return False
# @logger.catch @logger.catch
def main(): def main():
if is_admin(): if is_admin():