koishi-plugin-onebot-group-manage 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +24 -0
- package/lib/index.js +224 -0
- package/package.json +20 -0
- package/readme.md +5 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Context, Schema } from 'koishi';
|
|
2
|
+
export declare const name = "onebot-group-manage";
|
|
3
|
+
interface ActionRule {
|
|
4
|
+
requireGroupAdmin: boolean;
|
|
5
|
+
minAuthority: number;
|
|
6
|
+
}
|
|
7
|
+
interface DebugOptions {
|
|
8
|
+
verbose: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface SelfMuteConfig {
|
|
11
|
+
minSeconds: number;
|
|
12
|
+
maxSeconds: number;
|
|
13
|
+
}
|
|
14
|
+
export interface Config {
|
|
15
|
+
mute: ActionRule;
|
|
16
|
+
unmute: ActionRule;
|
|
17
|
+
kick: ActionRule;
|
|
18
|
+
title: ActionRule;
|
|
19
|
+
selfMute: SelfMuteConfig;
|
|
20
|
+
debug?: DebugOptions;
|
|
21
|
+
}
|
|
22
|
+
export declare const Config: Schema<Config>;
|
|
23
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
24
|
+
export {};
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name2 in all)
|
|
8
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
Config: () => Config,
|
|
24
|
+
apply: () => apply,
|
|
25
|
+
name: () => name
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(src_exports);
|
|
28
|
+
var import_koishi = require("koishi");
|
|
29
|
+
var name = "onebot-group-manage";
|
|
30
|
+
var ROLE_CACHE_TTL = 3e4;
|
|
31
|
+
var ROLE_QUERY_TIMEOUT = 1e4;
|
|
32
|
+
var roleCache = /* @__PURE__ */ new Map();
|
|
33
|
+
var actionSchema = import_koishi.Schema.object({
|
|
34
|
+
requireGroupAdmin: import_koishi.Schema.boolean().default(true).description("调用者必须是群管/群主"),
|
|
35
|
+
minAuthority: import_koishi.Schema.number().min(0).default(1).description("调用者最低 Koishi 权限,0 表示不校验")
|
|
36
|
+
});
|
|
37
|
+
var Config = import_koishi.Schema.object({
|
|
38
|
+
mute: actionSchema.description("禁言配置"),
|
|
39
|
+
unmute: actionSchema.description("解禁配置"),
|
|
40
|
+
kick: actionSchema.description("踢人配置"),
|
|
41
|
+
title: actionSchema.description("头衔配置"),
|
|
42
|
+
selfMute: import_koishi.Schema.object({
|
|
43
|
+
minSeconds: import_koishi.Schema.number().min(1).default(60).description("随机禁言最小秒数"),
|
|
44
|
+
maxSeconds: import_koishi.Schema.number().min(1).default(600).description("随机禁言最大秒数")
|
|
45
|
+
}).description("禁言我配置"),
|
|
46
|
+
debug: import_koishi.Schema.object({
|
|
47
|
+
verbose: import_koishi.Schema.boolean().default(false)
|
|
48
|
+
}).default({ verbose: false })
|
|
49
|
+
});
|
|
50
|
+
function withTimeout(p, ms) {
|
|
51
|
+
return Promise.race([
|
|
52
|
+
p,
|
|
53
|
+
new Promise((_, r) => setTimeout(() => r(new Error(`timeout ${ms}ms`)), ms))
|
|
54
|
+
]);
|
|
55
|
+
}
|
|
56
|
+
__name(withTimeout, "withTimeout");
|
|
57
|
+
function getBotOnebot(bot) {
|
|
58
|
+
return bot?.onebot || bot?.internal?.onebot || bot?.internal || null;
|
|
59
|
+
}
|
|
60
|
+
__name(getBotOnebot, "getBotOnebot");
|
|
61
|
+
function randomInt(min, max) {
|
|
62
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
63
|
+
}
|
|
64
|
+
__name(randomInt, "randomInt");
|
|
65
|
+
async function getMemberRole(probe, bot, guildId, userId, logger, verbose) {
|
|
66
|
+
const key = `${bot.selfId}:${guildId}:${userId}`;
|
|
67
|
+
const cached = roleCache.get(key);
|
|
68
|
+
if (cached && cached.expire > Date.now()) return cached.role;
|
|
69
|
+
try {
|
|
70
|
+
const info = await withTimeout(
|
|
71
|
+
probe.getGroupMemberInfo(Number(guildId), Number(userId), false),
|
|
72
|
+
ROLE_QUERY_TIMEOUT
|
|
73
|
+
);
|
|
74
|
+
const role = info?.role ?? null;
|
|
75
|
+
if (role) roleCache.set(key, { role, expire: Date.now() + ROLE_CACHE_TTL });
|
|
76
|
+
return role;
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
__name(getMemberRole, "getMemberRole");
|
|
82
|
+
async function verifyCaller(session, rule) {
|
|
83
|
+
const authority = Number(session.user?.authority ?? 0);
|
|
84
|
+
if (!rule.requireGroupAdmin && rule.minAuthority <= 0) return null;
|
|
85
|
+
if (rule.minAuthority > 0 && authority >= rule.minAuthority) return null;
|
|
86
|
+
if (rule.requireGroupAdmin && session.guildId) {
|
|
87
|
+
const probe = session.onebot || getBotOnebot(session.bot);
|
|
88
|
+
const role = await getMemberRole(
|
|
89
|
+
probe,
|
|
90
|
+
session.bot,
|
|
91
|
+
session.guildId,
|
|
92
|
+
session.userId
|
|
93
|
+
);
|
|
94
|
+
if (role === "owner" || role === "admin") return null;
|
|
95
|
+
}
|
|
96
|
+
if (rule.requireGroupAdmin && rule.minAuthority > 0) {
|
|
97
|
+
return `需要群管/群主或 Koishi≥${rule.minAuthority}`;
|
|
98
|
+
}
|
|
99
|
+
if (rule.requireGroupAdmin) return "需要群管或群主权限";
|
|
100
|
+
return `需要 Koishi≥${rule.minAuthority}`;
|
|
101
|
+
}
|
|
102
|
+
__name(verifyCaller, "verifyCaller");
|
|
103
|
+
function parseTargetId(raw, session) {
|
|
104
|
+
if (raw) {
|
|
105
|
+
const segs = import_koishi.segment.parse(raw);
|
|
106
|
+
const at = segs.find((s) => s.type === "at" && s.attrs?.id);
|
|
107
|
+
if (at) return String(at.attrs.id);
|
|
108
|
+
const m = raw.match(/\d{5,}/);
|
|
109
|
+
if (m) return m[0];
|
|
110
|
+
}
|
|
111
|
+
return session.quote?.user?.id || null;
|
|
112
|
+
}
|
|
113
|
+
__name(parseTargetId, "parseTargetId");
|
|
114
|
+
async function pickManageBot(ctx, guildId, requireOwner, preferBot) {
|
|
115
|
+
const bots = ctx.bots.filter((b) => b.platform === "onebot");
|
|
116
|
+
const probe = getBotOnebot(preferBot || bots[0]);
|
|
117
|
+
if (!probe) return null;
|
|
118
|
+
for (const bot of bots) {
|
|
119
|
+
const role = await getMemberRole(probe, bot, guildId, bot.selfId);
|
|
120
|
+
if (requireOwner ? role === "owner" : role === "owner" || role === "admin") {
|
|
121
|
+
return { bot, probe };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
__name(pickManageBot, "pickManageBot");
|
|
127
|
+
function apply(ctx, config) {
|
|
128
|
+
ctx.command("group.manage", "OneBot 群管理").channelFields(["platform"]);
|
|
129
|
+
ctx.command("group.manage/mute <target:string> <duration:number>", "禁言").alias("gmute").action(async ({ session }, target, duration) => {
|
|
130
|
+
if (!session?.guildId) return "仅限群聊";
|
|
131
|
+
const deny = await verifyCaller(session, config.mute);
|
|
132
|
+
if (deny) return deny;
|
|
133
|
+
const uid = parseTargetId(target, session);
|
|
134
|
+
if (!uid || duration <= 0) return "参数错误";
|
|
135
|
+
const picked = await pickManageBot(ctx, session.guildId, false, session.bot);
|
|
136
|
+
if (!picked) return "无可用群管 Bot";
|
|
137
|
+
const role = await getMemberRole(picked.probe, picked.bot, session.guildId, uid);
|
|
138
|
+
if (role === "owner") return "不能禁言群主";
|
|
139
|
+
await picked.probe.setGroupBan(Number(session.guildId), Number(uid), duration);
|
|
140
|
+
roleCache.clear();
|
|
141
|
+
return `已禁言 ${uid} ${duration} 秒`;
|
|
142
|
+
});
|
|
143
|
+
ctx.command("group.manage/unmute <target:string>", "解禁").alias("gunmute").action(async ({ session }, target) => {
|
|
144
|
+
if (!session?.guildId) return "仅限群聊";
|
|
145
|
+
const deny = await verifyCaller(session, config.unmute);
|
|
146
|
+
if (deny) return deny;
|
|
147
|
+
const uid = parseTargetId(target, session);
|
|
148
|
+
if (!uid) return "参数错误";
|
|
149
|
+
const picked = await pickManageBot(ctx, session.guildId, false, session.bot);
|
|
150
|
+
if (!picked) return "无可用群管 Bot";
|
|
151
|
+
await picked.probe.setGroupBan(Number(session.guildId), Number(uid), 0);
|
|
152
|
+
roleCache.clear();
|
|
153
|
+
return `已解禁 ${uid}`;
|
|
154
|
+
});
|
|
155
|
+
ctx.command("group.manage/kick <target:string>", "踢人").alias("gkick").action(async ({ session }, target) => {
|
|
156
|
+
if (!session?.guildId) return "仅限群聊";
|
|
157
|
+
const deny = await verifyCaller(session, config.kick);
|
|
158
|
+
if (deny) return deny;
|
|
159
|
+
const uid = parseTargetId(target, session);
|
|
160
|
+
if (!uid) return "参数错误";
|
|
161
|
+
const picked = await pickManageBot(ctx, session.guildId, false, session.bot);
|
|
162
|
+
if (!picked) return "无可用群管 Bot";
|
|
163
|
+
const role = await getMemberRole(picked.probe, picked.bot, session.guildId, uid);
|
|
164
|
+
if (role === "owner") return "不能踢群主";
|
|
165
|
+
await picked.probe.setGroupKick(Number(session.guildId), Number(uid), false);
|
|
166
|
+
roleCache.clear();
|
|
167
|
+
return `已踢出 ${uid}`;
|
|
168
|
+
});
|
|
169
|
+
ctx.command("group.manage/title <target:string> <title:text>", "设置头衔").alias("gtitle").action(async ({ session }, target, title) => {
|
|
170
|
+
if (!session?.guildId) return "仅限群聊";
|
|
171
|
+
const deny = await verifyCaller(session, config.title);
|
|
172
|
+
if (deny) return deny;
|
|
173
|
+
const uid = parseTargetId(target, session);
|
|
174
|
+
if (!uid) return "参数错误";
|
|
175
|
+
const picked = await pickManageBot(ctx, session.guildId, true, session.bot);
|
|
176
|
+
if (!picked) return "无群主 Bot";
|
|
177
|
+
await picked.probe.setGroupSpecialTitle(
|
|
178
|
+
Number(session.guildId),
|
|
179
|
+
Number(uid),
|
|
180
|
+
title.trim(),
|
|
181
|
+
-1
|
|
182
|
+
);
|
|
183
|
+
roleCache.clear();
|
|
184
|
+
return `已设置头衔`;
|
|
185
|
+
});
|
|
186
|
+
ctx.command("group.manage/mute.me", "禁言我").alias("gmute.me").action(async ({ session }) => {
|
|
187
|
+
if (!session?.guildId) return "仅限群聊";
|
|
188
|
+
const deny = await verifyCaller(session, config.mute);
|
|
189
|
+
if (deny) return deny;
|
|
190
|
+
const { minSeconds, maxSeconds } = config.selfMute;
|
|
191
|
+
const seconds = randomInt(minSeconds, maxSeconds);
|
|
192
|
+
const picked = await pickManageBot(ctx, session.guildId, false, session.bot);
|
|
193
|
+
if (!picked) return "无可用群管 Bot";
|
|
194
|
+
await picked.probe.setGroupBan(
|
|
195
|
+
Number(session.guildId),
|
|
196
|
+
Number(session.userId),
|
|
197
|
+
seconds
|
|
198
|
+
);
|
|
199
|
+
roleCache.clear();
|
|
200
|
+
return `你被禁言 ${seconds} 秒`;
|
|
201
|
+
});
|
|
202
|
+
ctx.command("group.manage/title.apply <title:text>", "申请群头衔").alias("gtitle.apply").action(async ({ session }, title) => {
|
|
203
|
+
if (!session?.guildId) return "仅限群聊";
|
|
204
|
+
const deny = await verifyCaller(session, config.title);
|
|
205
|
+
if (deny) return deny;
|
|
206
|
+
const picked = await pickManageBot(ctx, session.guildId, true, session.bot);
|
|
207
|
+
if (!picked) return "无群主 Bot";
|
|
208
|
+
await picked.probe.setGroupSpecialTitle(
|
|
209
|
+
Number(session.guildId),
|
|
210
|
+
Number(session.userId),
|
|
211
|
+
title.trim(),
|
|
212
|
+
-1
|
|
213
|
+
);
|
|
214
|
+
roleCache.clear();
|
|
215
|
+
return `你的头衔已设置为:${title}`;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
__name(apply, "apply");
|
|
219
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
220
|
+
0 && (module.exports = {
|
|
221
|
+
Config,
|
|
222
|
+
apply,
|
|
223
|
+
name
|
|
224
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-onebot-group-manage",
|
|
3
|
+
"description": "主要针对多bot环境的群管插件,自动使用有权限的bot",
|
|
4
|
+
"version": "0.0.2",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"typings": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"chatbot",
|
|
14
|
+
"koishi",
|
|
15
|
+
"plugin"
|
|
16
|
+
],
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"koishi": "^4.18.7"
|
|
19
|
+
}
|
|
20
|
+
}
|