mioku-plugin-admin 2.3.2 → 2.3.3
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/commands/verify.ts +53 -33
- package/config.md +4 -4
- package/package.json +1 -1
- package/verify/config.ts +15 -21
- package/verify/index.ts +4 -3
package/commands/verify.ts
CHANGED
|
@@ -29,6 +29,13 @@ const VERIFY_MODE_LABELS: Record<string, string> = {
|
|
|
29
29
|
chiral: "手性碳",
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
async function extractQuoteImageUrls(event: any): Promise<string[]> {
|
|
33
|
+
if (!event || typeof event.getQuoteMsg !== "function") return [];
|
|
34
|
+
const quoteMsg = await event.getQuoteMsg().catch(() => null);
|
|
35
|
+
if (!quoteMsg || !Array.isArray(quoteMsg.message)) return [];
|
|
36
|
+
return extractImageUrls(quoteMsg.message);
|
|
37
|
+
}
|
|
38
|
+
|
|
32
39
|
export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
33
40
|
const { ctx, getVerifyConfig, setVerifyConfig, verifyController } = options;
|
|
34
41
|
|
|
@@ -250,29 +257,32 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
250
257
|
|
|
251
258
|
// /入群提示 xxx
|
|
252
259
|
// /入群提示 关闭
|
|
253
|
-
//
|
|
260
|
+
// /入群提示(带图片,可来自当前消息或引用消息)— 仅图片也可
|
|
254
261
|
if (text.startsWith("/入群提示") || text.startsWith("#入群提示")) {
|
|
255
262
|
if (!(await ensureAdminPermission())) return;
|
|
256
263
|
|
|
257
264
|
const rawArg = text.replace(/^[/#]入群提示\s*/, "").trim();
|
|
258
265
|
const current = getVerifyConfig();
|
|
259
266
|
const groupCfg = getGroupVerifyConfig(current, groupId);
|
|
260
|
-
const
|
|
267
|
+
const directImageUrls = extractImageUrls(event.message);
|
|
268
|
+
const quoteImageUrls = await extractQuoteImageUrls(event).catch(() => []);
|
|
269
|
+
const imageUrls =
|
|
270
|
+
directImageUrls.length > 0 ? directImageUrls : quoteImageUrls;
|
|
261
271
|
|
|
262
272
|
if (rawArg === "关闭" || rawArg === "清空" || rawArg === "关") {
|
|
263
273
|
if (!hasCustomPrompt(groupCfg)) {
|
|
264
274
|
await event.reply("本群还没设置自定义入群提示哦~", true);
|
|
265
275
|
return;
|
|
266
276
|
}
|
|
267
|
-
const
|
|
277
|
+
const removedFile = groupCfg.promptImage;
|
|
268
278
|
const next = upsertGroupVerifyConfig(current, groupId, {
|
|
269
279
|
customPrompt: "",
|
|
270
|
-
|
|
280
|
+
promptImage: "",
|
|
271
281
|
});
|
|
272
282
|
await setVerifyConfig(next);
|
|
273
283
|
await pruneGroupPromptImages(groupId, []).catch(() => {});
|
|
274
284
|
ctx.logger.info(
|
|
275
|
-
`admin verify 关闭群 ${groupId} 自定义入群提示,清理图片 ${
|
|
285
|
+
`admin verify 关闭群 ${groupId} 自定义入群提示,清理图片 ${removedFile}`,
|
|
276
286
|
);
|
|
277
287
|
await event.reply("已关闭本群自定义入群提示~", true);
|
|
278
288
|
return;
|
|
@@ -281,23 +291,26 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
281
291
|
if (!rawArg && !imageUrls.length) {
|
|
282
292
|
if (!hasCustomPrompt(groupCfg)) {
|
|
283
293
|
await event.reply(
|
|
284
|
-
"用法:/入群提示 xxx(最多 50
|
|
294
|
+
"用法:/入群提示 xxx(最多 50 字),可附带图片(当前消息或引用消息中的图片)一起发送;/入群提示 关闭 关闭自定义提示~",
|
|
285
295
|
true,
|
|
286
296
|
);
|
|
287
297
|
return;
|
|
288
298
|
}
|
|
289
|
-
const
|
|
290
|
-
|
|
299
|
+
const lines = ["已开启本群自定义入群提示"];
|
|
300
|
+
lines.push(
|
|
291
301
|
groupCfg.customPrompt
|
|
292
302
|
? `文字:${groupCfg.customPrompt}`
|
|
293
303
|
: "文字:(未设置)",
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
304
|
+
);
|
|
305
|
+
lines.push(
|
|
306
|
+
groupCfg.promptImage
|
|
307
|
+
? `图片:已设置(filename=${groupCfg.promptImage})`
|
|
308
|
+
: "图片:(未设置)",
|
|
309
|
+
);
|
|
310
|
+
await event.reply(lines.join("\n"), true);
|
|
297
311
|
return;
|
|
298
312
|
}
|
|
299
313
|
|
|
300
|
-
let nextPrompt = groupCfg.customPrompt;
|
|
301
314
|
if (rawArg) {
|
|
302
315
|
const argLength = Array.from(rawArg).length;
|
|
303
316
|
if (argLength > MAX_CUSTOM_PROMPT_LENGTH) {
|
|
@@ -309,39 +322,46 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
309
322
|
});
|
|
310
323
|
return;
|
|
311
324
|
}
|
|
312
|
-
nextPrompt = normalizeCustomPrompt(rawArg);
|
|
313
325
|
}
|
|
326
|
+
const nextPrompt = rawArg
|
|
327
|
+
? normalizeCustomPrompt(rawArg)
|
|
328
|
+
: groupCfg.customPrompt;
|
|
314
329
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const
|
|
319
|
-
|
|
330
|
+
let nextImage = groupCfg.promptImage;
|
|
331
|
+
let imageNote = "";
|
|
332
|
+
if (imageUrls.length) {
|
|
333
|
+
const targetUrl = imageUrls[0];
|
|
334
|
+
const savedImage = await saveRemoteImageAsPrompt(groupId, targetUrl);
|
|
335
|
+
if (savedImage) {
|
|
336
|
+
const previousImage = groupCfg.promptImage;
|
|
337
|
+
nextImage = savedImage.filename;
|
|
338
|
+
imageNote = previousImage
|
|
339
|
+
? `图片已替换(旧文件 ${previousImage} 已删除)`
|
|
340
|
+
: `图片已设置(${savedImage.filename})`;
|
|
341
|
+
if (previousImage) {
|
|
342
|
+
ctx.logger.info(
|
|
343
|
+
`admin verify 替换群 ${groupId} 入群提示图片:${previousImage} -> ${savedImage.filename}`,
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
imageNote = "图片下载失败,请稍后重试";
|
|
348
|
+
}
|
|
320
349
|
}
|
|
321
350
|
|
|
322
|
-
const nextImages = imageUrls.length
|
|
323
|
-
? [...groupCfg.promptImages, ...saved]
|
|
324
|
-
: groupCfg.promptImages;
|
|
325
|
-
|
|
326
351
|
const next = upsertGroupVerifyConfig(current, groupId, {
|
|
327
352
|
customPrompt: nextPrompt,
|
|
328
|
-
|
|
353
|
+
promptImage: nextImage,
|
|
329
354
|
});
|
|
330
355
|
await setVerifyConfig(next);
|
|
331
|
-
await pruneGroupPromptImages(groupId,
|
|
356
|
+
await pruneGroupPromptImages(groupId, nextImage ? [nextImage] : []).catch(
|
|
357
|
+
() => {},
|
|
358
|
+
);
|
|
332
359
|
|
|
333
|
-
const lines
|
|
360
|
+
const lines = ["已更新本群自定义入群提示"];
|
|
334
361
|
if (rawArg) lines.push(`文字:${nextPrompt}`);
|
|
335
362
|
else if (groupCfg.customPrompt)
|
|
336
363
|
lines.push(`文字(保持):${groupCfg.customPrompt}`);
|
|
337
|
-
if (imageUrls.length)
|
|
338
|
-
lines.push(
|
|
339
|
-
saved.length
|
|
340
|
-
? `新增图片 ${saved.length} 张${failed > saved.length ? `,${failed - saved.length} 张保存失败` : ""}`
|
|
341
|
-
: `图片保存失败 ${failed} 张,请稍后重试`,
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
lines.push(`当前共 ${nextImages.length} 张图片`);
|
|
364
|
+
if (imageUrls.length && imageNote) lines.push(imageNote);
|
|
345
365
|
await event.reply(lines.join("\n"), true);
|
|
346
366
|
return;
|
|
347
367
|
}
|
package/config.md
CHANGED
|
@@ -106,11 +106,11 @@ fields:
|
|
|
106
106
|
description: 一旦设置该群将跳过 AI 生成欢迎,验证通过后直接发送这段文字(可附带本地图片一起)。上限 50 字,建议在群里直接用 /入群提示 xxx 设置或 /入群提示 关闭 关闭。
|
|
107
107
|
placeholder: 例:欢迎来到本群,请先看群公告~
|
|
108
108
|
|
|
109
|
-
- key:
|
|
109
|
+
- key: promptImage
|
|
110
110
|
label: 群自定义入群提示图片
|
|
111
|
-
type:
|
|
112
|
-
description:
|
|
113
|
-
placeholder: 例:
|
|
111
|
+
type: text
|
|
112
|
+
description: 单张图片文件名(保存在 data/admin/<群号>/prompt-images/),与文字一起发送。在群里发送 /入群提示 时附带图片(当前消息或引用消息中的图片均可)即可替换;/入群提示 关闭 会一并清空。
|
|
113
|
+
placeholder: 例:prompt-l8t9a-3f2c.png
|
|
114
114
|
|
|
115
115
|
- key: verify.reactionEmojiId
|
|
116
116
|
label: 回应模式表态表情ID
|
package/package.json
CHANGED
package/verify/config.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface VerifyGroupConfig {
|
|
|
7
7
|
enabled: boolean;
|
|
8
8
|
mode: VerifyMode;
|
|
9
9
|
customPrompt: string;
|
|
10
|
-
|
|
10
|
+
promptImage: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface VerifyConfig {
|
|
@@ -50,25 +50,16 @@ export function normalizeCustomPrompt(value: unknown): string {
|
|
|
50
50
|
return Array.from(trimmed).slice(0, MAX_CUSTOM_PROMPT_LENGTH).join("");
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export function
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
const result: string[] = [];
|
|
57
|
-
for (const item of value) {
|
|
58
|
-
if (typeof item !== "string") continue;
|
|
59
|
-
const name = item.trim();
|
|
60
|
-
if (!name || seen.has(name)) continue;
|
|
61
|
-
seen.add(name);
|
|
62
|
-
result.push(name);
|
|
63
|
-
}
|
|
64
|
-
return result;
|
|
53
|
+
export function normalizePromptImage(value: unknown): string {
|
|
54
|
+
if (typeof value !== "string") return "";
|
|
55
|
+
return value.trim();
|
|
65
56
|
}
|
|
66
57
|
|
|
67
58
|
export function hasCustomPrompt(groupCfg: VerifyGroupConfig | undefined): boolean {
|
|
68
59
|
if (!groupCfg) return false;
|
|
69
60
|
return (
|
|
70
61
|
Boolean(groupCfg.customPrompt && groupCfg.customPrompt.trim()) ||
|
|
71
|
-
groupCfg.
|
|
62
|
+
Boolean(groupCfg.promptImage && groupCfg.promptImage.trim())
|
|
72
63
|
);
|
|
73
64
|
}
|
|
74
65
|
|
|
@@ -81,6 +72,11 @@ export function normalizeVerifyMode(value: unknown): VerifyMode {
|
|
|
81
72
|
|
|
82
73
|
function normalizeVerifyGroup(raw: any): VerifyGroupConfig {
|
|
83
74
|
const groupId = Number(raw?.groupId || raw?.group_id || 0);
|
|
75
|
+
const promptImageRaw =
|
|
76
|
+
raw?.promptImage ??
|
|
77
|
+
raw?.prompt_image ??
|
|
78
|
+
(Array.isArray(raw?.promptImages) ? raw.promptImages[0] : undefined) ??
|
|
79
|
+
(Array.isArray(raw?.images) ? raw.images[0] : undefined);
|
|
84
80
|
return {
|
|
85
81
|
groupId: groupId > 0 ? groupId : 0,
|
|
86
82
|
enabled: raw?.enabled === true,
|
|
@@ -88,9 +84,7 @@ function normalizeVerifyGroup(raw: any): VerifyGroupConfig {
|
|
|
88
84
|
customPrompt: normalizeCustomPrompt(
|
|
89
85
|
raw?.customPrompt ?? raw?.custom_prompt ?? raw?.extraPrompt,
|
|
90
86
|
),
|
|
91
|
-
|
|
92
|
-
raw?.promptImages ?? raw?.prompt_images ?? raw?.images,
|
|
93
|
-
),
|
|
87
|
+
promptImage: normalizePromptImage(promptImageRaw),
|
|
94
88
|
};
|
|
95
89
|
}
|
|
96
90
|
|
|
@@ -157,7 +151,7 @@ export function getGroupVerifyConfig(
|
|
|
157
151
|
enabled: false,
|
|
158
152
|
mode: "reaction",
|
|
159
153
|
customPrompt: "",
|
|
160
|
-
|
|
154
|
+
promptImage: "",
|
|
161
155
|
};
|
|
162
156
|
}
|
|
163
157
|
|
|
@@ -174,8 +168,8 @@ export function upsertGroupVerifyConfig(
|
|
|
174
168
|
if (patch.customPrompt !== undefined) {
|
|
175
169
|
normalizedPatch.customPrompt = normalizeCustomPrompt(patch.customPrompt);
|
|
176
170
|
}
|
|
177
|
-
if (patch.
|
|
178
|
-
normalizedPatch.
|
|
171
|
+
if (patch.promptImage !== undefined) {
|
|
172
|
+
normalizedPatch.promptImage = normalizePromptImage(patch.promptImage);
|
|
179
173
|
}
|
|
180
174
|
if (idx >= 0) {
|
|
181
175
|
next.groups = config.groups.map((g, i) =>
|
|
@@ -189,7 +183,7 @@ export function upsertGroupVerifyConfig(
|
|
|
189
183
|
enabled: false,
|
|
190
184
|
mode: "reaction",
|
|
191
185
|
customPrompt: "",
|
|
192
|
-
|
|
186
|
+
promptImage: "",
|
|
193
187
|
...normalizedPatch,
|
|
194
188
|
},
|
|
195
189
|
];
|
package/verify/index.ts
CHANGED
|
@@ -367,15 +367,16 @@ export function createVerifyController(
|
|
|
367
367
|
if (prompt) {
|
|
368
368
|
segments.push(ctx.segment.text(prompt));
|
|
369
369
|
}
|
|
370
|
-
|
|
370
|
+
const filename = String(groupCfg.promptImage || "").trim();
|
|
371
|
+
if (filename) {
|
|
371
372
|
const imagePath = getGroupPromptImagePath(info.groupId, filename);
|
|
372
373
|
if (!existsSync(imagePath)) {
|
|
373
374
|
ctx.logger.warn(
|
|
374
375
|
`admin verify 自定义入群提示图片缺失: ${imagePath}`,
|
|
375
376
|
);
|
|
376
|
-
|
|
377
|
+
} else {
|
|
378
|
+
segments.push(ctx.segment.image(`file://${imagePath}`));
|
|
377
379
|
}
|
|
378
|
-
segments.push(ctx.segment.image(`file://${imagePath}`));
|
|
379
380
|
}
|
|
380
381
|
if (!segments.length) return false;
|
|
381
382
|
try {
|