From 4a6f8742106f5385e1e4721bfade0a0b1daadc1b Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Mon, 14 Apr 2025 15:03:29 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix:=20request=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=B6=85=E6=97=B6=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/config.py | 5 +++-- app/services/notification.py | 41 +++++++++++++++++++++++++----------- app/ui/home.py | 5 +++-- app/ui/member_manager.py | 3 ++- app/ui/setting.py | 6 ++++-- app/utils/downloader.py | 13 ++++++++---- resources/version.json | 7 +++++- 7 files changed, 56 insertions(+), 24 deletions(-) diff --git a/app/core/config.py b/app/core/config.py index 988f3ef..57e8394 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -599,7 +599,7 @@ class MaaUserConfig(QConfig): class AppConfig(GlobalConfig): - VERSION = "4.3.3.0" + VERSION = "4.3.3.1" gameid_refreshed = Signal() PASSWORD_refreshed = Signal() @@ -678,7 +678,8 @@ class AppConfig(GlobalConfig): for _ in range(3): try: response = requests.get( - "https://ota.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json" + "https://ota.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json", + timeout=10, ) gameid_infos: List[ Dict[str, Union[str, Dict[str, Union[str, int]]]] diff --git a/app/services/notification.py b/app/services/notification.py index 915f237..62f983a 100644 --- a/app/services/notification.py +++ b/app/services/notification.py @@ -28,6 +28,7 @@ v4.3 from PySide6.QtWidgets import QWidget from PySide6.QtCore import Signal import requests +import time from loguru import logger from plyer import notification import re @@ -229,25 +230,41 @@ class Notification(QWidget): content = f"{title}\n{content}" data = {"msgtype": "text", "text": {"content": content}} - response = requests.post( - url=Config.get(Config.notify_CompanyWebHookBotUrl), - json=data, - ) - if response.json()["errcode"] == 0: - logger.info("企业微信群机器人推送通知成功") - return True + # 从远程服务器获取最新主题图像 + for _ in range(3): + try: + response = requests.post( + url=Config.get(Config.notify_CompanyWebHookBotUrl), + json=data, + timeout=10, + ) + info = response.json() + break + except Exception as e: + err = e + time.sleep(0.1) else: - logger.info("企业微信群机器人推送通知失败") - logger.error(response.json()) + logger.error(f"推送企业微信群机器人时出错:{err}") self.push_info_bar.emit( "error", "企业微信群机器人通知推送失败", - f'使用企业微信群机器人推送通知时出错:\n{response.json()["errmsg"]}', + f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', -1, ) - return ( - f'使用企业微信群机器人推送通知时出错:\n{response.json()["errmsg"]}' + return None + + if info["errcode"] == 0: + logger.info("企业微信群机器人推送通知成功") + return True + else: + logger.error(f"企业微信群机器人推送通知失败:{info}") + self.push_info_bar.emit( + "error", + "企业微信群机器人通知推送失败", + f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', + -1, ) + return f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}' def send_test_notification(self): """发送测试通知到所有已启用的通知渠道""" diff --git a/app/ui/home.py b/app/ui/home.py index cbfb11a..783cae3 100644 --- a/app/ui/home.py +++ b/app/ui/home.py @@ -202,7 +202,8 @@ class Home(QWidget): for _ in range(3): try: response = requests.get( - "https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/theme_image.json" + "https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/theme_image.json", + timeout=10, ) theme_image = response.json() break @@ -238,7 +239,7 @@ class Home(QWidget): > time_local ): - response = requests.get(theme_image["url"]) + response = requests.get(theme_image["url"], timeout=10) if response.status_code == 200: with open( diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py index a0234a1..65b77fa 100644 --- a/app/ui/member_manager.py +++ b/app/ui/member_manager.py @@ -340,7 +340,8 @@ class MemberManager(QWidget): for _ in range(3): try: response = requests.get( - "https://mirrorchyan.com/api/resources/MAA/latest?user_agent=AutoMaaGui&os=win&arch=x64&channel=stable" + "https://mirrorchyan.com/api/resources/MAA/latest?user_agent=AutoMaaGui&os=win&arch=x64&channel=stable", + timeout=10, ) maa_info = response.json() break diff --git a/app/ui/setting.py b/app/ui/setting.py index b8cddf6..5b6ba60 100644 --- a/app/ui/setting.py +++ b/app/ui/setting.py @@ -271,7 +271,8 @@ class Setting(QWidget): for _ in range(3): try: response = requests.get( - f"https://mirrorchyan.com/api/resources/AUTO_MAA/latest?user_agent=AutoMaaGui¤t_version={version_text(current_version)}&cdk={Crypto.win_decryptor(Config.get(Config.update_MirrorChyanCDK))}&channel={Config.get(Config.update_UpdateType)}" + f"https://mirrorchyan.com/api/resources/AUTO_MAA/latest?user_agent=AutoMaaGui¤t_version={version_text(current_version)}&cdk={Crypto.win_decryptor(Config.get(Config.update_MirrorChyanCDK))}&channel={Config.get(Config.update_UpdateType)}", + timeout=10, ) version_info: Dict[str, Union[int, str, Dict[str, str]]] = ( response.json() @@ -417,7 +418,8 @@ class Setting(QWidget): for _ in range(3): try: response = requests.get( - "https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/notice.json" + "https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/notice.json", + timeout=10, ) notice = response.json() break diff --git a/app/utils/downloader.py b/app/utils/downloader.py index 0a8b126..7cde9a9 100644 --- a/app/utils/downloader.py +++ b/app/utils/downloader.py @@ -302,7 +302,10 @@ class DownloadManager(QDialog): elif self.config["mode"] == "MirrorChyan": with requests.get( - self.config["url"], allow_redirects=True, stream=True + self.config["url"], + allow_redirects=True, + timeout=10, + stream=True, ) as response: if response.status_code == 200: return response.url @@ -399,7 +402,7 @@ class DownloadManager(QDialog): url = self.get_download_url("下载") self.downloaded_size_list: List[List[int, bool]] = [] - response = requests.head(url) + response = requests.head(url, timeout=10) self.file_size = int(response.headers.get("content-length", 0)) part_size = self.file_size // self.config["thread_numb"] @@ -661,7 +664,8 @@ if __name__ == "__main__": for _ in range(3): try: response = requests.get( - f"https://mirrorchyan.com/api/resources/AUTO_MAA/latest?user_agent=AutoMaaDownloader¤t_version={version_text(current_version)}&cdk={mirrorchyan_CDK}&channel={update_type}" + f"https://mirrorchyan.com/api/resources/AUTO_MAA/latest?user_agent=AutoMaaDownloader¤t_version={version_text(current_version)}&cdk={mirrorchyan_CDK}&channel={update_type}", + timeout=10, ) version_info: Dict[str, Union[int, str, Dict[str, str]]] = response.json() break @@ -696,7 +700,8 @@ if __name__ == "__main__": for _ in range(3): try: response = requests.get( - "https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/download_info.json" + "https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/download_info.json", + timeout=10, ) download_info = response.json() diff --git a/resources/version.json b/resources/version.json index a203f90..6efddc7 100644 --- a/resources/version.json +++ b/resources/version.json @@ -1,8 +1,13 @@ { - "main_version": "4.3.3.0", + "main_version": "4.3.3.1", "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.3.1": { + "程序优化": [ + "request 添加超时限制" + ] + }, "4.3.3.0": { "修复BUG": [ "修复更新器无法下载MAA的异常" From 49ebd500778bf432f1729a863cca4bd56ec07fba Mon Sep 17 00:00:00 2001 From: aoxuan Date: Mon, 14 Apr 2025 16:04:53 +0800 Subject: [PATCH 2/6] =?UTF-8?q?refactor(ui):=20=E4=BC=98=E5=8C=96=E6=A8=A1?= =?UTF-8?q?=E6=8B=9F=E5=99=A8=E8=80=81=E6=9D=BF=E9=94=AE=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=8D=A1=E7=89=87=E7=9A=84=E6=8F=90=E7=A4=BA=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ui/setting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/ui/setting.py b/app/ui/setting.py index b8cddf6..b893afb 100644 --- a/app/ui/setting.py +++ b/app/ui/setting.py @@ -549,8 +549,8 @@ class FunctionSettingCard(HeaderCardWidget): self.card_BossKey = LineEditSettingCard( icon=FluentIcon.PAGE_RIGHT, title="模拟器老板键", - content="输入模拟器老板快捷键,以“+”分隔", - text="请输入安卓模拟器老板键", + content="请输入对应的模拟器老板键,请直接输入文字,多个键位之间请用“+”隔开。如:“Alt+Q”", + text="请以文字形式输入模拟器老板快捷键", qconfig=Config, configItem=Config.function_BossKey, parent=self, From 63cb1aaa7406277e55b96a7c056f910daedabf07 Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Tue, 15 Apr 2025 22:15:59 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=E8=87=AA=E5=8A=A8=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E6=B5=81=E7=A8=8B=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/config.py | 2 +- app/models/MAA.py | 226 ++++++++++++++++------------- app/ui/setting.py | 14 +- app/utils/downloader.py | 11 +- resources/docs/MAA_config_info.txt | 4 +- resources/version.json | 11 +- 6 files changed, 151 insertions(+), 117 deletions(-) diff --git a/app/core/config.py b/app/core/config.py index 57e8394..92fa29c 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -599,7 +599,7 @@ class MaaUserConfig(QConfig): class AppConfig(GlobalConfig): - VERSION = "4.3.3.1" + VERSION = "4.3.4.1" gameid_refreshed = Signal() PASSWORD_refreshed = Signal() diff --git a/app/models/MAA.py b/app/models/MAA.py index 9c8ad57..a5324aa 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -186,7 +186,7 @@ class MaaManager(QObject): logger.info(f"{self.name} | 开始代理用户: {user[0]}") - # 初始化代理情况记录和模式替换记录 + # 初始化代理情况记录和模式替换表 run_book = {"Annihilation": False, "Routine": False} mode_book = { "Annihilation": "自动代理_剿灭", @@ -196,92 +196,80 @@ class MaaManager(QObject): # 简洁模式用户默认开启日常选项 if user_data["Info"]["Mode"] == "简洁": user_data["Info"]["Routine"] = True + # 详细模式用户首次代理需打开模拟器 elif user_data["Info"]["Mode"] == "详细": - check_book = { - "Annihilation": True, - "Routine": True, - } + self.if_open_emulator = True user_logs_list = [] user_start_time = datetime.now() - # 尝试次数循环 - for i in range(self.set["RunSet"]["RunTimesLimit"]): + # 剿灭-日常模式循环 + for mode in ["Annihilation", "Routine"]: if self.isInterruptionRequested: break - logger.info( - f"{self.name} | 用户: {user[0]} - 尝试次数: {i + 1}/{self.set["RunSet"]["RunTimesLimit"]}" + # 剿灭模式;满足条件跳过剿灭 + if ( + mode == "Annihilation" + and self.set["RunSet"]["AnnihilationWeeklyLimit"] + and datetime.strptime( + user_data["Data"]["LastAnnihilationDate"], "%Y-%m-%d" + ).isocalendar()[:2] + == datetime.strptime(curdate, "%Y-%m-%d").isocalendar()[:2] + ): + logger.info( + f"{self.name} | 用户: {user_data["Info"]["Name"]} - 本周剿灭模式已达上限,跳过执行剿灭任务" + ) + run_book[mode] = True + continue + else: + self.weekly_annihilation_limit_reached = False + + if not user_data["Info"][mode]: + run_book[mode] = True + continue + + if user_data["Info"]["Mode"] == "详细": + + if not ( + self.data[user[2]]["Path"] / f"{mode}/gui.json" + ).exists(): + logger.error( + f"{self.name} | 用户: {user[0]} - 未找到{mode_book[mode][5:7]}配置文件" + ) + self.push_info_bar.emit( + "error", + "启动MAA代理进程失败", + f"未找到{user[0]}的{mode_book[mode][5:7]}配置文件!", + -1, + ) + run_book[mode] = False + continue + + # 更新当前模式到界面 + self.update_user_list.emit( + [ + ( + [f"{_[0]} - {mode_book[mode][5:7]}", _[1], _[2]] + if _[2] == user[2] + else _ + ) + for _ in self.user_list + ] ) - # 剿灭-日常模式循环 - for mode in ["Annihilation", "Routine"]: + # 尝试次数循环 + for i in range(self.set["RunSet"]["RunTimesLimit"]): if self.isInterruptionRequested: break - # 剿灭模式;满足条件跳过剿灭 - if ( - mode == "Annihilation" - and self.set["RunSet"]["AnnihilationWeeklyLimit"] - and datetime.strptime( - user_data["Data"]["LastAnnihilationDate"], "%Y-%m-%d" - ).isocalendar()[:2] - == datetime.strptime(curdate, "%Y-%m-%d").isocalendar()[:2] - ): - logger.info( - f"{self.name} | 用户: {user_data["Info"]["Name"]} - 本周剿灭模式已达上限,跳过执行剿灭任务" - ) - run_book[mode] = True - continue - else: - self.weekly_annihilation_limit_reached = False - - if not user_data["Info"][mode]: - run_book[mode] = True - continue if run_book[mode]: - continue + break logger.info( - f"{self.name} | 用户: {user[0]} - 模式: {mode_book[mode]}" - ) - - if user_data["Info"]["Mode"] == "详细": - - self.if_open_emulator = True - - if ( - check_book[mode] - and not ( - self.data[user[2]]["Path"] / f"{mode}/gui.json" - ).exists() - ): - logger.error( - f"{self.name} | 用户: {user[0]} - 未找到{mode_book[mode][5:7]}配置文件" - ) - self.push_info_bar.emit( - "error", - "启动MAA代理进程失败", - f"未找到{user[0]}的{mode_book[mode][5:7]}配置文件!", - -1, - ) - check_book[mode] = False - continue - elif not check_book[mode]: - continue - - # 更新当前模式到界面 - self.update_user_list.emit( - [ - ( - [f"{_[0]} - {mode_book[mode][5:7]}", _[1], _[2]] - if _[2] == user[2] - else _ - ) - for _ in self.user_list - ] + f"{self.name} | 用户: {user[0]} - 模式: {mode_book[mode]} - 尝试次数: {i + 1}/{self.set["RunSet"]["RunTimesLimit"]}" ) # 配置MAA @@ -293,24 +281,50 @@ class MaaManager(QObject): self.emulator_path = Path( set["Configurations"]["Default"]["Start.EmulatorPath"] ) + self.emulator_arguments = set["Configurations"]["Default"][ + "Start.EmulatorAddCommand" + ].split() self.ADB_path = Path( set["Configurations"]["Default"]["Connect.AdbPath"] ) + self.ADB_address = set["Configurations"]["Default"][ + "Connect.Address" + ] self.if_kill_emulator = bool( set["Configurations"]["Default"]["MainFunction.PostActions"] == "12" ) + self.if_open_emulator_process = bool( + set["Configurations"]["Default"][ + "Start.OpenEmulatorAfterLaunch" + ] + == "True" + ) # 添加静默进程标记 Config.silence_list.append(self.emulator_path) # 增强任务:任务开始前强杀ADB if "ADB" in self.set["RunSet"]["EnhanceTask"]: System.kill_process(self.ADB_path) + else: + try: + subprocess.run( + [self.ADB_path, "disconnect", self.ADB_address], + creationflags=subprocess.CREATE_NO_WINDOW, + ) + except subprocess.CalledProcessError as e: + # 忽略错误,因为可能本来就没有连接 + logger.warning(f"{self.name} | 释放ADB时出现异常:{e}") + + if self.if_open_emulator_process: + self.emulator_process = subprocess.Popen( + [self.emulator_path, *self.emulator_arguments], + creationflags=subprocess.CREATE_NO_WINDOW, + ) # 创建MAA任务 maa = subprocess.Popen( [self.maa_exe_path], - shell=True, creationflags=subprocess.CREATE_NO_WINDOW, ) # 监测MAA运行状态 @@ -339,8 +353,13 @@ 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 # 推送异常通知 Notify.push_plyer( @@ -357,14 +376,25 @@ class MaaManager(QObject): # 移除静默进程标记 Config.silence_list.remove(self.emulator_path) - # 增强任务:任务结束后强杀ADB和模拟器 + # 增强任务:任务结束后强杀ADB和模拟器或释放进程 if "ADB" in self.set["RunSet"]["EnhanceTask"]: System.kill_process(self.ADB_path) - if ( - self.if_kill_emulator - and "Emulator" in self.set["RunSet"]["EnhanceTask"] - ): - System.kill_process(self.emulator_path) + else: + try: + subprocess.run( + [self.ADB_path, "disconnect", self.ADB_address], + creationflags=subprocess.CREATE_NO_WINDOW, + ) + except subprocess.CalledProcessError as e: + # 忽略错误,因为可能本来就没有连接 + logger.warning(f"{self.name} | 释放ADB时出现异常:{e}") + 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 # 记录剿灭情况 if ( @@ -392,23 +422,6 @@ class MaaManager(QObject): {"user_name": user_data["Info"]["Name"]}, ) - # 成功完成代理的用户修改相关参数 - if run_book["Annihilation"] and run_book["Routine"]: - if ( - user_data["Data"]["ProxyTimes"] == 0 - and user_data["Info"]["RemainedDay"] != -1 - ): - user_data["Info"]["RemainedDay"] -= 1 - user_data["Data"]["ProxyTimes"] += 1 - user[1] = "完成" - Notify.push_plyer( - "成功完成一个自动代理任务!", - f"已完成用户 {user[0].replace("_", " 今天的")}任务", - f"已完成 {user[0].replace("_", " 的")}", - 3, - ) - break - if Config.get(Config.notify_IfSendStatistic): statistics = Config.merge_maa_logs("指定项", user_logs_list) @@ -428,8 +441,23 @@ class MaaManager(QObject): "统计信息", f"用户 {user[0]} 的自动代理统计报告", statistics ) - # 录入代理失败的用户 - if not (run_book["Annihilation"] and run_book["Routine"]): + if run_book["Annihilation"] and run_book["Routine"]: + # 成功完成代理的用户修改相关参数 + if ( + user_data["Data"]["ProxyTimes"] == 0 + and user_data["Info"]["RemainedDay"] != -1 + ): + user_data["Info"]["RemainedDay"] -= 1 + user_data["Data"]["ProxyTimes"] += 1 + user[1] = "完成" + Notify.push_plyer( + "成功完成一个自动代理任务!", + f"已完成用户 {user[0].replace("_", " 今天的")}任务", + f"已完成 {user[0].replace("_", " 的")}", + 3, + ) + else: + # 录入代理失败的用户 user[1] = "异常" self.update_user_list.emit(self.user_list) @@ -475,7 +503,6 @@ class MaaManager(QObject): # 创建MAA任务 maa = subprocess.Popen( [self.maa_exe_path], - shell=True, creationflags=subprocess.CREATE_NO_WINDOW, ) @@ -545,7 +572,6 @@ class MaaManager(QObject): # 创建MAA任务 maa = subprocess.Popen( [self.maa_exe_path], - shell=True, creationflags=subprocess.CREATE_NO_WINDOW, ) # 记录当前时间 @@ -1273,11 +1299,7 @@ class MaaManager(QObject): ] = "False" # 生息演算 # 启动模拟器仅生效一次 - if ( - "设置MAA" not in mode - and self.if_open_emulator - and self.set["RunSet"]["TaskTransitionMethod"] != "ExitEmulator" - ): + if "设置MAA" not in mode and self.if_open_emulator: self.if_open_emulator = False # 覆写配置文件 diff --git a/app/ui/setting.py b/app/ui/setting.py index 5b6ba60..92c3220 100644 --- a/app/ui/setting.py +++ b/app/ui/setting.py @@ -51,6 +51,7 @@ import shutil import requests import subprocess from datetime import datetime +from packaging import version from pathlib import Path from typing import Dict, List, Union @@ -337,7 +338,9 @@ class Setting(QWidget): ) # 有版本更新 - if remote_version > current_version: + if version.parse(version_text(remote_version)) > version.parse( + version_text(current_version) + ): version_info_json: Dict[str, Dict[str, str]] = json.loads( re.sub( @@ -354,9 +357,11 @@ class Setting(QWidget): all_version_info = {} for v_i in [ info - for version, info in version_info_json.items() - if list(map(int, version.split("."))) > current_version + for ver, info in version_info_json.items() + if version.parse(version_text(list(map(int, ver.split("."))))) + > version.parse(version_text(current_version)) ]: + for key, value in v_i.items(): if key in update_version_info: update_version_info[key] += value.copy() @@ -401,8 +406,7 @@ class Setting(QWidget): return None subprocess.Popen( - str(Config.app_path / "AUTO_Updater.active.exe"), - shell=True, + [Config.app_path / "AUTO_Updater.active.exe"], creationflags=subprocess.CREATE_NO_WINDOW, ) self.window().close() diff --git a/app/utils/downloader.py b/app/utils/downloader.py index 7cde9a9..a0864ed 100644 --- a/app/utils/downloader.py +++ b/app/utils/downloader.py @@ -33,6 +33,7 @@ import subprocess import time import win32crypt import base64 +from packaging import version from functools import partial from pathlib import Path @@ -529,14 +530,12 @@ class DownloadManager(QDialog): # 主程序更新完成后打开对应程序 if not self.isInterruptionRequested and self.name == "AUTO_MAA": subprocess.Popen( - str(self.app_path / "AUTO_MAA.exe"), - shell=True, + [self.app_path / "AUTO_MAA.exe"], creationflags=subprocess.CREATE_NO_WINDOW, ) elif not self.isInterruptionRequested and self.name == "MAA": subprocess.Popen( - str(self.app_path / "MAA.exe"), - shell=True, + [self.app_path / "MAA.exe"], creationflags=subprocess.CREATE_NO_WINDOW, ) @@ -720,7 +719,9 @@ if __name__ == "__main__": (app_path / "changes.json").unlink() # 启动更新线程 - if remote_version > current_version: + if version.parse(version_text(remote_version)) > version.parse( + version_text(current_version) + ): app = AUTO_MAA_Downloader( app_path, "AUTO_MAA", diff --git a/resources/docs/MAA_config_info.txt b/resources/docs/MAA_config_info.txt index 1510c73..a7cf7fb 100644 --- a/resources/docs/MAA_config_info.txt +++ b/resources/docs/MAA_config_info.txt @@ -38,6 +38,8 @@ #设置 "Start.ClientType": "Bilibili"、 "Official" #服务器 G"Timer.Timer1": "False" #时间设置1 +"Connect.AdbPath" #ADB路径 +"Connect.Address": "127.0.0.1:16448" #连接地址 G"VersionUpdate.ScheduledUpdateCheck": "True" #定时检查更新 G"VersionUpdate.AutoDownloadUpdatePackage": "True" #自动下载更新包 G"VersionUpdate.AutoInstallUpdatePackage": "True" #自动安装更新包 @@ -47,4 +49,4 @@ G"Start.MinimizeDirectly": "True" #启动MAA后直接最小化 G"GUI.UseTray": "True" #显示托盘图标 G"GUI.MinimizeToTray": "False" #最小化时隐藏至托盘 "Start.EmulatorPath" #模拟器路径 -"Connect.AdbPath" #ADB路径 \ No newline at end of file +"Start.EmulatorAddCommand": "-v 2" #附加命令 \ No newline at end of file diff --git a/resources/version.json b/resources/version.json index 6efddc7..0752ac1 100644 --- a/resources/version.json +++ b/resources/version.json @@ -1,11 +1,16 @@ { - "main_version": "4.3.3.1", + "main_version": "4.3.4.1", "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.3.1": { + "4.3.4.1": { + "新增功能": [ + "开始任务前自动释放ADB端口" + ], "程序优化": [ - "request 添加超时限制" + "request 添加超时限制", + "用户任务运行流程改进", + "自动代理中模拟器改由AUTO_MAA控制" ] }, "4.3.3.0": { From fe1910d16f45d75932b1b1ed8fc2532f1e86fa2f Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Tue, 15 Apr 2025 22:34:37 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=A1=B9=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ui/member_manager.py | 6 +++--- app/ui/queue_manager.py | 2 +- resources/version.json | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py index 65b77fa..6c2c66d 100644 --- a/app/ui/member_manager.py +++ b/app/ui/member_manager.py @@ -612,7 +612,7 @@ class MemberManager(QWidget): self.card_TaskTransitionMethod = ComboBoxSettingCard( icon=FluentIcon.PAGE_RIGHT, title="任务切换方式", - content="简洁用户列表下相邻两个任务间的切换方式", + content="相邻两个任务间的切换方式,使用“详细”配置的用户固定为“重启模拟器”", texts=["直接切换账号", "重启明日方舟", "重启模拟器"], qconfig=self.config, configItem=self.config.RunSet_TaskTransitionMethod, @@ -621,7 +621,7 @@ class MemberManager(QWidget): self.card_EnhanceTask = ComboBoxSettingCard( icon=FluentIcon.PAGE_RIGHT, title="自动代理增效任务", - content="自动代理时的额外操作,此操作无法区分多开,可能会干扰其他任务,也可能关闭您正在使用的模拟器", + content="自动代理时的额外操作,此操作无法区分多开模拟器,可能会干扰其他任务,也可能关闭您正在使用的模拟器", texts=[ "禁用", "强制关闭ADB", @@ -635,7 +635,7 @@ class MemberManager(QWidget): self.ProxyTimesLimit = SpinBoxSettingCard( icon=FluentIcon.PAGE_RIGHT, title="用户单日代理次数上限", - content="当用户本日代理成功次数超过该阈值时跳过代理,阈值为“0”时视为无代理次数上限", + content="当用户本日代理成功次数达到该阈值时跳过代理,阈值为“0”时视为无代理次数上限", range=(0, 1024), qconfig=self.config, configItem=self.config.RunSet_ProxyTimesLimit, diff --git a/app/ui/queue_manager.py b/app/ui/queue_manager.py index 1982eab..ccefa6f 100644 --- a/app/ui/queue_manager.py +++ b/app/ui/queue_manager.py @@ -421,7 +421,7 @@ class QueueManager(QWidget): self.card_Enable = SwitchSettingCard( icon=FluentIcon.HOME, title="状态", - content="调度队列状态", + content="调度队列状态,仅启用时会执行定时任务", qconfig=self.config, configItem=self.config.queueSet_Enabled, parent=self, diff --git a/resources/version.json b/resources/version.json index 0752ac1..a5012fd 100644 --- a/resources/version.json +++ b/resources/version.json @@ -10,7 +10,8 @@ "程序优化": [ "request 添加超时限制", "用户任务运行流程改进", - "自动代理中模拟器改由AUTO_MAA控制" + "自动代理中模拟器改由AUTO_MAA控制", + "修正部分配置项文案" ] }, "4.3.3.0": { From e8d592ae76e4837282f8d143c5f3d0f72e2e68ed Mon Sep 17 00:00:00 2001 From: aoxuan Date: Wed, 16 Apr 2025 16:58:22 +0800 Subject: [PATCH 5/6] =?UTF-8?q?refactor(app):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=85=B3=E5=8D=A1=E6=8E=89=E8=90=BD=E7=89=A9=E5=93=81=E6=AD=A3?= =?UTF-8?q?=E5=88=99=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/core/config.py b/app/core/config.py index 92fa29c..7709786 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -1368,7 +1368,7 @@ class AppConfig(GlobalConfig): # 如果已经找到了关卡,处理掉落物 if current_stage: item_match: List[str] = re.findall( - r"^(?!\[)([\u4e00-\u9fa5A-Za-z0-9\-]+)\s*:\s*([\d,]+)(?:\s*\(\+[\d,]+\))?", + r"^(?!\[)(\S+?)\s*:\s*([\d,]+)(?:\s*\(\+[\d,]+\))?", line, re.M, ) From 5e4660670f38db177235775148194672483a24b2 Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Sun, 20 Apr 2025 00:01:49 +0800 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20=E6=80=A7=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调度队列历史记录归入配置类管理 - 添加.gitignore - 工作流删除冗余部分 - 自动代理与人工排查结束后MAA恢复到全局配置 #40 - 网络相关操作由子线程执行 --- .github/workflows/build-app.yml | 34 ++----- .github/workflows/build-pre.yml | 174 -------------------------------- .gitignore | 8 ++ app/core/__init__.py | 2 + app/core/config.py | 66 ++++++------ app/core/main_info_bar.py | 5 +- app/core/network.py | 120 ++++++++++++++++++++++ app/core/task_manager.py | 36 +++---- app/core/timer.py | 5 +- app/models/MAA.py | 3 + app/ui/Widget.py | 25 +++++ app/ui/dispatch_center.py | 18 +++- app/ui/home.py | 69 ++++++------- app/ui/member_manager.py | 25 ++--- app/ui/queue_manager.py | 21 ++-- app/ui/setting.py | 100 +++++++++--------- resources/version.json | 11 +- 17 files changed, 331 insertions(+), 391 deletions(-) delete mode 100644 .github/workflows/build-pre.yml create mode 100644 .gitignore create mode 100644 app/core/network.py diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.yml index 506e9ce..ae188ab 100644 --- a/.github/workflows/build-app.yml +++ b/.github/workflows/build-app.yml @@ -102,20 +102,8 @@ jobs: with: name: version_info path: ./ - - name: Check if release exists - id: check_if_release_exists - run: | - release_id=$(gh release view $(sed 's/\r$//g' <(head -n 1 version_info.txt)) --json id --jq .id || true) - if [[ -z $release_id ]]; then - echo "release_exists=false" >> $GITHUB_OUTPUT - else - echo "release_exists=true" >> $GITHUB_OUTPUT - fi - env: - GITHUB_TOKEN: ${{ secrets.WORKFLOW_TOKEN }} - name: Create release id: create_release - if: steps.check_if_release_exists.outputs.release_exists == 'false' run: | set -xe shopt -s nullglob @@ -124,22 +112,12 @@ jobs: NOTES_MAIN="$(sed 's/\r$//g' <(tail -n +3 version_info.txt))" NOTES_TAIL="\`\`\`本release通过GitHub Actions自动构建\`\`\`" NOTES="$NOTES_MAIN

$NOTES_TAIL" - gh release create "$TAGNAME" --target "main" --title "$NAME" --notes "$NOTES" artifacts/* - env: - GITHUB_TOKEN: ${{ secrets.WORKFLOW_TOKEN }} - - name: Update release - id: update_release - if: steps.check_if_release_exists.outputs.release_exists == 'true' - run: | - set -xe - shopt -s nullglob - NAME="$(sed 's/\r$//g' <(head -n 1 version_info.txt))" - TAGNAME="$(sed 's/\r$//g' <(head -n 1 version_info.txt))" - NOTES_MAIN="$(sed 's/\r$//g' <(tail -n +3 version_info.txt))" - NOTES_TAIL="\`\`\`本release通过GitHub Actions自动构建\`\`\`" - NOTES="$NOTES_MAIN

$NOTES_TAIL" - gh release delete "$TAGNAME" --yes - gh release create "$TAGNAME" --target "main" --title "$NAME" --notes "$NOTES" artifacts/* + if [ "${{ github.ref_name }}" == "main" ]; then + PRERELEASE_FLAG="" + else + PRERELEASE_FLAG="--prerelease" + fi + gh release create "$TAGNAME" --target "main" --title "$NAME" --notes "$NOTES" $PRERELEASE_FLAG artifacts/* env: GITHUB_TOKEN: ${{ secrets.WORKFLOW_TOKEN }} - name: Trigger MirrorChyanUploading diff --git a/.github/workflows/build-pre.yml b/.github/workflows/build-pre.yml deleted file mode 100644 index 0de837d..0000000 --- a/.github/workflows/build-pre.yml +++ /dev/null @@ -1,174 +0,0 @@ -# -# Copyright © <2024> - -# This file is part of AUTO_MAA. - -# AUTO_MAA is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation, either version 3 of the License, -# or (at your option) any later version. - -# AUTO_MAA is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -# the GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with AUTO_MAA. If not, see . - -# DLmaster_361@163.com - -name: Build AUTO_MAA_Pre - -on: - workflow_dispatch: - -permissions: - contents: write - actions: write - -jobs: - pre_check: - name: Pre Checks - runs-on: ubuntu-latest - steps: - - name: Repo Check - id: repo_check - run: | - if [[ "$GITHUB_REPOSITORY" != "DLmaster361/AUTO_MAA" ]]; then - echo "When forking this repository to make your own builds, you have to adjust this check." - exit 1 - fi - exit 0 - build_AUTO_MAA: - runs-on: windows-latest - needs: pre_check - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install flake8 pytest - pip install -r requirements.txt - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Package - id: package - run: | - copy app\utils\package.py .\ - python package.py - - name: Read version - id: read_version - run: | - $MAIN_VERSION=(Get-Content -Path "version_info.txt" -TotalCount 1).Trim() - "AUTO_MAA_version=$MAIN_VERSION" | Out-File -FilePath $env:GITHUB_ENV -Append - $UPDATER_VERSION=(Get-Content -Path "version_info.txt" -TotalCount 2 | Select-Object -Index 1).Trim() - "updater_version=$UPDATER_VERSION" | Out-File -FilePath $env:GITHUB_ENV -Append - - name: Upload Artifact - uses: actions/upload-artifact@v4 - with: - name: AUTO_MAA_${{ env.AUTO_MAA_version }} - path: | - AUTO_MAA_${{ env.AUTO_MAA_version }}.zip - - name: Upload Version_Info Artifact - uses: actions/upload-artifact@v4 - with: - name: version_info - path: version_info.txt - publish_prerelease: - name: Publish prerelease - needs: build_AUTO_MAA - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Download artifacts - uses: actions/download-artifact@v4 - with: - pattern: AUTO_MAA_* - merge-multiple: true - path: artifacts - - name: Download Version_Info - uses: actions/download-artifact@v4 - with: - name: version_info - path: ./ - - name: Check if release exists - id: check_if_release_exists - run: | - release_id=$(gh release view $(sed 's/\r$//g' <(head -n 1 version_info.txt)) --json id --jq .id || true) - if [[ -z $release_id ]]; then - echo "release_exists=false" >> $GITHUB_OUTPUT - else - echo "release_exists=true" >> $GITHUB_OUTPUT - fi - env: - GITHUB_TOKEN: ${{ secrets.WORKFLOW_TOKEN }} - - name: Create prerelease - id: create_prerelease - if: steps.check_if_release_exists.outputs.release_exists == 'false' - run: | - set -xe - shopt -s nullglob - NAME="$(sed 's/\r$//g' <(head -n 1 version_info.txt))" - TAGNAME="$(sed 's/\r$//g' <(head -n 1 version_info.txt))" - NOTES_MAIN="$(sed 's/\r$//g' <(tail -n +3 version_info.txt))" - NOTES_TAIL="\`\`\`本release通过GitHub Actions自动构建\`\`\`" - NOTES="$NOTES_MAIN

$NOTES_TAIL" - gh release create "$TAGNAME" --target "main" --title "$NAME" --notes "$NOTES" --prerelease artifacts/* - env: - GITHUB_TOKEN: ${{ secrets.WORKFLOW_TOKEN }} - - name: Update prerelease - id: update_prerelease - if: steps.check_if_release_exists.outputs.release_exists == 'true' - run: | - set -xe - shopt -s nullglob - NAME="$(sed 's/\r$//g' <(head -n 1 version_info.txt))" - TAGNAME="$(sed 's/\r$//g' <(head -n 1 version_info.txt))" - NOTES_MAIN="$(sed 's/\r$//g' <(tail -n +3 version_info.txt))" - NOTES_TAIL="\`\`\`本release通过GitHub Actions自动构建\`\`\`" - NOTES="$NOTES_MAIN

$NOTES_TAIL" - gh release delete "$TAGNAME" --yes - gh release create "$TAGNAME" --target "main" --title "$NAME" --notes "$NOTES" --prerelease artifacts/* - env: - GITHUB_TOKEN: ${{ secrets.WORKFLOW_TOKEN }} - - name: Trigger MirrorChyanUploading - run: | - gh workflow run --repo $GITHUB_REPOSITORY mirrorchyan - gh workflow run --repo $GITHUB_REPOSITORY mirrorchyan_release_note - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Setup SSH Key - run: | - mkdir -p ~/.ssh - echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ssh-keyscan -H ${{ secrets.SERVER_IP }} >> ~/.ssh/known_hosts - - 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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f712af --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +__pycache__/ +config/ +data/ +debug/ +history/ +resources/notice.json +resources/theme_image.json +resources/images/Home/BannerTheme.jpg \ No newline at end of file diff --git a/app/core/__init__.py b/app/core/__init__.py index b4b072b..cdf8c0a 100644 --- a/app/core/__init__.py +++ b/app/core/__init__.py @@ -31,6 +31,7 @@ __license__ = "GPL-3.0 license" from .config import QueueConfig, MaaConfig, MaaUserConfig, Config from .main_info_bar import MainInfoBar +from .network import Network from .task_manager import Task, TaskManager from .timer import MainTimer @@ -40,6 +41,7 @@ __all__ = [ "MaaConfig", "MaaUserConfig", "MainInfoBar", + "Network", "Task", "TaskManager", "MainTimer", diff --git a/app/core/config.py b/app/core/config.py index 7709786..befaab9 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -32,8 +32,6 @@ import json import sys import shutil import re -import requests -import time import base64 from datetime import datetime, timedelta from collections import defaultdict @@ -53,6 +51,8 @@ from qfluentwidgets import ( from urllib.parse import urlparse from typing import Union, Dict, List +from .network import Network + class UrlListValidator(ConfigValidator): """Url list validator""" @@ -319,6 +319,13 @@ class QueueConfig(QConfig): self.queue_Member_9 = OptionsConfigItem("Queue", "Member_9", "禁用") self.queue_Member_10 = OptionsConfigItem("Queue", "Member_10", "禁用") + self.Data_LastProxyTime = ConfigItem( + "Data", "LastProxyTime", "2000-01-01 00:00:00" + ) + self.Data_LastProxyHistory = ConfigItem( + "Data", "LastProxyHistory", "暂无历史运行记录" + ) + def toDict(self, serialize=True): """convert config items to `dict`""" items = {} @@ -599,7 +606,7 @@ class MaaUserConfig(QConfig): class AppConfig(GlobalConfig): - VERSION = "4.3.4.1" + VERSION = "4.3.4.2" gameid_refreshed = Signal() PASSWORD_refreshed = Signal() @@ -614,7 +621,6 @@ class AppConfig(GlobalConfig): self.log_path = self.app_path / "debug/AUTO_MAA.log" self.database_path = self.app_path / "data/data.db" self.config_path = self.app_path / "config/config.json" - self.history_path = self.app_path / "history/main.json" self.key_path = self.app_path / "data/key" self.gameid_path = self.app_path / "data/gameid.txt" self.version_path = self.app_path / "resources/version.json" @@ -675,21 +681,18 @@ class AppConfig(GlobalConfig): def get_gameid(self) -> None: # 从MAA服务器获取活动关卡信息 - for _ in range(3): - try: - response = requests.get( - "https://ota.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json", - timeout=10, - ) - gameid_infos: List[ - Dict[str, Union[str, Dict[str, Union[str, int]]]] - ] = response.json()["Official"]["sideStoryStage"] - break - except Exception as e: - err = e - time.sleep(0.1) + Network.set_info( + mode="get", + url="https://ota.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json", + ) + Network.start() + Network.loop.exec() + if Network.stutus_code == 200: + gameid_infos: List[Dict[str, Union[str, Dict[str, Union[str, int]]]]] = ( + Network.response_json["Official"]["sideStoryStage"] + ) else: - logger.warning(f"无法从MAA服务器获取活动关卡信息:{err}") + logger.warning(f"无法从MAA服务器获取活动关卡信息:{Network.error_message}") gameid_infos = [] gameid_dict = {"value": [], "text": []} @@ -1540,24 +1543,15 @@ class AppConfig(GlobalConfig): def save_history(self, key: str, content: dict) -> None: """保存历史记录""" - history = {} - if self.history_path.exists(): - with self.history_path.open(mode="r", encoding="utf-8") as f: - history = json.load(f) - history[key] = content - with self.history_path.open(mode="w", encoding="utf-8") as f: - json.dump(history, f, ensure_ascii=False, indent=4) - - def get_history(self, key: str) -> dict: - """获取历史记录""" - - history = {} - if self.history_path.exists(): - with self.history_path.open(mode="r", encoding="utf-8") as f: - history = json.load(f) - return history.get( - key, {"Time": "0000-00-00 00:00", "History": "暂无历史运行记录"} - ) + if key in self.queue_dict: + self.queue_dict[key]["Config"].set( + self.queue_dict[key]["Config"].Data_LastProxyTime, content["Time"] + ) + self.queue_dict[key]["Config"].set( + self.queue_dict[key]["Config"].Data_LastProxyHistory, content["History"] + ) + else: + logger.warning(f"保存历史记录时未找到调度队列: {key}") Config = AppConfig() diff --git a/app/core/main_info_bar.py b/app/core/main_info_bar.py index 5ed7acc..97481e1 100644 --- a/app/core/main_info_bar.py +++ b/app/core/main_info_bar.py @@ -27,10 +27,7 @@ v4.3 from loguru import logger from PySide6.QtCore import Qt -from qfluentwidgets import ( - InfoBar, - InfoBarPosition, -) +from qfluentwidgets import InfoBar, InfoBarPosition class _MainInfoBar: diff --git a/app/core/network.py b/app/core/network.py new file mode 100644 index 0000000..f15e901 --- /dev/null +++ b/app/core/network.py @@ -0,0 +1,120 @@ +# +# Copyright © <2024> + +# This file is part of AUTO_MAA. + +# AUTO_MAA is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, +# or (at your option) any later version. + +# AUTO_MAA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with AUTO_MAA. If not, see . + +# DLmaster_361@163.com + +""" +AUTO_MAA +AUTO_MAA网络请求线程 +v4.3 +作者:DLmaster_361 +""" + +from loguru import logger +from PySide6.QtCore import QThread, QEventLoop, QTimer +import time +import requests +from pathlib import Path + + +class _Network(QThread): + + max_retries = 3 + timeout = 10 + backoff_factor = 0.1 + + def __init__(self) -> None: + super().__init__() + + self.if_running = False + self.mode = None + self.url = None + self.loop = QEventLoop() + self.wait_loop = QEventLoop() + + @logger.catch + def run(self) -> None: + """运行网络请求线程""" + + self.if_running = True + + print(self.url) + + if self.mode == "get": + self.get_json(self.url) + elif self.mode == "get_file": + self.get_file(self.url, self.path) + + self.if_running = False + + def set_info(self, mode: str, url: str, path: Path = None) -> None: + """设置网络请求信息""" + + while self.if_running: + QTimer.singleShot(self.backoff_factor * 1000, self.wait_loop.quit) + self.wait_loop.exec() + + self.mode = mode + self.url = url + self.path = path + + self.stutus_code = None + self.response_json = None + self.error_message = None + + def get_json(self, url: str) -> None: + """通过get方法获取json数据""" + + for _ in range(self.max_retries): + try: + response = requests.get(url, timeout=self.timeout) + self.stutus_code = response.status_code + self.response_json = response.json() + self.error_message = None + break + except Exception as e: + self.stutus_code = response.status_code if response else None + self.response_json = None + self.error_message = str(e) + time.sleep(self.backoff_factor) + + self.loop.quit() + print("quited") + + def get_file(self, url: str, path: Path) -> None: + """通过get方法获取json数据""" + + try: + response = requests.get(url, timeout=10) + if response.status_code == 200: + with open(path, "wb") as file: + file.write(response.content) + self.stutus_code = response.status_code + else: + self.stutus_code = response.status_code + self.error_message = "下载失败" + + except Exception as e: + self.stutus_code = response.status_code if response else None + self.error_message = str(e) + + self.loop.quit() + print("quited-----") + + +Network = _Network() diff --git a/app/core/task_manager.py b/app/core/task_manager.py index a6dedf9..4b8b016 100644 --- a/app/core/task_manager.py +++ b/app/core/task_manager.py @@ -229,37 +229,33 @@ class _TaskManager(QObject): self.task_dict[name].quit() self.task_dict[name].wait() - def remove_task(self, mode: str, name: str, logs: str): + def remove_task(self, mode: str, name: str, logs: list): """任务结束后的处理""" logger.info(f"任务结束:{name}") MainInfoBar.push_info_bar("info", "任务结束", name, 3000) self.task_dict[name].deleteLater() - - if len(logs) > 0: - time = logs[0][1]["Time"] - history = "" - for log in logs: - Config.save_history(log[0], log[1]) - history += ( - f"任务名称:{log[0]},{log[1]["History"].replace("\n","\n ")}\n" - ) - Config.save_history(name, {"Time": time, "History": history}) - else: - Config.save_history( - name, - { - "Time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), - "History": "没有任务被执行", - }, - ) - self.task_dict.pop(name) Config.running_list.remove(name) if "调度队列" in name and "人工排查" not in mode: + if len(logs) > 0: + time = logs[0][1]["Time"] + history = "" + for log in logs: + history += f"任务名称:{log[0]},{log[1]["History"].replace("\n","\n ")}\n" + Config.save_history(name, {"Time": time, "History": history}) + else: + Config.save_history( + name, + { + "Time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + "History": "没有任务被执行", + }, + ) + if ( Config.queue_dict[name]["Config"].get( Config.queue_dict[name]["Config"].queueSet_AfterAccomplish diff --git a/app/core/timer.py b/app/core/timer.py index bb9fd53..a028fef 100644 --- a/app/core/timer.py +++ b/app/core/timer.py @@ -64,8 +64,6 @@ class _MainTimer(QWidget): if not info["Config"].get(info["Config"].queueSet_Enabled): continue - history = Config.get_history(name) - data = info["Config"].toDict() time_set = [ @@ -77,7 +75,8 @@ class _MainTimer(QWidget): curtime = datetime.now().strftime("%Y-%m-%d %H:%M") if ( curtime[11:16] in time_set - and curtime != history["Time"][:16] + and curtime + != info["Config"].get(info["Config"].Data_LastProxyTime)[:16] and name not in Config.running_list ): diff --git a/app/models/MAA.py b/app/models/MAA.py index a5324aa..13ae979 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -597,6 +597,9 @@ class MaaManager(QObject): if self.isInterruptionRequested: System.kill_process(self.maa_exe_path) + # 复原MAA配置文件 + shutil.copy(self.config_path / "Default/gui.json", self.maa_set_path) + # 更新用户数据 updated_info = {_[2]: self.data[_[2]] for _ in self.user_list} self.update_user_info.emit(self.config_path.name, updated_info) diff --git a/app/ui/Widget.py b/app/ui/Widget.py index 2d29405..b50cb8c 100644 --- a/app/ui/Widget.py +++ b/app/ui/Widget.py @@ -870,6 +870,31 @@ class TimeEditSettingCard(SettingCard): self.TimeEdit.setTime(QTime.fromString(value, "HH:mm")) +class HistoryCard(HeaderCardWidget): + + def __init__(self, qconfig: QConfig, configItem: ConfigItem, parent=None): + super().__init__(parent) + self.setTitle("历史运行记录") + + self.qconfig = qconfig + self.configItem = configItem + + self.text = TextBrowser() + self.text.setMinimumHeight(300) + + if configItem: + self.setValue(self.qconfig.get(configItem)) + configItem.valueChanged.connect(self.setValue) + + self.viewLayout.addWidget(self.text) + + def setValue(self, content: str): + if self.configItem: + self.qconfig.set(self.configItem, content) + + self.text.setPlainText(content) + + class UrlItem(QWidget): """Url item""" diff --git a/app/ui/dispatch_center.py b/app/ui/dispatch_center.py index 657cbc7..54b07c6 100644 --- a/app/ui/dispatch_center.py +++ b/app/ui/dispatch_center.py @@ -143,9 +143,11 @@ class DispatchCenter(QWidget): task.update_log_text.connect( self.script_list["主调度台"].info.log_text.text.setText ) - task.accomplish.connect(lambda: self.disconnect_main_board(task.name)) + task.accomplish.connect( + lambda logs: self.disconnect_main_board(task.name, logs) + ) - def disconnect_main_board(self, name: str) -> None: + def disconnect_main_board(self, name: str, logs: list) -> None: """断开主调度台""" self.script_list["主调度台"].top_bar.Lable.hide() @@ -156,9 +158,15 @@ class DispatchCenter(QWidget): self.script_list["主调度台"].top_bar.button.clicked.connect( self.script_list["主调度台"].top_bar.start_task ) - self.script_list["主调度台"].info.log_text.text.setText( - Config.get_history(name)["History"] - ) + if len(logs) > 0: + history = "" + for log in logs: + history += ( + f"任务名称:{log[0]},{log[1]["History"].replace("\n","\n ")}\n" + ) + self.script_list["主调度台"].info.log_text.text.setText(history) + else: + self.script_list["主调度台"].info.log_text.text.setText("没有任务被执行") def update_top_bar(self): """更新顶栏""" diff --git a/app/ui/home.py b/app/ui/home.py index 783cae3..addc407 100644 --- a/app/ui/home.py +++ b/app/ui/home.py @@ -45,13 +45,11 @@ from qfluentwidgets import ( ) import re import shutil -import requests import json -import time from datetime import datetime from pathlib import Path -from app.core import Config, MainInfoBar +from app.core import Config, MainInfoBar, Network from .Widget import Banner, IconButton @@ -199,24 +197,21 @@ class Home(QWidget): elif Config.get(Config.function_HomeImageMode) == "主题图像": # 从远程服务器获取最新主题图像 - for _ in range(3): - try: - response = requests.get( - "https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/theme_image.json", - timeout=10, - ) - theme_image = response.json() - break - except Exception as e: - err = e - time.sleep(0.1) + Network.set_info( + mode="get", + url="https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/theme_image.json", + ) + Network.start() + Network.loop.exec() + if Network.stutus_code == 200: + theme_image = Network.response_json else: - logger.error(f"获取最新主题图像时出错:\n{err}") + logger.warning(f"获取最新主题图像时出错:{Network.error_message}") MainInfoBar.push_info_bar( - "error", - "主题图像获取失败", - f"获取最新主题图像信息时出错!", - -1, + "warning", + "获取最新主题图像时出错", + f"网络错误:{Network.stutus_code}", + 5000, ) return None @@ -239,15 +234,22 @@ class Home(QWidget): > time_local ): - response = requests.get(theme_image["url"], timeout=10) - if response.status_code == 200: + Network.set_info( + mode="get_file", + url=theme_image["url"], + path=Config.app_path / "resources/images/Home/BannerTheme.jpg", + ) + Network.start() + Network.loop.exec() - with open( - Config.app_path / "resources/images/Home/BannerTheme.jpg", "wb" - ) as file: - file.write(response.content) + if Network.stutus_code == 200: - logger.info(f"主题图像「{theme_image["name"]}」下载成功") + with (Config.app_path / "resources/theme_image.json").open( + mode="w", encoding="utf-8" + ) as f: + json.dump(theme_image, f, ensure_ascii=False, indent=4) + + logger.success(f"主题图像「{theme_image["name"]}」下载成功") MainInfoBar.push_info_bar( "success", "主题图像下载成功", @@ -257,19 +259,14 @@ class Home(QWidget): else: - logger.error("主题图像下载失败") + logger.warning(f"下载最新主题图像时出错:{Network.error_message}") MainInfoBar.push_info_bar( - "error", - "主题图像下载失败", - f"主题图像下载失败:{response.status_code}", - -1, + "warning", + "下载最新主题图像时出错", + f"网络错误:{Network.stutus_code}", + 5000, ) - with (Config.app_path / "resources/theme_image.json").open( - mode="w", encoding="utf-8" - ) as f: - json.dump(theme_image, f, ensure_ascii=False, indent=4) - else: logger.info("主题图像已是最新") diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py index 6c2c66d..e5d60ee 100644 --- a/app/ui/member_manager.py +++ b/app/ui/member_manager.py @@ -49,15 +49,13 @@ from qfluentwidgets import ( PrimaryToolButton, ) from PySide6.QtCore import Qt, Signal -import requests -import time from datetime import datetime from functools import partial from pathlib import Path from typing import List import shutil -from app.core import Config, MainInfoBar, TaskManager, MaaConfig, MaaUserConfig +from app.core import Config, MainInfoBar, TaskManager, MaaConfig, MaaUserConfig, Network from app.services import Crypto from app.utils import DownloadManager from .Widget import ( @@ -337,21 +335,18 @@ class MemberManager(QWidget): return None # 从mirrorc服务器获取最新版本信息 - for _ in range(3): - try: - response = requests.get( - "https://mirrorchyan.com/api/resources/MAA/latest?user_agent=AutoMaaGui&os=win&arch=x64&channel=stable", - timeout=10, - ) - maa_info = response.json() - break - except Exception as e: - err = e - time.sleep(0.1) + Network.set_info( + mode="get", + url="https://mirrorchyan.com/api/resources/MAA/latest?user_agent=AutoMaaGui&os=win&arch=x64&channel=stable", + ) + Network.start() + Network.loop.exec() + if Network.stutus_code == 200: + maa_info = Network.response_json else: choice = MessageBox( "错误", - f"获取版本信息时出错:\n{err}", + f"获取版本信息时出错:\n{Network.error_message}", self.window(), ) choice.cancelButton.hide() diff --git a/app/ui/queue_manager.py b/app/ui/queue_manager.py index ccefa6f..58e2a3c 100644 --- a/app/ui/queue_manager.py +++ b/app/ui/queue_manager.py @@ -39,7 +39,6 @@ from qfluentwidgets import ( FluentIcon, MessageBox, HeaderCardWidget, - TextBrowser, CommandBar, ) from PySide6.QtCore import Qt @@ -52,6 +51,7 @@ from .Widget import ( LineEditSettingCard, TimeEditSettingCard, NoOptionComboBoxSettingCard, + HistoryCard, ) @@ -387,7 +387,11 @@ class QueueManager(QWidget): self.queue_set = self.QueueSetSettingCard(self.config, self) self.time = self.TimeSettingCard(self.config, self) self.task = self.TaskSettingCard(self.config, self) - self.history = self.HistoryCard(f"调度队列_{uid}", self) + self.history = HistoryCard( + qconfig=self.config, + configItem=self.config.Data_LastProxyHistory, + parent=self, + ) content_layout.addWidget(self.queue_set) content_layout.addWidget(self.time) @@ -704,16 +708,3 @@ class QueueManager(QWidget): Layout.addWidget(self.card_Member_10) self.viewLayout.addLayout(Layout) - - class HistoryCard(HeaderCardWidget): - - def __init__(self, name: str, parent=None): - super().__init__(parent) - self.setTitle("历史运行记录") - - self.text = TextBrowser() - self.text.setMinimumHeight(300) - history = Config.get_history(name) - self.text.setPlainText(history["History"]) - - self.viewLayout.addWidget(self.text) diff --git a/app/ui/setting.py b/app/ui/setting.py index 68d0ef2..e0a4b11 100644 --- a/app/ui/setting.py +++ b/app/ui/setting.py @@ -26,11 +26,7 @@ v4.3 """ from loguru import logger -from PySide6.QtWidgets import ( - QWidget, - QApplication, - QVBoxLayout, -) +from PySide6.QtWidgets import QWidget, QVBoxLayout from PySide6.QtCore import Qt from qfluentwidgets import ( ScrollArea, @@ -48,14 +44,13 @@ import re import json import time import shutil -import requests import subprocess from datetime import datetime from packaging import version from pathlib import Path from typing import Dict, List, Union -from app.core import Config, MainInfoBar +from app.core import Config, MainInfoBar, Network from app.services import Crypto, System, Notify from .Widget import ( SwitchSettingCard, @@ -93,7 +88,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(self.check_update) + self.updater.card_CheckUpdate.clicked.connect( + lambda: self.check_update(if_click=True) + ) self.other.card_Notice.clicked.connect(self.show_notice) content_layout.addWidget(self.function) @@ -263,35 +260,36 @@ class Setting(QWidget): if choice.exec(): break - def check_update(self) -> None: + def check_update(self, if_click: bool = False) -> None: """检查版本更新,调起文件下载进程""" current_version = list(map(int, Config.VERSION.split("."))) - # 从远程服务器获取最新版本信息 - for _ in range(3): - try: - response = requests.get( - f"https://mirrorchyan.com/api/resources/AUTO_MAA/latest?user_agent=AutoMaaGui¤t_version={version_text(current_version)}&cdk={Crypto.win_decryptor(Config.get(Config.update_MirrorChyanCDK))}&channel={Config.get(Config.update_UpdateType)}", - timeout=10, - ) - version_info: Dict[str, Union[int, str, Dict[str, str]]] = ( - response.json() - ) - break - except Exception as e: - err = e - time.sleep(0.1) - else: - choice = MessageBox( - "错误", - f"获取版本信息时出错:\n{err}", - self.window(), + if Network.if_running and if_click: + MainInfoBar.push_info_bar( + "warning", "请求速度过快", "上个网络请求还未结束,请稍等片刻", 5000 ) - choice.cancelButton.hide() - choice.buttonLayout.insertStretch(1) - if choice.exec(): - return None + return None + # 从远程服务器获取最新版本信息 + Network.set_info( + mode="get", + url=f"https://mirrorchyan.com/api/resources/AUTO_MAA/latest?user_agent=AutoMaaGui¤t_version={version_text(current_version)}&cdk={Crypto.win_decryptor(Config.get(Config.update_MirrorChyanCDK))}&channel={Config.get(Config.update_UpdateType)}", + ) + Network.start() + Network.loop.exec() + if Network.stutus_code == 200: + version_info: Dict[str, Union[int, str, Dict[str, str]]] = ( + Network.response_json + ) + else: + logger.warning(f"获取版本信息时出错:{Network.error_message}") + MainInfoBar.push_info_bar( + "warning", + "获取版本信息时出错", + f"网络错误:{Network.stutus_code}", + 5000, + ) + return None if version_info["code"] != 0: @@ -415,32 +413,26 @@ class Setting(QWidget): else: MainInfoBar.push_info_bar("success", "更新检查", "已是最新版本~", 3000) - def show_notice(self, if_show: bool = True): + def show_notice(self, if_show: bool = True) -> None: """显示公告""" # 从远程服务器获取最新公告 - for _ in range(3): - try: - response = requests.get( - "https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/notice.json", - timeout=10, - ) - notice = response.json() - break - except Exception as e: - err = e - time.sleep(0.1) + Network.set_info( + mode="get", + url="https://gitee.com/DLmaster_361/AUTO_MAA/raw/server/notice.json", + ) + Network.start() + Network.loop.exec() + if Network.stutus_code == 200: + notice = Network.response_json else: - logger.warning(f"获取最新公告时出错:\n{err}") - if if_show: - choice = Dialog( - "网络错误", - f"获取最新公告时出错:\n{err}", - self, - ) - choice.cancelButton.hide() - choice.buttonLayout.insertStretch(1) - choice.exec() + logger.warning(f"获取最新公告时出错:{Network.error_message}") + MainInfoBar.push_info_bar( + "warning", + "获取最新公告时出错", + f"网络错误:{Network.stutus_code}", + 5000, + ) return None if (Config.app_path / "resources/notice.json").exists(): diff --git a/resources/version.json b/resources/version.json index a5012fd..8565d1c 100644 --- a/resources/version.json +++ b/resources/version.json @@ -1,8 +1,17 @@ { - "main_version": "4.3.4.1", + "main_version": "4.3.4.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.2": { + "程序优化": [ + "调度队列历史记录归入配置类管理", + "添加.gitignore", + "工作流删除冗余部分", + "自动代理与人工排查结束后MAA恢复到全局配置 #40", + "网络相关操作由子线程执行" + ] + }, "4.3.4.1": { "新增功能": [ "开始任务前自动释放ADB端口"