koishi-plugin-echo-cave 1.14.2 → 1.16.0

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.cjs CHANGED
@@ -37,6 +37,7 @@ var require_zh_CN = __commonJS({
37
37
  adminMessageProtection: "\u5F00\u542F\u7BA1\u7406\u5458\u6D88\u606F\u4FDD\u62A4\uFF0C\u5F00\u542F\u540E\u7BA1\u7406\u5458\u53D1\u5E03\u7684\u6D88\u606F\u53EA\u80FD\u7531\u7BA1\u7406\u5458\u5220\u9664",
38
38
  allowContributorDelete: "\u5141\u8BB8\u6295\u7A3F\u8005\u5220\u9664\u81EA\u5DF1\u6295\u7A3F\u7684\u56DE\u58F0\u6D1E",
39
39
  allowSenderDelete: "\u5141\u8BB8\u539F\u59CB\u53D1\u9001\u8005\u5220\u9664\u88AB\u6295\u7A3F\u7684\u56DE\u58F0\u6D1E",
40
+ deleteMediaWhenDeletingMsg: "\u5220\u9664\u56DE\u58F0\u6D1E\u6D88\u606F\u65F6\u662F\u5426\u540C\u65F6\u5220\u9664\u5173\u8054\u7684\u5A92\u4F53\u6587\u4EF6",
40
41
  enableSizeLimit: "\u662F\u5426\u542F\u7528\u5A92\u4F53\u6587\u4EF6\u5927\u5C0F\u9650\u5236",
41
42
  maxImageSize: "\u6700\u5927\u56FE\u7247\u5927\u5C0F (MB)",
42
43
  maxVideoSize: "\u6700\u5927\u89C6\u9891\u5927\u5C0F (MB)",
@@ -95,7 +96,8 @@ var require_zh_CN = __commonJS({
95
96
  noMsgQuoted: "\u{1F4A1} \u8BF7\u5F15\u7528\u4E00\u6761\u6D88\u606F\u540E\u518D\u4F7F\u7528\u6B64\u547D\u4EE4\uFF01",
96
97
  existingMsg: "\u267B\uFE0F \u8BE5\u6D88\u606F\u5DF2\u5B58\u5728\u4E8E\u56DE\u58F0\u6D1E\u7A74\u4E2D\uFF01",
97
98
  msgSaved: "\u2705 \u56DE\u58F0\u6D1E\u6D88\u606F\u5DF2\u6210\u529F\u5B58\u5165\uFF0C\u6D88\u606F ID\uFF1A{0}",
98
- msgFailedToSave: "\u274C \u56DE\u58F0\u6D1E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\uFF01"
99
+ msgFailedToSave: "\u274C \u56DE\u58F0\u6D1E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\uFF01",
100
+ userNotInGroup: "\u274C \u63D0\u4F9B\u7684\u7528\u6237 ID \u4E0D\u5168\u5C5E\u4E8E\u8BE5\u7FA4\u7EC4\uFF01"
99
101
  }
100
102
  },
101
103
  "cave.wipe": {
@@ -124,6 +126,17 @@ var require_zh_CN = __commonJS({
124
126
  msgListHeader: "\u{1F4DC} \u60A8\u5728\u672C\u9891\u9053\u53D1\u8A00\u7684\u56DE\u58F0\u6D1E\u6D88\u606F\u5217\u8868\uFF1A\n",
125
127
  msgListItem: "ID: {0} | \u521B\u5EFA\u65F6\u95F4: {1}\n"
126
128
  }
129
+ },
130
+ "cave.bind": {
131
+ description: "\u5C06\u7528\u6237\u7ED1\u5B9A\u5230\u7279\u5B9A\u56DE\u58F0\u6D1E",
132
+ messages: {
133
+ noIdProvided: "\u274C \u8BF7\u63D0\u4F9B\u8981\u7ED1\u5B9A\u7528\u6237\u7684\u56DE\u58F0\u6D1E\u6D88\u606F ID\uFF01",
134
+ noUserIdProvided: "\u274C \u8BF7\u63D0\u4F9B\u8981\u7ED1\u5B9A\u7684\u7528\u6237 ID\uFF01",
135
+ msgNotFound: "\u{1F50D} \u672A\u627E\u5230\u8BE5 ID \u7684\u56DE\u58F0\u6D1E\u6D88\u606F",
136
+ userBoundSuccess: "\u2705 \u5DF2\u6210\u529F\u5C06\u7528\u6237\u7ED1\u5B9A\u5230\u56DE\u58F0\u6D1E #{0}\uFF01",
137
+ userAlreadyBound: "\u2139\uFE0F \u8BE5\u7528\u6237\u5DF2\u7ED1\u5B9A\u5230\u56DE\u58F0\u6D1E #{0}\uFF01",
138
+ userNotInGroup: "\u274C \u63D0\u4F9B\u7684\u7528\u6237 ID \u4E0D\u5168\u5C5E\u4E8E\u8BE5\u7FA4\u7EC4\uFF01"
139
+ }
127
140
  }
128
141
  }
129
142
  };
@@ -325,6 +338,29 @@ async function checkAndCleanMediaFiles(ctx, cfg, type) {
325
338
  ctx.logger.error(`Failed to check and clean ${type} files: ${err}`);
326
339
  }
327
340
  }
341
+ async function deleteMediaFilesFromMessage(ctx, content) {
342
+ try {
343
+ const elements = JSON.parse(content);
344
+ const mediaElements = Array.isArray(elements) ? elements : [elements];
345
+ for (const element of mediaElements) {
346
+ if (element.type === "image" || element.type === "video" || element.type === "file" || element.type === "record") {
347
+ const fileUri = element.data?.file;
348
+ if (fileUri && fileUri.startsWith("file:///")) {
349
+ const filePath = decodeURIComponent(fileUri.replace("file:///", ""));
350
+ try {
351
+ await import_node_fs.promises.access(filePath);
352
+ await import_node_fs.promises.unlink(filePath);
353
+ ctx.logger.info(`Deleted media file: ${filePath}`);
354
+ } catch (err) {
355
+ ctx.logger.warn(`Failed to delete media file: ${filePath}, error: ${err}`);
356
+ }
357
+ }
358
+ }
359
+ }
360
+ } catch (err) {
361
+ ctx.logger.error(`Failed to parse message content when deleting media: ${err}`);
362
+ }
363
+ }
328
364
 
329
365
  // src/onebot-helper.ts
330
366
  async function getUserName(ctx, session, userId) {
@@ -336,6 +372,16 @@ async function getUserName(ctx, session, userId) {
336
372
  return userId;
337
373
  }
338
374
  }
375
+ async function checkUsersInGroup(ctx, session, userIds) {
376
+ try {
377
+ const groupMembers = await session.onebot.getGroupMemberList(session.channelId);
378
+ const memberIds = groupMembers.map((member) => member.user_id.toString());
379
+ return userIds.every((userId) => memberIds.includes(userId));
380
+ } catch (error) {
381
+ ctx.logger.warn(`\u83B7\u53D6\u7FA4\u6210\u5458\u5217\u8868\u5931\u8D25\uFF1A`, error);
382
+ return false;
383
+ }
384
+ }
339
385
 
340
386
  // src/cave-helper.ts
341
387
  async function sendCaveMsg(ctx, session, caveMsg, cfg) {
@@ -349,11 +395,19 @@ async function sendCaveMsg(ctx, session, caveMsg, cfg) {
349
395
  const date = formatDate(caveMsg.createTime);
350
396
  const originName = await getUserName(ctx, session, caveMsg.originUserId);
351
397
  const userName = await getUserName(ctx, session, caveMsg.userId);
398
+ let relatedUsersFormatted = "";
399
+ if (caveMsg.relatedUsers && caveMsg.relatedUsers.length > 0) {
400
+ const relatedUserNames = await Promise.all(
401
+ caveMsg.relatedUsers.map(async (userId) => await getUserName(ctx, session, userId))
402
+ );
403
+ relatedUsersFormatted = relatedUserNames.join(", ");
404
+ }
352
405
  const templateData = {
353
406
  id: caveMsg.id.toString(),
354
407
  date,
355
408
  originName,
356
409
  userName,
410
+ relatedUsers: relatedUsersFormatted,
357
411
  nl: "\n"
358
412
  };
359
413
  const TEMPLATE_COUNT = 5;
@@ -464,6 +518,7 @@ var Config = import_koishi.Schema.object({
464
518
  adminMessageProtection: import_koishi.Schema.boolean().default(false),
465
519
  allowContributorDelete: import_koishi.Schema.boolean().default(true),
466
520
  allowSenderDelete: import_koishi.Schema.boolean().default(true),
521
+ deleteMediaWhenDeletingMsg: import_koishi.Schema.boolean().default(true),
467
522
  enableSizeLimit: import_koishi.Schema.boolean().default(false),
468
523
  maxImageSize: import_koishi.Schema.number().default(2048),
469
524
  maxVideoSize: import_koishi.Schema.number().default(512),
@@ -484,7 +539,8 @@ function apply(ctx, cfg) {
484
539
  userId: "string",
485
540
  originUserId: "string",
486
541
  type: "string",
487
- content: "text"
542
+ content: "text",
543
+ relatedUsers: "list"
488
544
  },
489
545
  {
490
546
  primary: "id",
@@ -494,7 +550,9 @@ function apply(ctx, cfg) {
494
550
  ctx.command("cave [id:number]").action(
495
551
  async ({ session }, id) => await getCave(ctx, session, cfg, id)
496
552
  );
497
- ctx.command("cave.echo").action(async ({ session }) => await addCave(ctx, session, cfg));
553
+ ctx.command("cave.echo [...userIds:string]").action(
554
+ async ({ session }, ...userIds) => await addCave(ctx, session, cfg, userIds)
555
+ );
498
556
  ctx.command("cave.wipe <id:number>").action(
499
557
  async ({ session }, id) => await deleteCave(ctx, session, cfg, id)
500
558
  );
@@ -502,6 +560,9 @@ function apply(ctx, cfg) {
502
560
  ctx.command("cave.trace").action(
503
561
  async ({ session }) => await getCaveListByOriginUser(ctx, session)
504
562
  );
563
+ ctx.command("cave.bind <id:number> <...userIds:string>", { authority: 4 }).action(
564
+ async ({ session }, id, ...userIds) => await bindUsersToCave(ctx, session, id, userIds)
565
+ );
505
566
  }
506
567
  async function getCaveListByUser(ctx, session) {
507
568
  if (!session.guildId) {
@@ -601,10 +662,13 @@ async function deleteCave(ctx, session, cfg, id) {
601
662
  return session.text(".permissionDenied");
602
663
  }
603
664
  }
665
+ if (cfg.deleteMediaWhenDeletingMsg) {
666
+ await deleteMediaFilesFromMessage(ctx, caveMsg.content);
667
+ }
604
668
  await ctx.database.remove("echo_cave", id);
605
669
  return session.text(".msgDeleted", [id]);
606
670
  }
607
- async function addCave(ctx, session, cfg) {
671
+ async function addCave(ctx, session, cfg, userIds) {
608
672
  if (!session.guildId) {
609
673
  return session.text("echo-cave.general.privateChatReminder");
610
674
  }
@@ -643,6 +707,12 @@ async function addCave(ctx, session, cfg) {
643
707
  return session.text(".existingMsg");
644
708
  }
645
709
  });
710
+ if (userIds && userIds.length > 0) {
711
+ const isAllUsersInGroup = await checkUsersInGroup(ctx, session, userIds);
712
+ if (!isAllUsersInGroup) {
713
+ return session.text(".userNotInGroup");
714
+ }
715
+ }
646
716
  try {
647
717
  const result = await ctx.database.create("echo_cave", {
648
718
  channelId,
@@ -650,13 +720,37 @@ async function addCave(ctx, session, cfg) {
650
720
  userId,
651
721
  originUserId: quote.user.id,
652
722
  type,
653
- content
723
+ content,
724
+ relatedUsers: userIds || []
654
725
  });
655
726
  return session.text(".msgSaved", [result.id]);
656
727
  } catch (error) {
657
728
  return session.text(".msgFailedToSave");
658
729
  }
659
730
  }
731
+ async function bindUsersToCave(ctx, session, id, userIds) {
732
+ if (!session.guildId) {
733
+ return session.text("echo-cave.general.privateChatReminder");
734
+ }
735
+ if (!id) {
736
+ return session.text(".noIdProvided");
737
+ }
738
+ if (!userIds || userIds.length === 0) {
739
+ return session.text(".noUserIdProvided");
740
+ }
741
+ const caves = await ctx.database.get("echo_cave", id);
742
+ if (caves.length === 0) {
743
+ return session.text("echo-cave.general.noMsgWithId");
744
+ }
745
+ const isAllUsersInGroup = await checkUsersInGroup(ctx, session, userIds);
746
+ if (!isAllUsersInGroup) {
747
+ return session.text(".userNotInGroup");
748
+ }
749
+ await ctx.database.set("echo_cave", id, {
750
+ relatedUsers: userIds
751
+ });
752
+ return session.text(".userBoundSuccess", [id]);
753
+ }
660
754
  // Annotate the CommonJS export names for ESM import in node:
661
755
  0 && (module.exports = {
662
756
  Config,
package/lib/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export interface Config {
6
6
  adminMessageProtection?: boolean;
7
7
  allowContributorDelete?: boolean;
8
8
  allowSenderDelete?: boolean;
9
+ deleteMediaWhenDeletingMsg?: boolean;
9
10
  enableSizeLimit?: boolean;
10
11
  maxImageSize?: number;
11
12
  maxVideoSize?: number;
@@ -22,6 +23,7 @@ export interface EchoCave {
22
23
  originUserId: string;
23
24
  type: 'forward' | 'msg';
24
25
  content: string;
26
+ relatedUsers: string[];
25
27
  }
26
28
  declare module 'koishi' {
27
29
  interface Tables {
@@ -4,3 +4,4 @@ export declare function saveMedia(ctx: Context, mediaElement: Record<string, any
4
4
  export declare function processMediaElement(ctx: Context, element: any, cfg: Config): Promise<any>;
5
5
  export declare function convertFileUriToBase64(ctx: Context, element: any): Promise<any>;
6
6
  export declare function checkAndCleanMediaFiles(ctx: Context, cfg: Config, type: 'image' | 'video' | 'file' | 'record'): Promise<void>;
7
+ export declare function deleteMediaFilesFromMessage(ctx: Context, content: string): Promise<void>;
@@ -1,2 +1,6 @@
1
1
  import { Context, Session } from 'koishi';
2
2
  export declare function getUserName(ctx: Context, session: Session, userId: string): Promise<string>;
3
+ /**
4
+ * 检查用户是否属于指定群组
5
+ */
6
+ export declare function checkUsersInGroup(ctx: Context, session: Session, userIds: string[]): Promise<boolean>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-echo-cave",
3
3
  "description": "Group echo cave",
4
- "version": "1.14.2",
4
+ "version": "1.16.0",
5
5
  "main": "lib/index.cjs",
6
6
  "typings": "lib/index.d.ts",
7
7
  "type": "module",