From d7ec1325c445959f72060249c88a4e5404993a10 Mon Sep 17 00:00:00 2001 From: LWR Date: Sat, 20 May 2023 22:21:00 +0800 Subject: [PATCH] fix: Optimized the message push module and fixed some instances of missed push --- starbot/core/room.py | 3 +- starbot/core/sender.py | 73 ++++++++++++++-------- starbot/exception/NoPermissionException.py | 15 +++++ starbot/exception/__init__.py | 2 + starbot/utils/config.py | 10 +++ 5 files changed, 76 insertions(+), 27 deletions(-) create mode 100644 starbot/exception/NoPermissionException.py diff --git a/starbot/core/room.py b/starbot/core/room.py index 7bb0f31..0af7f81 100644 --- a/starbot/core/room.py +++ b/starbot/core/room.py @@ -207,8 +207,8 @@ class Up(BaseModel): "{url}": f"https://live.bilibili.com/{self.room_id}", "{cover}": "".join(["{urlpic=", arg_base["cover"], "}"]) } - await self.__bot.send_live_on_at(self) await self.__bot.send_live_on(self, args) + await self.__bot.send_live_on_at(self) @self.__room.on("PREPARING") async def live_off(event): @@ -365,6 +365,7 @@ class Up(BaseModel): 动态更新事件 """ logger.debug(f"{self.uname} (DYNAMIC_UPDATE): {event}") + logger.opt(colors=True).info(f"[动态更新] {self.uname}") dynamic_id = event["desc"]["dynamic_id"] dynamic_type = event["desc"]["type"] diff --git a/starbot/core/sender.py b/starbot/core/sender.py index 363c252..e407d0a 100644 --- a/starbot/core/sender.py +++ b/starbot/core/sender.py @@ -1,11 +1,11 @@ import asyncio import time from asyncio import AbstractEventLoop -from typing import Optional, List, Dict, Any, Union, Callable +from typing import Optional, List, Dict, Any, Union, Callable, Tuple from graia.ariadne import Ariadne from graia.ariadne.connection.config import config as AriadneConfig, HttpClientConfig, WebsocketClientConfig -from graia.ariadne.exception import RemoteException +from graia.ariadne.exception import RemoteException, AccountMuted from graia.ariadne.message.chain import MessageChain from graia.ariadne.message.element import At, AtAll from graia.ariadne.model import LogConfig, MemberPerm @@ -14,6 +14,7 @@ from pydantic import BaseModel, PrivateAttr from .model import LiveOn, LiveOff, DynamicUpdate, Message, PushType, PushTarget from .room import Up +from ..exception import NoPermissionException from ..exception.AtAllLimitedException import AtAllLimitedException from ..painter.LiveReportGenerator import LiveReportGenerator from ..utils import config, redis @@ -71,7 +72,6 @@ class Bot(BaseModel): Raises: """ - exception = None if msg.type == PushType.Friend: for message in msg.get_message_chains(): try: @@ -81,56 +81,73 @@ class Bot(BaseModel): logger.exception("消息推送模块异常", ex) continue else: - msgs = await self.group_message_filter(msg) - - if any([(AtAll in x) for x in msg.get_message_chains()]) and all([(AtAll not in x) for x in msgs]): - exception = AtAllLimitedException() + msgs, exception = await self.group_message_filter(msg) for message in msgs: try: await self.__bot.send_group_message(msg.id, message) logger.info(f"{self.qq} -> 群[{msg.id}] : {message.safe_display}") + except AccountMuted: + logger.warning(f"Bot({self.qq}) 在群 {msg.id} 中被禁言") + return except RemoteException as ex: if "AT_ALL_LIMITED" in str(ex): + logger.warning(f"Bot({self.qq}) 今日的@全体成员次数已达到上限") exception = AtAllLimitedException() self.__at_all_limited = time.localtime(time.time()).tm_yday continue else: logger.exception("消息推送模块异常", ex) continue + except Exception as ex: + logger.exception("消息推送模块异常", ex) + continue - if exception is not None: - raise exception + if exception is not None: + message = "" + if isinstance(exception, AtAllLimitedException): + message = config.get("AT_ALL_LIMITED_MESSAGE") + elif isinstance(exception, NoPermissionException): + message = config.get("NO_PERMISSION_MESSAGE") + if len(message) > 0: + try: + await self.__bot.send_group_message(msg.id, MessageChain(message)) + except Exception: + pass - async def group_message_filter(self, message: Message) -> List[MessageChain]: + async def group_message_filter(self, message: Message) -> Tuple[List[MessageChain], Optional[Exception]]: """ 过滤群消息中的非法元素 Args: - message: 源消息链 + message: 源消息 Returns: - 处理后的消息链 + 处理后的消息链和引发的异常 """ + exception = None + if message.type == PushType.Friend: - return message.get_message_chains() + return message.get_message_chains(), exception new_chains = [] # 过滤 Bot 不在群内的消息 group = await self.__bot.get_group(message.id) if group is None: - return new_chains + return new_chains, exception for chain in message.get_message_chains(): if AtAll in chain: + # 过滤已超出当日次数上限的 @全体成员 消息 + if time.localtime(time.time()).tm_yday == self.__at_all_limited: + exception = AtAllLimitedException() + chain = chain.exclude(AtAll) + # 过滤 Bot 不是群管理员时的 @全体成员 消息 bot_info = await self.__bot.get_member(message.id, self.qq) if bot_info.permission < MemberPerm.Administrator: - chain = chain.exclude(AtAll) - - # 过滤已超出当日次数上限的 @全体成员 消息 - if time.localtime(time.time()).tm_yday == self.__at_all_limited: + exception = NoPermissionException() chain = chain.exclude(AtAll) # 过滤多余的 @全体成员 消息 @@ -157,7 +174,7 @@ class Bot(BaseModel): if len(chain) != 0: new_chains.append(chain) - return new_chains + return new_chains, exception async def send_to_all_target(self, up: Up, msg: str, target_filter: Callable[[PushTarget], bool] = lambda t: True): """ @@ -189,11 +206,13 @@ class Bot(BaseModel): if not isinstance(up, Up): return + logger.debug(f"{up.uname} 已配置推送群: ({', '.join(map(lambda t: str(t.id), up.targets))})") for target in up.targets: select = type_selector(target) if not isinstance(select, (LiveOn, LiveOff, DynamicUpdate)): return + logger.debug(f"群 {target.id}: ({select.enabled}) ({select.message})") if select.enabled: message = select.message for arg, val in args.items(): @@ -208,24 +227,26 @@ class Bot(BaseModel): up: 要发送的 UP 主实例 args: 占位符参数 """ - try: - await self.__send_push_message(up, lambda t: t.live_on, args) - except AtAllLimitedException: - await self.send_live_on_at(up, True) + await self.__send_push_message(up, lambda t: t.live_on, args) - async def send_live_on_at(self, up: Up, limited: bool = False): + async def send_live_on_at(self, up: Up): """ 发送开播 @ 我列表中的 @ 消息 Args: up: 要发送的 UP 主实例 - limited: 是否为 @全体成员次数达到上限时发送。默认:False """ if not isinstance(up, Up): return + limited = self.__at_all_limited == time.localtime(time.time()).tm_yday for target in filter(lambda t: t.type == PushType.Group, up.targets): - if target.live_on.enabled and (limited or "{atall}" not in target.live_on.message): + group = await self.__bot.get_group(target.id) + if group is None: + continue + bot_info = await self.__bot.get_member(target.id, self.qq) + not_admin = bot_info.permission < MemberPerm.Administrator + if target.live_on.enabled and (limited or "{atall}" not in target.live_on.message or not_admin): ats = " ".join(["{at" + str(x) + "}" for x in await redis.range_live_on_at(target.id)]) await self.send_message(Message(id=target.id, content=ats, type=target.type)) diff --git a/starbot/exception/NoPermissionException.py b/starbot/exception/NoPermissionException.py new file mode 100644 index 0000000..c19dccc --- /dev/null +++ b/starbot/exception/NoPermissionException.py @@ -0,0 +1,15 @@ +""" +没有管理员权限异常 +""" + +from .ApiException import ApiException + + +class NoPermissionException(ApiException): + """ + 没有管理员权限异常 + """ + + def __init__(self): + super().__init__() + self.msg = "没有管理员权限" diff --git a/starbot/exception/__init__.py b/starbot/exception/__init__.py index 2dc9bc1..d276293 100644 --- a/starbot/exception/__init__.py +++ b/starbot/exception/__init__.py @@ -1,10 +1,12 @@ from .ApiException import * +from .AtAllLimitedException import * from .CredentialNoBiliJctException import * from .CredentialNoBuvid3Exception import * from .CredentialNoSessdataException import * from .DataSourceException import * from .LiveException import * from .NetworkException import * +from .NoPermissionException import * from .RedisException import * from .ResponseCodeException import * from .ResponseException import * diff --git a/starbot/utils/config.py b/starbot/utils/config.py index d640b4c..e123ce7 100644 --- a/starbot/utils/config.py +++ b/starbot/utils/config.py @@ -57,6 +57,11 @@ SIMPLE_CONFIG = { # 视为主播网络波动断线重连时,需发送的额外提示消息 "UP_DISCONNECT_CONNECT_MESSAGE": "检测到下播后短时间内重新开播,可能是由于主播网络波动引起,本次开播不再重复通知", + # 当日 @全体成员 达到上限后,需发送的额外提示消息 + "AT_ALL_LIMITED_MESSAGE": "今日@全体成员次数已达上限,将尝试@指定成员,请需要接收单独@消息的群员使用\"开播@我\"命令进行订阅", + # 设置了 @全体成员 但没有管理员权限时,需发送的额外提示消息 + "NO_PERMISSION_MESSAGE": "已设置@全体成员但没有管理员权限,将尝试@指定成员,请需要接收单独@消息的群员使用\"开播@我\"命令进行订阅", + # 动态推送抓取频率和视为新动态的时间间隔,单位:秒 "DYNAMIC_INTERVAL": 10, @@ -168,6 +173,11 @@ FULL_CONFIG = { # 视为主播网络波动断线重连时,需发送的额外提示消息 "UP_DISCONNECT_CONNECT_MESSAGE": "检测到下播后短时间内重新开播,可能是由于主播网络波动引起,本次开播不再重复通知", + # 当日 @全体成员 达到上限后,需发送的额外提示消息 + "AT_ALL_LIMITED_MESSAGE": "今日@全体成员次数已达上限,将尝试@指定成员,请需要接收单独@消息的群员使用\"开播@我\"命令进行订阅", + # 设置了 @全体成员 但没有管理员权限时,需发送的额外提示消息 + "NO_PERMISSION_MESSAGE": "已设置@全体成员但没有管理员权限,将尝试@指定成员,请需要接收单独@消息的群员使用\"开播@我\"命令进行订阅", + # 动态推送抓取频率和视为新动态的时间间隔,单位:秒 "DYNAMIC_INTERVAL": 10,