koishi-plugin-best-cave 2.6.4 → 2.6.6

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
@@ -44,9 +44,10 @@ export declare function getNextCaveId(ctx: Context, reusableIds: Set<number>): P
44
44
  * @param session 触发操作的会话。
45
45
  * @param config 插件配置。
46
46
  * @param logger 日志实例。
47
+ * @param creationTime 统一的创建时间戳,用于生成文件名。
47
48
  * @returns 包含数据库元素和待保存媒体列表的对象。
48
49
  */
49
- export declare function processMessageElements(sourceElements: h[], newId: number, session: Session, config: Config, logger: Logger): Promise<{
50
+ export declare function processMessageElements(sourceElements: h[], newId: number, session: Session, config: Config, logger: Logger, creationTime: Date): Promise<{
50
51
  finalElementsForDb: StoredElement[];
51
52
  mediaToSave: {
52
53
  sourceUrl: string;
package/lib/index.js CHANGED
@@ -249,9 +249,8 @@ var DataManager = class {
249
249
  async exportData() {
250
250
  const fileName = "cave_export.json";
251
251
  const cavesToExport = await this.ctx.database.get("cave", { status: "active" });
252
- const portableCaves = cavesToExport.map(({ id, ...rest }) => rest);
253
- await this.fileManager.saveFile(fileName, Buffer.from(JSON.stringify(portableCaves, null, 2)));
254
- return `成功导出 ${portableCaves.length} 条数据`;
252
+ await this.fileManager.saveFile(fileName, Buffer.from(JSON.stringify(cavesToExport, null, 2)));
253
+ return `成功导出 ${cavesToExport.length} 条数据`;
255
254
  }
256
255
  /**
257
256
  * @description 从 `cave_import.json` 文件导入回声洞数据。
@@ -267,15 +266,34 @@ var DataManager = class {
267
266
  } catch (error) {
268
267
  throw new Error(`读取导入文件失败: ${error.message}`);
269
268
  }
270
- const [lastCave] = await this.ctx.database.get("cave", {}, { sort: { id: "desc" }, limit: 1 });
271
- let startId = (lastCave?.id || 0) + 1;
272
- const newCavesToInsert = importedCaves.map((cave, index) => ({
273
- ...cave,
274
- id: startId + index,
275
- status: "active"
276
- }));
277
- await this.ctx.database.upsert("cave", newCavesToInsert);
278
- return `成功导入 ${newCavesToInsert.length} 条数据`;
269
+ const allDbCaves = await this.ctx.database.get("cave", {}, { fields: ["id"] });
270
+ const existingIds = new Set(allDbCaves.map((c) => c.id));
271
+ let maxId = allDbCaves.length > 0 ? Math.max(...allDbCaves.map((c) => c.id)) : 0;
272
+ const nonConflictingCaves = [];
273
+ const conflictingCaves = [];
274
+ let invalidCount = 0;
275
+ for (const importedCave of importedCaves) {
276
+ if (typeof importedCave.id !== "number" || !Array.isArray(importedCave.elements)) {
277
+ this.logger.warn(`回声洞(${importedCave.id})无效: ${JSON.stringify(importedCave)}`);
278
+ invalidCount++;
279
+ continue;
280
+ }
281
+ if (existingIds.has(importedCave.id)) {
282
+ conflictingCaves.push(importedCave);
283
+ } else {
284
+ nonConflictingCaves.push({ ...importedCave, status: "active" });
285
+ existingIds.add(importedCave.id);
286
+ maxId = Math.max(maxId, importedCave.id);
287
+ }
288
+ }
289
+ const newCavesFromConflicts = conflictingCaves.map((cave) => {
290
+ maxId++;
291
+ this.logger.info(`回声洞(${cave.id})已转移至(${maxId})`);
292
+ return { ...cave, maxId, status: "active" };
293
+ });
294
+ const finalCavesToUpsert = [...nonConflictingCaves, ...newCavesFromConflicts];
295
+ if (finalCavesToUpsert.length > 0) await this.ctx.database.upsert("cave", finalCavesToUpsert);
296
+ return `成功导入 ${finalCavesToUpsert.length} 条数据`;
279
297
  }
280
298
  };
281
299
 
@@ -439,7 +457,7 @@ async function getNextCaveId(ctx, reusableIds) {
439
457
  return newId;
440
458
  }
441
459
  __name(getNextCaveId, "getNextCaveId");
442
- async function processMessageElements(sourceElements, newId, session, config, logger2) {
460
+ async function processMessageElements(sourceElements, newId, session, config, logger2, creationTime) {
443
461
  const mediaToSave = [];
444
462
  let mediaIndex = 0;
445
463
  const typeMap = { "img": "image", "image": "image", "video": "video", "audio": "audio", "file": "file", "text": "text", "at": "at", "forward": "forward", "reply": "reply", "face": "face" };
@@ -462,7 +480,7 @@ async function processMessageElements(sourceElements, newId, session, config, lo
462
480
  if (fileIdentifier.startsWith("http")) {
463
481
  const ext = path2.extname(segment.data.file || "") || defaultExtMap[sType];
464
482
  const currentMediaIndex = ++mediaIndex;
465
- const fileName = `${newId}_${currentMediaIndex}_${session.channelId || session.guildId}_${session.userId}${ext}`;
483
+ const fileName = `${newId}_${currentMediaIndex}_${session.channelId || session.guildId}_${session.userId}_${creationTime.getTime()}${ext}`;
466
484
  mediaToSave.push({ sourceUrl: fileIdentifier, fileName });
467
485
  fileIdentifier = fileName;
468
486
  }
@@ -509,7 +527,7 @@ async function processMessageElements(sourceElements, newId, session, config, lo
509
527
  if (fileIdentifier.startsWith("http")) {
510
528
  const ext = path2.extname(el.attrs.file || "") || defaultExtMap[type];
511
529
  const currentMediaIndex = ++mediaIndex;
512
- const fileName = `${newId}_${currentMediaIndex}_${session.channelId || session.guildId}_${session.userId}${ext}`;
530
+ const fileName = `${newId}_${creationTime.getTime()}_${currentMediaIndex}_${session.userId}${ext}`;
513
531
  mediaToSave.push({ sourceUrl: fileIdentifier, fileName });
514
532
  fileIdentifier = fileName;
515
533
  }
@@ -1051,7 +1069,8 @@ function apply(ctx, config) {
1051
1069
  sourceElements = import_koishi3.h.parse(reply);
1052
1070
  }
1053
1071
  const newId = await getNextCaveId(ctx, reusableIds);
1054
- const { finalElementsForDb, mediaToSave } = await processMessageElements(sourceElements, newId, session, config, logger);
1072
+ const creationTime = /* @__PURE__ */ new Date();
1073
+ const { finalElementsForDb, mediaToSave } = await processMessageElements(sourceElements, newId, session, config, logger, creationTime);
1055
1074
  if (finalElementsForDb.length === 0) return "无可添加内容";
1056
1075
  const textHashesToStore = [];
1057
1076
  if (hashManager) {
@@ -1079,7 +1098,7 @@ function apply(ctx, config) {
1079
1098
  userId: session.userId,
1080
1099
  userName,
1081
1100
  status: initialStatus,
1082
- time: /* @__PURE__ */ new Date()
1101
+ time: creationTime
1083
1102
  });
1084
1103
  if (hasMedia) {
1085
1104
  handleFileUploads(ctx, config, fileManager, logger, reviewManager, newCave, mediaToSave, reusableIds, session, hashManager, textHashesToStore);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-best-cave",
3
3
  "description": "功能强大、高度可定制的回声洞。支持丰富的媒体类型、内容查重、人工审核、用户昵称、数据迁移以及本地/S3 双重文件存储后端。",
4
- "version": "2.6.4",
4
+ "version": "2.6.6",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],
@@ -29,6 +29,6 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@aws-sdk/client-s3": "^3.800.0",
32
- "koishi-plugin-shikoi": "0.0.1"
32
+ "sharp": "^0.32.1"
33
33
  }
34
34
  }