koishi-plugin-lili-hub 0.2.2 → 0.3.1

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 +413 -82
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -227,7 +227,9 @@ var Config = import_koishi.Schema.object({
227
227
  drunkMisfireRate: import_koishi.Schema.number().description("\u9189\u9152\u540E\u5B50\u5F39\u54D1\u5F39\u7684\u6982\u7387 (0-1)").default(0.35).min(0).max(1).step(0.01),
228
228
  drunkRampageRate: import_koishi.Schema.number().description("\u9189\u9152\u540E\u8FDE\u7EED\u5F00\u67AA\u7684\u6982\u7387 (0-1)").default(0.3).min(0).max(1).step(0.01),
229
229
  drunkRevengeRate: import_koishi.Schema.number().description("\u9189\u9152\u540E\u6CE2\u53CA\u5386\u53F2\u53C2\u4E0E\u8005\u7684\u6982\u7387 (0-1)").default(0.2).min(0).max(1).step(0.01),
230
- maxHistoryRounds: import_koishi.Schema.number().description("\u4FDD\u7559\u591A\u5C11\u8F6E\u5386\u53F2\u8BB0\u5F55\uFF08\u7528\u4E8E\u62A5\u4EC7\u673A\u5236\uFF09").default(3).min(1).max(20)
230
+ maxHistoryRounds: import_koishi.Schema.number().description("\u4FDD\u7559\u591A\u5C11\u8F6E\u5386\u53F2\u8BB0\u5F55\uFF08\u7528\u4E8E\u62A5\u4EC7\u673A\u5236\uFF09").default(3).min(1).max(20),
231
+ groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF0C\u7559\u7A7A\u4E3A\u6240\u6709\u7FA4\uFF09").default(""),
232
+ groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355\uFF08\u4EC5\u5728\u5217\u8868\u4E2D\u7684\u7FA4\u751F\u6548\uFF09/ \u9ED1\u540D\u5355\uFF08\u5217\u8868\u4E2D\u7684\u7FA4\u4E0D\u751F\u6548\uFF09").default("whitelist")
231
233
  }).description("\u{1F52B} \u4E3D\u4E3D\u8F6E\u76D8"),
232
234
  voice: import_koishi.Schema.object({
233
235
  voiceEnabled: import_koishi.Schema.boolean().description("\u662F\u5426\u64AD\u653E\u4E3D\u4E3D\u8BED\u97F3").default(true),
@@ -251,7 +253,8 @@ var Config = import_koishi.Schema.object({
251
253
  }).description("\u{1F50A} \u8BED\u97F3\u4E0E\u53F0\u8BCD\u8BBE\u7F6E"),
252
254
  voteMute: import_koishi.Schema.object({
253
255
  enabled: import_koishi.Schema.boolean().description("\u542F\u7528\u7D2F\u8BA1\u6295\u7968\u7981\u8A00\u529F\u80FD").default(false),
254
- groups: import_koishi.Schema.string().description("\u767D\u540D\u5355\u7FA4\u53F7\uFF08\u9017\u53F7\u5206\u9694\uFF0C\u7559\u7A7A\u4E3A\u6240\u6709\u7FA4\uFF09").default(""),
256
+ groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF0C\u7559\u7A7A\u4E3A\u6240\u6709\u7FA4\uFF09").default(""),
257
+ groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist"),
255
258
  voteWindowDays: import_koishi.Schema.number().description("\u7D2F\u8BA1\u6295\u7968\u7684\u65F6\u95F4\u7A97\u53E3\uFF08\u5929\uFF09").default(7).min(1).max(365),
256
259
  muteThreshold: import_koishi.Schema.number().description("\u7D2F\u8BA1\u7981\u8A00\u7968 \u2265 \u6B64\u503C\u65F6\u6267\u884C\u7981\u8A00").default(5).min(1).max(1e3),
257
260
  unmuteThreshold: import_koishi.Schema.number().description("\u7981\u8A00\u7968 \u2264 \u6B64\u503C\u65F6\u81EA\u52A8\u89E3\u7981").default(2).min(0).max(1e3),
@@ -259,19 +262,33 @@ var Config = import_koishi.Schema.object({
259
262
  }).description("\u{1F5F3}\uFE0F \u7D2F\u8BA1\u6295\u7968\u7981\u8A00"),
260
263
  fold: import_koishi.Schema.object({
261
264
  enabled: import_koishi.Schema.boolean().description("\u542F\u7528\u4E3D\u4E3D\u6298\u53E0\u529F\u80FD").default(false),
262
- groups: import_koishi.Schema.string().description("\u767D\u540D\u5355\u7FA4\u53F7\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
265
+ groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
266
+ groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist"),
267
+ adminOnly: import_koishi.Schema.boolean().description("\u4EC5\u7FA4\u4E3B\u548C\u7BA1\u7406\u5458\u53EF\u4EE5\u4F7F\u7528\u4E3D\u4E3D\u6298\u53E0").default(false),
263
268
  minutes: import_koishi.Schema.number().description("\u6298\u53E0\u65F6\u95F4\u8303\u56F4\uFF08\u5206\u949F\uFF09").default(10).min(1).max(1440)
264
269
  }).description("\u{1F4E6} \u4E3D\u4E3D\u6298\u53E0"),
265
270
  imitation: import_koishi.Schema.object({
266
271
  enabled: import_koishi.Schema.boolean().description("\u542F\u7528\u6A21\u4EFF\u7FA4\u53CB\u8BF4\u8BDD\u529F\u80FD").default(false),
267
- groups: import_koishi.Schema.string().description("\u767D\u540D\u5355\u7FA4\u53F7\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
272
+ groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
273
+ groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist"),
268
274
  interval: import_koishi.Schema.number().description("\u6BCF\u591A\u5C11\u6761\u6D88\u606F\u68C0\u67E5\u4E00\u6B21\u6A21\u4EFF").default(50).min(1).max(1e4),
269
275
  rate: import_koishi.Schema.number().description("\u6A21\u4EFF\u89E6\u53D1\u6982\u7387 (0-1)").default(0.05).min(0).max(1).step(0.01)
270
276
  }).description("\u{1F5E3}\uFE0F \u6A21\u4EFF\u7FA4\u53CB"),
271
277
  dedup: import_koishi.Schema.object({
272
278
  enabled: import_koishi.Schema.boolean().description("\u542F\u7528\u5408\u5E76\u6D88\u606F\u67E5\u91CD\u529F\u80FD\uFF08\u6C34\u8FC7\u4E86\uFF09").default(false),
273
- groups: import_koishi.Schema.string().description("\u767D\u540D\u5355\u7FA4\u53F7\uFF08\u9017\u53F7\u5206\u9694\uFF09").default("")
274
- }).description("\u{1F4A7} \u67E5\u91CD")
279
+ groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
280
+ groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist")
281
+ }).description("\u{1F4A7} \u67E5\u91CD"),
282
+ duel: import_koishi.Schema.object({
283
+ enabled: import_koishi.Schema.boolean().description("\u542F\u7528\u4E3D\u4E3D\u5BF9\u51B3\u529F\u80FD").default(false),
284
+ groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
285
+ groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist"),
286
+ countdownSeconds: import_koishi.Schema.number().description("\u5012\u8BA1\u65F6\u79D2\u6570").default(5).min(1).max(30),
287
+ acceptTimeoutSeconds: import_koishi.Schema.number().description("\u7B49\u5F85\u63A5\u53D7\u8D85\u65F6\uFF08\u79D2\uFF09").default(30).min(5).max(120),
288
+ drawTimeoutSeconds: import_koishi.Schema.number().description("\u62D4\u67AA\u7A97\u53E3\u8D85\u65F6\uFF08\u79D2\uFF09").default(10).min(3).max(60),
289
+ earlyDrawMuteSeconds: import_koishi.Schema.number().description("\u63D0\u524D\u62D4\u67AA\u7981\u8A00\u65F6\u957F\uFF08\u79D2\uFF09").default(600).min(0).max(2592e3),
290
+ lateMuteSeconds: import_koishi.Schema.number().description("\u665A\u62D4\u67AA/\u672A\u62D4\u67AA\u7981\u8A00\u65F6\u957F\uFF08\u79D2\uFF09").default(300).min(0).max(2592e3)
291
+ }).description("\u2694\uFE0F \u4E3D\u4E3D\u5BF9\u51B3")
275
292
  });
276
293
  function getGroupId(session) {
277
294
  return session.guildId || session.channelId;
@@ -289,9 +306,12 @@ function parseGroupList(raw) {
289
306
  function normalizeText(text) {
290
307
  return text.replace(/\[CQ:[^\]]*\]/g, "").replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
291
308
  }
292
- function isGroupAllowed(gid, groups) {
309
+ function isGroupAllowed(gid, groups, mode = "whitelist") {
293
310
  const list = parseGroupList(groups);
294
311
  if (list.length === 0) return true;
312
+ if (mode === "blacklist") {
313
+ return !list.includes(gid);
314
+ }
295
315
  return list.includes(gid);
296
316
  }
297
317
  function getMultiKillEvent(v, killCount) {
@@ -313,31 +333,6 @@ function isForwardMessage(session) {
313
333
  }
314
334
  return false;
315
335
  }
316
- function extractNodeText(nodeData) {
317
- if (!nodeData) return "";
318
- if (nodeData.id && !nodeData.content) return "";
319
- const c = nodeData.content;
320
- if (!c) return "";
321
- if (typeof c === "string") return normalizeText(c);
322
- if (Array.isArray(c)) {
323
- return normalizeText(
324
- c.filter((seg) => seg.type === "text").map((seg) => seg.data?.text || "").join("")
325
- );
326
- }
327
- return "";
328
- }
329
- function extractForwardTexts(session) {
330
- const results = [];
331
- if (session.elements) {
332
- for (const el of session.elements) {
333
- if (el.type === "node" || el.type === "forward") {
334
- const text = extractNodeText(el.attrs);
335
- if (text) results.push(text);
336
- }
337
- }
338
- }
339
- return results;
340
- }
341
336
  function extractTarget(session, cmdArg) {
342
337
  if (session.elements) {
343
338
  const atEl = session.elements.find((el) => el.type === "at" && el.attrs?.id);
@@ -379,9 +374,21 @@ function apply(ctx, config) {
379
374
  voteType: "string",
380
375
  timestamp: "unsigned"
381
376
  }, { autoInc: true });
377
+ ctx.model.extend("lili_duel", {
378
+ id: "unsigned",
379
+ gid: "string",
380
+ winnerId: "string",
381
+ winnerName: "string",
382
+ loserId: "string",
383
+ loserName: "string",
384
+ winnerTime: "unsigned",
385
+ loserTime: "unsigned",
386
+ timestamp: "unsigned"
387
+ }, { autoInc: true });
382
388
  const drinkStates = /* @__PURE__ */ new Map();
383
389
  const rouletteStates = /* @__PURE__ */ new Map();
384
390
  const imitationCounters = /* @__PURE__ */ new Map();
391
+ const duelStates = /* @__PURE__ */ new Map();
385
392
  function isDrunk(gid) {
386
393
  const s = drinkStates.get(gid);
387
394
  if (!s || s.drunkUntil === 0) return false;
@@ -504,8 +511,8 @@ function apply(ctx, config) {
504
511
  try {
505
512
  const history = await ctx.database.get("lili_roulette", { gid }, { sort: { timestamp: "desc" }, limit: config.roulette.maxHistoryRounds });
506
513
  const allHitUsers = /* @__PURE__ */ new Set();
507
- for (const h of history) {
508
- if (h.hitUserId) allHitUsers.add(h.hitUserId);
514
+ for (const h2 of history) {
515
+ if (h2.hitUserId) allHitUsers.add(h2.hitUserId);
509
516
  }
510
517
  const pool = [...allHitUsers].filter((u) => u !== session.userId);
511
518
  if (pool.length > 0) {
@@ -560,6 +567,7 @@ function apply(ctx, config) {
560
567
  ctx.command("\u4E3D\u4E3D\u8F6E\u76D8", "\u4FC4\u7F57\u65AF\u8F6E\u76D8\u8D4C").alias("\u4E3D\u4E3D\u5F00\u67AA").action(async ({ session }) => {
561
568
  if (!session?.userId) return;
562
569
  const gid = getGroupId(session);
570
+ if (!isGroupAllowed(gid, config.roulette.groups, config.roulette.groupMode)) return;
563
571
  if (!rouletteStates.has(gid)) {
564
572
  const bullet = randInt(1, config.roulette.chamberSize);
565
573
  const startTime = Date.now();
@@ -593,6 +601,7 @@ function apply(ctx, config) {
593
601
  ctx.command("\u4E3D\u4E3D\u559D\u9152", "\u4E3D\u4E3D\u5F00\u59CB\u559D\u9152\uFF0C\u9700\u8981\u559D 2-4 \u676F\u624D\u4F1A\u559D\u9189").action(async ({ session }) => {
594
602
  if (!session?.userId) return;
595
603
  const gid = getGroupId(session);
604
+ if (!isGroupAllowed(gid, config.roulette.groups, config.roulette.groupMode)) return;
596
605
  if (isDrunk(gid)) {
597
606
  await playEffect(session, config.voice.stillDrunk, 500);
598
607
  return;
@@ -641,7 +650,7 @@ function apply(ctx, config) {
641
650
  const gid = getGroupId(session);
642
651
  const vm = config.voteMute;
643
652
  if (!vm.enabled) return;
644
- if (!isGroupAllowed(gid, vm.groups)) return;
653
+ if (!isGroupAllowed(gid, vm.groups, vm.groupMode)) return;
645
654
  const targetId = extractTarget(session, targetUser);
646
655
  if (!targetId) return "\u{1F507} \u65E0\u6CD5\u89E3\u6790\u76EE\u6807\u7528\u6237\u3002\u8BF7\u4F7F\u7528 @ \u529F\u80FD\u9009\u62E9\u76EE\u6807\u3002";
647
656
  if (targetId === session.userId) return "\u{1F507} \u4E0D\u80FD\u7ED9\u81EA\u5DF1\u6295\u7968\u3002";
@@ -673,7 +682,7 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u7981\u8A00 ${timeStr}\u3002`
673
682
  const gid = getGroupId(session);
674
683
  const vm = config.voteMute;
675
684
  if (!vm.enabled) return;
676
- if (!isGroupAllowed(gid, vm.groups)) return;
685
+ if (!isGroupAllowed(gid, vm.groups, vm.groupMode)) return;
677
686
  const targetId = extractTarget(session, targetUser);
678
687
  if (!targetId) return "\u{1F50A} \u65E0\u6CD5\u89E3\u6790\u76EE\u6807\u7528\u6237\u3002\u8BF7\u4F7F\u7528 @ \u529F\u80FD\u9009\u62E9\u76EE\u6807\u3002";
679
688
  try {
@@ -694,22 +703,33 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
694
703
  return `\u{1F50A} \u5DF2\u64A4\u56DE\u4F60\u5BF9 ${import_koishi.segment.at(targetId)} \u7684\u7981\u8A00\u7968\u3002
695
704
  \u{1F4CA} \u5F53\u524D\u7981\u8A00\u7968\uFF1A${muteCount}\uFF08\u9700 \u2264 ${vm.unmuteThreshold} \u624D\u4F1A\u89E3\u7981\uFF09`;
696
705
  });
697
- ctx.command("\u4E3D\u4E3D\u6298\u53E0 <user:user>", "\u5408\u5E76\u8F6C\u53D1\u5E76\u64A4\u56DE\u76EE\u6807\u7528\u6237\u6700\u8FD1 X \u5206\u949F\u5185\u7684\u6D88\u606F").action(async ({ session }, targetUser) => {
706
+ ctx.command("\u4E3D\u4E3D\u6298\u53E0 <user:user> [minutes:number]", "\u5408\u5E76\u8F6C\u53D1\u5E76\u64A4\u56DE\u76EE\u6807\u7528\u6237\u6700\u8FD1 X \u5206\u949F\u5185\u7684\u6D88\u606F").action(async ({ session }, targetUser, minutesArg) => {
698
707
  if (!session?.userId) return;
699
708
  const gid = getGroupId(session);
700
709
  const fc = config.fold;
701
710
  if (!fc.enabled) return;
702
- if (!isGroupAllowed(gid, fc.groups)) return;
711
+ if (!isGroupAllowed(gid, fc.groups, fc.groupMode)) return;
712
+ if (fc.adminOnly) {
713
+ try {
714
+ const info = await session.bot.getGroupMemberInfo(gid, String(session.userId));
715
+ if (!info || info.role !== "owner" && info.role !== "admin") {
716
+ return "\u{1F4E6} \u4EC5\u7FA4\u4E3B\u6216\u7BA1\u7406\u5458\u53EF\u4EE5\u4F7F\u7528\u4E3D\u4E3D\u6298\u53E0\u529F\u80FD\u3002";
717
+ }
718
+ } catch {
719
+ return "\u{1F4E6} \u65E0\u6CD5\u9A8C\u8BC1\u7BA1\u7406\u5458\u8EAB\u4EFD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
720
+ }
721
+ }
703
722
  const targetId = extractTarget(session, targetUser);
704
723
  if (!targetId) return "\u{1F4E6} \u65E0\u6CD5\u89E3\u6790\u76EE\u6807\u7528\u6237\u3002\u8BF7\u4F7F\u7528 @ \u529F\u80FD\u6216\u76F4\u63A5\u8F93\u5165 QQ \u53F7\u3002";
705
- const since = Date.now() - fc.minutes * 60 * 1e3;
724
+ const foldedMinutes = typeof minutesArg === "number" && minutesArg >= 1 && minutesArg <= 1440 ? minutesArg : fc.minutes;
725
+ const since = Date.now() - foldedMinutes * 60 * 1e3;
706
726
  let messages;
707
727
  try {
708
728
  messages = await ctx.database.get("lili_message", { gid, userId: targetId, timestamp: { $gte: since } }, { sort: { timestamp: "asc" }, limit: 100 });
709
729
  } catch {
710
730
  return "\u{1F4E6} \u67E5\u8BE2\u6D88\u606F\u5931\u8D25\u3002";
711
731
  }
712
- if (!messages || messages.length === 0) return `\u{1F4E6} ${import_koishi.segment.at(targetId)} \u6700\u8FD1 ${fc.minutes} \u5206\u949F\u5185\u6CA1\u6709\u53D1\u8A00\u8BB0\u5F55\u3002`;
732
+ if (!messages || messages.length === 0) return `\u{1F4E6} ${import_koishi.segment.at(targetId)} \u6700\u8FD1 ${foldedMinutes} \u5206\u949F\u5185\u6CA1\u6709\u53D1\u8A00\u8BB0\u5F55\u3002`;
713
733
  const nodes = messages.map((m) => ({
714
734
  type: "node",
715
735
  data: { name: m.userName, uin: m.userId, content: m.content, time: String(Math.floor(m.timestamp / 1e3)) }
@@ -729,7 +749,7 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
729
749
  const time = new Date(m.timestamp).toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" });
730
750
  return `[${time}] ${m.userName}\uFF1A${m.content}`;
731
751
  });
732
- await session.send(`\u{1F4E6} \u4E3D\u4E3D\u6298\u53E0\u4E86 ${import_koishi.segment.at(targetId)} \u6700\u8FD1 ${fc.minutes} \u5206\u949F\u7684\u6D88\u606F\uFF1A
752
+ await session.send(`\u{1F4E6} \u4E3D\u4E3D\u6298\u53E0\u4E86 ${import_koishi.segment.at(targetId)} \u6700\u8FD1 ${foldedMinutes} \u5206\u949F\u7684\u6D88\u606F\uFF1A
733
753
  ` + lines.join("\n"));
734
754
  }
735
755
  for (const m of messages) {
@@ -741,6 +761,276 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
741
761
  }
742
762
  }
743
763
  });
764
+ ctx.command("\u4E3D\u4E3D\u5BF9\u51B3 <user:user>", "\u53D1\u8D77\u5BF9\u51B3").action(async ({ session }, targetUser) => {
765
+ if (!session?.userId) return;
766
+ const gid = getGroupId(session);
767
+ const dc = config.duel;
768
+ if (!dc.enabled) return;
769
+ if (!isGroupAllowed(gid, dc.groups, dc.groupMode)) return;
770
+ const targetId = extractTarget(session, targetUser);
771
+ if (!targetId) return "\u2694\uFE0F \u65E0\u6CD5\u89E3\u6790\u76EE\u6807\u7528\u6237\u3002\u8BF7\u4F7F\u7528 @ \u529F\u80FD\u9009\u62E9\u76EE\u6807\u3002";
772
+ if (targetId === String(session.userId)) return "\u2694\uFE0F \u4E0D\u80FD\u5411\u81EA\u5DF1\u53D1\u8D77\u5BF9\u51B3\uFF01";
773
+ const botId = session.bot.userId || session.bot.selfId;
774
+ if (botId && targetId === String(botId)) return "\u2694\uFE0F \u4E0D\u80FD\u5411 Bot \u53D1\u8D77\u5BF9\u51B3\uFF01";
775
+ const existing = duelStates.get(gid);
776
+ if (existing && existing.phase !== "finished") {
777
+ return "\u2694\uFE0F \u672C\u7FA4\u6B63\u5728\u8FDB\u884C\u4E00\u573A\u5BF9\u51B3\uFF0C\u8BF7\u7B49\u5F85\u7ED3\u675F\u540E\u518D\u53D1\u8D77\uFF01";
778
+ }
779
+ const challengerId = String(session.userId);
780
+ const challengerName = session.username || challengerId;
781
+ const targetName = session.elements?.find((el) => el.type === "at")?.attrs?.name || targetId;
782
+ const duel = {
783
+ challengerId,
784
+ challengerName,
785
+ targetId,
786
+ targetName,
787
+ session,
788
+ phase: "waiting_accept",
789
+ countdownEndTime: 0,
790
+ earlyDrawers: /* @__PURE__ */ new Set(),
791
+ drawTimes: /* @__PURE__ */ new Map(),
792
+ acceptTimer: null,
793
+ countdownTimer: null,
794
+ drawTimer: null
795
+ };
796
+ duel.acceptTimer = setTimeout(() => {
797
+ const d = duelStates.get(gid);
798
+ if (d && d.phase === "waiting_accept") {
799
+ session.send(`\u23F0 \u5BF9\u51B3\u8D85\u65F6\uFF01${targetName} \u672A\u5728 ${dc.acceptTimeoutSeconds} \u79D2\u5185\u63A5\u53D7\u6311\u6218\u3002`);
800
+ cleanupDuel(gid);
801
+ }
802
+ }, dc.acceptTimeoutSeconds * 1e3);
803
+ duelStates.set(gid, duel);
804
+ dbg("\u5BF9\u51B3-\u53D1\u8D77", { gid, challengerId, challengerName, targetId, targetName });
805
+ return `\u2694\uFE0F ${challengerName} \u5411 ${import_koishi.segment.at(targetId)} \u53D1\u8D77\u4E86\u5BF9\u51B3\uFF01
806
+ \u56DE\u590D"\u63A5\u53D7"\u5E94\u6218\uFF08${dc.acceptTimeoutSeconds}\u79D2\u5185\u6709\u6548\uFF09`;
807
+ });
808
+ ctx.command("\u4E3D\u4E3D\u5BF9\u51B3\u7FA4\u699C", "\u67E5\u770B\u672C\u7FA4\u5BF9\u51B3\u6392\u884C\u699C").action(async ({ session }) => {
809
+ const gid = getGroupId(session);
810
+ try {
811
+ const records = await ctx.database.get("lili_duel", { gid }, {
812
+ sort: { winnerTime: "asc" },
813
+ limit: 10
814
+ });
815
+ if (!records || records.length === 0) return "\u{1F3C6} \u672C\u7FA4\u6682\u65E0\u5BF9\u51B3\u8BB0\u5F55\u3002";
816
+ const lines = ["\u{1F3C6} \u4E3D\u4E3D\u5BF9\u51B3 \u7FA4\u6392\u884C\u699C"];
817
+ for (let i = 0; i < records.length; i++) {
818
+ const r = records[i];
819
+ const time = new Date(r.timestamp).toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" });
820
+ lines.push(`${i + 1}. ${r.winnerName} ${r.winnerTime}ms \u26A1\u80DC ${r.loserName} ${r.loserTime >= 0 ? r.loserTime + "ms" : "\u672A\u62D4\u67AA"} ${time}`);
821
+ }
822
+ return lines.join("\n");
823
+ } catch {
824
+ return "\u{1F3C6} \u67E5\u8BE2\u6392\u884C\u699C\u5931\u8D25\u3002";
825
+ }
826
+ });
827
+ ctx.command("\u4E3D\u4E3D\u5BF9\u51B3\u603B\u699C", "\u67E5\u770B\u5168\u7FA4\u5BF9\u51B3\u6392\u884C\u699C").action(async () => {
828
+ try {
829
+ const records = await ctx.database.get("lili_duel", {}, {
830
+ sort: { winnerTime: "asc" },
831
+ limit: 10
832
+ });
833
+ if (!records || records.length === 0) return "\u{1F3C6} \u6682\u65E0\u5BF9\u51B3\u8BB0\u5F55\u3002";
834
+ const lines = ["\u{1F3C6} \u4E3D\u4E3D\u5BF9\u51B3 \u603B\u6392\u884C\u699C"];
835
+ for (let i = 0; i < records.length; i++) {
836
+ const r = records[i];
837
+ const time = new Date(r.timestamp).toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" });
838
+ lines.push(`${i + 1}. ${r.winnerName} ${r.winnerTime}ms \u26A1\u80DC ${r.loserName} ${r.loserTime >= 0 ? r.loserTime + "ms" : "\u672A\u62D4\u67AA"} ${time}`);
839
+ }
840
+ return lines.join("\n");
841
+ } catch {
842
+ return "\u{1F3C6} \u67E5\u8BE2\u6392\u884C\u699C\u5931\u8D25\u3002";
843
+ }
844
+ });
845
+ function cleanupDuel(gid) {
846
+ const duel = duelStates.get(gid);
847
+ if (!duel) return;
848
+ if (duel.acceptTimer) clearTimeout(duel.acceptTimer);
849
+ if (duel.countdownTimer) clearTimeout(duel.countdownTimer);
850
+ if (duel.drawTimer) clearTimeout(duel.drawTimer);
851
+ duelStates.delete(gid);
852
+ }
853
+ async function resolveDuel(gid) {
854
+ const duel = duelStates.get(gid);
855
+ if (!duel || duel.phase === "finished") return;
856
+ duel.phase = "finished";
857
+ const dc = config.duel;
858
+ const { challengerId, challengerName, targetId, targetName, drawTimes, earlyDrawers, session } = duel;
859
+ if (duel.acceptTimer) clearTimeout(duel.acceptTimer);
860
+ if (duel.countdownTimer) clearTimeout(duel.countdownTimer);
861
+ if (duel.drawTimer) clearTimeout(duel.drawTimer);
862
+ const cTime = drawTimes.get(challengerId) ?? null;
863
+ const tTime = drawTimes.get(targetId) ?? null;
864
+ let winnerId, winnerName, loserId, loserName;
865
+ let winnerTime, loserTime;
866
+ let muteTargets = [];
867
+ let resultLines = [];
868
+ if (earlyDrawers.size > 0) {
869
+ for (const id of earlyDrawers) {
870
+ const name2 = id === challengerId ? challengerName : targetName;
871
+ muteTargets.push({ id, name: name2, duration: dc.earlyDrawMuteSeconds });
872
+ resultLines.push(`\u26A0\uFE0F ${name2} \u63D0\u524D\u62D4\u67AA\uFF01`);
873
+ }
874
+ const otherId = earlyDrawers.has(challengerId) ? targetId : challengerId;
875
+ const otherName = otherId === challengerId ? challengerName : targetName;
876
+ winnerId = otherId;
877
+ winnerName = otherName;
878
+ loserId = [...earlyDrawers][0];
879
+ loserName = loserId === challengerId ? challengerName : targetName;
880
+ winnerTime = drawTimes.get(otherId) ?? 0;
881
+ loserTime = -1;
882
+ for (const mt of muteTargets) {
883
+ await tryMute(session, mt.id, mt.duration);
884
+ resultLines.push(`\u{1F507} ${mt.name} \u88AB\u7981\u8A00 ${mt.duration} \u79D2\uFF01`);
885
+ }
886
+ } else if (cTime !== null && tTime !== null) {
887
+ if (cTime < tTime) {
888
+ winnerId = challengerId;
889
+ winnerName = challengerName;
890
+ winnerTime = cTime;
891
+ loserId = targetId;
892
+ loserName = targetName;
893
+ loserTime = tTime;
894
+ } else {
895
+ winnerId = targetId;
896
+ winnerName = targetName;
897
+ winnerTime = tTime;
898
+ loserId = challengerId;
899
+ loserName = challengerName;
900
+ loserTime = cTime;
901
+ }
902
+ resultLines.push(`\u{1F52B} ${winnerName} \u62D4\u67AA\u66F4\u5FEB\uFF01`);
903
+ muteTargets.push({ id: loserId, name: loserName, duration: dc.lateMuteSeconds });
904
+ } else if (cTime !== null) {
905
+ winnerId = challengerId;
906
+ winnerName = challengerName;
907
+ winnerTime = cTime;
908
+ loserId = targetId;
909
+ loserName = targetName;
910
+ loserTime = -1;
911
+ resultLines.push(`\u{1F52B} ${winnerName} \u62D4\u67AA\u4E86\uFF0C${loserName} \u6CA1\u6709\u62D4\u67AA\uFF01`);
912
+ muteTargets.push({ id: loserId, name: loserName, duration: dc.lateMuteSeconds });
913
+ } else if (tTime !== null) {
914
+ winnerId = targetId;
915
+ winnerName = targetName;
916
+ winnerTime = tTime;
917
+ loserId = challengerId;
918
+ loserName = challengerName;
919
+ loserTime = -1;
920
+ resultLines.push(`\u{1F52B} ${winnerName} \u62D4\u67AA\u4E86\uFF0C${loserName} \u6CA1\u6709\u62D4\u67AA\uFF01`);
921
+ muteTargets.push({ id: loserId, name: loserName, duration: dc.lateMuteSeconds });
922
+ } else {
923
+ resultLines.push("\u{1F52B} \u53CC\u65B9\u90FD\u6CA1\u6709\u62D4\u67AA\uFF01");
924
+ muteTargets.push(
925
+ { id: challengerId, name: challengerName, duration: dc.lateMuteSeconds },
926
+ { id: targetId, name: targetName, duration: dc.lateMuteSeconds }
927
+ );
928
+ winnerId = "";
929
+ winnerName = "";
930
+ winnerTime = 0;
931
+ loserId = "";
932
+ loserName = "";
933
+ loserTime = -1;
934
+ }
935
+ for (const mt of muteTargets) {
936
+ const muted = await tryMute(session, mt.id, mt.duration);
937
+ resultLines.push(muted ? `\u{1F507} ${mt.name} \u88AB\u7981\u8A00 ${mt.duration} \u79D2\uFF01` : `\u{1F507} ${mt.name} \u7981\u8A00\u5931\u8D25\uFF08\u6743\u9650\u4E0D\u8DB3\uFF09`);
938
+ }
939
+ if (cTime !== null) {
940
+ resultLines.push(`${challengerName} \u7528\u65F6\uFF1A${cTime}ms`);
941
+ } else {
942
+ resultLines.push(`${challengerName} \u672A\u62D4\u67AA`);
943
+ }
944
+ if (tTime !== null) {
945
+ resultLines.push(`${targetName} \u7528\u65F6\uFF1A${tTime}ms`);
946
+ } else {
947
+ resultLines.push(`${targetName} \u672A\u62D4\u67AA`);
948
+ }
949
+ if (winnerId && loserId) {
950
+ try {
951
+ await ctx.database.create("lili_duel", {
952
+ gid,
953
+ winnerId,
954
+ winnerName,
955
+ loserId,
956
+ loserName,
957
+ winnerTime,
958
+ loserTime,
959
+ timestamp: Date.now()
960
+ });
961
+ } catch (e) {
962
+ dbg("\u5BF9\u51B3\u8BB0\u5F55\u5165\u5E93\u5931\u8D25", { gid, error: String(e) });
963
+ }
964
+ }
965
+ await session.send(resultLines.join("\n"));
966
+ cleanupDuel(gid);
967
+ }
968
+ ctx.middleware(async (session, next) => {
969
+ if (!config.duel.enabled) return next();
970
+ const gid = getGroupId(session);
971
+ if (!gid) return next();
972
+ if (!isGroupAllowed(gid, config.duel.groups, config.duel.groupMode)) return next();
973
+ const duel = duelStates.get(gid);
974
+ if (!duel) return next();
975
+ const text = (session.content || "").trim();
976
+ const userId = String(session.userId);
977
+ if (userId !== duel.challengerId && userId !== duel.targetId) return next();
978
+ if (duel.phase === "waiting_accept" && userId === duel.targetId && text === "\u63A5\u53D7") {
979
+ if (duel.acceptTimer) clearTimeout(duel.acceptTimer);
980
+ duel.acceptTimer = null;
981
+ const dc = config.duel;
982
+ duel.phase = "countdown";
983
+ duel.countdownEndTime = Date.now() + dc.countdownSeconds * 1e3;
984
+ duel.earlyDrawers = /* @__PURE__ */ new Set();
985
+ duel.drawTimes = /* @__PURE__ */ new Map();
986
+ dbg("\u5BF9\u51B3-\u5F00\u59CB\u5012\u8BA1\u65F6", { gid, countdownSeconds: dc.countdownSeconds, challenger: duel.challengerId, target: duel.targetId });
987
+ duel.countdownTimer = setTimeout(async () => {
988
+ const d = duelStates.get(gid);
989
+ if (!d || d.phase !== "countdown") return;
990
+ d.phase = "drawing";
991
+ try {
992
+ await duel.session.send("\u2694\uFE0F \u5348\u65F6\u5DF2\u5230\uFF01");
993
+ } catch {
994
+ }
995
+ dbg("\u5BF9\u51B3-\u62D4\u67AA\u9636\u6BB5", { gid });
996
+ d.drawTimer = setTimeout(() => {
997
+ const d2 = duelStates.get(gid);
998
+ if (!d2 || d2.phase !== "drawing") return;
999
+ resolveDuel(gid);
1000
+ }, dc.drawTimeoutSeconds * 1e3);
1001
+ }, dc.countdownSeconds * 1e3);
1002
+ return;
1003
+ }
1004
+ if (text === "\u62D4\u67AA" && (duel.phase === "countdown" || duel.phase === "drawing")) {
1005
+ const now = Date.now();
1006
+ if (duel.phase === "countdown") {
1007
+ duel.earlyDrawers.add(userId);
1008
+ const name3 = userId === duel.challengerId ? duel.challengerName : duel.targetName;
1009
+ await session.send(`\u26A0\uFE0F ${name3} \u63D0\u524D\u62D4\u67AA\uFF01`);
1010
+ dbg("\u5BF9\u51B3-\u63D0\u524D\u62D4\u67AA", { gid, userId, name: name3 });
1011
+ if (duel.earlyDrawers.size >= 2) {
1012
+ duel.drawTimes.set(userId, now);
1013
+ const otherId = userId === duel.challengerId ? duel.targetId : duel.challengerId;
1014
+ if (!duel.drawTimes.has(otherId)) duel.drawTimes.set(otherId, now);
1015
+ resolveDuel(gid);
1016
+ }
1017
+ return;
1018
+ }
1019
+ if (duel.drawTimes.has(userId)) {
1020
+ await session.send("\u4F60\u5DF2\u7ECF\u62D4\u8FC7\u67AA\u4E86\uFF01");
1021
+ return;
1022
+ }
1023
+ const reactionTime = now - duel.countdownEndTime;
1024
+ duel.drawTimes.set(userId, reactionTime);
1025
+ const name2 = userId === duel.challengerId ? duel.challengerName : duel.targetName;
1026
+ dbg("\u5BF9\u51B3-\u62D4\u67AA", { gid, userId, name: name2, reactionTime });
1027
+ if (duel.drawTimes.has(duel.challengerId) && duel.drawTimes.has(duel.targetId)) {
1028
+ resolveDuel(gid);
1029
+ }
1030
+ return;
1031
+ }
1032
+ return next();
1033
+ });
744
1034
  ctx.middleware(async (session, next) => {
745
1035
  const gid = getGroupId(session);
746
1036
  const content = session.content || "";
@@ -751,17 +1041,83 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
751
1041
  if (botId && String(session.userId) === String(botId)) return next();
752
1042
  const isFwd = isForwardMessage(session);
753
1043
  let forwardTexts = [];
1044
+ async function fetchForwardTextsRecursive(msgId, depth) {
1045
+ if (depth > 3) return [];
1046
+ const results = [];
1047
+ try {
1048
+ const resp = await (session.onebot?.internal || session.bot?.internal)?.getForwardMsg?.(msgId);
1049
+ if (!resp) return results;
1050
+ let nodes = [];
1051
+ if (Array.isArray(resp)) {
1052
+ nodes = resp;
1053
+ } else if (resp?.messages && Array.isArray(resp.messages)) {
1054
+ nodes = resp.messages;
1055
+ } else if (resp?.data?.messages && Array.isArray(resp.data.messages)) {
1056
+ nodes = resp.data.messages;
1057
+ } else if (resp?.data && Array.isArray(resp.data)) {
1058
+ nodes = resp.data;
1059
+ }
1060
+ for (const node of nodes) {
1061
+ const content2 = node.content || node.data && node.data.content;
1062
+ if (Array.isArray(content2)) {
1063
+ const text = normalizeText(
1064
+ content2.filter((seg) => seg.type === "text").map((seg) => seg.data?.text || "").join("")
1065
+ );
1066
+ if (text) results.push(text);
1067
+ for (const seg of content2) {
1068
+ if (seg.type === "image") {
1069
+ const fileId = seg.data?.file || seg.data?.url || "";
1070
+ if (fileId) results.push(`[img:${fileId}]`);
1071
+ }
1072
+ if (seg.type === "face") {
1073
+ const faceId = seg.data?.id || "";
1074
+ if (faceId) results.push(`[face:${faceId}]`);
1075
+ }
1076
+ if (seg.type === "mface") {
1077
+ const emojiId = seg.data?.emoji_id || seg.data?.emojiId || "";
1078
+ if (emojiId) results.push(`[mface:${emojiId}]`);
1079
+ }
1080
+ if ((seg.type === "forward" || seg.type === "node") && seg.data?.id) {
1081
+ const nested = await fetchForwardTextsRecursive(String(seg.data.id), depth + 1);
1082
+ results.push(...nested);
1083
+ }
1084
+ }
1085
+ } else if (typeof content2 === "string") {
1086
+ const text = normalizeText(content2);
1087
+ if (text) results.push(text);
1088
+ }
1089
+ }
1090
+ } catch (e) {
1091
+ dbg("\u9012\u5F52\u83B7\u53D6\u8F6C\u53D1\u6D88\u606F\u5931\u8D25", { gid, msgId, error: String(e) });
1092
+ }
1093
+ return results;
1094
+ }
754
1095
  if (isFwd) {
755
- forwardTexts = extractForwardTexts(session);
1096
+ const topNodeIds = [];
1097
+ if (session.elements) {
1098
+ for (const el of session.elements) {
1099
+ if ((el.type === "node" || el.type === "forward") && el.attrs?.id) {
1100
+ topNodeIds.push(String(el.attrs.id));
1101
+ }
1102
+ }
1103
+ }
1104
+ if (topNodeIds.length > 0) {
1105
+ dbg("\u8F6C\u53D1\u6D88\u606F-\u5F00\u59CB\u9012\u5F52\u83B7\u53D6", { gid, topNodeIds });
1106
+ for (const msgId of topNodeIds) {
1107
+ const texts = await fetchForwardTextsRecursive(msgId, 1);
1108
+ forwardTexts.push(...texts);
1109
+ }
1110
+ forwardTexts = [...new Set(forwardTexts)];
1111
+ }
756
1112
  dbg("\u8F6C\u53D1\u6D88\u606F\u68C0\u6D4B", {
757
1113
  gid,
758
1114
  userId: session.userId,
759
1115
  elementTypes: session.elements?.map((e) => e.type) || [],
760
1116
  forwardTextsCount: forwardTexts.length,
761
- forwardTextsPreview: forwardTexts.slice(0, 3).map((t) => t.substring(0, 30))
1117
+ forwardTextsPreview: forwardTexts.slice(0, 5).map((t) => t.substring(0, 30))
762
1118
  });
763
1119
  }
764
- if (config.dedup.enabled && isGroupAllowed(gid, config.dedup.groups)) {
1120
+ if (config.dedup.enabled && isGroupAllowed(gid, config.dedup.groups, config.dedup.groupMode)) {
765
1121
  dbg("\u67E5\u91CD-\u4E2D\u95F4\u4EF6\u5165\u53E3", {
766
1122
  gid,
767
1123
  userId: session.userId,
@@ -771,7 +1127,7 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
771
1127
  contentPreview: normalizedText.substring(0, 50),
772
1128
  forwardTextsCount: forwardTexts.length
773
1129
  });
774
- if (isFwd) {
1130
+ if (isFwd && forwardTexts.length > 0) {
775
1131
  const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
776
1132
  dbg("\u67E5\u91CD\u68C0\u6D4B", { gid, forwardTextsCount: forwardTexts.length });
777
1133
  for (const fwdText of forwardTexts) {
@@ -782,40 +1138,15 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
782
1138
  if (matches && matches.length > 0 && matches[0].timestamp >= sevenDaysAgo) {
783
1139
  const original = matches[0];
784
1140
  const dateStr = new Date(original.timestamp).toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" });
785
- await session.send(`\u{1F4A7} \u6C34\u8FC7\u4E86\uFF01${import_koishi.segment.at(session.userId)} \u8FD9\u6761\u6D88\u606F ${import_koishi.segment.at(original.userId)} \u5728 ${dateStr} \u5C31\u53D1\u8FC7\u4E86\uFF01`);
1141
+ await session.send([
1142
+ (0, import_koishi.h)("quote", { id: original.messageId }),
1143
+ (0, import_koishi.h)("at", { id: session.userId }),
1144
+ import_koishi.h.text(` \u{1F4A7} \u6C34\u8FC7\u4E86\uFF01\u8FD9\u6761\u6D88\u606F\u5728 ${dateStr} \u5C31\u53D1\u8FC7\u4E86\uFF01`)
1145
+ ]);
786
1146
  return next();
787
1147
  }
788
- } catch {
789
- }
790
- }
791
- if (forwardTexts.length === 0 && session.elements) {
792
- const nodeIds = [];
793
- for (const el of session.elements) {
794
- if ((el.type === "node" || el.type === "forward") && el.attrs?.id && !el.attrs?.content) {
795
- nodeIds.push(el.attrs.id);
796
- }
797
- }
798
- if (nodeIds.length > 0) {
799
- dbg("\u67E5\u91CD-\u901A\u8FC7 get_forward_msg \u83B7\u53D6\u8282\u70B9\u5185\u5BB9", { gid, nodeIds });
800
- for (const msgId of nodeIds) {
801
- try {
802
- const resp = await (session.onebot?.internal || session.bot?.internal)?.getForwardMsg?.(msgId);
803
- if (resp?.messages) {
804
- for (const node of resp.messages) {
805
- const nodeText = normalizeText(typeof node.content === "string" ? node.content : "");
806
- if (!nodeText) continue;
807
- const matches = await ctx.database.get("lili_message", { gid, content: nodeText }, { sort: { timestamp: "asc" }, limit: 1 });
808
- if (matches && matches.length > 0 && matches[0].timestamp >= sevenDaysAgo) {
809
- const original = matches[0];
810
- const dateStr = new Date(original.timestamp).toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" });
811
- await session.send(`\u{1F4A7} \u6C34\u8FC7\u4E86\uFF01${import_koishi.segment.at(session.userId)} \u8FD9\u6761\u6D88\u606F ${import_koishi.segment.at(original.userId)} \u5728 ${dateStr} \u5C31\u53D1\u8FC7\u4E86\uFF01`);
812
- return next();
813
- }
814
- }
815
- }
816
- } catch {
817
- }
818
- }
1148
+ } catch (e) {
1149
+ dbg("\u67E5\u91CD\u67E5\u8BE2\u5F02\u5E38", { gid, error: String(e) });
819
1150
  }
820
1151
  }
821
1152
  }
@@ -823,8 +1154,8 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
823
1154
  const imitationGroups = parseGroupList(config.imitation.groups);
824
1155
  const dedupGroups = parseGroupList(config.dedup.groups);
825
1156
  const foldGroups = config.fold.enabled ? parseGroupList(config.fold.groups) : [];
826
- const dedupInGroup = config.dedup.enabled && isGroupAllowed(gid, config.dedup.groups);
827
- const foldInGroup = config.fold.enabled && isGroupAllowed(gid, config.fold.groups);
1157
+ const dedupInGroup = config.dedup.enabled && isGroupAllowed(gid, config.dedup.groups, config.dedup.groupMode);
1158
+ const foldInGroup = config.fold.enabled && isGroupAllowed(gid, config.fold.groups, config.fold.groupMode);
828
1159
  const shouldRecordAll = foldInGroup || dedupInGroup;
829
1160
  const shouldRecordLimited = textLen >= 15 && textLen <= 60 && normalizedText;
830
1161
  const recordGroups = /* @__PURE__ */ new Set([...imitationGroups, ...dedupGroups, ...foldGroups]);
@@ -854,13 +1185,13 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
854
1185
  timestamp: Date.now(),
855
1186
  messageId: session.messageId || ""
856
1187
  });
857
- dbg("\u8F6C\u53D1\u6D88\u606F\u6587\u5B57\u5DF2\u5165\u5E93", { gid, userId: session.userId, contentLen: fwdText.length });
1188
+ dbg("\u8F6C\u53D1\u6D88\u606F\u5185\u5BB9\u5DF2\u5165\u5E93", { gid, userId: session.userId, contentLen: fwdText.length, content: fwdText });
858
1189
  } catch (e) {
859
1190
  dbg("\u8F6C\u53D1\u6D88\u606F\u5165\u5E93\u5931\u8D25", { gid, error: String(e) });
860
1191
  }
861
1192
  }
862
1193
  }
863
- if (shouldRecord && !isFwd && normalizedText) {
1194
+ if (shouldRecord && !isFwd && normalizedText && textLen >= 15 && textLen <= 60) {
864
1195
  try {
865
1196
  await ctx.database.create("lili_message", {
866
1197
  gid,
@@ -875,7 +1206,7 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
875
1206
  dbg("\u6D88\u606F\u5165\u5E93\u5931\u8D25", { gid, error: String(e) });
876
1207
  }
877
1208
  }
878
- if (config.imitation.enabled && isGroupAllowed(gid, config.imitation.groups)) {
1209
+ if (config.imitation.enabled && isGroupAllowed(gid, config.imitation.groups, config.imitation.groupMode)) {
879
1210
  let count = imitationCounters.get(gid) || 0;
880
1211
  count++;
881
1212
  imitationCounters.set(gid, count);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-lili-hub",
3
3
  "description": "丽丽Hub — 自用丽丽主题QQ群娱乐插件:俄罗斯轮盘赌、喝酒发酒疯、模仿群友说话、合并消息查重(水过了)",
4
- "version": "0.2.2",
4
+ "version": "0.3.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [