koishi-plugin-best-cave 2.0.1 → 2.0.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.
@@ -0,0 +1,38 @@
1
+ import { Context, Logger } from 'koishi';
2
+ import { FileManager } from './FileManager';
3
+ import { Config } from './index';
4
+ /**
5
+ * 数据管理器 (DataManager)
6
+ * @description
7
+ * 负责处理回声洞数据的导入和导出功能。
8
+ */
9
+ export declare class DataManager {
10
+ private ctx;
11
+ private config;
12
+ private fileManager;
13
+ private logger;
14
+ /**
15
+ * 创建一个 DataManager 实例。
16
+ * @param ctx - Koishi 上下文,用于数据库操作。
17
+ * @param config - 插件配置。
18
+ * @param fileManager - 文件管理器实例,用于读写导入/导出文件。
19
+ * @param logger - 日志记录器实例。
20
+ */
21
+ constructor(ctx: Context, config: Config, fileManager: FileManager, logger: Logger);
22
+ /**
23
+ * 注册与数据导入导出相关的 `.export` 和 `.import` 子命令。
24
+ * @param cave - 主 `cave` 命令的实例,用于挂载子命令。
25
+ */
26
+ registerCommands(cave: any): void;
27
+ /**
28
+ * 导出所有状态为 'active' 的回声洞数据。
29
+ * 数据将被序列化为 JSON 并保存到 `cave_export.json` 文件中。
30
+ * @returns 一个描述导出结果的字符串消息。
31
+ */
32
+ exportData(): Promise<string>;
33
+ /**
34
+ * 从 `cave_import.json` 文件导入回声洞数据。
35
+ * @returns 一个描述导入结果的字符串消息。
36
+ */
37
+ importData(): Promise<string>;
38
+ }
package/lib/Utils.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ import { Context, h, Logger, Session } from 'koishi';
2
+ import { CaveObject, Config, StoredElement } from './index';
3
+ import { FileManager } from './FileManager';
4
+ /**
5
+ * 将数据库中存储的 StoredElement[] 数组转换为 Koishi h() 元素数组。
6
+ * @param elements - 从数据库读取的元素对象数组。
7
+ * @returns 转换后的 h() 元素数组,用于消息发送。
8
+ */
9
+ export declare function storedFormatToHElements(elements: StoredElement[]): h[];
10
+ /**
11
+ * 将指向本地媒体文件的 h() 元素转换为内联 Base64 格式。
12
+ * @param element - 包含本地文件路径的 h() 媒体元素。
13
+ * @param fileManager - FileManager 实例,用于读取文件。
14
+ * @param logger - Logger 实例,用于记录错误。
15
+ * @returns 转换后的 h() 元素,其 src 属性为 Base64 数据 URI。
16
+ */
17
+ export declare function mediaElementToBase64(element: h, fileManager: FileManager, logger: Logger): Promise<h>;
18
+ /**
19
+ * 构建一条包含回声洞内容的完整消息,准备发送。
20
+ * 此函数会处理 S3 URL、文件映射路径或本地文件到 Base64 的转换。
21
+ * @param cave - 要展示的回声洞对象。
22
+ * @param config - 插件配置。
23
+ * @param fileManager - FileManager 实例。
24
+ * @param logger - Logger 实例。
25
+ * @returns 一个包含 h() 元素和字符串的消息数组。
26
+ */
27
+ export declare function buildCaveMessage(cave: CaveObject, config: Config, fileManager: FileManager, logger: Logger): Promise<(string | h)[]>;
28
+ /**
29
+ * 清理数据库中所有被标记为 'delete' 状态的回声洞及其关联的文件。
30
+ * @param ctx - Koishi 上下文。
31
+ * @param fileManager - FileManager 实例,用于删除文件。
32
+ * @param logger - Logger 实例。
33
+ */
34
+ export declare function cleanupPendingDeletions(ctx: Context, fileManager: FileManager, logger: Logger): Promise<void>;
35
+ /**
36
+ * 根据插件配置(是否分群)和当前会话,生成数据库查询所需的范围条件。
37
+ * @param session - 当前会话对象。
38
+ * @param config - 插件配置。
39
+ * @returns 一个用于数据库查询的条件对象。
40
+ */
41
+ export declare function getScopeQuery(session: Session, config: Config): object;
42
+ /**
43
+ * 获取下一个可用的回声洞 ID。
44
+ * 策略是找到当前已存在的 ID 中最小的未使用正整数。
45
+ * @param ctx - Koishi 上下文。
46
+ * @param query - 查询回声洞的范围条件,用于分群模式。
47
+ * @returns 一个可用的新 ID。
48
+ * @performance 对于非常大的数据集,此函数可能会有性能瓶颈,因为它需要获取所有现有 ID。
49
+ */
50
+ export declare function getNextCaveId(ctx: Context, query?: object): Promise<number>;
51
+ /**
52
+ * 下载网络媒体资源并保存到文件存储中(本地或 S3)。
53
+ * @param ctx - Koishi 上下文。
54
+ * @param fileManager - FileManager 实例。
55
+ * @param url - 媒体资源的 URL。
56
+ * @param originalName - 原始文件名,用于获取扩展名。
57
+ * @param type - 媒体类型 ('img', 'video', 'audio', 'file')。
58
+ * @param caveId - 新建回声洞的 ID。
59
+ * @param index - 媒体在消息中的索引。
60
+ * @param channelId - 频道 ID。
61
+ * @param userId - 用户 ID。
62
+ * @returns 保存后的文件名/标识符。
63
+ */
64
+ export declare function downloadMedia(ctx: Context, fileManager: FileManager, url: string, originalName: string, type: string, caveId: number, index: number, channelId: string, userId: string): Promise<string>;
65
+ /**
66
+ * 检查用户在当前频道是否处于指令冷却状态。
67
+ * @param session - 当前会话对象。
68
+ * @param config - 插件配置。
69
+ * @param lastUsed - 存储各频道最后使用时间的 Map。
70
+ * @returns 如果处于冷却中,返回提示信息字符串;否则返回 null。
71
+ */
72
+ export declare function checkCooldown(session: Session, config: Config, lastUsed: Map<string, number>): string | null;
73
+ /**
74
+ * 更新指定频道的指令使用时间戳。
75
+ * @param session - 当前会话对象。
76
+ * @param config - 插件配置。
77
+ * @param lastUsed - 存储各频道最后使用时间的 Map。
78
+ */
79
+ export declare function updateCooldownTimestamp(session: Session, config: Config, lastUsed: Map<string, number>): void;
package/lib/index.d.ts CHANGED
@@ -41,13 +41,14 @@ declare module 'koishi' {
41
41
  * 插件的配置接口。
42
42
  */
43
43
  export interface Config {
44
- cooldown: number;
44
+ coolDown: number;
45
45
  perChannel: boolean;
46
46
  adminUsers: string[];
47
47
  enableProfile: boolean;
48
- enableDataIO: boolean;
48
+ enableIO: boolean;
49
49
  enableReview: boolean;
50
50
  caveFormat: string;
51
+ localPath?: string;
51
52
  enableS3: boolean;
52
53
  endpoint?: string;
53
54
  region?: string;
package/lib/index.js CHANGED
@@ -298,23 +298,27 @@ async function mediaElementToBase64(element, fileManager, logger2) {
298
298
  __name(mediaElementToBase64, "mediaElementToBase64");
299
299
  async function buildCaveMessage(cave, config, fileManager, logger2) {
300
300
  const caveHElements = storedFormatToHElements(cave.elements);
301
- const processedElements = await Promise.all(caveHElements.map(async (element) => {
301
+ const processedElements = await Promise.all(caveHElements.map((element) => {
302
302
  const isMedia = ["image", "video", "audio", "file"].includes(element.type);
303
303
  const fileName = element.attrs.src;
304
304
  if (!isMedia || !fileName) {
305
- return element;
305
+ return Promise.resolve(element);
306
306
  }
307
307
  if (config.enableS3 && config.publicUrl) {
308
308
  const fullUrl = config.publicUrl.endsWith("/") ? `${config.publicUrl}${fileName}` : `${config.publicUrl}/${fileName}`;
309
- return (0, import_koishi.h)(element.type, { ...element.attrs, src: fullUrl });
309
+ return Promise.resolve((0, import_koishi.h)(element.type, { ...element.attrs, src: fullUrl }));
310
+ }
311
+ if (config.localPath) {
312
+ const mappedPath = path2.join(config.localPath, fileName);
313
+ const fileUri = `file://${mappedPath}`;
314
+ return Promise.resolve((0, import_koishi.h)(element.type, { ...element.attrs, src: fileUri }));
310
315
  }
311
316
  return mediaElementToBase64(element, fileManager, logger2);
312
317
  }));
313
318
  const finalMessage = [];
314
319
  const formatString = config.caveFormat;
315
320
  const separatorIndex = formatString.indexOf("|");
316
- let headerFormat;
317
- let footerFormat;
321
+ let headerFormat, footerFormat;
318
322
  if (separatorIndex === -1) {
319
323
  headerFormat = formatString;
320
324
  footerFormat = "";
@@ -323,14 +327,10 @@ async function buildCaveMessage(cave, config, fileManager, logger2) {
323
327
  footerFormat = formatString.substring(separatorIndex + 1);
324
328
  }
325
329
  const headerText = headerFormat.replace("{id}", cave.id.toString()).replace("{name}", cave.userName);
326
- if (headerText.trim()) {
327
- finalMessage.push((0, import_koishi.h)("p", {}, headerText));
328
- }
330
+ if (headerText.trim()) finalMessage.push((0, import_koishi.h)("p", {}, headerText));
329
331
  finalMessage.push(...processedElements);
330
332
  const footerText = footerFormat.replace("{id}", cave.id.toString()).replace("{name}", cave.userName);
331
- if (footerText.trim()) {
332
- finalMessage.push((0, import_koishi.h)("p", {}, footerText));
333
- }
333
+ if (footerText.trim()) finalMessage.push((0, import_koishi.h)("p", {}, footerText));
334
334
  return finalMessage;
335
335
  }
336
336
  __name(buildCaveMessage, "buildCaveMessage");
@@ -376,20 +376,20 @@ async function downloadMedia(ctx, fileManager, url, originalName, type, caveId,
376
376
  }
377
377
  __name(downloadMedia, "downloadMedia");
378
378
  function checkCooldown(session, config, lastUsed) {
379
- if (config.cooldown <= 0 || !session.channelId || config.adminUsers.includes(session.userId)) {
379
+ if (config.coolDown <= 0 || !session.channelId || config.adminUsers.includes(session.userId)) {
380
380
  return null;
381
381
  }
382
382
  const now = Date.now();
383
383
  const lastTime = lastUsed.get(session.channelId) || 0;
384
- if (now - lastTime < config.cooldown * 1e3) {
385
- const waitTime = Math.ceil((config.cooldown * 1e3 - (now - lastTime)) / 1e3);
384
+ if (now - lastTime < config.coolDown * 1e3) {
385
+ const waitTime = Math.ceil((config.coolDown * 1e3 - (now - lastTime)) / 1e3);
386
386
  return `指令冷却中,请在 ${waitTime} 秒后重试`;
387
387
  }
388
388
  return null;
389
389
  }
390
390
  __name(checkCooldown, "checkCooldown");
391
391
  function updateCooldownTimestamp(session, config, lastUsed) {
392
- if (config.cooldown > 0 && session.channelId) {
392
+ if (config.coolDown > 0 && session.channelId) {
393
393
  lastUsed.set(session.channelId, Date.now());
394
394
  }
395
395
  }
@@ -633,24 +633,25 @@ var usage = `
633
633
  var logger = new import_koishi3.Logger("best-cave");
634
634
  var Config = import_koishi3.Schema.intersect([
635
635
  import_koishi3.Schema.object({
636
- cooldown: import_koishi3.Schema.number().default(10).description("冷却时间(秒)"),
636
+ coolDown: import_koishi3.Schema.number().default(10).description("冷却时间(秒)"),
637
637
  perChannel: import_koishi3.Schema.boolean().default(false).description("启用分群模式"),
638
638
  enableProfile: import_koishi3.Schema.boolean().default(false).description("启用自定义昵称"),
639
- enableDataIO: import_koishi3.Schema.boolean().default(false).description("启用导入导出"),
640
- adminUsers: import_koishi3.Schema.array(import_koishi3.Schema.string()).default([]).description("管理员 ID 列表"),
641
- caveFormat: import_koishi3.Schema.string().default("回声洞 ——({id})|—— {name}").required().description("自定义文本(使用|分隔)")
639
+ enableIO: import_koishi3.Schema.boolean().default(false).description("启用导入导出"),
640
+ caveFormat: import_koishi3.Schema.string().default("回声洞 ——({id})|—— {name}").required().description("自定义文本"),
641
+ adminUsers: import_koishi3.Schema.array(import_koishi3.Schema.string()).default([]).description("管理员 ID 列表")
642
642
  }).description("基础配置"),
643
643
  import_koishi3.Schema.object({
644
644
  enableReview: import_koishi3.Schema.boolean().default(false).description("启用审核")
645
645
  }).description("审核配置"),
646
646
  import_koishi3.Schema.object({
647
+ localPath: import_koishi3.Schema.string().description("文件映射路径"),
647
648
  enableS3: import_koishi3.Schema.boolean().default(false).description("启用 S3 存储"),
648
- endpoint: import_koishi3.Schema.string().required().description("端点 (Endpoint)"),
649
- bucket: import_koishi3.Schema.string().required().description("存储桶 (Bucket)"),
650
- region: import_koishi3.Schema.string().default("auto").description("区域 (Region)"),
651
649
  publicUrl: import_koishi3.Schema.string().description("公共访问 URL").role("link"),
652
- accessKeyId: import_koishi3.Schema.string().required().description("Access Key ID").role("secret"),
653
- secretAccessKey: import_koishi3.Schema.string().required().description("Secret Access Key").role("secret")
650
+ endpoint: import_koishi3.Schema.string().description("端点 (Endpoint)").role("link"),
651
+ bucket: import_koishi3.Schema.string().description("存储桶 (Bucket)"),
652
+ region: import_koishi3.Schema.string().default("auto").description("区域 (Region)"),
653
+ accessKeyId: import_koishi3.Schema.string().description("Access Key ID").role("secret"),
654
+ secretAccessKey: import_koishi3.Schema.string().description("Secret Access Key").role("secret")
654
655
  }).description("存储配置")
655
656
  ]);
656
657
  function apply(ctx, config) {
@@ -825,7 +826,7 @@ ${caveIds}`;
825
826
  profileManager = new ProfileManager(ctx);
826
827
  profileManager.registerCommands(cave);
827
828
  }
828
- if (config.enableDataIO) {
829
+ if (config.enableIO) {
829
830
  dataManager = new DataManager(ctx, config, fileManager, logger);
830
831
  dataManager.registerCommands(cave);
831
832
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-best-cave",
3
3
  "description": "最强大的回声洞现已重构完成啦!注意数据格式需要使用脚本转换哦~",
4
- "version": "2.0.1",
4
+ "version": "2.0.2",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],