Merge branch 'Clozy_dev' into dev
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
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
|
||||||
@@ -10,3 +10,4 @@ requests
|
|||||||
markdown
|
markdown
|
||||||
Jinja2
|
Jinja2
|
||||||
nuitka
|
nuitka
|
||||||
|
pillow
|
||||||
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 |
Reference in New Issue
Block a user