koishi-plugin-best-cave 1.1.4 → 1.1.5

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.d.ts CHANGED
@@ -24,11 +24,3 @@ export interface Config {
24
24
  enablePagination: boolean;
25
25
  itemsPerPage: number;
26
26
  }
27
- export declare function initCavePaths(ctx: Context): Promise<{
28
- dataDir: string;
29
- caveDir: string;
30
- caveFilePath: string;
31
- resourceDir: string;
32
- pendingFilePath: string;
33
- }>;
34
- export declare function handleCaveAction(ctx: Context, config: Config, session: any, options: any, content: string[], lastUsed: Map<string, number>): Promise<string | void>;
package/lib/index.js CHANGED
@@ -33,14 +33,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
33
33
  // src/locales/zh-CN.yml
34
34
  var require_zh_CN = __commonJS({
35
35
  "src/locales/zh-CN.yml"(exports2, module2) {
36
- module2.exports = { _config: { manager: "管理员", blacklist: "黑名单(用户)", whitelist: "审核白名单(用户/群组/频道)", number: "冷却时间(秒)", enableAudit: "启用审核", allowVideo: "允许视频上传", videoMaxSize: "视频最大大小(MB)", imageMaxSize: "图片最大大小(MB)", enablePagination: "启用统计分页", itemsPerPage: "每页显示数目" }, commands: { cave: { description: "回声洞", usage: "支持添加、抽取、查看、管理回声洞", examples: "使用 cave 随机抽取回声洞\n使用 -a 直接添加或引用添加\n使用 -g 查看指定回声洞\n使用 -r 删除指定回声洞", options: { a: "添加回声洞", g: "查看回声洞", r: "删除回声洞", p: "通过审核(批量)", d: "拒绝审核(批量)", l: "查询投稿统计" }, add: { noContent: "请在一分钟内发送内容", operationTimeout: "操作超时,添加取消", videoDisabled: "不允许上传视频", submitPending: "提交成功,序号为({0})", addSuccess: "添加成功,序号为({0})", mediaSizeExceeded: "{0}文件大小超过限制", mediaFormatUnsupported: "{0}格式不支持", videoSendFailed: "视频发送失败" }, remove: { noPermission: "你无权删除他人添加的回声洞", deletePending: "删除(待审核)", deleted: "已删除" }, list: { pageInfo: "第 {0} / {1} 页", header: "当前共有 {0} 项回声洞:", totalItems: "用户 {0} 共计投稿 {1} 项:", idsLine: "{0}" }, audit: { noPending: "暂无待审核回声洞", pendingNotFound: "未找到待审核回声洞", pendingResult: "{0},剩余 {1} 个待审核回声洞:[{2}]", auditPassed: "已通过", auditRejected: "已拒绝", batchAuditResult: "已{0} {1}/{2} 项回声洞", title: "待审核回声洞:", from: "投稿人:", sendFailed: "发送审核消息失败,无法联系管理员 {0}" }, error: { commandProcess: "命令处理失败:{0}", getCave: "获取回声洞失败", noCave: "暂无回声洞", saveFailed: "保存数据失败", mediaLoadFailed: "[加载{0}失败]", videoSendFailed: "视频发送失败", uploadImageFailed: "图片上传失败", uploadVideoFailed: "视频上传失败", fileRead: "读取 JSON 数据失败:{0}", fileWrite: "写入 JSON 数据失败:{0}", notFound: "未找到", userInfo: "获取用户信息失败:{0}", auditProcess: "审核处理失败:{0}", invalidId: "请输入有效的回声洞序号" }, message: { blacklisted: "你已被列入黑名单", managerOnly: "此操作仅限管理员可用", cooldown: "群聊冷却中...请在 {0} 秒后重试", caveTitle: "回声洞 —— ({0})", videoSending: "[视频发送中]", mediaInvalid: "[无效的{0}]", contributorSuffix: "—— {0}", mediaSizeExceeded: "{0}文件大小超过限制" } } } };
36
+ module2.exports = { _config: { manager: "管理员", blacklist: "黑名单(用户)", whitelist: "审核白名单(用户/群组/频道)", number: "冷却时间(秒)", enableAudit: "启用审核", allowVideo: "允许视频上传", videoMaxSize: "视频最大大小(MB)", imageMaxSize: "图片最大大小(MB)", enablePagination: "启用统计分页", itemsPerPage: "每页显示数目" }, commands: { cave: { description: "回声洞", usage: "支持添加、抽取、查看、管理回声洞", examples: "使用 cave 随机抽取回声洞\n使用 -a 直接添加或引用添加\n使用 -g 查看指定回声洞\n使用 -r 删除指定回声洞", options: { a: "添加回声洞", g: "查看回声洞", r: "删除回声洞", p: "通过审核(批量)", d: "拒绝审核(批量)", l: "查询投稿统计" }, add: { noContent: "请在一分钟内发送内容", operationTimeout: "操作超时,添加取消", videoDisabled: "不允许上传视频", submitPending: "提交成功,序号为({0})", addSuccess: "添加成功,序号为({0})", mediaSizeExceeded: "{0}文件大小超过限制", mediaFormatUnsupported: "{0}格式不支持", videoSendFailed: "视频发送失败", localFileNotAllowed: "检测到本地文件路径,无法保存" }, remove: { noPermission: "你无权删除他人添加的回声洞", deletePending: "删除(待审核)", deleted: "已删除" }, list: { pageInfo: "第 {0} / {1} 页", header: "当前共有 {0} 项回声洞:", totalItems: "用户 {0} 共计投稿 {1} 项:", idsLine: "{0}" }, audit: { noPending: "暂无待审核回声洞", pendingNotFound: "未找到待审核回声洞", pendingResult: "{0},剩余 {1} 个待审核回声洞:[{2}]", auditPassed: "已通过", auditRejected: "已拒绝", batchAuditResult: "已{0} {1}/{2} 项回声洞", title: "待审核回声洞:", from: "投稿人:", sendFailed: "发送审核消息失败,无法联系管理员 {0}" }, error: { commandProcess: "命令处理失败:{0}", getCave: "获取回声洞失败", noCave: "暂无回声洞", saveFailed: "保存数据失败", mediaLoadFailed: "[加载{0}失败]", videoSendFailed: "视频发送失败", uploadImageFailed: "图片上传失败", uploadVideoFailed: "视频上传失败", fileRead: "读取 JSON 数据失败:{0}", fileWrite: "写入 JSON 数据失败:{0}", notFound: "未找到", userInfo: "获取用户信息失败:{0}", auditProcess: "审核处理失败:{0}", invalidId: "请输入有效的回声洞序号" }, message: { blacklisted: "你已被列入黑名单", managerOnly: "此操作仅限管理员可用", cooldown: "群聊冷却中...请在 {0} 秒后重试", caveTitle: "回声洞 —— ({0})", videoSending: "[视频发送中]", mediaInvalid: "[无效的{0}]", contributorSuffix: "—— {0}", mediaSizeExceeded: "{0}文件大小超过限制" } } } };
37
37
  }
38
38
  });
39
39
 
40
40
  // src/locales/en-US.yml
41
41
  var require_en_US = __commonJS({
42
42
  "src/locales/en-US.yml"(exports2, module2) {
43
- module2.exports = { _config: { manager: "Manager", blacklist: "Blacklist (User)", whitelist: "Whitelist (User/Group/Channel)", number: "Cooldown Time (Seconds)", enableAudit: "Enable Audit", allowVideo: "Allow Video Upload", videoMaxSize: "Max Video Size (MB)", imageMaxSize: "Max Image Size (MB)", enablePagination: "Enable Pagination", itemsPerPage: "Items Per Page" }, commands: { cave: { description: "Echo Cave", usage: "Support adding, drawing, viewing, and managing Echo Cave", examples: "Use cave to randomly draw Echo Cave\nUse -a to add or reference directly\nUse -g to view specified Echo Cave\nUse -r to delete specified Echo Cave", options: { a: "Add Echo Cave", g: "View Echo Cave", r: "Delete Echo Cave", p: "Approve Audit (Batch)", d: "Reject Audit (Batch)", l: "Query Submission Statistics" }, add: { noContent: "Please send content within one minute", operationTimeout: "Operation timed out, addition canceled", videoDisabled: "Video upload not allowed", submitPending: "Submission successful, ID is ({0})", addSuccess: "Addition successful, ID is ({0})", mediaSizeExceeded: "{0} file size exceeds limit", mediaFormatUnsupported: "{0} format not supported", videoSendFailed: "Video send failed" }, remove: { noPermission: "You do not have permission to delete others' Echo Cave", deletePending: "Delete (Pending Audit)", deleted: "Deleted" }, list: { pageInfo: "Page {0} / {1}", header: "There are currently {0} Echo Caves:", totalItems: "User {0} has submitted a total of {1} items:", idsLine: "{0}" }, audit: { noPending: "No pending Echo Caves", pendingNotFound: "Pending Echo Cave not found", pendingResult: "{0}, {1} pending Echo Caves remaining: [{2}]", auditPassed: "Approved", auditRejected: "Rejected", batchAuditResult: "{0} {1}/{2} Echo Caves", title: "Pending Echo Caves:", from: "Contributor:", sendFailed: "Failed to send audit message, unable to contact manager {0}" }, error: { commandProcess: "Command processing failed: {0}", getCave: "Failed to get Echo Cave", noCave: "No Echo Caves", saveFailed: "Failed to save data", mediaLoadFailed: "[Failed to load {0}]", videoSendFailed: "Video send failed", uploadImageFailed: "Image upload failed", uploadVideoFailed: "Video upload failed", fileRead: "Failed to read JSON data: {0}", fileWrite: "Failed to write JSON data: {0}", notFound: "Not found", userInfo: "Failed to get user information: {0}", auditProcess: "Audit processing failed: {0}", invalidId: "Please enter a valid Echo Cave ID" }, message: { blacklisted: "You have been blacklisted", managerOnly: "This operation is for managers only", cooldown: "Group chat cooldown... Please try again in {0} seconds", caveTitle: "Echo Cave —— ({0})", videoSending: "[Video sending]", mediaInvalid: "[Invalid {0}]", contributorSuffix: "—— {0}", mediaSizeExceeded: "{0} file size exceeds limit" } } } };
43
+ module2.exports = { _config: { manager: "Manager", blacklist: "Blacklist (User)", whitelist: "Whitelist (User/Group/Channel)", number: "Cooldown Time (Seconds)", enableAudit: "Enable Audit", allowVideo: "Allow Video Upload", videoMaxSize: "Max Video Size (MB)", imageMaxSize: "Max Image Size (MB)", enablePagination: "Enable Pagination", itemsPerPage: "Items Per Page" }, commands: { cave: { description: "Echo Cave", usage: "Support adding, drawing, viewing, and managing Echo Cave", examples: "Use cave to randomly draw Echo Cave\nUse -a to add or reference directly\nUse -g to view specified Echo Cave\nUse -r to delete specified Echo Cave", options: { a: "Add Echo Cave", g: "View Echo Cave", r: "Delete Echo Cave", p: "Approve Audit (Batch)", d: "Reject Audit (Batch)", l: "Query Submission Statistics" }, add: { noContent: "Please send content within one minute", operationTimeout: "Operation timed out, addition canceled", videoDisabled: "Video upload not allowed", submitPending: "Submission successful, ID is ({0})", addSuccess: "Addition successful, ID is ({0})", mediaSizeExceeded: "{0} file size exceeds limit", mediaFormatUnsupported: "{0} format not supported", videoSendFailed: "Video send failed", localFileNotAllowed: "Local file path detected, cannot save" }, remove: { noPermission: "You do not have permission to delete others' Echo Cave", deletePending: "Delete (Pending Audit)", deleted: "Deleted" }, list: { pageInfo: "Page {0} / {1}", header: "There are currently {0} Echo Caves:", totalItems: "User {0} has submitted a total of {1} items:", idsLine: "{0}" }, audit: { noPending: "No pending Echo Caves", pendingNotFound: "Pending Echo Cave not found", pendingResult: "{0}, {1} pending Echo Caves remaining: [{2}]", auditPassed: "Approved", auditRejected: "Rejected", batchAuditResult: "{0} {1}/{2} Echo Caves", title: "Pending Echo Caves:", from: "Contributor:", sendFailed: "Failed to send audit message, unable to contact manager {0}" }, error: { commandProcess: "Command processing failed: {0}", getCave: "Failed to get Echo Cave", noCave: "No Echo Caves", saveFailed: "Failed to save data", mediaLoadFailed: "[Failed to load {0}]", videoSendFailed: "Video send failed", uploadImageFailed: "Image upload failed", uploadVideoFailed: "Video upload failed", fileRead: "Failed to read JSON data: {0}", fileWrite: "Failed to write JSON data: {0}", notFound: "Not found", userInfo: "Failed to get user information: {0}", auditProcess: "Audit processing failed: {0}", invalidId: "Please enter a valid Echo Cave ID" }, message: { blacklisted: "You have been blacklisted", managerOnly: "This operation is for managers only", cooldown: "Group chat cooldown... Please try again in {0} seconds", caveTitle: "Echo Cave —— ({0})", videoSending: "[Video sending]", mediaInvalid: "[Invalid {0}]", contributorSuffix: "—— {0}", mediaSizeExceeded: "{0} file size exceeds limit" } } } };
44
44
  }
45
45
  });
46
46
 
@@ -49,8 +49,6 @@ var src_exports = {};
49
49
  __export(src_exports, {
50
50
  Config: () => Config,
51
51
  apply: () => apply,
52
- handleCaveAction: () => handleCaveAction,
53
- initCavePaths: () => initCavePaths,
54
52
  inject: () => inject,
55
53
  name: () => name
56
54
  });
@@ -78,8 +76,260 @@ var Config = import_koishi.Schema.object({
78
76
  async function apply(ctx, config) {
79
77
  ctx.i18n.define("zh-CN", require_zh_CN());
80
78
  ctx.i18n.define("en-US", require_en_US());
81
- const { caveFilePath, resourceDir, pendingFilePath } = await initCavePaths(ctx);
79
+ const dataDir = path.join(ctx.baseDir, "data");
80
+ const caveDir = path.join(dataDir, "cave");
81
+ const caveFilePath = path.join(caveDir, "cave.json");
82
+ const resourceDir = path.join(caveDir, "resources");
83
+ const pendingFilePath = path.join(caveDir, "pending.json");
84
+ await FileHandler.ensureDirectory(dataDir);
85
+ await FileHandler.ensureDirectory(caveDir);
86
+ await FileHandler.ensureDirectory(resourceDir);
87
+ await FileHandler.ensureJsonFile(caveFilePath);
88
+ await FileHandler.ensureJsonFile(pendingFilePath);
82
89
  const lastUsed = /* @__PURE__ */ new Map();
90
+ async function processList(caveFilePath2, session, content, options, config2) {
91
+ const caveData = await CacheManager.getCaveData(caveFilePath2, session);
92
+ const caveDir2 = path.dirname(caveFilePath2);
93
+ const stats = {};
94
+ for (const cave of caveData) {
95
+ if (cave.contributor_number === "10000") continue;
96
+ if (!stats[cave.contributor_number]) stats[cave.contributor_number] = [];
97
+ stats[cave.contributor_number].push(cave.cave_id);
98
+ }
99
+ const statFilePath = path.join(caveDir2, "stat.json");
100
+ fs.writeFileSync(statFilePath, JSON.stringify(stats, null, 2), "utf8");
101
+ const lines = Object.entries(stats).map(([cid, ids]) => {
102
+ return session.text("commands.cave.list.totalItems", [cid, ids.length]) + "\n" + session.text("commands.cave.list.idsLine", [ids.join(",")]);
103
+ });
104
+ const totalSubmissions = Object.values(stats).reduce((sum, arr) => sum + arr.length, 0);
105
+ if (config2.enablePagination) {
106
+ const itemsPerPage = config2.itemsPerPage;
107
+ const totalPages = Math.max(1, Math.ceil(lines.length / itemsPerPage));
108
+ let query = (content[0] || String(options.l) || "").trim();
109
+ let pageNum = parseInt(query, 10);
110
+ if (isNaN(pageNum) || pageNum < 1) pageNum = 1;
111
+ if (pageNum > totalPages) pageNum = totalPages;
112
+ const start = (pageNum - 1) * itemsPerPage;
113
+ const paginatedLines = lines.slice(start, start + itemsPerPage);
114
+ return session.text("commands.cave.list.header", [totalSubmissions]) + "\n" + paginatedLines.join("\n") + "\n" + session.text("commands.cave.list.pageInfo", [pageNum, totalPages]);
115
+ } else {
116
+ return session.text("commands.cave.list.header", [totalSubmissions]) + "\n" + lines.join("\n");
117
+ }
118
+ }
119
+ __name(processList, "processList");
120
+ async function processAudit(ctx2, pendingFilePath2, caveFilePath2, resourceDir2, session, options, content) {
121
+ const pendingData = await CacheManager.getPendingData(pendingFilePath2, session);
122
+ const isApprove = Boolean(options.p);
123
+ if (options.p === true && content[0] === "all" || options.d === true && content[0] === "all") {
124
+ return await handleAudit(ctx2, pendingData, isApprove, caveFilePath2, resourceDir2, pendingFilePath2, session);
125
+ }
126
+ const id = parseInt(content[0] || (typeof options.p === "string" ? options.p : "") || (typeof options.d === "string" ? options.d : ""));
127
+ if (isNaN(id)) {
128
+ return sendMessage(session, "commands.cave.error.invalidId", [], true);
129
+ }
130
+ return sendMessage(session, await handleAudit(ctx2, pendingData, isApprove, caveFilePath2, resourceDir2, pendingFilePath2, session, id), [], true);
131
+ }
132
+ __name(processAudit, "processAudit");
133
+ async function processView(caveFilePath2, resourceDir2, session, options, content) {
134
+ const caveId = parseInt(content[0] || (typeof options.g === "string" ? options.g : ""));
135
+ if (isNaN(caveId)) return sendMessage(session, "commands.cave.error.invalidId", [], true);
136
+ const data = await CacheManager.getCaveData(caveFilePath2, session);
137
+ const cave = data.find((item) => item.cave_id === caveId);
138
+ if (!cave) return sendMessage(session, "commands.cave.error.notFound", [], true);
139
+ const caveContent = await buildMessage(cave, resourceDir2, session);
140
+ return caveContent;
141
+ }
142
+ __name(processView, "processView");
143
+ async function processRandom(caveFilePath2, resourceDir2, session, config2, lastUsed2) {
144
+ try {
145
+ const data = await CacheManager.getCaveData(caveFilePath2, session);
146
+ if (data.length === 0) {
147
+ return sendMessage(session, "commands.cave.error.noCave", [], true);
148
+ }
149
+ const guildId = session.guildId;
150
+ const now = Date.now();
151
+ const lastCall = lastUsed2.get(guildId) || 0;
152
+ const isManager = config2.manager.includes(session.userId);
153
+ if (!isManager && now - lastCall < config2.number * 1e3) {
154
+ const waitTime = Math.ceil((config2.number * 1e3 - (now - lastCall)) / 1e3);
155
+ return sendMessage(session, "commands.cave.message.cooldown", [waitTime], true);
156
+ }
157
+ if (!isManager) lastUsed2.set(guildId, now);
158
+ const cave = (() => {
159
+ const validCaves = data.filter((cave2) => cave2.elements && cave2.elements.length > 0);
160
+ if (!validCaves.length) return void 0;
161
+ const randomIndex = Math.floor(Math.random() * validCaves.length);
162
+ return validCaves[randomIndex];
163
+ })();
164
+ return cave ? buildMessage(cave, resourceDir2, session) : sendMessage(session, "commands.cave.error.getCave", [], true);
165
+ } catch (error) {
166
+ return sendMessage(session, "commands.cave.error.commandProcess", [error.message], true);
167
+ }
168
+ }
169
+ __name(processRandom, "processRandom");
170
+ async function processDelete(caveFilePath2, resourceDir2, pendingFilePath2, session, config2, options, content) {
171
+ const caveId = parseInt(content[0] || (typeof options.r === "string" ? options.r : ""));
172
+ if (isNaN(caveId)) return sendMessage(session, "commands.cave.error.invalidId", [], true);
173
+ const data = await CacheManager.getCaveData(caveFilePath2, session);
174
+ const pendingData = await CacheManager.getPendingData(pendingFilePath2, session);
175
+ const index = data.findIndex((item) => item.cave_id === caveId);
176
+ const pendingIndex = pendingData.findIndex((item) => item.cave_id === caveId);
177
+ if (index === -1 && pendingIndex === -1) return sendMessage(session, "commands.cave.error.notFound", [], true);
178
+ let targetCave;
179
+ let isPending = false;
180
+ if (index !== -1) {
181
+ targetCave = data[index];
182
+ } else {
183
+ targetCave = pendingData[pendingIndex];
184
+ isPending = true;
185
+ }
186
+ if (targetCave.contributor_number !== session.userId && !config2.manager.includes(session.userId)) {
187
+ return sendMessage(session, "commands.cave.remove.noPermission", [], true);
188
+ }
189
+ const caveContent = await buildMessage(targetCave, resourceDir2, session);
190
+ if (targetCave.elements) {
191
+ for (const element of targetCave.elements) {
192
+ if ((element.type === "img" || element.type === "video") && element.file) {
193
+ const fullPath = path.join(resourceDir2, element.file);
194
+ if (fs.existsSync(fullPath)) fs.unlinkSync(fullPath);
195
+ }
196
+ }
197
+ }
198
+ if (isPending) {
199
+ pendingData.splice(pendingIndex, 1);
200
+ await FileHandler.writeJsonData(pendingFilePath2, pendingData, session);
201
+ const deleteStatus = isPending ? session.text("commands.cave.remove.deletePending") : "";
202
+ const deleteMessage = session.text("commands.cave.remove.deleted");
203
+ return `${deleteMessage}${deleteStatus}
204
+ ${caveContent}`;
205
+ } else {
206
+ data.splice(index, 1);
207
+ await FileHandler.writeJsonData(caveFilePath2, data, session);
208
+ const deleteStatus = isPending ? session.text("commands.cave.remove.deletePending") : "";
209
+ const deleteMessage = session.text("commands.cave.remove.deleted");
210
+ return `${deleteMessage}${deleteStatus}${caveContent}`;
211
+ }
212
+ }
213
+ __name(processDelete, "processDelete");
214
+ async function processAdd(ctx2, config2, caveFilePath2, resourceDir2, pendingFilePath2, session, content) {
215
+ try {
216
+ let inputParts = [];
217
+ if (content.length > 0) {
218
+ inputParts = content;
219
+ }
220
+ if (!inputParts.length) {
221
+ await sendMessage(session, "commands.cave.add.noContent", [], true);
222
+ const reply = await session.prompt({ timeout: 6e4 });
223
+ if (!reply || reply.trim() === "") {
224
+ return sendMessage(session, "commands.cave.add.operationTimeout", [], true);
225
+ }
226
+ inputParts = [reply];
227
+ }
228
+ const combinedInput = inputParts.join("\n");
229
+ if (combinedInput.includes("/app/.config/QQ/")) {
230
+ return sendMessage(session, "commands.cave.add.localFileNotAllowed", [], true);
231
+ }
232
+ let { imageUrls, imageElements, videoUrls, videoElements, textParts } = await extractMediaContent(combinedInput);
233
+ if (videoUrls.length > 0 && !config2.allowVideo) {
234
+ return sendMessage(session, "commands.cave.add.videoDisabled", [], true);
235
+ }
236
+ const pendingData = await CacheManager.getPendingData(pendingFilePath2, session);
237
+ const data = await CacheManager.getCaveData(caveFilePath2, session);
238
+ const usedIds = /* @__PURE__ */ new Set([...data.map((item) => item.cave_id), ...pendingData.map((item) => item.cave_id)]);
239
+ let caveId = 1;
240
+ while (usedIds.has(caveId)) {
241
+ caveId++;
242
+ }
243
+ let savedImages = [];
244
+ if (imageUrls.length > 0) {
245
+ try {
246
+ const imageFileNames = imageElements.map((el) => el.fileName);
247
+ const imageFileSizes = imageElements.map((el) => el.fileSize);
248
+ savedImages = await saveMedia(
249
+ imageUrls,
250
+ imageFileNames,
251
+ imageFileSizes,
252
+ resourceDir2,
253
+ caveId,
254
+ config2,
255
+ ctx2,
256
+ "img",
257
+ session
258
+ );
259
+ } catch (error) {
260
+ return sendMessage(session, "commands.cave.error.uploadImageFailed", [], true);
261
+ }
262
+ }
263
+ let savedVideos = [];
264
+ if (videoUrls.length > 0) {
265
+ try {
266
+ const videoFileNames = videoElements.map((el) => el.fileName);
267
+ const videoFileSizes = videoElements.map((el) => el.fileSize);
268
+ savedVideos = await saveMedia(
269
+ videoUrls,
270
+ videoFileNames,
271
+ videoFileSizes,
272
+ resourceDir2,
273
+ caveId,
274
+ config2,
275
+ ctx2,
276
+ "video",
277
+ session
278
+ );
279
+ } catch (error) {
280
+ return sendMessage(session, "commands.cave.error.uploadVideoFailed", [], true);
281
+ }
282
+ }
283
+ const elements = [];
284
+ elements.push(...textParts);
285
+ savedImages.forEach((file, idx) => {
286
+ if (imageElements[idx]) {
287
+ elements.push({ ...imageElements[idx], type: "img", file });
288
+ }
289
+ });
290
+ savedVideos.forEach((file, idx) => {
291
+ if (videoElements[idx]) {
292
+ elements.push({ ...videoElements[idx], type: "video", file });
293
+ }
294
+ });
295
+ elements.sort((a, b) => a.index - b.index);
296
+ let contributorName = session.username;
297
+ if (ctx2.database) {
298
+ try {
299
+ const userInfo = await ctx2.database.getUser(session.platform, session.userId);
300
+ contributorName = userInfo?.nickname || session.username;
301
+ } catch (error) {
302
+ return sendMessage(
303
+ session,
304
+ "commands.cave.error.userInfo",
305
+ [error.message],
306
+ true
307
+ );
308
+ }
309
+ }
310
+ const newCave = {
311
+ cave_id: caveId,
312
+ elements: cleanElementsForSave(elements, true),
313
+ contributor_number: session.userId,
314
+ contributor_name: contributorName
315
+ };
316
+ const bypassAudit = config2.whitelist.includes(session.userId) || session.guildId && config2.whitelist.includes(session.guildId) || session.channelId && config2.whitelist.includes(session.channelId);
317
+ if (config2.enableAudit && !bypassAudit) {
318
+ pendingData.push({ ...newCave, elements: cleanElementsForSave(elements, true) });
319
+ await FileHandler.writeJsonData(pendingFilePath2, pendingData, session);
320
+ await sendAuditMessage(ctx2, config2, newCave, await buildMessage(newCave, resourceDir2, session), session);
321
+ return sendMessage(session, "commands.cave.add.submitPending", [caveId], false);
322
+ } else {
323
+ const caveWithoutIndex = { ...newCave, elements: cleanElementsForSave(elements, false) };
324
+ data.push(caveWithoutIndex);
325
+ await FileHandler.writeJsonData(caveFilePath2, data, session);
326
+ return sendMessage(session, "commands.cave.add.addSuccess", [caveId], false);
327
+ }
328
+ } catch (error) {
329
+ return sendMessage(session, "commands.cave.error.commandProcess", [error.message], true);
330
+ }
331
+ }
332
+ __name(processAdd, "processAdd");
83
333
  ctx.command("cave [message]").option("a", "添加回声洞").option("g", "查看回声洞", { type: "string" }).option("r", "删除回声洞", { type: "string" }).option("p", "通过审核", { type: "string" }).option("d", "拒绝审核", { type: "string" }).option("l", "查询投稿统计", { type: "string" }).before(async ({ session, options }) => {
84
334
  if (config.blacklist.includes(session.userId)) {
85
335
  return sendTempMessage(session, "commands.cave.message.blacklisted");
@@ -89,7 +339,32 @@ async function apply(ctx, config) {
89
339
  return sendTempMessage(session, "commands.cave.message.managerOnly");
90
340
  }
91
341
  }).action(async ({ session, options }, ...content) => {
92
- return await handleCaveAction(ctx, config, session, options, content, lastUsed);
342
+ try {
343
+ const dataDir2 = path.join(ctx.baseDir, "data");
344
+ const caveDir2 = path.join(dataDir2, "cave");
345
+ const caveFilePath2 = path.join(caveDir2, "cave.json");
346
+ const resourceDir2 = path.join(caveDir2, "resources");
347
+ const pendingFilePath2 = path.join(caveDir2, "pending.json");
348
+ if (options.l !== void 0) {
349
+ return await processList(caveFilePath2, session, content, options, config);
350
+ }
351
+ if (options.p || options.d) {
352
+ return await processAudit(ctx, pendingFilePath2, caveFilePath2, resourceDir2, session, options, content);
353
+ }
354
+ if (options.g) {
355
+ return await processView(caveFilePath2, resourceDir2, session, options, content);
356
+ }
357
+ if (options.r) {
358
+ return await processDelete(caveFilePath2, resourceDir2, pendingFilePath2, session, config, options, content);
359
+ }
360
+ if (options.a) {
361
+ return await processAdd(ctx, config, caveFilePath2, resourceDir2, pendingFilePath2, session, content);
362
+ }
363
+ return await processRandom(caveFilePath2, resourceDir2, session, config, lastUsed);
364
+ } catch (error) {
365
+ logger.error(error);
366
+ return sendMessage(session, "commands.cave.error.commandProcess", [error.message], true);
367
+ }
93
368
  });
94
369
  }
95
370
  __name(apply, "apply");
@@ -98,9 +373,10 @@ var FileHandler = class {
98
373
  static {
99
374
  __name(this, "FileHandler");
100
375
  }
101
- static readJsonData(filePath, session, validator) {
376
+ static writeQueue = /* @__PURE__ */ new Map();
377
+ static async readJsonData(filePath, session, validator) {
102
378
  try {
103
- const data = fs.readFileSync(filePath, "utf8");
379
+ const data = await fs.promises.readFile(filePath, "utf8");
104
380
  const parsed = JSON.parse(data || "[]");
105
381
  return Array.isArray(parsed) ? validator ? parsed.filter(validator) : parsed : [];
106
382
  } catch (error) {
@@ -108,13 +384,27 @@ var FileHandler = class {
108
384
  return [];
109
385
  }
110
386
  }
111
- static writeJsonData(filePath, data, session) {
112
- try {
113
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf8");
114
- } catch (error) {
115
- logger.error(session.text("commands.cave.error.fileWrite", [error.message]));
116
- throw new Error(session.text("commands.cave.error.saveFailed"));
387
+ static async writeJsonData(filePath, data, session) {
388
+ const queueKey = filePath;
389
+ const writeOperation = /* @__PURE__ */ __name(async () => {
390
+ try {
391
+ const jsonString = JSON.stringify(data, null, 2);
392
+ await fs.promises.writeFile(filePath, jsonString, "utf8");
393
+ } catch (error) {
394
+ logger.error(session.text("commands.cave.error.fileWrite", [error.message]));
395
+ throw new Error(session.text("commands.cave.error.saveFailed"));
396
+ }
397
+ }, "writeOperation");
398
+ if (!this.writeQueue.has(queueKey)) {
399
+ this.writeQueue.set(queueKey, Promise.resolve());
117
400
  }
401
+ const currentPromise = this.writeQueue.get(queueKey).then(writeOperation).finally(() => {
402
+ if (this.writeQueue.get(queueKey) === currentPromise) {
403
+ this.writeQueue.delete(queueKey);
404
+ }
405
+ });
406
+ this.writeQueue.set(queueKey, currentPromise);
407
+ return currentPromise;
118
408
  }
119
409
  static async ensureDirectory(dir) {
120
410
  !fs.existsSync(dir) && await fs.promises.mkdir(dir, { recursive: true });
@@ -124,12 +414,10 @@ var FileHandler = class {
124
414
  }
125
415
  };
126
416
  async function saveMedia(urls, fileNames, fileSizes, resourceDir, caveId, config, ctx, mediaType, session) {
127
- const savedFiles = [];
128
417
  const defaults = mediaType === "img" ? { ext: "png", accept: "image/*", maxSize: config.imageMaxSize } : { ext: "mp4", accept: "video/*", maxSize: config.videoMaxSize };
129
418
  const extPattern = /\.[a-zA-Z0-9]+$/;
130
- for (let i = 0; i < urls.length; i++) {
419
+ const downloadPromises = urls.map(async (url, i) => {
131
420
  try {
132
- const url = urls[i];
133
421
  const processedUrl = (() => {
134
422
  try {
135
423
  const decodedUrl = decodeURIComponent(url);
@@ -145,7 +433,7 @@ async function saveMedia(urls, fileNames, fileSizes, resourceDir, caveId, config
145
433
  const sizeInBytes = parseInt(fileSize);
146
434
  if (sizeInBytes > defaults.maxSize * 1024 * 1024) {
147
435
  logger.warn(session.text("commands.cave.message.mediaSizeExceeded", [mediaType]));
148
- continue;
436
+ return null;
149
437
  }
150
438
  }
151
439
  if (fileName && extPattern.test(fileName)) {
@@ -165,14 +453,15 @@ async function saveMedia(urls, fileNames, fileSizes, resourceDir, caveId, config
165
453
  });
166
454
  const fileBuffer = Buffer.from(response.data);
167
455
  await fs.promises.writeFile(targetPath, fileBuffer);
168
- savedFiles.push(finalFileName);
456
+ return finalFileName;
169
457
  } catch (error) {
170
458
  const errorKey = mediaType === "img" ? "commands.cave.error.uploadImageFailed" : "commands.cave.error.uploadVideoFailed";
171
459
  await sendTempMessage(session, errorKey);
172
- return [];
460
+ return null;
173
461
  }
174
- }
175
- return savedFiles;
462
+ });
463
+ const results = await Promise.all(downloadPromises);
464
+ return results.filter((name2) => name2 !== null);
176
465
  }
177
466
  __name(saveMedia, "saveMedia");
178
467
  async function sendAuditMessage(ctx, config, cave, content, session) {
@@ -216,12 +505,12 @@ async function handleAudit(ctx, pendingData, isApprove, caveFilePath, resourceDi
216
505
  const pendingIndex = pendingData.findIndex((item) => item.cave_id === targetId);
217
506
  if (pendingIndex === -1) return sendMessage(session, "commands.cave.audit.pendingNotFound", [], true);
218
507
  const cave = pendingData[pendingIndex];
219
- const data2 = isApprove ? FileHandler.readJsonData(caveFilePath, session) : null;
508
+ const data2 = isApprove ? await FileHandler.readJsonData(caveFilePath, session) : null;
220
509
  const auditResult = await handleSingleCaveAudit(ctx, cave, isApprove, resourceDir, data2, session);
221
510
  if (typeof auditResult === "string") return auditResult;
222
- if (isApprove && data2) FileHandler.writeJsonData(caveFilePath, data2, session);
511
+ if (isApprove && data2) await FileHandler.writeJsonData(caveFilePath, data2, session);
223
512
  pendingData.splice(pendingIndex, 1);
224
- FileHandler.writeJsonData(pendingFilePath, pendingData, session);
513
+ await FileHandler.writeJsonData(pendingFilePath, pendingData, session);
225
514
  const remainingCount = pendingData.length;
226
515
  if (remainingCount > 0) {
227
516
  const remainingIds = pendingData.map((c) => c.cave_id).join(", ");
@@ -240,13 +529,13 @@ async function handleAudit(ctx, pendingData, isApprove, caveFilePath, resourceDi
240
529
  // 审核结果改为永久消息
241
530
  );
242
531
  }
243
- const data = isApprove ? FileHandler.readJsonData(caveFilePath, session) : null;
532
+ const data = isApprove ? await FileHandler.readJsonData(caveFilePath, session) : null;
244
533
  let processedCount = 0;
245
534
  for (const cave of pendingData) {
246
535
  await handleSingleCaveAudit(ctx, cave, isApprove, resourceDir, data, session) && processedCount++;
247
536
  }
248
- if (isApprove && data) FileHandler.writeJsonData(caveFilePath, data, session);
249
- FileHandler.writeJsonData(pendingFilePath, [], session);
537
+ if (isApprove && data) await FileHandler.writeJsonData(caveFilePath, data, session);
538
+ await FileHandler.writeJsonData(pendingFilePath, [], session);
250
539
  return sendMessage(session, "commands.cave.audit.batchAuditResult", [
251
540
  isApprove ? "通过" : "拒绝",
252
541
  processedCount,
@@ -276,17 +565,30 @@ async function sendTempMessage(session, key, params = [], timeout = 1e4) {
276
565
  return "";
277
566
  }
278
567
  __name(sendTempMessage, "sendTempMessage");
568
+ var messageQueue = /* @__PURE__ */ new Map();
279
569
  async function sendMessage(session, key, params = [], isTemp = true, timeout = 1e4) {
280
- const msg = await session.send(session.text(key, params));
281
- if (isTemp) {
282
- setTimeout(async () => {
283
- try {
284
- await session.bot.deleteMessage(session.channelId, msg);
285
- } catch (error) {
286
- logger.error("Failed to delete message:", error);
287
- }
288
- }, timeout);
570
+ const channelId = session.channelId;
571
+ const sendOperation = /* @__PURE__ */ __name(async () => {
572
+ const msg = await session.send(session.text(key, params));
573
+ if (isTemp) {
574
+ setTimeout(async () => {
575
+ try {
576
+ await session.bot.deleteMessage(channelId, msg);
577
+ } catch (error) {
578
+ logger.error("Failed to delete message:", error);
579
+ }
580
+ }, timeout);
581
+ }
582
+ }, "sendOperation");
583
+ if (!messageQueue.has(channelId)) {
584
+ messageQueue.set(channelId, Promise.resolve());
289
585
  }
586
+ const currentPromise = messageQueue.get(channelId).then(sendOperation).finally(() => {
587
+ if (messageQueue.get(channelId) === currentPromise) {
588
+ messageQueue.delete(channelId);
589
+ }
590
+ });
591
+ messageQueue.set(channelId, currentPromise);
290
592
  return "";
291
593
  }
292
594
  __name(sendMessage, "sendMessage");
@@ -365,296 +667,49 @@ async function buildMessage(cave, resourceDir, session) {
365
667
  return content;
366
668
  }
367
669
  __name(buildMessage, "buildMessage");
368
- async function initCavePaths(ctx) {
369
- const dataDir = path.join(ctx.baseDir, "data");
370
- const caveDir = path.join(dataDir, "cave");
371
- const caveFilePath = path.join(caveDir, "cave.json");
372
- const resourceDir = path.join(caveDir, "resources");
373
- const pendingFilePath = path.join(caveDir, "pending.json");
374
- await FileHandler.ensureDirectory(dataDir);
375
- await FileHandler.ensureDirectory(caveDir);
376
- await FileHandler.ensureDirectory(resourceDir);
377
- await FileHandler.ensureJsonFile(caveFilePath);
378
- await FileHandler.ensureJsonFile(pendingFilePath);
379
- return { dataDir, caveDir, caveFilePath, resourceDir, pendingFilePath };
380
- }
381
- __name(initCavePaths, "initCavePaths");
382
- async function handleCaveAction(ctx, config, session, options, content, lastUsed) {
383
- try {
384
- const { caveFilePath, resourceDir, pendingFilePath } = await initCavePaths(ctx);
385
- async function processList() {
386
- const caveData = FileHandler.readJsonData(caveFilePath, session);
387
- const caveDir = path.dirname(caveFilePath);
388
- const stats = {};
389
- for (const cave of caveData) {
390
- if (cave.contributor_number === "10000") continue;
391
- if (!stats[cave.contributor_number]) stats[cave.contributor_number] = [];
392
- stats[cave.contributor_number].push(cave.cave_id);
393
- }
394
- const statFilePath = path.join(caveDir, "stat.json");
395
- fs.writeFileSync(statFilePath, JSON.stringify(stats, null, 2), "utf8");
396
- const lines = Object.entries(stats).map(([cid, ids]) => {
397
- return session.text("commands.cave.list.totalItems", [cid, ids.length]) + "\n" + session.text("commands.cave.list.idsLine", [ids.join(",")]);
398
- });
399
- const totalSubmissions = Object.values(stats).reduce((sum, arr) => sum + arr.length, 0);
400
- if (config.enablePagination) {
401
- const itemsPerPage = config.itemsPerPage;
402
- const totalPages = Math.max(1, Math.ceil(lines.length / itemsPerPage));
403
- let query = (content[0] || String(options.l) || "").trim();
404
- let pageNum = parseInt(query, 10);
405
- if (isNaN(pageNum) || pageNum < 1) pageNum = 1;
406
- if (pageNum > totalPages) pageNum = totalPages;
407
- const start = (pageNum - 1) * itemsPerPage;
408
- const paginatedLines = lines.slice(start, start + itemsPerPage);
409
- return session.text("commands.cave.list.header", [totalSubmissions]) + "\n" + paginatedLines.join("\n") + "\n" + session.text("commands.cave.list.pageInfo", [pageNum, totalPages]);
410
- } else {
411
- return session.text("commands.cave.list.header", [totalSubmissions]) + "\n" + lines.join("\n");
412
- }
413
- }
414
- __name(processList, "processList");
415
- async function processAudit() {
416
- const pendingData = FileHandler.readJsonData(pendingFilePath, session);
417
- const isApprove = Boolean(options.p);
418
- if (options.p === true && content[0] === "all" || options.d === true && content[0] === "all") {
419
- return await handleAudit(ctx, pendingData, isApprove, caveFilePath, resourceDir, pendingFilePath, session);
420
- }
421
- const id = parseInt(content[0] || (typeof options.p === "string" ? options.p : "") || (typeof options.d === "string" ? options.d : ""));
422
- if (isNaN(id)) {
423
- return sendMessage(session, "commands.cave.error.invalidId", [], true);
424
- }
425
- return sendMessage(session, await handleAudit(ctx, pendingData, isApprove, caveFilePath, resourceDir, pendingFilePath, session, id), [], true);
426
- }
427
- __name(processAudit, "processAudit");
428
- async function processView() {
429
- const caveId = parseInt(content[0] || (typeof options.g === "string" ? options.g : ""));
430
- if (isNaN(caveId)) return sendMessage(session, "commands.cave.error.invalidId", [], true);
431
- const data = FileHandler.readJsonData(
432
- caveFilePath,
433
- session,
434
- (item) => item && typeof item.cave_id === "number" && Array.isArray(item.elements) && item.elements.every(
435
- (el) => el.type === "text" && typeof el.content === "string" || el.type === "img" && typeof el.file === "string" || el.type === "video" && typeof el.file === "string"
436
- ) && typeof item.contributor_number === "string" && typeof item.contributor_name === "string"
437
- );
438
- const cave = data.find((item) => item.cave_id === caveId);
439
- if (!cave) return sendMessage(session, "commands.cave.error.notFound", [], true);
440
- const caveContent = await buildMessage(cave, resourceDir, session);
441
- return caveContent;
442
- }
443
- __name(processView, "processView");
444
- async function processRandom() {
445
- try {
446
- const data = FileHandler.readJsonData(
447
- caveFilePath,
448
- session,
449
- (item) => item && typeof item.cave_id === "number" && Array.isArray(item.elements) && item.elements.every(
450
- (el) => el.type === "text" && typeof el.content === "string" || el.type === "img" && typeof el.file === "string"
451
- ) && typeof item.contributor_number === "string" && typeof item.contributor_name === "string"
452
- );
453
- if (data.length === 0) {
454
- return sendMessage(session, "commands.cave.error.noCave", [], true);
455
- }
456
- const guildId = session.guildId;
457
- const now = Date.now();
458
- const lastCall = lastUsed.get(guildId) || 0;
459
- const isManager = config.manager.includes(session.userId);
460
- if (!isManager && now - lastCall < config.number * 1e3) {
461
- const waitTime = Math.ceil((config.number * 1e3 - (now - lastCall)) / 1e3);
462
- return sendMessage(session, "commands.cave.message.cooldown", [waitTime], true);
463
- }
464
- if (!isManager) lastUsed.set(guildId, now);
465
- const cave = (() => {
466
- const validCaves = data.filter((cave2) => cave2.elements && cave2.elements.length > 0);
467
- if (!validCaves.length) return void 0;
468
- const randomIndex = Math.floor(Math.random() * validCaves.length);
469
- return validCaves[randomIndex];
470
- })();
471
- return cave ? buildMessage(cave, resourceDir, session) : sendMessage(session, "commands.cave.error.getCave", [], true);
472
- } catch (error) {
473
- return sendMessage(session, "commands.cave.error.commandProcess", [error.message], true);
474
- }
475
- }
476
- __name(processRandom, "processRandom");
477
- async function processDelete() {
478
- const caveId = parseInt(content[0] || (typeof options.r === "string" ? options.r : ""));
479
- if (isNaN(caveId)) return sendMessage(session, "commands.cave.error.invalidId", [], true);
480
- const data = FileHandler.readJsonData(
481
- caveFilePath,
482
- session,
483
- (item) => item && typeof item.cave_id === "number"
484
- );
485
- const pendingData = FileHandler.readJsonData(pendingFilePath, session);
486
- const index = data.findIndex((item) => item.cave_id === caveId);
487
- const pendingIndex = pendingData.findIndex((item) => item.cave_id === caveId);
488
- if (index === -1 && pendingIndex === -1) return sendMessage(session, "commands.cave.error.notFound", [], true);
489
- let targetCave;
490
- let isPending = false;
491
- if (index !== -1) {
492
- targetCave = data[index];
493
- } else {
494
- targetCave = pendingData[pendingIndex];
495
- isPending = true;
496
- }
497
- if (targetCave.contributor_number !== session.userId && !config.manager.includes(session.userId)) {
498
- return sendMessage(session, "commands.cave.remove.noPermission", [], true);
499
- }
500
- const caveContent = await buildMessage(targetCave, resourceDir, session);
501
- if (targetCave.elements) {
502
- for (const element of targetCave.elements) {
503
- if ((element.type === "img" || element.type === "video") && element.file) {
504
- const fullPath = path.join(resourceDir, element.file);
505
- if (fs.existsSync(fullPath)) fs.unlinkSync(fullPath);
506
- }
507
- }
508
- }
509
- if (isPending) {
510
- pendingData.splice(pendingIndex, 1);
511
- FileHandler.writeJsonData(pendingFilePath, pendingData, session);
512
- const deleteStatus = isPending ? session.text("commands.cave.remove.deletePending") : "";
513
- const deleteMessage = session.text("commands.cave.remove.deleted");
514
- return `${deleteMessage}${deleteStatus}
515
- ${caveContent}`;
516
- } else {
517
- data.splice(index, 1);
518
- FileHandler.writeJsonData(caveFilePath, data, session);
519
- const deleteStatus = isPending ? session.text("commands.cave.remove.deletePending") : "";
520
- const deleteMessage = session.text("commands.cave.remove.deleted");
521
- return `${deleteMessage}${deleteStatus}${caveContent}`;
522
- }
670
+ var CacheManager = class {
671
+ static {
672
+ __name(this, "CacheManager");
673
+ }
674
+ static caveDataCache = null;
675
+ static pendingDataCache = null;
676
+ static cacheTimeout = 5 * 60 * 1e3;
677
+ // 5分钟缓存
678
+ static lastCaveUpdate = 0;
679
+ static lastPendingUpdate = 0;
680
+ static clearCache() {
681
+ this.caveDataCache = null;
682
+ this.pendingDataCache = null;
683
+ }
684
+ static async getCaveData(filePath, session) {
685
+ const now = Date.now();
686
+ if (!this.caveDataCache || now - this.lastCaveUpdate > this.cacheTimeout) {
687
+ this.caveDataCache = await FileHandler.readJsonData(filePath, session);
688
+ this.lastCaveUpdate = now;
523
689
  }
524
- __name(processDelete, "processDelete");
525
- async function processAdd() {
526
- try {
527
- let inputParts = [];
528
- if (content.length > 0) {
529
- inputParts = content;
530
- }
531
- if (!inputParts.length) {
532
- await sendMessage(session, "commands.cave.add.noContent", [], true);
533
- const reply = await session.prompt({ timeout: 6e4 });
534
- if (!reply || reply.trim() === "") {
535
- return sendMessage(session, "commands.cave.add.operationTimeout", [], true);
536
- }
537
- inputParts = [reply];
538
- }
539
- let { imageUrls, imageElements, videoUrls, videoElements, textParts } = await extractMediaContent(inputParts.join("\n"));
540
- if (videoUrls.length > 0 && !config.allowVideo) {
541
- return sendMessage(session, "commands.cave.add.videoDisabled", [], true);
542
- }
543
- const pendingData = FileHandler.readJsonData(pendingFilePath, session);
544
- const data = FileHandler.readJsonData(caveFilePath, session, (item) => item && typeof item.cave_id === "number");
545
- const usedIds = /* @__PURE__ */ new Set([...data.map((item) => item.cave_id), ...pendingData.map((item) => item.cave_id)]);
546
- let caveId = 1;
547
- while (usedIds.has(caveId)) {
548
- caveId++;
549
- }
550
- let savedImages = [];
551
- if (imageUrls.length > 0) {
552
- try {
553
- const imageFileNames = imageElements.map((el) => el.fileName);
554
- const imageFileSizes = imageElements.map((el) => el.fileSize);
555
- savedImages = await saveMedia(
556
- imageUrls,
557
- imageFileNames,
558
- imageFileSizes,
559
- resourceDir,
560
- caveId,
561
- config,
562
- ctx,
563
- "img",
564
- session
565
- );
566
- } catch (error) {
567
- return sendMessage(session, "commands.cave.error.uploadImageFailed", [], true);
568
- }
569
- }
570
- let savedVideos = [];
571
- if (videoUrls.length > 0) {
572
- try {
573
- const videoFileNames = videoElements.map((el) => el.fileName);
574
- const videoFileSizes = videoElements.map((el) => el.fileSize);
575
- savedVideos = await saveMedia(
576
- videoUrls,
577
- videoFileNames,
578
- videoFileSizes,
579
- resourceDir,
580
- caveId,
581
- config,
582
- ctx,
583
- "video",
584
- session
585
- );
586
- } catch (error) {
587
- return sendMessage(session, "commands.cave.error.uploadVideoFailed", [], true);
588
- }
589
- }
590
- const elements = [];
591
- elements.push(...textParts);
592
- savedImages.forEach((file, idx) => {
593
- if (imageElements[idx]) {
594
- elements.push({ ...imageElements[idx], type: "img", file });
595
- }
596
- });
597
- savedVideos.forEach((file, idx) => {
598
- if (videoElements[idx]) {
599
- elements.push({ ...videoElements[idx], type: "video", file });
600
- }
601
- });
602
- elements.sort((a, b) => a.index - b.index);
603
- let contributorName = session.username;
604
- if (ctx.database) {
605
- try {
606
- const userInfo = await ctx.database.getUser(session.platform, session.userId);
607
- contributorName = userInfo?.nickname || session.username;
608
- } catch (error) {
609
- return sendMessage(
610
- session,
611
- "commands.cave.error.userInfo",
612
- [error.message],
613
- true
614
- );
615
- }
616
- }
617
- const newCave = {
618
- cave_id: caveId,
619
- elements: cleanElementsForSave(elements, true),
620
- contributor_number: session.userId,
621
- contributor_name: contributorName
622
- };
623
- const bypassAudit = config.whitelist.includes(session.userId) || session.guildId && config.whitelist.includes(session.guildId) || session.channelId && config.whitelist.includes(session.channelId);
624
- if (config.enableAudit && !bypassAudit) {
625
- pendingData.push({ ...newCave, elements: cleanElementsForSave(elements, true) });
626
- FileHandler.writeJsonData(pendingFilePath, pendingData, session);
627
- await sendAuditMessage(ctx, config, newCave, await buildMessage(newCave, resourceDir, session), session);
628
- return sendMessage(session, "commands.cave.add.submitPending", [caveId], false);
629
- } else {
630
- const caveWithoutIndex = { ...newCave, elements: cleanElementsForSave(elements, false) };
631
- data.push(caveWithoutIndex);
632
- FileHandler.writeJsonData(caveFilePath, data, session);
633
- return sendMessage(session, "commands.cave.add.addSuccess", [caveId], false);
634
- }
635
- } catch (error) {
636
- return sendMessage(session, "commands.cave.error.commandProcess", [error.message], true);
637
- }
690
+ return this.caveDataCache;
691
+ }
692
+ static async getPendingData(filePath, session) {
693
+ const now = Date.now();
694
+ if (!this.pendingDataCache || now - this.lastPendingUpdate > this.cacheTimeout) {
695
+ this.pendingDataCache = await FileHandler.readJsonData(filePath, session);
696
+ this.lastPendingUpdate = now;
638
697
  }
639
- __name(processAdd, "processAdd");
640
- if (options.l !== void 0) return await processList();
641
- if (options.p || options.d) return await processAudit();
642
- if (options.g) return await processView();
643
- if (options.r) return await processDelete();
644
- if (options.a) return await processAdd();
645
- return await processRandom();
646
- } catch (error) {
647
- logger.error(error);
648
- return sendMessage(session, "commands.cave.error.commandProcess", [error.message], true);
698
+ return this.pendingDataCache;
649
699
  }
650
- }
651
- __name(handleCaveAction, "handleCaveAction");
700
+ static updateCaveData(data) {
701
+ this.caveDataCache = data;
702
+ this.lastCaveUpdate = Date.now();
703
+ }
704
+ static updatePendingData(data) {
705
+ this.pendingDataCache = data;
706
+ this.lastPendingUpdate = Date.now();
707
+ }
708
+ };
652
709
  // Annotate the CommonJS export names for ESM import in node:
653
710
  0 && (module.exports = {
654
711
  Config,
655
712
  apply,
656
- handleCaveAction,
657
- initCavePaths,
658
713
  inject,
659
714
  name
660
715
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-best-cave",
3
3
  "description": "最好的 cave 插件,可开关的审核系统,可引用添加,支持图文混合内容,可查阅投稿列表,完美复刻你的 .cave 体验!",
4
- "version": "1.1.4",
4
+ "version": "1.1.5",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],