@alemonjs/qq-bot 2.1.34 → 2.1.36
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/README.md +8 -8
- package/lib/format.d.ts +4 -1
- package/lib/format.js +68 -4
- package/lib/index.websoket.js +1 -1
- package/lib/sdk/qr-auth.d.ts +3 -3
- package/lib/sdk/qr-auth.js +4 -7
- package/lib/sends.js +11 -61
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -116,7 +116,7 @@ export default async () => {
|
|
|
116
116
|
|
|
117
117
|
### 流程
|
|
118
118
|
|
|
119
|
-
1. 启动适配器(默认 WebSocket
|
|
119
|
+
1. 启动适配器(默认 WebSocket 模式),通过 CBP 输出授权二维码与链接;二维码图片由 CBP/UI 统一处理;
|
|
120
120
|
2. 使用**手机 QQ**(开放平台上该机器人的管理者账号)扫描二维码(终端直接扫,或打开保存的图片扫),并在页面中确认授权;
|
|
121
121
|
3. 适配器自动轮询授权结果,平台下发的凭证在本地解密(AES-256-GCM,密钥不落盘);
|
|
122
122
|
4. `app_id` 与 `secret` 自动写入 `alemon.config.yaml` 的 `qq-bot` 节(保留文件中已有的注释与原格式),随后立即连接,无需重启。
|
|
@@ -131,13 +131,13 @@ export default async () => {
|
|
|
131
131
|
|
|
132
132
|
### 说明
|
|
133
133
|
|
|
134
|
-
| 事项 | 说明
|
|
135
|
-
| -------- |
|
|
136
|
-
| 触发条件 | 配置中未填写 `app_id`/`secret`,且未配置 `bots`(WebSocket 模式)
|
|
137
|
-
| 二维码 |
|
|
138
|
-
| 凭证安全 | AppSecret 全程密文传输、本地解密,密钥仅存内存不落盘
|
|
139
|
-
| 失败处理 | 超时 / 刷新次数用尽 / 授权取消时跳过连接并输出日志,可重启重试或手动配置
|
|
140
|
-
| Webhook | Webhook 模式(配置 `route`/`port`/`ws`)不触发扫码流程,需自行填写完整配置
|
|
134
|
+
| 事项 | 说明 |
|
|
135
|
+
| -------- | -------------------------------------------------------------------------- |
|
|
136
|
+
| 触发条件 | 配置中未填写 `app_id`/`secret`,且未配置 `bots`(WebSocket 模式) |
|
|
137
|
+
| 二维码 | CBP 统一输出,过期自动刷新(最多 3 次),总超时 10 分钟 |
|
|
138
|
+
| 凭证安全 | AppSecret 全程密文传输、本地解密,密钥仅存内存不落盘 |
|
|
139
|
+
| 失败处理 | 超时 / 刷新次数用尽 / 授权取消时跳过连接并输出日志,可重启重试或手动配置 |
|
|
140
|
+
| Webhook | Webhook 模式(配置 `route`/`port`/`ws`)不触发扫码流程,需自行填写完整配置 |
|
|
141
141
|
|
|
142
142
|
---
|
|
143
143
|
|
package/lib/format.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { DataEnums, DataMarkDown } from "alemonjs";
|
|
2
2
|
//#region src/format.d.ts
|
|
3
|
+
/** 群聊、私聊和频道共用有序正文;提及等原生文本由发送上下文提供。 */
|
|
4
|
+
declare const formatQQContent: (items: DataEnums[], renderNative: (item: DataEnums) => string, plain?: boolean, hideUnsupported?: boolean | number) => string;
|
|
3
5
|
/**
|
|
4
6
|
* 将结构化 Markdown 子元素数组转为可读纯文本
|
|
5
7
|
*/
|
|
@@ -22,5 +24,6 @@ declare const markdownRawToText: (raw: string, hideUnsupported?: boolean | numbe
|
|
|
22
24
|
* 其余类型降级为文本
|
|
23
25
|
*/
|
|
24
26
|
declare const dataEnumToText: (item: DataEnums, hideUnsupported?: boolean | number) => string;
|
|
27
|
+
declare const createMarkdownText: (data: DataMarkDown['value']) => string;
|
|
25
28
|
//#endregion
|
|
26
|
-
export { buttonsToText, dataEnumToText, markdownRawToText, markdownToText };
|
|
29
|
+
export { buttonsToText, createMarkdownText, dataEnumToText, formatQQContent, markdownRawToText, markdownToText };
|
package/lib/format.js
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
|
+
import { joinMarkdownParts, renderMarkdownBlockquote } from "alemonjs/markdown";
|
|
2
|
+
|
|
1
3
|
//#region src/format.ts
|
|
4
|
+
/** 群聊、私聊和频道共用有序正文;提及等原生文本由发送上下文提供。 */
|
|
5
|
+
const formatQQContent = (items, renderNative, plain = false, hideUnsupported) => {
|
|
6
|
+
return items.map((item) => {
|
|
7
|
+
if (item.type === "Markdown") return plain ? markdownToText(item.value, hideUnsupported) : createMarkdownText(item.value);
|
|
8
|
+
if (item.type === "MarkdownOriginal") {
|
|
9
|
+
const text = plain ? markdownRawToText(item.value, hideUnsupported) : item.value;
|
|
10
|
+
return text ? `\n\n${text}\n\n` : "";
|
|
11
|
+
}
|
|
12
|
+
if (item.type === "BT.group") {
|
|
13
|
+
if (!plain || Number(hideUnsupported) >= 4) return "";
|
|
14
|
+
const text = item.value.map((row) => row.value.map((button) => {
|
|
15
|
+
if (Number(hideUnsupported) >= 3) return "";
|
|
16
|
+
if (Number(hideUnsupported) >= 2) return button.options?.data || button.value;
|
|
17
|
+
return hideUnsupported ? button.value : `[${button.value}]`;
|
|
18
|
+
}).filter(Boolean).join(" ")).filter(Boolean).join("\n");
|
|
19
|
+
return text ? `\n\n${text}\n\n` : "";
|
|
20
|
+
}
|
|
21
|
+
return renderNative(item);
|
|
22
|
+
}).join("");
|
|
23
|
+
};
|
|
2
24
|
/**
|
|
3
25
|
* 将结构化 Markdown 子元素数组转为可读纯文本
|
|
4
26
|
*/
|
|
5
27
|
const markdownToText = (items, hideUnsupported) => {
|
|
6
28
|
if (Number(hideUnsupported) >= 4) return "";
|
|
7
|
-
return items.map((item) => {
|
|
29
|
+
return joinMarkdownParts(items, items.map((item) => {
|
|
8
30
|
switch (item.type) {
|
|
9
31
|
case "MD.text": return item.value;
|
|
10
32
|
case "MD.title": return hideUnsupported ? `${item.value}\n` : `【${item.value}】\n`;
|
|
@@ -16,6 +38,7 @@ const markdownToText = (items, hideUnsupported) => {
|
|
|
16
38
|
case "MD.link": {
|
|
17
39
|
const v = item.value;
|
|
18
40
|
if (Number(hideUnsupported) >= 3) return "";
|
|
41
|
+
if (!v.url) return v.text;
|
|
19
42
|
return Number(hideUnsupported) >= 2 ? v.url : `${v.text}( ${v.url} )`;
|
|
20
43
|
}
|
|
21
44
|
case "MD.image": return hideUnsupported ? "" : "[图片]";
|
|
@@ -23,7 +46,7 @@ const markdownToText = (items, hideUnsupported) => {
|
|
|
23
46
|
if (typeof li.value === "object") return `${li.value.index}. ${li.value.text ?? ""}`;
|
|
24
47
|
return `· ${li.value}`;
|
|
25
48
|
}).join("\n") + "\n";
|
|
26
|
-
case "MD.blockquote": return
|
|
49
|
+
case "MD.blockquote": return renderMarkdownBlockquote(item.value, (children) => markdownToText(children, hideUnsupported));
|
|
27
50
|
case "MD.divider": return hideUnsupported ? "" : "————————\n";
|
|
28
51
|
case "MD.newline": return "\n";
|
|
29
52
|
case "MD.code": return item.value;
|
|
@@ -37,7 +60,7 @@ const markdownToText = (items, hideUnsupported) => {
|
|
|
37
60
|
return hideUnsupported ? String(item.value) : `[${item.value}]`;
|
|
38
61
|
default: return String(item?.value ?? "");
|
|
39
62
|
}
|
|
40
|
-
})
|
|
63
|
+
}));
|
|
41
64
|
};
|
|
42
65
|
/**
|
|
43
66
|
* 将按钮组转为可读纯文本
|
|
@@ -88,6 +111,47 @@ const dataEnumToText = (item, hideUnsupported) => {
|
|
|
88
111
|
default: return "";
|
|
89
112
|
}
|
|
90
113
|
};
|
|
114
|
+
const mdFormatters = {
|
|
115
|
+
"MD.title": (value) => `# ${value} `,
|
|
116
|
+
"MD.subtitle": (value) => `## ${value} `,
|
|
117
|
+
"MD.text": (value) => `${value} `,
|
|
118
|
+
"MD.bold": (value) => `**${value}** `,
|
|
119
|
+
"MD.divider": () => "\n***\n",
|
|
120
|
+
"MD.italic": (value) => `__${value}__ `,
|
|
121
|
+
"MD.italicStar": (value) => `*${value}* `,
|
|
122
|
+
"MD.strikethrough": (value) => `~~${value}~~ `,
|
|
123
|
+
"MD.blockquote": (value) => renderMarkdownBlockquote(value, createMarkdownText),
|
|
124
|
+
"MD.newline": () => "\n",
|
|
125
|
+
"MD.link": (value) => {
|
|
126
|
+
if (!value?.text && !value?.url) return "";
|
|
127
|
+
if (!value?.text || !value?.url) return `<${value?.url ?? value?.text}> `;
|
|
128
|
+
return `[🔗${value?.text}](${value?.url}) `;
|
|
129
|
+
},
|
|
130
|
+
"MD.image": (value, options) => `\n\n`,
|
|
131
|
+
"MD.mention": (value, options) => {
|
|
132
|
+
const { belong } = options || {};
|
|
133
|
+
if (belong === "channel") return "";
|
|
134
|
+
if (value === "everyone") return "<qqbot-at-everyone />";
|
|
135
|
+
if (belong === "user") return `<qqbot-at-user id="${value}" />`;
|
|
136
|
+
return `<qqbot-at-user id="${value}" />`;
|
|
137
|
+
},
|
|
138
|
+
"MD.content": (value) => `${value}`,
|
|
139
|
+
"MD.button": (title, options) => {
|
|
140
|
+
const { data, autoEnter } = options || {};
|
|
141
|
+
if (autoEnter) return `<qqbot-cmd-enter text="${data}" show="${title}" />`;
|
|
142
|
+
return `<qqbot-cmd-input text="${data}" show="${title}" />`;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const createMarkdownText = (data) => {
|
|
146
|
+
return joinMarkdownParts(data, data.map((mdItem) => {
|
|
147
|
+
if (mdFormatters[mdItem.type]) return mdFormatters[mdItem.type](mdItem?.value, mdItem?.options);
|
|
148
|
+
if (mdItem.type === "MD.list" && typeof mdItem.value !== "string") return `${mdItem.value.map((listItem) => {
|
|
149
|
+
return typeof listItem.value === "object" ? `\n${listItem.value.index}. ${listItem.value.text}` : `\n- ${listItem.value}`;
|
|
150
|
+
}).join("")}\n`;
|
|
151
|
+
if (mdItem.type === "MD.code") return `\n\`\`\`${mdItem?.options?.language || ""}\n${mdItem.value}\n\`\`\`\n`;
|
|
152
|
+
return String(mdItem["value"] || "");
|
|
153
|
+
}));
|
|
154
|
+
};
|
|
91
155
|
|
|
92
156
|
//#endregion
|
|
93
|
-
export { buttonsToText, dataEnumToText, markdownRawToText, markdownToText };
|
|
157
|
+
export { buttonsToText, createMarkdownText, dataEnumToText, formatQQContent, markdownRawToText, markdownToText };
|
package/lib/index.websoket.js
CHANGED
|
@@ -31,7 +31,7 @@ const bootstrap = async () => {
|
|
|
31
31
|
activeRegistry = registry;
|
|
32
32
|
if (!hasConfiguredCredentials()) {
|
|
33
33
|
logger.info("[qq-bot] 未检测到 app_id/secret 配置,进入扫码登录流程");
|
|
34
|
-
const result = await qrLogin({ onQRCode: (qrBuffer, url,
|
|
34
|
+
const result = await qrLogin({ onQRCode: (qrBuffer, url, loginId, refresh) => {
|
|
35
35
|
loginStatus = {
|
|
36
36
|
state: "awaiting_qrcode",
|
|
37
37
|
type: "qrcode",
|
package/lib/sdk/qr-auth.d.ts
CHANGED
|
@@ -35,14 +35,14 @@ type QRLoginOptions = {
|
|
|
35
35
|
pollInterval?: number;
|
|
36
36
|
/** 注入门户请求(测试用) */
|
|
37
37
|
request?: PortalRequest;
|
|
38
|
-
/**
|
|
39
|
-
onQRCode?: (qrBuffer: Buffer, url: string,
|
|
38
|
+
/** 二维码生成回调;图片由回调方或 CBP 统一处理,不在适配器运行目录落盘 */
|
|
39
|
+
onQRCode?: (qrBuffer: Buffer, url: string, loginId: string, refresh: number) => void | Promise<void>;
|
|
40
40
|
/** 状态变化回调 */
|
|
41
41
|
onStatus?: (message: string) => void | Promise<void>;
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
44
|
* 扫码登录流程:
|
|
45
|
-
* 创建绑定任务 →
|
|
45
|
+
* 创建绑定任务 → 生成二维码并通过回调交给 CBP/UI → 轮询授权结果 → 解密 AppSecret。
|
|
46
46
|
* 成功返回 { appId, clientSecret, userOpenid };超时/失败/刷新次数用尽返回 null
|
|
47
47
|
*/
|
|
48
48
|
declare const qrLogin: (options?: QRLoginOptions) => Promise<QRLoginResult | null>;
|
package/lib/sdk/qr-auth.js
CHANGED
|
@@ -2,7 +2,7 @@ import { getConfig, logger } from "alemonjs";
|
|
|
2
2
|
import axios from "axios";
|
|
3
3
|
import { createDecipheriv, randomBytes } from "node:crypto";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { dirname
|
|
5
|
+
import { dirname } from "node:path";
|
|
6
6
|
import QRCode from "qrcode";
|
|
7
7
|
import YAML from "yaml";
|
|
8
8
|
|
|
@@ -51,7 +51,7 @@ const buildConnectUrl = (taskId) => {
|
|
|
51
51
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
52
52
|
/**
|
|
53
53
|
* 扫码登录流程:
|
|
54
|
-
* 创建绑定任务 →
|
|
54
|
+
* 创建绑定任务 → 生成二维码并通过回调交给 CBP/UI → 轮询授权结果 → 解密 AppSecret。
|
|
55
55
|
* 成功返回 { appId, clientSecret, userOpenid };超时/失败/刷新次数用尽返回 null
|
|
56
56
|
*/
|
|
57
57
|
const qrLogin = async (options = {}) => {
|
|
@@ -70,7 +70,6 @@ const qrLogin = async (options = {}) => {
|
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
72
|
const url = buildConnectUrl(taskId);
|
|
73
|
-
let qrImagePath = null;
|
|
74
73
|
let qrBuffer = null;
|
|
75
74
|
try {
|
|
76
75
|
qrBuffer = await QRCode.toBuffer(url, {
|
|
@@ -78,12 +77,10 @@ const qrLogin = async (options = {}) => {
|
|
|
78
77
|
width: 320,
|
|
79
78
|
margin: 2
|
|
80
79
|
});
|
|
81
|
-
qrImagePath = join(process.cwd(), "qqbot-login-qr.png");
|
|
82
|
-
writeFileSync(qrImagePath, qrBuffer);
|
|
83
80
|
} catch (err) {
|
|
84
|
-
logger.warn(`[qq-bot]
|
|
81
|
+
logger.warn(`[qq-bot] 二维码生成失败:${err?.message ?? err}`);
|
|
85
82
|
}
|
|
86
|
-
if (qrBuffer && onQRCode) await onQRCode(qrBuffer, url,
|
|
83
|
+
if (qrBuffer && onQRCode) await onQRCode(qrBuffer, url, taskId, refresh);
|
|
87
84
|
await onStatus?.("请使用手机 QQ 扫描二维码并确认授权");
|
|
88
85
|
logger.warn("[qq-bot] 注意:扫码授权完成后平台将重置机器人密钥,旧密钥会立即失效;若该机器人已在其他实例中运行,请更新其配置");
|
|
89
86
|
while (Date.now() < deadline) {
|
package/lib/sends.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getQQBotConfig } from "./config.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createMarkdownText, dataEnumToText, formatQQContent } from "./format.js";
|
|
3
3
|
import { ResultCode, createResult, logger } from "alemonjs";
|
|
4
4
|
import { readFileSync } from "fs";
|
|
5
5
|
import axios from "axios";
|
|
@@ -172,47 +172,6 @@ const createArkListData = (value) => {
|
|
|
172
172
|
]
|
|
173
173
|
};
|
|
174
174
|
};
|
|
175
|
-
const mdFormatters = {
|
|
176
|
-
"MD.title": (value) => `# ${value} `,
|
|
177
|
-
"MD.subtitle": (value) => `## ${value} `,
|
|
178
|
-
"MD.text": (value) => `${value} `,
|
|
179
|
-
"MD.bold": (value) => `**${value}** `,
|
|
180
|
-
"MD.divider": () => "\n***\n",
|
|
181
|
-
"MD.italic": (value) => `__${value}__ `,
|
|
182
|
-
"MD.italicStar": (value) => `*${value}* `,
|
|
183
|
-
"MD.strikethrough": (value) => `~~${value}~~ `,
|
|
184
|
-
"MD.blockquote": (value) => `\n> ${value} `,
|
|
185
|
-
"MD.newline": () => "\n",
|
|
186
|
-
"MD.link": (value) => {
|
|
187
|
-
if (!value?.text && !value?.url) return "";
|
|
188
|
-
if (!value?.text || !value?.url) return `<${value?.url ?? value?.text}> `;
|
|
189
|
-
return `[🔗${value?.text}](${value?.url}) `;
|
|
190
|
-
},
|
|
191
|
-
"MD.image": (value, options) => `\n\n`,
|
|
192
|
-
"MD.mention": (value, options) => {
|
|
193
|
-
const { belong } = options || {};
|
|
194
|
-
if (belong === "channel") return "";
|
|
195
|
-
if (belong === "user") return `<qqbot-at-user id="${value}" />`;
|
|
196
|
-
if (value === "everyone") return "<qqbot-at-everyone />";
|
|
197
|
-
return `<qqbot-at-user id="${value}" />`;
|
|
198
|
-
},
|
|
199
|
-
"MD.content": (value) => `${value}`,
|
|
200
|
-
"MD.button": (title, options) => {
|
|
201
|
-
const { data, autoEnter } = options || {};
|
|
202
|
-
if (autoEnter) return `<qqbot-cmd-enter text="${data}" show="${title}" />`;
|
|
203
|
-
return `<qqbot-cmd-input text="${data}" show="${title}" />`;
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
const createMarkdownText = (data) => {
|
|
207
|
-
return data.map((mdItem) => {
|
|
208
|
-
if (mdFormatters[mdItem.type]) return mdFormatters[mdItem.type](mdItem?.value, mdItem?.options);
|
|
209
|
-
if (mdItem.type === "MD.list" && typeof mdItem.value !== "string") return `${mdItem.value.map((listItem) => {
|
|
210
|
-
return typeof listItem.value === "object" ? `\n${listItem.value.index}. ${listItem.value.text}` : `\n- ${listItem.value}`;
|
|
211
|
-
}).join("")}\n`;
|
|
212
|
-
if (mdItem.type === "MD.code") return `\n\`\`\`${mdItem?.options?.language || ""}\n${mdItem.value}\n\`\`\`\n`;
|
|
213
|
-
return String(mdItem["value"] || "");
|
|
214
|
-
}).join("");
|
|
215
|
-
};
|
|
216
175
|
const formatMention = (item, mode) => {
|
|
217
176
|
if (mode === "guild-direct") return "";
|
|
218
177
|
const value = item.value;
|
|
@@ -373,16 +332,7 @@ const resolveMediaUrl = async (media, uploadMedia) => {
|
|
|
373
332
|
}
|
|
374
333
|
};
|
|
375
334
|
/** 移除富媒体占位符(dataEnumToText 降级产生的 [视频]/[音频]/[附件]) */
|
|
376
|
-
const stripMediaPlaceholders = (text) => text.replace(/\[附件[^\]]*\]/g, "").replace(/\[音频\]/g, "").replace(/\[视频\]/g, "").
|
|
377
|
-
/** 当 markdownToText 选项开启时,将 Markdown 和按钮降级为纯文本并追加到 content */
|
|
378
|
-
const flattenMdToText = (content, val) => {
|
|
379
|
-
const mdItems = val.filter((item) => item.type === "Markdown");
|
|
380
|
-
const btnItems = val.filter((item) => item.type === "BT.group");
|
|
381
|
-
const parts = [content];
|
|
382
|
-
for (const item of mdItems) if (item.type === "Markdown" && typeof item.value !== "string") parts.push(markdownToText(item.value));
|
|
383
|
-
for (const item of btnItems) if (item.type === "BT.group" && typeof item.value !== "string") parts.push(buttonsToText(item.value));
|
|
384
|
-
return parts.filter(Boolean).join("\n").replace(/^[^\S\n\r]+|[^\S\n\r]+$/g, "");
|
|
385
|
-
};
|
|
335
|
+
const stripMediaPlaceholders = (text) => text.replace(/\[附件[^\]]*\]/g, "").replace(/\[音频\]/g, "").replace(/\[视频\]/g, "").trim();
|
|
386
336
|
/** Open API 通用发送逻辑(群组 / C2C) */
|
|
387
337
|
const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMessage, label, options) => {
|
|
388
338
|
const config = getQQBotConfig();
|
|
@@ -392,7 +342,7 @@ const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMes
|
|
|
392
342
|
const fileInfo = await resolveMediaUrl(media, uploadMedia);
|
|
393
343
|
if (!fileInfo) return [createResult(ResultCode.Fail, "媒体上传失败", null)];
|
|
394
344
|
const res = await sendMessage({
|
|
395
|
-
content: stripMediaPlaceholders(
|
|
345
|
+
content: stripMediaPlaceholders(formatQQContent(val, (item) => extractContent([item], "group"), true, config.hideUnsupported)),
|
|
396
346
|
media: { file_info: fileInfo },
|
|
397
347
|
msg_type: 7,
|
|
398
348
|
...baseParams
|
|
@@ -404,7 +354,7 @@ const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMes
|
|
|
404
354
|
return [];
|
|
405
355
|
}
|
|
406
356
|
if (mdToText) {
|
|
407
|
-
const textContent =
|
|
357
|
+
const textContent = formatQQContent(val, (item) => extractContent([item], "group"), true, config.hideUnsupported);
|
|
408
358
|
if (textContent) {
|
|
409
359
|
const res = await sendMessage({
|
|
410
360
|
content: textContent,
|
|
@@ -417,7 +367,7 @@ const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMes
|
|
|
417
367
|
}
|
|
418
368
|
const mdParams = buildMdAndButtonsParams(val);
|
|
419
369
|
if (mdParams) {
|
|
420
|
-
if (mdParams.markdown?.content
|
|
370
|
+
if (mdParams.markdown?.content) mdParams.markdown.content = formatQQContent(val, (item) => extractContent([item], "group"));
|
|
421
371
|
const res = await sendMessage({
|
|
422
372
|
content,
|
|
423
373
|
msg_type: 2,
|
|
@@ -463,14 +413,14 @@ const resolveImageBuffer = async (images) => {
|
|
|
463
413
|
return null;
|
|
464
414
|
};
|
|
465
415
|
/** Guild API 通用发送逻辑(频道公聊 / 频道私聊) */
|
|
466
|
-
const sendGuildMessage = async (content, val, baseParams, sendMessage, label) => {
|
|
416
|
+
const sendGuildMessage = async (content, val, baseParams, sendMessage, label, mode) => {
|
|
467
417
|
const config = getQQBotConfig();
|
|
468
418
|
const mdToText = config.markdownToText === true;
|
|
469
419
|
const images = filterImages(val);
|
|
470
420
|
if (images.length > 0) {
|
|
471
421
|
const imageBuffer = await resolveImageBuffer(images);
|
|
472
422
|
const res = await sendMessage({
|
|
473
|
-
content:
|
|
423
|
+
content: formatQQContent(val, (item) => extractContent([item], mode), true, config.hideUnsupported),
|
|
474
424
|
...baseParams
|
|
475
425
|
}, imageBuffer);
|
|
476
426
|
return [createResult(ResultCode.Ok, label, { id: res?.id })];
|
|
@@ -480,7 +430,7 @@ const sendGuildMessage = async (content, val, baseParams, sendMessage, label) =>
|
|
|
480
430
|
return [];
|
|
481
431
|
}
|
|
482
432
|
if (mdToText) {
|
|
483
|
-
const textContent =
|
|
433
|
+
const textContent = formatQQContent(val, (item) => extractContent([item], mode), true, config.hideUnsupported);
|
|
484
434
|
if (textContent) {
|
|
485
435
|
const res = await sendMessage({
|
|
486
436
|
content: textContent,
|
|
@@ -492,7 +442,7 @@ const sendGuildMessage = async (content, val, baseParams, sendMessage, label) =>
|
|
|
492
442
|
}
|
|
493
443
|
const mdParams = buildMdAndButtonsParams(val);
|
|
494
444
|
if (mdParams) {
|
|
495
|
-
if (mdParams.markdown?.content
|
|
445
|
+
if (mdParams.markdown?.content) mdParams.markdown.content = formatQQContent(val, (item) => extractContent([item], mode));
|
|
496
446
|
const res = await sendMessage({
|
|
497
447
|
content: "",
|
|
498
448
|
...mdParams,
|
|
@@ -549,7 +499,7 @@ const DIRECT_MESSAGE_CREATE = async (client, event, val) => {
|
|
|
549
499
|
const baseParams = buildBaseParams(event._tag, event.MessageId, "INTERACTION_CREATE_GUILD");
|
|
550
500
|
const content = extractContent(val, "guild-direct");
|
|
551
501
|
try {
|
|
552
|
-
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.dmsMessages(event.UserId, data, buf), "client.dmsMessage");
|
|
502
|
+
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.dmsMessages(event.UserId, data, buf), "client.dmsMessage", "guild-direct");
|
|
553
503
|
} catch (err) {
|
|
554
504
|
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
555
505
|
}
|
|
@@ -561,7 +511,7 @@ const MESSAGE_CREATE = async (client, event, val) => {
|
|
|
561
511
|
const baseParams = buildBaseParams(event._tag, event.MessageId, "INTERACTION_CREATE_GUILD");
|
|
562
512
|
const content = extractContent(val, "guild-public");
|
|
563
513
|
try {
|
|
564
|
-
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.channelsMessages(event.ChannelId, data, buf), "client.channelsMessagesPost");
|
|
514
|
+
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.channelsMessages(event.ChannelId, data, buf), "client.channelsMessagesPost", "guild-public");
|
|
565
515
|
} catch (err) {
|
|
566
516
|
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
567
517
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alemonjs/qq-bot",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.36",
|
|
4
4
|
"description": "QQ官方平台",
|
|
5
5
|
"author": "lemonade",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"yaml": "^2.5.1"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"alemonjs": "^2.1.
|
|
33
|
+
"alemonjs": "^2.1.108"
|
|
34
34
|
},
|
|
35
35
|
"types": "lib",
|
|
36
36
|
"exports": {
|
|
@@ -97,5 +97,5 @@
|
|
|
97
97
|
"type": "git",
|
|
98
98
|
"url": "https://github.com/lemonade-lab/alemonjs.git"
|
|
99
99
|
},
|
|
100
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "a4d4fded0874b070e356e6a83b06bd3e474f9133"
|
|
101
101
|
}
|