From 78335ed8a56ea412cad85d0312b8a088dcc29405 Mon Sep 17 00:00:00 2001 From: YIU Date: Fri, 17 May 2024 00:30:27 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Fix=20=E4=BF=AE=E5=A4=8D=E5=9C=A8=20Onebot?= =?UTF-8?q?=20v11=20=E9=80=82=E9=85=8D=E5=99=A8=E4=B8=8A=E4=B8=BB=E5=8A=A8?= =?UTF-8?q?=E5=8F=91=E9=80=81=E6=B6=88=E6=81=AF=E5=A4=B1=E8=B4=A5=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题描述 #95 --- amiyabot/adapters/onebot/v11/builder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/amiyabot/adapters/onebot/v11/builder.py b/amiyabot/adapters/onebot/v11/builder.py index 5c04131..e193a15 100644 --- a/amiyabot/adapters/onebot/v11/builder.py +++ b/amiyabot/adapters/onebot/v11/builder.py @@ -117,9 +117,12 @@ async def append_voice(file: str): def send_msg(chain: Chain, chain_data: Union[str, list]): - return { + msg_data = { 'message_type': chain.data.message_type, 'user_id': chain.data.user_id, 'group_id': chain.data.channel_id, 'message': chain_data, } + msg_data = {k: v for k, v in msg_data.items() if v is not None and v != ''} + + return msg_data From cacc6f9bf63935155ba5923f3cfac69d628ebcdb Mon Sep 17 00:00:00 2001 From: Vivien <34387011+vivien8261@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:21:21 +0800 Subject: [PATCH 2/2] =?UTF-8?q?update:=20=E6=94=AF=E6=8C=81=E5=85=A8?= =?UTF-8?q?=E5=9F=9Fbot=EF=BC=88=E5=90=8C=E6=97=B6=E4=BD=BF=E7=94=A8qq?= =?UTF-8?q?=E7=BE=A4=E8=81=8A=E5=92=8Cqq=E9=A2=91=E9=81=93=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- amiyabot/adapters/tencent/intents.py | 53 +++++++++++++ .../adapters/tencent/qqGlobal/__init__.py | 27 +++++++ amiyabot/adapters/tencent/qqGlobal/package.py | 20 +++++ amiyabot/adapters/tencent/qqGroup/__init__.py | 51 +++++++----- amiyabot/adapters/tencent/qqGroup/api.py | 3 + amiyabot/adapters/tencent/qqGroup/package.py | 12 ++- amiyabot/adapters/tencent/qqGuild/__init__.py | 7 +- amiyabot/adapters/tencent/qqGuild/intents.py | 77 ------------------- amiyabot/builtin/message/structure.py | 6 +- 9 files changed, 149 insertions(+), 107 deletions(-) create mode 100644 amiyabot/adapters/tencent/intents.py create mode 100644 amiyabot/adapters/tencent/qqGlobal/__init__.py create mode 100644 amiyabot/adapters/tencent/qqGlobal/package.py delete mode 100644 amiyabot/adapters/tencent/qqGuild/intents.py diff --git a/amiyabot/adapters/tencent/intents.py b/amiyabot/adapters/tencent/intents.py new file mode 100644 index 0000000..084be40 --- /dev/null +++ b/amiyabot/adapters/tencent/intents.py @@ -0,0 +1,53 @@ +""" +https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/interface-framework/event-emit.html#websocket-%E6%96%B9%E5%BC%8F +""" +import enum + + +class IntentsClass(enum.Enum): + @classmethod + def calc(cls): + intent = 0 + for item in cls: + intent |= item.value + return intent + + +class CommonIntents(IntentsClass): + GUILDS = 1 << 0 + GUILD_MEMBERS = 1 << 1 + GUILD_MESSAGE_REACTIONS = 1 << 10 + DIRECT_MESSAGE = 1 << 12 + INTERACTION = 1 << 26 + MESSAGE_AUDIT = 1 << 27 + AUDIO_ACTION = 1 << 29 + + +class PublicIntents(IntentsClass): + PUBLIC_GUILD_MESSAGES = 1 << 30 + + +class PrivateIntents(IntentsClass): + GUILD_MESSAGES = 1 << 9 + FORUMS_EVENT = 1 << 28 + + +class GroupIntents(IntentsClass): + GROUP_AND_C2C_EVENT = 1 << 25 + + +def get_intents(private: bool, name: str) -> int: + if name == 'QQGroup': + return GroupIntents.calc() + + res = CommonIntents.calc() + + if private: + res |= PrivateIntents.calc() + else: + res |= PublicIntents.calc() + + if name == 'QQGlobal': + res |= GroupIntents.calc() + + return res diff --git a/amiyabot/adapters/tencent/qqGlobal/__init__.py b/amiyabot/adapters/tencent/qqGlobal/__init__.py new file mode 100644 index 0000000..bcbea5a --- /dev/null +++ b/amiyabot/adapters/tencent/qqGlobal/__init__.py @@ -0,0 +1,27 @@ +from amiyabot.builtin.messageChain import Chain, ChainBuilder +from amiyabot.adapters.tencent.qqGuild import QQGuildBotInstance +from amiyabot.adapters.tencent.qqGroup import QQGroupBotInstance + +from .package import package_qq_global_message + + +class QQGlobalBotInstance(QQGroupBotInstance): + def __init__(self, appid: str, token: str, client_secret: str, default_chain_builder: ChainBuilder): + super().__init__(appid, token, client_secret, default_chain_builder) + + self.guild = QQGuildBotInstance(appid, token) + + def __str__(self): + return 'QQGlobal' + + @property + def package_method(self): + return package_qq_global_message + + async def send_chain_message(self, chain: Chain, is_sync: bool = False): + if not (chain.data.channel_openid or chain.data.user_openid): + return await self.guild.send_chain_message(chain, is_sync) + return await super().send_chain_message(chain, is_sync) + + +qq_global = QQGlobalBotInstance.build_adapter diff --git a/amiyabot/adapters/tencent/qqGlobal/package.py b/amiyabot/adapters/tencent/qqGlobal/package.py new file mode 100644 index 0000000..a81bb15 --- /dev/null +++ b/amiyabot/adapters/tencent/qqGlobal/package.py @@ -0,0 +1,20 @@ +from amiyabot.adapters import BotAdapterProtocol +from amiyabot.adapters.tencent.qqGroup.package import package_qq_group_message +from amiyabot.adapters.tencent.qqGuild.package import package_qq_guild_message + + +async def package_qq_global_message( + instance: BotAdapterProtocol, + event: str, + message: dict, + is_reference: bool = False, +): + group_message_created = [ + 'C2C_MESSAGE_CREATE', + 'GROUP_AT_MESSAGE_CREATE', + ] + + if event in group_message_created: + return await package_qq_group_message(instance, event, message, is_reference) + + return await package_qq_guild_message(instance, event, message, is_reference) diff --git a/amiyabot/adapters/tencent/qqGroup/__init__.py b/amiyabot/adapters/tencent/qqGroup/__init__.py index d4a3d03..94aa8a1 100644 --- a/amiyabot/adapters/tencent/qqGroup/__init__.py +++ b/amiyabot/adapters/tencent/qqGroup/__init__.py @@ -2,6 +2,7 @@ from typing import Optional from amiyabot.builtin.messageChain import Chain, ChainBuilder +from amiyabot.adapters import HANDLER_TYPE from amiyabot.adapters.tencent.qqGuild import QQGuildBotInstance from .api import QQGroupAPI, log @@ -13,23 +14,6 @@ build_message_send, ) from .package import package_qq_group_message -from ... import HANDLER_TYPE - - -def qq_group( - client_secret: str, - default_chain_builder: Optional[ChainBuilder] = None, - default_chain_builder_options: QQGroupChainBuilderOptions = QQGroupChainBuilderOptions(), -): - def adapter(appid: str, token: str): - if default_chain_builder: - cb = default_chain_builder - else: - cb = QQGroupChainBuilder(default_chain_builder_options) - - return QQGroupBotInstance(appid, token, client_secret, cb) - - return adapter class QQGroupBotInstance(QQGuildBotInstance): @@ -43,6 +27,23 @@ def __init__(self, appid: str, token: str, client_secret: str, default_chain_bui def __str__(self): return 'QQGroup' + @classmethod + def build_adapter( + cls, + client_secret: str, + default_chain_builder: Optional[ChainBuilder] = None, + default_chain_builder_options: QQGroupChainBuilderOptions = QQGroupChainBuilderOptions(), + ): + def adapter(appid: str, token: str): + if default_chain_builder: + cb = default_chain_builder + else: + cb = QQGroupChainBuilder(default_chain_builder_options) + + return cls(appid, token, client_secret, cb) + + return adapter + @property def api(self): return self.__access_token_api @@ -74,10 +75,20 @@ async def send_chain_message(self, chain: Chain, is_sync: bool = False): for payload in payloads: async with log.catch('post error:', ignore=[asyncio.TimeoutError]): res.append( - await self.api.post_group_message( - chain.data.channel_openid, - payload, + await ( + self.api.post_private_message( + chain.data.user_openid, + payload, + ) + if chain.data.is_direct + else self.api.post_group_message( + chain.data.channel_openid, + payload, + ) ) ) return [QQGroupMessageCallback(chain.data, self, item) for item in res] + + +qq_group = QQGroupBotInstance.build_adapter diff --git a/amiyabot/adapters/tencent/qqGroup/api.py b/amiyabot/adapters/tencent/qqGroup/api.py index a854673..682f357 100644 --- a/amiyabot/adapters/tencent/qqGroup/api.py +++ b/amiyabot/adapters/tencent/qqGroup/api.py @@ -61,3 +61,6 @@ async def upload_file(self, channel_openid: str, file_type: int, url: str, srv_s async def post_group_message(self, channel_openid: str, payload: dict): return await self.post(f'/v2/groups/{channel_openid}/messages', payload) + + async def post_private_message(self, user_openid: str, payload: dict): + return await self.post(f'/v2/users/{user_openid}/messages', payload) diff --git a/amiyabot/adapters/tencent/qqGroup/package.py b/amiyabot/adapters/tencent/qqGroup/package.py index 2434a15..8cf6a91 100644 --- a/amiyabot/adapters/tencent/qqGroup/package.py +++ b/amiyabot/adapters/tencent/qqGroup/package.py @@ -13,11 +13,15 @@ async def package_qq_group_message(instance: BotAdapterProtocol, event: str, mes data.is_direct = event == 'C2C_MESSAGE_CREATE' data.is_at = True - data.user_id = message['author']['id'] - data.user_openid = message['author']['member_openid'] - data.channel_id = message['group_id'] - data.channel_openid = message['group_openid'] data.message_id = message['id'] + data.user_id = message['author']['id'] + + if data.is_direct: + data.user_openid = message['author']['user_openid'] + else: + data.user_openid = message['author']['member_openid'] + data.channel_id = message['group_id'] + data.channel_openid = message['group_openid'] if 'attachments' in message: for item in message['attachments']: diff --git a/amiyabot/adapters/tencent/qqGuild/__init__.py b/amiyabot/adapters/tencent/qqGuild/__init__.py index 8112ce9..7b67f17 100644 --- a/amiyabot/adapters/tencent/qqGuild/__init__.py +++ b/amiyabot/adapters/tencent/qqGuild/__init__.py @@ -8,10 +8,10 @@ from amiyabot.builtin.message import Message from amiyabot.builtin.messageChain import Chain from amiyabot.adapters import BotAdapterProtocol, HANDLER_TYPE +from amiyabot.adapters.tencent.intents import get_intents from .api import QQGuildAPI, log from .model import GateWay, Payload, ShardsRecord, ConnectionHandler -from .intents import get_intents from .package import package_qq_guild_message from .builder import build_message_send, QQGuildMessageCallback @@ -91,7 +91,8 @@ async def create_connection(self, handler: ConnectionHandler, shards_index: int if payload.t == 'READY': self.bot_name = payload.d['user']['username'] log.info( - f'connected({sign}): {self.bot_name}(%s)' % ('private' if handler.private else 'public') + f'connected({sign}): {self.bot_name}({self}-%s)' + % ('private' if handler.private else 'public') ) self.shards_record[shards_index].session_id = payload.d['session_id'] @@ -104,7 +105,7 @@ async def create_connection(self, handler: ConnectionHandler, shards_index: int if payload.op == 10: create_token = { 'token': f'Bot {self.appid}.{self.token}', - 'intents': get_intents(handler.private, self.__str__()).get_all_intents(), + 'intents': get_intents(handler.private, self.__str__()), 'shard': [shards_index, gateway.shards], 'properties': { '$os': sys.platform, diff --git a/amiyabot/adapters/tencent/qqGuild/intents.py b/amiyabot/adapters/tencent/qqGuild/intents.py deleted file mode 100644 index 962ed85..0000000 --- a/amiyabot/adapters/tencent/qqGuild/intents.py +++ /dev/null @@ -1,77 +0,0 @@ -import abc - -from typing import Type - - -class IntentsClass: - @classmethod - @abc.abstractmethod - def get_all_intents(cls): - raise NotImplementedError - - -class PublicIntents(IntentsClass): - GUILDS = 1 << 0 - GUILD_MEMBERS = 1 << 1 - GUILD_MESSAGE_REACTIONS = 1 << 10 - DIRECT_MESSAGE = 1 << 12 - INTERACTION = 1 << 26 - MESSAGE_AUDIT = 1 << 27 - AUDIO_ACTION = 1 << 29 - PUBLIC_GUILD_MESSAGES = 1 << 30 - - @classmethod - def public_intents(cls, private: bool = False): - intent = 0 - intent |= cls.GUILDS - intent |= cls.GUILD_MEMBERS - intent |= cls.GUILD_MESSAGE_REACTIONS - intent |= cls.DIRECT_MESSAGE - intent |= cls.INTERACTION - intent |= cls.MESSAGE_AUDIT - intent |= cls.AUDIO_ACTION - - if not private: - intent |= cls.PUBLIC_GUILD_MESSAGES - - return intent - - @classmethod - def get_all_intents(cls): - return cls.public_intents() - - -class PrivateIntents(PublicIntents): - GUILD_MESSAGES = 1 << 9 - FORUMS_EVENT = 1 << 28 - - @classmethod - def get_all_intents(cls): - intent = cls.public_intents(private=True) - intent |= cls.GUILD_MESSAGES - intent |= cls.FORUMS_EVENT - - return intent - - -class GroupIntents(IntentsClass): - C2C_MESSAGE_CREATE = 1 << 25 - GROUP_AT_MESSAGE_CREATE = 1 << 25 - - @classmethod - def get_all_intents(cls): - intent = 0 - intent |= cls.GROUP_AT_MESSAGE_CREATE - - return intent - - -def get_intents(private: bool, name: str) -> Type[IntentsClass]: - if name == 'QQGroup': - return GroupIntents - return PrivateIntents if private else PublicIntents - - -""" -https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/interface-framework/event-emit.html#websocket-%E6%96%B9%E5%BC%8F -""" diff --git a/amiyabot/builtin/message/structure.py b/amiyabot/builtin/message/structure.py index 4efb047..fb0e14b 100644 --- a/amiyabot/builtin/message/structure.py +++ b/amiyabot/builtin/message/structure.py @@ -68,14 +68,14 @@ def __str__(self): face = ''.join([f'[face:{n}]' for n in self.face]) image = '[image]' * len(self.image) - return 'Bot:{bot} Channel:{channel} User:{user}{admin}{direct} {nickname}: {message}'.format( + return 'Bot:{bot}{channel} User:{user}{admin}{direct}{nickname}: {message}'.format( **{ 'bot': self.instance.appid, - 'channel': self.channel_id, + 'channel': f' Channel:{self.channel_id}' if self.channel_id else '', 'user': self.user_id, 'admin': '(admin)' if self.is_admin else '', 'direct': '(direct)' if self.is_direct else '', - 'nickname': self.nickname, + 'nickname': f' {self.nickname}' if self.nickname else '', 'message': text + face + image, } )