koishi-plugin-group-control 0.2.4 → 0.2.6

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.
Files changed (2) hide show
  1. package/lib/index.js +85 -146
  2. package/package.json +2 -2
package/lib/index.js CHANGED
@@ -141,31 +141,36 @@ function apply(ctx, config) {
141
141
  if (config.invite.enabled) {
142
142
  const pendingInvites = /* @__PURE__ */ new Map();
143
143
  ctx.on("guild-request", async (session) => {
144
- const { guildId, userId, platform } = session;
145
144
  const raw = session.original || session.raw || session.event?._data || {};
146
145
  const flag = raw.flag || session.flag || session.messageId;
146
+ const rawUserId = raw.user_id ? String(raw.user_id) : session.userId;
147
+ const rawGroupId = raw.group_id ? String(raw.group_id) : session.guildId;
148
+ const { platform } = session;
147
149
  if (!flag && config.invite.showDetailedLog) {
148
150
  console.warn("Group Control: 未能提取到邀请 flag,可能导致无法处理邀请。Raw event:", JSON.stringify(raw));
149
151
  }
150
- let userName = userId;
152
+ if (config.invite.showDetailedLog) {
153
+ console.log(`收到群邀请事件 - 原始数据: UserID=${raw.user_id}, GroupID=${raw.group_id}, Flag=${flag}`);
154
+ }
155
+ let userName = rawUserId;
151
156
  try {
152
- const userInfo = await session.bot.getUser(userId);
153
- userName = userInfo?.nickname || userInfo?.name || userId;
157
+ const userInfo = await session.bot.getUser(rawUserId);
158
+ userName = userInfo?.nickname || userInfo?.name || rawUserId;
154
159
  } catch (error) {
155
160
  console.error("获取用户信息失败:", error);
156
161
  }
157
- let groupName = guildId;
162
+ let groupName = rawGroupId;
158
163
  try {
159
- const guildInfo = await session.bot.getGuild(guildId);
160
- groupName = guildInfo?.name || guildInfo?.group_name || guildId;
164
+ const guildInfo = await session.bot.getGuild(rawGroupId);
165
+ groupName = guildInfo?.name || guildInfo?.group_name || rawGroupId;
161
166
  } catch (error) {
162
167
  console.error("获取群信息失败:", error);
163
168
  }
164
169
  try {
165
- const waitMessage = config.invite.inviteWaitMessage.replace("{groupName}", groupName).replace("{groupId}", guildId).replace("{userName}", userName).replace("{userId}", userId);
166
- await session.bot.sendPrivateMessage(userId, waitMessage);
170
+ const waitMessage = config.invite.inviteWaitMessage.replace("{groupName}", groupName).replace("{groupId}", rawGroupId).replace("{userName}", userName).replace("{userId}", rawUserId);
171
+ await session.bot.sendPrivateMessage(rawUserId, waitMessage);
167
172
  } catch (error) {
168
- console.error("发送等待审核提示失败:", error);
173
+ console.error(`发送等待审核提示给 ${rawUserId} 失败:`, error);
169
174
  }
170
175
  if (!config.invite.adminQQs || config.invite.adminQQs.length === 0) {
171
176
  if (config.invite.autoApprove) {
@@ -177,34 +182,30 @@ function apply(ctx, config) {
177
182
  reason: ""
178
183
  });
179
184
  if (config.invite.showDetailedLog) {
180
- console.log(`自动同意群聊邀请: 群号 ${guildId}, 邀请者 ${userId}`);
185
+ console.log(`自动同意群聊邀请: 群号 ${rawGroupId}, 邀请者 ${rawUserId}`);
181
186
  }
182
187
  } catch (error) {
183
188
  console.error("自动同意群聊邀请失败:", error);
184
189
  }
185
- } else {
186
- if (config.invite.showDetailedLog) {
187
- console.log(`未配置管理员且未启用自动同意,忽略群聊邀请: 群号 ${guildId}, 邀请者 ${userId}`);
188
- }
189
190
  }
190
191
  return;
191
192
  }
192
- const inviteId = `${guildId}_${userId}_${Date.now()}`;
193
+ const inviteId = `${rawGroupId}_${rawUserId}_${Date.now()}`;
193
194
  pendingInvites.set(inviteId, {
194
- groupId: guildId,
195
- userId,
195
+ groupId: rawGroupId,
196
+ userId: rawUserId,
196
197
  userName,
197
198
  time: Date.now(),
198
199
  flag
199
200
  });
200
- const requestMessage = config.invite.inviteRequestMessage.replace("{groupName}", groupName).replace("{groupId}", guildId).replace("{userName}", userName).replace("{userId}", userId);
201
+ const requestMessage = config.invite.inviteRequestMessage.replace("{groupName}", groupName).replace("{groupId}", rawGroupId).replace("{userName}", userName).replace("{userId}", rawUserId);
201
202
  let requestSent = false;
202
203
  if (config.invite.notificationGroupId) {
203
204
  try {
204
205
  await session.bot.sendMessage(config.invite.notificationGroupId, requestMessage);
205
206
  requestSent = true;
206
207
  if (config.invite.showDetailedLog) {
207
- console.log(`发送群聊邀请请求到通知群 ${config.invite.notificationGroupId}`);
208
+ console.log(`发送邀请请求到通知群 ${config.invite.notificationGroupId}`);
208
209
  }
209
210
  } catch (error) {
210
211
  console.error(`发送邀请请求到通知群 ${config.invite.notificationGroupId} 失败:`, error);
@@ -216,7 +217,7 @@ function apply(ctx, config) {
216
217
  await session.bot.sendPrivateMessage(adminQQ, requestMessage);
217
218
  requestSent = true;
218
219
  if (config.invite.showDetailedLog) {
219
- console.log(`发送群聊邀请请求给管理员 ${adminQQ}: 群号 ${guildId}, 邀请者 ${userId}`);
220
+ console.log(`发送邀请请求给管理员 ${adminQQ}`);
220
221
  }
221
222
  } catch (error) {
222
223
  console.error(`发送邀请请求给管理员 ${adminQQ} 失败:`, error);
@@ -224,32 +225,22 @@ function apply(ctx, config) {
224
225
  }
225
226
  }
226
227
  if (!requestSent && config.invite.showDetailedLog) {
227
- console.warn("群邀请请求未发送给任何目标(未配置通知群且私聊发送失败或未配置管理员)");
228
+ console.warn("群邀请请求发送失败:未配置通知群且管理员私聊发送失败");
228
229
  }
229
230
  });
230
231
  ctx.on("message", async (session) => {
231
- const { userId, content, platform, guildId } = session;
232
- if (!config.invite.adminQQs.includes(userId)) {
233
- return;
234
- }
232
+ const { userId, content, guildId } = session;
233
+ if (!config.invite.adminQQs.includes(userId)) return;
235
234
  const isNotificationGroup = config.invite.notificationGroupId && guildId === config.invite.notificationGroupId;
236
235
  const isPrivate = !guildId;
237
- if (!isNotificationGroup && !isPrivate && config.invite.notificationGroupId) {
238
- return;
239
- }
236
+ if (!isNotificationGroup && !isPrivate && config.invite.notificationGroupId) return;
240
237
  const hasQuote = session.elements.some((element) => element.type === "quote");
241
- if (!hasQuote) {
242
- return;
243
- }
238
+ if (!hasQuote) return;
244
239
  const trimmedContent = content.trim();
245
- if (trimmedContent !== "同意" && trimmedContent !== "拒绝" && trimmedContent !== "accept" && trimmedContent !== "reject") {
246
- return;
247
- }
240
+ if (!["同意", "拒绝", "accept", "reject"].includes(trimmedContent)) return;
248
241
  const quoteElement = session.elements.find((element) => element.type === "quote");
249
- if (!quoteElement) {
250
- return;
251
- }
252
- const quoteMessageContent = quoteElement.attrs.content || quoteElement.attrs.text || "";
242
+ if (!quoteElement) return;
243
+ const quoteMessageContent = session.quote?.content || quoteElement.attrs.content || quoteElement.attrs.text || "";
253
244
  const groupIdMatch = quoteMessageContent.match(/群号:(\d+)/i);
254
245
  const userIdMatch = quoteMessageContent.match(/QQ:\s*(\d+)/i);
255
246
  if (groupIdMatch && userIdMatch) {
@@ -273,20 +264,17 @@ function apply(ctx, config) {
273
264
  approve: true,
274
265
  reason: ""
275
266
  });
276
- if (config.invite.showDetailedLog) {
277
- console.log(`管理员 ${userId} 同意群聊邀请: 群号 ${inviteData.groupId}, 邀请者 ${inviteData.userId}`);
278
- }
279
267
  await session.send(`已同意加入群 ${inviteData.groupId}`);
280
268
  try {
281
269
  await session.bot.sendPrivateMessage(inviteData.userId, `您的群聊邀请已通过管理员审核,机器人已加入群聊。`);
282
270
  } catch (error) {
283
- console.error("通知邀请者审核结果失败:", error);
271
+ console.error("通知邀请者失败:", error);
284
272
  }
285
273
  } catch (error) {
286
274
  console.error("处理同意邀请失败:", error);
287
275
  await session.send(`处理同意邀请失败: ${error.message}`);
288
276
  }
289
- } else if (trimmedContent === "拒绝" || trimmedContent === "reject") {
277
+ } else {
290
278
  try {
291
279
  await session.bot.internal.setGroupAddRequest({
292
280
  flag: inviteData.flag,
@@ -294,14 +282,11 @@ function apply(ctx, config) {
294
282
  approve: false,
295
283
  reason: "已拒绝"
296
284
  });
297
- if (config.invite.showDetailedLog) {
298
- console.log(`管理员 ${userId} 拒绝群聊邀请: 群号 ${inviteData.groupId}, 邀请者 ${inviteData.userId}`);
299
- }
300
285
  await session.send(`已拒绝加入群 ${inviteData.groupId}`);
301
286
  try {
302
287
  await session.bot.sendPrivateMessage(inviteData.userId, `您的群聊邀请未通过管理员审核,机器人将不会加入该群聊。`);
303
288
  } catch (error) {
304
- console.error("通知邀请者审核结果失败:", error);
289
+ console.error("通知邀请者失败:", error);
305
290
  }
306
291
  } catch (error) {
307
292
  console.error("处理拒绝邀请失败:", error);
@@ -320,8 +305,7 @@ function apply(ctx, config) {
320
305
  if (config.basic.welcomeMessage) {
321
306
  try {
322
307
  await session.bot.sendMessage(guildId, config.basic.welcomeMessage, platform);
323
- } catch (error) {
324
- console.error("发送欢迎消息失败:", error);
308
+ } catch (e) {
325
309
  }
326
310
  }
327
311
  return;
@@ -330,29 +314,24 @@ function apply(ctx, config) {
330
314
  if (blacklisted) {
331
315
  try {
332
316
  await session.bot.sendMessage(guildId, config.basic.blacklistMessage, platform);
333
- } catch (error) {
334
- console.error("发送黑名单提示失败:", error);
317
+ } catch (e) {
335
318
  }
336
319
  try {
337
320
  await session.bot.internal.setGroupLeave(parseInt(guildId));
338
- } catch (error) {
339
- console.error("退出黑名单群聊失败:", error);
321
+ } catch (e) {
340
322
  }
341
323
  return;
342
324
  }
343
325
  if (config.basic.welcomeMessage) {
344
326
  try {
345
327
  await session.bot.sendMessage(guildId, config.basic.welcomeMessage, platform);
346
- } catch (error) {
347
- console.error("发送欢迎消息失败:", error);
328
+ } catch (e) {
348
329
  }
349
330
  }
350
331
  });
351
332
  ctx.on("guild-removed", async (session) => {
352
333
  const { guildId, platform } = session;
353
- if (!config.basic.enableBlacklist) {
354
- return;
355
- }
334
+ if (!config.basic.enableBlacklist) return;
356
335
  const quittingKey = `${platform}:${guildId}`;
357
336
  if (quittingGuilds.has(quittingKey)) {
358
337
  quittingGuilds.delete(quittingKey);
@@ -372,83 +351,53 @@ function apply(ctx, config) {
372
351
  const { guildId, platform } = session;
373
352
  if (config.frequency.whitelist && config.frequency.whitelist.includes(guildId)) return;
374
353
  let record = await getCommandFrequencyRecord(ctx, platform, guildId);
375
- function handleExpiredWindow(currentRecord, platform2, guildId2, now2, windowStart2, warnDelay) {
376
- if (currentRecord && currentRecord.lastCommandTime < windowStart2) {
377
- if (currentRecord.warningSent && currentRecord.firstWarningTime > 0) {
378
- if (now2 - currentRecord.firstWarningTime > warnDelay) {
379
- return { platform: platform2, guildId: guildId2, commandCount: 1, lastCommandTime: now2, warningSent: false, blockExpiryTime: 0, firstWarningTime: 0 };
380
- } else {
381
- currentRecord.commandCount = 1;
382
- currentRecord.lastCommandTime = now2;
383
- return currentRecord;
384
- }
385
- } else if (isCurrentlyBlocked(currentRecord) && Date.now() >= currentRecord.blockExpiryTime * 1e3) {
386
- return { platform: platform2, guildId: guildId2, commandCount: 1, lastCommandTime: now2, warningSent: false, blockExpiryTime: 0, firstWarningTime: 0 };
387
- } else {
388
- return { platform: platform2, guildId: guildId2, commandCount: 1, lastCommandTime: now2, warningSent: false, blockExpiryTime: 0, firstWarningTime: 0 };
389
- }
354
+ const now = Math.floor(Date.now() / 1e3);
355
+ const windowStart = now - config.frequency.window;
356
+ if (record && record.lastCommandTime < windowStart) {
357
+ if (record.warningSent && record.firstWarningTime > 0 && now - record.firstWarningTime <= config.frequency.warnDelay) {
358
+ record.commandCount = 1;
359
+ record.lastCommandTime = now;
360
+ } else if (isCurrentlyBlocked(record) && Date.now() < record.blockExpiryTime * 1e3) {
390
361
  } else {
391
- if (currentRecord) {
392
- currentRecord.commandCount += 1;
393
- currentRecord.lastCommandTime = now2;
394
- return currentRecord;
395
- } else {
396
- return { platform: platform2, guildId: guildId2, commandCount: 1, lastCommandTime: now2, warningSent: false, blockExpiryTime: 0, firstWarningTime: 0 };
397
- }
362
+ record = { platform, guildId, commandCount: 1, lastCommandTime: now, warningSent: false, blockExpiryTime: 0, firstWarningTime: 0 };
398
363
  }
364
+ } else if (!record) {
365
+ record = { platform, guildId, commandCount: 1, lastCommandTime: now, warningSent: false, blockExpiryTime: 0, firstWarningTime: 0 };
366
+ } else {
367
+ record.commandCount += 1;
368
+ record.lastCommandTime = now;
399
369
  }
400
- __name(handleExpiredWindow, "handleExpiredWindow");
401
- if (record && isCurrentlyBlocked(record)) {
370
+ if (isCurrentlyBlocked(record)) {
402
371
  try {
403
372
  const remainingTime = Math.ceil((record.blockExpiryTime * 1e3 - Date.now()) / 1e3);
404
- const blockedMessage = config.frequency.blockedMsg.replace("{time}", remainingTime.toString());
405
- await session.bot.sendMessage(guildId, blockedMessage, platform);
406
- } catch (error) {
407
- console.error("发送屏蔽提示失败:", error);
373
+ await session.bot.sendMessage(guildId, config.frequency.blockedMsg.replace("{time}", remainingTime.toString()), platform);
374
+ } catch (e) {
408
375
  }
409
- throw new Error("Command frequency limit exceeded - currently blocked");
376
+ throw new Error("Blocked");
410
377
  }
411
- const now = Math.floor(Date.now() / 1e3);
412
- const windowStart = now - config.frequency.window;
413
- record = handleExpiredWindow(record, platform, guildId, now, windowStart, config.frequency.warnDelay);
414
378
  if (record.commandCount > config.frequency.limit) {
415
- if (isCurrentlyBlocked(record)) {
416
- const remainingTime = Math.ceil((record.blockExpiryTime * 1e3 - Date.now()) / 1e3);
379
+ if (!record.warningSent) {
417
380
  try {
418
- const blockedMessage = config.frequency.blockedMsg.replace("{time}", remainingTime.toString());
419
- await session.bot.sendMessage(guildId, blockedMessage, platform);
420
- } catch (error) {
421
- console.error("发送屏蔽提示失败:", error);
381
+ await session.bot.sendMessage(guildId, config.frequency.warnMsg, platform);
382
+ } catch (e) {
422
383
  }
423
- throw new Error("Command frequency limit exceeded - currently blocked");
384
+ record.warningSent = true;
385
+ record.commandCount = 1;
386
+ record.lastCommandTime = now;
387
+ record.firstWarningTime = now;
388
+ await updateCommandFrequencyRecord(ctx, platform, guildId, record);
389
+ throw new Error("Warning");
424
390
  } else {
425
- if (!record.warningSent) {
426
- try {
427
- await session.bot.sendMessage(guildId, config.frequency.warnMsg, platform);
428
- } catch (error) {
429
- console.error("发送频率警告消息失败:", error);
430
- }
431
- record.warningSent = true;
432
- record.commandCount = 1;
433
- record.lastCommandTime = now;
434
- record.firstWarningTime = now;
435
- await updateCommandFrequencyRecord(ctx, platform, guildId, record);
436
- throw new Error("Command frequency limit exceeded - warning issued");
437
- } else {
438
- const blockExpiryTime = now + config.frequency.blockDur;
439
- record.blockExpiryTime = blockExpiryTime;
440
- record.warningSent = false;
441
- record.commandCount = 0;
442
- record.firstWarningTime = 0;
443
- await updateCommandFrequencyRecord(ctx, platform, guildId, record);
444
- try {
445
- const blockMessage = config.frequency.blockMsg.replace("{duration}", config.frequency.blockDur.toString());
446
- await session.bot.sendMessage(guildId, blockMessage, platform);
447
- } catch (error) {
448
- console.error("发送屏蔽通知失败:", error);
449
- }
450
- throw new Error("Command frequency limit exceeded - blocked");
391
+ record.blockExpiryTime = now + config.frequency.blockDur;
392
+ record.warningSent = false;
393
+ record.commandCount = 0;
394
+ record.firstWarningTime = 0;
395
+ await updateCommandFrequencyRecord(ctx, platform, guildId, record);
396
+ try {
397
+ await session.bot.sendMessage(guildId, config.frequency.blockMsg.replace("{duration}", config.frequency.blockDur.toString()), platform);
398
+ } catch (e) {
451
399
  }
400
+ throw new Error("Blocked");
452
401
  }
453
402
  }
454
403
  await updateCommandFrequencyRecord(ctx, platform, guildId, record);
@@ -459,34 +408,25 @@ function apply(ctx, config) {
459
408
  if (!session.guildId) return "quit 指令只能在群聊中使用。";
460
409
  const { guildId, platform, userId } = session;
461
410
  quittingGuilds.add(`${platform}:${guildId}`);
462
- const message = config.basic.quitMessage.replace("{userId}", userId);
463
411
  try {
464
- await session.bot.sendMessage(session.guildId, message, platform);
465
- } catch (sendError) {
466
- console.error("发送退出提示消息失败:", sendError);
412
+ await session.bot.sendMessage(session.guildId, config.basic.quitMessage.replace("{userId}", userId), platform);
413
+ } catch (e) {
467
414
  }
468
415
  try {
469
416
  await session.bot.internal.setGroupLeave(parseInt(guildId));
470
- } catch (leaveError) {
417
+ } catch (e) {
471
418
  quittingGuilds.delete(`${platform}:${guildId}`);
472
- console.error("退出群聊失败:", leaveError);
473
- return `退出失败: ${leaveError.message || "OneBot API 调用失败"}`;
419
+ return `退出失败: ${e.message}`;
474
420
  }
475
421
  return "";
476
422
  });
477
423
  }
478
- async function viewBlacklist({ session }) {
424
+ async function viewBlacklist() {
479
425
  const errorMsg = isBlacklistEnabled(config.basic);
480
426
  if (errorMsg) return errorMsg;
481
427
  const records = await getAllBlacklistedGuilds(ctx);
482
428
  if (records.length === 0) return "黑名单为空。";
483
- let msg = "黑名单列表:\n";
484
- records.forEach((r) => {
485
- const time = formatDate(r.timestamp);
486
- msg += `- ${r.guildId} (时间: ${time})
487
- `;
488
- });
489
- return msg.trim();
429
+ return "黑名单列表:\n" + records.map((r) => `- ${r.guildId} (时间: ${formatDate(r.timestamp)})`).join("\n");
490
430
  }
491
431
  __name(viewBlacklist, "viewBlacklist");
492
432
  ctx.command("view-blacklist", "查看被拉黑的群聊列表", { authority: 4 }).action(viewBlacklist);
@@ -494,7 +434,7 @@ function apply(ctx, config) {
494
434
  const errorMsg = isBlacklistEnabled(config.basic);
495
435
  if (errorMsg) return errorMsg;
496
436
  const guildId = parseGuildId(input);
497
- if (!guildId) return `输入格式错误。请输入纯群号或 onebot:群号 格式。`;
437
+ if (!guildId) return `输入格式错误。`;
498
438
  const removed = await removeBlacklistedGuild(ctx, guildId);
499
439
  return removed ? `已移除群聊 ${guildId}` : `群聊 ${guildId} 不在黑名单中。`;
500
440
  }
@@ -504,22 +444,21 @@ function apply(ctx, config) {
504
444
  const errorMsg = isBlacklistEnabled(config.basic);
505
445
  if (errorMsg) return errorMsg;
506
446
  const guildId = parseGuildId(input);
507
- if (!guildId) return `输入格式错误。请输入纯群号或 onebot:群号 格式。`;
447
+ if (!guildId) return `输入格式错误。`;
508
448
  const existing = await getBlacklistedGuild(ctx, guildId);
509
449
  if (existing.length > 0) return `群聊 ${guildId} 已在黑名单中。`;
510
450
  await createBlacklistedGuild(ctx, guildId, "manual_add");
511
451
  return `已添加群聊 ${guildId} 到黑名单。`;
512
452
  }
513
453
  __name(addToBlacklist, "addToBlacklist");
514
- ctx.command("add-to-blacklist <groupId:text>", "手动添加群聊到黑名单 (输入群号)", { authority: 4 }).action(addToBlacklist);
515
- async function clearBlacklist({ session }) {
454
+ ctx.command("add-to-blacklist <groupId:text>", "手动添加群聊到黑名单", { authority: 4 }).action(addToBlacklist);
455
+ async function clearBlacklist() {
516
456
  const errorMsg = isBlacklistEnabled(config.basic);
517
457
  if (errorMsg) return errorMsg;
518
458
  const records = await getAllBlacklistedGuilds(ctx);
519
- const count = records.length;
520
- if (count === 0) return "黑名单已是空的。";
459
+ if (records.length === 0) return "黑名单已是空的。";
521
460
  await clearBlacklistedGuilds(ctx);
522
- return `已清空黑名单,共移除 ${count} 个群聊。`;
461
+ return `已清空黑名单,共移除 ${records.length} 个群聊。`;
523
462
  }
524
463
  __name(clearBlacklist, "clearBlacklist");
525
464
  ctx.command("clear-blacklist", "清空黑名单", { authority: 4 }).action(clearBlacklist);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-group-control",
3
3
  "description": "Koishi群聊自管理插件,支持自定义机器人进群消息、被踢出自动拉黑、刷屏自动屏蔽功能和主动退群指令等。(仅支持OneBot适配器)",
4
- "version": "0.2.4",
4
+ "version": "0.2.6",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -23,4 +23,4 @@
23
23
  "peerDependencies": {
24
24
  "koishi": "^4.18.7"
25
25
  }
26
- }
26
+ }