@alemonjs/qq-bot 2.1.32 → 2.1.34
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 +1984 -35
- package/dist/assets/index.css +1 -1
- package/dist/assets/index.js +12 -5
- package/dist/index.html +1 -1
- package/lib/config.d.ts +44 -19
- package/lib/config.js +39 -35
- package/lib/desktop.d.ts +4 -1
- package/lib/desktop.js +53 -57
- package/lib/format.d.ts +26 -5
- package/lib/format.js +84 -101
- package/lib/hook.d.ts +82 -64
- package/lib/hook.js +35 -32
- package/lib/index.d.ts +6 -4
- package/lib/index.js +13 -16
- package/lib/index.webhook.d.ts +4 -1
- package/lib/index.webhook.js +12 -14
- package/lib/index.websoket.d.ts +6 -3
- package/lib/index.websoket.js +131 -41
- package/lib/message/AT_MESSAGE_CREATE.d.ts +36 -33
- package/lib/message/AT_MESSAGE_CREATE.js +1 -1
- package/lib/message/CHANNEL_CREATE.d.ts +17 -14
- package/lib/message/CHANNEL_CREATE.js +1 -1
- package/lib/message/CHANNEL_DELETE.d.ts +22 -14
- package/lib/message/CHANNEL_DELETE.js +1 -1
- package/lib/message/CHANNEL_UPDATE.d.ts +22 -14
- package/lib/message/CHANNEL_UPDATE.js +1 -1
- package/lib/message/DIRECT_MESSAGE_CREATE.d.ts +35 -27
- package/lib/message/DIRECT_MESSAGE_CREATE.js +1 -1
- package/lib/message/DIRECT_MESSAGE_DELETE.d.ts +23 -15
- package/lib/message/DIRECT_MESSAGE_DELETE.js +1 -1
- package/lib/message/ERROR.d.ts +4 -1
- package/lib/message/ERROR.js +1 -1
- package/lib/message/GUILD_CREATE.d.ts +22 -14
- package/lib/message/GUILD_CREATE.js +1 -1
- package/lib/message/GUILD_DELETE.d.ts +22 -14
- package/lib/message/GUILD_DELETE.js +1 -1
- package/lib/message/GUILD_MEMBER_ADD.d.ts +21 -13
- package/lib/message/GUILD_MEMBER_ADD.js +1 -1
- package/lib/message/GUILD_MEMBER_REMOVE.d.ts +21 -13
- package/lib/message/GUILD_MEMBER_REMOVE.js +1 -1
- package/lib/message/GUILD_MEMBER_UPDATE.d.ts +21 -13
- package/lib/message/GUILD_MEMBER_UPDATE.js +1 -1
- package/lib/message/GUILD_UPDATE.d.ts +22 -14
- package/lib/message/GUILD_UPDATE.js +1 -1
- package/lib/message/INTERACTION_CREATE.d.ts +52 -44
- package/lib/message/INTERACTION_CREATE.js +1 -1
- package/lib/message/MESSAGE_CREATE.d.ts +12 -1
- package/lib/message/MESSAGE_CREATE.js +1 -1
- package/lib/message/MESSAGE_DELETE.d.ts +12 -1
- package/lib/message/MESSAGE_DELETE.js +1 -1
- package/lib/message/MESSAGE_REACTION_ADD.d.ts +15 -12
- package/lib/message/MESSAGE_REACTION_ADD.js +1 -1
- package/lib/message/MESSAGE_REACTION_REMOVE.d.ts +15 -12
- package/lib/message/MESSAGE_REACTION_REMOVE.js +1 -1
- package/lib/message/PUBLIC_MESSAGE_DELETE.d.ts +20 -13
- package/lib/message/PUBLIC_MESSAGE_DELETE.js +1 -1
- package/lib/message/READY.d.ts +11 -5
- package/lib/message/READY.js +1 -1
- package/lib/message/group/C2C_MESSAGE_CREATE.d.ts +18 -15
- package/lib/message/group/C2C_MESSAGE_CREATE.js +1 -1
- package/lib/message/group/C2C_MSG_RECEIVE.d.ts +13 -3
- package/lib/message/group/C2C_MSG_RECEIVE.js +1 -1
- package/lib/message/group/C2C_MSG_REJECT.d.ts +9 -3
- package/lib/message/group/C2C_MSG_REJECT.js +1 -1
- package/lib/message/group/FRIEND_ADD.d.ts +13 -3
- package/lib/message/group/FRIEND_ADD.js +1 -1
- package/lib/message/group/FRIEND_DEL.d.ts +9 -3
- package/lib/message/group/FRIEND_DEL.js +1 -1
- package/lib/message/group/GROUP_ADD_ROBOT.d.ts +23 -4
- package/lib/message/group/GROUP_ADD_ROBOT.js +1 -1
- package/lib/message/group/GROUP_AT_MESSAGE_CREATE.d.ts +38 -32
- package/lib/message/group/GROUP_AT_MESSAGE_CREATE.js +1 -1
- package/lib/message/group/GROUP_DEL_ROBOT.d.ts +19 -4
- package/lib/message/group/GROUP_DEL_ROBOT.js +1 -1
- package/lib/message/group/GROUP_JOIN_REQUEST.d.ts +84 -0
- package/lib/message/group/GROUP_JOIN_REQUEST.js +1 -0
- package/lib/message/group/GROUP_MEMBER_ADD.d.ts +8 -5
- package/lib/message/group/GROUP_MEMBER_ADD.js +1 -1
- package/lib/message/group/GROUP_MEMBER_REMOVE.d.ts +8 -5
- package/lib/message/group/GROUP_MEMBER_REMOVE.js +1 -1
- package/lib/message/group/GROUP_MESSAGE_CREATE.d.ts +38 -32
- package/lib/message/group/GROUP_MESSAGE_CREATE.js +1 -1
- package/lib/message/group/GROUP_MSG_RECEIVE.d.ts +14 -4
- package/lib/message/group/GROUP_MSG_RECEIVE.js +1 -1
- package/lib/message/group/GROUP_MSG_REJECT.d.ts +10 -4
- package/lib/message/group/GROUP_MSG_REJECT.js +1 -1
- package/lib/message/group/MESSAGE_AUDIT_PASS.d.ts +12 -6
- package/lib/message/group/MESSAGE_AUDIT_PASS.js +1 -1
- package/lib/message/group/MESSAGE_AUDIT_REJECT.d.ts +12 -6
- package/lib/message/group/MESSAGE_AUDIT_REJECT.js +1 -1
- package/lib/register.d.ts +12 -9
- package/lib/register.js +1246 -1200
- package/lib/sdk/api.d.ts +937 -251
- package/lib/sdk/api.js +1481 -758
- package/lib/sdk/client.webhook.d.ts +25 -8
- package/lib/sdk/client.webhook.js +185 -189
- package/lib/sdk/client.websoket.d.ts +31 -9
- package/lib/sdk/client.websoket.js +369 -392
- package/lib/sdk/config.d.ts +6 -2
- package/lib/sdk/config.js +9 -6
- package/lib/sdk/instance.d.ts +11 -3
- package/lib/sdk/instance.js +73 -83
- package/lib/sdk/intents.d.ts +89 -3
- package/lib/sdk/intents.js +116 -31
- package/lib/sdk/message.d.ts +7 -4
- package/lib/sdk/message.group.d.ts +38 -33
- package/lib/sdk/message.group.js +1 -1
- package/lib/sdk/message.guild.d.ts +40 -37
- package/lib/sdk/message.guild.js +1 -1
- package/lib/sdk/message.js +1 -1
- package/lib/sdk/message.public.d.ts +8 -5
- package/lib/sdk/message.public.js +1 -1
- package/lib/sdk/qr-auth.d.ts +55 -0
- package/lib/sdk/qr-auth.js +169 -0
- package/lib/sdk/registry.d.ts +34 -24
- package/lib/sdk/registry.js +134 -114
- package/lib/sdk/session.d.ts +19 -15
- package/lib/sdk/session.js +51 -54
- package/lib/sdk/typing.d.ts +416 -68
- package/lib/sdk/typing.js +1 -1
- package/lib/sdk/webhook.secret.d.ts +33 -13
- package/lib/sdk/webhook.secret.js +50 -36
- package/lib/sends.d.ts +46 -25
- package/lib/sends.js +533 -497
- package/lib/types.d.ts +52 -41
- package/lib/types.js +1 -1
- package/lib/upload.d.ts +50 -0
- package/lib/upload.js +89 -0
- package/lib/utils.d.ts +9 -1
- package/lib/utils.js +10 -5
- package/package.json +11 -8
package/lib/sends.js
CHANGED
|
@@ -1,541 +1,577 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
1
|
+
import { getQQBotConfig } from "./config.js";
|
|
2
|
+
import { buttonsToText, dataEnumToText, markdownToText } from "./format.js";
|
|
3
|
+
import { ResultCode, createResult, logger } from "alemonjs";
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
import axios from "axios";
|
|
6
6
|
|
|
7
|
+
//#region src/sends.ts
|
|
8
|
+
/** QQ Bot 平台按钮限制:最多 5 行,每行最多 5 个按钮 */
|
|
7
9
|
const MAX_BUTTON_ROWS = 5;
|
|
8
10
|
const MAX_BUTTONS_PER_ROW = 5;
|
|
11
|
+
/**
|
|
12
|
+
* QQ-Bot 按钮样式(render_data.style):
|
|
13
|
+
* 0 灰色线框 / 1 蓝色线框 / 3 红框 / 4 蓝底白字
|
|
14
|
+
*/
|
|
15
|
+
const BUTTON_STYLE_MAP = {
|
|
16
|
+
gray: 0,
|
|
17
|
+
blue: 1,
|
|
18
|
+
red: 3,
|
|
19
|
+
"blue-fill": 4
|
|
20
|
+
};
|
|
21
|
+
/** 解析按钮样式:支持样式名与数字(含数字字符串),默认灰框 0 */
|
|
22
|
+
const resolveButtonStyle = (style) => {
|
|
23
|
+
if (typeof style === "number") return style;
|
|
24
|
+
if (typeof style === "string") {
|
|
25
|
+
if (BUTTON_STYLE_MAP[style] !== void 0) return BUTTON_STYLE_MAP[style];
|
|
26
|
+
if (style.trim() !== "" && !Number.isNaN(Number(style))) return Number(style);
|
|
27
|
+
}
|
|
28
|
+
return 0;
|
|
29
|
+
};
|
|
9
30
|
const createButtonsData = (rows, startId = 0) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
let id = startId;
|
|
32
|
+
return {
|
|
33
|
+
rows: rows.slice(0, MAX_BUTTON_ROWS).map((row) => ({ buttons: row.value.slice(0, MAX_BUTTONS_PER_ROW).map((button) => {
|
|
34
|
+
const value = button.value;
|
|
35
|
+
const options = button.options;
|
|
36
|
+
id++;
|
|
37
|
+
const typing = options?.type ?? "command";
|
|
38
|
+
const typeMap = {
|
|
39
|
+
command: 2,
|
|
40
|
+
link: 0,
|
|
41
|
+
call: 1
|
|
42
|
+
};
|
|
43
|
+
const rowData = options?.rawData ?? {};
|
|
44
|
+
const data = options?.data;
|
|
45
|
+
const modal = options?.modal ?? (typeof data === "object" && data ? {
|
|
46
|
+
content: data.click,
|
|
47
|
+
confirmText: data.confirm,
|
|
48
|
+
cancelText: data.cancel
|
|
49
|
+
} : void 0);
|
|
50
|
+
const action = {
|
|
51
|
+
type: typeMap[typing],
|
|
52
|
+
permission: {
|
|
53
|
+
type: typeof options.permission?.type === "undefined" ? 2 : options?.permission?.type,
|
|
54
|
+
specify_user_ids: options?.permission?.userIds,
|
|
55
|
+
specify_role_ids: options?.permission?.roleIds
|
|
56
|
+
},
|
|
57
|
+
unsupport_tips: options?.toolTip ?? "",
|
|
58
|
+
data: typeof data === "string" ? data : "",
|
|
59
|
+
at_bot_show_channel_list: options?.atBotShowChannelList ?? false,
|
|
60
|
+
enter: options?.autoEnter ?? false,
|
|
61
|
+
reply: options?.reply ?? false,
|
|
62
|
+
anchor: options?.anchor ?? 0,
|
|
63
|
+
click_limit: options?.clickLimit
|
|
64
|
+
};
|
|
65
|
+
if (modal) action.modal = {
|
|
66
|
+
content: modal.content ?? "是否确认操作?",
|
|
67
|
+
confirm_text: modal.confirmText ?? "是",
|
|
68
|
+
cancel_text: modal.cancelText ?? "否"
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
id: String(id),
|
|
72
|
+
render_data: {
|
|
73
|
+
label: value,
|
|
74
|
+
visited_label: value,
|
|
75
|
+
style: resolveButtonStyle(options?.style)
|
|
76
|
+
},
|
|
77
|
+
action,
|
|
78
|
+
...rowData
|
|
79
|
+
};
|
|
80
|
+
}) })),
|
|
81
|
+
nextId: id
|
|
82
|
+
};
|
|
46
83
|
};
|
|
47
84
|
const createArkCardData = (value) => ({
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
85
|
+
template_id: 24,
|
|
86
|
+
kv: [
|
|
87
|
+
{
|
|
88
|
+
key: "#DESC#",
|
|
89
|
+
value: value.decs
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
key: "#PROMPT#",
|
|
93
|
+
value: value.prompt
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
key: "#TITLE#",
|
|
97
|
+
value: value.title
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
key: "#METADESC#",
|
|
101
|
+
value: value.metadecs
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
key: "#IMG#",
|
|
105
|
+
value: value.cover
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
key: "#LINK#",
|
|
109
|
+
value: value.link
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
key: "#SUBTITLE#",
|
|
113
|
+
value: value.subtitle
|
|
114
|
+
}
|
|
115
|
+
]
|
|
58
116
|
});
|
|
59
117
|
const createArkBigCardData = (value) => ({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
118
|
+
template_id: 37,
|
|
119
|
+
kv: [
|
|
120
|
+
{
|
|
121
|
+
key: "#PROMPT#",
|
|
122
|
+
value: value.prompt
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
key: "#METATITLE#",
|
|
126
|
+
value: value.title
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
key: "#METASUBTITLE#",
|
|
130
|
+
value: value.subtitle
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
key: "#METACOVER#",
|
|
134
|
+
value: value.cover
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
key: "#METAURL#",
|
|
138
|
+
value: value.link
|
|
139
|
+
}
|
|
140
|
+
]
|
|
68
141
|
});
|
|
69
142
|
const createArkListData = (value) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
143
|
+
const [tip, data] = value;
|
|
144
|
+
return {
|
|
145
|
+
template_id: 23,
|
|
146
|
+
kv: [
|
|
147
|
+
{
|
|
148
|
+
key: "#DESC#",
|
|
149
|
+
value: tip.value.desc
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
key: "#PROMPT#",
|
|
153
|
+
value: tip.value.prompt
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
key: "#LIST#",
|
|
157
|
+
obj: data.value.map((item) => {
|
|
158
|
+
const v = item.value;
|
|
159
|
+
if (typeof v === "string") return { obj_kv: [{
|
|
160
|
+
key: "desc",
|
|
161
|
+
value: v
|
|
162
|
+
}] };
|
|
163
|
+
return { obj_kv: [{
|
|
164
|
+
key: "desc",
|
|
165
|
+
value: v.title
|
|
166
|
+
}, {
|
|
167
|
+
key: "link",
|
|
168
|
+
value: v.link
|
|
169
|
+
}] };
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
};
|
|
93
174
|
};
|
|
94
175
|
const mdFormatters = {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return '<qqbot-at-everyone />';
|
|
125
|
-
}
|
|
126
|
-
return `<qqbot-at-user id="${value}" />`;
|
|
127
|
-
},
|
|
128
|
-
'MD.content': value => `${value}`,
|
|
129
|
-
'MD.button': (title, options) => {
|
|
130
|
-
const { data, autoEnter } = options || {};
|
|
131
|
-
if (autoEnter) {
|
|
132
|
-
return `<qqbot-cmd-enter text="${data}" show="${title}" />`;
|
|
133
|
-
}
|
|
134
|
-
return `<qqbot-cmd-input text="${data}" show="${title}" />`;
|
|
135
|
-
}
|
|
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
|
+
}
|
|
136
205
|
};
|
|
137
206
|
const createMarkdownText = (data) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
});
|
|
147
|
-
return `${listStr.join('')}\n`;
|
|
148
|
-
}
|
|
149
|
-
if (mdItem.type === 'MD.code') {
|
|
150
|
-
const language = mdItem?.options?.language || '';
|
|
151
|
-
return `\n\`\`\`${language}\n${mdItem.value}\n\`\`\`\n`;
|
|
152
|
-
}
|
|
153
|
-
return String(mdItem['value'] || '');
|
|
154
|
-
})
|
|
155
|
-
.join('');
|
|
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("");
|
|
156
215
|
};
|
|
157
216
|
const formatMention = (item, mode) => {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (item.options?.belong === 'channel') {
|
|
171
|
-
return `<#${value}>`;
|
|
172
|
-
}
|
|
173
|
-
return '';
|
|
174
|
-
}
|
|
175
|
-
if (isEmptyMention) {
|
|
176
|
-
return '';
|
|
177
|
-
}
|
|
178
|
-
if (item.options?.belong === 'user') {
|
|
179
|
-
return `<@${value}>`;
|
|
180
|
-
}
|
|
181
|
-
return '';
|
|
217
|
+
if (mode === "guild-direct") return "";
|
|
218
|
+
const value = item.value;
|
|
219
|
+
const isEmptyMention = value === "everyone" || value === "all" || value === "" || typeof value !== "string";
|
|
220
|
+
if (mode === "guild-public") {
|
|
221
|
+
if (isEmptyMention) return "@everyone";
|
|
222
|
+
if (item.options?.belong === "user") return `<@!${value}>`;
|
|
223
|
+
if (item.options?.belong === "channel") return `<#${value}>`;
|
|
224
|
+
return "";
|
|
225
|
+
}
|
|
226
|
+
if (isEmptyMention) return "";
|
|
227
|
+
if (item.options?.belong === "user") return `<@${value}>`;
|
|
228
|
+
return "";
|
|
182
229
|
};
|
|
230
|
+
/** 从消息数据中提取文本内容 */
|
|
183
231
|
const extractContent = (val, mode) => {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
if (item.type === 'Text') {
|
|
212
|
-
return item.value;
|
|
213
|
-
}
|
|
214
|
-
return '';
|
|
215
|
-
})
|
|
216
|
-
.join('');
|
|
217
|
-
const config = getQQBotConfig();
|
|
218
|
-
const hide = config.hideUnsupported;
|
|
219
|
-
const fallbackText = val
|
|
220
|
-
.filter(item => !nativeTypes.has(item.type))
|
|
221
|
-
.map(item => dataEnumToText(item, hide))
|
|
222
|
-
.filter(Boolean)
|
|
223
|
-
.join('\n');
|
|
224
|
-
return [nativeText, fallbackText].filter(Boolean).join('\n');
|
|
232
|
+
const nativeTypes = /* @__PURE__ */ new Set([
|
|
233
|
+
"Mention",
|
|
234
|
+
"Text",
|
|
235
|
+
"Link",
|
|
236
|
+
"Image",
|
|
237
|
+
"ImageFile",
|
|
238
|
+
"ImageURL",
|
|
239
|
+
"Audio",
|
|
240
|
+
"Video",
|
|
241
|
+
"Attachment",
|
|
242
|
+
"Markdown",
|
|
243
|
+
"MarkdownOriginal",
|
|
244
|
+
"BT.group",
|
|
245
|
+
"ButtonTemplate",
|
|
246
|
+
"Ark.list",
|
|
247
|
+
"Ark.Card",
|
|
248
|
+
"Ark.BigCard"
|
|
249
|
+
]);
|
|
250
|
+
const nativeText = val.filter((item) => item.type === "Mention" || item.type === "Text" || item.type === "Link").map((item) => {
|
|
251
|
+
if (item.type === "Link") return `[${item.value}](${item?.options?.link})`;
|
|
252
|
+
if (item.type === "Mention") return formatMention(item, mode);
|
|
253
|
+
if (item.type === "Text") return item.value;
|
|
254
|
+
return "";
|
|
255
|
+
}).join("");
|
|
256
|
+
const hide = getQQBotConfig().hideUnsupported;
|
|
257
|
+
return [nativeText, val.filter((item) => !nativeTypes.has(item.type)).map((item) => dataEnumToText(item, hide)).filter(Boolean).join("\n")].filter(Boolean).join("\n");
|
|
225
258
|
};
|
|
259
|
+
/**
|
|
260
|
+
* notice 事件中平台支持以 event_id 被动回复的 tag
|
|
261
|
+
* (群聊:GROUP_ADD_ROBOT / GROUP_MSG_RECEIVE;单聊:C2C_MSG_RECEIVE / FRIEND_ADD)
|
|
262
|
+
*/
|
|
263
|
+
const NOTICE_EVENT_REPLY_TAGS = /* @__PURE__ */ new Set([
|
|
264
|
+
"GROUP_ADD_ROBOT",
|
|
265
|
+
"GROUP_MSG_RECEIVE",
|
|
266
|
+
"C2C_MSG_RECEIVE",
|
|
267
|
+
"FRIEND_ADD"
|
|
268
|
+
]);
|
|
269
|
+
/** 构建 baseParams(event_id 或 msg_id) */
|
|
226
270
|
const buildBaseParams = (tag, messageId, interactionTag) => {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
return { msg_id: messageId };
|
|
271
|
+
if (tag && NOTICE_EVENT_REPLY_TAGS.has(tag) || tag === interactionTag) return { event_id: messageId };
|
|
272
|
+
return { msg_id: messageId };
|
|
231
273
|
};
|
|
274
|
+
/** 构建 Markdown 和按钮参数 */
|
|
232
275
|
const buildMdAndButtonsParams = (val) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
else if (item.type === 'MarkdownOriginal' && typeof item?.value === 'string') {
|
|
272
|
-
if (params['markdown']?.content) {
|
|
273
|
-
params['markdown'].content += '\n' + item.value;
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
params['markdown'] = { content: item.value };
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
if (params['keyboard']?.content?.nextId !== undefined) {
|
|
281
|
-
delete params['keyboard'].content.nextId;
|
|
282
|
-
}
|
|
283
|
-
return params;
|
|
276
|
+
const items = val.filter((item) => item.type === "Markdown" || item.type === "MarkdownOriginal" || item.type === "BT.group" || item.type === "ButtonTemplate");
|
|
277
|
+
if (items.length === 0) return null;
|
|
278
|
+
const params = {};
|
|
279
|
+
let keyboardExtra;
|
|
280
|
+
for (const item of items) if (item.type === "ButtonTemplate") {
|
|
281
|
+
if (item?.value) params["keyboard"] = { id: item.value };
|
|
282
|
+
} else if (item.type === "BT.group" && typeof item?.value !== "string") {
|
|
283
|
+
const groupOptions = item?.options ?? {};
|
|
284
|
+
if (groupOptions.smallButton || groupOptions.rawData) keyboardExtra = {
|
|
285
|
+
smallButton: keyboardExtra?.smallButton || groupOptions.smallButton,
|
|
286
|
+
rawData: groupOptions.rawData
|
|
287
|
+
};
|
|
288
|
+
if (params["keyboard"]?.content?.rows) {
|
|
289
|
+
const existingRows = params["keyboard"].content.rows;
|
|
290
|
+
const currentId = params["keyboard"].content.nextId ?? existingRows.length;
|
|
291
|
+
const remaining = MAX_BUTTON_ROWS - existingRows.length;
|
|
292
|
+
if (remaining > 0) {
|
|
293
|
+
const { rows: newRows, nextId } = createButtonsData(item.value.slice(0, remaining), currentId);
|
|
294
|
+
existingRows.push(...newRows);
|
|
295
|
+
params["keyboard"].content.nextId = nextId;
|
|
296
|
+
}
|
|
297
|
+
} else params["keyboard"] = { content: createButtonsData(item.value) };
|
|
298
|
+
} else if (item.type === "Markdown" && typeof item?.value !== "string") {
|
|
299
|
+
const content = createMarkdownText(item.value);
|
|
300
|
+
if (content) {
|
|
301
|
+
if (params["markdown"]?.content) params["markdown"].content += content;
|
|
302
|
+
else params["markdown"] = { content };
|
|
303
|
+
}
|
|
304
|
+
} else if (item.type === "MarkdownOriginal" && typeof item?.value === "string") {
|
|
305
|
+
if (params["markdown"]?.content) params["markdown"].content += "\n" + item.value;
|
|
306
|
+
else params["markdown"] = { content: item.value };
|
|
307
|
+
}
|
|
308
|
+
if (keyboardExtra && params["keyboard"]?.content) {
|
|
309
|
+
if (keyboardExtra.smallButton) params["keyboard"].content.style = { font_size: "small" };
|
|
310
|
+
if (keyboardExtra.rawData) Object.assign(params["keyboard"].content, keyboardExtra.rawData);
|
|
311
|
+
}
|
|
312
|
+
if (params["keyboard"]?.content?.nextId !== void 0) delete params["keyboard"].content.nextId;
|
|
313
|
+
return params;
|
|
284
314
|
};
|
|
315
|
+
/** 构建 Ark 参数 */
|
|
285
316
|
const buildArkParams = (val) => {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
317
|
+
const items = val.filter((item) => item.type === "Ark.BigCard" || item.type === "Ark.Card" || item.type === "Ark.list");
|
|
318
|
+
if (items.length === 0) return null;
|
|
319
|
+
const params = {};
|
|
320
|
+
for (const item of items) if (item.type === "Ark.Card" && typeof item?.value !== "string") params["ark"] = createArkCardData(item.value);
|
|
321
|
+
else if (item.type === "Ark.BigCard" && typeof item?.value !== "string") params["ark"] = createArkBigCardData(item.value);
|
|
322
|
+
else if (item.type === "Ark.list" && typeof item?.value !== "string") params["ark"] = createArkListData(item.value);
|
|
323
|
+
return params;
|
|
324
|
+
};
|
|
325
|
+
/**
|
|
326
|
+
* 富媒体类型 → QQ file_type 映射
|
|
327
|
+
* 1 图片 / 2 视频 / 3 语音 / 4 文件
|
|
328
|
+
*/
|
|
329
|
+
const MEDIA_FILE_TYPE = {
|
|
330
|
+
Image: 1,
|
|
331
|
+
ImageFile: 1,
|
|
332
|
+
ImageURL: 1,
|
|
333
|
+
Video: 2,
|
|
334
|
+
Audio: 3,
|
|
335
|
+
Attachment: 4
|
|
303
336
|
};
|
|
337
|
+
/** 过滤富媒体数据(图片/视频/音频/文件) */
|
|
338
|
+
const filterMedia = (val) => {
|
|
339
|
+
return val.filter((item) => MEDIA_FILE_TYPE[item.type] !== void 0);
|
|
340
|
+
};
|
|
341
|
+
/** 过滤图片数据(仅图片,频道路径使用) */
|
|
304
342
|
const filterImages = (val) => {
|
|
305
|
-
|
|
343
|
+
return val.filter((item) => item.type === "Image" || item.type === "ImageFile" || item.type === "ImageURL");
|
|
344
|
+
};
|
|
345
|
+
/** 将媒体数据解析为 base64(支持 URL / file:// / base64:// / buffer:// / Buffer / 裸 base64) */
|
|
346
|
+
const resolveFileData = async (item) => {
|
|
347
|
+
if (item.type === "ImageURL") return await axios.get(item.value, { responseType: "arraybuffer" }).then((res) => Buffer.from(res.data, "binary").toString("base64"));
|
|
348
|
+
if (item.type === "ImageFile") return readFileSync(item.value, "base64");
|
|
349
|
+
const value = item.value;
|
|
350
|
+
if (typeof value === "string") {
|
|
351
|
+
if (value.startsWith("https://") || value.startsWith("http://")) return await axios.get(value, { responseType: "arraybuffer" }).then((res) => Buffer.from(res.data, "binary").toString("base64"));
|
|
352
|
+
if (value.startsWith("buffer://")) return value.replace("buffer://", "");
|
|
353
|
+
if (value.startsWith("file://")) return readFileSync(value.replace("file://", ""), "base64");
|
|
354
|
+
if (value.startsWith("base64://")) return value.replace("base64://", "");
|
|
355
|
+
return value;
|
|
356
|
+
}
|
|
357
|
+
if (Buffer.isBuffer(value)) return value.toString("base64");
|
|
306
358
|
};
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
else if (typeof item.value === 'string' && item.value.startsWith('base64://')) {
|
|
324
|
-
fileData = item.value.replace('base64://', '');
|
|
325
|
-
}
|
|
326
|
-
else if (Buffer.isBuffer(item.value)) {
|
|
327
|
-
fileData = item.value.toString('base64');
|
|
328
|
-
}
|
|
329
|
-
else if (typeof item.value === 'string' && item.value.startsWith('buffer://')) {
|
|
330
|
-
fileData = item.value.replace('buffer://', '');
|
|
331
|
-
}
|
|
332
|
-
else if (typeof item.value === 'string') {
|
|
333
|
-
fileData = item.value;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
else if (item.type === 'ImageFile') {
|
|
337
|
-
fileData = readFileSync(item.value, 'base64');
|
|
338
|
-
}
|
|
339
|
-
if (fileData) {
|
|
340
|
-
fileInfo = await uploadMedia({ file_type: fileType, file_data: fileData }).then(res => res?.file_info);
|
|
341
|
-
}
|
|
342
|
-
if (fileInfo) {
|
|
343
|
-
return fileInfo;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
return undefined;
|
|
359
|
+
/**
|
|
360
|
+
* 通过富媒体上传获取 file_info(图片/视频/音频/文件)
|
|
361
|
+
* 按 MEDIA_FILE_TYPE 自动选择 file_type,超出 10MB 的文件自动走分片上传
|
|
362
|
+
*/
|
|
363
|
+
const resolveMediaUrl = async (media, uploadMedia) => {
|
|
364
|
+
for (const item of media) {
|
|
365
|
+
const fileData = await resolveFileData(item);
|
|
366
|
+
if (fileData) {
|
|
367
|
+
const fileInfo = await uploadMedia({
|
|
368
|
+
file_type: MEDIA_FILE_TYPE[item.type] ?? 1,
|
|
369
|
+
file_data: fileData
|
|
370
|
+
}).then((res) => res?.file_info);
|
|
371
|
+
if (fileInfo) return fileInfo;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
347
374
|
};
|
|
375
|
+
/** 移除富媒体占位符(dataEnumToText 降级产生的 [视频]/[音频]/[附件]) */
|
|
376
|
+
const stripMediaPlaceholders = (text) => text.replace(/\[附件[^\]]*\]/g, "").replace(/\[音频\]/g, "").replace(/\[视频\]/g, "").replace(/\n{2,}/g, "\n").trim();
|
|
377
|
+
/** 当 markdownToText 选项开启时,将 Markdown 和按钮降级为纯文本并追加到 content */
|
|
348
378
|
const flattenMdToText = (content, val) => {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
for (const item of btnItems) {
|
|
358
|
-
if (item.type === 'BT.group' && typeof item.value !== 'string') {
|
|
359
|
-
parts.push(buttonsToText(item.value));
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
return parts
|
|
363
|
-
.filter(Boolean)
|
|
364
|
-
.join('\n')
|
|
365
|
-
.replace(/^[^\S\n\r]+|[^\S\n\r]+$/g, '');
|
|
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, "");
|
|
366
385
|
};
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
386
|
+
/** Open API 通用发送逻辑(群组 / C2C) */
|
|
387
|
+
const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMessage, label, options) => {
|
|
388
|
+
const config = getQQBotConfig();
|
|
389
|
+
const mdToText = config.markdownToText === true;
|
|
390
|
+
const media = filterMedia(val);
|
|
391
|
+
if (media.length > 0) {
|
|
392
|
+
const fileInfo = await resolveMediaUrl(media, uploadMedia);
|
|
393
|
+
if (!fileInfo) return [createResult(ResultCode.Fail, "媒体上传失败", null)];
|
|
394
|
+
const res = await sendMessage({
|
|
395
|
+
content: stripMediaPlaceholders(flattenMdToText(content, val)),
|
|
396
|
+
media: { file_info: fileInfo },
|
|
397
|
+
msg_type: 7,
|
|
398
|
+
...baseParams
|
|
399
|
+
});
|
|
400
|
+
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
401
|
+
}
|
|
402
|
+
if (config.hideUnsupported === true && !content && !buildMdAndButtonsParams(val) && !buildArkParams(val)) {
|
|
403
|
+
logger.info("[qq-bot] hideUnsupported: 消息内容转换后为空,跳过发送");
|
|
404
|
+
return [];
|
|
405
|
+
}
|
|
406
|
+
if (mdToText) {
|
|
407
|
+
const textContent = flattenMdToText(content, val);
|
|
408
|
+
if (textContent) {
|
|
409
|
+
const res = await sendMessage({
|
|
410
|
+
content: textContent,
|
|
411
|
+
msg_type: 0,
|
|
412
|
+
...baseParams
|
|
413
|
+
});
|
|
414
|
+
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
415
|
+
}
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
const mdParams = buildMdAndButtonsParams(val);
|
|
419
|
+
if (mdParams) {
|
|
420
|
+
if (mdParams.markdown?.content && content) mdParams.markdown.content = content + "\n" + mdParams.markdown.content;
|
|
421
|
+
const res = await sendMessage({
|
|
422
|
+
content,
|
|
423
|
+
msg_type: 2,
|
|
424
|
+
...mdParams,
|
|
425
|
+
...baseParams,
|
|
426
|
+
force_verify_image_resource: options?.forceVerifyImageResource
|
|
427
|
+
});
|
|
428
|
+
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
429
|
+
}
|
|
430
|
+
const arkParams = buildArkParams(val);
|
|
431
|
+
if (arkParams) {
|
|
432
|
+
const res = await sendMessage({
|
|
433
|
+
content,
|
|
434
|
+
msg_type: 3,
|
|
435
|
+
...arkParams,
|
|
436
|
+
...baseParams
|
|
437
|
+
});
|
|
438
|
+
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
439
|
+
}
|
|
440
|
+
if (content) {
|
|
441
|
+
const res = await sendMessage({
|
|
442
|
+
content,
|
|
443
|
+
msg_type: 0,
|
|
444
|
+
...baseParams
|
|
445
|
+
});
|
|
446
|
+
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
447
|
+
}
|
|
448
|
+
return [];
|
|
429
449
|
};
|
|
450
|
+
/** 将图片数据解析为 Buffer */
|
|
430
451
|
const resolveImageBuffer = async (images) => {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
return Buffer.from(item.value.replace('base64://', ''), 'base64');
|
|
444
|
-
}
|
|
445
|
-
if (item.value.startsWith('file://')) {
|
|
446
|
-
return readFileSync(item.value.replace('file://', ''));
|
|
447
|
-
}
|
|
448
|
-
return Buffer.from(item.value, 'base64');
|
|
449
|
-
}
|
|
450
|
-
if (Buffer.isBuffer(item.value)) {
|
|
451
|
-
return item.value;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
return null;
|
|
452
|
+
for (const item of images) {
|
|
453
|
+
if (item.type === "ImageURL") return await axios.get(item.value, { responseType: "arraybuffer" }).then((res) => res?.data);
|
|
454
|
+
if (item.type === "ImageFile") return readFileSync(item.value);
|
|
455
|
+
if (typeof item.value === "string") {
|
|
456
|
+
if (item.value.startsWith("https://") || item.value.startsWith("http://")) return await axios.get(item.value, { responseType: "arraybuffer" }).then((res) => res?.data);
|
|
457
|
+
if (item.value.startsWith("base64://")) return Buffer.from(item.value.replace("base64://", ""), "base64");
|
|
458
|
+
if (item.value.startsWith("file://")) return readFileSync(item.value.replace("file://", ""));
|
|
459
|
+
return Buffer.from(item.value, "base64");
|
|
460
|
+
}
|
|
461
|
+
if (Buffer.isBuffer(item.value)) return item.value;
|
|
462
|
+
}
|
|
463
|
+
return null;
|
|
455
464
|
};
|
|
465
|
+
/** Guild API 通用发送逻辑(频道公聊 / 频道私聊) */
|
|
456
466
|
const sendGuildMessage = async (content, val, baseParams, sendMessage, label) => {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
467
|
+
const config = getQQBotConfig();
|
|
468
|
+
const mdToText = config.markdownToText === true;
|
|
469
|
+
const images = filterImages(val);
|
|
470
|
+
if (images.length > 0) {
|
|
471
|
+
const imageBuffer = await resolveImageBuffer(images);
|
|
472
|
+
const res = await sendMessage({
|
|
473
|
+
content: flattenMdToText(content, val),
|
|
474
|
+
...baseParams
|
|
475
|
+
}, imageBuffer);
|
|
476
|
+
return [createResult(ResultCode.Ok, label, { id: res?.id })];
|
|
477
|
+
}
|
|
478
|
+
if (config.hideUnsupported && !content && !buildMdAndButtonsParams(val) && !buildArkParams(val)) {
|
|
479
|
+
logger.info("[qq-bot] hideUnsupported: 消息内容转换后为空,跳过发送");
|
|
480
|
+
return [];
|
|
481
|
+
}
|
|
482
|
+
if (mdToText) {
|
|
483
|
+
const textContent = flattenMdToText(content, val);
|
|
484
|
+
if (textContent) {
|
|
485
|
+
const res = await sendMessage({
|
|
486
|
+
content: textContent,
|
|
487
|
+
...baseParams
|
|
488
|
+
});
|
|
489
|
+
return [createResult(ResultCode.Ok, label, { id: res?.id })];
|
|
490
|
+
}
|
|
491
|
+
return [];
|
|
492
|
+
}
|
|
493
|
+
const mdParams = buildMdAndButtonsParams(val);
|
|
494
|
+
if (mdParams) {
|
|
495
|
+
if (mdParams.markdown?.content && content) mdParams.markdown.content = content + "\n" + mdParams.markdown.content;
|
|
496
|
+
const res = await sendMessage({
|
|
497
|
+
content: "",
|
|
498
|
+
...mdParams,
|
|
499
|
+
...baseParams
|
|
500
|
+
});
|
|
501
|
+
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
502
|
+
}
|
|
503
|
+
const arkParams = buildArkParams(val);
|
|
504
|
+
if (arkParams) {
|
|
505
|
+
const res = await sendMessage({
|
|
506
|
+
content,
|
|
507
|
+
...arkParams,
|
|
508
|
+
...baseParams
|
|
509
|
+
});
|
|
510
|
+
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
511
|
+
}
|
|
512
|
+
if (content) {
|
|
513
|
+
const res = await sendMessage({
|
|
514
|
+
content,
|
|
515
|
+
...baseParams
|
|
516
|
+
});
|
|
517
|
+
return [createResult(ResultCode.Ok, label, { id: res?.id })];
|
|
518
|
+
}
|
|
519
|
+
return [];
|
|
496
520
|
};
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
521
|
+
/**
|
|
522
|
+
* 群组消息
|
|
523
|
+
*/
|
|
524
|
+
const GROUP_AT_MESSAGE_CREATE = async (client, event, val, options) => {
|
|
525
|
+
const baseParams = buildBaseParams(event._tag, event.MessageId, "INTERACTION_CREATE_GROUP");
|
|
526
|
+
const content = extractContent(val, "group");
|
|
527
|
+
try {
|
|
528
|
+
return await sendOpenApiMessage(content, val, baseParams, (data) => client.postRichMediaByGroup(event.ChannelId, data), (data) => client.groupOpenMessages(event.ChannelId, data), "client.groupOpenMessages", options);
|
|
529
|
+
} catch (err) {
|
|
530
|
+
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
531
|
+
}
|
|
506
532
|
};
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
533
|
+
/**
|
|
534
|
+
* 私聊消息
|
|
535
|
+
*/
|
|
536
|
+
const C2C_MESSAGE_CREATE = async (client, event, val, options) => {
|
|
537
|
+
const baseParams = buildBaseParams(event._tag, event.MessageId, "INTERACTION_CREATE_C2C");
|
|
538
|
+
const content = extractContent(val, "group");
|
|
539
|
+
try {
|
|
540
|
+
return await sendOpenApiMessage(content, val, baseParams, (data) => client.postRichMediaByUser(event.UserId, data), (data) => client.usersOpenMessages(event.UserId, data), "client.usersOpenMessages", options);
|
|
541
|
+
} catch (err) {
|
|
542
|
+
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
543
|
+
}
|
|
516
544
|
};
|
|
545
|
+
/**
|
|
546
|
+
* 频道私聊
|
|
547
|
+
*/
|
|
517
548
|
const DIRECT_MESSAGE_CREATE = async (client, event, val) => {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
549
|
+
const baseParams = buildBaseParams(event._tag, event.MessageId, "INTERACTION_CREATE_GUILD");
|
|
550
|
+
const content = extractContent(val, "guild-direct");
|
|
551
|
+
try {
|
|
552
|
+
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.dmsMessages(event.UserId, data, buf), "client.dmsMessage");
|
|
553
|
+
} catch (err) {
|
|
554
|
+
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
555
|
+
}
|
|
526
556
|
};
|
|
557
|
+
/**
|
|
558
|
+
* 频道公聊
|
|
559
|
+
*/
|
|
527
560
|
const MESSAGE_CREATE = async (client, event, val) => {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
561
|
+
const baseParams = buildBaseParams(event._tag, event.MessageId, "INTERACTION_CREATE_GUILD");
|
|
562
|
+
const content = extractContent(val, "guild-public");
|
|
563
|
+
try {
|
|
564
|
+
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.channelsMessages(event.ChannelId, data, buf), "client.channelsMessagesPost");
|
|
565
|
+
} catch (err) {
|
|
566
|
+
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
567
|
+
}
|
|
536
568
|
};
|
|
569
|
+
/**
|
|
570
|
+
* 频道公聊 @
|
|
571
|
+
*/
|
|
537
572
|
const AT_MESSAGE_CREATE = (client, event, val) => {
|
|
538
|
-
|
|
573
|
+
return MESSAGE_CREATE(client, event, val);
|
|
539
574
|
};
|
|
540
575
|
|
|
541
|
-
|
|
576
|
+
//#endregion
|
|
577
|
+
export { AT_MESSAGE_CREATE, C2C_MESSAGE_CREATE, DIRECT_MESSAGE_CREATE, GROUP_AT_MESSAGE_CREATE, MESSAGE_CREATE };
|