diff --git a/app/models/MAA.py b/app/models/MAA.py index a2bd23e..2cb5810 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -608,13 +608,14 @@ class MaaManager(QObject): Config.app_path / f"history/{curdate}/{user_data["Info"]["Name"]}/{start_time.strftime("%H-%M-%S")}.json", ) - - if Config.get(Config.notify_IfSendSixStar) and if_six_star: - + if if_six_star: self.push_notification( "公招六星", f"喜报:用户 {user[0]} 公招出六星啦!", - {"user_name": user_data["Info"]["Name"]}, + { + "user_name": user_data["Info"]["Name"], + "user_index": user[2], + }, ) # 执行MAA解压更新动作 @@ -643,6 +644,7 @@ class MaaManager(QObject): if Config.get(Config.notify_IfSendStatistic): statistics = Config.merge_maa_logs("指定项", user_logs_list) + statistics["user_index"] = user[2] statistics["user_info"] = user[0] statistics["start_time"] = user_start_time.strftime( "%Y-%m-%d %H:%M:%S" @@ -1772,26 +1774,30 @@ class MaaManager(QObject): 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") - Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) - Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) - - # # 发送用户单独通知 - # for user_name in message["failed_user"].split("、") + message["waiting_user"].split("、"): - # if not user_name: # 跳过空字符串 - # continue - # user_config = Config.member_dict.get(user_name) - # if user_config and user_config.get(user_config.Notify_Enable): - # user_notify = UserNotification(user_config) - # user_notify.send_notification( - # f"{self.mode[2:4]}任务未完成通知", - # f"您的{self.mode[2:4]}任务未完成,请检查相关设置。\n\n{message_text}" - # ) + if Config.get(Config.notify_IfServerChan): + 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), + ) return message_text elif mode == "统计信息": + user_index = message.get("user_index") # 生成文本通知内容 formatted = [] for stage, items in message["drop_statistics"].items(): @@ -1818,40 +1824,166 @@ class MaaManager(QObject): 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_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)) - Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) + if Config.get(Config.notify_IfServerChan): + 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") - # if user_name: - # user_config = Config.member_dict.get(user_name) - # if user_config and user_config.get(user_config.Notify_Enable): - # user_notify = UserNotification(user_config) - # user_notify.send_notification( - # f"{self.mode[2:4]}任务统计报告", - # f"您的{self.mode[2:4]}任务统计报告如下:\n\n{message_text}" - # ) + # 发送用户单独通知 + user_data = self.data.get(user_index, {}).get("Config", {}) + if user_data["Notify"].get("IfSendStatistic", False): + if user_data.get("Notify") and user_data["Notify"].get( + "Enabled", False + ): + # 发送邮件通知 + if user_data.get("Notify", {}).get("IfSendMail", False): + 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 == "公招六星": + user_index = message.get("user_index") # 生成HTML通知内容 template = env.get_template("MAA_six_star.html") + + # 这里需要看一下,我给message加了个user_index message_html = template.render(message) - # 发送全局通知 - 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)) - Notify.CompanyWebHookBotPush(title, "好羡慕~\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) + if Config.get(Config.notify_IfSendSixStar): + # 发送全局通知 + if Config.get(Config.notify_IfSendMail): + 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_name: - # user_config = Config.member_dict.get(user_name) - # if user_config and user_config.get(user_config.Notify_Enable): - # user_notify = UserNotification(user_config) - # user_notify.send_notification( - # "公招六星通知", - # "恭喜您在公招中获得了六星干员!" - # ) + # 判断是否单独发送六星 + if user_data["Notify"].get("IfSendSixStar", False): + if user_data.get("Notify") and user_data["Notify"].get( + "Enabled", False + ): + # 发送邮件通知 + 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 diff --git a/app/services/notification.py b/app/services/notification.py index 639e3ac..4cb60bb 100644 --- a/app/services/notification.py +++ b/app/services/notification.py @@ -69,219 +69,208 @@ class Notification(QWidget): def send_mail(self, mode, title, content, to_address) -> None: """推送邮件通知""" - - if Config.get(Config.notify_IfSendMail): - - if ( - Config.get(Config.notify_SMTPServerAddress) == "" - or Config.get(Config.notify_AuthorizationCode) == "" - 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( + if ( + Config.get(Config.notify_SMTPServerAddress) == "" + or Config.get(Config.notify_AuthorizationCode) == "" + or not bool( + re.match( + r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", 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, - 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 + ) + ): + 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), + 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 def ServerChanPush(self, title, content, send_key, tag, channel): """使用Server酱推送通知""" - if Config.get(Config.notify_IfServerChan): - if not send_key: - logger.error("请正确设置Server酱的SendKey") - self.push_info_bar.emit( - "error", "Server酱通知推送异常", "请正确设置Server酱的SendKey", -1 - ) - return None + if not send_key: + logger.error("请正确设置Server酱的SendKey") + self.push_info_bar.emit( + "error", "Server酱通知推送异常", "请正确设置Server酱的SendKey", -1 + ) + return None - try: - # 构造 URL - if send_key.startswith("sctp"): - match = re.match(r"^sctp(\d+)t", send_key) - if match: - url = f"https://{match.group(1)}.push.ft07.com/send/{send_key}.send" - else: - raise ValueError("SendKey 格式错误(sctp)") + try: + # 构造 URL + if send_key.startswith("sctp"): + match = re.match(r"^sctp(\d+)t", send_key) + if match: + url = f"https://{match.group(1)}.push.ft07.com/send/{send_key}.send" else: - 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( - "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) + raise ValueError("SendKey 格式错误(sctp)") 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( - "error", - "企业微信群机器人通知推送失败", - f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', + "warning", + "Server酱通知推送异常", + "请正确设置 ServerChan 的 Tag", -1, ) - return None - if info["errcode"] == 0: - logger.info("企业微信群机器人推送通知成功") + 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: - logger.error(f"企业微信群机器人推送通知失败:{info}") + error_code = result.get("code", "-1") + logger.error(f"Server酱通知推送失败:响应码:{error_code}") self.push_info_bar.emit( - "error", - "企业微信群机器人通知推送失败", - f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', - -1, + "error", "Server酱通知推送失败", f"响应码:{error_code}", -1 ) - return f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}' - return None + return f"Server酱通知推送失败:{error_code}" + + 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): """发送测试通知到所有已启用的通知渠道"""