Compare commits
21 Commits
v4.3.10-be
...
v4.4.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0572caa528 | ||
|
|
4233040585 | ||
|
|
c27dc8e380 | ||
|
|
e746756e56 | ||
|
|
1829d1cd0b | ||
|
|
fb979e5639 | ||
|
|
e7d0a85ad5 | ||
|
|
a384711327 | ||
|
|
3fd4778a48 | ||
|
|
4841dc09b3 | ||
|
|
b3aa4fc776 | ||
|
|
a9b3b8b6f4 | ||
|
|
56ef196695 | ||
| 242238d341 | |||
| f66f6d38fe | |||
| d58077f58b | |||
| 4d4d6dbedf | |||
| f60b276916 | |||
| 87857fd499 | |||
| 3c371cd079 | |||
|
|
428b849bcc |
22
.github/workflows/build-app.yml
vendored
22
.github/workflows/build-app.yml
vendored
@@ -107,8 +107,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
|
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
|
||||||
organization-id: '787a1d5f-6177-4f30-9559-d2646473584a'
|
organization-id: '787a1d5f-6177-4f30-9559-d2646473584a'
|
||||||
project-slug: 'AUTO_MAA_'
|
project-slug: 'AUTO_MAA'
|
||||||
signing-policy-slug: 'test-signing'
|
signing-policy-slug: 'release-signing'
|
||||||
artifact-configuration-slug: "AUTO_MAA"
|
artifact-configuration-slug: "AUTO_MAA"
|
||||||
github-artifact-id: '${{ steps.upload-unsigned-main-program.outputs.artifact-id }}'
|
github-artifact-id: '${{ steps.upload-unsigned-main-program.outputs.artifact-id }}'
|
||||||
wait-for-completion: true
|
wait-for-completion: true
|
||||||
@@ -155,8 +155,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
|
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
|
||||||
organization-id: '787a1d5f-6177-4f30-9559-d2646473584a'
|
organization-id: '787a1d5f-6177-4f30-9559-d2646473584a'
|
||||||
project-slug: 'AUTO_MAA_'
|
project-slug: 'AUTO_MAA'
|
||||||
signing-policy-slug: 'test-signing'
|
signing-policy-slug: 'release-signing'
|
||||||
artifact-configuration-slug: "AUTO_MAA-Setup"
|
artifact-configuration-slug: "AUTO_MAA-Setup"
|
||||||
github-artifact-id: '${{ steps.upload-unsigned-setup-program.outputs.artifact-id }}'
|
github-artifact-id: '${{ steps.upload-unsigned-setup-program.outputs.artifact-id }}'
|
||||||
wait-for-completion: true
|
wait-for-completion: true
|
||||||
@@ -243,7 +243,19 @@ jobs:
|
|||||||
TAGNAME="$(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_MAIN="$(sed 's/\r$//g' <(tail -n +3 version_info.txt))"
|
||||||
NOTES="$NOTES_MAIN
|
NOTES="$NOTES_MAIN
|
||||||
|
|
||||||
|
## 代码签名策略(Code signing policy)
|
||||||
|
|
||||||
|
Free code signing provided by [SignPath.io](https://signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
|
||||||
|
|
||||||
|
- 审批人(Approvers): [DLmaster (@DLmaster361)](https://github.com/DLmaster361)
|
||||||
|
|
||||||
|
## 隐私政策(Privacy policy)
|
||||||
|
|
||||||
|
除非用户、安装者或使用者特别要求,否则本程序不会将任何信息传输到其他网络系统。
|
||||||
|
|
||||||
|
This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it.
|
||||||
|
|
||||||
[已有 Mirror酱 CDK ?前往 Mirror酱 高速下载](https://mirrorchyan.com/zh/projects?rid=AUTO_MAA&source=auto_maa-release)
|
[已有 Mirror酱 CDK ?前往 Mirror酱 高速下载](https://mirrorchyan.com/zh/projects?rid=AUTO_MAA&source=auto_maa-release)
|
||||||
|
|
||||||
\`\`\`本release通过GitHub Actions自动构建\`\`\`"
|
\`\`\`本release通过GitHub Actions自动构建\`\`\`"
|
||||||
|
|||||||
19
README.md
19
README.md
@@ -52,13 +52,10 @@
|
|||||||
- **传播:** AUTO_MAA原则上允许传播者自由传播本软件,但无论在何种传播过程中,不得删除项目作者与开发者所留版权声明,不得隐瞒项目作者与相关开发者的存在。由于软件性质,项目组不希望发现任何人在明日方舟官方媒体(包括官方媒体账号与森空岛社区等)或明日方舟游戏相关内容(包括同好群、线下活动与游戏内容讨论等)下提及AUTO_MAA或MAA,希望各位理解。
|
- **传播:** AUTO_MAA原则上允许传播者自由传播本软件,但无论在何种传播过程中,不得删除项目作者与开发者所留版权声明,不得隐瞒项目作者与相关开发者的存在。由于软件性质,项目组不希望发现任何人在明日方舟官方媒体(包括官方媒体账号与森空岛社区等)或明日方舟游戏相关内容(包括同好群、线下活动与游戏内容讨论等)下提及AUTO_MAA或MAA,希望各位理解。
|
||||||
- **衍生:** AUTO_MAA允许任何人对软件本体或软件部分代码进行二次开发或利用。但依据GPL,相关成果再次分发时也必须使用GPL或兼容的协议开源。
|
- **衍生:** AUTO_MAA允许任何人对软件本体或软件部分代码进行二次开发或利用。但依据GPL,相关成果再次分发时也必须使用GPL或兼容的协议开源。
|
||||||
- **贡献:** 不论是直接参与软件的维护编写,或是撰写文档、测试、反馈BUG、给出建议、参与讨论,都为AUTO_MAA项目的发展完善做出了不可忽视的贡献。项目组提倡各位贡献者遵照GitHub开源社区惯例,发布Issues参与项目。避免私信或私发邮件(安全性漏洞或敏感问题除外),以帮助更多用户。
|
- **贡献:** 不论是直接参与软件的维护编写,或是撰写文档、测试、反馈BUG、给出建议、参与讨论,都为AUTO_MAA项目的发展完善做出了不可忽视的贡献。项目组提倡各位贡献者遵照GitHub开源社区惯例,发布Issues参与项目。避免私信或私发邮件(安全性漏洞或敏感问题除外),以帮助更多用户。
|
||||||
|
- **图像:** `AUTO_MAA主页默认图像` 并不适用开源协议,著作权归 [NARINpopo](https://space.bilibili.com/1877154) 画师所有,商业使用权归 [DLmaster (@DLmaster361)](https://github.com/DLmaster361) 所有,软件用户仅拥有非商业使用权。不得以开源协议已授权为由在未经授权的情况下使用 `AUTO_MAA主页默认图像`,不得在未经授权的情况下将 `AUTO_MAA主页默认图像` 用于任何商业用途。
|
||||||
|
|
||||||
以上细则是本项目对GPL的相关补充与强调。未提及的以GPL为准,发生冲突的以本细则为准。如有不清楚的部分,请发Issues询问。若发生纠纷,相关内容也没有在Issues上提及的,项目组拥有最终解释权。
|
以上细则是本项目对GPL的相关补充与强调。未提及的以GPL为准,发生冲突的以本细则为准。如有不清楚的部分,请发Issues询问。若发生纠纷,相关内容也没有在Issues上提及的,项目组拥有最终解释权。
|
||||||
|
|
||||||
**注意**
|
|
||||||
|
|
||||||
- 由于本软件有修改其它目录JSON文件等行为,使用前请将AUTO_MAA添加入Windows Defender信任区以及防病毒软件的信任区或开发者目录,避免被误杀。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 使用方法
|
# 使用方法
|
||||||
@@ -75,11 +72,23 @@
|
|||||||
|
|
||||||
可在[《AUTO_MAA开发者协作文档》](https://docs.qq.com/aio/DQ3Z5eHNxdmxFQmZX)的`开发任务`页面中查看开发进度。
|
可在[《AUTO_MAA开发者协作文档》](https://docs.qq.com/aio/DQ3Z5eHNxdmxFQmZX)的`开发任务`页面中查看开发进度。
|
||||||
|
|
||||||
|
## 代码签名策略(Code signing policy)
|
||||||
|
|
||||||
|
Free code signing provided by [SignPath.io](https://signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
|
||||||
|
|
||||||
|
- 审批人(Approvers): [DLmaster (@DLmaster361)](https://github.com/DLmaster361)
|
||||||
|
|
||||||
|
## 隐私政策(Privacy policy)
|
||||||
|
|
||||||
|
除非用户、安装者或使用者特别要求,否则本程序不会将任何信息传输到其他网络系统。
|
||||||
|
|
||||||
|
This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it.
|
||||||
|
|
||||||
## 特别鸣谢
|
## 特别鸣谢
|
||||||
|
|
||||||
- 下载服务器:由[AoXuan (@ClozyA)](https://github.com/ClozyA) 个人为项目赞助。
|
- 下载服务器:由[AoXuan (@ClozyA)](https://github.com/ClozyA) 个人为项目赞助。
|
||||||
|
|
||||||
- EXE签名: Free code signing provided by [SignPath.io](https://signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
|
- EXE签名: 由 [SignPath.io](https://signpath.io/)提供免费代码签名,签名来自[SignPath Foundation](https://signpath.org/)。
|
||||||
|
|
||||||
## 贡献者
|
## 贡献者
|
||||||
|
|
||||||
|
|||||||
@@ -576,7 +576,7 @@ class MaaPlanConfig(LQConfig):
|
|||||||
|
|
||||||
class AppConfig(GlobalConfig):
|
class AppConfig(GlobalConfig):
|
||||||
|
|
||||||
VERSION = "4.3.10.3"
|
VERSION = "4.3.12.0"
|
||||||
|
|
||||||
gameid_refreshed = Signal()
|
gameid_refreshed = Signal()
|
||||||
PASSWORD_refreshed = Signal()
|
PASSWORD_refreshed = Signal()
|
||||||
|
|||||||
@@ -96,17 +96,9 @@ class _MainTimer(QObject):
|
|||||||
|
|
||||||
windows = System.get_window_info()
|
windows = System.get_window_info()
|
||||||
|
|
||||||
# 排除雷电名为新通知的窗口
|
# 此处排除雷电名为新通知的窗口
|
||||||
windows = [
|
|
||||||
window
|
|
||||||
for window in windows
|
|
||||||
if not (
|
|
||||||
window[0] == "新通知" and Path(window[1]) in Config.silence_list
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
if any(
|
if any(
|
||||||
str(emulator_path) in window
|
str(emulator_path) in window and window[0] != "新通知"
|
||||||
for window in windows
|
for window in windows
|
||||||
for emulator_path in Config.silence_list
|
for emulator_path in Config.silence_list
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import subprocess
|
|||||||
import shutil
|
import shutil
|
||||||
import re
|
import re
|
||||||
import win32com.client
|
import win32com.client
|
||||||
|
from functools import partial
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
@@ -39,6 +40,7 @@ from typing import Union, List, Dict
|
|||||||
|
|
||||||
from app.core import Config, MaaConfig, MaaUserConfig
|
from app.core import Config, MaaConfig, MaaUserConfig
|
||||||
from app.services import Notify, Crypto, System, skland_sign_in
|
from app.services import Notify, Crypto, System, skland_sign_in
|
||||||
|
from app.utils.ImageUtils import ImageUtils
|
||||||
|
|
||||||
|
|
||||||
class MaaManager(QObject):
|
class MaaManager(QObject):
|
||||||
@@ -242,9 +244,17 @@ class MaaManager(QObject):
|
|||||||
"info",
|
"info",
|
||||||
f"森空岛签到{type}",
|
f"森空岛签到{type}",
|
||||||
"、".join(user_list),
|
"、".join(user_list),
|
||||||
-1,
|
-1 if type == "失败" else 5000,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if skland_result["总计"] == 0:
|
||||||
|
self.push_info_bar.emit(
|
||||||
|
"info",
|
||||||
|
"森空岛签到失败",
|
||||||
|
user[0],
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
skland_result["总计"] > 0
|
skland_result["总计"] > 0
|
||||||
and len(skland_result["失败"]) == 0
|
and len(skland_result["失败"]) == 0
|
||||||
@@ -959,8 +969,10 @@ class MaaManager(QObject):
|
|||||||
if self.isInterruptionRequested:
|
if self.isInterruptionRequested:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 移除静默进程标记
|
# 10s后移除静默进程标记
|
||||||
Config.silence_list.remove(self.emulator_path)
|
QTimer.singleShot(
|
||||||
|
10000, partial(Config.silence_list.remove, self.emulator_path)
|
||||||
|
)
|
||||||
|
|
||||||
if "-" in self.ADB_address:
|
if "-" in self.ADB_address:
|
||||||
ADB_ip = f"{self.ADB_address.split("-")[0]}-"
|
ADB_ip = f"{self.ADB_address.split("-")[0]}-"
|
||||||
@@ -1269,10 +1281,15 @@ class MaaManager(QObject):
|
|||||||
else:
|
else:
|
||||||
self.agree_bilibili(False)
|
self.agree_bilibili(False)
|
||||||
|
|
||||||
|
# 切换配置
|
||||||
|
if data["Current"] != "Default":
|
||||||
|
|
||||||
|
data["Configurations"]["Default"] = data["Configurations"][data["Current"]]
|
||||||
|
data["Current"] = "Default"
|
||||||
|
|
||||||
# 自动代理配置
|
# 自动代理配置
|
||||||
if "自动代理" in mode:
|
if "自动代理" in mode:
|
||||||
|
|
||||||
data["Current"] = "Default" # 切换配置
|
|
||||||
for i in range(1, 9):
|
for i in range(1, 9):
|
||||||
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
|
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
|
||||||
|
|
||||||
@@ -1578,7 +1595,6 @@ class MaaManager(QObject):
|
|||||||
# 人工排查配置
|
# 人工排查配置
|
||||||
elif "人工排查" in mode:
|
elif "人工排查" in mode:
|
||||||
|
|
||||||
data["Current"] = "Default" # 切换配置
|
|
||||||
for i in range(1, 9):
|
for i in range(1, 9):
|
||||||
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
|
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
|
||||||
data["Configurations"]["Default"][
|
data["Configurations"]["Default"][
|
||||||
@@ -1651,7 +1667,6 @@ class MaaManager(QObject):
|
|||||||
# 设置MAA配置
|
# 设置MAA配置
|
||||||
elif "设置MAA" in mode:
|
elif "设置MAA" in mode:
|
||||||
|
|
||||||
data["Current"] = "Default" # 切换配置
|
|
||||||
for i in range(1, 9):
|
for i in range(1, 9):
|
||||||
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
|
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
|
||||||
data["Configurations"]["Default"][
|
data["Configurations"]["Default"][
|
||||||
@@ -1707,7 +1722,6 @@ class MaaManager(QObject):
|
|||||||
|
|
||||||
elif mode == "更新MAA":
|
elif mode == "更新MAA":
|
||||||
|
|
||||||
data["Current"] = "Default" # 切换配置
|
|
||||||
for i in range(1, 9):
|
for i in range(1, 9):
|
||||||
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
|
data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置
|
||||||
data["Configurations"]["Default"][
|
data["Configurations"]["Default"][
|
||||||
@@ -1995,6 +2009,10 @@ class MaaManager(QObject):
|
|||||||
"好羡慕~\n\nAUTO_MAA 敬上",
|
"好羡慕~\n\nAUTO_MAA 敬上",
|
||||||
Config.get(Config.notify_CompanyWebHookBotUrl),
|
Config.get(Config.notify_CompanyWebHookBotUrl),
|
||||||
)
|
)
|
||||||
|
Notify.CompanyWebHookBotPushImage(
|
||||||
|
Config.app_path / "resources/images/notification/six_star.png",
|
||||||
|
Config.get(Config.notify_CompanyWebHookBotUrl),
|
||||||
|
)
|
||||||
|
|
||||||
# 发送用户单独通知
|
# 发送用户单独通知
|
||||||
if user_data["Notify"]["Enabled"] and user_data["Notify"]["IfSendSixStar"]:
|
if user_data["Notify"]["Enabled"] and user_data["Notify"]["IfSendSixStar"]:
|
||||||
@@ -2037,8 +2055,14 @@ class MaaManager(QObject):
|
|||||||
"好羡慕~\n\nAUTO_MAA 敬上",
|
"好羡慕~\n\nAUTO_MAA 敬上",
|
||||||
user_data["Notify"]["CompanyWebHookBotUrl"],
|
user_data["Notify"]["CompanyWebHookBotUrl"],
|
||||||
)
|
)
|
||||||
|
Notify.CompanyWebHookBotPushImage(
|
||||||
|
Config.app_path
|
||||||
|
/ "resources/images/notification/six_star.png",
|
||||||
|
Config.get(Config.notify_CompanyWebHookBotUrl),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"{self.name} |用户CompanyWebHookBot密钥为空,无法发送用户单独的CompanyWebHookBot通知"
|
f"{self.name} |用户CompanyWebHookBot密钥为空,无法发送用户单独的CompanyWebHookBot通知"
|
||||||
)
|
)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ from email.header import Header
|
|||||||
from email.mime.multipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.utils import formataddr
|
from email.utils import formataddr
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from PySide6.QtCore import QObject, Signal
|
from PySide6.QtCore import QObject, Signal
|
||||||
@@ -40,6 +41,7 @@ from plyer import notification
|
|||||||
|
|
||||||
from app.core import Config
|
from app.core import Config
|
||||||
from app.services.security import Crypto
|
from app.services.security import Crypto
|
||||||
|
from app.utils.ImageUtils import ImageUtils
|
||||||
|
|
||||||
|
|
||||||
class Notification(QObject):
|
class Notification(QObject):
|
||||||
@@ -271,6 +273,100 @@ class Notification(QObject):
|
|||||||
)
|
)
|
||||||
return f"使用企业微信群机器人推送通知时出错:{err}"
|
return f"使用企业微信群机器人推送通知时出错:{err}"
|
||||||
|
|
||||||
|
def CompanyWebHookBotPushImage(self, image_path: Path, webhook_url: str) -> bool:
|
||||||
|
"""使用企业微信群机器人推送图片通知"""
|
||||||
|
try:
|
||||||
|
# 压缩图片
|
||||||
|
ImageUtils.compress_image_if_needed(image_path)
|
||||||
|
|
||||||
|
# 检查图片是否存在
|
||||||
|
if not image_path.exists():
|
||||||
|
logger.error(
|
||||||
|
"图片推送异常 | 图片不存在或者压缩失败,请检查图片路径是否正确"
|
||||||
|
)
|
||||||
|
self.push_info_bar.emit(
|
||||||
|
"error",
|
||||||
|
"企业微信群机器人通知推送异常",
|
||||||
|
"图片不存在或者压缩失败,请检查图片路径是否正确",
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not webhook_url:
|
||||||
|
logger.error("请正确设置企业微信群机器人的WebHook地址")
|
||||||
|
self.push_info_bar.emit(
|
||||||
|
"error",
|
||||||
|
"企业微信群机器人通知推送异常",
|
||||||
|
"请正确设置企业微信群机器人的WebHook地址",
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 获取图片base64和md5
|
||||||
|
try:
|
||||||
|
image_base64 = ImageUtils.get_base64_from_file(str(image_path))
|
||||||
|
image_md5 = ImageUtils.calculate_md5_from_file(str(image_path))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"图片编码或MD5计算失败:{e}")
|
||||||
|
self.push_info_bar.emit(
|
||||||
|
"error",
|
||||||
|
"企业微信群机器人通知推送异常",
|
||||||
|
f"图片编码或MD5计算失败:{e}",
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"msgtype": "image",
|
||||||
|
"image": {"base64": image_base64, "md5": image_md5},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in range(3):
|
||||||
|
try:
|
||||||
|
response = requests.post(
|
||||||
|
url=webhook_url,
|
||||||
|
json=data,
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
info = response.json()
|
||||||
|
break
|
||||||
|
except requests.RequestException as e:
|
||||||
|
err = e
|
||||||
|
logger.warning(f"推送企业微信群机器人图片第{_+1}次失败:{e}")
|
||||||
|
time.sleep(0.1)
|
||||||
|
else:
|
||||||
|
logger.error(f"推送企业微信群机器人图片时出错:{err}")
|
||||||
|
self.push_info_bar.emit(
|
||||||
|
"error",
|
||||||
|
"企业微信群机器人图片推送失败",
|
||||||
|
f"使用企业微信群机器人推送图片时出错:{err}",
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if info.get("errcode") == 0:
|
||||||
|
logger.info("企业微信群机器人推送图片成功")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.error(f"企业微信群机器人推送图片失败:{info}")
|
||||||
|
self.push_info_bar.emit(
|
||||||
|
"error",
|
||||||
|
"企业微信群机器人图片推送失败",
|
||||||
|
f"使用企业微信群机器人推送图片时出错:{info}",
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"推送企业微信群机器人图片时发生未知异常:{e}")
|
||||||
|
self.push_info_bar.emit(
|
||||||
|
"error",
|
||||||
|
"企业微信群机器人图片推送失败",
|
||||||
|
f"发生未知异常:{e}",
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
def send_test_notification(self):
|
def send_test_notification(self):
|
||||||
"""发送测试通知到所有已启用的通知渠道"""
|
"""发送测试通知到所有已启用的通知渠道"""
|
||||||
# 发送系统通知
|
# 发送系统通知
|
||||||
@@ -307,6 +403,10 @@ class Notification(QObject):
|
|||||||
"这是 AUTO_MAA 外部通知测试信息。如果你看到了这段内容,说明 AUTO_MAA 的通知功能已经正确配置且可以正常工作!",
|
"这是 AUTO_MAA 外部通知测试信息。如果你看到了这段内容,说明 AUTO_MAA 的通知功能已经正确配置且可以正常工作!",
|
||||||
Config.get(Config.notify_CompanyWebHookBotUrl),
|
Config.get(Config.notify_CompanyWebHookBotUrl),
|
||||||
)
|
)
|
||||||
|
Notify.CompanyWebHookBotPushImage(
|
||||||
|
Config.app_path / "resources/images/notification/test_notify.png",
|
||||||
|
Config.get(Config.notify_CompanyWebHookBotUrl),
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -153,7 +153,9 @@ def skland_sign_in(token) -> dict:
|
|||||||
headers=header_login,
|
headers=header_login,
|
||||||
).json()
|
).json()
|
||||||
if rsp["status"] != 0:
|
if rsp["status"] != 0:
|
||||||
raise Exception(f'使用token: {token} 获得认证代码失败:{rsp.get("msg")}')
|
raise Exception(
|
||||||
|
f'使用token: {token[:3]}******{token[-3:]} 获得认证代码失败:{rsp.get("msg")}'
|
||||||
|
)
|
||||||
return rsp["data"]["code"]
|
return rsp["data"]["code"]
|
||||||
|
|
||||||
# 获取已绑定的角色列表
|
# 获取已绑定的角色列表
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ class PlanManager(QWidget):
|
|||||||
self.plan_manager.clear_SettingBox()
|
self.plan_manager.clear_SettingBox()
|
||||||
|
|
||||||
shutil.rmtree(Config.plan_dict[name]["Path"])
|
shutil.rmtree(Config.plan_dict[name]["Path"])
|
||||||
Config.change_plan(name, "禁用")
|
Config.change_plan(name, "固定")
|
||||||
for i in range(int(name[3:]) + 1, len(Config.plan_dict) + 1):
|
for i in range(int(name[3:]) + 1, len(Config.plan_dict) + 1):
|
||||||
if Config.plan_dict[f"计划_{i}"]["Path"].exists():
|
if Config.plan_dict[f"计划_{i}"]["Path"].exists():
|
||||||
Config.plan_dict[f"计划_{i}"]["Path"].rename(
|
Config.plan_dict[f"计划_{i}"]["Path"].rename(
|
||||||
|
|||||||
67
app/utils/ImageUtils.py
Normal file
67
app/utils/ImageUtils.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import base64
|
||||||
|
import hashlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
class ImageUtils:
|
||||||
|
@staticmethod
|
||||||
|
def get_base64_from_file(image_path):
|
||||||
|
"""从本地文件读取并返回base64编码字符串"""
|
||||||
|
with open(image_path, "rb") as f:
|
||||||
|
return base64.b64encode(f.read()).decode("utf-8")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def calculate_md5_from_file(image_path):
|
||||||
|
"""从本地文件读取并返回md5值(hex字符串)"""
|
||||||
|
with open(image_path, "rb") as f:
|
||||||
|
return hashlib.md5(f.read()).hexdigest()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def calculate_md5_from_base64(base64_content):
|
||||||
|
"""从base64字符串计算md5"""
|
||||||
|
image_data = base64.b64decode(base64_content)
|
||||||
|
return hashlib.md5(image_data).hexdigest()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def compress_image_if_needed(image_path: Path, max_size_mb=2) -> Path:
|
||||||
|
"""
|
||||||
|
如果图片大于max_size_mb,则压缩并覆盖原文件,返回原始路径(Path对象)
|
||||||
|
"""
|
||||||
|
if hasattr(Image, "Resampling"): # Pillow 9.1.0及以后
|
||||||
|
RESAMPLE = Image.Resampling.LANCZOS
|
||||||
|
else:
|
||||||
|
RESAMPLE = Image.ANTIALIAS
|
||||||
|
|
||||||
|
max_size = max_size_mb * 1024 * 1024
|
||||||
|
if image_path.stat().st_size <= max_size:
|
||||||
|
return image_path
|
||||||
|
|
||||||
|
img = Image.open(image_path)
|
||||||
|
suffix = image_path.suffix.lower()
|
||||||
|
quality = 90 if suffix in [".jpg", ".jpeg"] else None
|
||||||
|
step = 5
|
||||||
|
|
||||||
|
if suffix in [".jpg", ".jpeg"]:
|
||||||
|
while True:
|
||||||
|
img.save(image_path, quality=quality, optimize=True)
|
||||||
|
if image_path.stat().st_size <= max_size or quality <= 10:
|
||||||
|
break
|
||||||
|
quality -= step
|
||||||
|
elif suffix == ".png":
|
||||||
|
width, height = img.size
|
||||||
|
while True:
|
||||||
|
img.save(image_path, optimize=True)
|
||||||
|
if (
|
||||||
|
image_path.stat().st_size <= max_size
|
||||||
|
or width <= 200
|
||||||
|
or height <= 200
|
||||||
|
):
|
||||||
|
break
|
||||||
|
width = int(width * 0.95)
|
||||||
|
height = int(height * 0.95)
|
||||||
|
img = img.resize((width, height), RESAMPLE)
|
||||||
|
else:
|
||||||
|
raise ValueError("仅支持JPG/JPEG和PNG格式图片的压缩。")
|
||||||
|
|
||||||
|
return image_path
|
||||||
@@ -6,7 +6,9 @@ psutil
|
|||||||
pywin32
|
pywin32
|
||||||
keyboard
|
keyboard
|
||||||
pycryptodome
|
pycryptodome
|
||||||
|
certifi==2025.4.26
|
||||||
requests
|
requests
|
||||||
markdown
|
markdown
|
||||||
Jinja2
|
Jinja2
|
||||||
nuitka
|
nuitka
|
||||||
|
pillow
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 1.7 MiB |
BIN
resources/images/notification/six_star.png
Normal file
BIN
resources/images/notification/six_star.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
BIN
resources/images/notification/test_notify.png
Normal file
BIN
resources/images/notification/test_notify.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
@@ -1,6 +1,25 @@
|
|||||||
{
|
{
|
||||||
"main_version": "4.3.10.3",
|
"main_version": "4.3.12.0",
|
||||||
"version_info": {
|
"version_info": {
|
||||||
|
"4.3.12.0": {
|
||||||
|
"修复BUG": [
|
||||||
|
"固定certifi版本号"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"4.3.11.0": {
|
||||||
|
"修复BUG": [
|
||||||
|
"修复删除计划表引发的错误"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"4.3.10.0": {
|
||||||
|
"新增功能": [
|
||||||
|
"更换全新默认主页图",
|
||||||
|
"适配 MAA 无`Default`配置情况 #52"
|
||||||
|
],
|
||||||
|
"程序优化": [
|
||||||
|
"静默模式控制时段延长至模拟器完成启动的10s后"
|
||||||
|
]
|
||||||
|
},
|
||||||
"4.3.10.3": {
|
"4.3.10.3": {
|
||||||
"程序优化": [
|
"程序优化": [
|
||||||
"使用 keyboard 模块替代 pyautogui 模块"
|
"使用 keyboard 模块替代 pyautogui 模块"
|
||||||
|
|||||||
Reference in New Issue
Block a user