Merge branch 'Clozy_dev' into dev

This commit is contained in:
DLmaster361
2025-06-11 23:05:59 +08:00
6 changed files with 180 additions and 1 deletions

View File

@@ -40,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):
@@ -1998,6 +1999,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"]:
@@ -2040,8 +2045,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

View File

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

67
app/utils/ImageUtils.py Normal file
View 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

View File

@@ -10,3 +10,4 @@ requests
markdown markdown
Jinja2 Jinja2
nuitka nuitka
pillow

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB