mioku-plugin-meme 3.0.1 → 3.0.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/configs/base.ts +1 -1
- package/index.ts +92 -97
- package/package.json +2 -66
- package/shared.ts +26 -11
package/configs/base.ts
CHANGED
package/index.ts
CHANGED
|
@@ -42,8 +42,6 @@ function stripCommandPrefix(
|
|
|
42
42
|
|
|
43
43
|
const memePlugin = definePlugin({
|
|
44
44
|
name: "meme",
|
|
45
|
-
version: "1.0.0",
|
|
46
|
-
description: "基于 meme-generator API 的表情包制作插件",
|
|
47
45
|
|
|
48
46
|
async setup(ctx: MiokuContext) {
|
|
49
47
|
const configService = getService(ctx, Services.Config);
|
|
@@ -80,8 +78,8 @@ const memePlugin = definePlugin({
|
|
|
80
78
|
);
|
|
81
79
|
}
|
|
82
80
|
const rawText = ctx.text(event)?.trim() ?? "";
|
|
83
|
-
const
|
|
84
|
-
if (!
|
|
81
|
+
const hasPrefix = baseConfig.trigger.prefixes.some((p: string) => rawText.startsWith(p));
|
|
82
|
+
if (!hasPrefix) {
|
|
85
83
|
return;
|
|
86
84
|
}
|
|
87
85
|
const chatRuntime = aiService?.getChatRuntime();
|
|
@@ -147,6 +145,96 @@ const memePlugin = definePlugin({
|
|
|
147
145
|
);
|
|
148
146
|
}
|
|
149
147
|
|
|
148
|
+
ctx.command({
|
|
149
|
+
name: "meme 菜单",
|
|
150
|
+
match: /^(?:(?:表情|meme)包?(?:菜单|展示|制作(?:列表)?)|meme\s+(?:菜单|列表|展示))$/i,
|
|
151
|
+
prefixes: baseConfig.trigger.prefixes,
|
|
152
|
+
description: "查看已同步的表情菜单",
|
|
153
|
+
usage: ".meme 菜单",
|
|
154
|
+
handler: ({ event }) => runtime.sendMenu(ctx, event),
|
|
155
|
+
});
|
|
156
|
+
ctx.command({
|
|
157
|
+
name: "随机表情",
|
|
158
|
+
match: /^随机(?:表情|meme)(?:包)?$/i,
|
|
159
|
+
prefixes: baseConfig.trigger.prefixes,
|
|
160
|
+
description: "随机生成一个头像类表情",
|
|
161
|
+
usage: ".随机表情",
|
|
162
|
+
handler: ({ event }) => runtime.sendRandom(ctx, event),
|
|
163
|
+
});
|
|
164
|
+
ctx.command({
|
|
165
|
+
name: "meme 帮助",
|
|
166
|
+
match: /^(?:(?:头像|文字)?(?:表情|meme)包?(?:制作(?:菜单|教程)?|帮助|说明|指令|使用说明)|(?:头像|文字)(?:表情|meme)包?|meme\s+帮助)$/i,
|
|
167
|
+
prefixes: baseConfig.trigger.prefixes,
|
|
168
|
+
description: "查看表情制作教程与参数说明",
|
|
169
|
+
usage: ".meme 帮助",
|
|
170
|
+
handler: ({ event }) => runtime.sendHelp(ctx, event),
|
|
171
|
+
});
|
|
172
|
+
ctx.command({
|
|
173
|
+
name: "meme 搜索",
|
|
174
|
+
match: /^(?:表情|meme)包?(?:搜索|检索)\s*(.*)$/i,
|
|
175
|
+
prefixes: baseConfig.trigger.prefixes,
|
|
176
|
+
description: "搜索相关表情关键词",
|
|
177
|
+
usage: ".meme 搜索 摸",
|
|
178
|
+
handler: async ({ event, match }) => {
|
|
179
|
+
const query = String(match?.[1] ?? "").trim();
|
|
180
|
+
if (!query) {
|
|
181
|
+
await notifyByAIRuntime(
|
|
182
|
+
event,
|
|
183
|
+
"用户发起了 meme 搜索但没有给关键词。请自然提醒他补一个搜索词",
|
|
184
|
+
"你想搜什么?",
|
|
185
|
+
);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
await runtime.sendSearch(ctx, event, query);
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
ctx.command({
|
|
192
|
+
name: "meme 详情",
|
|
193
|
+
match: /^meme包?\s+详情\s+(.+)$/i,
|
|
194
|
+
prefixes: baseConfig.trigger.prefixes,
|
|
195
|
+
description: "查看表情参数和预览",
|
|
196
|
+
usage: ".meme 详情 摸头",
|
|
197
|
+
handler: async ({ event, match }) => {
|
|
198
|
+
const keyword = String(match?.[1] ?? "").trim();
|
|
199
|
+
if (!runtime.getDetail(keyword)) {
|
|
200
|
+
await notifyByAIRuntime(
|
|
201
|
+
event,
|
|
202
|
+
`用户查询了不存在的表情详情关键词 "${keyword}"。请自然提醒先搜索可用关键词`,
|
|
203
|
+
`未找到表情关键词:${keyword}`,
|
|
204
|
+
);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
await runtime.sendDetail(ctx, event, keyword);
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
ctx.command({
|
|
211
|
+
name: "meme 更新",
|
|
212
|
+
match: /^(?:(?:表情|meme)包?更新|meme\s+更新)$/i,
|
|
213
|
+
prefixes: baseConfig.trigger.prefixes,
|
|
214
|
+
permission: baseConfig.permissions.ownerOnlyUpdate ? "master" : "member",
|
|
215
|
+
description: "刷新远端表情缓存",
|
|
216
|
+
usage: ".meme 更新",
|
|
217
|
+
handler: async ({ event }) => {
|
|
218
|
+
await replyWithParts({
|
|
219
|
+
ctx,
|
|
220
|
+
event,
|
|
221
|
+
parts: ["开始刷新 meme 缓存,请稍等..."],
|
|
222
|
+
quoteReply: baseConfig.behavior.quoteReply,
|
|
223
|
+
});
|
|
224
|
+
try {
|
|
225
|
+
await runtime.refreshCache();
|
|
226
|
+
await runtime.sendMenu(ctx, event);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
await notifyByAIRuntime(
|
|
229
|
+
event,
|
|
230
|
+
`meme 缓存刷新失败,错误信息:${error}。请自然告知用户稍后重试或让管理员检查 meme API 服务状态。`,
|
|
231
|
+
`刷新 meme 缓存失败:${error}`,
|
|
232
|
+
error,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
|
|
150
238
|
ctx.handle("message", async (event) => {
|
|
151
239
|
const rawText = ctx.text(event)?.trim();
|
|
152
240
|
if (!rawText) {
|
|
@@ -169,99 +257,6 @@ const memePlugin = definePlugin({
|
|
|
169
257
|
: rawText;
|
|
170
258
|
|
|
171
259
|
try {
|
|
172
|
-
if (
|
|
173
|
-
commandText &&
|
|
174
|
-
(/^(?:表情|meme)包?(?:菜单|展示|制作(?:列表)?)$/i.test(commandText) ||
|
|
175
|
-
/^meme\s+(?:菜单|列表|展示)$/i.test(commandText))
|
|
176
|
-
) {
|
|
177
|
-
await runtime.sendMenu(ctx, event);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (commandText && /^随机(?:表情|meme)(?:包)?$/i.test(commandText)) {
|
|
182
|
-
await runtime.sendRandom(ctx, event);
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (
|
|
187
|
-
commandText &&
|
|
188
|
-
(/^(?:(?:头像|文字)?(?:表情|meme)包?(?:制作(?:菜单|教程)?|帮助|说明|指令|使用说明)|(?:头像|文字)(?:表情|meme)包?)$/i.test(
|
|
189
|
-
commandText,
|
|
190
|
-
) ||
|
|
191
|
-
/^meme\s+帮助$/i.test(commandText))
|
|
192
|
-
) {
|
|
193
|
-
await runtime.sendHelp(ctx, event);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const searchMatch = commandText.match(
|
|
198
|
-
/^(?:表情|meme)包?(?:搜索|检索)\s*(.*)$/i,
|
|
199
|
-
);
|
|
200
|
-
if (searchMatch) {
|
|
201
|
-
const query = (searchMatch[1] || "").trim();
|
|
202
|
-
if (!query) {
|
|
203
|
-
await notifyByAIRuntime(
|
|
204
|
-
event,
|
|
205
|
-
"用户发起了 meme 搜索但没有给关键词。请自然提醒他补一个搜索词",
|
|
206
|
-
"你想搜什么?",
|
|
207
|
-
);
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
await runtime.sendSearch(ctx, event, query);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const detailCommandMatch =
|
|
215
|
-
commandText.match(/^meme包?\s+详情\s+(.+)$/i);
|
|
216
|
-
if (detailCommandMatch) {
|
|
217
|
-
const keyword = detailCommandMatch[1].trim();
|
|
218
|
-
if (!runtime.getDetail(keyword)) {
|
|
219
|
-
await notifyByAIRuntime(
|
|
220
|
-
event,
|
|
221
|
-
`用户查询了不存在的表情详情关键词 "${keyword}"。请自然提醒先搜索可用关键词`,
|
|
222
|
-
`未找到表情关键词:${keyword}`,
|
|
223
|
-
);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
await runtime.sendDetail(ctx, event, keyword);
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (
|
|
231
|
-
commandText &&
|
|
232
|
-
(/^(?:表情|meme)包?更新$/i.test(commandText) ||
|
|
233
|
-
/^meme\s+更新$/i.test(commandText))
|
|
234
|
-
) {
|
|
235
|
-
if (baseConfig.permissions.ownerOnlyUpdate && !ctx.isOwner(event)) {
|
|
236
|
-
await notifyByAIRuntime(
|
|
237
|
-
event,
|
|
238
|
-
"用户尝试刷新 meme 缓存,但权限不足。请自然提醒该操作仅主人可用",
|
|
239
|
-
"不支持小男娘使用喵",
|
|
240
|
-
);
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
await replyWithParts({
|
|
245
|
-
ctx,
|
|
246
|
-
event,
|
|
247
|
-
parts: ["开始刷新 meme 缓存,请稍等..."],
|
|
248
|
-
quoteReply: baseConfig.behavior.quoteReply,
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
try {
|
|
252
|
-
await runtime.refreshCache();
|
|
253
|
-
await runtime.sendMenu(ctx, event);
|
|
254
|
-
} catch (error) {
|
|
255
|
-
await notifyByAIRuntime(
|
|
256
|
-
event,
|
|
257
|
-
`meme 缓存刷新失败,错误信息:${error}。请自然告知用户稍后重试或让管理员检查 meme API 服务状态。`,
|
|
258
|
-
`刷新 meme 缓存失败:${error}`,
|
|
259
|
-
error,
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
260
|
const genericGenerateMatch = commandText.match(
|
|
266
261
|
/^meme包?\s+(?:生成|制作)\s+(.+)$/i,
|
|
267
262
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mioku-plugin-meme",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "基于 meme-generator API 的表情包制作插件",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -15,71 +15,7 @@
|
|
|
15
15
|
"services": [
|
|
16
16
|
"config",
|
|
17
17
|
"ai"
|
|
18
|
-
]
|
|
19
|
-
"accessHooks": [
|
|
20
|
-
{
|
|
21
|
-
"id": "meme-菜单",
|
|
22
|
-
"match": "/^\\/meme\\s*菜单/"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"id": "meme-搜索",
|
|
26
|
-
"match": "/^\\/meme\\s*搜索/"
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"id": "meme-详情",
|
|
30
|
-
"match": "/^\\/meme\\s*详情/"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"id": "meme-更新",
|
|
34
|
-
"match": "/^\\/meme\\s*更新/"
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
"id": "随机表情",
|
|
38
|
-
"match": "/^\\/随机表情/"
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
"help": {
|
|
42
|
-
"title": "Meme 表情包",
|
|
43
|
-
"description": "接入 meme-generator API 的表情包制作插件",
|
|
44
|
-
"commands": [
|
|
45
|
-
{
|
|
46
|
-
"cmd": "/meme 菜单",
|
|
47
|
-
"desc": "查看已同步的表情菜单",
|
|
48
|
-
"usage": "/meme 菜单",
|
|
49
|
-
"role": "member"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"cmd": "/meme 搜索 <关键词>",
|
|
53
|
-
"desc": "搜索相关表情关键词",
|
|
54
|
-
"usage": "/meme 搜索 摸",
|
|
55
|
-
"role": "member"
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"cmd": "/meme 详情 <关键词>",
|
|
59
|
-
"desc": "查看表情参数和预览",
|
|
60
|
-
"usage": "/meme 详情 摸头",
|
|
61
|
-
"role": "member"
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
"cmd": "/随机表情",
|
|
65
|
-
"desc": "随机生成一个头像类表情",
|
|
66
|
-
"usage": "/随机表情",
|
|
67
|
-
"role": "member"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
"cmd": "<表情关键词> [文本1/文本2][#参数]",
|
|
71
|
-
"desc": "直接按关键词生成表情",
|
|
72
|
-
"usage": "摸头 小明#圆",
|
|
73
|
-
"role": "member"
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"cmd": "/meme 更新",
|
|
77
|
-
"desc": "刷新远端表情缓存",
|
|
78
|
-
"usage": "/meme 更新",
|
|
79
|
-
"role": "master"
|
|
80
|
-
}
|
|
81
|
-
]
|
|
82
|
-
}
|
|
18
|
+
]
|
|
83
19
|
},
|
|
84
20
|
"peerDependencies": {
|
|
85
21
|
"mioku": "^1.0.0"
|
package/shared.ts
CHANGED
|
@@ -74,8 +74,15 @@ function getSenderName(event: any): string {
|
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
/** qlogo 头像服务只认数字 QQ 号,openid 平台直接跳过 */
|
|
78
|
+
function getAvatarUrl(
|
|
79
|
+
userId: string | number | undefined,
|
|
80
|
+
adapter?: string,
|
|
81
|
+
): string {
|
|
82
|
+
const id = String(userId ?? "").trim();
|
|
83
|
+
if (!id || !/^\d+$/.test(id)) return "";
|
|
84
|
+
if (adapter && adapter !== "onebotv11" && adapter !== "icqq") return "";
|
|
85
|
+
return `https://q1.qlogo.cn/g?b=qq&s=640&nk=${id}`;
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
function extractTextAndArgs(input: string): { text: string; args: string } {
|
|
@@ -906,11 +913,11 @@ export class MemePluginRuntime {
|
|
|
906
913
|
): Promise<string[]> {
|
|
907
914
|
const sourceType = source?.type || "auto";
|
|
908
915
|
if (sourceType === "user_avatar") {
|
|
909
|
-
const qq =
|
|
910
|
-
if (!
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
916
|
+
const qq = String(source?.qq ?? "").trim();
|
|
917
|
+
if (!qq) return [];
|
|
918
|
+
return [getAvatarUrl(qq, event?.bot?.adapter)]
|
|
919
|
+
.filter(Boolean)
|
|
920
|
+
.slice(0, params.max_images || 1);
|
|
914
921
|
}
|
|
915
922
|
|
|
916
923
|
if (sourceType === "message_image") {
|
|
@@ -942,15 +949,20 @@ export class MemePluginRuntime {
|
|
|
942
949
|
|
|
943
950
|
const atUserIds = getAtUserIds(event?.message || []);
|
|
944
951
|
if (urls.length < (params.min_images || 0) && atUserIds.length > 0) {
|
|
945
|
-
urls.push(
|
|
952
|
+
urls.push(
|
|
953
|
+
...atUserIds
|
|
954
|
+
.map((userId) => getAvatarUrl(userId, event?.bot?.adapter))
|
|
955
|
+
.filter(Boolean),
|
|
956
|
+
);
|
|
946
957
|
}
|
|
947
958
|
|
|
948
959
|
if (
|
|
949
960
|
urls.length === 0 &&
|
|
950
961
|
this.baseConfig.behavior.useSenderAvatarFallback &&
|
|
951
|
-
event?.user_id
|
|
962
|
+
String(event?.user_id ?? "").trim()
|
|
952
963
|
) {
|
|
953
|
-
|
|
964
|
+
const selfAvatar = getAvatarUrl(event.user_id, event?.bot?.adapter);
|
|
965
|
+
if (selfAvatar) urls.push(selfAvatar);
|
|
954
966
|
}
|
|
955
967
|
|
|
956
968
|
return uniqueStrings(urls).slice(0, maxImages);
|
|
@@ -1008,7 +1020,10 @@ export class MemePluginRuntime {
|
|
|
1008
1020
|
const infos = await Promise.all(
|
|
1009
1021
|
atUserIds.map(async (userId) => {
|
|
1010
1022
|
try {
|
|
1011
|
-
const member = await bot.getMemberInfo(
|
|
1023
|
+
const member = await bot.getMemberInfo(
|
|
1024
|
+
String(event.group_id ?? ""),
|
|
1025
|
+
String(userId),
|
|
1026
|
+
);
|
|
1012
1027
|
return {
|
|
1013
1028
|
name: member?.card || member?.nickname || String(userId),
|
|
1014
1029
|
gender: String(member?.sex || "unknown"),
|