Compare commits

...

17 Commits

Author SHA1 Message Date
DLmaster361
fba5395bf0 Merge branch 'dev' 2025-05-04 16:44:46 +08:00
DLmaster361
2c4508ee16 fix: 修复版本号错误 2025-05-04 16:43:49 +08:00
d239443555 chore(release): 发版 4.3.6.2 2025-05-04 16:36:36 +08:00
e45ad08fab refactor(notification): 重构 Server酱 推送服务 2025-05-04 16:25:46 +08:00
ddf5d26c4b refactor(notification): 重构 Server酱 推送服务 2025-05-04 16:12:45 +08:00
DLmaster361
ce74dcf912 Merge branch 'dev' of github.com:DLmaster361/AUTO_MAA into dev 2025-05-04 15:18:31 +08:00
DLmaster361
41412e1ef4 feat(ui): 新增无人值守模式 2025-05-04 15:18:26 +08:00
雪影
1395d48cd0 头部信息居中 (#43)
Co-authored-by: DLmaster361 <DLmaster_361@163.com>
2025-05-04 13:57:56 +08:00
DLmaster361
418c3d4742 fix(ui): 修复隐藏到托盘时,托盘无法退出主程序的问题 2025-05-04 11:12:34 +08:00
DLmaster361
17ec962a22 fix(ui): 修复软件窗口相关问题
- 修复软件窗口最大化异常问题
- 修复异常操作导致窗口离开屏幕后难以复原的问题
- 修正剩余理智关卡文案
- 主窗口显示版本号
2025-05-04 03:14:14 +08:00
DLmaster361
989ee73549 feat(maa): 单次自动代理任务中,已完成的子任务在重复执行时不再启用 2025-05-02 11:36:40 +08:00
DLmaster361
7e452e1253 Merge branch 'dev' 2025-05-02 00:40:55 +08:00
DLmaster361
5bdb5c8025 fix: 详细配置模式下更新也由AUTO统筹配置 2025-05-02 00:39:58 +08:00
DLmaster361
924a5fea0b feat: 适配6周年游戏变动的优化
- 用户设置中新增连战次数与剩余理智关卡两项配置项
- 支持自动代理时更新MAA
- 移除增效任务
2025-05-01 21:31:09 +08:00
DLmaster361
b51a57a6ee fix: 修复无法建立网络连接时软件卡死问题 2025-04-29 09:40:11 +08:00
DLmaster361
4079188881 fix: 脚本实例任务完成后即时更新状态信息 2025-04-28 20:41:08 +08:00
DLmaster361
174163e305 feat: 模拟器路径适配快捷方式 2025-04-28 18:35:56 +08:00
17 changed files with 835 additions and 468 deletions

View File

@@ -135,18 +135,3 @@ jobs:
- name: Upload Release to Server
run: |
scp -r artifacts/* ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_IP }}:/home/user/files/AUTO_MAA/
- name: Install obsutil
run: |
wget https://obs-community.obs.cn-north-1.myhuaweicloud.com/obsutil/current/obsutil_linux_amd64.tar.gz
tar -xzvf obsutil_linux_amd64.tar.gz --strip-components=1
chmod 755 obsutil
./obsutil version
- name: Upload Release to Huawei OBS
env:
OBS_AK: ${{ secrets.OBS_AK }}
OBS_SK: ${{ secrets.OBS_SK }}
OBS_ENDPOINT: ${{ secrets.OBS_ENDPOINT }}
OBS_BUCKET: ${{ secrets.OBS_BUCKET }}
run: |
./obsutil config -i $OBS_AK -k $OBS_SK -e $OBS_ENDPOINT
./obsutil cp artifacts/ obs://$OBS_BUCKET/releases/ -r -f

View File

@@ -1,20 +1,20 @@
# AUTO_MAA
MAA多账号管理与自动化软件
!["软件图标"](https://github.com/DLmaster361/AUTO_MAA/blob/main/resources/images/AUTO_MAA.png "软件图标")
<h1 align="center">AUTO_MAA</h1>
<p align="center">
MAA多账号管理与自动化软件<br><br>
<img alt="软件图标" src="https://github.com/DLmaster361/AUTO_MAA/blob/main/resources/images/AUTO_MAA.png">
</p>
---
</h1>
[![GitHub Stars](https://img.shields.io/github/stars/DLmaster361/AUTO_MAA?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/stargazers)
[![GitHub Forks](https://img.shields.io/github/forks/DLmaster361/AUTO_MAA?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/network)
[![GitHub Downloads](https://img.shields.io/github/downloads/DLmaster361/AUTO_MAA/total?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/releases/latest)
[![GitHub Issues](https://img.shields.io/github/issues/DLmaster361/AUTO_MAA?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/issues)
[![GitHub Contributors](https://img.shields.io/github/contributors/DLmaster361/AUTO_MAA?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/graphs/contributors)
[![GitHub License](https://img.shields.io/github/license/DLmaster361/AUTO_MAA?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/blob/main/LICENSE)
</div>
<p align="center">
<a href="https://github.com/DLmaster361/AUTO_MAA/stargazers"><img alt="GitHub Stars" src="https://img.shields.io/github/stars/DLmaster361/AUTO_MAA?style=flat-square"></a>
<a href="https://github.com/DLmaster361/AUTO_MAA/network"><img alt="GitHub Forks" src="https://img.shields.io/github/forks/DLmaster361/AUTO_MAA?style=flat-square"></a>
<a href="https://github.com/DLmaster361/AUTO_MAA/releases/latest"><img alt="GitHub Downloads" src="https://img.shields.io/github/downloads/DLmaster361/AUTO_MAA/total?style=flat-square"></a>
<a href="https://github.com/DLmaster361/AUTO_MAA/issues"><img alt="GitHub Issues" src="https://img.shields.io/github/issues/DLmaster361/AUTO_MAA?style=flat-square"></a>
<a href="https://github.com/DLmaster361/AUTO_MAA/graphs/contributors"><img alt="GitHub Contributors" src="https://img.shields.io/github/contributors/DLmaster361/AUTO_MAA?style=flat-square"></a>
<a href="https://github.com/DLmaster361/AUTO_MAA/blob/main/LICENSE"><img alt="GitHub License" src="https://img.shields.io/github/license/DLmaster361/AUTO_MAA?style=flat-square"></a>
<a href="https://mirrorchyan.com/zh/projects?rid=AUTO_MAA"><img alt="mirrorc" src="https://img.shields.io/badge/Mirror%E9%85%B1-%239af3f6?logo=countingworkspro&logoColor=4f46e5"></a>
</p>
## 软件介绍

View File

@@ -103,6 +103,9 @@ class GlobalConfig(QConfig):
"Function", "IfSilence", False, BoolValidator()
)
self.function_BossKey = ConfigItem("Function", "BossKey", "")
self.function_UnattendedMode = ConfigItem(
"Function", "UnattendedMode", False, BoolValidator()
)
self.function_IfAgreeBilibili = ConfigItem(
"Function", "IfAgreeBilibili", False, BoolValidator()
)
@@ -409,27 +412,24 @@ class MaaConfig(QConfig):
"ExitEmulator",
OptionsValidator(["NoAction", "ExitGame", "ExitEmulator"]),
)
self.RunSet_EnhanceTask = OptionsConfigItem(
"RunSet",
"EnhanceTask",
"None",
OptionsValidator(["None", "KillADB", "KillEmulator", "KillADB&Emulator"]),
)
self.RunSet_ProxyTimesLimit = RangeConfigItem(
"RunSet", "ProxyTimesLimit", 0, RangeValidator(0, 1024)
)
self.RunSet_RunTimesLimit = RangeConfigItem(
"RunSet", "RunTimesLimit", 3, RangeValidator(1, 1024)
)
self.RunSet_AnnihilationTimeLimit = RangeConfigItem(
"RunSet", "AnnihilationTimeLimit", 40, RangeValidator(1, 1024)
)
self.RunSet_RoutineTimeLimit = RangeConfigItem(
"RunSet", "RoutineTimeLimit", 10, RangeValidator(1, 1024)
)
self.RunSet_RunTimesLimit = RangeConfigItem(
"RunSet", "RunTimesLimit", 3, RangeValidator(1, 1024)
)
self.RunSet_AnnihilationWeeklyLimit = ConfigItem(
"RunSet", "AnnihilationWeeklyLimit", False, BoolValidator()
)
self.RunSet_AutoUpdateMaa = ConfigItem(
"RunSet", "AutoUpdateMaa", False, BoolValidator()
)
def toDict(self, serialize=True):
"""convert config items to `dict`"""
@@ -521,17 +521,22 @@ class MaaUserConfig(QConfig):
"Info", "Annihilation", False, BoolValidator()
)
self.Info_Routine = ConfigItem("Info", "Routine", False, BoolValidator())
self.Info_Infrastructure = ConfigItem(
"Info", "Infrastructure", False, BoolValidator()
self.Info_InfrastMode = OptionsConfigItem(
"Info",
"InfrastMode",
"Normal",
OptionsValidator(["Normal", "Rotation", "Custom"]),
)
self.Info_Password = ConfigItem("Info", "Password", "")
self.Info_Notes = ConfigItem("Info", "Notes", "")
self.Info_MedicineNumb = ConfigItem(
"Info", "MedicineNumb", 0, RangeValidator(0, 1024)
)
self.Info_SeriesNumb = ConfigItem("Info", "SeriesNumb", 1, RangeValidator(1, 6))
self.Info_GameId = ConfigItem("Info", "GameId", "-")
self.Info_GameId_1 = ConfigItem("Info", "GameId_1", "-")
self.Info_GameId_2 = ConfigItem("Info", "GameId_2", "-")
self.Info_GameId_Remain = ConfigItem("Info", "GameId_Remain", "-")
self.Data_LastProxyDate = ConfigItem("Data", "LastProxyDate", "2000-01-01")
self.Data_LastAnnihilationDate = ConfigItem(
@@ -541,6 +546,9 @@ class MaaUserConfig(QConfig):
"Data", "ProxyTimes", 0, RangeValidator(0, 1024)
)
self.Data_IfPassCheck = ConfigItem("Data", "IfPassCheck", True, BoolValidator())
self.Data_CustomInfrastPlanIndex = ConfigItem(
"Data", "CustomInfrastPlanIndex", "0"
)
def toDict(self, serialize=True):
"""convert config items to `dict`"""
@@ -609,7 +617,7 @@ class MaaUserConfig(QConfig):
class AppConfig(GlobalConfig):
VERSION = "4.3.4.0"
VERSION = "4.3.6.2"
gameid_refreshed = Signal()
PASSWORD_refreshed = Signal()
@@ -628,6 +636,7 @@ class AppConfig(GlobalConfig):
self.gameid_path = self.app_path / "data/gameid.txt"
self.version_path = self.app_path / "resources/version.json"
self.main_window = None
self.PASSWORD = ""
self.running_list = []
self.silence_list = []
@@ -1289,6 +1298,10 @@ class AppConfig(GlobalConfig):
user_config.set(
user_config.Data_IfPassCheck, info["Config"]["Data"]["IfPassCheck"]
)
user_config.set(
user_config.Data_CustomInfrastPlanIndex,
info["Config"]["Data"]["CustomInfrastPlanIndex"],
)
self.user_info_changed.emit()

View File

@@ -29,17 +29,15 @@ from loguru import logger
from PySide6.QtCore import Qt
from qfluentwidgets import InfoBar, InfoBarPosition
from .config import Config
class _MainInfoBar:
"""信息通知栏"""
def __init__(self, main_window=None):
self.main_window = main_window
def push_info_bar(self, mode: str, title: str, content: str, time: int):
"""推送到信息通知栏"""
if self.main_window is None:
if Config.main_window is None:
logger.error("信息通知栏未设置父窗口")
return None
@@ -61,7 +59,7 @@ class _MainInfoBar:
isClosable=True,
position=InfoBarPosition.TOP_RIGHT,
duration=time,
parent=self.main_window,
parent=Config.main_window,
)
else:
logger.error(f"未知的通知栏模式: {mode}")

View File

@@ -78,6 +78,8 @@ class _Network(QThread):
def get_json(self, url: str) -> None:
"""通过get方法获取json数据"""
response = None
for _ in range(self.max_retries):
try:
response = requests.get(url, timeout=self.timeout)
@@ -94,7 +96,9 @@ class _Network(QThread):
self.loop.quit()
def get_file(self, url: str, path: Path) -> None:
"""通过get方法获取json数据"""
"""通过get方法下载文件"""
response = None
try:
response = requests.get(url, timeout=10)

View File

@@ -154,6 +154,7 @@ class Task(QThread):
Config.running_list.remove(task[2])
task[1] = "完成"
self.update_task_list.emit(self.task_list)
logger.info(f"任务完成:{task[0]}")
self.push_info_bar.emit("info", "任务完成", task[0], 3000)
@@ -172,10 +173,9 @@ class _TaskManager(QObject):
create_gui = Signal(Task)
connect_gui = Signal(Task)
def __init__(self, main_window=None):
def __init__(self):
super(_TaskManager, self).__init__()
self.main_window = main_window
self.task_dict: Dict[str, Task] = {}
def add_task(
@@ -278,7 +278,7 @@ class _TaskManager(QObject):
}
choice = ProgressRingMessageBox(
self.main_window,
Config.main_window,
f"{mode_book[Config.queue_dict[name]["Config"].get(Config.queue_dict[name]["Config"].queueSet_AfterAccomplish)]}倒计时",
)
if choice.exec():
@@ -324,7 +324,7 @@ class _TaskManager(QObject):
def push_dialog(self, name: str, title: str, content: str):
"""推送对话框"""
choice = MessageBox(title, content, self.main_window)
choice = MessageBox(title, content, Config.main_window)
choice.yesButton.setText("")
choice.cancelButton.setText("")

View File

@@ -55,6 +55,9 @@ class _MainTimer(QWidget):
"""长时间定期检定任务"""
Config.get_gameid()
Config.main_window.setting.show_notice()
if Config.get(Config.update_IfAutoUpdate):
Config.main_window.setting.check_update()
def timed_start(self):
"""定时启动代理任务"""

View File

@@ -28,11 +28,12 @@ v4.3
from loguru import logger
from PySide6.QtCore import QObject, Signal, QEventLoop, QFileSystemWatcher, QTimer
import json
from datetime import datetime, timedelta
import subprocess
import shutil
import time
import re
import win32com.client
from datetime import datetime, timedelta
from pathlib import Path
from jinja2 import Environment, FileSystemLoader
from typing import Union, List, Dict
@@ -90,6 +91,8 @@ class MaaManager(QObject):
self.interrupt.connect(self.quit_monitor)
self.maa_version = None
self.maa_update_package = ""
self.task_dict = {}
self.set = config["Config"].toDict()
self.data = {}
@@ -262,6 +265,67 @@ class MaaManager(QObject):
]
)
# 解析任务构成
if user_data["Info"]["Mode"] == "简洁":
if mode == "Annihilation":
self.task_dict = {
"WakeUp": "True",
"Recruiting": "False",
"Base": "False",
"Combat": "True",
"Mission": "False",
"Mall": "False",
"AutoRoguelike": "False",
"Reclamation": "False",
}
elif mode == "Routine":
self.task_dict = {
"WakeUp": "True",
"Recruiting": "True",
"Base": "True",
"Combat": "True",
"Mission": "True",
"Mall": "True",
"AutoRoguelike": "False",
"Reclamation": "False",
}
elif user_data["Info"]["Mode"] == "详细":
with (self.data[user[2]]["Path"] / f"{mode}/gui.json").open(
mode="r", encoding="utf-8"
) as f:
data = json.load(f)
self.task_dict = {
"WakeUp": data["Configurations"]["Default"][
"TaskQueue.WakeUp.IsChecked"
],
"Recruiting": data["Configurations"]["Default"][
"TaskQueue.Recruiting.IsChecked"
],
"Base": data["Configurations"]["Default"][
"TaskQueue.Base.IsChecked"
],
"Combat": data["Configurations"]["Default"][
"TaskQueue.Combat.IsChecked"
],
"Mission": data["Configurations"]["Default"][
"TaskQueue.Mission.IsChecked"
],
"Mall": data["Configurations"]["Default"][
"TaskQueue.Mall.IsChecked"
],
"AutoRoguelike": data["Configurations"]["Default"][
"TaskQueue.AutoRoguelike.IsChecked"
],
"Reclamation": data["Configurations"]["Default"][
"TaskQueue.Reclamation.IsChecked"
],
}
# 尝试次数循环
for i in range(self.set["RunSet"]["RunTimesLimit"]):
@@ -287,6 +351,41 @@ class MaaManager(QObject):
self.emulator_arguments = set["Configurations"]["Default"][
"Start.EmulatorAddCommand"
].split()
# 如果是快捷方式,进行解析
if (
self.emulator_path.suffix == ".lnk"
and self.emulator_path.exists()
):
try:
shell = win32com.client.Dispatch("WScript.Shell")
shortcut = shell.CreateShortcut(str(self.emulator_path))
self.emulator_path = Path(shortcut.TargetPath)
self.emulator_arguments = shortcut.Arguments.split()
except Exception as e:
logger.error(
f"{self.name} | 解析快捷方式时出现异常:{e}"
)
self.push_info_bar.emit(
"error",
"解析快捷方式时出现异常",
"请检查快捷方式",
-1,
)
self.if_open_emulator = True
break
elif not self.emulator_path.exists():
logger.error(
f"{self.name} | 模拟器快捷方式不存在:{self.emulator_path}"
)
self.push_info_bar.emit(
"error",
"启动模拟器时出现异常",
"模拟器快捷方式不存在",
-1,
)
self.if_open_emulator = True
break
self.ADB_path = Path(
set["Configurations"]["Default"]["Connect.AdbPath"]
)
@@ -309,10 +408,7 @@ class MaaManager(QObject):
== "True"
)
# 增强任务:任务开始前强杀ADB
if "ADB" in self.set["RunSet"]["EnhanceTask"]:
System.kill_process(self.ADB_path)
else:
# 任务开始前释放ADB
try:
subprocess.run(
[self.ADB_path, "disconnect", self.ADB_address],
@@ -359,13 +455,40 @@ class MaaManager(QObject):
self.start_monitor(start_time, mode_book[mode])
if self.maa_result == "Success!":
# 标记任务完成
run_book[mode] = True
# 从配置文件中解析所需信息
with self.maa_set_path.open(
mode="r", encoding="utf-8"
) as f:
data = json.load(f)
# 记录自定义基建索引
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"
]
logger.info(
f"{self.name} | 用户: {user[0]} - MAA进程完成代理任务"
)
run_book[mode] = True
self.update_log_text.emit(
"检测到MAA进程完成代理任务\n正在等待相关程序结束\n请等待10s"
)
for _ in range(10):
if self.isInterruptionRequested:
break
@@ -382,13 +505,30 @@ class MaaManager(QObject):
# 无命令行中止MAA与其子程序
System.kill_process(self.maa_exe_path)
if "Emulator" in self.set["RunSet"]["EnhanceTask"]:
System.kill_process(self.emulator_path)
else:
# 中止模拟器进程
self.emulator_process.terminate()
self.emulator_process.wait()
self.if_open_emulator = True
# 从配置文件中解析所需信息
with self.maa_set_path.open(
mode="r", encoding="utf-8"
) as f:
data = json.load(f)
# 记录更新包路径
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(
"用户自动代理出现异常!",
@@ -404,10 +544,7 @@ class MaaManager(QObject):
# 移除静默进程标记
Config.silence_list.remove(self.emulator_path)
# 增强任务:任务结束后强杀ADB和模拟器或释放进程
if "ADB" in self.set["RunSet"]["EnhanceTask"]:
System.kill_process(self.ADB_path)
else:
# 任务结束后释放ADB
try:
subprocess.run(
[self.ADB_path, "disconnect", self.ADB_address],
@@ -424,14 +561,35 @@ class MaaManager(QObject):
"请检查MAA中ADB路径设置",
-1,
)
# 任务结束后再次手动中止模拟器进程,防止退出不彻底
if self.if_kill_emulator:
if "Emulator" in self.set["RunSet"]["EnhanceTask"]:
System.kill_process(self.emulator_path)
else:
self.emulator_process.terminate()
self.emulator_process.wait()
self.if_open_emulator = True
# 执行MAA解压更新动作
if self.maa_update_package:
logger.info(
f"{self.name} | 检测到MAA更新正在执行更新动作"
)
self.update_log_text.emit(
f"检测到MAA存在更新\nMAA正在执行更新动作\n请等待10s"
)
self.set_maa("更新MAA", None)
subprocess.Popen(
[self.maa_exe_path],
creationflags=subprocess.CREATE_NO_WINDOW,
)
for _ in range(10):
if self.isInterruptionRequested:
break
time.sleep(1)
System.kill_process(self.maa_exe_path)
logger.info(f"{self.name} | 更新动作结束")
# 记录剿灭情况
if (
mode == "Annihilation"
@@ -747,7 +905,7 @@ class MaaManager(QObject):
self.update_log_text.emit("".join(logs))
# 获取MAA版本号
if not self.maa_version:
if not self.set["RunSet"]["AutoUpdateMaa"] and not self.maa_version:
section_match = re.search(r"={35}(.*?)={35}", log, re.DOTALL)
if section_match:
@@ -780,26 +938,53 @@ class MaaManager(QObject):
else:
self.weekly_annihilation_limit_reached = False
if mode == "自动代理_日常" and "任务出错: Fight" in log:
self.maa_result = "MAA未能实际执行任务"
elif "任务出错: StartUp" in log:
if "任务出错: StartUp" in log:
self.maa_result = "MAA未能正确登录PRTS"
elif "任务已全部完成!" in log:
if "完成任务: StartUp" in log:
self.task_dict["WakeUp"] = "False"
if "完成任务: Recruit" in log:
self.task_dict["Recruiting"] = "False"
if "完成任务: Infrast" in log:
self.task_dict["Base"] = "False"
if "完成任务: Fight" in log or "剿灭任务失败" in log:
self.task_dict["Combat"] = "False"
if "完成任务: Mall" in log:
self.task_dict["Mall"] = "False"
if "完成任务: Award" in log:
self.task_dict["Mission"] = "False"
if "完成任务: Roguelike" in log:
self.task_dict["AutoRoguelike"] = "False"
if "完成任务: Reclamation" in log:
self.task_dict["Reclamation"] = "False"
if all(v == "False" for v in self.task_dict.values()):
self.maa_result = "Success!"
else:
self.maa_result = "MAA部分任务执行失败"
elif "请「检查连接设置」或「尝试重启模拟器与 ADB」或「重启电脑」" in log:
self.maa_result = "MAA的ADB连接异常"
elif "未检测到任何模拟器" in log:
self.maa_result = "MAA未检测到任何模拟器"
elif "已停止" in log:
self.maa_result = "MAA在完成任务前中止"
elif "MaaAssistantArknights GUI exited" in log:
self.maa_result = "MAA在完成任务前退出"
elif datetime.now() - latest_time > timedelta(
minutes=self.set["RunSet"][time_book[mode]]
):
self.maa_result = "MAA进程超时"
elif self.isInterruptionRequested:
self.maa_result = "任务被手动中止"
else:
self.maa_result = "Wait"
@@ -859,7 +1044,7 @@ class MaaManager(QObject):
"""配置MAA运行参数"""
logger.info(f"{self.name} | 配置MAA运行参数: {mode}/{index}")
if "设置MAA" not in self.mode:
if "设置MAA" not in self.mode and "更新MAA" not in mode:
user_data = self.data[index]["Config"]
# 配置MAA前关闭可能未正常退出的MAA进程
@@ -874,7 +1059,7 @@ class MaaManager(QObject):
self.config_path / "Default/gui.json",
self.maa_set_path,
)
elif (mode == "设置MAA_全局") or (
elif (mode in ["设置MAA_全局", "更新MAA"]) or (
("自动代理" in mode or "人工排查" in mode)
and user_data["Info"]["Mode"] == "简洁"
):
@@ -901,7 +1086,7 @@ class MaaManager(QObject):
with self.maa_set_path.open(mode="r", encoding="utf-8") as f:
data = json.load(f)
if "设置MAA" not in mode and (
if ("设置MAA" not in self.mode and "更新MAA" not in mode) and (
(
user_data["Info"]["Mode"] == "简洁"
and user_data["Info"]["Server"] == "Bilibili"
@@ -949,10 +1134,20 @@ class MaaManager(QObject):
data["Configurations"]["Default"][
"Start.RunDirectly"
] = "True" # 启动MAA后直接运行
data["Configurations"]["Default"]["Start.OpenEmulatorAfterLaunch"] = (
"True" if self.if_open_emulator else "False"
data["Configurations"]["Default"]["Start.OpenEmulatorAfterLaunch"] = str(
self.if_open_emulator
) # 启动MAA后自动开启模拟器
data["Global"][
"VersionUpdate.ScheduledUpdateCheck"
] = "False" # 定时检查更新
data["Global"]["VersionUpdate.AutoDownloadUpdatePackage"] = str(
self.set["RunSet"]["AutoUpdateMaa"]
) # 自动下载更新包
data["Global"][
"VersionUpdate.AutoInstallUpdatePackage"
] = "False" # 自动安装更新包
if Config.get(Config.function_IfSilence):
data["Global"]["Start.MinimizeDirectly"] = "True" # 启动MAA后直接最小化
data["Global"]["GUI.UseTray"] = "True" # 显示托盘图标
@@ -970,49 +1165,53 @@ class MaaManager(QObject):
"Info"
]["Id"]
# 按预设设定任务
data["Configurations"]["Default"]["TaskQueue.Recruiting.IsChecked"] = (
self.task_dict["Recruiting"]
) # 自动公招
data["Configurations"]["Default"]["TaskQueue.Base.IsChecked"] = (
self.task_dict["Base"]
) # 基建换班
data["Configurations"]["Default"]["TaskQueue.Combat.IsChecked"] = (
self.task_dict["Combat"]
) # 刷理智
data["Configurations"]["Default"]["TaskQueue.Mission.IsChecked"] = (
self.task_dict["Mission"]
) # 领取奖励
data["Configurations"]["Default"]["TaskQueue.Mall.IsChecked"] = (
self.task_dict["Mall"]
) # 获取信用及购物
data["Configurations"]["Default"]["TaskQueue.AutoRoguelike.IsChecked"] = (
self.task_dict["AutoRoguelike"]
) # 自动肉鸽
data["Configurations"]["Default"]["TaskQueue.Reclamation.IsChecked"] = (
self.task_dict["Reclamation"]
) # 生息演算
if user_data["Info"]["Mode"] == "简洁":
data["Global"][
"VersionUpdate.ScheduledUpdateCheck"
] = "False" # 定时检查更新
data["Global"][
"VersionUpdate.AutoDownloadUpdatePackage"
] = "False" # 自动下载更新包
data["Global"][
"VersionUpdate.AutoInstallUpdatePackage"
] = "False" # 自动安装更新包
data["Configurations"]["Default"][
"TaskQueue.WakeUp.IsChecked"
] = "True" # 开始唤醒
data["Configurations"]["Default"]["Start.ClientType"] = user_data[
"Info"
][
"Server"
] # 客户端类型
# 整理任务顺序
data["Configurations"]["Default"]["TaskQueue.Order.WakeUp"] = "0"
data["Configurations"]["Default"]["TaskQueue.Order.Recruiting"] = "1"
data["Configurations"]["Default"]["TaskQueue.Order.Base"] = "2"
data["Configurations"]["Default"]["TaskQueue.Order.Combat"] = "3"
data["Configurations"]["Default"]["TaskQueue.Order.Mall"] = "4"
data["Configurations"]["Default"]["TaskQueue.Order.Mission"] = "5"
data["Configurations"]["Default"]["TaskQueue.Order.AutoRoguelike"] = "6"
data["Configurations"]["Default"]["TaskQueue.Order.Reclamation"] = "7"
if "剿灭" in mode:
data["Configurations"]["Default"][
"TaskQueue.WakeUp.IsChecked"
] = "True" # 开始唤醒
data["Configurations"]["Default"][
"TaskQueue.Recruiting.IsChecked"
] = "False" # 自动公招
data["Configurations"]["Default"][
"TaskQueue.Base.IsChecked"
] = "False" # 基建换班
data["Configurations"]["Default"][
"TaskQueue.Combat.IsChecked"
] = "True" # 刷理智
data["Configurations"]["Default"][
"TaskQueue.Mission.IsChecked"
] = "False" # 领取奖励
data["Configurations"]["Default"][
"TaskQueue.Mall.IsChecked"
] = "False" # 获取信用及购物
data["Configurations"]["Default"][
"TaskQueue.AutoRoguelike.IsChecked"
] = "False" # 自动肉鸽
data["Configurations"]["Default"][
"TaskQueue.Reclamation.IsChecked"
] = "False" # 生息演算
data["Configurations"]["Default"][
"MainFunction.Stage1"
] = "Annihilation" # 主关卡
@@ -1049,31 +1248,6 @@ class MaaManager(QObject):
elif "日常" in mode:
data["Configurations"]["Default"][
"TaskQueue.WakeUp.IsChecked"
] = "True" # 开始唤醒
data["Configurations"]["Default"][
"TaskQueue.Recruiting.IsChecked"
] = "True" # 自动公招
data["Configurations"]["Default"][
"TaskQueue.Base.IsChecked"
] = "True" # 基建换班
data["Configurations"]["Default"][
"TaskQueue.Combat.IsChecked"
] = "True" # 刷理智
data["Configurations"]["Default"][
"TaskQueue.Mission.IsChecked"
] = "True" # 领取奖励
data["Configurations"]["Default"][
"TaskQueue.Mall.IsChecked"
] = "True" # 获取信用及购物
data["Configurations"]["Default"][
"TaskQueue.AutoRoguelike.IsChecked"
] = "False" # 自动肉鸽
data["Configurations"]["Default"][
"TaskQueue.Reclamation.IsChecked"
] = "False" # 生息演算
data["Configurations"]["Default"]["MainFunction.UseMedicine"] = (
"False" if user_data["Info"]["MedicineNumb"] == 0 else "True"
) # 吃理智药
@@ -1097,55 +1271,47 @@ class MaaManager(QObject):
if user_data["Info"]["GameId_2"] != "-"
else ""
) # 备选关卡2
data["Configurations"]["Default"][
"Fight.RemainingSanityStage"
] = "" # 剩余理智关卡
# 连战次数
if user_data["Info"]["GameId"] == "1-7":
data["Configurations"]["Default"]["Fight.RemainingSanityStage"] = (
user_data["Info"]["GameId_Remain"]
if user_data["Info"]["GameId_Remain"] != "-"
else ""
) # 剩余理智关卡
data["Configurations"]["Default"][
"MainFunction.Series.Quantity"
] = "6"
else:
data["Configurations"]["Default"][
"MainFunction.Series.Quantity"
] = "1"
] = str(
user_data["Info"]["SeriesNumb"]
) # 连战次数
data["Configurations"]["Default"][
"Penguin.IsDrGrandet"
] = "False" # 博朗台模式
data["Configurations"]["Default"][
"GUI.CustomStageCode"
] = "True" # 手动输入关卡名
# 备选关卡
if (
user_data["Info"]["GameId_1"] == "-"
and user_data["Info"]["GameId_2"] == "-"
):
data["Configurations"]["Default"][
"GUI.UseAlternateStage"
] = "False"
else:
data["Configurations"]["Default"][
"GUI.UseAlternateStage"
] = "True"
] = "True" # 备选关卡
data["Configurations"]["Default"][
"Fight.UseRemainingSanityStage"
] = "False" # 使用剩余理智
] = "True" # 使用剩余理智
data["Configurations"]["Default"][
"Fight.UseExpiringMedicine"
] = "True" # 无限吃48小时内过期的理智药
# 自定义基建配置
if user_data["Info"]["Infrastructure"]:
if user_data["Info"]["InfrastMode"] == "Custom":
if (
self.data[index]["Path"]
/ "Infrastructure/infrastructure.json"
).exists():
data["Configurations"]["Default"][
"Infrast.CustomInfrastEnabled"
] = "True" # 启用自定义基建配置
"Infrast.InfrastMode"
] = "Custom" # 基建模式
data["Configurations"]["Default"][
"Infrast.CustomInfrastPlanIndex"
] = "1" # 自定义基建配置索引
] = user_data["Data"][
"CustomInfrastPlanIndex"
] # 自定义基建配置索引
data["Configurations"]["Default"][
"Infrast.DefaultInfrast"
] = "user_defined" # 内置配置
@@ -1170,11 +1336,13 @@ class MaaManager(QObject):
)
data["Configurations"]["Default"][
"Infrast.CustomInfrastEnabled"
] = "False" # 禁用自定义基建配置
] = "Normal" # 基建模式
else:
data["Configurations"]["Default"][
"Infrast.CustomInfrastEnabled"
] = "False" # 禁用自定义基建配置
"Infrast.InfrastMode"
] = user_data["Info"][
"InfrastMode"
] # 基建模式
elif user_data["Info"]["Mode"] == "详细":
@@ -1207,19 +1375,22 @@ class MaaManager(QObject):
if user_data["Info"]["GameId_2"] != "-"
else ""
) # 备选关卡2
# 备选关卡
if (
user_data["Info"]["GameId_1"] == "-"
and user_data["Info"]["GameId_2"] == "-"
):
data["Configurations"]["Default"]["Fight.RemainingSanityStage"] = (
user_data["Info"]["GameId_Remain"]
if user_data["Info"]["GameId_Remain"] != "-"
else ""
) # 剩余理智关卡
data["Configurations"]["Default"][
"MainFunction.Series.Quantity"
] = str(
user_data["Info"]["SeriesNumb"]
) # 连战次数
data["Configurations"]["Default"][
"GUI.UseAlternateStage"
] = "False"
else:
] = "True" # 备选关卡
data["Configurations"]["Default"][
"GUI.UseAlternateStage"
] = "True"
"Fight.UseRemainingSanityStage"
] = "True" # 使用剩余理智
# 人工排查配置
elif "人工排查" in mode:
@@ -1237,8 +1408,8 @@ class MaaManager(QObject):
data["Global"]["GUI.UseTray"] = "True" # 显示托盘图标
data["Global"]["GUI.MinimizeToTray"] = "True" # 最小化时隐藏至托盘
data["Configurations"]["Default"]["Start.OpenEmulatorAfterLaunch"] = (
"True" if self.if_open_emulator else "False"
data["Configurations"]["Default"]["Start.OpenEmulatorAfterLaunch"] = str(
self.if_open_emulator
) # 启动MAA后自动开启模拟器
# 账号切换
@@ -1352,8 +1523,63 @@ class MaaManager(QObject):
"TaskQueue.Reclamation.IsChecked"
] = "False" # 生息演算
elif mode == "更新MAA":
data["Current"] = "Default" # 切换配置
for i in range(1, 9):
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
data["Configurations"]["Default"][
"MainFunction.PostActions"
] = "0" # 完成后无动作
data["Configurations"]["Default"][
"Start.RunDirectly"
] = "False" # 启动MAA后直接运行
data["Configurations"]["Default"][
"Start.OpenEmulatorAfterLaunch"
] = "False" # 启动MAA后自动开启模拟器
data["Global"]["Start.MinimizeDirectly"] = "True" # 启动MAA后直接最小化
data["Global"]["GUI.UseTray"] = "True" # 显示托盘图标
data["Global"]["GUI.MinimizeToTray"] = "True" # 最小化时隐藏至托盘
data["Global"][
"VersionUpdate.package"
] = self.maa_update_package # 更新包路径
data["Global"][
"VersionUpdate.ScheduledUpdateCheck"
] = "False" # 定时检查更新
data["Global"][
"VersionUpdate.AutoDownloadUpdatePackage"
] = "False" # 自动下载更新包
data["Global"][
"VersionUpdate.AutoInstallUpdatePackage"
] = "True" # 自动安装更新包
data["Configurations"]["Default"][
"TaskQueue.WakeUp.IsChecked"
] = "False" # 开始唤醒
data["Configurations"]["Default"][
"TaskQueue.Recruiting.IsChecked"
] = "False" # 自动公招
data["Configurations"]["Default"][
"TaskQueue.Base.IsChecked"
] = "False" # 基建换班
data["Configurations"]["Default"][
"TaskQueue.Combat.IsChecked"
] = "False" # 刷理智
data["Configurations"]["Default"][
"TaskQueue.Mission.IsChecked"
] = "False" # 领取奖励
data["Configurations"]["Default"][
"TaskQueue.Mall.IsChecked"
] = "False" # 获取信用及购物
data["Configurations"]["Default"][
"TaskQueue.AutoRoguelike.IsChecked"
] = "False" # 自动肉鸽
data["Configurations"]["Default"][
"TaskQueue.Reclamation.IsChecked"
] = "False" # 生息演算
# 启动模拟器仅生效一次
if "设置MAA" not in mode and self.if_open_emulator:
if "设置MAA" not in mode and "更新MAA" not in mode and self.if_open_emulator:
self.if_open_emulator = False
# 覆写配置文件

View File

@@ -37,9 +37,6 @@ from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import formataddr
from serverchan_sdk import sc_send
from app.core import Config
from app.services.security import Crypto
@@ -143,76 +140,91 @@ class Notification(QWidget):
self.push_info_bar.emit("error", "发送邮件时出错", f"{e}", -1)
def ServerChanPush(self, title, content):
"""使用Server酱推送通知"""
"""使用Server酱推送通知(支持 tag 和 channel避免使用SDK"""
if Config.get(Config.notify_IfServerChan):
if Config.get(Config.notify_ServerChanKey) == "":
logger.error("请正确设置Server酱的SendKey")
self.push_info_bar.emit(
"error",
"Server酱通知推送异常",
"请正确设置Server酱的SendKey",
-1,
)
return None
else:
send_key = Config.get(Config.notify_ServerChanKey)
option = {}
is_valid = lambda s: s == "" or (
s == "|".join(s.split("|")) and (s.count("|") == 0 or all(s.split("|")))
if not send_key:
logger.error("请正确设置Server酱的SendKey")
self.push_info_bar.emit(
"error", "Server酱通知推送异常", "请正确设置Server酱的SendKey", -1
)
"""
is_valid => True, 如果启用的话需要正确设置Tag和Channel。
允许空的Tag和Channel即不启用但不允许例如a||b|a|ba|b|||||
"""
send_tag = "|".join(
_.strip() for _ in Config.get(Config.notify_ServerChanTag).split("|")
return None
try:
# 构造 URL
if send_key.startswith("sctp"):
match = re.match(r"^sctp(\d+)t", send_key)
if match:
url = f"https://{match.group(1)}.push.ft07.com/send/{send_key}.send"
else:
raise ValueError("SendKey 格式错误sctp")
else:
url = f"https://sctapi.ftqq.com/{send_key}.send"
# 构建 tags 和 channel
def is_valid(s):
return s == "" or (
s == "|".join(s.split("|"))
and (s.count("|") == 0 or all(s.split("|")))
)
send_channel = "|".join(
tags = "|".join(
_.strip()
for _ in Config.get(Config.notify_ServerChanTag).split("|")
)
channels = "|".join(
_.strip()
for _ in Config.get(Config.notify_ServerChanChannel).split("|")
)
if is_valid(send_tag):
option["tags"] = send_tag
options = {}
if is_valid(tags):
options["tags"] = tags
else:
option["tags"] = ""
logger.warning("请正确设置Auto_MAA中ServerChan的Tag。")
logger.warning("Server酱 Tag 配置不正确,将被忽略")
self.push_info_bar.emit(
"warning",
"Server酱通知推送异常",
"请正确设置Auto_MAA中ServerChanTag",
"请正确设置 ServerChanTag",
-1,
)
if is_valid(send_channel):
option["channel"] = send_channel
if is_valid(channels):
options["channel"] = channels
else:
option["channel"] = ""
logger.warning("请正确设置Auto_MAA中ServerChan的Channel。")
logger.warning("Server酱 Channel 配置不正确,将被忽略")
self.push_info_bar.emit(
"warning",
"Server酱通知推送异常",
"请正确设置Auto_MAA中ServerChanChannel",
"请正确设置 ServerChanChannel",
-1,
)
response = sc_send(send_key, title, content, option)
if response["code"] == 0:
# 请求发送
params = {"title": title, "desp": content, **options}
headers = {"Content-Type": "application/json;charset=utf-8"}
response = requests.post(url, json=params, headers=headers, timeout=10)
result = response.json()
if result.get("code") == 0:
logger.info("Server酱推送通知成功")
return True
else:
logger.info("Server酱推送通知失败")
logger.error(response)
error_code = result.get("code", "-1")
logger.error(f"Server酱通知推送失败响应码{error_code}")
self.push_info_bar.emit(
"error",
"Server酱通知推送失败",
f'使用Server酱推送通知时出错\n{response["data"]['error']}',
-1,
"error", "Server酱通知推送失败", f"响应码:{error_code}", -1
)
return f'使用Server酱推送通知时出错:\n{response["data"]['error']}'
return f"Server酱通知推送失败:{error_code}"
except Exception as e:
logger.exception("Server酱通知推送异常")
self.push_info_bar.emit(
"error", "Server酱通知推送异常", f"请检查相关设置,如还有问题可联系开发者", -1
)
return f"Server酱通知推送异常{str(e)}"
def CompanyWebHookBotPush(self, title, content):
"""使用企业微信群机器人推送通知"""

View File

@@ -44,9 +44,7 @@ class _SystemHandler:
ES_CONTINUOUS = 0x80000000
ES_SYSTEM_REQUIRED = 0x00000001
def __init__(self, main_window: QWidget = None):
self.main_window = main_window
def __init__(self):
self.set_Sleep()
self.set_SelfStart()
@@ -112,7 +110,7 @@ class _SystemHandler:
elif mode == "KillSelf":
self.main_window.close()
Config.main_window.close()
QApplication.quit()
elif sys.platform.startswith("linux"):
@@ -138,7 +136,7 @@ class _SystemHandler:
elif mode == "KillSelf":
self.main_window.close()
Config.main_window.close()
QApplication.quit()
def is_startup(self) -> bool:

View File

@@ -621,6 +621,53 @@ class PushAndSwitchButtonSettingCard(SettingCard):
self.switchButton.setText("" if isChecked else "")
class PushAndComboBoxSettingCard(SettingCard):
"""Setting card with push & combo box"""
clicked = Signal()
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
title: str,
content: Union[str, None],
text: str,
texts: List[str],
qconfig: QConfig,
configItem: OptionsConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.comboBox = ComboBox(self)
self.button = PushButton(text, self)
self.hBoxLayout.addWidget(self.button, 0, Qt.AlignRight)
self.hBoxLayout.addWidget(self.comboBox, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
self.button.clicked.connect(self.clicked)
self.optionToText = {o: t for o, t in zip(configItem.options, texts)}
for text, option in zip(texts, configItem.options):
self.comboBox.addItem(text, userData=option)
self.comboBox.setCurrentText(self.optionToText[self.qconfig.get(configItem)])
self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged)
configItem.valueChanged.connect(self.setValue)
def _onCurrentIndexChanged(self, index: int):
self.qconfig.set(self.configItem, self.comboBox.itemData(index))
def setValue(self, value):
if value not in self.optionToText:
return
self.comboBox.setCurrentText(self.optionToText[value])
self.qconfig.set(self.configItem, value)
class SpinBoxSettingCard(SettingCard):
"""Setting card with SpinBox"""

View File

@@ -26,7 +26,7 @@ v4.3
"""
from loguru import logger
from PySide6.QtWidgets import QSystemTrayIcon
from PySide6.QtWidgets import QApplication, QSystemTrayIcon
from qfluentwidgets import (
qconfig,
Action,
@@ -62,16 +62,22 @@ class AUTO_MAA(MSFluentWindow):
super().__init__()
self.setWindowIcon(QIcon(str(Config.app_path / "resources/icons/AUTO_MAA.ico")))
self.setWindowTitle("AUTO_MAA")
version_numb = list(map(int, Config.VERSION.split(".")))
version_text = (
f"v{'.'.join(str(_) for _ in version_numb[0:3])}"
if version_numb[3] == 0
else f"v{'.'.join(str(_) for _ in version_numb[0:3])}-beta.{version_numb[3]}"
)
self.setWindowTitle(f"AUTO_MAA - {version_text}")
self.switch_theme()
self.splashScreen = SplashScreen(self.windowIcon(), self)
self.show_ui("显示主窗口", if_quick=True)
TaskManager.main_window = self.window()
MainInfoBar.main_window = self.window()
System.main_window = self.window()
Config.main_window = self.window()
# 创建主窗口
self.home = Home(self)
@@ -173,13 +179,19 @@ class AUTO_MAA(MSFluentWindow):
# 退出主程序菜单项
self.tray_menu.addAction(
Action(FluentIcon.POWER_BUTTON, "退出主程序", triggered=self.window().close)
Action(
FluentIcon.POWER_BUTTON,
"退出主程序",
triggered=lambda: (self.window().close(), QApplication.quit()),
)
)
# 设置托盘菜单
self.tray.setContextMenu(self.tray_menu)
self.tray.activated.connect(self.on_tray_activated)
self.set_min_method()
Config.user_info_changed.connect(self.member_manager.refresh_dashboard)
TaskManager.create_gui.connect(self.dispatch_center.add_board)
TaskManager.connect_gui.connect(self.dispatch_center.connect_main_board)
@@ -255,11 +267,11 @@ class AUTO_MAA(MSFluentWindow):
self.start_main_task()
# 获取公告
self.setting.show_notice(if_show=False)
self.setting.show_notice(if_first=True)
# 检查更新
if Config.get(Config.update_IfAutoUpdate):
self.setting.check_update()
self.setting.check_update(if_first=True)
# 直接最小化
if Config.get(Config.start_IfMinimizeDirectly):
@@ -347,6 +359,7 @@ class AUTO_MAA(MSFluentWindow):
if mode == "显示主窗口":
# 配置主窗口
if not self.window().isVisible():
size = list(
map(
int,
@@ -359,16 +372,25 @@ class AUTO_MAA(MSFluentWindow):
Config.get(Config.ui_location).split("x"),
)
)
if self.window().isMaximized():
self.window().showNormal()
self.window().setGeometry(location[0], location[1], size[0], size[1])
self.window().show()
self.window().raise_()
self.window().activateWindow()
if not if_quick:
if Config.get(Config.ui_maximized):
self.window().showMaximized()
self.set_min_method()
self.titleBar.maxBtn.click()
self.show_ui("配置托盘")
if not any(
self.window().geometry().intersects(screen.availableGeometry())
for screen in QApplication.screens()
):
self.window().showNormal()
self.window().setGeometry(100, 100, 1200, 700)
self.window().raise_()
self.window().activateWindow()
elif mode == "配置托盘":
if Config.get(Config.ui_IfShowTray):
@@ -389,6 +411,7 @@ class AUTO_MAA(MSFluentWindow):
Config.ui_location,
f"{self.geometry().x()}x{self.geometry().y()}",
)
Config.set(Config.ui_maximized, self.window().isMaximized())
Config.save()

View File

@@ -69,6 +69,7 @@ from .Widget import (
ComboBoxSettingCard,
SwitchSettingCard,
PushAndSwitchButtonSettingCard,
PushAndComboBoxSettingCard,
)
@@ -613,21 +614,7 @@ class MemberManager(QWidget):
configItem=self.config.RunSet_TaskTransitionMethod,
parent=self,
)
self.card_EnhanceTask = ComboBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="自动代理增效任务",
content="自动代理时的额外操作,此操作无法区分多开模拟器,可能会干扰其他任务,也可能关闭您正在使用的模拟器",
texts=[
"禁用",
"强制关闭ADB",
"强制关闭所有模拟器",
"强制关闭ADB和所有模拟器",
],
qconfig=self.config,
configItem=self.config.RunSet_EnhanceTask,
parent=self,
)
self.ProxyTimesLimit = SpinBoxSettingCard(
self.card_ProxyTimesLimit = SpinBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="用户单日代理次数上限",
content="当用户本日代理成功次数达到该阈值时跳过代理阈值为“0”时视为无代理次数上限",
@@ -636,25 +623,7 @@ class MemberManager(QWidget):
configItem=self.config.RunSet_ProxyTimesLimit,
parent=self,
)
self.AnnihilationTimeLimit = SpinBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="剿灭代理超时限制",
content="MAA日志无变化时间超过该阈值视为超时单位为分钟",
range=(1, 1024),
qconfig=self.config,
configItem=self.config.RunSet_AnnihilationTimeLimit,
parent=self,
)
self.RoutineTimeLimit = SpinBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="自动代理超时限制",
content="MAA日志无变化时间超过该阈值视为超时单位为分钟",
range=(1, 1024),
qconfig=self.config,
configItem=self.config.RunSet_RoutineTimeLimit,
parent=self,
)
self.RunTimesLimit = SpinBoxSettingCard(
self.card_RunTimesLimit = SpinBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="代理重试次数限制",
content="若超过该次数限制仍未完成代理,视为代理失败",
@@ -663,7 +632,25 @@ class MemberManager(QWidget):
configItem=self.config.RunSet_RunTimesLimit,
parent=self,
)
self.AnnihilationWeeklyLimit = SwitchSettingCard(
self.card_AnnihilationTimeLimit = SpinBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="剿灭代理超时限制",
content="MAA日志无变化时间超过该阈值视为超时单位为分钟",
range=(1, 1024),
qconfig=self.config,
configItem=self.config.RunSet_AnnihilationTimeLimit,
parent=self,
)
self.card_RoutineTimeLimit = SpinBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="自动代理超时限制",
content="MAA日志无变化时间超过该阈值视为超时单位为分钟",
range=(1, 1024),
qconfig=self.config,
configItem=self.config.RunSet_RoutineTimeLimit,
parent=self,
)
self.card_AnnihilationWeeklyLimit = SwitchSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="每周剿灭仅执行到上限",
content="每周剿灭模式执行到上限,本周剩下时间不再执行剿灭任务",
@@ -671,16 +658,24 @@ class MemberManager(QWidget):
configItem=self.config.RunSet_AnnihilationWeeklyLimit,
parent=self,
)
self.card_AutoUpdateMaa = SwitchSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="自动代理时自动更新MAA",
content="执行自动代理任务时自动更新MAA关闭后仍会进行MAA版本检查",
qconfig=self.config,
configItem=self.config.RunSet_AutoUpdateMaa,
parent=self,
)
widget = QWidget()
Layout = QVBoxLayout(widget)
Layout.addWidget(self.card_TaskTransitionMethod)
Layout.addWidget(self.card_EnhanceTask)
Layout.addWidget(self.ProxyTimesLimit)
Layout.addWidget(self.AnnihilationTimeLimit)
Layout.addWidget(self.RoutineTimeLimit)
Layout.addWidget(self.RunTimesLimit)
Layout.addWidget(self.AnnihilationWeeklyLimit)
Layout.addWidget(self.card_ProxyTimesLimit)
Layout.addWidget(self.card_RunTimesLimit)
Layout.addWidget(self.card_AnnihilationTimeLimit)
Layout.addWidget(self.card_RoutineTimeLimit)
Layout.addWidget(self.card_AnnihilationWeeklyLimit)
Layout.addWidget(self.card_AutoUpdateMaa)
self.viewLayout.setContentsMargins(0, 0, 0, 0)
self.viewLayout.setSpacing(0)
self.addGroupWidget(widget)
@@ -1049,7 +1044,7 @@ class MemberManager(QWidget):
self.name = name
self.dashboard = TableWidget(self)
self.dashboard.setColumnCount(10)
self.dashboard.setColumnCount(11)
self.dashboard.setHorizontalHeaderLabels(
[
"用户名",
@@ -1059,8 +1054,9 @@ class MemberManager(QWidget):
"代理情况",
"给药量",
"关卡选择",
"备选关卡-1",
"备选关卡-2",
"备选 - 1",
"备选 - 2",
"剩余理智",
"",
]
)
@@ -1070,14 +1066,14 @@ class MemberManager(QWidget):
self.dashboard.horizontalHeader().setSectionResizeMode(
col, QHeaderView.ResizeMode.ResizeToContents
)
for col in range(6, 9):
for col in range(6, 10):
self.dashboard.horizontalHeader().setSectionResizeMode(
col, QHeaderView.ResizeMode.Stretch
)
self.dashboard.horizontalHeader().setSectionResizeMode(
9, QHeaderView.ResizeMode.Fixed
10, QHeaderView.ResizeMode.Fixed
)
self.dashboard.setColumnWidth(9, 32)
self.dashboard.setColumnWidth(10, 32)
self.viewLayout.addWidget(self.dashboard)
self.viewLayout.setContentsMargins(3, 0, 3, 3)
@@ -1207,8 +1203,32 @@ class MemberManager(QWidget):
else config.get(config.Info_GameId_2)
),
)
self.dashboard.setItem(
int(name[3:]) - 1,
9,
QTableWidgetItem(
"不使用"
if config.get(config.Info_GameId_Remain) == "-"
else (
(
Config.gameid_dict["ALL"]["text"][
Config.gameid_dict["ALL"][
"value"
].index(
config.get(
config.Info_GameId_Remain
)
)
]
)
if config.get(config.Info_GameId_Remain)
in Config.gameid_dict["ALL"]["value"]
else config.get(config.Info_GameId_Remain)
)
),
)
self.dashboard.setCellWidget(
int(name[3:]) - 1, 9, button
int(name[3:]) - 1, 10, button
)
class UserMemberSettingBox(HeaderCardWidget):
@@ -1307,13 +1327,18 @@ class MemberManager(QWidget):
configItem=self.config.Info_Routine,
parent=self,
)
self.card_Infrastructure = PushAndSwitchButtonSettingCard(
self.card_InfrastMode = PushAndComboBoxSettingCard(
icon=FluentIcon.CAFE,
title="自定义基建",
content="自定义基建相关设置项",
title="基建模式",
content="配置文件仅在自定义基建中生效",
text="选择配置文件",
texts=[
"常规模式",
"一键轮休",
"自定义基建",
],
qconfig=self.config,
configItem=self.config.Info_Infrastructure,
configItem=self.config.Info_InfrastMode,
parent=self,
)
self.card_Password = PasswordLineEditSettingCard(
@@ -1344,6 +1369,15 @@ class MemberManager(QWidget):
configItem=self.config.Info_MedicineNumb,
parent=self,
)
self.card_SeriesNumb = SpinBoxSettingCard(
icon=FluentIcon.GAME,
title="连战次数",
content="连战次数较大时建议搭配剩余理智关卡使用",
range=(1, 6),
qconfig=self.config,
configItem=self.config.Info_SeriesNumb,
parent=self,
)
self.card_GameId = EditableComboBoxSettingCard(
icon=FluentIcon.GAME,
title="关卡选择",
@@ -1356,7 +1390,7 @@ class MemberManager(QWidget):
)
self.card_GameId_1 = EditableComboBoxSettingCard(
icon=FluentIcon.GAME,
title="备选关卡-1",
title="备选关卡 - 1",
content="按下回车以添加自定义关卡号",
value=Config.gameid_dict["ALL"]["value"],
texts=Config.gameid_dict["ALL"]["text"],
@@ -1366,7 +1400,7 @@ class MemberManager(QWidget):
)
self.card_GameId_2 = EditableComboBoxSettingCard(
icon=FluentIcon.GAME,
title="备选关卡-2",
title="备选关卡 - 2",
content="按下回车以添加自定义关卡号",
value=Config.gameid_dict["ALL"]["value"],
texts=Config.gameid_dict["ALL"]["text"],
@@ -1374,6 +1408,19 @@ class MemberManager(QWidget):
configItem=self.config.Info_GameId_2,
parent=self,
)
self.card_GameId_Remain = EditableComboBoxSettingCard(
icon=FluentIcon.GAME,
title="剩余理智关卡",
content="按下回车以添加自定义关卡号",
value=Config.gameid_dict["ALL"]["value"],
texts=[
"不使用" if _ == "当前/上次" else _
for _ in Config.gameid_dict["ALL"]["text"]
],
qconfig=self.config,
configItem=self.config.Info_GameId_Remain,
parent=self,
)
self.card_UserLable = UserLableSettingCard(
icon=FluentIcon.INFO,
@@ -1402,16 +1449,19 @@ class MemberManager(QWidget):
h4_layout = QHBoxLayout()
h4_layout.addWidget(self.card_Annihilation)
h4_layout.addWidget(self.card_Routine)
h4_layout.addWidget(self.card_Infrastructure)
h4_layout.addWidget(self.card_InfrastMode)
h5_layout = QHBoxLayout()
h5_layout.addWidget(self.card_Password)
h5_layout.addWidget(self.card_Notes)
h6_layout = QHBoxLayout()
h6_layout.addWidget(self.card_MedicineNumb)
h6_layout.addWidget(self.card_GameId)
h6_layout.addWidget(self.card_SeriesNumb)
h7_layout = QHBoxLayout()
h7_layout.addWidget(self.card_GameId)
h7_layout.addWidget(self.card_GameId_1)
h7_layout.addWidget(self.card_GameId_2)
h8_layout = QHBoxLayout()
h8_layout.addWidget(self.card_GameId_2)
h8_layout.addWidget(self.card_GameId_Remain)
Layout = QVBoxLayout()
Layout.addLayout(h1_layout)
@@ -1422,6 +1472,7 @@ class MemberManager(QWidget):
Layout.addLayout(h5_layout)
Layout.addLayout(h6_layout)
Layout.addLayout(h7_layout)
Layout.addLayout(h8_layout)
self.viewLayout.addLayout(Layout)
self.viewLayout.setContentsMargins(3, 0, 3, 3)
@@ -1435,7 +1486,7 @@ class MemberManager(QWidget):
self.card_Routine.clicked.connect(
lambda: self.set_maa("Routine")
)
self.card_Infrastructure.clicked.connect(
self.card_InfrastMode.clicked.connect(
self.set_infrastructure
)
Config.gameid_refreshed.connect(self.refresh_gameid)
@@ -1450,12 +1501,12 @@ class MemberManager(QWidget):
self.card_Routine.setVisible(False)
self.card_Server.setVisible(True)
self.card_Annihilation.button.setVisible(False)
self.card_Infrastructure.setVisible(True)
self.card_InfrastMode.setVisible(True)
elif self.config.get(self.config.Info_Mode) == "详细":
self.card_Server.setVisible(False)
self.card_Infrastructure.setVisible(False)
self.card_InfrastMode.setVisible(False)
self.card_Annihilation.button.setVisible(True)
self.card_Routine.setVisible(True)
@@ -1473,6 +1524,13 @@ class MemberManager(QWidget):
Config.gameid_dict["ALL"]["value"],
Config.gameid_dict["ALL"]["text"],
)
self.card_GameId_Remain.reLoadOptions(
Config.gameid_dict["ALL"]["value"],
[
"不使用" if _ == "当前/上次" else _
for _ in Config.gameid_dict["ALL"]["text"]
],
)
def refresh_password(self):

View File

@@ -87,9 +87,9 @@ class Setting(QWidget):
self.start.card_IfSelfStart.checkedChanged.connect(System.set_SelfStart)
self.security.card_changePASSWORD.clicked.connect(self.change_PASSWORD)
self.updater.card_CheckUpdate.clicked.connect(
lambda: self.check_update(if_click=True)
lambda: self.check_update(if_show=True)
)
self.other.card_Notice.clicked.connect(self.show_notice)
self.other.card_Notice.clicked.connect(lambda: self.show_notice(if_show=True))
content_layout.addWidget(self.function)
content_layout.addWidget(self.start)
@@ -177,10 +177,7 @@ class Setting(QWidget):
while True:
choice = LineEditMessageBox(
self.window(),
"未检测到管理密钥,请设置您的管理密钥",
"管理密钥",
"密码",
self.window(), "请设置您的管理密钥", "管理密钥", "密码"
)
if choice.exec() and choice.input.text() != "":
Crypto.get_PASSWORD(choice.input.text())
@@ -258,12 +255,12 @@ class Setting(QWidget):
if choice.exec():
break
def check_update(self, if_click: bool = False) -> None:
def check_update(self, if_show: bool = False, if_first: bool = False) -> None:
"""检查版本更新,调起文件下载进程"""
current_version = list(map(int, Config.VERSION.split(".")))
if Network.if_running and if_click:
if Network.if_running and if_show:
MainInfoBar.push_info_bar(
"warning", "请求速度过快", "上个网络请求还未结束,请稍等片刻", 5000
)
@@ -333,8 +330,14 @@ class Setting(QWidget):
)
)
# 有版本更新
if version.parse(version_text(remote_version)) > version.parse(
if (
if_show
or (
not if_show
and if_first
and not Config.get(Config.function_UnattendedMode)
)
) and version.parse(version_text(remote_version)) > version.parse(
version_text(current_version)
):
@@ -410,11 +413,26 @@ class Setting(QWidget):
self.window().close()
QApplication.quit()
# 无版本更新
elif (
if_show
or if_first
or version.parse(version_text(remote_version))
> version.parse(version_text(current_version))
):
if version.parse(version_text(remote_version)) > version.parse(
version_text(current_version)
):
MainInfoBar.push_info_bar(
"info",
"发现新版本",
f"{version_text(current_version)} --> {version_text(remote_version)}",
3600000,
)
else:
MainInfoBar.push_info_bar("success", "更新检查", "已是最新版本~", 3000)
def show_notice(self, if_show: bool = True) -> None:
def show_notice(self, if_show: bool = False, if_first: bool = False) -> None:
"""显示公告"""
# 从远程服务器获取最新公告
@@ -453,9 +471,11 @@ class Setting(QWidget):
}
if if_show or (
datetime.now()
if_first
and datetime.now()
> datetime.strptime(notice["time"], "%Y-%m-%d %H:%M")
> time_local
and not Config.get(Config.function_UnattendedMode)
):
choice = NoticeMessageBox(self.window(), "公告", notice["notice_dict"])
@@ -467,6 +487,17 @@ class Setting(QWidget):
) as f:
json.dump(notice, f, ensure_ascii=False, indent=4)
elif (
datetime.now()
> datetime.strptime(notice["time"], "%Y-%m-%d %H:%M")
> time_local
):
MainInfoBar.push_info_bar(
"info", "有新公告", "请前往设置界面查看公告", 3600000
)
return None
class FunctionSettingCard(HeaderCardWidget):
@@ -501,6 +532,14 @@ class FunctionSettingCard(HeaderCardWidget):
parent=self,
)
self.card_IfSilence = self.SilenceSettingCard(self)
self.card_UnattendedMode = SwitchSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="无人值守模式",
content="开启后AUTO_MAA不再主动弹出对话框以免影响代理任务运行",
qconfig=Config,
configItem=Config.function_UnattendedMode,
parent=self,
)
self.card_IfAgreeBilibili = SwitchSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="托管bilibili游戏隐私政策",
@@ -523,6 +562,7 @@ class FunctionSettingCard(HeaderCardWidget):
Layout.addWidget(self.card_HistoryRetentionTime)
Layout.addWidget(self.card_IfAllowSleep)
Layout.addWidget(self.card_IfSilence)
Layout.addWidget(self.card_UnattendedMode)
Layout.addWidget(self.card_IfAgreeBilibili)
Layout.addWidget(self.card_IfSkipMumuSplashAds)
self.viewLayout.addLayout(Layout)
@@ -998,9 +1038,9 @@ class OtherSettingCard(HeaderCardWidget):
)
self.card_UserDocs = HyperlinkCard(
url="https://clozya.github.io/AUTOMAA_docs",
text="访问",
text="查看指南",
icon=FluentIcon.PAGE_RIGHT,
title="AUTO_MAA官方文档站",
title="用户指南",
content="访问AUTO_MAA的官方文档站获取使用指南和项目相关信息",
parent=self,
)

View File

@@ -613,11 +613,7 @@ class DownloadManager(QDialog):
class AUTO_MAA_Downloader(QApplication):
def __init__(
self,
app_path: Path,
name: str,
main_version: list,
config: dict,
self, app_path: Path, name: str, main_version: list, config: dict
) -> None:
super().__init__()

View File

@@ -6,10 +6,18 @@
"TaskQueue.Recruiting.IsChecked": "True" #自动公招
"TaskQueue.Base.IsChecked": "True" #基建换班
"TaskQueue.Combat.IsChecked": "True" #刷理智
"TaskQueue.Mission.IsChecked": "True" #领取奖励
"TaskQueue.Mall.IsChecked": "True" #获取信用及购物
"TaskQueue.Mission.IsChecked": "True" #领取奖励
"TaskQueue.AutoRoguelike.IsChecked": "False" #自动肉鸽
"TaskQueue.Reclamation.IsChecked": "False" #生息演算
"TaskQueue.Order.WakeUp": "0"
"TaskQueue.Order.Recruiting": "1"
"TaskQueue.Order.Base": "2"
"TaskQueue.Order.Combat": "3"
"TaskQueue.Order.Mall": "4"
"TaskQueue.Order.Mission": "5"
"TaskQueue.Order.AutoRoguelike": "6"
"TaskQueue.Order.Reclamation": "7"
#刷理智
"MainFunction.UseMedicine": "True" #吃理智药
"MainFunction.UseMedicine.Quantity": "999" #吃理智药数量
@@ -30,8 +38,8 @@
"Penguin.EnablePenguin": "True" #上报企鹅物流
"Yituliu.EnableYituliu": "True" #上报一图流
#基建换班
"Infrast.CustomInfrastEnabled": "True" #启用自定义基建配置
"Infrast.CustomInfrastPlanIndex": "1" #自定义基建配置索引
"Infrast.InfrastMode": "Normal"、"Rotation"、"Custom" #基建模式
"Infrast.CustomInfrastPlanIndex": "1" #自定义基建配置索引
"Infrast.DefaultInfrast": "user_defined" #内置配置
"Infrast.IsCustomInfrastFileReadOnly": "False" #自定义基建配置文件只读
"Infrast.CustomInfrastFile": "" #自定义基建配置文件地址
@@ -50,3 +58,4 @@ G"GUI.UseTray": "True" #显示托盘图标
G"GUI.MinimizeToTray": "False" #最小化时隐藏至托盘
"Start.EmulatorPath" #模拟器路径
"Start.EmulatorAddCommand": "-v 2" #附加命令
G"VersionUpdate.package": "MirrorChyanAppv5.15.6.zip" #更新包标识

View File

@@ -1,93 +1,49 @@
{
"main_version": "4.3.4.0",
"main_version": "4.3.6.2",
"updater_version": "1.0.0.0",
"announcement": "\n## 新增功能\n- 屏蔽MuMu模拟器开屏广告功能上线\n- 更新器支持多线程下载\n- 添加强制关闭ADB与模拟器等增强任务项\n## 修复BUG\n- 修复统计信息HTML模板公招匹配错误\n- 修复密码显示按钮动画异常\n- 修复`检测到MAA未能实际执行任务`报错被异常屏蔽\n- 修复MAA超时判定异常失效\n## 程序优化\n- 关机等电源操作添加100s倒计时\n- 人工排查弹窗方法优化\n- 人工排查时自动屏蔽静默操作\n- 公告样式优化",
"version_info": {
"4.3.4.0": {
"修复BUG": [
"同步到MAAv5.15.4的tasks目录结构变化"
]
},
"4.3.4.7": {
"4.3.6.2": {
"新增功能": [
"主调度台支持直接启动多开调度台"
"新增`无人值守模式`"
],
"修复BUG": [
"修复软件窗口最大化异常问题",
"修复异常操作导致窗口离开屏幕后难以复原的问题",
"修正剩余理智关卡文案",
"修复隐藏到托盘时,托盘无法退出主程序的问题",
"修复Server酱网络异常导致的卡死问题"
],
"程序优化": [
"历史记录保留时间选项扩展"
"主窗口显示版本号"
]
},
"4.3.4.6": {
"4.3.6.1": {
"新增功能": [
"历史记录添加`按周合并`、`按月合并`功能",
"新增MAA稳定版更新提醒"
],
"修复BUG": [
"修复历史记录选项卡无法回收的问题"
],
"程序优化": [
"历史记录添加`选中最近一月`、`选中最近一周`选项与打开日志文件所在目录功能",
"MAA报错判定结果文案拆分优化"
"单次自动代理任务中,已完成的子任务在重复执行时不再启用"
]
},
"4.3.4.5": {
"修复BUG": [
"修复启动时运行主任务的历史记录与完成后任务异常"
],
"程序优化": [
"历史记录转为自行搜索",
"历史记录时间条目排序规则优化"
]
},
"4.3.4.4": {
"修复BUG": [
"修复更新时主程序退出不彻底"
],
"程序优化": [
"ADB路径与模拟器路径添加报错提示",
"ADB路径兼容相对路径"
]
},
"4.3.4.3": {
"修复BUG": [
"修复更新器使用mirrorc下载时删除已弃用的文件卡死"
]
},
"4.3.4.2": {
"程序优化": [
"调度队列历史记录归入配置类管理",
"添加.gitignore",
"工作流删除冗余部分",
"自动代理与人工排查结束后MAA恢复到全局配置 #40",
"网络相关操作由子线程执行"
]
},
"4.3.4.1": {
"4.3.5.0": {
"新增功能": [
"开始任务前自动释放ADB端口"
"用户设置中新增连战次数与剩余理智关卡两项配置项",
"支持自动代理时更新MAA"
],
"修复BUG": [
"适配MAAv5.16.0基建模式",
"适配自定义基建自动轮换功能"
],
"程序优化": [
"request 添加超时限制",
"用户任务运行流程改进",
"自动代理中模拟器改由AUTO_MAA控制",
"修正部分配置项文案"
"移除增效任务"
]
},
"4.3.3.0": {
"4.3.5.2": {
"修复BUG": [
"修复更新器无法下载MAA的异常"
],
"修复无法建立网络连接时软件卡死问题"
]
},
"4.3.5.1": {
"程序优化": [
"自动发版改为手动触发"
]
},
"4.3.2.0": {
"修复BUG": [
"修复更新器无法启动的异常"
]
},
"4.3.1.0": {
"修复BUG": [
"覆盖规避v4.3.0错误包"
"模拟器路径适配快捷方式"
]
}
},
@@ -100,7 +56,6 @@
"https://ghfast.top/"
],
"download_dict": {
"官方下载站-jp": "https://jp-download.fearr.xyz/AUTO_MAA/",
"官方下载站-hw": "http://hwobs.fearr.xyz/releases/artifacts/"
"官方下载站-jp": "https://jp-download.fearr.xyz/AUTO_MAA/"
}
}