koishi-plugin-lili-hub 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +442 -39
- 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,37 @@ 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"),
|
|
263
267
|
minutes: import_koishi.Schema.number().description("\u6298\u53E0\u65F6\u95F4\u8303\u56F4\uFF08\u5206\u949F\uFF09").default(10).min(1).max(1440)
|
|
264
268
|
}).description("\u{1F4E6} \u4E3D\u4E3D\u6298\u53E0"),
|
|
265
269
|
imitation: import_koishi.Schema.object({
|
|
266
270
|
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("\
|
|
271
|
+
groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
|
|
272
|
+
groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist"),
|
|
268
273
|
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
274
|
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
275
|
}).description("\u{1F5E3}\uFE0F \u6A21\u4EFF\u7FA4\u53CB"),
|
|
271
276
|
dedup: import_koishi.Schema.object({
|
|
272
277
|
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
|
-
|
|
278
|
+
groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
|
|
279
|
+
groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist")
|
|
280
|
+
}).description("\u{1F4A7} \u67E5\u91CD"),
|
|
281
|
+
duel: import_koishi.Schema.object({
|
|
282
|
+
enabled: import_koishi.Schema.boolean().description("\u542F\u7528\u4E3D\u4E3D\u5BF9\u51B3\u529F\u80FD").default(false),
|
|
283
|
+
groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
|
|
284
|
+
groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist"),
|
|
285
|
+
countdownSeconds: import_koishi.Schema.number().description("\u5012\u8BA1\u65F6\u79D2\u6570").default(5).min(1).max(30),
|
|
286
|
+
acceptTimeoutSeconds: import_koishi.Schema.number().description("\u7B49\u5F85\u63A5\u53D7\u8D85\u65F6\uFF08\u79D2\uFF09").default(30).min(5).max(120),
|
|
287
|
+
drawTimeoutSeconds: import_koishi.Schema.number().description("\u62D4\u67AA\u7A97\u53E3\u8D85\u65F6\uFF08\u79D2\uFF09").default(10).min(3).max(60),
|
|
288
|
+
earlyDrawMuteSeconds: import_koishi.Schema.number().description("\u63D0\u524D\u62D4\u67AA\u7981\u8A00\u65F6\u957F\uFF08\u79D2\uFF09").default(600).min(0).max(2592e3),
|
|
289
|
+
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)
|
|
290
|
+
}).description("\u2694\uFE0F \u4E3D\u4E3D\u5BF9\u51B3"),
|
|
291
|
+
chain: import_koishi.Schema.object({
|
|
292
|
+
enabled: import_koishi.Schema.boolean().description("\u542F\u7528\u7FA4\u63A5\u9F99\u529F\u80FD").default(false),
|
|
293
|
+
groups: import_koishi.Schema.string().description("\u7FA4\u53F7\u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").default(""),
|
|
294
|
+
groupMode: import_koishi.Schema.union(["whitelist", "blacklist"]).description("\u7FA4\u7EC4\u8FC7\u6EE4\u6A21\u5F0F\uFF1A\u767D\u540D\u5355 / \u9ED1\u540D\u5355").default("whitelist")
|
|
295
|
+
}).description("\u{1F4DD} \u7FA4\u63A5\u9F99")
|
|
275
296
|
});
|
|
276
297
|
function getGroupId(session) {
|
|
277
298
|
return session.guildId || session.channelId;
|
|
@@ -289,9 +310,12 @@ function parseGroupList(raw) {
|
|
|
289
310
|
function normalizeText(text) {
|
|
290
311
|
return text.replace(/\[CQ:[^\]]*\]/g, "").replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
|
|
291
312
|
}
|
|
292
|
-
function isGroupAllowed(gid, groups) {
|
|
313
|
+
function isGroupAllowed(gid, groups, mode = "whitelist") {
|
|
293
314
|
const list = parseGroupList(groups);
|
|
294
315
|
if (list.length === 0) return true;
|
|
316
|
+
if (mode === "blacklist") {
|
|
317
|
+
return !list.includes(gid);
|
|
318
|
+
}
|
|
295
319
|
return list.includes(gid);
|
|
296
320
|
}
|
|
297
321
|
function getMultiKillEvent(v, killCount) {
|
|
@@ -354,9 +378,30 @@ function apply(ctx, config) {
|
|
|
354
378
|
voteType: "string",
|
|
355
379
|
timestamp: "unsigned"
|
|
356
380
|
}, { autoInc: true });
|
|
381
|
+
ctx.model.extend("lili_duel", {
|
|
382
|
+
id: "unsigned",
|
|
383
|
+
gid: "string",
|
|
384
|
+
winnerId: "string",
|
|
385
|
+
winnerName: "string",
|
|
386
|
+
loserId: "string",
|
|
387
|
+
loserName: "string",
|
|
388
|
+
winnerTime: "unsigned",
|
|
389
|
+
loserTime: "unsigned",
|
|
390
|
+
timestamp: "unsigned"
|
|
391
|
+
}, { autoInc: true });
|
|
357
392
|
const drinkStates = /* @__PURE__ */ new Map();
|
|
358
393
|
const rouletteStates = /* @__PURE__ */ new Map();
|
|
359
394
|
const imitationCounters = /* @__PURE__ */ new Map();
|
|
395
|
+
const duelStates = /* @__PURE__ */ new Map();
|
|
396
|
+
const chainStates = /* @__PURE__ */ new Map();
|
|
397
|
+
function formatChain(chain) {
|
|
398
|
+
const lines = [chain.content];
|
|
399
|
+
for (let i = 0; i < chain.participants.length; i++) {
|
|
400
|
+
const p = chain.participants[i];
|
|
401
|
+
lines.push(`${i + 1}.${p.userName}\uFF08${p.userId}\uFF09`);
|
|
402
|
+
}
|
|
403
|
+
return lines.join("\n");
|
|
404
|
+
}
|
|
360
405
|
function isDrunk(gid) {
|
|
361
406
|
const s = drinkStates.get(gid);
|
|
362
407
|
if (!s || s.drunkUntil === 0) return false;
|
|
@@ -535,6 +580,7 @@ function apply(ctx, config) {
|
|
|
535
580
|
ctx.command("\u4E3D\u4E3D\u8F6E\u76D8", "\u4FC4\u7F57\u65AF\u8F6E\u76D8\u8D4C").alias("\u4E3D\u4E3D\u5F00\u67AA").action(async ({ session }) => {
|
|
536
581
|
if (!session?.userId) return;
|
|
537
582
|
const gid = getGroupId(session);
|
|
583
|
+
if (!isGroupAllowed(gid, config.roulette.groups, config.roulette.groupMode)) return;
|
|
538
584
|
if (!rouletteStates.has(gid)) {
|
|
539
585
|
const bullet = randInt(1, config.roulette.chamberSize);
|
|
540
586
|
const startTime = Date.now();
|
|
@@ -568,6 +614,7 @@ function apply(ctx, config) {
|
|
|
568
614
|
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 }) => {
|
|
569
615
|
if (!session?.userId) return;
|
|
570
616
|
const gid = getGroupId(session);
|
|
617
|
+
if (!isGroupAllowed(gid, config.roulette.groups, config.roulette.groupMode)) return;
|
|
571
618
|
if (isDrunk(gid)) {
|
|
572
619
|
await playEffect(session, config.voice.stillDrunk, 500);
|
|
573
620
|
return;
|
|
@@ -616,7 +663,7 @@ function apply(ctx, config) {
|
|
|
616
663
|
const gid = getGroupId(session);
|
|
617
664
|
const vm = config.voteMute;
|
|
618
665
|
if (!vm.enabled) return;
|
|
619
|
-
if (!isGroupAllowed(gid, vm.groups)) return;
|
|
666
|
+
if (!isGroupAllowed(gid, vm.groups, vm.groupMode)) return;
|
|
620
667
|
const targetId = extractTarget(session, targetUser);
|
|
621
668
|
if (!targetId) return "\u{1F507} \u65E0\u6CD5\u89E3\u6790\u76EE\u6807\u7528\u6237\u3002\u8BF7\u4F7F\u7528 @ \u529F\u80FD\u9009\u62E9\u76EE\u6807\u3002";
|
|
622
669
|
if (targetId === session.userId) return "\u{1F507} \u4E0D\u80FD\u7ED9\u81EA\u5DF1\u6295\u7968\u3002";
|
|
@@ -648,7 +695,7 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u7981\u8A00 ${timeStr}\u3002`
|
|
|
648
695
|
const gid = getGroupId(session);
|
|
649
696
|
const vm = config.voteMute;
|
|
650
697
|
if (!vm.enabled) return;
|
|
651
|
-
if (!isGroupAllowed(gid, vm.groups)) return;
|
|
698
|
+
if (!isGroupAllowed(gid, vm.groups, vm.groupMode)) return;
|
|
652
699
|
const targetId = extractTarget(session, targetUser);
|
|
653
700
|
if (!targetId) return "\u{1F50A} \u65E0\u6CD5\u89E3\u6790\u76EE\u6807\u7528\u6237\u3002\u8BF7\u4F7F\u7528 @ \u529F\u80FD\u9009\u62E9\u76EE\u6807\u3002";
|
|
654
701
|
try {
|
|
@@ -669,22 +716,26 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
|
|
|
669
716
|
return `\u{1F50A} \u5DF2\u64A4\u56DE\u4F60\u5BF9 ${import_koishi.segment.at(targetId)} \u7684\u7981\u8A00\u7968\u3002
|
|
670
717
|
\u{1F4CA} \u5F53\u524D\u7981\u8A00\u7968\uFF1A${muteCount}\uFF08\u9700 \u2264 ${vm.unmuteThreshold} \u624D\u4F1A\u89E3\u7981\uFF09`;
|
|
671
718
|
});
|
|
672
|
-
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) => {
|
|
719
|
+
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) => {
|
|
673
720
|
if (!session?.userId) return;
|
|
674
721
|
const gid = getGroupId(session);
|
|
675
722
|
const fc = config.fold;
|
|
676
723
|
if (!fc.enabled) return;
|
|
677
|
-
if (!isGroupAllowed(gid, fc.groups)) return;
|
|
724
|
+
if (!isGroupAllowed(gid, fc.groups, fc.groupMode)) return;
|
|
678
725
|
const targetId = extractTarget(session, targetUser);
|
|
679
726
|
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";
|
|
680
|
-
const
|
|
727
|
+
const foldedMinutes = typeof minutesArg === "number" && minutesArg >= 1 && minutesArg <= 1440 ? minutesArg : fc.minutes;
|
|
728
|
+
const since = Date.now() - foldedMinutes * 60 * 1e3;
|
|
729
|
+
dbg("\u6298\u53E0-\u67E5\u8BE2", { gid, targetId, since: new Date(since).toLocaleTimeString("zh-CN"), foldedMinutes });
|
|
681
730
|
let messages;
|
|
682
731
|
try {
|
|
683
732
|
messages = await ctx.database.get("lili_message", { gid, userId: targetId, timestamp: { $gte: since } }, { sort: { timestamp: "asc" }, limit: 100 });
|
|
684
|
-
} catch {
|
|
733
|
+
} catch (e) {
|
|
734
|
+
dbg("\u6298\u53E0-\u67E5\u8BE2\u5931\u8D25", { gid, error: String(e) });
|
|
685
735
|
return "\u{1F4E6} \u67E5\u8BE2\u6D88\u606F\u5931\u8D25\u3002";
|
|
686
736
|
}
|
|
687
|
-
|
|
737
|
+
dbg("\u6298\u53E0-\u67E5\u8BE2\u7ED3\u679C", { gid, targetId, count: messages?.length || 0 });
|
|
738
|
+
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`;
|
|
688
739
|
const nodes = messages.map((m) => ({
|
|
689
740
|
type: "node",
|
|
690
741
|
data: { name: m.userName, uin: m.userId, content: m.content, time: String(Math.floor(m.timestamp / 1e3)) }
|
|
@@ -704,7 +755,7 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
|
|
|
704
755
|
const time = new Date(m.timestamp).toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" });
|
|
705
756
|
return `[${time}] ${m.userName}\uFF1A${m.content}`;
|
|
706
757
|
});
|
|
707
|
-
await session.send(`\u{1F4E6} \u4E3D\u4E3D\u6298\u53E0\u4E86 ${import_koishi.segment.at(targetId)} \u6700\u8FD1 ${
|
|
758
|
+
await session.send(`\u{1F4E6} \u4E3D\u4E3D\u6298\u53E0\u4E86 ${import_koishi.segment.at(targetId)} \u6700\u8FD1 ${foldedMinutes} \u5206\u949F\u7684\u6D88\u606F\uFF1A
|
|
708
759
|
` + lines.join("\n"));
|
|
709
760
|
}
|
|
710
761
|
for (const m of messages) {
|
|
@@ -716,6 +767,348 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
|
|
|
716
767
|
}
|
|
717
768
|
}
|
|
718
769
|
});
|
|
770
|
+
ctx.command("\u4E3D\u4E3D\u5BF9\u51B3 <user:user>", "\u53D1\u8D77\u5BF9\u51B3").action(async ({ session }, targetUser) => {
|
|
771
|
+
if (!session?.userId) return;
|
|
772
|
+
const gid = getGroupId(session);
|
|
773
|
+
const dc = config.duel;
|
|
774
|
+
if (!dc.enabled) return;
|
|
775
|
+
if (!isGroupAllowed(gid, dc.groups, dc.groupMode)) return;
|
|
776
|
+
const targetId = extractTarget(session, targetUser);
|
|
777
|
+
if (!targetId) return "\u2694\uFE0F \u65E0\u6CD5\u89E3\u6790\u76EE\u6807\u7528\u6237\u3002\u8BF7\u4F7F\u7528 @ \u529F\u80FD\u9009\u62E9\u76EE\u6807\u3002";
|
|
778
|
+
if (targetId === String(session.userId)) return "\u2694\uFE0F \u4E0D\u80FD\u5411\u81EA\u5DF1\u53D1\u8D77\u5BF9\u51B3\uFF01";
|
|
779
|
+
const botId = session.bot.userId || session.bot.selfId;
|
|
780
|
+
if (botId && targetId === String(botId)) return "\u2694\uFE0F \u4E0D\u80FD\u5411 Bot \u53D1\u8D77\u5BF9\u51B3\uFF01";
|
|
781
|
+
const existing = duelStates.get(gid);
|
|
782
|
+
if (existing && existing.phase !== "finished") {
|
|
783
|
+
return "\u2694\uFE0F \u672C\u7FA4\u6B63\u5728\u8FDB\u884C\u4E00\u573A\u5BF9\u51B3\uFF0C\u8BF7\u7B49\u5F85\u7ED3\u675F\u540E\u518D\u53D1\u8D77\uFF01";
|
|
784
|
+
}
|
|
785
|
+
const challengerId = String(session.userId);
|
|
786
|
+
const challengerName = session.username || challengerId;
|
|
787
|
+
const targetName = session.elements?.find((el) => el.type === "at")?.attrs?.name || targetId;
|
|
788
|
+
const duel = {
|
|
789
|
+
challengerId,
|
|
790
|
+
challengerName,
|
|
791
|
+
targetId,
|
|
792
|
+
targetName,
|
|
793
|
+
session,
|
|
794
|
+
phase: "waiting_accept",
|
|
795
|
+
countdownEndTime: 0,
|
|
796
|
+
earlyDrawers: /* @__PURE__ */ new Set(),
|
|
797
|
+
drawTimes: /* @__PURE__ */ new Map(),
|
|
798
|
+
acceptTimer: null,
|
|
799
|
+
countdownTimer: null,
|
|
800
|
+
drawTimer: null
|
|
801
|
+
};
|
|
802
|
+
duel.acceptTimer = setTimeout(() => {
|
|
803
|
+
const d = duelStates.get(gid);
|
|
804
|
+
if (d && d.phase === "waiting_accept") {
|
|
805
|
+
session.send(`\u23F0 \u5BF9\u51B3\u8D85\u65F6\uFF01${targetName} \u672A\u5728 ${dc.acceptTimeoutSeconds} \u79D2\u5185\u63A5\u53D7\u6311\u6218\u3002`);
|
|
806
|
+
cleanupDuel(gid);
|
|
807
|
+
}
|
|
808
|
+
}, dc.acceptTimeoutSeconds * 1e3);
|
|
809
|
+
duelStates.set(gid, duel);
|
|
810
|
+
dbg("\u5BF9\u51B3-\u53D1\u8D77", { gid, challengerId, challengerName, targetId, targetName });
|
|
811
|
+
return `\u2694\uFE0F ${challengerName} \u5411 ${import_koishi.segment.at(targetId)} \u53D1\u8D77\u4E86\u5BF9\u51B3\uFF01
|
|
812
|
+
\u56DE\u590D"\u63A5\u53D7"\u5E94\u6218\uFF08${dc.acceptTimeoutSeconds}\u79D2\u5185\u6709\u6548\uFF09`;
|
|
813
|
+
});
|
|
814
|
+
ctx.command("\u4E3D\u4E3D\u5BF9\u51B3\u7FA4\u699C", "\u67E5\u770B\u672C\u7FA4\u5BF9\u51B3\u6392\u884C\u699C").action(async ({ session }) => {
|
|
815
|
+
const gid = getGroupId(session);
|
|
816
|
+
try {
|
|
817
|
+
const records = await ctx.database.get("lili_duel", { gid }, {
|
|
818
|
+
sort: { winnerTime: "asc" },
|
|
819
|
+
limit: 10
|
|
820
|
+
});
|
|
821
|
+
if (!records || records.length === 0) return "\u{1F3C6} \u672C\u7FA4\u6682\u65E0\u5BF9\u51B3\u8BB0\u5F55\u3002";
|
|
822
|
+
const lines = ["\u{1F3C6} \u4E3D\u4E3D\u5BF9\u51B3 \u7FA4\u6392\u884C\u699C"];
|
|
823
|
+
for (let i = 0; i < records.length; i++) {
|
|
824
|
+
const r = records[i];
|
|
825
|
+
const time = new Date(r.timestamp).toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" });
|
|
826
|
+
lines.push(`${i + 1}. ${r.winnerName} ${r.winnerTime}ms \u26A1\u80DC ${r.loserName} ${r.loserTime >= 0 ? r.loserTime + "ms" : "\u672A\u62D4\u67AA"} ${time}`);
|
|
827
|
+
}
|
|
828
|
+
return lines.join("\n");
|
|
829
|
+
} catch {
|
|
830
|
+
return "\u{1F3C6} \u67E5\u8BE2\u6392\u884C\u699C\u5931\u8D25\u3002";
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
ctx.command("\u4E3D\u4E3D\u5BF9\u51B3\u603B\u699C", "\u67E5\u770B\u5168\u7FA4\u5BF9\u51B3\u6392\u884C\u699C").action(async () => {
|
|
834
|
+
try {
|
|
835
|
+
const records = await ctx.database.get("lili_duel", {}, {
|
|
836
|
+
sort: { winnerTime: "asc" },
|
|
837
|
+
limit: 10
|
|
838
|
+
});
|
|
839
|
+
if (!records || records.length === 0) return "\u{1F3C6} \u6682\u65E0\u5BF9\u51B3\u8BB0\u5F55\u3002";
|
|
840
|
+
const lines = ["\u{1F3C6} \u4E3D\u4E3D\u5BF9\u51B3 \u603B\u6392\u884C\u699C"];
|
|
841
|
+
for (let i = 0; i < records.length; i++) {
|
|
842
|
+
const r = records[i];
|
|
843
|
+
const time = new Date(r.timestamp).toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" });
|
|
844
|
+
lines.push(`${i + 1}. ${r.winnerName} ${r.winnerTime}ms \u26A1\u80DC ${r.loserName} ${r.loserTime >= 0 ? r.loserTime + "ms" : "\u672A\u62D4\u67AA"} ${time}`);
|
|
845
|
+
}
|
|
846
|
+
return lines.join("\n");
|
|
847
|
+
} catch {
|
|
848
|
+
return "\u{1F3C6} \u67E5\u8BE2\u6392\u884C\u699C\u5931\u8D25\u3002";
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
function cleanupDuel(gid) {
|
|
852
|
+
const duel = duelStates.get(gid);
|
|
853
|
+
if (!duel) return;
|
|
854
|
+
if (duel.acceptTimer) clearTimeout(duel.acceptTimer);
|
|
855
|
+
if (duel.countdownTimer) clearTimeout(duel.countdownTimer);
|
|
856
|
+
if (duel.drawTimer) clearTimeout(duel.drawTimer);
|
|
857
|
+
duelStates.delete(gid);
|
|
858
|
+
}
|
|
859
|
+
async function resolveDuel(gid) {
|
|
860
|
+
const duel = duelStates.get(gid);
|
|
861
|
+
if (!duel || duel.phase === "finished") return;
|
|
862
|
+
duel.phase = "finished";
|
|
863
|
+
const dc = config.duel;
|
|
864
|
+
const { challengerId, challengerName, targetId, targetName, drawTimes, earlyDrawers, session } = duel;
|
|
865
|
+
if (duel.acceptTimer) clearTimeout(duel.acceptTimer);
|
|
866
|
+
if (duel.countdownTimer) clearTimeout(duel.countdownTimer);
|
|
867
|
+
if (duel.drawTimer) clearTimeout(duel.drawTimer);
|
|
868
|
+
const cTime = drawTimes.get(challengerId) ?? null;
|
|
869
|
+
const tTime = drawTimes.get(targetId) ?? null;
|
|
870
|
+
let winnerId, winnerName, loserId, loserName;
|
|
871
|
+
let winnerTime, loserTime;
|
|
872
|
+
let muteTargets = [];
|
|
873
|
+
let resultLines = [];
|
|
874
|
+
if (earlyDrawers.size > 0) {
|
|
875
|
+
for (const id of earlyDrawers) {
|
|
876
|
+
const name2 = id === challengerId ? challengerName : targetName;
|
|
877
|
+
muteTargets.push({ id, name: name2, duration: dc.earlyDrawMuteSeconds });
|
|
878
|
+
resultLines.push(`\u26A0\uFE0F ${name2} \u63D0\u524D\u62D4\u67AA\uFF01`);
|
|
879
|
+
}
|
|
880
|
+
const otherId = earlyDrawers.has(challengerId) ? targetId : challengerId;
|
|
881
|
+
const otherName = otherId === challengerId ? challengerName : targetName;
|
|
882
|
+
winnerId = otherId;
|
|
883
|
+
winnerName = otherName;
|
|
884
|
+
loserId = [...earlyDrawers][0];
|
|
885
|
+
loserName = loserId === challengerId ? challengerName : targetName;
|
|
886
|
+
winnerTime = drawTimes.get(otherId) ?? 0;
|
|
887
|
+
loserTime = -1;
|
|
888
|
+
for (const mt of muteTargets) {
|
|
889
|
+
await tryMute(session, mt.id, mt.duration);
|
|
890
|
+
resultLines.push(`\u{1F507} ${mt.name} \u88AB\u7981\u8A00 ${mt.duration} \u79D2\uFF01`);
|
|
891
|
+
}
|
|
892
|
+
} else if (cTime !== null && tTime !== null) {
|
|
893
|
+
if (cTime < tTime) {
|
|
894
|
+
winnerId = challengerId;
|
|
895
|
+
winnerName = challengerName;
|
|
896
|
+
winnerTime = cTime;
|
|
897
|
+
loserId = targetId;
|
|
898
|
+
loserName = targetName;
|
|
899
|
+
loserTime = tTime;
|
|
900
|
+
} else {
|
|
901
|
+
winnerId = targetId;
|
|
902
|
+
winnerName = targetName;
|
|
903
|
+
winnerTime = tTime;
|
|
904
|
+
loserId = challengerId;
|
|
905
|
+
loserName = challengerName;
|
|
906
|
+
loserTime = cTime;
|
|
907
|
+
}
|
|
908
|
+
resultLines.push(`\u{1F52B} ${winnerName} \u62D4\u67AA\u66F4\u5FEB\uFF01`);
|
|
909
|
+
muteTargets.push({ id: loserId, name: loserName, duration: dc.lateMuteSeconds });
|
|
910
|
+
} else if (cTime !== null) {
|
|
911
|
+
winnerId = challengerId;
|
|
912
|
+
winnerName = challengerName;
|
|
913
|
+
winnerTime = cTime;
|
|
914
|
+
loserId = targetId;
|
|
915
|
+
loserName = targetName;
|
|
916
|
+
loserTime = -1;
|
|
917
|
+
resultLines.push(`\u{1F52B} ${winnerName} \u62D4\u67AA\u4E86\uFF0C${loserName} \u6CA1\u6709\u62D4\u67AA\uFF01`);
|
|
918
|
+
muteTargets.push({ id: loserId, name: loserName, duration: dc.lateMuteSeconds });
|
|
919
|
+
} else if (tTime !== null) {
|
|
920
|
+
winnerId = targetId;
|
|
921
|
+
winnerName = targetName;
|
|
922
|
+
winnerTime = tTime;
|
|
923
|
+
loserId = challengerId;
|
|
924
|
+
loserName = challengerName;
|
|
925
|
+
loserTime = -1;
|
|
926
|
+
resultLines.push(`\u{1F52B} ${winnerName} \u62D4\u67AA\u4E86\uFF0C${loserName} \u6CA1\u6709\u62D4\u67AA\uFF01`);
|
|
927
|
+
muteTargets.push({ id: loserId, name: loserName, duration: dc.lateMuteSeconds });
|
|
928
|
+
} else {
|
|
929
|
+
resultLines.push("\u{1F52B} \u53CC\u65B9\u90FD\u6CA1\u6709\u62D4\u67AA\uFF01");
|
|
930
|
+
muteTargets.push(
|
|
931
|
+
{ id: challengerId, name: challengerName, duration: dc.lateMuteSeconds },
|
|
932
|
+
{ id: targetId, name: targetName, duration: dc.lateMuteSeconds }
|
|
933
|
+
);
|
|
934
|
+
winnerId = "";
|
|
935
|
+
winnerName = "";
|
|
936
|
+
winnerTime = 0;
|
|
937
|
+
loserId = "";
|
|
938
|
+
loserName = "";
|
|
939
|
+
loserTime = -1;
|
|
940
|
+
}
|
|
941
|
+
for (const mt of muteTargets) {
|
|
942
|
+
const muted = await tryMute(session, mt.id, mt.duration);
|
|
943
|
+
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`);
|
|
944
|
+
}
|
|
945
|
+
if (cTime !== null) {
|
|
946
|
+
resultLines.push(`${challengerName} \u7528\u65F6\uFF1A${cTime}ms`);
|
|
947
|
+
} else {
|
|
948
|
+
resultLines.push(`${challengerName} \u672A\u62D4\u67AA`);
|
|
949
|
+
}
|
|
950
|
+
if (tTime !== null) {
|
|
951
|
+
resultLines.push(`${targetName} \u7528\u65F6\uFF1A${tTime}ms`);
|
|
952
|
+
} else {
|
|
953
|
+
resultLines.push(`${targetName} \u672A\u62D4\u67AA`);
|
|
954
|
+
}
|
|
955
|
+
if (winnerId && loserId) {
|
|
956
|
+
try {
|
|
957
|
+
await ctx.database.create("lili_duel", {
|
|
958
|
+
gid,
|
|
959
|
+
winnerId,
|
|
960
|
+
winnerName,
|
|
961
|
+
loserId,
|
|
962
|
+
loserName,
|
|
963
|
+
winnerTime,
|
|
964
|
+
loserTime,
|
|
965
|
+
timestamp: Date.now()
|
|
966
|
+
});
|
|
967
|
+
} catch (e) {
|
|
968
|
+
dbg("\u5BF9\u51B3\u8BB0\u5F55\u5165\u5E93\u5931\u8D25", { gid, error: String(e) });
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
await session.send(resultLines.join("\n"));
|
|
972
|
+
cleanupDuel(gid);
|
|
973
|
+
}
|
|
974
|
+
ctx.middleware(async (session, next) => {
|
|
975
|
+
if (!config.duel.enabled) return next();
|
|
976
|
+
const gid = getGroupId(session);
|
|
977
|
+
if (!gid) return next();
|
|
978
|
+
if (!isGroupAllowed(gid, config.duel.groups, config.duel.groupMode)) return next();
|
|
979
|
+
const duel = duelStates.get(gid);
|
|
980
|
+
if (!duel) return next();
|
|
981
|
+
const text = (session.content || "").trim();
|
|
982
|
+
const userId = String(session.userId);
|
|
983
|
+
if (userId !== duel.challengerId && userId !== duel.targetId) return next();
|
|
984
|
+
if (duel.phase === "waiting_accept" && userId === duel.targetId && text === "\u63A5\u53D7") {
|
|
985
|
+
if (duel.acceptTimer) clearTimeout(duel.acceptTimer);
|
|
986
|
+
duel.acceptTimer = null;
|
|
987
|
+
const dc = config.duel;
|
|
988
|
+
duel.phase = "countdown";
|
|
989
|
+
duel.countdownEndTime = Date.now() + dc.countdownSeconds * 1e3;
|
|
990
|
+
duel.earlyDrawers = /* @__PURE__ */ new Set();
|
|
991
|
+
duel.drawTimes = /* @__PURE__ */ new Map();
|
|
992
|
+
dbg("\u5BF9\u51B3-\u5F00\u59CB\u5012\u8BA1\u65F6", { gid, countdownSeconds: dc.countdownSeconds, challenger: duel.challengerId, target: duel.targetId });
|
|
993
|
+
duel.countdownTimer = setTimeout(async () => {
|
|
994
|
+
const d = duelStates.get(gid);
|
|
995
|
+
if (!d || d.phase !== "countdown") return;
|
|
996
|
+
d.phase = "drawing";
|
|
997
|
+
try {
|
|
998
|
+
await duel.session.send("\u2694\uFE0F \u5348\u65F6\u5DF2\u5230\uFF01");
|
|
999
|
+
} catch {
|
|
1000
|
+
}
|
|
1001
|
+
dbg("\u5BF9\u51B3-\u62D4\u67AA\u9636\u6BB5", { gid });
|
|
1002
|
+
d.drawTimer = setTimeout(() => {
|
|
1003
|
+
const d2 = duelStates.get(gid);
|
|
1004
|
+
if (!d2 || d2.phase !== "drawing") return;
|
|
1005
|
+
resolveDuel(gid);
|
|
1006
|
+
}, dc.drawTimeoutSeconds * 1e3);
|
|
1007
|
+
}, dc.countdownSeconds * 1e3);
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
if (text === "\u62D4\u67AA" && (duel.phase === "countdown" || duel.phase === "drawing")) {
|
|
1011
|
+
const now = Date.now();
|
|
1012
|
+
if (duel.phase === "countdown") {
|
|
1013
|
+
duel.earlyDrawers.add(userId);
|
|
1014
|
+
const name3 = userId === duel.challengerId ? duel.challengerName : duel.targetName;
|
|
1015
|
+
await session.send(`\u26A0\uFE0F ${name3} \u63D0\u524D\u62D4\u67AA\uFF01`);
|
|
1016
|
+
dbg("\u5BF9\u51B3-\u63D0\u524D\u62D4\u67AA", { gid, userId, name: name3 });
|
|
1017
|
+
if (duel.earlyDrawers.size >= 2) {
|
|
1018
|
+
duel.drawTimes.set(userId, now);
|
|
1019
|
+
const otherId = userId === duel.challengerId ? duel.targetId : duel.challengerId;
|
|
1020
|
+
if (!duel.drawTimes.has(otherId)) duel.drawTimes.set(otherId, now);
|
|
1021
|
+
resolveDuel(gid);
|
|
1022
|
+
}
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
if (duel.drawTimes.has(userId)) {
|
|
1026
|
+
await session.send("\u4F60\u5DF2\u7ECF\u62D4\u8FC7\u67AA\u4E86\uFF01");
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
const reactionTime = now - duel.countdownEndTime;
|
|
1030
|
+
duel.drawTimes.set(userId, reactionTime);
|
|
1031
|
+
const name2 = userId === duel.challengerId ? duel.challengerName : duel.targetName;
|
|
1032
|
+
dbg("\u5BF9\u51B3-\u62D4\u67AA", { gid, userId, name: name2, reactionTime });
|
|
1033
|
+
if (duel.drawTimes.has(duel.challengerId) && duel.drawTimes.has(duel.targetId)) {
|
|
1034
|
+
resolveDuel(gid);
|
|
1035
|
+
}
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
return next();
|
|
1039
|
+
});
|
|
1040
|
+
ctx.command("\u521B\u5EFA\u63A5\u9F99 <content:string>", "\u521B\u5EFA\u7FA4\u63A5\u9F99\uFF0C\u521B\u5EFA\u8005\u81EA\u52A8\u4E3A\u7B2C\u4E00\u4F4D").action(async ({ session }, content) => {
|
|
1041
|
+
if (!session?.userId) return;
|
|
1042
|
+
const gid = getGroupId(session);
|
|
1043
|
+
const cc = config.chain;
|
|
1044
|
+
if (!cc.enabled) return;
|
|
1045
|
+
if (!isGroupAllowed(gid, cc.groups, cc.groupMode)) return;
|
|
1046
|
+
if (!content || !content.trim()) {
|
|
1047
|
+
return "\u{1F4DD} \u8BF7\u63D0\u4F9B\u63A5\u9F99\u5185\u5BB9\uFF0C\u4F8B\u5982\uFF1A\u521B\u5EFA\u63A5\u9F99 \u4ECA\u5929\u4E2D\u5348\u5403\u4EC0\u4E48";
|
|
1048
|
+
}
|
|
1049
|
+
const chainContent = content.trim();
|
|
1050
|
+
const userId = String(session.userId);
|
|
1051
|
+
const userName = session.username || userId;
|
|
1052
|
+
chainStates.set(gid, {
|
|
1053
|
+
content: chainContent,
|
|
1054
|
+
creatorId: userId,
|
|
1055
|
+
creatorName: userName,
|
|
1056
|
+
participants: [{ userId, userName }],
|
|
1057
|
+
createdAt: Date.now()
|
|
1058
|
+
});
|
|
1059
|
+
dbg("\u63A5\u9F99-\u521B\u5EFA", { gid, creatorId: userId, content: chainContent });
|
|
1060
|
+
return formatChain(chainStates.get(gid));
|
|
1061
|
+
});
|
|
1062
|
+
ctx.command("\u67E5\u770B\u63A5\u9F99", "\u67E5\u770B\u5F53\u524D\u7FA4\u63A5\u9F99").action(async ({ session }) => {
|
|
1063
|
+
const gid = getGroupId(session);
|
|
1064
|
+
const cc = config.chain;
|
|
1065
|
+
if (!cc.enabled) return;
|
|
1066
|
+
if (!isGroupAllowed(gid, cc.groups, cc.groupMode)) return;
|
|
1067
|
+
const chain = chainStates.get(gid);
|
|
1068
|
+
if (!chain) return '\u{1F4DD} \u672C\u7FA4\u6682\u65E0\u63A5\u9F99\uFF0C\u4F7F\u7528"\u521B\u5EFA\u63A5\u9F99 <\u5185\u5BB9>"\u5F00\u59CB\u4E00\u4E2A\u5427\uFF01';
|
|
1069
|
+
return formatChain(chain);
|
|
1070
|
+
});
|
|
1071
|
+
ctx.command("\u9000\u51FA\u63A5\u9F99", "\u9000\u51FA\u5F53\u524D\u7FA4\u63A5\u9F99").alias("\u53D6\u6D88\u63A5\u9F99").action(async ({ session }) => {
|
|
1072
|
+
const gid = getGroupId(session);
|
|
1073
|
+
const cc = config.chain;
|
|
1074
|
+
if (!cc.enabled) return;
|
|
1075
|
+
if (!isGroupAllowed(gid, cc.groups, cc.groupMode)) return;
|
|
1076
|
+
const chain = chainStates.get(gid);
|
|
1077
|
+
if (!chain) return "\u{1F4DD} \u672C\u7FA4\u6682\u65E0\u63A5\u9F99\u3002";
|
|
1078
|
+
const userId = String(session.userId);
|
|
1079
|
+
const idx = chain.participants.findIndex((p) => p.userId === userId);
|
|
1080
|
+
if (idx === -1) return "\u{1F4DD} \u4F60\u6CA1\u6709\u53C2\u4E0E\u8FD9\u4E2A\u63A5\u9F99\u3002";
|
|
1081
|
+
const userName = chain.participants[idx].userName;
|
|
1082
|
+
chain.participants.splice(idx, 1);
|
|
1083
|
+
dbg("\u63A5\u9F99-\u9000\u51FA", { gid, userId, userName, remaining: chain.participants.length });
|
|
1084
|
+
if (chain.participants.length === 0) {
|
|
1085
|
+
chainStates.delete(gid);
|
|
1086
|
+
return "\u{1F4DD} \u4F60\u9000\u51FA\u4E86\u63A5\u9F99\uFF0C\u63A5\u9F99\u5DF2\u56E0\u65E0\u4EBA\u53C2\u4E0E\u800C\u7ED3\u675F\u3002";
|
|
1087
|
+
}
|
|
1088
|
+
await session.send(`\u{1F4DD} ${userName} \u5DF2\u9000\u51FA\u63A5\u9F99\u3002
|
|
1089
|
+
|
|
1090
|
+
${formatChain(chain)}`);
|
|
1091
|
+
});
|
|
1092
|
+
ctx.middleware(async (session, next) => {
|
|
1093
|
+
if (!config.chain.enabled) return next();
|
|
1094
|
+
const gid = getGroupId(session);
|
|
1095
|
+
if (!gid) return next();
|
|
1096
|
+
if (!isGroupAllowed(gid, config.chain.groups, config.chain.groupMode)) return next();
|
|
1097
|
+
const text = (session.content || "").trim();
|
|
1098
|
+
if (text !== "\u63A5\u9F99") return next();
|
|
1099
|
+
const chain = chainStates.get(gid);
|
|
1100
|
+
if (!chain) return next();
|
|
1101
|
+
const userId = String(session.userId);
|
|
1102
|
+
if (chain.participants.some((p) => p.userId === userId)) {
|
|
1103
|
+
await session.send("\u{1F4DD} \u4F60\u5DF2\u7ECF\u53C2\u4E0E\u8FC7\u8FD9\u4E2A\u63A5\u9F99\u4E86\uFF01");
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
const userName = session.username || userId;
|
|
1107
|
+
chain.participants.push({ userId, userName });
|
|
1108
|
+
dbg("\u63A5\u9F99-\u53C2\u4E0E", { gid, userId, participantCount: chain.participants.length });
|
|
1109
|
+
await session.send(formatChain(chain));
|
|
1110
|
+
return;
|
|
1111
|
+
});
|
|
719
1112
|
ctx.middleware(async (session, next) => {
|
|
720
1113
|
const gid = getGroupId(session);
|
|
721
1114
|
const content = session.content || "";
|
|
@@ -802,7 +1195,7 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
|
|
|
802
1195
|
forwardTextsPreview: forwardTexts.slice(0, 5).map((t) => t.substring(0, 30))
|
|
803
1196
|
});
|
|
804
1197
|
}
|
|
805
|
-
if (config.dedup.enabled && isGroupAllowed(gid, config.dedup.groups)) {
|
|
1198
|
+
if (config.dedup.enabled && isGroupAllowed(gid, config.dedup.groups, config.dedup.groupMode)) {
|
|
806
1199
|
dbg("\u67E5\u91CD-\u4E2D\u95F4\u4EF6\u5165\u53E3", {
|
|
807
1200
|
gid,
|
|
808
1201
|
userId: session.userId,
|
|
@@ -813,15 +1206,19 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
|
|
|
813
1206
|
forwardTextsCount: forwardTexts.length
|
|
814
1207
|
});
|
|
815
1208
|
if (isFwd && forwardTexts.length > 0) {
|
|
816
|
-
const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
817
1209
|
dbg("\u67E5\u91CD\u68C0\u6D4B", { gid, forwardTextsCount: forwardTexts.length });
|
|
818
1210
|
for (const fwdText of forwardTexts) {
|
|
819
1211
|
if (!fwdText) continue;
|
|
820
1212
|
try {
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1213
|
+
const sevenDaysAgoMs = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
1214
|
+
const recentMsgs = await ctx.database.get("lili_message", { gid, timestamp: { $gte: sevenDaysAgoMs } }, { sort: { timestamp: "asc" }, limit: 1e3 });
|
|
1215
|
+
const match = recentMsgs.find((m) => {
|
|
1216
|
+
if (m.content === fwdText) return true;
|
|
1217
|
+
return normalizeText(m.content) === fwdText;
|
|
1218
|
+
});
|
|
1219
|
+
dbg("\u67E5\u91CD\u67E5\u8BE2", { gid, fwdText: fwdText.substring(0, 50), recentMsgCount: recentMsgs?.length || 0, matched: !!match });
|
|
1220
|
+
if (match) {
|
|
1221
|
+
const original = match;
|
|
825
1222
|
const dateStr = new Date(original.timestamp).toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" });
|
|
826
1223
|
await session.send([
|
|
827
1224
|
(0, import_koishi.h)("quote", { id: original.messageId }),
|
|
@@ -839,8 +1236,8 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
|
|
|
839
1236
|
const imitationGroups = parseGroupList(config.imitation.groups);
|
|
840
1237
|
const dedupGroups = parseGroupList(config.dedup.groups);
|
|
841
1238
|
const foldGroups = config.fold.enabled ? parseGroupList(config.fold.groups) : [];
|
|
842
|
-
const dedupInGroup = config.dedup.enabled && isGroupAllowed(gid, config.dedup.groups);
|
|
843
|
-
const foldInGroup = config.fold.enabled && isGroupAllowed(gid, config.fold.groups);
|
|
1239
|
+
const dedupInGroup = config.dedup.enabled && isGroupAllowed(gid, config.dedup.groups, config.dedup.groupMode);
|
|
1240
|
+
const foldInGroup = config.fold.enabled && isGroupAllowed(gid, config.fold.groups, config.fold.groupMode);
|
|
844
1241
|
const shouldRecordAll = foldInGroup || dedupInGroup;
|
|
845
1242
|
const shouldRecordLimited = textLen >= 15 && textLen <= 60 && normalizedText;
|
|
846
1243
|
const recordGroups = /* @__PURE__ */ new Set([...imitationGroups, ...dedupGroups, ...foldGroups]);
|
|
@@ -864,8 +1261,8 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
|
|
|
864
1261
|
try {
|
|
865
1262
|
await ctx.database.create("lili_message", {
|
|
866
1263
|
gid,
|
|
867
|
-
userId: session.userId,
|
|
868
|
-
userName: session.username || session.userId,
|
|
1264
|
+
userId: String(session.userId),
|
|
1265
|
+
userName: session.username || String(session.userId),
|
|
869
1266
|
content: fwdText,
|
|
870
1267
|
timestamp: Date.now(),
|
|
871
1268
|
messageId: session.messageId || ""
|
|
@@ -876,22 +1273,28 @@ ${import_koishi.segment.at(targetId)} \u5DF2\u88AB\u89E3\u9664\u7981\u8A00\u3002
|
|
|
876
1273
|
}
|
|
877
1274
|
}
|
|
878
1275
|
}
|
|
879
|
-
if (shouldRecord && !isFwd
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1276
|
+
if (shouldRecord && !isFwd) {
|
|
1277
|
+
const shouldStore = shouldRecordAll || normalizedText && textLen >= 15 && textLen <= 60;
|
|
1278
|
+
if (shouldStore) {
|
|
1279
|
+
const storeContent = shouldRecordAll ? session.content || normalizedText || "" : normalizedText;
|
|
1280
|
+
if (storeContent) {
|
|
1281
|
+
try {
|
|
1282
|
+
await ctx.database.create("lili_message", {
|
|
1283
|
+
gid,
|
|
1284
|
+
userId: String(session.userId),
|
|
1285
|
+
userName: session.username || String(session.userId),
|
|
1286
|
+
content: storeContent,
|
|
1287
|
+
timestamp: Date.now(),
|
|
1288
|
+
messageId: session.messageId || ""
|
|
1289
|
+
});
|
|
1290
|
+
dbg("\u6D88\u606F\u5DF2\u5165\u5E93", { gid, userId: String(session.userId), contentLen: storeContent.length, shouldRecordAll, messageId: session.messageId });
|
|
1291
|
+
} catch (e) {
|
|
1292
|
+
dbg("\u6D88\u606F\u5165\u5E93\u5931\u8D25", { gid, error: String(e) });
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
892
1295
|
}
|
|
893
1296
|
}
|
|
894
|
-
if (config.imitation.enabled && isGroupAllowed(gid, config.imitation.groups)) {
|
|
1297
|
+
if (config.imitation.enabled && isGroupAllowed(gid, config.imitation.groups, config.imitation.groupMode)) {
|
|
895
1298
|
let count = imitationCounters.get(gid) || 0;
|
|
896
1299
|
count++;
|
|
897
1300
|
imitationCounters.set(gid, count);
|