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 +0 -8
- package/lib/index.js +375 -320
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
|
376
|
+
static writeQueue = /* @__PURE__ */ new Map();
|
|
377
|
+
static async readJsonData(filePath, session, validator) {
|
|
102
378
|
try {
|
|
103
|
-
const data = fs.
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
async
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|