Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 39 additions & 16 deletions nonebot/adapters/qq/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
Event,
FriendAddEvent,
GroupAddRobotEvent,
GroupAtMessageCreateEvent,
GroupMessageCreateEvent,
GuildMessageEvent,
InteractionCreateEvent,
Expand Down Expand Up @@ -115,36 +116,58 @@ async def _check_reply(
bot: Bot 对象
event: MessageEvent 对象
"""
if not isinstance(event, GuildMessageEvent) or event.message_reference is None:
return
try:
event.reply = await bot.get_message_of_id(
channel_id=event.channel_id,
message_id=event.message_reference.message_id,
)
if event.reply.author.id == bot.self_info.id:
if isinstance(event, GuildMessageEvent):
if event.message_reference is None:
return
try:
event.reply = await bot.get_message_of_id(
channel_id=event.channel_id,
message_id=event.message_reference.message_id,
)
if event.reply.author.id == bot.self_info.id:
event.to_me = True
except Exception as e:
log("WARNING", f"Error when getting message reply info: {e!r}", e)
else:
if not event.msg_elements:
return
event.reply = event.msg_elements[0]
if (
event.reply.author
and event.reply.author.bot
and event.reply.author.username == bot.self_info.username
):
event.to_me = True
except Exception as e:
log("WARNING", f"Error when getting message reply info: {e!r}", e)


def _check_at_me(
bot: "Bot",
event: GuildMessageEvent | QQMessageEvent,
):
message = event.get_message()
if not message:
message.append(MessageSegment.text(""))
if isinstance(event, GroupAtMessageCreateEvent):
event.original_message = message.copy()
event.original_message.insert(0, MessageSegment.mention_user(bot.self_info.id))
if message and message[0].type == "text":
message[0].data["text"] = message[0].data["text"].lstrip("\xa0").lstrip()
if not message[0].data["text"]:
del message[0]
return
if (
isinstance(event, GuildMessageEvent)
and event.mentions is not None
and bot.self_info.id in {user.id for user in event.mentions}
):
event.to_me = True

if (
isinstance(event, QQMessageEvent)
and event.mentions is not None
and any(user.is_you for user in event.mentions)
):
event.to_me = True
if isinstance(event, GroupMessageCreateEvent):
for seg in message:
if seg.type == "mention_user" and seg.data.get("is_bot", False):
seg.data["user_id"] = bot.self_info.id

event.original_message = message.copy()

def _is_at_me_seg(segment: MessageSegment) -> bool:
if segment.type == "mention_user":
Expand Down
33 changes: 22 additions & 11 deletions nonebot/adapters/qq/event.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import datetime
from enum import Enum
from typing import TypeVar, cast
from typing import TYPE_CHECKING, TypeVar, cast
from typing_extensions import override

from nonebot.utils import escape_tag
Expand All @@ -23,6 +23,7 @@
MessageReaction,
Post,
QQMessage,
QQReplyMessage,
Reply,
RichText,
Thread,
Expand Down Expand Up @@ -270,6 +271,10 @@ class GuildMemberRemoveEvent(GuildMemberEvent):
class MessageEvent(Event):
to_me: bool = False

if TYPE_CHECKING:
message: Message
original_message: Message

@override
def get_type(self) -> str:
return "message"
Expand Down Expand Up @@ -306,9 +311,9 @@ def get_event_description(self) -> str:

@override
def get_message(self) -> Message:
if not hasattr(self, "_message"):
setattr(self, "_message", Message.from_guild_message(self))
return getattr(self, "_message")
if not hasattr(self, "message"):
self.message = Message.from_guild_message(self)
return self.message


@register_event_class
Expand Down Expand Up @@ -360,13 +365,18 @@ class DirectMessageDeleteEvent(MessageDeleteEvent):


class QQMessageEvent(MessageEvent, QQMessage):
reply: QQReplyMessage | None = None
_reply_seq: int = 0

@override
def get_message(self) -> Message:
if not hasattr(self, "_message"):
setattr(self, "_message", Message.from_qq_message(self))
return getattr(self, "_message")
if not hasattr(self, "message"):
self.message = Message.from_qq_message(self)
return self.message

def get_reply_message(self) -> Message | None:
if self.reply:
return Message.from_qq_message(self.reply)


@register_event_class
Expand Down Expand Up @@ -396,18 +406,18 @@ class GroupMessageCreateEvent(QQMessageEvent):
__type__ = EventType.GROUP_MESSAGE_CREATE

author: GroupMemberAuthor
group_openid: str
group_id: str
group_openid: str

@override
def get_message(self) -> Message:
# tmp fix to remove space before text due to at not in content
msg = Message.from_qq_message(self)
if msg and msg[0].type == "text":
msg[0].data["text"] = msg[0].data["text"].lstrip()
if not hasattr(self, "_message"):
setattr(self, "_message", msg)
return getattr(self, "_message")
if not hasattr(self, "message"):
self.message = msg
return self.message

@override
def get_user_id(self) -> str:
Expand Down Expand Up @@ -731,6 +741,7 @@ class GroupMsgReceiveEvent(GroupRobotEvent):
"GroupAddRobotEvent",
"GroupAtMessageCreateEvent",
"GroupDelRobotEvent",
"GroupMessageCreateEvent",
"GroupMsgReceiveEvent",
"GroupMsgRejectEvent",
"GroupRobotEvent",
Expand Down
124 changes: 65 additions & 59 deletions nonebot/adapters/qq/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
from pathlib import Path
import re
from typing import TYPE_CHECKING, Literal, TypedDict, Union, overload
from typing_extensions import Self, override
from typing_extensions import NotRequired, Self, override

from nonebot.compat import type_validate_python

from nonebot.adapters import Message as BaseMessage
from nonebot.adapters import MessageSegment as BaseMessageSegment

from .models import Attachment as QQAttachment
from .models import GroupMentionUser as QQGroupMentionUser
from .models import Message as GuildMessage
from .models import (
GroupMentionUser,
MessageActionButton,
MessageArk,
MessageEmbed,
Expand All @@ -24,7 +23,9 @@
MessageReference,
MessageStream,
QQMessage,
QQReplyMessage,
)
from .models import Message as GuildMessage
from .utils import escape, unescape


Expand All @@ -43,8 +44,11 @@ def emoji(id: str) -> "Emoji":
return Emoji("emoji", data={"id": id})

@staticmethod
def mention_user(user_id: str) -> "MentionUser":
return MentionUser("mention_user", {"user_id": str(user_id)})
def mention_user(user_id: str, username: str | None = None) -> "MentionUser":
data: "_MentionUserData" = {"user_id": str(user_id)}
if username:
data["username"] = username
return MentionUser("mention_user", data)

@staticmethod
def mention_channel(channel_id: str) -> "MentionChannel":
Expand Down Expand Up @@ -283,42 +287,10 @@ def __str__(self) -> str:
return f"<emoji:{self.data['id']}>"


class _GroupMentionUserData(TypedDict):
bot: bool
id: str
is_you: bool
member_openid: str
scope: str
username: str


@dataclass
class GroupMentionUser(MessageSegment):
if TYPE_CHECKING:
data: _GroupMentionUserData

@override
def __str__(self) -> str:
return f"<@{self.data['id']}>"

@classmethod
@override
def _validate(cls, value) -> Self:
instance = super()._validate(value)
mention_user = type_validate_python(QQGroupMentionUser, instance.data)
instance.data = {
"bot": mention_user.bot,
"id": mention_user.id,
"is_you": mention_user.is_you,
"member_openid": mention_user.member_openid,
"scope": mention_user.scope,
"username": mention_user.username,
}
return instance


class _MentionUserData(TypedDict):
user_id: str
username: NotRequired[str]
is_bot: NotRequired[bool]


@dataclass
Expand Down Expand Up @@ -524,7 +496,6 @@ def _validate(cls, value) -> Self:
"mention_user": MentionUser,
"mention_channel": MentionChannel,
"mention_everyone": MentionEveryone,
"group_mention_user": GroupMentionUser,
"image": Attachment,
"file_image": LocalAttachment,
"audio": Attachment,
Expand Down Expand Up @@ -605,22 +576,29 @@ def __radd__(self, other: str | MessageSegment | Iterable[MessageSegment]) -> Se
@override
def _construct(msg: str) -> Iterable[MessageSegment]:
text_begin = 0
msg = msg.replace("@everyone", "")
msg = re.sub(r"\<qqbot-at-everyone\s/\>", "", msg)
for embed in re.finditer(
r"\<(?P<type>(?:@|#|emoji:))!?(?P<id>\w+?)\>",
r"\<(?P<type>(?:@|#|emoji:))!?(?P<id>\w+?)\>|\<(?P<type1>qqbot-at-user) id=\"(?P<id1>\w+)\"\s/\>", # noqa: E501
msg,
):
content = msg[text_begin : embed.pos + embed.start()]
if content:
yield Text("text", {"text": unescape(content)})
text_begin = embed.pos + embed.end()
if embed.group("type") == "@":
yield MentionUser("mention_user", {"user_id": embed.group("id")})
if embed.group("id") == "all":
yield MessageSegment.mention_everyone()
else:
yield MentionUser("mention_user", {"user_id": embed.group("id")})
elif embed.group("type") == "#":
yield MentionChannel(
"mention_channel", {"channel_id": embed.group("id")}
)
else:
elif embed.group("type") == "emoji":
yield Emoji("emoji", {"id": embed.group("id")})
elif embed.group("type1") == "qqbot-at-user":
yield MentionUser("mention_user", {"user_id": embed.group("id1")})
content = msg[text_begin:]
if content:
yield Text("text", {"text": unescape(msg[text_begin:])})
Expand All @@ -643,8 +621,15 @@ def from_guild_message(cls, message: GuildMessage) -> Self:
return msg

@classmethod
def from_qq_message(cls, message: QQMessage) -> Self:
def from_qq_message(cls, message: QQMessage | QQReplyMessage) -> Self:
msg = cls()
# if isinstance(message, QQMessage) and message.msg_elements:
# msg.append(Reference("reference", {
# "reference": MessageReference(
# message_id=message.msg_elements[0].msg_idx
# ),
# "message": message.msg_elements[0]
# }))
Comment thread
yanyongyu marked this conversation as resolved.
if message.content:
msg.extend(Message(message.content))
if message.attachments:
Expand All @@ -663,21 +648,42 @@ def content_type(seg: QQAttachment):
for seg in message.attachments
if seg.url
)
if message.mentions:
msg.extend(
GroupMentionUser(
"group_mention_user",
data={
"bot": mention.bot,
"id": mention.id,
"is_you": mention.is_you,
"member_openid": mention.member_openid,
"scope": mention.scope,
"username": mention.username,
},
)
for mention in message.mentions
)
mentions = {
m.id: m
for m in getattr(message, "mentions", [])
if isinstance(m, GroupMentionUser)
}
ats = msg["mention_user"]
if not ats:
for mention in mentions.values():
if mention.is_you:
msg.insert(
0,
MentionUser(
"mention_user",
{
"user_id": mention.id,
"username": mention.username,
"is_bot": True,
},
),
)
else:
msg.append(
MentionUser(
"mention_user",
{
"user_id": mention.id,
"username": mention.username,
"is_bot": False,
},
)
)
else:
for at in ats:
if mention := mentions.get(at.data["user_id"]):
at.data["username"] = mention.username
at.data["is_bot"] = mention.is_you
return msg

def extract_content(self, escape_text: bool = True) -> str:
Expand Down
Loading
Loading