UNPKG

koishi-plugin-onebot-manager

Version:

提供群管命令,可基于规则自动处理好友/加群/邀请请求,且能监听管理/进群/退群事件

754 lines (747 loc) 37 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name2 in all) __defProp(target, name2, { get: all[name2], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Config: () => Config, apply: () => apply, inject: () => inject, name: () => name, usage: () => usage }); module.exports = __toCommonJS(src_exports); var import_koishi2 = require("koishi"); // src/request.ts var OnebotRequest = class { /** * 创建 OneBot 请求处理实例 * @param ctx - Koishi 上下文 * @param logger - 日志记录器 * @param config - 配置项 */ constructor(ctx, logger, config = {}) { this.ctx = ctx; this.logger = logger; this.config = config; } static { __name(this, "OnebotRequest"); } requestNumberMap = /* @__PURE__ */ new Map(); nextRequestNumber = 1; activeRequests = /* @__PURE__ */ new Map(); /** * 清理并取消一个活动中的请求 */ cleanupActiveRequest(requestKey) { const activeRequest = this.activeRequests.get(requestKey); if (!activeRequest) return; activeRequest.disposer?.(); if (activeRequest.timeoutTimer) clearTimeout(activeRequest.timeoutTimer); this.requestNumberMap.delete(activeRequest.requestNumber); this.activeRequests.delete(requestKey); } /** * 发送请求通知 */ async sendRequestNotification(session, type, status, details = {}) { const { notifyTarget = "" } = this.config; if (!notifyTarget) return; const [targetType, targetId] = notifyTarget.split(":"); if (!targetId || targetType !== "guild" && targetType !== "private") { this.logger.warn(`通知目标错误: ${notifyTarget}`); return; } try { const eventData = session.event?._data || {}; const user = await session.bot.getUser?.(session.userId)?.catch(() => null) ?? { name: session.userId }; const guild = type !== "friend" ? await session.bot.getGuild?.(session.guildId)?.catch(() => null) ?? null : null; const operator = type === "guild" && eventData.operator_id && eventData.operator_id !== session.userId ? await session.bot.getUser?.(eventData.operator_id.toString())?.catch(() => null) ?? null : null; const msgLines = []; if (user?.avatar) msgLines.push(`<image url="${user.avatar}"/>`); msgLines.push(`类型:${type === "friend" ? "好友申请" : type === "member" ? "加群请求" : eventData.sub_type === "invite" ? "群邀请" : "直接入群"}`); if (session.userId && !(type === "guild" && eventData.sub_type !== "invite" && session.userId === session.selfId)) msgLines.push(`用户:${user?.name ? `${user.name}(${session.userId})` : session.userId}`); if (operator) msgLines.push(`操作者:${operator.name ? `${operator.name}(${eventData.operator_id})` : eventData.operator_id}`); if (guild) msgLines.push(`群组:${guild.name ? `${guild.name}(${session.guildId})` : session.guildId}`); if (eventData.comment) msgLines.push(`验证信息:${eventData.comment}`); const sendFunc = targetType === "private" ? (m) => session.bot.sendPrivateMessage(targetId, m) : (m) => session.bot.sendMessage(targetId, m); await sendFunc(msgLines.join("\n")); if (status === "pending" && details.requestNumber) await sendFunc(`请回复以下命令处理请求 #${details.requestNumber}: 通过[y/ya]${details.requestNumber} [备注] | 拒绝[n/na]${details.requestNumber} [理由]`); } catch (error) { this.logger.error(`发送请求 #${details.requestNumber} 通知失败: ${error}`); } } /** * 处理收到的请求 */ async processRequest(session, type) { const requestKey = type === "friend" ? `friend:${session.userId}` : type === "guild" ? `guild:${session.guildId}` : `member:${session.userId}:${session.guildId}`; this.cleanupActiveRequest(requestKey); try { const autoAcceptResult = await this.shouldAutoAccept(session, type); if (autoAcceptResult === true) { await this.processRequestAction(session, type, true); await this.sendRequestNotification(session, type, "approved"); } else if (typeof autoAcceptResult === "string") { await this.processRequestAction(session, type, false, autoAcceptResult); await this.sendRequestNotification(session, type, "rejected", { reason: autoAcceptResult }); } else { await this.setupManualHandling(session, type, requestKey); } } catch (error) { this.logger.error(`处理请求 ${requestKey} 失败: ${error}`); } } /** * 判断是否应自动接受请求 */ async shouldAutoAccept(session, type) { const validationMessage = session.event?._data?.comment; if (type === "member") { const { MemberRequestAutoRules = [] } = this.config; const rule = MemberRequestAutoRules.find((r) => r.guildId === session.guildId); if (!rule) return false; if (rule.keyword) { try { if (!new RegExp(rule.keyword).test(validationMessage)) return false; } catch (e) { this.logger.warn(`群 ${rule.guildId} 正则无效: ${rule.keyword}`); return false; } } if (rule.minLevel >= 0) { try { const userInfo = await session.onebot.getStrangerInfo(session.userId, false); if (userInfo.level < rule.minLevel) return `QQ 等级低于${rule.minLevel}级`; } catch (error) { return `获取用户信息失败: ${error}`; } } return true; } if (type === "friend") { const { FriendRequestAutoRegex, FriendLevel = -1 } = this.config; if (FriendRequestAutoRegex) { try { if (new RegExp(FriendRequestAutoRegex).test(validationMessage)) return true; } catch (e) { this.logger.warn(`好友申请正则无效: ${FriendRequestAutoRegex}`); } } if (FriendLevel < 0) return false; try { const userInfo = await session.onebot.getStrangerInfo(session.userId, false); if (userInfo.level < FriendLevel) return `QQ 等级低于${FriendLevel}级`; return true; } catch (error) { return `获取用户信息失败: ${error}`; } } if (type === "guild") { const { GuildAllowUsers = [], GuildMinMemberCount = -1, GuildMaxCapacity = -1 } = this.config; if (GuildAllowUsers.includes(session.userId)) return true; let user; try { user = await this.ctx.database.getUser(session.platform, session.userId); } catch { } if (user?.authority > 1) return true; if (GuildMinMemberCount >= 0 || GuildMaxCapacity >= 0) { try { const info = await session.onebot.getGroupInfo(session.guildId, true); if (GuildMinMemberCount >= 0 && info.member_count < GuildMinMemberCount) return `群成员数量不足${GuildMinMemberCount}人`; if (GuildMaxCapacity >= 0 && info.max_member_count < GuildMaxCapacity) return `群最大容量不足${GuildMaxCapacity}人`; return true; } catch (error) { return `获取群信息失败: ${error}`; } } } return false; } /** * 处理请求操作(接受或拒绝) */ async processRequestAction(session, type, approve, reason = "", remark = "") { try { const eventData = session.event?._data || {}; if (!approve && type === "guild" && (session.event?.type === "guild-added" || eventData.notice_type === "group_increase")) { if (reason) { try { await session.bot.sendMessage(session.guildId, `将退出该群 ${reason}`); } catch (error) { this.logger.warn(`发送退群通知失败: ${error}`); } } try { await session.onebot.setGroupLeave(session.guildId, false); return true; } catch (error) { this.logger.error(`退出群组 ${session.guildId} 失败: ${error}`); return false; } } const flag = eventData.flag; if (!flag) return false; if (type === "friend") await session.onebot.setFriendAddRequest(flag, approve, remark); else await session.onebot.setGroupAddRequest(flag, eventData.sub_type ?? "add", approve, approve ? "" : reason); return true; } catch (error) { this.logger.error(`请求处理失败: ${error}`); return false; } } /** * 设置手动处理流程:通知、响应监听和超时回退 */ async setupManualHandling(session, type, requestId) { const requestNumber = this.nextRequestNumber++; this.requestNumberMap.set(requestNumber, requestId); const activeRequest = { session, type, requestNumber }; this.activeRequests.set(requestId, activeRequest); await this.sendRequestNotification(session, type, "pending", { requestNumber }); const timeoutMin = typeof this.config.manualTimeout === "number" ? this.config.manualTimeout : 60; if (timeoutMin > 0) { const timeoutAction = this.config.manualTimeoutAction; activeRequest.timeoutTimer = setTimeout(async () => { const currentRequest = this.activeRequests.get(requestId); if (!currentRequest) return; this.cleanupActiveRequest(requestId); try { await this.processRequestAction(currentRequest.session, currentRequest.type, timeoutAction === "accept", timeoutAction === "reject" ? "请求处理超时,已自动拒绝" : ""); const { notifyTarget: notifyTarget2 = "" } = this.config; if (notifyTarget2) { const [targetType2, targetId2] = notifyTarget2.split(":"); const sendFunc2 = targetType2 === "private" ? (m) => session.bot.sendPrivateMessage(targetId2, m) : (m) => session.bot.sendMessage(targetId2, m); await sendFunc2(`请求 #${requestNumber} 超时,已自动${timeoutAction === "accept" ? "通过" : "拒绝"}`); } } catch (e) { this.logger.error(`请求 #${requestNumber} 超时处理失败: ${e}`); } }, timeoutMin * 60 * 1e3); } const { notifyTarget = "" } = this.config; const [targetType, targetId] = notifyTarget.split(":"); const sendFunc = targetType === "private" ? (m) => session.bot.sendPrivateMessage(targetId, m) : (m) => session.bot.sendMessage(targetId, m); activeRequest.disposer = this.ctx.middleware(async (s, next) => { if (activeRequest.disposer && (targetType === "private" ? s.userId !== targetId : s.guildId !== targetId)) return next(); const bulkMatch = s.content.trim().match(/^(ya|na|全部同意|全部拒绝)\s*(.*)$/); if (bulkMatch && this.activeRequests.size > 0) { const requestsToProcess = [...this.activeRequests.values()]; this.activeRequests.clear(); this.requestNumberMap.clear(); const isApprove2 = bulkMatch[1] === "ya" || bulkMatch[1] === "全部同意"; const extraContent2 = bulkMatch[2]?.trim() || ""; let successCount = 0; for (const req of requestsToProcess) { req.disposer?.(); if (req.timeoutTimer) clearTimeout(req.timeoutTimer); try { const reason = !isApprove2 ? extraContent2 : ""; const remark = isApprove2 && req.type === "friend" ? extraContent2 : ""; await this.processRequestAction(req.session, req.type, isApprove2, reason, remark); successCount++; } catch (error) { this.logger.error(`处理请求 #${req.requestNumber} 失败: ${error}`); } } if (successCount > 0) await sendFunc(`已${isApprove2 ? "通过" : "拒绝"} ${successCount} 个请求${extraContent2 ? `,理由/备注:${extraContent2}` : ""}`); return; } const match = s.content.trim().match(new RegExp(`^(y|n|通过|拒绝)(${requestNumber})\\s*(.*)$`)); if (!match) return next(); this.cleanupActiveRequest(requestId); const isApprove = match[1] === "y" || match[1] === "通过"; const extraContent = match[3]?.trim() || ""; try { await this.processRequestAction(session, type, isApprove, !isApprove ? extraContent : "", isApprove && type === "friend" ? extraContent : ""); await sendFunc(`请求 #${requestNumber} 已${isApprove ? "通过" : "拒绝"}${extraContent ? `,${isApprove ? "备注" : "原因"}:${extraContent}` : ""}`); } catch (error) { this.logger.error(`响应处理失败: ${error}`); await sendFunc(`处理请求 #${requestNumber} 失败: ${error.message}`); } }); } /** * 注册请求类事件监听器 */ registerEventListeners() { if (this.config.enable) { const handleRequest = /* @__PURE__ */ __name((type) => async (session) => { const data = session.event?._data || {}; session.userId = data.user_id?.toString(); if (type !== "friend") session.guildId = data.group_id?.toString(); await this.processRequest(session, type); }, "handleRequest"); this.ctx.on("friend-request", handleRequest("friend")); this.ctx.on("guild-request", handleRequest("guild")); this.ctx.on("guild-member-request", handleRequest("member")); this.ctx.on("guild-added", handleRequest("guild")); } } }; // src/listener.ts var OneBotListener = class { /** * 创建 OneBot 通知监听实例 * @param ctx - Koishi 上下文 * @param logger - 日志记录器 * @param config - 配置项 */ constructor(ctx, logger, config = {}) { this.ctx = ctx; this.logger = logger; this.config = config; } static { __name(this, "OneBotListener"); } /** * 发送群成员变动通知 (入群/退群) */ async sendGuildMemberUpdateMessage(session, messageTemplate) { if (!messageTemplate || !messageTemplate.trim()) return; try { const user = await session.bot.getUser(session.userId).catch(() => null); const guild = await session.bot.getGuild(session.guildId).catch(() => null); const replacements = { "{userName}": user?.name || session.userId, "{userId}": session.userId, "{guildName}": guild?.name || session.guildId, "{guildId}": session.guildId }; const regex = new RegExp(Object.keys(replacements).join("|"), "g"); const message = messageTemplate.replace(regex, (match) => replacements[match]); if (!message.trim()) return; if (this.config.redirectMsg && this.config.notifyTarget) { const [targetType, targetId] = this.config.notifyTarget.split(":"); if (!targetId || targetType !== "guild" && targetType !== "private") { this.logger.warn(`通知目标错误: ${this.config.notifyTarget}`); await session.bot.sendMessage(session.guildId, message); } else { const sendFunc = targetType === "private" ? (m) => session.bot.sendPrivateMessage(targetId, m) : (m) => session.bot.sendMessage(targetId, m); await sendFunc(message); } } else { await session.bot.sendMessage(session.guildId, message); } } catch (error) { this.logger.error("发送群成员变动通知失败:", error); } } /** * 处理机器人被踢或主动退群事件 */ async handleBotRemoved(session) { const { notifyTarget = "" } = this.config; if (!notifyTarget) return; const [targetType, targetId] = notifyTarget.split(":"); if (!targetId || targetType !== "guild" && targetType !== "private") { this.logger.warn(`通知目标错误: ${notifyTarget}`); return; } try { const subType = session.event?._data?.sub_type; const operatorId = session.event.operator?.id || session.event?._data?.operator_id; const guildId = session.guildId; const guild = await session.bot.getGuild(guildId).catch(() => null); const guildIdentifier = guild?.name ? `${guild.name}(${guildId})` : guildId; let msg = ""; if (subType === "kick_me" && operatorId) { const operator = await session.bot.getUser(operatorId.toString()).catch(() => null); const operatorIdentifier = operator?.name ? `${operator.name}(${operatorId})` : operatorId; msg = `已被 ${operatorIdentifier} 踢出 ${guildIdentifier}`; } else { msg = `已退出 ${guildIdentifier}`; } const sendFunc = targetType === "private" ? (m) => session.bot.sendPrivateMessage(targetId, m) : (m) => session.bot.sendMessage(targetId, m); await sendFunc(msg); } catch (error) { this.logger.error(`发送被踢/退群通知失败:`, error); } } /** * 处理群内管理员变动事件,并发送到 notifyTarget */ async handleAdminChange(session) { if (session.event?.platform !== "onebot" || session.event?.subtype !== "role" || session.event?._data?.notice_type !== "group_admin") return; const { notifyTarget = "" } = this.config; if (!notifyTarget) return; const [targetType, targetId] = notifyTarget.split(":"); if (!targetId || targetType !== "guild" && targetType !== "private") { this.logger.warn(`通知目标错误: ${notifyTarget}`); return; } try { const eventData = session.event._data; const subType = eventData.sub_type; const changedUserId = eventData.user_id?.toString(); const guildId = eventData.group_id?.toString(); if (!changedUserId || !guildId) return; const [targetUser, guild] = await Promise.all([ session.bot.getUser(changedUserId).catch(() => ({ name: changedUserId })), session.bot.getGuild(guildId).catch(() => ({ name: guildId })) ]); const targetIdentifier = targetUser.name && targetUser.name !== changedUserId ? `${targetUser.name}(${changedUserId})` : changedUserId; const guildIdentifier = guild.name && guild.name !== guildId ? `${guild.name}(${guildId})` : guildId; const actionText = subType === "set" ? "设置为" : "取消了"; const message = `${targetIdentifier} 已被${actionText} ${guildIdentifier} 的管理员`; const sendFunc = targetType === "private" ? (m) => session.bot.sendPrivateMessage(targetId, m) : (m) => session.bot.sendMessage(targetId, m); await sendFunc(message); } catch (error) { this.logger.error("发送管理员变动通知失败:", error); } } /** * 注册所有通知类事件监听器 */ registerEventListeners() { if (this.config.enableJoin) { this.ctx.on("guild-member-added", (session) => this.sendGuildMemberUpdateMessage(session, this.config.joinMessage)); } if (this.config.enableLeave) { this.ctx.on("guild-member-removed", (session) => this.sendGuildMemberUpdateMessage(session, this.config.leaveMessage)); } if (this.config.enableKick) { this.ctx.on("guild-removed", this.handleBotRemoved.bind(this)); } if (this.config.enableAdmin) { this.ctx.on("guild-member", this.handleAdminChange.bind(this)); } } }; // src/utils.ts var import_koishi = require("koishi"); var ROLE_MAP = { owner: "群主", admin: "管理员", member: "成员" }; var getRoleName = /* @__PURE__ */ __name((role) => ROLE_MAP[role] || role || "未知", "getRoleName"); var utils = { /** * 解析目标字符串,返回QQ号或null */ parseTarget(target) { if (!target) return null; try { const at = import_koishi.h.select(import_koishi.h.parse(target), "at")[0]?.attrs?.id; if (at && !isNaN(Number(at))) return at; const match = target.match(/@?(\d{5,10})/)?.[1]; return match && !isNaN(Number(match)) ? match : null; } catch { return null; } }, /** * 处理错误并发送提示消息 */ handleError(session, error) { const errorMsg = error?.message || String(error); return session.send(errorMsg).then((msg) => { if (typeof msg === "string") setTimeout(() => session.bot.deleteMessage(session.channelId, msg).catch(() => { }), 1e4); return null; }); }, /** * 检查机器人和用户在指定群内的权限角色 */ async checkPermission(session, groupId, logger) { if (!groupId) return { bot: null, user: null }; try { const [bot, user] = await Promise.all([ session.onebot.getGroupMemberInfo(groupId, +session.selfId, true), session.onebot.getGroupMemberInfo(groupId, +session.userId, true) ]); return { bot: bot?.role ?? null, user: user?.role ?? null }; } catch (e) { logger?.error("获取群成员信息失败:", e); return { bot: null, user: null }; } }, /** * 包装函数,执行前检查机器人和用户的群权限 */ withRoleCheck(session, groupId, logger, requiredBotRoles = [], requiredUserRoles = [], commandWhitelist = [], fn) { return (...args) => utils.checkPermission(session, groupId, logger).then(({ bot, user }) => { const errors = []; if (requiredBotRoles.length && (!bot || !requiredBotRoles.includes(bot))) { errors.push(`需要${requiredBotRoles.map(getRoleName).join("或")}(当前为${getRoleName(bot)})`); } const isWhitelisted = commandWhitelist.includes(session.userId); if (!isWhitelisted && requiredUserRoles.length && (!user || !requiredUserRoles.includes(user))) { errors.push(`用户需要${requiredUserRoles.map(getRoleName).join("或")}(当前为${getRoleName(user)})`); } if (errors.length) return utils.handleError(session, `权限不足:${errors.join(";")}`); return fn(...args); }); } }; // src/command.ts function getTitleLen(title) { return Array.from(title).reduce((len, char) => { const code = char.codePointAt(0); if (code && (code >= 126976 && code <= 131071 || code >= 9728 && code <= 9983 || code >= 9984 && code <= 10175 || code === 12349 || code === 8265 || code === 8252 || code === 8505 || code >= 8192 && code <= 8207 || code >= 8232 && code <= 8239 || code === 8287 || code >= 8293 && code <= 8303 || code >= 8400 && code <= 8447 || code >= 8448 && code <= 8527 || code >= 8960 && code <= 9215 || code >= 11008 && code <= 11263 || code >= 10496 && code <= 10623 || code >= 12800 && code <= 13055 || code >= 55296 && code <= 57343 || code >= 65024 && code <= 65039 || code >= 65520 && code <= 65535)) { return len + 6; } if (code && code >= 32 && code <= 126) { return len + 1; } return len + 3; }, 0); } __name(getTitleLen, "getTitleLen"); function getGroupId(options, session) { const groupId = options.group ? Number(options.group) : Number(session.guildId); if (isNaN(groupId) || groupId <= 0) throw new Error("无效或未指定群号"); return groupId; } __name(getGroupId, "getGroupId"); function getTargetId(target, session, utils2) { if (!target) return session.userId; const parsed = utils2.parseTarget(target); return parsed; } __name(getTargetId, "getTargetId"); function createGroupCommand(utils2, logger, botRoles, userRoles, commandWhitelist, actionFn) { return ({ session, options }, ...args) => { try { const groupId = getGroupId(options, session); const action = /* @__PURE__ */ __name(() => actionFn(session, options, groupId, ...args), "action"); return utils2.withRoleCheck(session, groupId, logger, botRoles, userRoles, commandWhitelist, action)(); } catch (error) { return utils2.handleError(session, error); } }; } __name(createGroupCommand, "createGroupCommand"); function adminAction(set, utils2, logger, commandWhitelist) { return createGroupCommand( utils2, logger, ["owner"], ["owner", "admin"], commandWhitelist, async (session, options, groupId, target) => { if (!target) return "请指定成员"; const targetId = utils2.parseTarget(target); if (!targetId) return "无效的成员ID"; await session.onebot.setGroupAdmin(groupId, Number(targetId), set); return set ? `已设置成员 ${targetId} 为管理` : `已取消成员 ${targetId} 的管理`; } ); } __name(adminAction, "adminAction"); function registerCommands(qgroup, logger, utils2, commandWhitelist) { qgroup.subcommand("tag [title:string] [target]", "设置专属头衔").option("group", "-g, --group <groupId> 指定群号").usage("设置或清除指定成员的群头衔\n使用引号添加不连续的内容,最多18字符\n英文(标点)和数字1字符,中文和其他符号3字符,Emoji6字符").action(async ({ session, options }, title = "", target) => { try { const groupId = getGroupId(options, session); if (title && getTitleLen(title) > 18) return "设置头衔失败: 长度超过18字符"; const targetId = getTargetId(target, session, utils2); if (targetId === "无效成员") return targetId; const requiredBotRoles = ["owner"]; const requiredUserRoles = target && targetId !== session.userId ? ["owner", "admin"] : []; const actionFn = /* @__PURE__ */ __name(async () => { await session.onebot.setGroupSpecialTitle(groupId, Number(targetId), title); return `已${title ? "将" : "清除"}${targetId === session.userId ? "您" : `用户 ${targetId}`} 的头衔${title ? `设置为:${title}` : ""}`; }, "actionFn"); return utils2.withRoleCheck(session, groupId, logger, requiredBotRoles, requiredUserRoles, commandWhitelist, actionFn)(); } catch (error) { return utils2.handleError(session, error); } }); qgroup.subcommand("membercard [card:string] [target]", "设置群名片").option("group", "-g, --group <groupId> 指定群号").usage("设置或清除指定成员的群名片").action(async ({ session, options }, card = "", target) => { try { const groupId = getGroupId(options, session); const targetId = getTargetId(target, session, utils2); if (targetId === "无效成员") return targetId; const isTargetingSelf = targetId === session.userId; const isTargetingBot = targetId === session.selfId; if (isTargetingSelf) { await session.onebot.setGroupCard(groupId, Number(targetId), card); return `已${card ? "将" : "清除"}您的群名片${card ? `设置为:${card}` : ""}`; } const requiredUserRoles = ["owner", "admin"]; const requiredBotRoles = isTargetingBot ? [] : ["owner", "admin"]; const actionFn = /* @__PURE__ */ __name(async () => { await session.onebot.setGroupCard(groupId, Number(targetId), card); return `已${card ? "将" : "清除"}用户 ${targetId} 的群名片${card ? `设置为:${card}` : ""}`; }, "actionFn"); return utils2.withRoleCheck(session, groupId, logger, requiredBotRoles, requiredUserRoles, commandWhitelist, actionFn)(); } catch (error) { return utils2.handleError(session, error); } }); qgroup.subcommand("groupname <group_name:string>", "设置群名称").option("group", "-g, --group <groupId> 指定群号").usage("设置当前群的名称").action(createGroupCommand( utils2, logger, ["owner", "admin"], ["owner", "admin"], commandWhitelist, async (session, options, groupId, group_name) => { if (!group_name) return "请输入群名"; await session.onebot.setGroupName(groupId, group_name); return `已将群名设置为:${group_name}`; } )); const essenceAction = /* @__PURE__ */ __name((del = false) => createGroupCommand( utils2, logger, ["owner", "admin"], ["owner", "admin"], commandWhitelist, async (session, options, groupId, messageId) => { const targetMessageId = session.quote?.id || messageId; if (!targetMessageId) return "请提供消息ID或引用消息"; if (del) { await session.onebot.deleteEssenceMsg(targetMessageId); return "已移除精华消息"; } await session.onebot.setEssenceMsg(targetMessageId); return "已设置精华消息"; } ), "essenceAction"); const essence = qgroup.subcommand("essence [messageId:string]", "设置精华消息").option("group", "-g, --group <groupId> 指定群号").usage("在指定群设置精华消息 (权限检查将在目标群进行)").action(essenceAction(false)); essence.subcommand(".del [messageId:string]", "移除精华消息").option("group", "-g, --group <groupId> 指定群号").usage("在指定群移除精华消息 (权限检查将在目标群进行)").action(essenceAction(true)); const admin = qgroup.subcommand("admin <target>", "设置群管理").option("group", "-g, --group <groupId> 指定群号").usage("设置指定成员为群管理").action(adminAction(true, utils2, logger, commandWhitelist)); admin.subcommand(".del <target>", "取消群管理").option("group", "-g, --group <groupId> 指定群号").usage("取消指定成员的群管理").action(adminAction(false, utils2, logger, commandWhitelist)); const mute = qgroup.subcommand("mute <target> [duration]", "禁言群成员").option("cancel", "-c, --cancel 取消禁言").option("group", "-g, --group <groupId> 指定群号").usage("禁言指定成员,默认 30 分钟,最长 30 天").action(createGroupCommand( utils2, logger, ["owner", "admin"], ["owner", "admin"], commandWhitelist, async (session, options, groupId, target, duration) => { const targetId = utils2.parseTarget(target); if (!targetId) return "请指定有效成员"; const banDuration = options.cancel ? 0 : duration ? Number(duration) : 1800; if (banDuration > 2591999) return `操作失败:禁言时长不能超过 30 天`; await session.onebot.setGroupBan(groupId, Number(targetId), banDuration); return options.cancel ? `已取消禁言成员 ${targetId}` : `已禁言成员 ${targetId} ${banDuration} 秒`; } )); mute.subcommand(".all [enable:boolean]", "全体禁言").option("group", "-g, --group <groupId> 指定群号").usage("开启或关闭全体禁言").action(createGroupCommand( utils2, logger, ["owner", "admin"], ["owner", "admin"], commandWhitelist, async (session, options, groupId, enable) => { const val = typeof enable === "boolean" ? enable : true; await session.onebot.setGroupWholeBan(groupId, val); return val ? "已开启全体禁言" : "已关闭全体禁言"; } )); qgroup.subcommand("kick <target>", "逐出群成员").option("reject", "-r, --reject 拒绝再次加群").option("group", "-g, --group <groupId> 指定群号").usage("逐出指定成员,使用 -r 拒绝此人再次加群").action(createGroupCommand( utils2, logger, ["owner", "admin"], ["owner", "admin"], commandWhitelist, async (session, options, groupId, target) => { const targetId = utils2.parseTarget(target); if (!targetId) return "请指定有效的成员"; await session.onebot.setGroupKick(groupId, Number(targetId), !!options.reject); return `已将成员 ${targetId} 逐出群${options.reject ? ",并拒绝其再次加群" : ""}`; } )); qgroup.subcommand("revoke", "撤回消息").usage("回复指定消息来撤回对应内容。").action(async ({ session }) => { const quote = session.quote; if (!quote?.id) return "请回复需要撤回的消息"; try { const isWhitelisted = commandWhitelist.includes(session.userId); if (isWhitelisted) { await session.onebot.deleteMsg(quote.id); return; } const { user: userRole } = await utils2.checkPermission(session, session.guildId, logger); if (userRole !== "member" || quote.user?.id === session.userId || quote.user?.id === session.selfId) { await session.onebot.deleteMsg(quote.id); } else { return utils2.handleError(session, "仅管理员可撤回他人消息"); } } catch (error) { return utils2.handleError(session, error); } }); } __name(registerCommands, "registerCommands"); // src/index.ts var name = "onebot-manager"; var inject = { optional: ["database"] }; var usage = ` <div style="border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);"> <h2 style="margin-top: 0; color: #4a6ee0;">📌 插件说明</h2> <p>📖 <strong>使用文档</strong>:请点击左上角的 <strong>插件主页</strong> 查看插件使用文档</p> <p>🔍 <strong>更多插件</strong>:可访问 <a href="https://github.com/YisRime" style="color:#4a6ee0;text-decoration:none;">苡淞的 GitHub</a> 查看本人的所有插件</p> </div> <div style="border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);"> <h2 style="margin-top: 0; color: #e0574a;">❤️ 支持与反馈</h2> <p>🌟 喜欢这个插件?请在 <a href="https://github.com/YisRime" style="color:#e0574a;text-decoration:none;">GitHub</a> 上给我一个 Star!</p> <p>🐛 遇到问题?请通过 <strong>Issues</strong> 提交反馈,或加入 QQ 群 <a href="https://qm.qq.com/q/PdLMx9Jowq" style="color:#e0574a;text-decoration:none;"><strong>855571375</strong></a> 进行交流</p> </div> `; var Config = import_koishi2.Schema.intersect([ import_koishi2.Schema.object({ enableKick: import_koishi2.Schema.boolean().description("开启被踢监听").default(true), enableAdmin: import_koishi2.Schema.boolean().description("开启管理监听").default(true), notifyTarget: import_koishi2.Schema.string().description("通知目标(guild/private:number)").required(), enableJoin: import_koishi2.Schema.boolean().description("开启入群监听").default(false), enableLeave: import_koishi2.Schema.boolean().description("开启退群监听").default(false), redirectMsg: import_koishi2.Schema.boolean().description("汇总变动通知").default(false), joinMessage: import_koishi2.Schema.string().default("{userName} 加入了本群").description("进群提示"), leaveMessage: import_koishi2.Schema.string().default("{userName} 离开了本群").description("退群提示") }).description("监听配置"), import_koishi2.Schema.object({ enable: import_koishi2.Schema.boolean().description("开启请求监听").default(true), manualTimeout: import_koishi2.Schema.number().description("请求超时时长").default(360).min(0), manualTimeoutAction: import_koishi2.Schema.union([ import_koishi2.Schema.const("accept").description("同意"), import_koishi2.Schema.const("reject").description("拒绝") ]).description("默认超时操作").default("accept"), FriendLevel: import_koishi2.Schema.number().description("最低好友等级").default(-1).min(-1).max(256), GuildMinMemberCount: import_koishi2.Schema.number().description("最低群成员数").default(-1).min(-1).max(3e3), GuildMaxCapacity: import_koishi2.Schema.number().description("最低受邀容量").default(-1).min(-1).max(3e3), FriendRequestAutoRegex: import_koishi2.Schema.string().description("好友验证正则"), MemberRequestAutoRules: import_koishi2.Schema.array(import_koishi2.Schema.object({ guildId: import_koishi2.Schema.string().description("群号"), keyword: import_koishi2.Schema.string().description("正则"), minLevel: import_koishi2.Schema.number().description("等级").default(-1) })).description("加群验证规则").role("table"), GuildAllowUsers: import_koishi2.Schema.array(String).description("额外邀请加群白名单").role("table") }).description("请求配置"), import_koishi2.Schema.object({ commandWhitelist: import_koishi2.Schema.array(String).description("额外命令使用白名单").role("table") }).description("命令配置") ]); function apply(ctx, config = {}) { const logger = ctx.logger("onebot-manager"); new OnebotRequest(ctx, logger, config).registerEventListeners(); new OneBotListener(ctx, logger, config).registerEventListeners(); const qgroup = ctx.command("qgroup", "QQ 群管").usage("群管相关功能,需要管理权限"); registerCommands(qgroup, logger, utils, config.commandWhitelist || []); } __name(apply, "apply"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Config, apply, inject, name, usage });