import logging import threading import time from datetime import datetime from typing import Dict, Any, List, Optional, Set, Tuple from wcferry import Wcf from plugin_common.message_plugin_interface import MessagePluginInterface from plugin_common.plugin_interface import PluginStatus from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager class GroupMemberChangePlugin(MessagePluginInterface): """群成员变更监控插件""" @property def name(self) -> str: return "群成员变更监控" @property def version(self) -> str: return "1.0.0" @property def description(self) -> str: return "监控群成员变动并发送通知" @property def author(self) -> str: return "Trae AI" def __init__(self): super().__init__() self.status = PluginStatus.LOADED self.LOG = logging.getLogger(f"Plugin.{self.name}") # 初始化本地缓存字典,使用 group_id 作为键 self.local_members = {} # 监控线程 self.monitor_thread = None self.stop_flag = False # 检查间隔时间(秒) self.check_interval = 30 def initialize(self, context: Dict[str, Any]) -> bool: """初始化插件""" self.LOG.info(f"正在初始化 {self.name} 插件...") # 保存上下文对象 self.wcf: Wcf = context.get("wcf") # 获取群管理器 # 从配置中获取启用状态和检查间隔 plugin_config = self._config.get("GroupMemberChange", {}) self.check_interval = plugin_config.get("check_interval", 30) self.LOG.info(f"{self.name} 插件初始化完成,检查间隔: {self.check_interval}秒") return True def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]: """处理接收到的消息""" # 此插件主要通过定时任务工作,不处理消息 return False, "无需执行" def start(self) -> bool: """启动插件""" if self.status == PluginStatus.RUNNING: self.LOG.warning(f"{self.name} 插件已经在运行中") return True self.stop_flag = False # 启动监控线程 self.monitor_thread = threading.Thread(target=self._monitor_groups, daemon=True) self.monitor_thread.start() self.status = PluginStatus.RUNNING self.LOG.info(f"[{self.name}] 插件已启动") return True def stop(self) -> bool: """停止插件""" if self.status != PluginStatus.RUNNING: self.LOG.warning(f"{self.name} 插件未在运行中") return True self.stop_flag = True if self.monitor_thread and self.monitor_thread.is_alive(): self.monitor_thread.join(timeout=5) self.status = PluginStatus.STOPPED self.LOG.info(f"[{self.name}] 插件已停止") return True def _monitor_groups(self): """监控群成员变化的线程函数""" self.LOG.info("群成员监控线程已启动") while not self.stop_flag: try: # 获取所有启用了机器人的群组 group_list = GroupBotManager.get_group_list() for group_id in group_list: # 检查群是否启用了成员变更提醒功能 if GroupBotManager.get_group_permission(group_id, Feature.GROUP_MEMBER_CHANGE) == PermissionStatus.ENABLED: self._check_group_members(group_id) # 等待指定的时间间隔 for _ in range(self.check_interval): if self.stop_flag: break time.sleep(1) except Exception as e: self.LOG.error(f"监控群成员变化时发生错误: {e}", exc_info=True) time.sleep(5) # 发生错误时短暂休眠 self.LOG.info("群成员监控线程已停止") def _check_group_members(self, group_id: str): """检查指定群的成员变化""" try: # 获取当前群成员 current_members = self.wcf.get_chatroom_members(group_id) # 如果是首次检查该群 if group_id not in self.local_members: self.LOG.info(f"首次检查群 {group_id},记录当前成员") self.local_members[group_id] = current_members return # 获取上次记录的成员 previous_members = self.local_members[group_id] # 比较成员变化 current_member_ids = set(current_members.keys()) previous_member_ids = set(previous_members.keys()) # 找出退群的成员 left_members = previous_member_ids - current_member_ids # 找出新加入的成员 joined_members = current_member_ids - previous_member_ids # 如果有成员变化 if left_members or joined_members: self.LOG.info(f"群 {group_id} 成员发生变化: {len(joined_members)}人加入, {len(left_members)}人退出") # 处理退群成员 for wxid in left_members: nickname = previous_members[wxid] self._send_leave_notification(group_id, wxid, nickname) # 处理新加入成员 for wxid in joined_members: nickname = current_members[wxid] # 可以在这里添加欢迎新成员的代码 # 更新本地缓存 self.local_members[group_id] = current_members except Exception as e: self.LOG.error(f"检查群 {group_id} 成员变化时发生错误: {e}", exc_info=True) def _send_leave_notification(self, group_id: str, wxid: str, nickname: str): """发送成员退群通知""" now_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') message = f"""【退群提醒】 用户: {nickname} 微信号: {wxid} 退群时间: {now_time} """ self.wcf.send_text(message, group_id) self.LOG.info(f"已发送退群通知: {nickname} 退出群 {group_id}") @property def commands(self) -> List[str]: """插件支持的命令列表""" return [] def get_help(self) -> str: """获取插件帮助信息""" return "群成员变更监控插件:自动监控群成员变动并发送通知。"