Compare commits

...

18 Commits

Author SHA1 Message Date
DLmaster361
494b655156 Merge branch 'dev' 2025-04-20 00:02:42 +08:00
DLmaster361
2940f2557c Merge branch 'DLMS_dev' into dev 2025-04-20 00:02:25 +08:00
DLmaster361
5e4660670f chore: 性能优化
- 调度队列历史记录归入配置类管理
- 添加.gitignore
- 工作流删除冗余部分
- 自动代理与人工排查结束后MAA恢复到全局配置 #40
- 网络相关操作由子线程执行
2025-04-20 00:01:49 +08:00
e8d592ae76 refactor(app): 优化关卡掉落物品正则匹配 2025-04-16 16:58:22 +08:00
DLmaster361
97ea51df59 docs: README链接修复 2025-04-16 11:23:24 +08:00
DLmaster361
986061dc97 Merge branch 'DLMS_dev' into dev 2025-04-15 22:34:52 +08:00
DLmaster361
fe1910d16f fix: 修正部分配置项文案 2025-04-15 22:34:37 +08:00
DLmaster361
63cb1aaa74 feat: 自动代理流程优化 2025-04-15 22:15:59 +08:00
49ebd50077 refactor(ui): 优化模拟器老板键设置卡片的提示文本 2025-04-14 16:04:53 +08:00
DLmaster361
4a6f874210 fix: request 添加超时限制 2025-04-14 15:03:29 +08:00
DLmaster
9394c7a9c5 Merge branch 'dev' 2025-04-13 16:52:12 +08:00
DLmaster
7e502420fa fix: 修复更新器无法下载MAA的异常 2025-04-13 16:46:54 +08:00
DLmaster
12f4b764de Merge branch 'dev' 2025-04-13 02:50:34 +08:00
DLmaster
4da4b7d552 fix: 发布到stable 2025-04-13 02:50:23 +08:00
DLmaster
d38abbbaa0 Merge branch 'dev' 2025-04-13 00:46:14 +08:00
DLmaster
67bf7f649e fix(utils): 改回单文件打包 2025-04-13 00:45:47 +08:00
DLmaster
acb35403b0 Merge branch 'main' into dev 2025-04-12 23:10:19 +08:00
DLmaster
7d5dccc649 fix(ui): 修复更新器无法启动的异常 2025-04-12 23:09:47 +08:00
25 changed files with 564 additions and 557 deletions

View File

@@ -21,11 +21,7 @@
name: Build AUTO_MAA
on:
push:
branches: [ "main" ]
paths-ignore:
- '**.md'
- 'LICENSE'
workflow_dispatch:
permissions:
contents: write
@@ -106,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
@@ -128,22 +112,12 @@ jobs:
NOTES_MAIN="$(sed 's/\r$//g' <(tail -n +3 version_info.txt))"
NOTES_TAIL="\`\`\`本release通过GitHub Actions自动构建\`\`\`"
NOTES="$NOTES_MAIN<br><br>$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<br><br>$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

View File

@@ -1,178 +0,0 @@
# <AUTO_MAA:A MAA Multi Account Management and Automation Tool>
# Copyright © <2024> <DLmaster361>
# This file is part of AUTO_MAA.
# AUTO_MAA is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
# AUTO_MAA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
# the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with AUTO_MAA. If not, see <https://www.gnu.org/licenses/>.
# DLmaster_361@163.com
name: Build AUTO_MAA_Pre
on:
push:
branches: [ "dev" ]
paths-ignore:
- '**.md'
- 'LICENSE'
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<br><br>$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<br><br>$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

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
__pycache__/
config/
data/
debug/
history/
resources/notice.json
resources/theme_image.json
resources/images/Home/BannerTheme.jpg

View File

@@ -98,4 +98,4 @@ MAA多账号管理与自动化软件
如果喜欢这个项目的话,给作者来杯咖啡吧!
![payid](https://github.com/DLmaster361/AUTO_MAA/blob/main/resources/README/payid.png "payid")
![payid](resources/images/README/payid.png "payid")

View File

@@ -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",

View File

@@ -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.1.0"
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,20 +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"
)
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": []}
@@ -1367,7 +1371,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,
)
@@ -1539,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()

View File

@@ -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:

120
app/core/network.py Normal file
View File

@@ -0,0 +1,120 @@
# <AUTO_MAA:A MAA Multi Account Management and Automation Tool>
# Copyright © <2024> <DLmaster361>
# This file is part of AUTO_MAA.
# AUTO_MAA is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
# AUTO_MAA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
# the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with AUTO_MAA. If not, see <https://www.gnu.org/licenses/>.
# 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()

View File

@@ -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

View File

@@ -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
):

View File

@@ -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,
)
# 记录当前时间
@@ -571,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)
@@ -1273,11 +1302,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
# 覆写配置文件

View File

@@ -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):
"""发送测试通知到所有已启用的通知渠道"""

View File

@@ -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"""

View File

@@ -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):
"""更新顶栏"""

View File

@@ -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,23 +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"
)
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
@@ -238,15 +234,22 @@ class Home(QWidget):
> time_local
):
response = requests.get(theme_image["url"])
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",
"主题图像下载成功",
@@ -256,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("主题图像已是最新")

View File

@@ -238,6 +238,13 @@ class AUTO_MAA(MSFluentWindow):
# 清理旧日志
self.clean_old_logs()
# 清理临时更新器
if (Config.app_path / "AUTO_Updater.active.exe").exists():
try:
(Config.app_path / "AUTO_Updater.active.exe").unlink()
except Exception:
pass
# 检查密码
self.setting.check_PASSWORD()
@@ -399,11 +406,6 @@ class AUTO_MAA(MSFluentWindow):
self.show_ui("隐藏到托盘", if_quick=True)
# 清理临时更新器
if (Config.app_path / "AUTO_Updater.active.exe").exists():
System.kill_process(Config.app_path / "AUTO_Updater.active.exe")
(Config.app_path / "AUTO_Updater.active.exe").unlink()
# 清理各功能线程
MainTimer.Timer.stop()
MainTimer.Timer.deleteLater()

View File

@@ -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,20 +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=MaaWpfGui&os=win&arch=x64&channel=stable"
)
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()
@@ -372,7 +368,10 @@ class MemberManager(QWidget):
Path(folder),
"MAA",
maa_version,
{"thread_numb": Config.get(Config.update_ThreadNumb)},
{
"mode": "Proxy",
"thread_numb": Config.get(Config.update_ThreadNumb),
},
)
self.downloader.show()
self.downloader.run()
@@ -608,7 +607,7 @@ class MemberManager(QWidget):
self.card_TaskTransitionMethod = ComboBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="任务切换方式",
content="简洁用户列表下相邻两个任务间的切换方式",
content="相邻两个任务间的切换方式,使用“详细”配置的用户固定为“重启模拟器”",
texts=["直接切换账号", "重启明日方舟", "重启模拟器"],
qconfig=self.config,
configItem=self.config.RunSet_TaskTransitionMethod,
@@ -617,7 +616,7 @@ class MemberManager(QWidget):
self.card_EnhanceTask = ComboBoxSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="自动代理增效任务",
content="自动代理时的额外操作,此操作无法区分多开,可能会干扰其他任务,也可能关闭您正在使用的模拟器",
content="自动代理时的额外操作,此操作无法区分多开模拟器,可能会干扰其他任务,也可能关闭您正在使用的模拟器",
texts=[
"禁用",
"强制关闭ADB",
@@ -631,7 +630,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,

View File

@@ -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)
@@ -421,7 +425,7 @@ class QueueManager(QWidget):
self.card_Enable = SwitchSettingCard(
icon=FluentIcon.HOME,
title="状态",
content="调度队列状态",
content="调度队列状态,仅启用时会执行定时任务",
qconfig=self.config,
configItem=self.config.queueSet_Enabled,
parent=self,
@@ -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)

View File

@@ -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,13 +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,
@@ -92,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)
@@ -262,34 +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?current_version={version_text(current_version)}&cdk={Crypto.win_decryptor(Config.get(Config.update_MirrorChyanCDK))}&channel={Config.get(Config.update_UpdateType)}"
)
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&current_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:
@@ -336,7 +336,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(
@@ -353,9 +355,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()
@@ -400,42 +404,35 @@ 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.close()
QApplication.quit()
self.window().close()
# 无版本更新
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"
)
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():
@@ -550,8 +547,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,

View File

@@ -33,6 +33,7 @@ import subprocess
import time
import win32crypt
import base64
from packaging import version
from functools import partial
from pathlib import Path
@@ -302,7 +303,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 +403,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"]
@@ -507,16 +511,16 @@ class DownloadManager(QDialog):
self.zip_loop.exec()
self.update_info("正在删除已弃用的文件")
if (app_path / "changes.json").exists():
if (self.app_path / "changes.json").exists():
with (app_path / "changes.json").open(mode="r", encoding="utf-8") as f:
with (self.app_path / "changes.json").open(mode="r", encoding="utf-8") as f:
info: Dict[str, List[str]] = json.load(f)
if "deleted" in info:
for file_path in info:
(self.app_path / file_path).unlink()
(app_path / "changes.json").unlink()
(self.app_path / "changes.json").unlink()
self.update_info("正在删除临时文件")
self.update_progress(0, 0, 0)
@@ -526,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,
)
@@ -661,7 +663,8 @@ if __name__ == "__main__":
for _ in range(3):
try:
response = requests.get(
f"https://mirrorchyan.com/api/resources/AUTO_MAA/latest?current_version={version_text(current_version)}&cdk={mirrorchyan_CDK}&channel={update_type}"
f"https://mirrorchyan.com/api/resources/AUTO_MAA/latest?user_agent=AutoMaaDownloader&current_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 +699,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()
@@ -715,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",

View File

@@ -71,8 +71,9 @@ if __name__ == "__main__":
print("Packaging AUTO_MAA main program ...")
os.system(
"powershell -Command python -m nuitka --standalone --mingw64"
"powershell -Command python -m nuitka --standalone --onefile --mingw64"
" --enable-plugins=pyside6 --windows-console-mode=disable"
" --onefile-tempdir-spec='{TEMP}\\AUTO_MAA'"
" --windows-icon-from-ico=resources\\icons\\AUTO_MAA.ico"
" --company-name='AUTO_MAA Team' --product-name=AUTO_MAA"
f" --file-version={version["main_version"]}"
@@ -107,19 +108,9 @@ if __name__ == "__main__":
(root_path / "AUTO_MAA").mkdir(parents=True, exist_ok=True)
print("Start to copy AUTO_MAA main program ...")
for item in (root_path / "main.dist").iterdir():
if item.is_dir():
shutil.copytree(
item, root_path / "AUTO_MAA" / item.name, dirs_exist_ok=True
)
else:
shutil.copy(item, root_path / "AUTO_MAA/")
shutil.rmtree(root_path / "main.dist")
print("Start to copy AUTO_MAA update program ...")
print("Start to move AUTO_MAA program ...")
shutil.move(root_path / "AUTO_MAA.exe", root_path / "AUTO_MAA/")
shutil.move(root_path / "AUTO_Updater.exe", root_path / "AUTO_MAA/")
print("Start to copy rescourses ...")

View File

@@ -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路径
"Start.EmulatorAddCommand": "-v 2" #附加命令

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,9 +1,42 @@
{
"main_version": "4.3.1.0",
"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.1.0":{
"4.3.4.2": {
"程序优化": [
"调度队列历史记录归入配置类管理",
"添加.gitignore",
"工作流删除冗余部分",
"自动代理与人工排查结束后MAA恢复到全局配置 #40",
"网络相关操作由子线程执行"
]
},
"4.3.4.1": {
"新增功能": [
"开始任务前自动释放ADB端口"
],
"程序优化": [
"request 添加超时限制",
"用户任务运行流程改进",
"自动代理中模拟器改由AUTO_MAA控制",
"修正部分配置项文案"
]
},
"4.3.3.0": {
"修复BUG": [
"修复更新器无法下载MAA的异常"
],
"程序优化": [
"自动发版改为手动触发"
]
},
"4.3.2.0": {
"修复BUG": [
"修复更新器无法启动的异常"
]
},
"4.3.1.0": {
"修复BUG": [
"覆盖规避v4.3.0错误包"
]