koishi-plugin-ll-brick 1.0.5 → 1.0.7
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 +97 -29
- package/package.json +1 -1
- package/readme.md +18 -0
package/lib/index.js
CHANGED
|
@@ -52,11 +52,9 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
52
52
|
])
|
|
53
53
|
]);
|
|
54
54
|
exports.inject = ["database"];
|
|
55
|
-
// QQ
|
|
56
|
-
// 因此 QQ 平台的回复直接走开放平台 internal API 发 markdown
|
|
57
|
-
//
|
|
58
|
-
const BRICK_IMG = 'https://img3.tofaka.com/autoupload/ontjZmlK09ZHnuFOv9znC7KXl_QqVl-bpSwqP4fJO68/20260624/lOIl/240X240/images.jpg';
|
|
59
|
-
const FIRE_IMG = 'https://img3.tofaka.com/autoupload/ontjZmlK09ZHnuFOv9znC7KXl_QqVl-bpSwqP4fJO68/20260624/xsnm/447X447/images_%282%29.jpg';
|
|
55
|
+
// 本插件面向 QQ 官方机器人。@ 标签(<qqbot-at-user>)只有在 markdown 消息里才渲染,
|
|
56
|
+
// 因此 QQ 平台的回复直接走开放平台 internal API 发 markdown;其他平台沿用原 h.at 文本消息。
|
|
57
|
+
// 所有通知均为 markdown 卡片(不含图片)。
|
|
60
58
|
function atUser(session, userId) {
|
|
61
59
|
if (session?.platform === 'qq') {
|
|
62
60
|
return `<qqbot-at-user id="${userId}" />`;
|
|
@@ -75,20 +73,22 @@ function stripMarkdown(md) {
|
|
|
75
73
|
.replace(/\n{3,}/g, '\n\n')
|
|
76
74
|
.trim();
|
|
77
75
|
}
|
|
78
|
-
|
|
76
|
+
function mdCard(lines) {
|
|
77
|
+
return lines.filter(Boolean).join('\n');
|
|
78
|
+
}
|
|
79
|
+
async function sendQQMarkdown(session, text) {
|
|
79
80
|
const channelId = session.guildId;
|
|
80
81
|
const internal = session.bot?.internal;
|
|
81
82
|
if (!channelId || !internal || typeof internal.sendMessage !== 'function') {
|
|
82
83
|
return false;
|
|
83
84
|
}
|
|
84
|
-
const
|
|
85
|
-
const plain = stripMarkdown(md) || ' ';
|
|
85
|
+
const plain = stripMarkdown(text) || ' ';
|
|
86
86
|
try {
|
|
87
87
|
await internal.sendMessage(channelId, {
|
|
88
88
|
msg_type: 2,
|
|
89
89
|
msg_seq: 0,
|
|
90
90
|
content: plain,
|
|
91
|
-
markdown: { content:
|
|
91
|
+
markdown: { content: text },
|
|
92
92
|
});
|
|
93
93
|
return true;
|
|
94
94
|
}
|
|
@@ -100,6 +100,22 @@ async function sendQQMarkdown(session, imageUrl, text) {
|
|
|
100
100
|
return false;
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
+
// QQ 官方适配器未实现 getGuildMemberIter/getGuildMemberList,改走开放平台群成员列表 API
|
|
104
|
+
async function getQQMemberIds(session) {
|
|
105
|
+
const http = session.bot?.http;
|
|
106
|
+
if (!http || typeof http.get !== 'function') return [];
|
|
107
|
+
try {
|
|
108
|
+
const resp = await http.get(`/v2/groups/${session.guildId}/members`);
|
|
109
|
+
const list = resp?.data;
|
|
110
|
+
if (!Array.isArray(list)) return [];
|
|
111
|
+
return list
|
|
112
|
+
.map((m) => m?.member_openid || m?.openid || m?.id || m?.member?.openid || m?.member?.user?.id || m?.user?.id)
|
|
113
|
+
.filter(Boolean);
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
103
119
|
async function apply(ctx, config) {
|
|
104
120
|
ctx.model.extend('brick', {
|
|
105
121
|
id: 'unsigned',
|
|
@@ -136,7 +152,19 @@ async function apply(ctx, config) {
|
|
|
136
152
|
return `已经在烧砖了`;
|
|
137
153
|
}
|
|
138
154
|
users[user].burning = true;
|
|
139
|
-
|
|
155
|
+
const startCard = mdCard([
|
|
156
|
+
'# 🔥 砖厂开始烧砖啦!',
|
|
157
|
+
'---',
|
|
158
|
+
'> 🏭 **工作状态**:现在开始烧砖啦!',
|
|
159
|
+
`> 💬 **烧砖规则**:群友每发送 **${config.cost}** 条消息,就能成功烧好一块新砖 🧱`,
|
|
160
|
+
'> 📢 大家快来水群,给砖窑添把火吧!',
|
|
161
|
+
]);
|
|
162
|
+
if (session.platform === 'qq') {
|
|
163
|
+
await sendQQMarkdown(session, startCard);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
await session.send(startCard);
|
|
167
|
+
}
|
|
140
168
|
let messageCount = 0;
|
|
141
169
|
const dispose = ctx.guild(session.guildId).middleware(async (session_in, next) => {
|
|
142
170
|
if (![session.selfId, session.userId].includes(session_in.userId)) {
|
|
@@ -149,12 +177,17 @@ async function apply(ctx, config) {
|
|
|
149
177
|
brick: koishi_1.$.add(row.brick, 1),
|
|
150
178
|
}], ["userId", "guildId"]);
|
|
151
179
|
users[user].burning = false;
|
|
152
|
-
const fireDone =
|
|
180
|
+
const fireDone = mdCard([
|
|
181
|
+
'# 🎉 砖厂出炉啦!',
|
|
182
|
+
'---',
|
|
183
|
+
`> 🔨 ${atUser(session, session.userId)} 砖已经烧好啦!`,
|
|
184
|
+
'> 📢 快去用 `砖头 拍人` 狠狠地拍一下吧!',
|
|
185
|
+
]);
|
|
153
186
|
if (session.platform === 'qq') {
|
|
154
|
-
await sendQQMarkdown(session,
|
|
187
|
+
await sendQQMarkdown(session, fireDone);
|
|
155
188
|
}
|
|
156
189
|
else {
|
|
157
|
-
await session.send(
|
|
190
|
+
await session.send(fireDone);
|
|
158
191
|
}
|
|
159
192
|
}
|
|
160
193
|
}
|
|
@@ -199,29 +232,36 @@ async function apply(ctx, config) {
|
|
|
199
232
|
const probability = config.specialUser[targetUserId] !== undefined
|
|
200
233
|
? config.specialUser[targetUserId] / 100
|
|
201
234
|
: config.reverse / 100;
|
|
202
|
-
const brickImg = koishi_1.h.image('https://img3.tofaka.com/autoupload/ontjZmlK09ZHnuFOv9znC7KXl_QqVl-bpSwqP4fJO68/20260624/lOIl/240X240/images.jpg');
|
|
203
235
|
const isQQ = session.platform === 'qq';
|
|
204
236
|
if (koishi_1.Random.bool(probability)) {
|
|
205
237
|
const muteErr = await tryMute(session.userId);
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
238
|
+
const msg = mdCard([
|
|
239
|
+
'# 💥 群内突发事件!',
|
|
240
|
+
'---',
|
|
241
|
+
'> ⚠️ 危险警告:有人动用了板砖!',
|
|
242
|
+
`> 🎯 ${atUser(session, targetUserId)} 夺过你的砖头,把你拍晕了 **${muteTime}** 秒 🏏`,
|
|
243
|
+
muteErr ? '> ⚠️ 因为我不是群管理员,所以并没什么卵用' : '',
|
|
244
|
+
]);
|
|
209
245
|
if (isQQ) {
|
|
210
|
-
await sendQQMarkdown(session,
|
|
246
|
+
await sendQQMarkdown(session, msg);
|
|
211
247
|
return;
|
|
212
248
|
}
|
|
213
|
-
return
|
|
249
|
+
return msg;
|
|
214
250
|
}
|
|
215
251
|
else {
|
|
216
252
|
const muteErr = await tryMute(targetUserId);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
253
|
+
const msg = mdCard([
|
|
254
|
+
'# 💥 群内突发事件!',
|
|
255
|
+
'---',
|
|
256
|
+
'> ⚠️ 危险警告:有人动用了板砖!',
|
|
257
|
+
`> 🎯 ${atUser(session, targetUserId)} 你被 ${atUser(session, session.userId)} 一砖头拍晕了 **${muteTime}** 秒 🏏`,
|
|
258
|
+
muteErr ? '> ⚠️ 因为我不是群管理员,所以并没什么卵用' : '',
|
|
259
|
+
]);
|
|
220
260
|
if (isQQ) {
|
|
221
|
-
await sendQQMarkdown(session,
|
|
261
|
+
await sendQQMarkdown(session, msg);
|
|
222
262
|
return;
|
|
223
263
|
}
|
|
224
|
-
return
|
|
264
|
+
return msg;
|
|
225
265
|
}
|
|
226
266
|
async function tryMute(slapedUserId) {
|
|
227
267
|
users[`${session.guildId}:${slapedUserId}`].muted = true;
|
|
@@ -252,8 +292,16 @@ async function apply(ctx, config) {
|
|
|
252
292
|
.alias("随机拍人")
|
|
253
293
|
.action(async ({ session }) => {
|
|
254
294
|
const guildMember = [];
|
|
255
|
-
|
|
256
|
-
guildMember.push(
|
|
295
|
+
if (session.platform === 'qq') {
|
|
296
|
+
guildMember.push(...await getQQMemberIds(session));
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
for await (const member of session.bot.getGuildMemberIter(session.guildId)) {
|
|
300
|
+
guildMember.push(member?.user.id);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (!guildMember.length) {
|
|
304
|
+
return '获取群成员列表失败,无法随机拍人';
|
|
257
305
|
}
|
|
258
306
|
await session.execute(`砖头.拍人 ${koishi_1.h.at(koishi_1.Random.pick(guildMember))}`);
|
|
259
307
|
});
|
|
@@ -278,7 +326,6 @@ async function apply(ctx, config) {
|
|
|
278
326
|
const date = new Date();
|
|
279
327
|
const today = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
|
280
328
|
let brick = koishi_1.Random.int(config.minGain, config.maxGain + 1);
|
|
281
|
-
const signImg = koishi_1.h.image('https://img3.tofaka.com/autoupload/ontjZmlK09ZHnuFOv9znC7KXl_QqVl-bpSwqP4fJO68/20260624/yNf2/447X447/images_%281%29.jpg');
|
|
282
329
|
const userData = await ctx.database.get('brick', {
|
|
283
330
|
userId: session.userId,
|
|
284
331
|
guildId: session.guildId,
|
|
@@ -290,7 +337,17 @@ async function apply(ctx, config) {
|
|
|
290
337
|
brick: brick,
|
|
291
338
|
checkingDay: today
|
|
292
339
|
});
|
|
293
|
-
|
|
340
|
+
const card = mdCard([
|
|
341
|
+
'# 🎡 砖厂打卡成功!',
|
|
342
|
+
'---',
|
|
343
|
+
`> 😋 辛苦啦!你刚刚搬运获得了 **${brick}** 块砖头 🧱`,
|
|
344
|
+
`> 📦 **当前库存**:你现在共有 \`${brick}/${config.maxBrick}\` 块砖头。`,
|
|
345
|
+
]);
|
|
346
|
+
if (session.platform === 'qq') {
|
|
347
|
+
await sendQQMarkdown(session, card);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
return card;
|
|
294
351
|
}
|
|
295
352
|
if (userData[0].checkingDay === today) {
|
|
296
353
|
return "你今天已经签到过了";
|
|
@@ -310,7 +367,18 @@ async function apply(ctx, config) {
|
|
|
310
367
|
brick: koishi_1.$.add(row.brick, brick),
|
|
311
368
|
checkingDay: today
|
|
312
369
|
}], ["userId", "guildId"]);
|
|
313
|
-
|
|
370
|
+
const total = userData[0].brick + brick;
|
|
371
|
+
const card = mdCard([
|
|
372
|
+
'# 🎡 砖厂打卡成功!',
|
|
373
|
+
'---',
|
|
374
|
+
`> 😋 辛苦啦!你刚刚搬运获得了 **${brick}** 块砖头 🧱`,
|
|
375
|
+
`> 📦 **当前库存**:你现在共有 \`${total}/${config.maxBrick}\` 块砖头。`,
|
|
376
|
+
]);
|
|
377
|
+
if (session.platform === 'qq') {
|
|
378
|
+
await sendQQMarkdown(session, card);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
return card;
|
|
314
382
|
});
|
|
315
383
|
}
|
|
316
384
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -13,6 +13,24 @@
|
|
|
13
13
|
- `砖头 查看` — 查看自己的砖头数量
|
|
14
14
|
- `砖头 签到`(可选开启)— 每日签到获取随机砖头
|
|
15
15
|
|
|
16
|
+
## v1.0.7 更新
|
|
17
|
+
|
|
18
|
+
- **移除所有图片**,所有通知统一改为 markdown 卡片样式(`# 标题` + `---` + `> 引用行`),加载更快
|
|
19
|
+
- 烧砖开始:「砖厂开始烧砖啦!」
|
|
20
|
+
- 烧砖完成:「砖厂出炉啦!」
|
|
21
|
+
- 拍人成功:「群内突发事件!」(两种分支)
|
|
22
|
+
- 签到打卡:「砖厂打卡成功!」
|
|
23
|
+
- `@` 保留用 `<qqbot-at-user>`,markdown 里正常渲染(与欢迎插件一致)
|
|
24
|
+
|
|
25
|
+
## v1.0.6 修复
|
|
26
|
+
|
|
27
|
+
- 修复 **`砖头 随机拍人` 报错 `not implemented: getGuildMemberList`**(QQ 官方适配器未实现群成员迭代接口):
|
|
28
|
+
- QQ 平台改为调用开放平台群成员列表 API(`/v2/groups/{openid}/members`)随机挑人;其他平台保持原逻辑
|
|
29
|
+
- 获取不到成员时返回提示,不再崩溃
|
|
30
|
+
- 修复 **拍人/烧砖完成消息中 markdown 图片不显示**:
|
|
31
|
+
- 根因:QQ markdown 图片必须带尺寸参数(如 `#240px #240px`),之前 `` 没带,图片显示异常
|
|
32
|
+
- 修复:嵌入图片统一加 `#240px #240px`(拍人)/ `#447px #447px`(烧砖)尺寸参数
|
|
33
|
+
|
|
16
34
|
## v1.0.5 修复
|
|
17
35
|
|
|
18
36
|
- 修复 **手机端 QQ 不显示图片**(电脑端正常)的问题:
|