feat: 初步完成后端自定义webhook适配;重构配置项管理体系

This commit is contained in:
DLmaster361
2025-10-01 11:05:50 +08:00
parent 68b1ed4238
commit e286fc8d55
12 changed files with 2181 additions and 1976 deletions

View File

@@ -25,9 +25,10 @@ import json
import uuid
import win32com.client
from copy import deepcopy
from urllib.parse import urlparse
from datetime import datetime
from pathlib import Path
from typing import List, Any, Dict, Union, Optional
from typing import List, Any, Dict, Union, Optional, TypeVar, Generic, Type
from app.utils import dpapi_encrypt, dpapi_decrypt
@@ -127,17 +128,25 @@ class DateTimeValidator(ConfigValidator):
class JSONValidator(ConfigValidator):
def __init__(self, tpye: type[dict] | type[list] = dict) -> None:
self.type = tpye
def validate(self, value: Any) -> bool:
if not isinstance(value, str):
return False
try:
json.loads(value)
return True
data = json.loads(value)
if isinstance(data, self.type):
return True
else:
return False
except json.JSONDecodeError:
return False
def correct(self, value: Any) -> str:
return value if self.validate(value) else "{ }"
return (
value if self.validate(value) else ("{ }" if self.type == dict else "[ ]")
)
class EncryptValidator(ConfigValidator):
@@ -246,6 +255,67 @@ class UserNameValidator(ConfigValidator):
return value
class URLValidator(ConfigValidator):
"""URL格式验证器"""
def __init__(
self,
schemes: list[str] | None = None,
require_netloc: bool = True,
default: str = "",
):
"""
:param schemes: 允许的协议列表, 若为 None 则允许任意协议
:param require_netloc: 是否要求必须包含网络位置, 如域名或IP
"""
self.schemes = [s.lower() for s in schemes] if schemes else None
self.require_netloc = require_netloc
self.default = default
def validate(self, value: Any) -> bool:
if value == self.default:
return True
if not isinstance(value, str):
return False
try:
parsed = urlparse(value)
except Exception:
return False
# 检查协议
if self.schemes is not None:
if not parsed.scheme or parsed.scheme.lower() not in self.schemes:
return False
else:
# 不限制协议仍要求有 scheme
if not parsed.scheme:
return False
# 检查是否包含网络位置
if self.require_netloc and not parsed.netloc:
return False
return True
def correct(self, value: Any) -> str:
if self.validate(value):
return value
if isinstance(value, str):
# 简单尝试:若看起来像域名,加上 https://
stripped = value.strip()
if stripped and not stripped.startswith(("http://", "https://")):
candidate = f"https://{stripped}"
if self.validate(candidate):
return candidate
return self.default
class ConfigItem:
"""配置项"""
@@ -537,7 +607,10 @@ class ConfigBase:
await item.unlock()
class MultipleConfig:
T = TypeVar("T", bound="ConfigBase")
class MultipleConfig(Generic[T]):
"""
多配置项管理类
@@ -550,7 +623,7 @@ class MultipleConfig:
子配置项的类型列表, 必须是 ConfigBase 的子类
"""
def __init__(self, sub_config_type: List[type]):
def __init__(self, sub_config_type: List[Type[T]]):
if not sub_config_type:
raise ValueError("子配置项类型列表不能为空")
@@ -561,13 +634,13 @@ class MultipleConfig:
f"配置类型 {config_type.__name__} 必须是 ConfigBase 的子类"
)
self.sub_config_type = sub_config_type
self.file: None | Path = None
self.sub_config_type: List[Type[T]] = sub_config_type
self.file: Path | None = None
self.order: List[uuid.UUID] = []
self.data: Dict[uuid.UUID, ConfigBase] = {}
self.data: Dict[uuid.UUID, T] = {}
self.is_locked = False
def __getitem__(self, key: uuid.UUID) -> ConfigBase:
def __getitem__(self, key: uuid.UUID) -> T:
"""允许通过 config[uuid] 访问配置项"""
if key not in self.data:
raise KeyError(f"配置项 '{key}' 不存在")
@@ -665,7 +738,9 @@ class MultipleConfig:
if self.file:
await self.save()
async def toDict(self) -> Dict[str, Union[list, dict]]:
async def toDict(
self, ignore_multi_config: bool = False, if_decrypt: bool = True
) -> Dict[str, Union[list, dict]]:
"""
将配置项转换为字典
@@ -678,7 +753,7 @@ class MultipleConfig:
]
}
for uid, config in self.items():
data[str(uid)] = await config.toDict()
data[str(uid)] = await config.toDict(ignore_multi_config, if_decrypt)
return data
async def get(self, uid: uuid.UUID) -> Dict[str, Union[list, dict]]:
@@ -721,7 +796,7 @@ class MultipleConfig:
encoding="utf-8",
)
async def add(self, config_type: type) -> tuple[uuid.UUID, ConfigBase]:
async def add(self, config_type: Type[T]) -> tuple[uuid.UUID, T]:
"""
添加一个新的配置项

View File

@@ -25,6 +25,7 @@ __author__ = "DLmaster361 <DLmaster_361@163.com>"
__license__ = "GPL-3.0 license"
from .ConfigBase import *
from .config import *
from .schema import *
__all__ = ["ConfigBase", "schema"]
__all__ = ["ConfigBase", "config", "schema"]

569
app/models/config.py Normal file
View File

@@ -0,0 +1,569 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2025 AUTO-MAS Team
# This file is part of AUTO-MAS.
# AUTO-MAS 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-MAS 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-MAS. If not, see <https://www.gnu.org/licenses/>.
# Contact: DLmaster_361@163.com
from pathlib import Path
from datetime import datetime, timedelta
from .ConfigBase import *
class Webhook(ConfigBase):
"""Webhook 配置"""
Info_Name = ConfigItem("Info", "Name", "")
Info_Enabled = ConfigItem("Info", "Enabled", True, BoolValidator())
Data_Url = ConfigItem("Data", "Url", "", URLValidator())
Data_Template = ConfigItem("Data", "Template", "")
Data_Headers = ConfigItem("Data", "Headers", "{ }", JSONValidator())
Data_Method = ConfigItem(
"Data", "Method", "POST", OptionsValidator(["POST", "GET"])
)
class GlobalConfig(ConfigBase):
"""全局配置"""
Function_HistoryRetentionTime = ConfigItem(
"Function",
"HistoryRetentionTime",
0,
OptionsValidator([7, 15, 30, 60, 90, 180, 365, 0]),
)
Function_IfAllowSleep = ConfigItem(
"Function", "IfAllowSleep", False, BoolValidator()
)
Function_IfSilence = ConfigItem("Function", "IfSilence", False, BoolValidator())
Function_BossKey = ConfigItem("Function", "BossKey", "")
Function_IfAgreeBilibili = ConfigItem(
"Function", "IfAgreeBilibili", False, BoolValidator()
)
Function_IfSkipMumuSplashAds = ConfigItem(
"Function", "IfSkipMumuSplashAds", False, BoolValidator()
)
Voice_Enabled = ConfigItem("Voice", "Enabled", False, BoolValidator())
Voice_Type = ConfigItem(
"Voice", "Type", "simple", OptionsValidator(["simple", "noisy"])
)
Start_IfSelfStart = ConfigItem("Start", "IfSelfStart", False, BoolValidator())
Start_IfMinimizeDirectly = ConfigItem(
"Start", "IfMinimizeDirectly", False, BoolValidator()
)
UI_IfShowTray = ConfigItem("UI", "IfShowTray", False, BoolValidator())
UI_IfToTray = ConfigItem("UI", "IfToTray", False, BoolValidator())
Notify_SendTaskResultTime = ConfigItem(
"Notify",
"SendTaskResultTime",
"不推送",
OptionsValidator(["不推送", "任何时刻", "仅失败时"]),
)
Notify_IfSendStatistic = ConfigItem(
"Notify", "IfSendStatistic", False, BoolValidator()
)
Notify_IfSendSixStar = ConfigItem("Notify", "IfSendSixStar", False, BoolValidator())
Notify_IfPushPlyer = ConfigItem("Notify", "IfPushPlyer", False, BoolValidator())
Notify_IfSendMail = ConfigItem("Notify", "IfSendMail", False, BoolValidator())
Notify_SMTPServerAddress = ConfigItem("Notify", "SMTPServerAddress", "")
Notify_AuthorizationCode = ConfigItem(
"Notify", "AuthorizationCode", "", EncryptValidator()
)
Notify_FromAddress = ConfigItem("Notify", "FromAddress", "")
Notify_ToAddress = ConfigItem("Notify", "ToAddress", "")
Notify_IfServerChan = ConfigItem("Notify", "IfServerChan", False, BoolValidator())
Notify_ServerChanKey = ConfigItem("Notify", "ServerChanKey", "")
Notify_CustomWebhooks = MultipleConfig([Webhook])
Update_IfAutoUpdate = ConfigItem("Update", "IfAutoUpdate", False, BoolValidator())
Update_Source = ConfigItem(
"Update",
"Source",
"GitHub",
OptionsValidator(["GitHub", "MirrorChyan", "AutoSite"]),
)
Update_ProxyAddress = ConfigItem("Update", "ProxyAddress", "")
Update_MirrorChyanCDK = ConfigItem(
"Update", "MirrorChyanCDK", "", EncryptValidator()
)
Data_UID = ConfigItem("Data", "UID", str(uuid.uuid4()), UUIDValidator())
Data_LastStatisticsUpload = ConfigItem(
"Data",
"LastStatisticsUpload",
"2000-01-01 00:00:00",
DateTimeValidator("%Y-%m-%d %H:%M:%S"),
)
Data_LastStageUpdated = ConfigItem(
"Data",
"LastStageUpdated",
"2000-01-01 00:00:00",
DateTimeValidator("%Y-%m-%d %H:%M:%S"),
)
Data_StageTimeStamp = ConfigItem(
"Data",
"StageTimeStamp",
"2000-01-01 00:00:00",
DateTimeValidator("%Y-%m-%d %H:%M:%S"),
)
Data_Stage = ConfigItem("Data", "Stage", "{ }", JSONValidator())
Data_LastNoticeUpdated = ConfigItem(
"Data",
"LastNoticeUpdated",
"2000-01-01 00:00:00",
DateTimeValidator("%Y-%m-%d %H:%M:%S"),
)
Data_IfShowNotice = ConfigItem("Data", "IfShowNotice", True, BoolValidator())
Data_Notice = ConfigItem("Data", "Notice", "{ }", JSONValidator())
Data_LastWebConfigUpdated = ConfigItem(
"Data",
"LastWebConfigUpdated",
"2000-01-01 00:00:00",
DateTimeValidator("%Y-%m-%d %H:%M:%S"),
)
Data_WebConfig = ConfigItem("Data", "WebConfig", "{ }", JSONValidator())
class QueueItem(ConfigBase):
"""队列项配置"""
related_config: dict[str, MultipleConfig] = {}
def __init__(self) -> None:
super().__init__()
self.Info_ScriptId = ConfigItem(
"Info",
"ScriptId",
"-",
MultipleUIDValidator("-", self.related_config, "ScriptConfig"),
)
class TimeSet(ConfigBase):
"""时间设置配置"""
def __init__(self) -> None:
super().__init__()
self.Info_Enabled = ConfigItem("Info", "Enabled", False, BoolValidator())
self.Info_Time = ConfigItem("Info", "Time", "00:00", DateTimeValidator("%H:%M"))
class QueueConfig(ConfigBase):
"""队列配置"""
def __init__(self) -> None:
super().__init__()
self.Info_Name = ConfigItem("Info", "Name", "新队列")
self.Info_TimeEnabled = ConfigItem(
"Info", "TimeEnabled", False, BoolValidator()
)
self.Info_StartUpEnabled = ConfigItem(
"Info", "StartUpEnabled", False, BoolValidator()
)
self.Info_AfterAccomplish = ConfigItem(
"Info",
"AfterAccomplish",
"NoAction",
OptionsValidator(
[
"NoAction",
"KillSelf",
"Sleep",
"Hibernate",
"Shutdown",
"ShutdownForce",
]
),
)
self.Data_LastTimedStart = ConfigItem(
"Data",
"LastTimedStart",
"2000-01-01 00:00",
DateTimeValidator("%Y-%m-%d %H:%M"),
)
self.TimeSet = MultipleConfig([TimeSet])
self.QueueItem = MultipleConfig([QueueItem])
class MaaUserConfig(ConfigBase):
"""MAA用户配置"""
related_config: dict[str, MultipleConfig] = {}
def __init__(self) -> None:
super().__init__()
self.Info_Name = ConfigItem("Info", "Name", "新用户", UserNameValidator())
self.Info_Id = ConfigItem("Info", "Id", "")
self.Info_Mode = ConfigItem(
"Info", "Mode", "简洁", OptionsValidator(["简洁", "详细"])
)
self.Info_StageMode = ConfigItem(
"Info",
"StageMode",
"Fixed",
MultipleUIDValidator("Fixed", self.related_config, "PlanConfig"),
)
self.Info_Server = ConfigItem(
"Info",
"Server",
"Official",
OptionsValidator(
["Official", "Bilibili", "YoStarEN", "YoStarJP", "YoStarKR", "txwy"]
),
)
self.Info_Status = ConfigItem("Info", "Status", True, BoolValidator())
self.Info_RemainedDay = ConfigItem(
"Info", "RemainedDay", -1, RangeValidator(-1, 9999)
)
self.Info_Annihilation = ConfigItem(
"Info",
"Annihilation",
"Annihilation",
OptionsValidator(
[
"Close",
"Annihilation",
"Chernobog@Annihilation",
"LungmenOutskirts@Annihilation",
"LungmenDowntown@Annihilation",
]
),
)
self.Info_Routine = ConfigItem("Info", "Routine", True, BoolValidator())
self.Info_InfrastMode = ConfigItem(
"Info",
"InfrastMode",
"Normal",
OptionsValidator(["Normal", "Rotation", "Custom"]),
)
self.Info_InfrastPath = ConfigItem(
"Info", "InfrastPath", str(Path.cwd()), FileValidator()
)
self.Info_Password = ConfigItem("Info", "Password", "", EncryptValidator())
self.Info_Notes = ConfigItem("Info", "Notes", "")
self.Info_MedicineNumb = ConfigItem(
"Info", "MedicineNumb", 0, RangeValidator(0, 9999)
)
self.Info_SeriesNumb = ConfigItem(
"Info",
"SeriesNumb",
"0",
OptionsValidator(["0", "6", "5", "4", "3", "2", "1", "-1"]),
)
self.Info_Stage = ConfigItem("Info", "Stage", "-")
self.Info_Stage_1 = ConfigItem("Info", "Stage_1", "-")
self.Info_Stage_2 = ConfigItem("Info", "Stage_2", "-")
self.Info_Stage_3 = ConfigItem("Info", "Stage_3", "-")
self.Info_Stage_Remain = ConfigItem("Info", "Stage_Remain", "-")
self.Info_IfSkland = ConfigItem("Info", "IfSkland", False, BoolValidator())
self.Info_SklandToken = ConfigItem(
"Info", "SklandToken", "", EncryptValidator()
)
self.Data_LastProxyDate = ConfigItem(
"Data", "LastProxyDate", "2000-01-01", DateTimeValidator("%Y-%m-%d")
)
self.Data_LastAnnihilationDate = ConfigItem(
"Data", "LastAnnihilationDate", "2000-01-01", DateTimeValidator("%Y-%m-%d")
)
self.Data_LastSklandDate = ConfigItem(
"Data", "LastSklandDate", "2000-01-01", DateTimeValidator("%Y-%m-%d")
)
self.Data_ProxyTimes = ConfigItem(
"Data", "ProxyTimes", 0, RangeValidator(0, 9999)
)
self.Data_IfPassCheck = ConfigItem("Data", "IfPassCheck", True, BoolValidator())
self.Data_CustomInfrastPlanIndex = ConfigItem(
"Data", "CustomInfrastPlanIndex", "0"
)
self.Task_IfWakeUp = ConfigItem("Task", "IfWakeUp", True, BoolValidator())
self.Task_IfRecruiting = ConfigItem(
"Task", "IfRecruiting", True, BoolValidator()
)
self.Task_IfBase = ConfigItem("Task", "IfBase", True, BoolValidator())
self.Task_IfCombat = ConfigItem("Task", "IfCombat", True, BoolValidator())
self.Task_IfMall = ConfigItem("Task", "IfMall", True, BoolValidator())
self.Task_IfMission = ConfigItem("Task", "IfMission", True, BoolValidator())
self.Task_IfAutoRoguelike = ConfigItem(
"Task", "IfAutoRoguelike", False, BoolValidator()
)
self.Task_IfReclamation = ConfigItem(
"Task", "IfReclamation", False, BoolValidator()
)
self.Notify_Enabled = ConfigItem("Notify", "Enabled", False, BoolValidator())
self.Notify_IfSendStatistic = ConfigItem(
"Notify", "IfSendStatistic", False, BoolValidator()
)
self.Notify_IfSendSixStar = ConfigItem(
"Notify", "IfSendSixStar", False, BoolValidator()
)
self.Notify_IfSendMail = ConfigItem(
"Notify", "IfSendMail", False, BoolValidator()
)
self.Notify_ToAddress = ConfigItem("Notify", "ToAddress", "")
self.Notify_IfServerChan = ConfigItem(
"Notify", "IfServerChan", False, BoolValidator()
)
self.Notify_ServerChanKey = ConfigItem("Notify", "ServerChanKey", "")
self.Notify_CustomWebhooks = MultipleConfig([Webhook])
class MaaConfig(ConfigBase):
"""MAA配置"""
def __init__(self) -> None:
super().__init__()
self.Info_Name = ConfigItem("Info", "Name", "新 MAA 脚本")
self.Info_Path = ConfigItem("Info", "Path", str(Path.cwd()), FolderValidator())
self.Run_TaskTransitionMethod = ConfigItem(
"Run",
"TaskTransitionMethod",
"ExitEmulator",
OptionsValidator(["NoAction", "ExitGame", "ExitEmulator"]),
)
self.Run_ProxyTimesLimit = ConfigItem(
"Run", "ProxyTimesLimit", 0, RangeValidator(0, 9999)
)
self.Run_ADBSearchRange = ConfigItem(
"Run", "ADBSearchRange", 0, RangeValidator(0, 3)
)
self.Run_RunTimesLimit = ConfigItem(
"Run", "RunTimesLimit", 3, RangeValidator(1, 9999)
)
self.Run_AnnihilationTimeLimit = ConfigItem(
"Run", "AnnihilationTimeLimit", 40, RangeValidator(1, 9999)
)
self.Run_RoutineTimeLimit = ConfigItem(
"Run", "RoutineTimeLimit", 10, RangeValidator(1, 9999)
)
self.Run_AnnihilationWeeklyLimit = ConfigItem(
"Run", "AnnihilationWeeklyLimit", True, BoolValidator()
)
self.UserData = MultipleConfig([MaaUserConfig])
class MaaPlanConfig(ConfigBase):
"""MAA计划表配置"""
def __init__(self) -> None:
super().__init__()
self.Info_Name = ConfigItem("Info", "Name", "新 MAA 计划表")
self.Info_Mode = ConfigItem(
"Info", "Mode", "ALL", OptionsValidator(["ALL", "Weekly"])
)
self.config_item_dict: dict[str, Dict[str, ConfigItem]] = {}
for group in [
"ALL",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
]:
self.config_item_dict[group] = {}
self.config_item_dict[group]["MedicineNumb"] = ConfigItem(
group, "MedicineNumb", 0, RangeValidator(0, 9999)
)
self.config_item_dict[group]["SeriesNumb"] = ConfigItem(
group,
"SeriesNumb",
"0",
OptionsValidator(["0", "6", "5", "4", "3", "2", "1", "-1"]),
)
self.config_item_dict[group]["Stage"] = ConfigItem(group, "Stage", "-")
self.config_item_dict[group]["Stage_1"] = ConfigItem(group, "Stage_1", "-")
self.config_item_dict[group]["Stage_2"] = ConfigItem(group, "Stage_2", "-")
self.config_item_dict[group]["Stage_3"] = ConfigItem(group, "Stage_3", "-")
self.config_item_dict[group]["Stage_Remain"] = ConfigItem(
group, "Stage_Remain", "-"
)
for name in [
"MedicineNumb",
"SeriesNumb",
"Stage",
"Stage_1",
"Stage_2",
"Stage_3",
"Stage_Remain",
]:
setattr(self, f"{group}_{name}", self.config_item_dict[group][name])
def get_current_info(self, name: str) -> ConfigItem:
"""获取当前的计划表配置项"""
if self.get("Info", "Mode") == "ALL":
return self.config_item_dict["ALL"][name]
elif self.get("Info", "Mode") == "Weekly":
dt = datetime.now()
if dt.time() < datetime.min.time().replace(hour=4):
dt = dt - timedelta(days=1)
today = dt.strftime("%A")
if today in self.config_item_dict:
return self.config_item_dict[today][name]
else:
return self.config_item_dict["ALL"][name]
else:
raise ValueError("非法的计划表模式")
class GeneralUserConfig(ConfigBase):
"""通用脚本用户配置"""
def __init__(self) -> None:
super().__init__()
self.Info_Name = ConfigItem("Info", "Name", "新用户", UserNameValidator())
self.Info_Status = ConfigItem("Info", "Status", True, BoolValidator())
self.Info_RemainedDay = ConfigItem(
"Info", "RemainedDay", -1, RangeValidator(-1, 9999)
)
self.Info_IfScriptBeforeTask = ConfigItem(
"Info", "IfScriptBeforeTask", False, BoolValidator()
)
self.Info_ScriptBeforeTask = ConfigItem(
"Info", "ScriptBeforeTask", str(Path.cwd()), FileValidator()
)
self.Info_IfScriptAfterTask = ConfigItem(
"Info", "IfScriptAfterTask", False, BoolValidator()
)
self.Info_ScriptAfterTask = ConfigItem(
"Info", "ScriptAfterTask", str(Path.cwd()), FileValidator()
)
self.Info_Notes = ConfigItem("Info", "Notes", "")
self.Data_LastProxyDate = ConfigItem(
"Data", "LastProxyDate", "2000-01-01", DateTimeValidator("%Y-%m-%d")
)
self.Data_ProxyTimes = ConfigItem(
"Data", "ProxyTimes", 0, RangeValidator(0, 9999)
)
self.Notify_Enabled = ConfigItem("Notify", "Enabled", False, BoolValidator())
self.Notify_IfSendStatistic = ConfigItem(
"Notify", "IfSendStatistic", False, BoolValidator()
)
self.Notify_IfSendMail = ConfigItem(
"Notify", "IfSendMail", False, BoolValidator()
)
self.Notify_ToAddress = ConfigItem("Notify", "ToAddress", "")
self.Notify_IfServerChan = ConfigItem(
"Notify", "IfServerChan", False, BoolValidator()
)
self.Notify_ServerChanKey = ConfigItem("Notify", "ServerChanKey", "")
self.Notify_CustomWebhooks = MultipleConfig([Webhook])
class GeneralConfig(ConfigBase):
"""通用配置"""
def __init__(self) -> None:
super().__init__()
self.Info_Name = ConfigItem("Info", "Name", "新通用脚本")
self.Info_RootPath = ConfigItem(
"Info", "RootPath", str(Path.cwd()), FileValidator()
)
self.Script_ScriptPath = ConfigItem(
"Script", "ScriptPath", str(Path.cwd()), FileValidator()
)
self.Script_Arguments = ConfigItem("Script", "Arguments", "")
self.Script_IfTrackProcess = ConfigItem(
"Script", "IfTrackProcess", False, BoolValidator()
)
self.Script_ConfigPath = ConfigItem(
"Script", "ConfigPath", str(Path.cwd()), FileValidator()
)
self.Script_ConfigPathMode = ConfigItem(
"Script", "ConfigPathMode", "File", OptionsValidator(["File", "Folder"])
)
self.Script_UpdateConfigMode = ConfigItem(
"Script",
"UpdateConfigMode",
"Never",
OptionsValidator(["Never", "Success", "Failure", "Always"]),
)
self.Script_LogPath = ConfigItem(
"Script", "LogPath", str(Path.cwd()), FileValidator()
)
self.Script_LogPathFormat = ConfigItem("Script", "LogPathFormat", "%Y-%m-%d")
self.Script_LogTimeStart = ConfigItem(
"Script", "LogTimeStart", 1, RangeValidator(1, 9999)
)
self.Script_LogTimeEnd = ConfigItem(
"Script", "LogTimeEnd", 1, RangeValidator(1, 9999)
)
self.Script_LogTimeFormat = ConfigItem(
"Script", "LogTimeFormat", "%Y-%m-%d %H:%M:%S"
)
self.Script_SuccessLog = ConfigItem("Script", "SuccessLog", "")
self.Script_ErrorLog = ConfigItem("Script", "ErrorLog", "")
self.Game_Enabled = ConfigItem("Game", "Enabled", False, BoolValidator())
self.Game_Type = ConfigItem(
"Game", "Type", "Emulator", OptionsValidator(["Emulator", "Client"])
)
self.Game_Path = ConfigItem("Game", "Path", str(Path.cwd()), FileValidator())
self.Game_Arguments = ConfigItem("Game", "Arguments", "")
self.Game_WaitTime = ConfigItem("Game", "WaitTime", 0, RangeValidator(0, 9999))
self.Game_IfForceClose = ConfigItem(
"Game", "IfForceClose", False, BoolValidator()
)
self.Run_ProxyTimesLimit = ConfigItem(
"Run", "ProxyTimesLimit", 0, RangeValidator(0, 9999)
)
self.Run_RunTimesLimit = ConfigItem(
"Run", "RunTimesLimit", 3, RangeValidator(1, 9999)
)
self.Run_RunTimeLimit = ConfigItem(
"Run", "RunTimeLimit", 10, RangeValidator(1, 9999)
)
self.UserData = MultipleConfig([GeneralUserConfig])
CLASS_BOOK = {"MAA": MaaConfig, "MaaPlan": MaaPlanConfig, "General": GeneralConfig}
"""配置类映射表"""

View File

@@ -75,6 +75,30 @@ class GetStageIn(BaseModel):
)
class WebhookIndexItem(BaseModel):
uid: str = Field(..., description="唯一标识符")
type: Literal["Webhook"] = Field(..., description="配置类型")
class Webhook_Info(BaseModel):
Name: Optional[str] = Field(default=None, description="Webhook名称")
Enabled: Optional[bool] = Field(default=None, description="是否启用")
class Webhook_Data(BaseModel):
url: Optional[str] = Field(default=None, description="Webhook URL")
template: Optional[str] = Field(default=None, description="消息模板")
headers: Optional[Dict[str, str]] = Field(default=None, description="自定义请求头")
method: Optional[Literal["POST", "GET"]] = Field(
default=None, description="请求方法"
)
class Webhook(BaseModel):
Info: Optional[Webhook_Info] = Field(default=None, description="Webhook基础信息")
Data: Optional[Webhook_Data] = Field(default=None, description="Webhook配置数据")
class GlobalConfig_Function(BaseModel):
HistoryRetentionTime: Optional[Literal[7, 15, 30, 60, 90, 180, 365, 0]] = Field(
None, description="历史记录保留时间, 0表示永久保存"
@@ -111,18 +135,6 @@ class GlobalConfig_UI(BaseModel):
IfToTray: Optional[bool] = Field(default=None, description="是否最小化到托盘")
class CustomWebhook(BaseModel):
id: str = Field(..., description="Webhook唯一标识")
name: str = Field(..., description="Webhook名称")
url: str = Field(..., description="Webhook URL")
template: str = Field(..., description="消息模板")
enabled: bool = Field(default=True, description="是否启用")
headers: Optional[Dict[str, str]] = Field(default=None, description="自定义请求头")
method: Optional[Literal["POST", "GET"]] = Field(
default="POST", description="请求方法"
)
class GlobalConfig_Notify(BaseModel):
SendTaskResultTime: Optional[Literal["不推送", "任何时刻", "仅失败时"]] = Field(
default=None, description="任务结果推送时机"
@@ -143,9 +155,6 @@ class GlobalConfig_Notify(BaseModel):
default=None, description="是否使用ServerChan推送"
)
ServerChanKey: Optional[str] = Field(default=None, description="ServerChan推送密钥")
CustomWebhooks: Optional[List[CustomWebhook]] = Field(
default=None, description="自定义Webhook列表"
)
class GlobalConfig_Update(BaseModel):
@@ -313,9 +322,6 @@ class MaaUserConfig_Notify(BaseModel):
default=None, description="是否使用Server酱推送"
)
ServerChanKey: Optional[str] = Field(default=None, description="ServerChanKey")
CustomWebhooks: Optional[List[CustomWebhook]] = Field(
default=None, description="用户自定义Webhook列表"
)
class GeneralUserConfig_Notify(BaseModel):
@@ -618,6 +624,46 @@ class UserSetIn(UserInBase):
jsonFile: str = Field(..., description="JSON文件路径, 用于导入自定义基建文件")
class WebhookInBase(BaseModel):
scriptId: Optional[str] = Field(
default=None, description="所属脚本ID, 获取全局设置的Webhook数据时无需携带"
)
userId: Optional[str] = Field(
default=None, description="所属用户ID, 获取全局设置的Webhook数据时无需携带"
)
class WebhookGetIn(WebhookInBase):
webhookId: Optional[str] = Field(
default=None, description="Webhook ID, 未携带时表示获取所有Webhook数据"
)
class WebhookGetOut(OutBase):
index: List[WebhookIndexItem] = Field(..., description="Webhook索引列表")
data: Dict[str, Webhook] = Field(
..., description="Webhook数据字典, key来自于index列表的uid"
)
class WebhookCreateOut(OutBase):
webhookId: str = Field(..., description="新创建的Webhook ID")
data: Webhook = Field(..., description="Webhook配置数据")
class WebhookUpdateIn(WebhookInBase):
webhookId: str = Field(..., description="Webhook ID")
data: Webhook = Field(..., description="Webhook更新数据")
class WebhookDeleteIn(WebhookInBase):
webhookId: str = Field(..., description="Webhook ID")
class WebhookReorderIn(WebhookInBase):
indexList: List[str] = Field(..., description="Webhook ID列表, 按新顺序排列")
class PlanCreateIn(BaseModel):
type: Literal["MaaPlan"]