koishi-plugin-best-cave 2.3.7 → 2.3.9

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/Utils.d.ts CHANGED
@@ -50,9 +50,11 @@ export declare function updateCooldownTimestamp(session: Session, config: Config
50
50
  * @param sourceElements 原始的 Koishi 消息元素数组。
51
51
  * @param newId 这条回声洞的新 ID。
52
52
  * @param session 触发操作的会话。
53
+ * @param config 插件配置。
54
+ * @param logger 日志实例。
53
55
  * @returns 包含数据库元素和待保存媒体列表的对象。
54
56
  */
55
- export declare function processMessageElements(sourceElements: h[], newId: number, session: Session): Promise<{
57
+ export declare function processMessageElements(sourceElements: h[], newId: number, session: Session, config: Config, logger: Logger): Promise<{
56
58
  finalElementsForDb: StoredElement[];
57
59
  mediaToSave: {
58
60
  sourceUrl: string;
package/lib/index.d.ts CHANGED
@@ -48,6 +48,7 @@ export interface Config {
48
48
  secretAccessKey?: string;
49
49
  bucket?: string;
50
50
  publicUrl?: string;
51
+ debug: boolean;
51
52
  }
52
53
  export declare const Config: Schema<Config>;
53
54
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js CHANGED
@@ -406,57 +406,46 @@ function updateCooldownTimestamp(session, config, lastUsed) {
406
406
  }
407
407
  }
408
408
  __name(updateCooldownTimestamp, "updateCooldownTimestamp");
409
- async function processMessageElements(sourceElements, newId, session) {
409
+ async function processMessageElements(sourceElements, newId, session, config, logger2) {
410
410
  const mediaToSave = [];
411
411
  let mediaIndex = 0;
412
- async function transform(elements, logger2 = new import_koishi.Logger("best-cave:transform")) {
412
+ async function transform(elements) {
413
413
  const result = [];
414
414
  const typeMap = { "img": "image", "image": "image", "video": "video", "audio": "audio", "file": "file", "text": "text", "at": "at", "forward": "forward" };
415
415
  const defaultExtMap = { "image": ".jpg", "video": ".mp4", "audio": ".mp3", "file": ".dat" };
416
416
  for (const el of elements) {
417
417
  const type = typeMap[el.type];
418
+ if (config.debug) logger2.info(`正在处理元素 <${el.type}>, 映射类型: ${type || "无"}`);
418
419
  if (!type) {
419
- if (el.children) result.push(...await transform(el.children, logger2));
420
+ if (el.children) result.push(...await transform(el.children));
420
421
  continue;
421
422
  }
422
423
  if (type === "text" && el.attrs.content?.trim()) {
423
- result.push({ type: "text", content: el.attrs.content.trim() });
424
+ const content = el.attrs.content.trim();
425
+ if (config.debug) logger2.info(`发现 [text] 元素,内容: "${content}"`);
426
+ result.push({ type: "text", content });
424
427
  } else if (type === "at" && el.attrs.id) {
428
+ if (config.debug) logger2.info(`发现 [at] 元素,ID: "${el.attrs.id}"`);
425
429
  result.push({ type: "at", content: el.attrs.id });
426
- } else if (type === "forward") {
427
- const childrenToProcess = [...el.children || []];
428
- if (childrenToProcess.length === 0 && Array.isArray(el.attrs.content)) {
429
- for (const node of el.attrs.content) {
430
- if (!node) continue;
431
- const contentToNormalize = node.message;
432
- if (contentToNormalize) {
433
- try {
434
- childrenToProcess.push(...import_koishi.h.normalize(contentToNormalize));
435
- } catch (error) {
436
- logger2.warn(`跳过无法解析的转发节点内容: ${error}`);
437
- childrenToProcess.push(import_koishi.h.text("[内容解析失败]"));
438
- }
439
- }
440
- }
441
- }
442
- if (childrenToProcess.length > 0) {
443
- const transformedChildren = await transform(childrenToProcess, logger2);
444
- if (transformedChildren.length > 0) {
445
- result.push({ type: "forward", content: JSON.stringify(transformedChildren) });
446
- }
447
- }
430
+ } else if (type === "forward" && el.children?.length) {
431
+ if (config.debug) logger2.info(`发现 [forward] 元素,开始递归解析子元素...`);
432
+ const transformedChildren = await transform(el.children);
433
+ result.push({ type: "forward", content: JSON.stringify(transformedChildren) });
448
434
  } else if (["image", "video", "audio", "file"].includes(type) && el.attrs.src) {
449
435
  let fileIdentifier = el.attrs.src;
436
+ if (config.debug) logger2.info(`发现 [${type}] 元素,src: "${fileIdentifier}"`);
450
437
  if (fileIdentifier.startsWith("http")) {
451
438
  const ext = path2.extname(el.attrs.file || "") || defaultExtMap[type];
452
439
  const currentMediaIndex = ++mediaIndex;
453
440
  const fileName = `${newId}_${currentMediaIndex}_${session.channelId || "private"}_${session.userId}${ext}`;
441
+ if (config.debug) logger2.info(`[${type}] 是远程文件,文件名: "${fileName}"`);
454
442
  mediaToSave.push({ sourceUrl: fileIdentifier, fileName });
455
443
  fileIdentifier = fileName;
456
444
  }
457
445
  result.push({ type, file: fileIdentifier });
458
446
  } else if (el.children) {
459
- result.push(...await transform(el.children, logger2));
447
+ if (config.debug) logger2.info(`元素 <${el.type}> 无直接内容,递归其子元素...`);
448
+ result.push(...await transform(el.children));
460
449
  }
461
450
  }
462
451
  return result;
@@ -472,7 +461,6 @@ async function handleFileUploads(ctx, config, fileManager, logger2, reviewManage
472
461
  const imageHashesToStore = [];
473
462
  const allExistingImageHashes = hashManager ? await ctx.database.get("cave_hash", { type: { $ne: "simhash" } }) : [];
474
463
  const existingGlobalHashes = allExistingImageHashes.filter((h4) => h4.type === "phash_g");
475
- const existingQuadrantHashes = allExistingImageHashes.filter((h4) => h4.type.startsWith("phash_q"));
476
464
  for (const media of mediaToToSave) {
477
465
  const buffer = Buffer.from(await ctx.http.get(media.sourceUrl, { responseType: "arraybuffer", timeout: 3e4 }));
478
466
  downloadedMedia.push({ fileName: media.fileName, buffer });
@@ -487,16 +475,6 @@ async function handleFileUploads(ctx, config, fileManager, logger2, reviewManage
487
475
  return;
488
476
  }
489
477
  }
490
- const notifiedPartialCaves = /* @__PURE__ */ new Set();
491
- for (const newSubHash of Object.values(quadrantHashes)) {
492
- for (const existing of existingQuadrantHashes) {
493
- if (notifiedPartialCaves.has(existing.cave)) continue;
494
- if (newSubHash === existing.hash) {
495
- await session.send(`图片与回声洞(${existing.cave})局部相同`);
496
- notifiedPartialCaves.add(existing.cave);
497
- }
498
- }
499
- }
500
478
  imageHashesToStore.push({ hash: globalHash, type: "phash_g" });
501
479
  imageHashesToStore.push({ hash: quadrantHashes.q1, type: "phash_q1" });
502
480
  imageHashesToStore.push({ hash: quadrantHashes.q2, type: "phash_q2" });
@@ -1027,7 +1005,10 @@ var Config = import_koishi3.Schema.intersect([
1027
1005
  region: import_koishi3.Schema.string().default("auto").description("区域 (Region)"),
1028
1006
  accessKeyId: import_koishi3.Schema.string().description("Access Key ID").role("secret"),
1029
1007
  secretAccessKey: import_koishi3.Schema.string().description("Secret Access Key").role("secret")
1030
- }).description("存储配置")
1008
+ }).description("存储配置"),
1009
+ import_koishi3.Schema.object({
1010
+ debug: import_koishi3.Schema.boolean().default(false).description("启用调试模式,将在控制台输出详细的操作日志。")
1011
+ }).description("开发配置")
1031
1012
  ]);
1032
1013
  function apply(ctx, config) {
1033
1014
  ctx.model.extend("cave", {
@@ -1070,18 +1051,36 @@ function apply(ctx, config) {
1070
1051
  });
1071
1052
  cave.subcommand(".add [content:text]", "添加回声洞").usage("添加一条回声洞。可直接发送内容,也可回复或引用消息。").action(async ({ session }, content) => {
1072
1053
  try {
1073
- let sourceElements = session.quote?.elements;
1074
- if (!sourceElements && content?.trim()) {
1054
+ let sourceElements;
1055
+ let sourceOrigin = "";
1056
+ if (session.quote?.elements) {
1057
+ sourceElements = session.quote.elements;
1058
+ sourceOrigin = "引用(quote)";
1059
+ } else if (content?.trim()) {
1075
1060
  sourceElements = import_koishi3.h.parse(content);
1076
- }
1077
- if (!sourceElements) {
1061
+ sourceOrigin = `指令参数(content)`;
1062
+ } else {
1078
1063
  await session.send("请在一分钟内发送你要添加的内容");
1079
1064
  const reply = await session.prompt(6e4);
1080
1065
  if (!reply) return "等待操作超时";
1081
1066
  sourceElements = import_koishi3.h.parse(reply);
1067
+ sourceOrigin = `用户回复(prompt)`;
1068
+ }
1069
+ if (config.debug) {
1070
+ logger.info(`内容来源: ${sourceOrigin}`);
1071
+ logger.info(`获取到的消息内容 (sourceElements):
1072
+ ${JSON.stringify(sourceElements, null, 2)}`);
1073
+ logger.info(`完整的会话对象 (session):
1074
+ ${JSON.stringify(session, null, 2)}`);
1082
1075
  }
1083
1076
  const newId = await getNextCaveId(ctx, getScopeQuery(session, config, false), reusableIds);
1084
- const { finalElementsForDb, mediaToSave } = await processMessageElements(sourceElements, newId, session);
1077
+ const { finalElementsForDb, mediaToSave } = await processMessageElements(sourceElements, newId, session, config, logger);
1078
+ if (config.debug) {
1079
+ logger.info(`提取后数据库元素(finalElementsForDb):
1080
+ ${JSON.stringify(finalElementsForDb, null, 2)}`);
1081
+ logger.info(`提取后待存媒体(mediaToSave):
1082
+ ${JSON.stringify(mediaToSave, null, 2)}`);
1083
+ }
1085
1084
  if (finalElementsForDb.length === 0) return "无可添加内容";
1086
1085
  const textHashesToStore = [];
1087
1086
  if (hashManager) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-best-cave",
3
3
  "description": "功能强大、高度可定制的回声洞。支持丰富的媒体类型、内容查重、人工审核、用户昵称、数据迁移以及本地/S3 双重文件存储后端。",
4
- "version": "2.3.7",
4
+ "version": "2.3.9",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],