feature:1.加群功能插件化;2.成员变更不监听消息,使用定时检查策略;
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# 从当前包的main模块导入GroupMemberChangePlugin类
|
||||
from .main import GroupMemberChangePlugin
|
||||
|
||||
# 提供get_plugin函数,返回插件实例
|
||||
def get_plugin():
|
||||
"""获取插件实例"""
|
||||
return GroupMemberChangePlugin()
|
||||
@@ -0,0 +1,3 @@
|
||||
[GroupMemberChange]
|
||||
enable = true
|
||||
check_interval = 30 # 检查间隔,单位为秒
|
||||
@@ -0,0 +1,247 @@
|
||||
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.wcf = None
|
||||
self.gbm = None
|
||||
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")
|
||||
if not self.wcf:
|
||||
self.LOG.error("无法获取wcf对象,插件初始化失败")
|
||||
return False
|
||||
|
||||
# 获取群管理器
|
||||
self.gbm = context.get("gbm")
|
||||
if not self.gbm:
|
||||
self.LOG.error("无法获取群管理器对象,插件初始化失败")
|
||||
return False
|
||||
|
||||
# 从配置中获取启用状态和检查间隔
|
||||
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 = self.gbm.get_group_list()
|
||||
|
||||
for group_id in group_list:
|
||||
# 检查群是否启用了成员变更提醒功能
|
||||
if self.gbm.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]
|
||||
member_info = self._get_member_info(wxid, nickname)
|
||||
self._send_leave_notification(group_id, member_info)
|
||||
|
||||
# 处理新加入成员
|
||||
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 _get_member_info(self, wxid: str, nickname: str) -> Dict[str, str]:
|
||||
"""获取成员详细信息"""
|
||||
try:
|
||||
# 尝试获取成员详细信息
|
||||
member_info = {
|
||||
"wxid": wxid,
|
||||
"nickname": nickname,
|
||||
"remark": "",
|
||||
"gender": "未知",
|
||||
"region": "未知"
|
||||
}
|
||||
|
||||
# 尝试获取用户详情
|
||||
user_info = self.wcf.get_user_info(wxid)
|
||||
if user_info:
|
||||
member_info["remark"] = user_info.get("remark", "")
|
||||
|
||||
# 性别转换
|
||||
gender_code = user_info.get("gender", 0)
|
||||
if gender_code == 1:
|
||||
member_info["gender"] = "男"
|
||||
elif gender_code == 2:
|
||||
member_info["gender"] = "女"
|
||||
|
||||
# 地区信息
|
||||
country = user_info.get("country", "")
|
||||
province = user_info.get("province", "")
|
||||
city = user_info.get("city", "")
|
||||
if country or province or city:
|
||||
member_info["region"] = f"{country} {province} {city}".strip()
|
||||
|
||||
return member_info
|
||||
|
||||
except Exception as e:
|
||||
self.LOG.error(f"获取成员 {wxid} 信息时发生错误: {e}")
|
||||
return {
|
||||
"wxid": wxid,
|
||||
"nickname": nickname,
|
||||
"remark": "",
|
||||
"gender": "未知",
|
||||
"region": "未知"
|
||||
}
|
||||
|
||||
def _send_leave_notification(self, group_id: str, member_info: Dict[str, str]):
|
||||
"""发送成员退群通知"""
|
||||
now_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
message = f"""【退群提醒】
|
||||
用户: {member_info['nickname']} ({member_info['gender']})
|
||||
群备注: {member_info['remark']}
|
||||
微信号: {member_info['wxid']}
|
||||
地区: {member_info['region']}
|
||||
退群时间: {now_time}
|
||||
"""
|
||||
|
||||
self.wcf.send_text(message, group_id)
|
||||
self.LOG.info(f"已发送退群通知: {member_info['nickname']} 退出群 {group_id}")
|
||||
|
||||
@property
|
||||
def commands(self) -> List[str]:
|
||||
"""插件支持的命令列表"""
|
||||
return []
|
||||
|
||||
def get_help(self) -> str:
|
||||
"""获取插件帮助信息"""
|
||||
return "群成员变更监控插件:自动监控群成员变动并发送通知。"
|
||||
Reference in New Issue
Block a user