koishi-plugin-echo-cave 1.16.9 → 1.16.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/index.cjs +9 -268
  2. package/package.json +1 -1
package/lib/index.cjs CHANGED
@@ -200,82 +200,6 @@ function parseUserIds(userIds) {
200
200
  // src/media-helper.ts
201
201
  var import_axios = __toESM(require("axios"), 1);
202
202
  var import_node_fs = require("node:fs");
203
- var import_node_path = __toESM(require("node:path"), 1);
204
- async function saveMedia(ctx, mediaElement, type, cfg) {
205
- const mediaUrl = mediaElement.url;
206
- const originalMediaName = mediaElement.file;
207
- const ext = (() => {
208
- const i = originalMediaName.lastIndexOf(".");
209
- return i === -1 ? type === "image" ? "png" : type === "video" ? "mp4" : type === "record" ? "mp3" : "bin" : originalMediaName.slice(i + 1).toLowerCase();
210
- })();
211
- const mediaDir = import_node_path.default.join(ctx.baseDir, "data", "cave", type + "s");
212
- const mediaName = Date.now().toString();
213
- const fullMediaPath = import_node_path.default.join(mediaDir, `${mediaName}.${ext}`);
214
- ctx.logger.info(`Saving ${type} from ${mediaUrl} -> ${fullMediaPath}`);
215
- try {
216
- await import_node_fs.promises.mkdir(mediaDir, { recursive: true });
217
- const res = await import_axios.default.get(mediaUrl, {
218
- responseType: "arraybuffer",
219
- validateStatus: () => true
220
- });
221
- if (res.status < 200 || res.status >= 300) {
222
- ctx.logger.warn(
223
- `${type.charAt(0).toUpperCase() + type.slice(1)} download failed: HTTP ${res.status}`
224
- );
225
- return mediaUrl;
226
- }
227
- const contentType = res.headers["content-type"];
228
- if (contentType) {
229
- if (type === "image" && !contentType.startsWith("image/")) {
230
- ctx.logger.warn(`Invalid image content-type: ${contentType}`);
231
- return mediaUrl;
232
- }
233
- if (type === "video" && !contentType.startsWith("video/")) {
234
- ctx.logger.warn(`Invalid video content-type: ${contentType}`);
235
- return mediaUrl;
236
- }
237
- if (type === "record" && !contentType.startsWith("audio/")) {
238
- ctx.logger.warn(`Invalid record content-type: ${contentType}`);
239
- return mediaUrl;
240
- }
241
- }
242
- const buffer = Buffer.from(res.data);
243
- if (!buffer || buffer.length === 0) {
244
- ctx.logger.warn(`Downloaded ${type} buffer is empty`);
245
- return mediaUrl;
246
- }
247
- await import_node_fs.promises.writeFile(fullMediaPath, buffer);
248
- ctx.logger.info(
249
- `${type.charAt(0).toUpperCase() + type.slice(1)} saved successfully: ${fullMediaPath}`
250
- );
251
- await checkAndCleanMediaFiles(ctx, cfg, type);
252
- return fullMediaPath;
253
- } catch (err) {
254
- ctx.logger.error(`Failed to save ${type}: ${err}`);
255
- return mediaUrl;
256
- }
257
- }
258
- async function processMediaElement(ctx, element, cfg) {
259
- if (element.type === "image" || element.type === "video" || element.type === "file" || element.type === "record") {
260
- const savedPath = await saveMedia(
261
- ctx,
262
- element.data,
263
- element.type,
264
- cfg
265
- );
266
- const fileUri = `file:///${savedPath.replace(/\\/g, "/")}`;
267
- return {
268
- ...element,
269
- data: {
270
- ...element.data,
271
- file: fileUri,
272
- // Remove the url field
273
- url: void 0
274
- }
275
- };
276
- }
277
- return element;
278
- }
279
203
  async function convertFileUriToBase64(ctx, element) {
280
204
  if (element.type === "image" || element.type === "video" || element.type === "file" || element.type === "record") {
281
205
  const fileUri = element.data.file;
@@ -305,72 +229,6 @@ async function convertFileUriToBase64(ctx, element) {
305
229
  }
306
230
  return element;
307
231
  }
308
- async function checkAndCleanMediaFiles(ctx, cfg, type) {
309
- if (!cfg.enableSizeLimit) {
310
- return;
311
- }
312
- const mediaDir = import_node_path.default.join(ctx.baseDir, "data", "cave", type + "s");
313
- const maxSize = (() => {
314
- switch (type) {
315
- case "image":
316
- return (cfg.maxImageSize || 100) * 1024 * 1024;
317
- // 转换为字节
318
- case "video":
319
- return (cfg.maxVideoSize || 500) * 1024 * 1024;
320
- case "file":
321
- return (cfg.maxFileSize || 1e3) * 1024 * 1024;
322
- case "record":
323
- return (cfg.maxRecordSize || 200) * 1024 * 1024;
324
- }
325
- })();
326
- try {
327
- const files = await import_node_fs.promises.readdir(mediaDir);
328
- if (files.length === 0) {
329
- return;
330
- }
331
- const fileInfos = await Promise.all(
332
- files.map(async (file) => {
333
- const filePath = import_node_path.default.join(mediaDir, file);
334
- const stats = await import_node_fs.promises.stat(filePath);
335
- return {
336
- path: filePath,
337
- size: stats.size,
338
- mtime: stats.mtimeMs
339
- };
340
- })
341
- );
342
- const totalSize = fileInfos.reduce((sum, file) => sum + file.size, 0);
343
- ctx.logger.info(
344
- `${type} directory total size: ${(totalSize / (1024 * 1024)).toFixed(2)} MB, max allowed: ${(maxSize / (1024 * 1024)).toFixed(2)} MB`
345
- );
346
- if (totalSize > maxSize) {
347
- ctx.logger.warn(
348
- `${type} directory size exceeds limit! Total: ${(totalSize / (1024 * 1024)).toFixed(2)} MB, Max: ${(maxSize / (1024 * 1024)).toFixed(2)} MB`
349
- );
350
- fileInfos.sort((a, b) => a.mtime - b.mtime);
351
- let currentSize = totalSize;
352
- let filesToDelete = [];
353
- for (const file of fileInfos) {
354
- if (currentSize <= maxSize) {
355
- break;
356
- }
357
- filesToDelete.push(file);
358
- currentSize -= file.size;
359
- }
360
- for (const file of filesToDelete) {
361
- await import_node_fs.promises.unlink(file.path);
362
- ctx.logger.info(
363
- `Deleted oldest ${type} file: ${import_node_path.default.basename(file.path)} (${(file.size / (1024 * 1024)).toFixed(2)} MB)`
364
- );
365
- }
366
- ctx.logger.info(
367
- `Cleanup completed. ${type} directory new size: ${(currentSize / (1024 * 1024)).toFixed(2)} MB`
368
- );
369
- }
370
- } catch (err) {
371
- ctx.logger.error(`Failed to check and clean ${type} files: ${err}`);
372
- }
373
- }
374
232
  async function deleteMediaFilesFromMessage(ctx, content) {
375
233
  try {
376
234
  const elements = JSON.parse(content);
@@ -488,60 +346,6 @@ function formatDate(date) {
488
346
  });
489
347
  }
490
348
 
491
- // src/forward-helper.ts
492
- async function reconstructForwardMsg(ctx, session, message, cfg) {
493
- return Promise.all(
494
- message.map(async (msg) => {
495
- const content = await processForwardMessageContent(ctx, session, msg, cfg);
496
- const senderNickname = msg.sender.nickname;
497
- let senderUserId = msg.sender.user_id;
498
- senderUserId = senderUserId === 1094950020 ? await getUserIdFromNickname(session, senderNickname, senderUserId) : senderUserId;
499
- return {
500
- type: "node",
501
- data: {
502
- user_id: senderUserId,
503
- nickname: senderNickname,
504
- content
505
- }
506
- };
507
- })
508
- );
509
- }
510
- async function getUserIdFromNickname(session, nickname, userId) {
511
- const memberInfos = await session.onebot.getGroupMemberList(session.channelId);
512
- const matches = memberInfos.filter((m) => m.nickname === nickname);
513
- if (matches.length === 1) {
514
- return matches[0].user_id;
515
- }
516
- return userId;
517
- }
518
- async function processForwardMessageContent(ctx, session, msg, cfg) {
519
- if (typeof msg.message === "string") {
520
- return msg.message;
521
- }
522
- const firstElement = msg.message[0];
523
- if (firstElement?.type === "forward") {
524
- return reconstructForwardMsg(ctx, session, firstElement.data.content, cfg);
525
- }
526
- return Promise.all(
527
- msg.message.map(async (element) => {
528
- return processMediaElement(ctx, element, cfg);
529
- })
530
- );
531
- }
532
-
533
- // src/msg-helper.ts
534
- async function processMessageContent(ctx, msg, cfg) {
535
- return Promise.all(
536
- msg.map(async (element) => {
537
- if (element.type === "reply") {
538
- return element;
539
- }
540
- return processMediaElement(ctx, element, cfg);
541
- })
542
- );
543
- }
544
-
545
349
  // src/index.ts
546
350
  var import_koishi_plugin_adapter_onebot3 = require("@pynickle/koishi-plugin-adapter-onebot");
547
351
  var import_koishi = require("koishi");
@@ -583,8 +387,10 @@ function apply(ctx, cfg) {
583
387
  ctx.command("cave [id:number]").action(
584
388
  async ({ session }, id) => await getCave(ctx, session, cfg, id)
585
389
  );
586
- ctx.command("cave.echo [...userIds:user]").action(
587
- async ({ session }, ...userIds) => await addCave(ctx, session, cfg, userIds)
390
+ ctx.command("cave.echo [userIds:text]").action(
391
+ async ({ session }, userIds) => {
392
+ ctx.logger.info(`User ${session.userId} is adding a cave message with related users: ${userIds}`);
393
+ }
588
394
  );
589
395
  ctx.command("cave.wipe <id:number>").action(
590
396
  async ({ session }, id) => await deleteCave(ctx, session, cfg, id)
@@ -593,8 +399,11 @@ function apply(ctx, cfg) {
593
399
  ctx.command("cave.trace").action(
594
400
  async ({ session }) => await getCaveListByOriginUser(ctx, session)
595
401
  );
596
- ctx.command("cave.bind <id:number> <...userIds:user>", { authority: 4 }).action(
597
- async ({ session }, id, ...userIds) => await bindUsersToCave(ctx, session, id, userIds)
402
+ ctx.command("cave.bind <id:number> <...userIds>", { authority: 4 }).action(
403
+ async ({ session }, id, ...userIds) => {
404
+ ctx.logger.info(`Binding users ${JSON.stringify(userIds)} to cave ID ${id}`);
405
+ await bindUsersToCave(ctx, session, id, userIds);
406
+ }
598
407
  );
599
408
  }
600
409
  async function getCaveListByUser(ctx, session) {
@@ -701,74 +510,6 @@ async function deleteCave(ctx, session, cfg, id) {
701
510
  await ctx.database.remove("echo_cave", id);
702
511
  return session.text(".msgDeleted", [id]);
703
512
  }
704
- async function addCave(ctx, session, cfg, userIds) {
705
- if (!session.guildId) {
706
- return session.text("echo-cave.general.privateChatReminder");
707
- }
708
- if (!session.quote) {
709
- return session.text(".noMsgQuoted");
710
- }
711
- const { userId, channelId, quote } = session;
712
- const messageId = quote.id;
713
- let parsedUserIds = [];
714
- if (userIds && userIds.length > 0) {
715
- ctx.logger.info(`Original userIds in addCave: ${JSON.stringify(userIds)}`);
716
- const result = parseUserIds(userIds);
717
- if (result.error === "invalid_all_mention") {
718
- return session.text(".invalidAllMention");
719
- }
720
- parsedUserIds = result.parsedUserIds;
721
- ctx.logger.info(`Parsed userIds in addCave: ${JSON.stringify(parsedUserIds)}`);
722
- const isAllUsersInGroup = await checkUsersInGroup(ctx, session, parsedUserIds);
723
- if (!isAllUsersInGroup) {
724
- return session.text(".userNotInGroup");
725
- }
726
- }
727
- let content;
728
- let type;
729
- if (quote.elements[0].type === "forward") {
730
- type = "forward";
731
- const message = await reconstructForwardMsg(
732
- ctx,
733
- session,
734
- await session.onebot.getForwardMsg(messageId),
735
- cfg
736
- );
737
- content = JSON.stringify(message);
738
- } else {
739
- type = "msg";
740
- const message = (await session.onebot.getMsg(messageId)).message;
741
- let msgJson;
742
- if (typeof message === "string") {
743
- msgJson = import_koishi_plugin_adapter_onebot3.CQCode.parse(message);
744
- } else {
745
- if (message[0].type === "video" || message[0].type === "file") {
746
- type = "forward";
747
- }
748
- msgJson = message;
749
- }
750
- content = JSON.stringify(await processMessageContent(ctx, msgJson, cfg));
751
- }
752
- await ctx.database.get("echo_cave", { content }).then((existing) => {
753
- if (existing) {
754
- return session.text(".existingMsg");
755
- }
756
- });
757
- try {
758
- const result = await ctx.database.create("echo_cave", {
759
- channelId,
760
- createTime: /* @__PURE__ */ new Date(),
761
- userId,
762
- originUserId: quote.user.id,
763
- type,
764
- content,
765
- relatedUsers: parsedUserIds || []
766
- });
767
- return session.text(".msgSaved", [result.id]);
768
- } catch (error) {
769
- return session.text(".msgFailedToSave");
770
- }
771
- }
772
513
  async function bindUsersToCave(ctx, session, id, userIds) {
773
514
  if (!session.guildId) {
774
515
  return session.text("echo-cave.general.privateChatReminder");
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.16.9",
4
+ "version": "1.16.11",
5
5
  "main": "lib/index.cjs",
6
6
  "typings": "lib/index.d.ts",
7
7
  "type": "module",