diff --git a/.gitignore b/.gitignore index 8895dac..817f839 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ __pycache__/main.cpython-313.pyc +ref/ \ No newline at end of file diff --git a/_conf_schema.json b/_conf_schema.json new file mode 100644 index 0000000..447205a --- /dev/null +++ b/_conf_schema.json @@ -0,0 +1,14 @@ +{ + "group_whitelist": { + "description": "允许中转的群聊ID白名单(仅处理这些群的消息)", + "type": "list", + "hint": "填写需要允许中转的群号,多个群号用英文逗号分隔", + "default": [] + }, + "private_blacklist": { + "description": "不允许中转的私聊账号黑名单(这些账号的私聊消息将被忽略)", + "type": "list", + "hint": "填写需要屏蔽的用户ID,多个ID用英文逗号分隔", + "default": [] + } +} diff --git a/main.py b/main.py index 99ca4be..1f510f0 100644 --- a/main.py +++ b/main.py @@ -1,24 +1,92 @@ -from astrbot.api.event import filter, AstrMessageEvent, MessageEventResult +from astrbot.api.event import AstrMessageEvent +from astrbot.api.event.filter import event_message_type, EventMessageType from astrbot.api.star import Context, Star, register from astrbot.api import logger +import astrbot.api.message_components as Comp -@register("helloworld", "YourName", "一个简单的 Hello World 插件", "1.0.0") -class MyPlugin(Star): - def __init__(self, context: Context): + +def _check_at_bot(message_obj) -> bool: + """ + 检测群聊消息是否@了当前机器人。 + 依据: plugin.md 中 AstrBotMessage 及消息链定义: + - message_obj.message 为 BaseMessageComponent 列表 + - At(qq=...) 为 @ 消息段,message_obj.self_id 为机器人的标识 ID + 当消息链中存在 At 且其 qq 等于 self_id 时,判定为@了机器人。 + 忽略 AtAll(@全体)。 + """ + try: + self_id = str(getattr(message_obj, "self_id", "")) or "" + segments = getattr(message_obj, "message", []) or [] + except Exception: + return False + + if not self_id or not isinstance(segments, list): + return False + + for seg in segments: + # 适配对象消息段 + try: + if isinstance(seg, Comp.At): + # 排除 @all + if isinstance(seg, Comp.AtAll): + continue + if str(seg.qq) == self_id: + return True + except Exception: + pass + + # 适配字典形式的消息段(稳健性处理) + try: + if isinstance(seg, dict): + seg_type = str(seg.get("type", "")).lower() + data = seg.get("data", {}) or {} + if seg_type == "at": + qq = str(data.get("qq", "")) + if qq and qq.lower() != "all" and qq == self_id: + return True + except Exception: + pass + + return False + + + + +@register("relay", "YourName", "消息中转插件", "1.0.0") +class RelayPlugin(Star): + def __init__(self, context: Context, config=None): super().__init__(context) + self.config = config or {} + # 读取群聊白名单和私聊黑名单,全部转为字符串集合,避免类型不一致 + self.group_whitelist = set(str(x) for x in self.config.get("group_whitelist", [])) + self.private_blacklist = set(str(x) for x in self.config.get("private_blacklist", [])) + logger.info(f"[RelayPlugin] 群聊白名单: {self.group_whitelist}") + logger.info(f"[RelayPlugin] 私聊黑名单: {self.private_blacklist}") - async def initialize(self): - """可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。""" - - # 注册指令的装饰器。指令名为 helloworld。注册成功后,发送 `/helloworld` 就会触发这个指令,并回复 `你好, {user_name}!` - @filter.command("helloworld") - async def helloworld(self, event: AstrMessageEvent): - """这是一个 hello world 指令""" # 这是 handler 的描述,将会被解析方便用户了解插件内容。建议填写。 - user_name = event.get_sender_name() - message_str = event.message_str # 用户发的纯文本消息字符串 - message_chain = event.get_messages() # 用户所发的消息的消息链 # from astrbot.api.message_components import * - logger.info(message_chain) - yield event.plain_result(f"Hello, {user_name}, 你发了 {message_str}!") # 发送一条纯文本消息 + @event_message_type(EventMessageType.GROUP_MESSAGE) + async def on_group_message(self, event: AstrMessageEvent): + + group_id = str(event.message_obj.group_id) + at_bot = _check_at_bot(event.message_obj) + + if group_id not in self.group_whitelist: + logger.info(f"[RelayPlugin] 群聊 {group_id} 不在白名单,忽略消息") + return + if not at_bot: + logger.info(f"[RelayPlugin] 群聊 {group_id} 消息未@机器人,忽略消息") + return + logger.info(f"[RelayPlugin] 群聊 {group_id} 消息链: {event.message_obj.message}") + # TODO: 处理函数留空 - async def terminate(self): - """可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。""" + @event_message_type(EventMessageType.PRIVATE_MESSAGE) + async def on_private_message(self, event: AstrMessageEvent): + sender = event.message_obj.sender + if hasattr(sender, 'id'): + sender_id = str(sender.id) + else: + sender_id = str(sender) + if sender_id in set(str(x) for x in self.private_blacklist): + logger.info(f"[RelayPlugin] 私聊 {sender_id} 在黑名单,忽略消息") + return + logger.info(f"[RelayPlugin] 私聊 {sender_id} 消息链: {event.message_obj.message}") + # TODO: 处理函数留空 \ No newline at end of file