# -*- coding: utf-8 -*- """ 管理员专用的广播插件 功能: - 仅限管理员在私聊中调用。 - 通过回复一条消息并发送指令,将该消息转发给机器人所在的所有群聊。 - 此插件不写入 __plugin_meta__,保持隐藏。 """ import asyncio from core.managers.command_manager import matcher from models.events.message import MessageEvent, PrivateMessageEvent from core.permission import Permission from core.utils.logger import logger # --- 会话状态管理 --- # 结构: {user_id: asyncio.TimerHandle} broadcast_sessions: dict[int, asyncio.TimerHandle] = {} def cleanup_session(user_id: int): """ 清理超时的广播会话。 """ if user_id in broadcast_sessions: del broadcast_sessions[user_id] logger.info(f"[Broadcast] 会话 {user_id} 已超时,自动取消。") @matcher.command("broadcast", "广播", permission=Permission.ADMIN) async def broadcast_start(event: MessageEvent): """ 广播指令的入口,启动一个等待用户消息的会话。 """ # 1. 仅限私聊 if not isinstance(event, PrivateMessageEvent): return user_id = event.user_id # 如果上一个会话的超时任务还在,先取消它 if user_id in broadcast_sessions: broadcast_sessions[user_id].cancel() await event.reply("已进入广播模式,请在 60 秒内发送您想要广播的消息内容。") # 设置 60 秒超时 loop = asyncio.get_running_loop() timeout_handler = loop.call_later( 60, cleanup_session, user_id ) broadcast_sessions[user_id] = timeout_handler @matcher.on_message() async def handle_broadcast_content(event: MessageEvent): """ 通用消息处理器,用于捕获广播模式下的消息输入。 将捕获到的消息打包成一个新的合并转发消息并广播。 """ # 仅处理私聊消息,且用户在广播会话中 if not isinstance(event, PrivateMessageEvent) or event.user_id not in broadcast_sessions: return user_id = event.user_id # 成功捕获到消息,取消超时任务并清理会话 broadcast_sessions[user_id].cancel() del broadcast_sessions[user_id] message_to_broadcast = event.message if not message_to_broadcast: await event.reply("捕获到的消息为空,已取消广播。") return True # --- 执行广播逻辑 --- bot = event.bot try: group_list = await bot.get_group_list() if not group_list: await event.reply("机器人目前没有加入任何群聊。") return True except Exception as e: logger.error(f"[Broadcast] 获取群聊列表失败: {e}") await event.reply(f"获取群聊列表时发生错误: {e}") return True success_count, failed_count = 0, 0 total_groups = len(group_list) await event.reply(f"已收到广播内容,准备打包并向 {total_groups} 个群聊广播...") # --- 将管理员发送的消息打包成一个单节点的合并转发消息 --- try: nodes_to_send = [ bot.build_forward_node( user_id=event.user_id, nickname=event.sender.nickname if event.sender else "未知用户", message=message_to_broadcast ) ] except Exception as e: logger.error(f"[Broadcast] 构建转发节点失败: {e}") await event.reply(f"构建转发消息节点时发生错误: {e}") return True # --- 向所有群聊发送打包好的合并转发消息 --- for group in group_list: try: await bot.send_group_forward_msg(group.group_id, nodes_to_send) success_count += 1 except Exception as e: failed_count += 1 logger.error(f"[Broadcast] 转发至群聊 {group.group_id} 失败: {e}") report = f"广播完成。\n总群聊: {total_groups}\n成功: {success_count}\n失败: {failed_count}" await event.reply(report) return True # 消费事件,防止其他处理器响应