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.
- package/lib/index.js +413 -82
- 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("\
|
|
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("\
|
|
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("\
|
|
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("\
|
|
274
|
-
|
|
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
|
|
508
|
-
if (
|
|
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
|
|
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 ${
|
|
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 ${
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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\
|
|
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);
|