feat(notification): 增加用户单独通知功能

This commit is contained in:
2025-05-23 15:01:26 +08:00
parent 86df9e7a50
commit 3127c83603
2 changed files with 361 additions and 240 deletions

View File

@@ -608,13 +608,14 @@ class MaaManager(QObject):
Config.app_path Config.app_path
/ f"history/{curdate}/{user_data["Info"]["Name"]}/{start_time.strftime("%H-%M-%S")}.json", / f"history/{curdate}/{user_data["Info"]["Name"]}/{start_time.strftime("%H-%M-%S")}.json",
) )
if if_six_star:
if Config.get(Config.notify_IfSendSixStar) and if_six_star:
self.push_notification( self.push_notification(
"公招六星", "公招六星",
f"喜报:用户 {user[0]} 公招出六星啦!", f"喜报:用户 {user[0]} 公招出六星啦!",
{"user_name": user_data["Info"]["Name"]}, {
"user_name": user_data["Info"]["Name"],
"user_index": user[2],
},
) )
# 执行MAA解压更新动作 # 执行MAA解压更新动作
@@ -643,6 +644,7 @@ class MaaManager(QObject):
if Config.get(Config.notify_IfSendStatistic): if Config.get(Config.notify_IfSendStatistic):
statistics = Config.merge_maa_logs("指定项", user_logs_list) statistics = Config.merge_maa_logs("指定项", user_logs_list)
statistics["user_index"] = user[2]
statistics["user_info"] = user[0] statistics["user_info"] = user[0]
statistics["start_time"] = user_start_time.strftime( statistics["start_time"] = user_start_time.strftime(
"%Y-%m-%d %H:%M:%S" "%Y-%m-%d %H:%M:%S"
@@ -1772,26 +1774,30 @@ class MaaManager(QObject):
message_html = template.render(message) message_html = template.render(message)
# 发送全局通知 # 发送全局通知
Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) if Config.get(Config.notify_IfSendMail):
Notify.send_mail(
"网页", title, message_html, Config.get(Config.notify_ToAddress)
)
serverchan_message = message_text.replace("\n", "\n\n") serverchan_message = message_text.replace("\n", "\n\n")
Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) if Config.get(Config.notify_IfServerChan):
Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) Notify.ServerChanPush(
title,
# # 发送用户单独通知 f"{serverchan_message}\n\nAUTO_MAA 敬上",
# for user_name in message["failed_user"].split("、") + message["waiting_user"].split("、"): Config.get(Config.notify_ServerChanKey),
# if not user_name: # 跳过空字符串 Config.get(Config.notify_ServerChanTag),
# continue Config.get(Config.notify_ServerChanChannel),
# user_config = Config.member_dict.get(user_name) )
# if user_config and user_config.get(user_config.Notify_Enable): if Config.get(Config.notify_IfCompanyWebHookBot):
# user_notify = UserNotification(user_config) Notify.CompanyWebHookBotPush(
# user_notify.send_notification( title,
# f"{self.mode[2:4]}任务未完成通知", f"{message_text}\n\nAUTO_MAA 敬上",
# f"您的{self.mode[2:4]}任务未完成,请检查相关设置。\n\n{message_text}" Config.get(Config.notify_CompanyWebHookBotUrl),
# ) )
return message_text return message_text
elif mode == "统计信息": elif mode == "统计信息":
user_index = message.get("user_index")
# 生成文本通知内容 # 生成文本通知内容
formatted = [] formatted = []
for stage, items in message["drop_statistics"].items(): for stage, items in message["drop_statistics"].items():
@@ -1818,40 +1824,166 @@ class MaaManager(QObject):
message_html = template.render(message) message_html = template.render(message)
# 发送全局通知 # 发送全局通知
Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) if Config.get(Config.notify_IfSendMail):
Notify.send_mail(
"网页", title, message_html, Config.get(Config.notify_ToAddress)
)
# ServerChan的换行是两个换行符。故而将\n替换为\n\n # ServerChan的换行是两个换行符。故而将\n替换为\n\n
serverchan_message = message_text.replace("\n", "\n\n") serverchan_message = message_text.replace("\n", "\n\n")
Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) if Config.get(Config.notify_IfServerChan):
Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) Notify.ServerChanPush(
title,
f"{serverchan_message}\n\nAUTO_MAA 敬上",
Config.get(Config.notify_ServerChanKey),
Config.get(Config.notify_ServerChanTag),
Config.get(Config.notify_ServerChanChannel),
)
if Config.get(Config.notify_IfCompanyWebHookBot):
Notify.CompanyWebHookBotPush(
title,
f"{message_text}\n\nAUTO_MAA 敬上",
Config.get(Config.notify_CompanyWebHookBotUrl),
)
# # 发送用户单独通知 # 发送用户单独通知
# user_name = message.get("user_info") user_data = self.data.get(user_index, {}).get("Config", {})
# if user_name: if user_data["Notify"].get("IfSendStatistic", False):
# user_config = Config.member_dict.get(user_name) if user_data.get("Notify") and user_data["Notify"].get(
# if user_config and user_config.get(user_config.Notify_Enable): "Enabled", False
# user_notify = UserNotification(user_config) ):
# user_notify.send_notification( # 发送邮件通知
# f"{self.mode[2:4]}任务统计报告", if user_data.get("Notify", {}).get("IfSendMail", False):
# f"您的{self.mode[2:4]}任务统计报告如下:\n\n{message_text}" userToAddress = user_data.get("Notify", {}).get("ToAddress")
# ) if userToAddress:
Notify.send_mail("网页", title, message_text, userToAddress)
else:
logger.error(
f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知"
)
# 发送ServerChan通知
if user_data.get("Notify", {}).get("IfServerChan", False):
userServerChanKey = user_data.get("Notify", {}).get(
"ServerChanKey"
)
userServerChanTag = user_data.get("Notify", {}).get(
"ServerChanTag"
)
userServerChanChannel = user_data.get("Notify", {}).get(
"ServerChanChannel"
)
if userServerChanKey:
Notify.ServerChanPush(
title,
f"{serverchan_message}\n\nAUTO_MAA 敬上",
userServerChanKey,
userServerChanTag,
userServerChanChannel,
)
else:
logger.error(
f"{self.name} |用户ServerChan密钥为空无法发送用户单独的ServerChan通知"
)
# 推送CompanyWebHookBot通知
if user_data.get("Notify", {}).get("IfCompanyWebHookBot", False):
userCompanyWebHookBotUrl = user_data.get("Notify", {}).get(
"CompanyWebHookBotUrl"
)
if userCompanyWebHookBotUrl:
Notify.CompanyWebHookBotPush(
title,
f"{message_text}\n\nAUTO_MAA 敬上",
userCompanyWebHookBotUrl,
)
else:
logger.error(
f"{self.name} |用户CompanyWebHookBot密钥为空无法发送用户单独的CompanyWebHookBot通知"
)
elif mode == "公招六星": elif mode == "公招六星":
user_index = message.get("user_index")
# 生成HTML通知内容 # 生成HTML通知内容
template = env.get_template("MAA_six_star.html") template = env.get_template("MAA_six_star.html")
# 这里需要看一下我给message加了个user_index
message_html = template.render(message) message_html = template.render(message)
# 发送全局通知 if Config.get(Config.notify_IfSendSixStar):
Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) # 发送全局通知
Notify.ServerChanPush(title, "好羡慕~\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) if Config.get(Config.notify_IfSendMail):
Notify.CompanyWebHookBotPush(title, "好羡慕~\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) Notify.send_mail(
"网页", title, message_html, Config.get(Config.notify_ToAddress)
)
if Config.get(Config.notify_IfServerChan):
Notify.ServerChanPush(
title,
"好羡慕~\n\nAUTO_MAA 敬上",
Config.get(Config.notify_ServerChanKey),
Config.get(Config.notify_ServerChanTag),
Config.get(Config.notify_ServerChanChannel),
)
if Config.get(Config.notify_IfCompanyWebHookBot):
Notify.CompanyWebHookBotPush(
title,
"好羡慕~\n\nAUTO_MAA 敬上",
Config.get(Config.notify_CompanyWebHookBotUrl),
)
# 发送用户单独通知
user_data = self.data.get(user_index, {}).get("Config", {})
# # 发送用户单独通知 # 判断是否单独发送六星
# user_name = message.get("user_name") if user_data["Notify"].get("IfSendSixStar", False):
# if user_name: if user_data.get("Notify") and user_data["Notify"].get(
# user_config = Config.member_dict.get(user_name) "Enabled", False
# if user_config and user_config.get(user_config.Notify_Enable): ):
# user_notify = UserNotification(user_config) # 发送邮件通知
# user_notify.send_notification( if user_data.get("Notify", {}).get("IfSendMail", False):
# "公招六星通知", userToAddress = user_data.get("Notify", {}).get("ToAddress")
# "恭喜您在公招中获得了六星干员!" if userToAddress:
# ) Notify.send_mail("网页", title, message_html, userToAddress)
else:
logger.error(
f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知"
)
# 发送ServerChan通知
if user_data.get("Notify", {}).get("IfServerChan", False):
userServerChanKey = user_data.get("Notify", {}).get(
"ServerChanKey"
)
userServerChanTag = user_data.get("Notify", {}).get(
"ServerChanTag"
)
userServerChanChannel = user_data.get("Notify", {}).get(
"ServerChanChannel"
)
if userServerChanKey:
Notify.ServerChanPush(
title,
"好羡慕~\n\nAUTO_MAA 敬上",
userServerChanKey,
userServerChanTag,
userServerChanChannel,
)
else:
logger.error(
f"{self.name} |用户ServerChan密钥为空无法发送用户单独的ServerChan通知"
)
# 推送CompanyWebHookBot通知
if user_data.get("Notify", {}).get("IfCompanyWebHookBot", False):
userCompanyWebHookBotUrl = user_data.get("Notify", {}).get(
"CompanyWebHookBotUrl"
)
if userCompanyWebHookBotUrl:
Notify.CompanyWebHookBotPush(
title,
"好羡慕~\n\nAUTO_MAA 敬上",
userCompanyWebHookBotUrl,
)
else:
logger.error(
f"{self.name} |用户CompanyWebHookBot密钥为空无法发送用户单独的CompanyWebHookBot通知"
)
return None

View File

@@ -69,219 +69,208 @@ class Notification(QWidget):
def send_mail(self, mode, title, content, to_address) -> None: def send_mail(self, mode, title, content, to_address) -> None:
"""推送邮件通知""" """推送邮件通知"""
if (
if Config.get(Config.notify_IfSendMail): Config.get(Config.notify_SMTPServerAddress) == ""
or Config.get(Config.notify_AuthorizationCode) == ""
if ( or not bool(
Config.get(Config.notify_SMTPServerAddress) == "" re.match(
or Config.get(Config.notify_AuthorizationCode) == "" r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
or not bool(
re.match(
r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
Config.get(Config.notify_FromAddress),
)
)
or not bool(
re.match(
r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
to_address,
)
)
):
logger.error(
"请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址"
)
self.push_info_bar.emit(
"error",
"邮件通知推送异常",
"请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址",
-1,
)
return None
try:
# 定义邮件正文
if mode == "文本":
message = MIMEText(content, "plain", "utf-8")
elif mode == "网页":
message = MIMEMultipart("alternative")
message["From"] = formataddr(
(
Header("AUTO_MAA通知服务", "utf-8").encode(),
Config.get(Config.notify_FromAddress),
)
) # 发件人显示的名字
message["To"] = formataddr(
(
Header("AUTO_MAA用户", "utf-8").encode(),
to_address,
)
) # 收件人显示的名字
message["Subject"] = Header(title, "utf-8")
if mode == "网页":
message.attach(MIMEText(content, "html", "utf-8"))
smtpObj = smtplib.SMTP_SSL(
Config.get(Config.notify_SMTPServerAddress),
465,
)
smtpObj.login(
Config.get(Config.notify_FromAddress), Config.get(Config.notify_FromAddress),
Crypto.win_decryptor(Config.get(Config.notify_AuthorizationCode)),
) )
smtpObj.sendmail( )
Config.get(Config.notify_FromAddress), or not bool(
re.match(
r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
to_address, to_address,
message.as_string(),
) )
smtpObj.quit() )
logger.success("邮件发送成功") ):
return None logger.error(
except Exception as e: "请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址"
logger.error(f"发送邮件时出错:\n{e}") )
self.push_info_bar.emit("error", "发送邮件时出错", f"{e}", -1) self.push_info_bar.emit(
return None "error",
"邮件通知推送异常",
"请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址",
-1,
)
return None
try:
# 定义邮件正文
if mode == "文本":
message = MIMEText(content, "plain", "utf-8")
elif mode == "网页":
message = MIMEMultipart("alternative")
message["From"] = formataddr(
(
Header("AUTO_MAA通知服务", "utf-8").encode(),
Config.get(Config.notify_FromAddress),
)
) # 发件人显示的名字
message["To"] = formataddr(
(
Header("AUTO_MAA用户", "utf-8").encode(),
to_address,
)
) # 收件人显示的名字
message["Subject"] = Header(title, "utf-8")
if mode == "网页":
message.attach(MIMEText(content, "html", "utf-8"))
smtpObj = smtplib.SMTP_SSL(
Config.get(Config.notify_SMTPServerAddress),
465,
)
smtpObj.login(
Config.get(Config.notify_FromAddress),
Crypto.win_decryptor(Config.get(Config.notify_AuthorizationCode)),
)
smtpObj.sendmail(
Config.get(Config.notify_FromAddress),
to_address,
message.as_string(),
)
smtpObj.quit()
logger.success("邮件发送成功")
return None
except Exception as e:
logger.error(f"发送邮件时出错:\n{e}")
self.push_info_bar.emit("error", "发送邮件时出错", f"{e}", -1)
return None
return None return None
def ServerChanPush(self, title, content, send_key, tag, channel): def ServerChanPush(self, title, content, send_key, tag, channel):
"""使用Server酱推送通知""" """使用Server酱推送通知"""
if Config.get(Config.notify_IfServerChan): if not send_key:
if not send_key: logger.error("请正确设置Server酱的SendKey")
logger.error("请正确设置Server酱的SendKey") self.push_info_bar.emit(
self.push_info_bar.emit( "error", "Server酱通知推送异常", "请正确设置Server酱的SendKey", -1
"error", "Server酱通知推送异常", "请正确设置Server酱的SendKey", -1 )
) return None
return None
try: try:
# 构造 URL # 构造 URL
if send_key.startswith("sctp"): if send_key.startswith("sctp"):
match = re.match(r"^sctp(\d+)t", send_key) match = re.match(r"^sctp(\d+)t", send_key)
if match: if match:
url = f"https://{match.group(1)}.push.ft07.com/send/{send_key}.send" url = f"https://{match.group(1)}.push.ft07.com/send/{send_key}.send"
else:
raise ValueError("SendKey 格式错误sctp")
else: else:
url = f"https://sctapi.ftqq.com/{send_key}.send" raise ValueError("SendKey 格式错误sctp")
# 构建 tags 和 channel
def is_valid(s):
return s == "" or (
s == "|".join(s.split("|"))
and (s.count("|") == 0 or all(s.split("|")))
)
tags = "|".join(
_.strip()
for _ in tag.split("|")
)
channels = "|".join(
_.strip()
for _ in channel.split("|")
)
options = {}
if is_valid(tags):
options["tags"] = tags
else:
logger.warning("Server酱 Tag 配置不正确,将被忽略")
self.push_info_bar.emit(
"warning",
"Server酱通知推送异常",
"请正确设置 ServerChan 的 Tag",
-1,
)
if is_valid(channels):
options["channel"] = channels
else:
logger.warning("Server酱 Channel 配置不正确,将被忽略")
self.push_info_bar.emit(
"warning",
"Server酱通知推送异常",
"请正确设置 ServerChan 的 Channel",
-1,
)
# 请求发送
params = {"title": title, "desp": content, **options}
headers = {"Content-Type": "application/json;charset=utf-8"}
response = requests.post(url, json=params, headers=headers, timeout=10)
result = response.json()
if result.get("code") == 0:
logger.info("Server酱推送通知成功")
return True
else:
error_code = result.get("code", "-1")
logger.error(f"Server酱通知推送失败响应码{error_code}")
self.push_info_bar.emit(
"error", "Server酱通知推送失败", f"响应码:{error_code}", -1
)
return f"Server酱通知推送失败{error_code}"
except Exception as e:
logger.exception("Server酱通知推送异常")
self.push_info_bar.emit(
"error", "Server酱通知推送异常", f"请检查相关设置,如还有问题可联系开发者", -1
)
return f"Server酱通知推送异常{str(e)}"
return None
def CompanyWebHookBotPush(self, title, content,webhook_url):
"""使用企业微信群机器人推送通知"""
if Config.get(Config.notify_IfCompanyWebHookBot):
if webhook_url == "":
logger.error("请正确设置企业微信群机器人的WebHook地址")
self.push_info_bar.emit(
"error",
"企业微信群机器人通知推送异常",
"请正确设置企业微信群机器人的WebHook地址",
-1,
)
return None
content = f"{title}\n{content}"
data = {"msgtype": "text", "text": {"content": content}}
for _ in range(3):
try:
response = requests.post(
url=webhook_url,
json=data,
timeout=10,
)
info = response.json()
break
except Exception as e:
err = e
time.sleep(0.1)
else: else:
logger.error(f"推送企业微信群机器人时出错:{err}") url = f"https://sctapi.ftqq.com/{send_key}.send"
# 构建 tags 和 channel
def is_valid(s):
return s == "" or (
s == "|".join(s.split("|"))
and (s.count("|") == 0 or all(s.split("|")))
)
tags = "|".join(_.strip() for _ in tag.split("|"))
channels = "|".join(_.strip() for _ in channel.split("|"))
options = {}
if is_valid(tags):
options["tags"] = tags
else:
logger.warning("Server酱 Tag 配置不正确,将被忽略")
self.push_info_bar.emit( self.push_info_bar.emit(
"error", "warning",
"企业微信群机器人通知推送失败", "Server酱通知推送异常",
f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', "请正确设置 ServerChan 的 Tag",
-1, -1,
) )
return None
if info["errcode"] == 0: if is_valid(channels):
logger.info("企业微信群机器人推送通知成功") options["channel"] = channels
else:
logger.warning("Server酱 Channel 配置不正确,将被忽略")
self.push_info_bar.emit(
"warning",
"Server酱通知推送异常",
"请正确设置 ServerChan 的 Channel",
-1,
)
# 请求发送
params = {"title": title, "desp": content, **options}
headers = {"Content-Type": "application/json;charset=utf-8"}
response = requests.post(url, json=params, headers=headers, timeout=10)
result = response.json()
if result.get("code") == 0:
logger.info("Server酱推送通知成功")
return True return True
else: else:
logger.error(f"企业微信群机器人推送通知失败:{info}") error_code = result.get("code", "-1")
logger.error(f"Server酱通知推送失败响应码{error_code}")
self.push_info_bar.emit( self.push_info_bar.emit(
"error", "error", "Server酱通知推送失败", f"响应码:{error_code}", -1
"企业微信群机器人通知推送失败",
f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}',
-1,
) )
return f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}' return f"Server酱通知推送失败{error_code}"
return None
except Exception as e:
logger.exception("Server酱通知推送异常")
self.push_info_bar.emit(
"error",
"Server酱通知推送异常",
"请检查相关设置和网络连接。如全部配置正确,请稍后再试。",
-1,
)
return f"Server酱通知推送异常{str(e)}"
def CompanyWebHookBotPush(self, title, content, webhook_url):
"""使用企业微信群机器人推送通知"""
if webhook_url == "":
logger.error("请正确设置企业微信群机器人的WebHook地址")
self.push_info_bar.emit(
"error",
"企业微信群机器人通知推送异常",
"请正确设置企业微信群机器人的WebHook地址",
-1,
)
return None
content = f"{title}\n{content}"
data = {"msgtype": "text", "text": {"content": content}}
for _ in range(3):
try:
response = requests.post(
url=webhook_url,
json=data,
timeout=10,
)
info = response.json()
break
except Exception as e:
err = e
time.sleep(0.1)
else:
logger.error(f"推送企业微信群机器人时出错:{err}")
self.push_info_bar.emit(
"error",
"企业微信群机器人通知推送失败",
f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}',
-1,
)
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): def send_test_notification(self):
"""发送测试通知到所有已启用的通知渠道""" """发送测试通知到所有已启用的通知渠道"""