koishi-plugin-onebot-manager
Version:
提供群管命令,可基于规则自动处理好友/加群/邀请请求,且能监听管理/进群/退群事件
754 lines (747 loc) • 37 kB
JavaScript
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
});