koishi-plugin-best-cave 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +353 -316
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
5
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
7
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name2 in all)
|
|
10
13
|
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
@@ -27,6 +30,20 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// src/locales/zh-CN.yml
|
|
34
|
+
var require_zh_CN = __commonJS({
|
|
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}文件大小超过限制" } } } };
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// src/locales/en-US.yml
|
|
41
|
+
var require_en_US = __commonJS({
|
|
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" } } } };
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
30
47
|
// src/index.ts
|
|
31
48
|
var src_exports = {};
|
|
32
49
|
__export(src_exports, {
|
|
@@ -44,22 +61,32 @@ var path = __toESM(require("path"));
|
|
|
44
61
|
var name = "cave";
|
|
45
62
|
var inject = ["database"];
|
|
46
63
|
var Config = import_koishi.Schema.object({
|
|
47
|
-
manager: import_koishi.Schema.array(import_koishi.Schema.string()).required()
|
|
48
|
-
blacklist: import_koishi.Schema.array(import_koishi.Schema.string()).default([])
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
manager: import_koishi.Schema.array(import_koishi.Schema.string()).required(),
|
|
65
|
+
blacklist: import_koishi.Schema.array(import_koishi.Schema.string()).default([]),
|
|
66
|
+
whitelist: import_koishi.Schema.array(import_koishi.Schema.string()).default([]),
|
|
67
|
+
number: import_koishi.Schema.number().default(60),
|
|
68
|
+
enableAudit: import_koishi.Schema.boolean().default(false),
|
|
69
|
+
allowVideo: import_koishi.Schema.boolean().default(true),
|
|
70
|
+
videoMaxSize: import_koishi.Schema.number().default(16),
|
|
71
|
+
imageMaxSize: import_koishi.Schema.number().default(4),
|
|
72
|
+
enablePagination: import_koishi.Schema.boolean().default(false),
|
|
73
|
+
itemsPerPage: import_koishi.Schema.number().default(10)
|
|
74
|
+
}).i18n({
|
|
75
|
+
"zh-CN": require_zh_CN()._config,
|
|
76
|
+
"en-US": require_en_US()._config
|
|
54
77
|
});
|
|
55
78
|
async function apply(ctx, config) {
|
|
79
|
+
ctx.i18n.define("zh-CN", require_zh_CN());
|
|
80
|
+
ctx.i18n.define("en-US", require_en_US());
|
|
56
81
|
const { caveFilePath, resourceDir, pendingFilePath } = await initCavePaths(ctx);
|
|
57
82
|
const lastUsed = /* @__PURE__ */ new Map();
|
|
58
|
-
ctx.command("cave [message
|
|
59
|
-
if (config.blacklist.includes(session.userId))
|
|
83
|
+
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
|
+
if (config.blacklist.includes(session.userId)) {
|
|
85
|
+
return sendTempMessage(session, "commands.cave.message.blacklisted");
|
|
86
|
+
}
|
|
60
87
|
if (session.content && session.content.includes("-help")) return;
|
|
61
88
|
if ((options.l || options.p || options.d) && !config.manager.includes(session.userId)) {
|
|
62
|
-
return "
|
|
89
|
+
return sendTempMessage(session, "commands.cave.message.managerOnly");
|
|
63
90
|
}
|
|
64
91
|
}).action(async ({ session, options }, ...content) => {
|
|
65
92
|
return await handleCaveAction(ctx, config, session, options, content, lastUsed);
|
|
@@ -71,43 +98,32 @@ var FileHandler = class {
|
|
|
71
98
|
static {
|
|
72
99
|
__name(this, "FileHandler");
|
|
73
100
|
}
|
|
74
|
-
static readJsonData(filePath, validator) {
|
|
101
|
+
static readJsonData(filePath, session, validator) {
|
|
75
102
|
try {
|
|
76
103
|
const data = fs.readFileSync(filePath, "utf8");
|
|
77
104
|
const parsed = JSON.parse(data || "[]");
|
|
78
|
-
|
|
79
|
-
return validator ? parsed.filter(validator) : parsed;
|
|
105
|
+
return Array.isArray(parsed) ? validator ? parsed.filter(validator) : parsed : [];
|
|
80
106
|
} catch (error) {
|
|
81
|
-
|
|
107
|
+
logger.error(session.text("commands.cave.error.fileRead", [error.message]));
|
|
108
|
+
return [];
|
|
82
109
|
}
|
|
83
110
|
}
|
|
84
|
-
static writeJsonData(filePath, data) {
|
|
111
|
+
static writeJsonData(filePath, data, session) {
|
|
85
112
|
try {
|
|
86
113
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf8");
|
|
87
114
|
} catch (error) {
|
|
88
|
-
|
|
115
|
+
logger.error(session.text("commands.cave.error.fileWrite", [error.message]));
|
|
116
|
+
throw new Error(session.text("commands.cave.error.saveFailed"));
|
|
89
117
|
}
|
|
90
118
|
}
|
|
91
119
|
static async ensureDirectory(dir) {
|
|
92
|
-
|
|
93
|
-
if (!fs.existsSync(dir)) {
|
|
94
|
-
await fs.promises.mkdir(dir, { recursive: true });
|
|
95
|
-
}
|
|
96
|
-
} catch (error) {
|
|
97
|
-
throw new Error(`操作失败: ${error.message}`);
|
|
98
|
-
}
|
|
120
|
+
!fs.existsSync(dir) && await fs.promises.mkdir(dir, { recursive: true });
|
|
99
121
|
}
|
|
100
122
|
static async ensureJsonFile(filePath, defaultContent = "[]") {
|
|
101
|
-
|
|
102
|
-
if (!fs.existsSync(filePath)) {
|
|
103
|
-
await fs.promises.writeFile(filePath, defaultContent, "utf8");
|
|
104
|
-
}
|
|
105
|
-
} catch (error) {
|
|
106
|
-
throw new Error(`操作失败: ${error.message}`);
|
|
107
|
-
}
|
|
123
|
+
!fs.existsSync(filePath) && await fs.promises.writeFile(filePath, defaultContent, "utf8");
|
|
108
124
|
}
|
|
109
125
|
};
|
|
110
|
-
async function saveMedia(urls,
|
|
126
|
+
async function saveMedia(urls, fileNames, fileSizes, resourceDir, caveId, config, ctx, mediaType, session) {
|
|
111
127
|
const savedFiles = [];
|
|
112
128
|
const defaults = mediaType === "img" ? { ext: "png", accept: "image/*", maxSize: config.imageMaxSize } : { ext: "mp4", accept: "video/*", maxSize: config.videoMaxSize };
|
|
113
129
|
const extPattern = /\.[a-zA-Z0-9]+$/;
|
|
@@ -123,32 +139,20 @@ async function saveMedia(urls, fileSuggestions, resourceDir, caveId, config, ctx
|
|
|
123
139
|
}
|
|
124
140
|
})();
|
|
125
141
|
let ext = defaults.ext;
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
142
|
+
const fileName = fileNames[i];
|
|
143
|
+
const fileSize = fileSizes[i];
|
|
144
|
+
if (fileSize) {
|
|
145
|
+
const sizeInBytes = parseInt(fileSize);
|
|
146
|
+
if (sizeInBytes > defaults.maxSize * 1024 * 1024) {
|
|
147
|
+
logger.warn(session.text("commands.cave.message.mediaSizeExceeded", [mediaType]));
|
|
148
|
+
continue;
|
|
133
149
|
}
|
|
134
|
-
if (sizeCandidate > defaults.maxSize * 1024 * 1024) {
|
|
135
|
-
throw new Error(`${mediaType === "img" ? "图片" : "视频"}超出大小限制 (${defaults.maxSize}MB),实际大小为 ${(sizeCandidate / (1024 * 1024)).toFixed(2)}MB`);
|
|
136
|
-
}
|
|
137
|
-
} else if (suggestion && extPattern.test(suggestion)) {
|
|
138
|
-
ext = suggestion.match(extPattern)[0].slice(1);
|
|
139
150
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const parts = suggestion.split(";");
|
|
143
|
-
const srcFilename = path.basename(parts[0]);
|
|
144
|
-
filename = `${caveId}_${srcFilename}`;
|
|
145
|
-
} else if (suggestion && extPattern.test(suggestion)) {
|
|
146
|
-
const srcFilename = path.basename(suggestion);
|
|
147
|
-
filename = `${caveId}_${srcFilename}`;
|
|
148
|
-
} else {
|
|
149
|
-
filename = `${caveId}_${i + 1}.${ext}`;
|
|
151
|
+
if (fileName && extPattern.test(fileName)) {
|
|
152
|
+
ext = fileName.match(extPattern)[0].slice(1);
|
|
150
153
|
}
|
|
151
|
-
const
|
|
154
|
+
const finalFileName = fileName ? `${caveId}_${path.basename(fileName)}` : `${caveId}_${i + 1}.${ext}`;
|
|
155
|
+
const targetPath = path.join(resourceDir, finalFileName);
|
|
152
156
|
const response = await ctx.http(processedUrl, {
|
|
153
157
|
method: "GET",
|
|
154
158
|
responseType: "arraybuffer",
|
|
@@ -161,28 +165,30 @@ async function saveMedia(urls, fileSuggestions, resourceDir, caveId, config, ctx
|
|
|
161
165
|
});
|
|
162
166
|
const fileBuffer = Buffer.from(response.data);
|
|
163
167
|
await fs.promises.writeFile(targetPath, fileBuffer);
|
|
164
|
-
savedFiles.push(
|
|
168
|
+
savedFiles.push(finalFileName);
|
|
165
169
|
} catch (error) {
|
|
166
|
-
|
|
170
|
+
const errorKey = mediaType === "img" ? "commands.cave.error.uploadImageFailed" : "commands.cave.error.uploadVideoFailed";
|
|
171
|
+
await sendTempMessage(session, errorKey);
|
|
172
|
+
return [];
|
|
167
173
|
}
|
|
168
174
|
}
|
|
169
175
|
return savedFiles;
|
|
170
176
|
}
|
|
171
177
|
__name(saveMedia, "saveMedia");
|
|
172
|
-
async function sendAuditMessage(ctx, config, cave, content) {
|
|
173
|
-
const auditMessage =
|
|
178
|
+
async function sendAuditMessage(ctx, config, cave, content, session) {
|
|
179
|
+
const auditMessage = `${session.text("commands.cave.audit.title")}
|
|
174
180
|
${content}
|
|
175
|
-
|
|
181
|
+
${session.text("commands.cave.audit.from")}${cave.contributor_number}`;
|
|
176
182
|
for (const managerId of config.manager) {
|
|
177
183
|
try {
|
|
178
184
|
await ctx.bots[0]?.sendPrivateMessage(managerId, auditMessage);
|
|
179
185
|
} catch (error) {
|
|
180
|
-
logger.error(
|
|
186
|
+
logger.error(session.text("commands.cave.audit.sendFailed", [managerId]));
|
|
181
187
|
}
|
|
182
188
|
}
|
|
183
189
|
}
|
|
184
190
|
__name(sendAuditMessage, "sendAuditMessage");
|
|
185
|
-
async function handleSingleCaveAudit(ctx, cave, isApprove, resourceDir, data) {
|
|
191
|
+
async function handleSingleCaveAudit(ctx, cave, isApprove, resourceDir, data, session) {
|
|
186
192
|
try {
|
|
187
193
|
if (isApprove && data) {
|
|
188
194
|
const caveWithoutIndex = {
|
|
@@ -200,42 +206,52 @@ async function handleSingleCaveAudit(ctx, cave, isApprove, resourceDir, data) {
|
|
|
200
206
|
}
|
|
201
207
|
return true;
|
|
202
208
|
} catch (error) {
|
|
203
|
-
|
|
209
|
+
return sendTempMessage(session, "commands.cave.error.auditProcess", [error.message]);
|
|
204
210
|
}
|
|
205
211
|
}
|
|
206
212
|
__name(handleSingleCaveAudit, "handleSingleCaveAudit");
|
|
207
|
-
async function handleAudit(ctx, pendingData, isApprove, caveFilePath, resourceDir, pendingFilePath, targetId) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
let processedCount = 0;
|
|
229
|
-
for (const cave of pendingData) {
|
|
230
|
-
const success = await handleSingleCaveAudit(ctx, cave, isApprove, resourceDir, data);
|
|
231
|
-
if (success) processedCount++;
|
|
213
|
+
async function handleAudit(ctx, pendingData, isApprove, caveFilePath, resourceDir, pendingFilePath, session, targetId) {
|
|
214
|
+
if (pendingData.length === 0) return sendMessage(session, "commands.cave.audit.noPending", [], true);
|
|
215
|
+
if (typeof targetId === "number") {
|
|
216
|
+
const pendingIndex = pendingData.findIndex((item) => item.cave_id === targetId);
|
|
217
|
+
if (pendingIndex === -1) return sendMessage(session, "commands.cave.audit.pendingNotFound", [], true);
|
|
218
|
+
const cave = pendingData[pendingIndex];
|
|
219
|
+
const data2 = isApprove ? FileHandler.readJsonData(caveFilePath, session) : null;
|
|
220
|
+
const auditResult = await handleSingleCaveAudit(ctx, cave, isApprove, resourceDir, data2, session);
|
|
221
|
+
if (typeof auditResult === "string") return auditResult;
|
|
222
|
+
if (isApprove && data2) FileHandler.writeJsonData(caveFilePath, data2, session);
|
|
223
|
+
pendingData.splice(pendingIndex, 1);
|
|
224
|
+
FileHandler.writeJsonData(pendingFilePath, pendingData, session);
|
|
225
|
+
const remainingCount = pendingData.length;
|
|
226
|
+
if (remainingCount > 0) {
|
|
227
|
+
const remainingIds = pendingData.map((c) => c.cave_id).join(", ");
|
|
228
|
+
const action = isApprove ? "auditPassed" : "auditRejected";
|
|
229
|
+
return sendMessage(session, "commands.cave.audit.pendingResult", [
|
|
230
|
+
session.text(`commands.cave.audit.${action}`),
|
|
231
|
+
remainingCount,
|
|
232
|
+
remainingIds
|
|
233
|
+
], false);
|
|
232
234
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
return sendMessage(
|
|
236
|
+
session,
|
|
237
|
+
isApprove ? "commands.cave.audit.auditPassed" : "commands.cave.audit.auditRejected",
|
|
238
|
+
[],
|
|
239
|
+
false
|
|
240
|
+
// 审核结果改为永久消息
|
|
241
|
+
);
|
|
238
242
|
}
|
|
243
|
+
const data = isApprove ? FileHandler.readJsonData(caveFilePath, session) : null;
|
|
244
|
+
let processedCount = 0;
|
|
245
|
+
for (const cave of pendingData) {
|
|
246
|
+
await handleSingleCaveAudit(ctx, cave, isApprove, resourceDir, data, session) && processedCount++;
|
|
247
|
+
}
|
|
248
|
+
if (isApprove && data) FileHandler.writeJsonData(caveFilePath, data, session);
|
|
249
|
+
FileHandler.writeJsonData(pendingFilePath, [], session);
|
|
250
|
+
return sendMessage(session, "commands.cave.audit.batchAuditResult", [
|
|
251
|
+
isApprove ? "通过" : "拒绝",
|
|
252
|
+
processedCount,
|
|
253
|
+
pendingData.length
|
|
254
|
+
], false);
|
|
239
255
|
}
|
|
240
256
|
__name(handleAudit, "handleAudit");
|
|
241
257
|
function cleanElementsForSave(elements, keepIndex = false) {
|
|
@@ -248,6 +264,32 @@ function cleanElementsForSave(elements, keepIndex = false) {
|
|
|
248
264
|
}));
|
|
249
265
|
}
|
|
250
266
|
__name(cleanElementsForSave, "cleanElementsForSave");
|
|
267
|
+
async function sendTempMessage(session, key, params = [], timeout = 1e4) {
|
|
268
|
+
const msg = await session.send(session.text(key, params));
|
|
269
|
+
setTimeout(async () => {
|
|
270
|
+
try {
|
|
271
|
+
await session.bot.deleteMessage(session.channelId, msg);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
logger.error("Failed to delete message:", error);
|
|
274
|
+
}
|
|
275
|
+
}, timeout);
|
|
276
|
+
return "";
|
|
277
|
+
}
|
|
278
|
+
__name(sendTempMessage, "sendTempMessage");
|
|
279
|
+
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);
|
|
289
|
+
}
|
|
290
|
+
return "";
|
|
291
|
+
}
|
|
292
|
+
__name(sendMessage, "sendMessage");
|
|
251
293
|
async function extractMediaContent(originalContent) {
|
|
252
294
|
const parsedTexts = originalContent.split(/<img[^>]+>|<video[^>]+>/g).map((t) => t.trim()).filter((t) => t);
|
|
253
295
|
const textParts = [];
|
|
@@ -261,67 +303,65 @@ async function extractMediaContent(originalContent) {
|
|
|
261
303
|
const imgMatches = originalContent.match(/<img[^>]+src="([^"]+)"[^>]*>/g) || [];
|
|
262
304
|
imgMatches.forEach((img, idx) => {
|
|
263
305
|
const srcMatch = img.match(/src="([^"]+)"/);
|
|
264
|
-
const
|
|
306
|
+
const fileName = img.match(/file="([^"]+)"/)?.[1];
|
|
307
|
+
const fileSize = img.match(/fileSize="([^"]+)"/)?.[1];
|
|
265
308
|
if (srcMatch?.[1]) {
|
|
266
309
|
imageUrls.push(srcMatch[1]);
|
|
267
|
-
|
|
268
|
-
imageElements.push({ type: "img", index: idx * 3 + 1, fileAttr: suggestion });
|
|
310
|
+
imageElements.push({ type: "img", index: idx * 3 + 1, fileName, fileSize });
|
|
269
311
|
}
|
|
270
312
|
});
|
|
271
313
|
const videoMatches = originalContent.match(/<video[^>]+src="([^"]+)"[^>]*>/g) || [];
|
|
272
314
|
videoMatches.forEach((video, idx) => {
|
|
273
315
|
const srcMatch = video.match(/src="([^"]+)"/);
|
|
274
|
-
const
|
|
316
|
+
const fileName = video.match(/file="([^"]+)"/)?.[1];
|
|
317
|
+
const fileSize = video.match(/fileSize="([^"]+)"/)?.[1];
|
|
275
318
|
if (srcMatch?.[1]) {
|
|
276
319
|
videoUrls.push(srcMatch[1]);
|
|
277
|
-
|
|
278
|
-
videoElements.push({ type: "video", index: idx * 3 + 2, fileAttr: suggestion });
|
|
320
|
+
videoElements.push({ type: "video", index: idx * 3 + 2, fileName, fileSize });
|
|
279
321
|
}
|
|
280
322
|
});
|
|
281
323
|
return { imageUrls, imageElements, videoUrls, videoElements, textParts };
|
|
282
324
|
}
|
|
283
325
|
__name(extractMediaContent, "extractMediaContent");
|
|
284
326
|
async function buildMessage(cave, resourceDir, session) {
|
|
285
|
-
let content =
|
|
286
|
-
`;
|
|
327
|
+
let content = session.text("commands.cave.message.caveTitle", [cave.cave_id]) + "\n";
|
|
287
328
|
const videoElements = [];
|
|
288
329
|
for (const element of cave.elements) {
|
|
289
330
|
if (element.type === "text") {
|
|
290
331
|
content += element.content + "\n";
|
|
291
332
|
} else if (element.type === "img" && element.file) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
333
|
+
const fullImagePath = path.join(resourceDir, element.file);
|
|
334
|
+
if (fs.existsSync(fullImagePath)) {
|
|
335
|
+
try {
|
|
295
336
|
const imageBuffer = fs.readFileSync(fullImagePath);
|
|
296
|
-
|
|
297
|
-
|
|
337
|
+
content += (0, import_koishi.h)("image", { src: `data:image/png;base64,${imageBuffer.toString("base64")}` }) + "\n";
|
|
338
|
+
} catch (error) {
|
|
339
|
+
content += session.text("commands.cave.error.mediaLoadFailed", ["图片"]) + "\n";
|
|
298
340
|
}
|
|
299
|
-
}
|
|
300
|
-
|
|
341
|
+
} else {
|
|
342
|
+
content += session.text("commands.cave.message.mediaInvalid", ["图片"]) + "\n";
|
|
301
343
|
}
|
|
302
344
|
} else if (element.type === "video" && element.file) {
|
|
303
345
|
videoElements.push({ file: element.file });
|
|
304
346
|
}
|
|
305
347
|
}
|
|
306
348
|
if (videoElements.length > 0 && session) {
|
|
307
|
-
content +=
|
|
308
|
-
`;
|
|
349
|
+
content += session.text("commands.cave.message.videoSending") + "\n";
|
|
309
350
|
for (const video of videoElements) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
351
|
+
const fullVideoPath = path.join(resourceDir, video.file);
|
|
352
|
+
if (fs.existsSync(fullVideoPath)) {
|
|
353
|
+
try {
|
|
313
354
|
const videoBuffer = fs.readFileSync(fullVideoPath);
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
});
|
|
355
|
+
session.send((0, import_koishi.h)("video", { src: `data:video/mp4;base64,${videoBuffer.toString("base64")}` })).catch((error) => logger.warn(session.text("commands.cave.error.videoSendFailed"), error.message));
|
|
356
|
+
} catch (error) {
|
|
357
|
+
content += session.text("commands.cave.error.mediaLoadFailed", ["视频"]) + "\n";
|
|
318
358
|
}
|
|
319
|
-
}
|
|
320
|
-
|
|
359
|
+
} else {
|
|
360
|
+
content += session.text("commands.cave.message.mediaInvalid", ["视频"]) + "\n";
|
|
321
361
|
}
|
|
322
362
|
}
|
|
323
363
|
}
|
|
324
|
-
content +=
|
|
364
|
+
content += session.text("commands.cave.message.contributorSuffix", [cave.contributor_name]);
|
|
325
365
|
return content;
|
|
326
366
|
}
|
|
327
367
|
__name(buildMessage, "buildMessage");
|
|
@@ -340,18 +380,10 @@ async function initCavePaths(ctx) {
|
|
|
340
380
|
}
|
|
341
381
|
__name(initCavePaths, "initCavePaths");
|
|
342
382
|
async function handleCaveAction(ctx, config, session, options, content, lastUsed) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const lines = [];
|
|
348
|
-
for (let i = 0; i < ids.length; i += 10) {
|
|
349
|
-
lines.push(ids.slice(i, i + 10).join(", "));
|
|
350
|
-
}
|
|
351
|
-
return lines.join("\n");
|
|
352
|
-
};
|
|
353
|
-
__name(formatIds, "formatIds");
|
|
354
|
-
const caveData = FileHandler.readJsonData(caveFilePath);
|
|
383
|
+
try {
|
|
384
|
+
const { caveFilePath, resourceDir, pendingFilePath } = await initCavePaths(ctx);
|
|
385
|
+
async function processList() {
|
|
386
|
+
const caveData = FileHandler.readJsonData(caveFilePath, session);
|
|
355
387
|
const caveDir = path.dirname(caveFilePath);
|
|
356
388
|
const stats = {};
|
|
357
389
|
for (const cave of caveData) {
|
|
@@ -360,114 +392,100 @@ async function handleCaveAction(ctx, config, session, options, content, lastUsed
|
|
|
360
392
|
stats[cave.contributor_number].push(cave.cave_id);
|
|
361
393
|
}
|
|
362
394
|
const statFilePath = path.join(caveDir, "stat.json");
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const count = stats[queryId].length;
|
|
379
|
-
return `${queryId} 共计投稿 ${count} 项回声洞:
|
|
380
|
-
` + formatIds(stats[queryId]);
|
|
381
|
-
} else {
|
|
382
|
-
return `未找到投稿者 ${queryId}`;
|
|
383
|
-
}
|
|
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]);
|
|
384
410
|
} else {
|
|
385
|
-
|
|
386
|
-
const lines = Object.entries(stats).map(([cid, ids]) => {
|
|
387
|
-
total += ids.length;
|
|
388
|
-
return `${cid} 共计投稿 ${ids.length} 项回声洞:
|
|
389
|
-
` + formatIds(ids);
|
|
390
|
-
});
|
|
391
|
-
return `==回声洞共计投稿 ${total} 项==
|
|
392
|
-
` + lines.join("\n");
|
|
411
|
+
return session.text("commands.cave.list.header", [totalSubmissions]) + "\n" + lines.join("\n");
|
|
393
412
|
}
|
|
394
|
-
} catch (error) {
|
|
395
|
-
return `操作失败: ${error.message}`;
|
|
396
413
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
try {
|
|
401
|
-
const pendingData = FileHandler.readJsonData(pendingFilePath);
|
|
414
|
+
__name(processList, "processList");
|
|
415
|
+
async function processAudit() {
|
|
416
|
+
const pendingData = FileHandler.readJsonData(pendingFilePath, session);
|
|
402
417
|
const isApprove = Boolean(options.p);
|
|
403
418
|
if (options.p === true && content[0] === "all" || options.d === true && content[0] === "all") {
|
|
404
|
-
return await handleAudit(ctx, pendingData, isApprove, caveFilePath, resourceDir, pendingFilePath);
|
|
419
|
+
return await handleAudit(ctx, pendingData, isApprove, caveFilePath, resourceDir, pendingFilePath, session);
|
|
405
420
|
}
|
|
406
421
|
const id = parseInt(content[0] || (typeof options.p === "string" ? options.p : "") || (typeof options.d === "string" ? options.d : ""));
|
|
407
|
-
if (isNaN(id))
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
return
|
|
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);
|
|
411
426
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
async function processView() {
|
|
415
|
-
try {
|
|
427
|
+
__name(processAudit, "processAudit");
|
|
428
|
+
async function processView() {
|
|
416
429
|
const caveId = parseInt(content[0] || (typeof options.g === "string" ? options.g : ""));
|
|
417
|
-
if (isNaN(caveId)) return "
|
|
430
|
+
if (isNaN(caveId)) return sendMessage(session, "commands.cave.error.invalidId", [], true);
|
|
418
431
|
const data = FileHandler.readJsonData(
|
|
419
432
|
caveFilePath,
|
|
433
|
+
session,
|
|
420
434
|
(item) => item && typeof item.cave_id === "number" && Array.isArray(item.elements) && item.elements.every(
|
|
421
435
|
(el) => el.type === "text" && typeof el.content === "string" || el.type === "img" && typeof el.file === "string" || el.type === "video" && typeof el.file === "string"
|
|
422
436
|
) && typeof item.contributor_number === "string" && typeof item.contributor_name === "string"
|
|
423
437
|
);
|
|
424
438
|
const cave = data.find((item) => item.cave_id === caveId);
|
|
425
|
-
if (!cave) return "
|
|
439
|
+
if (!cave) return sendMessage(session, "commands.cave.error.notFound", [], true);
|
|
426
440
|
const caveContent = await buildMessage(cave, resourceDir, session);
|
|
427
441
|
return caveContent;
|
|
428
|
-
} catch (error) {
|
|
429
|
-
return `操作失败: ${error.message}`;
|
|
430
442
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
+
}
|
|
448
475
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const validCaves = data.filter((cave2) => cave2.elements && cave2.elements.length > 0);
|
|
452
|
-
if (!validCaves.length) return void 0;
|
|
453
|
-
const randomIndex = Math.floor(Math.random() * validCaves.length);
|
|
454
|
-
return validCaves[randomIndex];
|
|
455
|
-
})();
|
|
456
|
-
return cave ? buildMessage(cave, resourceDir, session) : "获取回声洞失败";
|
|
457
|
-
}
|
|
458
|
-
__name(processRandom, "processRandom");
|
|
459
|
-
async function processDelete() {
|
|
460
|
-
try {
|
|
476
|
+
__name(processRandom, "processRandom");
|
|
477
|
+
async function processDelete() {
|
|
461
478
|
const caveId = parseInt(content[0] || (typeof options.r === "string" ? options.r : ""));
|
|
462
|
-
if (isNaN(caveId)) return "
|
|
479
|
+
if (isNaN(caveId)) return sendMessage(session, "commands.cave.error.invalidId", [], true);
|
|
463
480
|
const data = FileHandler.readJsonData(
|
|
464
481
|
caveFilePath,
|
|
482
|
+
session,
|
|
465
483
|
(item) => item && typeof item.cave_id === "number"
|
|
466
484
|
);
|
|
467
|
-
const pendingData = FileHandler.readJsonData(pendingFilePath);
|
|
485
|
+
const pendingData = FileHandler.readJsonData(pendingFilePath, session);
|
|
468
486
|
const index = data.findIndex((item) => item.cave_id === caveId);
|
|
469
487
|
const pendingIndex = pendingData.findIndex((item) => item.cave_id === caveId);
|
|
470
|
-
if (index === -1 && pendingIndex === -1) return "
|
|
488
|
+
if (index === -1 && pendingIndex === -1) return sendMessage(session, "commands.cave.error.notFound", [], true);
|
|
471
489
|
let targetCave;
|
|
472
490
|
let isPending = false;
|
|
473
491
|
if (index !== -1) {
|
|
@@ -477,130 +495,148 @@ async function handleCaveAction(ctx, config, session, options, content, lastUsed
|
|
|
477
495
|
isPending = true;
|
|
478
496
|
}
|
|
479
497
|
if (targetCave.contributor_number !== session.userId && !config.manager.includes(session.userId)) {
|
|
480
|
-
return "
|
|
498
|
+
return sendMessage(session, "commands.cave.remove.noPermission", [], true);
|
|
481
499
|
}
|
|
482
500
|
const caveContent = await buildMessage(targetCave, resourceDir, session);
|
|
483
501
|
if (targetCave.elements) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (fs.existsSync(fullPath)) fs.unlinkSync(fullPath);
|
|
489
|
-
}
|
|
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);
|
|
490
506
|
}
|
|
491
|
-
} catch (error) {
|
|
492
|
-
return `操作失败: ${error.message}`;
|
|
493
507
|
}
|
|
494
508
|
}
|
|
495
509
|
if (isPending) {
|
|
496
510
|
pendingData.splice(pendingIndex, 1);
|
|
497
|
-
FileHandler.writeJsonData(pendingFilePath, pendingData);
|
|
498
|
-
|
|
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}
|
|
499
515
|
${caveContent}`;
|
|
500
516
|
} else {
|
|
501
517
|
data.splice(index, 1);
|
|
502
|
-
FileHandler.writeJsonData(caveFilePath, data);
|
|
503
|
-
|
|
504
|
-
|
|
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}`;
|
|
505
522
|
}
|
|
506
|
-
} catch (error) {
|
|
507
|
-
return `操作失败: ${error.message}`;
|
|
508
523
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const nicknames = Array.isArray(session.app.config.nickname) ? session.app.config.nickname : session.app.config.nickname ? [session.app.config.nickname] : [];
|
|
516
|
-
const allTriggers = [...prefixes, ...nicknames];
|
|
517
|
-
const triggerPattern = allTriggers.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
518
|
-
const commandPattern = new RegExp(`^(?:${triggerPattern}).*?-a\\s*`);
|
|
519
|
-
originalContent = originalContent.replace(commandPattern, "");
|
|
520
|
-
let { imageUrls, imageElements, videoUrls, videoElements, textParts } = await extractMediaContent(originalContent);
|
|
521
|
-
if (textParts.length === 0 && imageUrls.length === 0 && videoUrls.length === 0) {
|
|
522
|
-
await session.send("请在一分钟内发送你要添加的内容");
|
|
523
|
-
const reply = await session.prompt({ timeout: 6e4 });
|
|
524
|
-
if (!reply || reply.trim() === "") {
|
|
525
|
-
return "操作超时,放弃本次添加";
|
|
524
|
+
__name(processDelete, "processDelete");
|
|
525
|
+
async function processAdd() {
|
|
526
|
+
try {
|
|
527
|
+
let inputParts = [];
|
|
528
|
+
if (content.length > 0) {
|
|
529
|
+
inputParts = content;
|
|
526
530
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (videoUrls.length > 0 && !config.allowVideo) {
|
|
535
|
-
return "已关闭上传视频功能";
|
|
536
|
-
}
|
|
537
|
-
const pendingData = FileHandler.readJsonData(pendingFilePath);
|
|
538
|
-
const data = FileHandler.readJsonData(caveFilePath, (item) => item && typeof item.cave_id === "number");
|
|
539
|
-
const maxDataId = data.length > 0 ? Math.max(...data.map((item) => item.cave_id)) : 0;
|
|
540
|
-
const maxPendingId = pendingData.length > 0 ? Math.max(...pendingData.map((item) => item.cave_id)) : 0;
|
|
541
|
-
const caveId = Math.max(maxDataId, maxPendingId) + 1;
|
|
542
|
-
let savedImages = [];
|
|
543
|
-
if (imageUrls.length > 0) {
|
|
544
|
-
try {
|
|
545
|
-
const fileSuggestions = imageElements.map((el) => el.fileAttr);
|
|
546
|
-
savedImages = await saveMedia(imageUrls, fileSuggestions, resourceDir, caveId, config, ctx, "img");
|
|
547
|
-
} catch (error) {
|
|
548
|
-
return `操作失败: ${error.message}`;
|
|
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];
|
|
549
538
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
try {
|
|
554
|
-
const fileSuggestions = videoElements.map((el) => el.fileAttr);
|
|
555
|
-
savedVideos = await saveMedia(videoUrls, fileSuggestions, resourceDir, caveId, config, ctx, "video");
|
|
556
|
-
} catch (error) {
|
|
557
|
-
return `操作失败: ${error.message}`;
|
|
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);
|
|
558
542
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
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++;
|
|
565
549
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
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
|
+
}
|
|
570
569
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
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
|
+
}
|
|
580
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);
|
|
581
637
|
}
|
|
582
|
-
const newCave = {
|
|
583
|
-
cave_id: caveId,
|
|
584
|
-
elements: cleanElementsForSave(elements, true),
|
|
585
|
-
contributor_number: session.userId,
|
|
586
|
-
contributor_name: contributorName
|
|
587
|
-
};
|
|
588
|
-
if (config.enableAudit) {
|
|
589
|
-
pendingData.push({ ...newCave, elements: cleanElementsForSave(elements, true) });
|
|
590
|
-
FileHandler.writeJsonData(pendingFilePath, pendingData);
|
|
591
|
-
await sendAuditMessage(ctx, config, newCave, await buildMessage(newCave, resourceDir, session));
|
|
592
|
-
return `已提交审核,序号为 (${caveId})`;
|
|
593
|
-
}
|
|
594
|
-
const caveWithoutIndex = { ...newCave, elements: cleanElementsForSave(elements, false) };
|
|
595
|
-
data.push(caveWithoutIndex);
|
|
596
|
-
FileHandler.writeJsonData(caveFilePath, data);
|
|
597
|
-
return `添加成功!序号为 (${caveId})`;
|
|
598
|
-
} catch (error) {
|
|
599
|
-
return `操作失败: ${error.message}`;
|
|
600
638
|
}
|
|
601
|
-
|
|
602
|
-
__name(processAdd, "processAdd");
|
|
603
|
-
try {
|
|
639
|
+
__name(processAdd, "processAdd");
|
|
604
640
|
if (options.l !== void 0) return await processList();
|
|
605
641
|
if (options.p || options.d) return await processAudit();
|
|
606
642
|
if (options.g) return await processView();
|
|
@@ -608,7 +644,8 @@ ${caveContent}`;
|
|
|
608
644
|
if (options.a) return await processAdd();
|
|
609
645
|
return await processRandom();
|
|
610
646
|
} catch (error) {
|
|
611
|
-
|
|
647
|
+
logger.error(error);
|
|
648
|
+
return sendMessage(session, "commands.cave.error.commandProcess", [error.message], true);
|
|
612
649
|
}
|
|
613
650
|
}
|
|
614
651
|
__name(handleCaveAction, "handleCaveAction");
|