@karinjs/adapter-qqbot 1.3.1 → 2.0.0
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 +222 -766
- package/dist/apps/login.d.ts +20 -0
- package/dist/apps/login.js +57 -0
- package/dist/config-H7LrvlNU.js +197 -0
- package/dist/index.d.ts +589 -418
- package/dist/index.js +2844 -97
- package/dist/onboard-BX8g8Wik.js +249 -0
- package/dist/utils-DO4gEkVN.js +3 -0
- package/dist/web.config.d.ts +20 -23
- package/dist/web.config.js +170 -221
- package/package.json +24 -18
- package/dist/chunk-PYOUSZ6B.js +0 -1501
package/dist/chunk-PYOUSZ6B.js
DELETED
|
@@ -1,1501 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __export = (target, all) => {
|
|
3
|
-
for (var name in all)
|
|
4
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
// src/root.ts
|
|
8
|
-
import path from "path";
|
|
9
|
-
import { fileURLToPath } from "url";
|
|
10
|
-
var filePath = fileURLToPath(import.meta.url);
|
|
11
|
-
var dirPath = path.resolve(filePath, "../..");
|
|
12
|
-
var basename = path.basename(dirPath);
|
|
13
|
-
|
|
14
|
-
// src/core/index.ts
|
|
15
|
-
import { URL } from "url";
|
|
16
|
-
|
|
17
|
-
// src/utils/config.ts
|
|
18
|
-
var config_exports = {};
|
|
19
|
-
__export(config_exports, {
|
|
20
|
-
config: () => config,
|
|
21
|
-
formatConfig: () => formatConfig,
|
|
22
|
-
getConfig: () => getConfig,
|
|
23
|
-
getDefaultConfig: () => getDefaultConfig,
|
|
24
|
-
pkg: () => pkg,
|
|
25
|
-
writeConfig: () => writeConfig
|
|
26
|
-
});
|
|
27
|
-
import fs2 from "fs";
|
|
28
|
-
import {
|
|
29
|
-
watch,
|
|
30
|
-
basePath,
|
|
31
|
-
requireFileSync,
|
|
32
|
-
common as common2
|
|
33
|
-
} from "node-karin";
|
|
34
|
-
|
|
35
|
-
// src/core/api/sign.ts
|
|
36
|
-
import nacl from "tweetnacl";
|
|
37
|
-
var generateKeyPair = (seed) => {
|
|
38
|
-
let finalSeed = seed;
|
|
39
|
-
while (finalSeed.length < 32) {
|
|
40
|
-
finalSeed = finalSeed.repeat(2);
|
|
41
|
-
}
|
|
42
|
-
finalSeed = finalSeed.slice(0, 32);
|
|
43
|
-
const seedBuffer = Buffer.from(finalSeed, "utf-8");
|
|
44
|
-
const keyPair = nacl.sign.keyPair.fromSeed(seedBuffer);
|
|
45
|
-
return keyPair;
|
|
46
|
-
};
|
|
47
|
-
var signMessage = (privateKey, eventTs, plainToken) => {
|
|
48
|
-
const message = eventTs + plainToken;
|
|
49
|
-
const messageBytes = Buffer.from(message, "utf-8");
|
|
50
|
-
const signature = nacl.sign.detached(messageBytes, privateKey);
|
|
51
|
-
return Buffer.from(signature).toString("hex");
|
|
52
|
-
};
|
|
53
|
-
var sign = (secret, eventTs, plainToken) => {
|
|
54
|
-
const { secretKey } = generateKeyPair(secret);
|
|
55
|
-
const signature = signMessage(secretKey, eventTs, plainToken);
|
|
56
|
-
return signature;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// src/connection/webSocket.ts
|
|
60
|
-
import { WebSocket } from "node-karin/ws";
|
|
61
|
-
|
|
62
|
-
// src/utils/common.ts
|
|
63
|
-
import fs from "fs";
|
|
64
|
-
import qrcode from "qrcode";
|
|
65
|
-
import size from "image-size";
|
|
66
|
-
import lodash from "node-karin/lodash";
|
|
67
|
-
import EventEmitter from "events";
|
|
68
|
-
import GetUrls from "@karinjs/geturls";
|
|
69
|
-
import { encode, isSilk } from "silk-wasm";
|
|
70
|
-
import { common, ffmpeg, logger, segment, tempPath } from "node-karin";
|
|
71
|
-
var event = new EventEmitter();
|
|
72
|
-
var random = (min, max) => lodash.random(min, max);
|
|
73
|
-
var fakeEvent = (log2) => {
|
|
74
|
-
logger.fatal(`${logger.red("[QQBot][\u865A\u5047\u4E8B\u4EF6]")} ${log2.replace(/\n/g, "\\n")}`);
|
|
75
|
-
};
|
|
76
|
-
var handleUrl = (text, exclude = []) => {
|
|
77
|
-
text = text.replace(/[\u4e00-\u9fa5]/g, "|");
|
|
78
|
-
const urls = GetUrls.getUrls(text, {
|
|
79
|
-
exclude,
|
|
80
|
-
/** 去除 WWW */
|
|
81
|
-
stripWWW: false,
|
|
82
|
-
/** 规范化协议 */
|
|
83
|
-
normalizeProtocol: false,
|
|
84
|
-
/** 移除查询参数 */
|
|
85
|
-
removeQueryParameters: false,
|
|
86
|
-
/** 移除唯一斜杠 */
|
|
87
|
-
removeSingleSlash: false,
|
|
88
|
-
/** 查询参数排序 */
|
|
89
|
-
sortQueryParameters: false,
|
|
90
|
-
/** 去除认证信息 */
|
|
91
|
-
stripAuthentication: false,
|
|
92
|
-
/** 去除文本片段 */
|
|
93
|
-
stripTextFragment: false,
|
|
94
|
-
/** 移除末尾斜杠 */
|
|
95
|
-
removeTrailingSlash: false,
|
|
96
|
-
/** 不进行标准处理url */
|
|
97
|
-
normalize: false
|
|
98
|
-
});
|
|
99
|
-
return urls;
|
|
100
|
-
};
|
|
101
|
-
var qrs = async (urls) => {
|
|
102
|
-
const list = await Promise.all(urls.map((url) => qrcode.toDataURL(url)));
|
|
103
|
-
return list.map((item) => `base64://${item.split(",")[1]}`);
|
|
104
|
-
};
|
|
105
|
-
var textToButton = (text, isC2C = false) => {
|
|
106
|
-
text = text.replace(/@everyone/g, "everyone").replace(/\n/g, "\r");
|
|
107
|
-
if (isC2C) text = text.replace(/<qqbot-at-user id=".+" \/>/gm, "").replace(/<@.+>/gm, "");
|
|
108
|
-
const urls = handleUrl(text);
|
|
109
|
-
if (urls.length === 0) {
|
|
110
|
-
return { text, buttons: [] };
|
|
111
|
-
}
|
|
112
|
-
const buttons = [];
|
|
113
|
-
urls.forEach((url, index) => {
|
|
114
|
-
text = text.replace(new RegExp(url, "g"), `[\u8BF7\u70B9\u51FB \u6309\u94AE${index} \u67E5\u770B]`);
|
|
115
|
-
buttons.push(segment.button({ text: `${index}. ${url}`, link: url }));
|
|
116
|
-
});
|
|
117
|
-
return { text, buttons: buttons.length > 5 ? buttons.slice(0, 5) : buttons };
|
|
118
|
-
};
|
|
119
|
-
var getImageSize = async (url) => {
|
|
120
|
-
const buffer = await common.buffer(url);
|
|
121
|
-
const { width = 100, height = 100 } = size(buffer);
|
|
122
|
-
return { width, height };
|
|
123
|
-
};
|
|
124
|
-
var escapeMarkdown = (text) => {
|
|
125
|
-
text = text.replace(/^(\s*)#(?!#)/gm, "$1\r#");
|
|
126
|
-
text = text.replace(/(?<!\\)\*\*\*(.+?)(?<!\\)\*\*\*/g, "\\*\\*\\*$1\\*\\*\\*");
|
|
127
|
-
text = text.replace(/(?<!\\)\*\*(.+?)(?<!\\)\*\*/g, "\\*\\*$1\\*\\*");
|
|
128
|
-
text = text.replace(/(?<!\\)__(.+?)(?<!\\)__/g, "\\__\\__$1\\__\\__");
|
|
129
|
-
text = text.replace(/(?<!\\)\*(.+?)(?<!\\)\*/g, "\\*$1\\*");
|
|
130
|
-
text = text.replace(/(?<!\\)_(.+?)(?<!\\)_/g, "\\_$1\\_");
|
|
131
|
-
text = text.replace(/(?<!\\)~~(.+?)(?<!\\)~~/g, "\\~\\~$1\\~\\~");
|
|
132
|
-
return text;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
// src/connection/webSocket.ts
|
|
136
|
-
var cache = /* @__PURE__ */ new Map();
|
|
137
|
-
var createWebSocketConnection = (config2) => {
|
|
138
|
-
if (config2.appId === "default") return;
|
|
139
|
-
if (config2.event.type !== 2) return;
|
|
140
|
-
const appid = config2.appId;
|
|
141
|
-
const url = config2.event.wsUrl;
|
|
142
|
-
const headers = { "x-bot-appid": appid, authorization: "Bearer " + config2.event.wsToken };
|
|
143
|
-
const socket = new WebSocket(url, { headers });
|
|
144
|
-
const close = (isClose = false) => {
|
|
145
|
-
try {
|
|
146
|
-
socket.removeAllListeners();
|
|
147
|
-
socket == null ? void 0 : socket.close();
|
|
148
|
-
if (isClose) {
|
|
149
|
-
log("warn", `${appid}: WebSocket\u8FDE\u63A5\u5DF2\u4E3B\u52A8\u5173\u95ED: ${url}`);
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
log("error", `${appid}: WebSocket\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u5C06\u57285\u79D2\u540E\u91CD\u8FDE: ${url}`);
|
|
153
|
-
setTimeout(() => createWebSocketConnection(config2), 5e3);
|
|
154
|
-
} finally {
|
|
155
|
-
const ws = cache.get(appid);
|
|
156
|
-
if (ws) {
|
|
157
|
-
cache.delete(appid);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
socket.on("close", () => close(false));
|
|
162
|
-
socket.on("error", (error) => {
|
|
163
|
-
log("error", error);
|
|
164
|
-
close();
|
|
165
|
-
});
|
|
166
|
-
socket.on("open", () => {
|
|
167
|
-
cache.set(appid, { socket, close });
|
|
168
|
-
log("info", `${appid}: WebSocket\u8FDE\u63A5\u5DF2\u6253\u5F00: ${url}`);
|
|
169
|
-
});
|
|
170
|
-
socket.on("message", (event2) => {
|
|
171
|
-
const raw = event2.toString();
|
|
172
|
-
const data = JSON.parse(raw);
|
|
173
|
-
if ((data == null ? void 0 : data.type) === "event") {
|
|
174
|
-
return eventHandler(config2, data, raw);
|
|
175
|
-
}
|
|
176
|
-
if ((data == null ? void 0 : data.type) === "sign") {
|
|
177
|
-
signHandler(config2, data, raw, socket);
|
|
178
|
-
}
|
|
179
|
-
log("error", `${appid}: \u672A\u77E5\u7684\u6D88\u606F\u7C7B\u578B: ${raw}`);
|
|
180
|
-
});
|
|
181
|
-
return socket;
|
|
182
|
-
};
|
|
183
|
-
var stopWebSocketConnection = (appid) => {
|
|
184
|
-
const result = cache.get(appid);
|
|
185
|
-
if (result) {
|
|
186
|
-
result.close();
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
return false;
|
|
190
|
-
};
|
|
191
|
-
var eventHandler = (config2, data, raw) => {
|
|
192
|
-
var _a, _b, _c;
|
|
193
|
-
const { appId, secret } = config2;
|
|
194
|
-
if (!((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.headers) || !((_b = data == null ? void 0 : data.data) == null ? void 0 : _b.headers["x-signature-ed25519"]) || !((_c = data == null ? void 0 : data.data) == null ? void 0 : _c.headers["x-signature-timestamp"])) {
|
|
195
|
-
fakeEvent(`\u672A\u627E\u5230\u7B7E\u540D\u5B57\u6BB5: ${raw}`);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
const signature = sign(secret, data.data.headers["x-signature-timestamp"], data.data.event);
|
|
199
|
-
if (signature !== data.data.headers["x-signature-ed25519"]) {
|
|
200
|
-
log("error", `${appId}: \u7B7E\u540D\u9A8C\u8BC1\u5931\u8D25: ${raw}`);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
event.emit(appId, JSON.parse(data.data.event));
|
|
204
|
-
};
|
|
205
|
-
var signHandler = (config2, data, raw, socket) => {
|
|
206
|
-
var _a, _b;
|
|
207
|
-
const { appId, secret } = config2;
|
|
208
|
-
if (!((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.eventTs) || !((_b = data == null ? void 0 : data.data) == null ? void 0 : _b.plainToken)) {
|
|
209
|
-
const text = `\u672A\u627E\u5230 eventTs \u6216 plainToken: ${raw}`;
|
|
210
|
-
log("error", `${appId}: ${text}`);
|
|
211
|
-
const response2 = { echo: data.echo, type: "sign", data: { status: "error", message: text } };
|
|
212
|
-
socket.send(JSON.stringify(response2));
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
const signature = sign(secret, data.data.eventTs, data.data.plainToken);
|
|
216
|
-
const response = { echo: data.echo, type: "sign", data: { status: "success", message: signature } };
|
|
217
|
-
socket.send(JSON.stringify(response));
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
// src/utils/config.ts
|
|
221
|
-
var cache2;
|
|
222
|
-
var cacheMap = {};
|
|
223
|
-
var pkg = () => requireFileSync(`${dirPath}/package.json`);
|
|
224
|
-
var pluginName = pkg().name.replace(/\//g, "-");
|
|
225
|
-
var dirConfig = `${basePath}/${pluginName}/config`;
|
|
226
|
-
var config = () => {
|
|
227
|
-
const cfgPath = `${dirConfig}/config.json`;
|
|
228
|
-
if (!fs2.existsSync(cfgPath)) {
|
|
229
|
-
fs2.writeFileSync(cfgPath, JSON.stringify([], null, 2));
|
|
230
|
-
}
|
|
231
|
-
if (cache2) return cache2;
|
|
232
|
-
const user = requireFileSync(cfgPath);
|
|
233
|
-
const result = formatConfig(user);
|
|
234
|
-
cache2 = result;
|
|
235
|
-
result.forEach((v) => {
|
|
236
|
-
cacheMap[v.appId] = v;
|
|
237
|
-
});
|
|
238
|
-
return result;
|
|
239
|
-
};
|
|
240
|
-
var getConfig = (appid) => {
|
|
241
|
-
return cacheMap[appid];
|
|
242
|
-
};
|
|
243
|
-
var writeConfig = (config2) => {
|
|
244
|
-
fs2.writeFileSync(`${dirConfig}/config.json`, JSON.stringify(config2, null, 2));
|
|
245
|
-
};
|
|
246
|
-
var formatConfig = (user) => {
|
|
247
|
-
const def = getDefaultConfig()[0];
|
|
248
|
-
const result = [];
|
|
249
|
-
user.forEach((item) => {
|
|
250
|
-
result.push({
|
|
251
|
-
...def,
|
|
252
|
-
...item,
|
|
253
|
-
event: {
|
|
254
|
-
...def.event,
|
|
255
|
-
...item.event
|
|
256
|
-
},
|
|
257
|
-
markdown: {
|
|
258
|
-
...def.markdown,
|
|
259
|
-
...item.markdown
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
return result;
|
|
264
|
-
};
|
|
265
|
-
var getDefaultConfig = () => [
|
|
266
|
-
{
|
|
267
|
-
appId: "",
|
|
268
|
-
secret: "",
|
|
269
|
-
prodApi: "https://api.sgroup.qq.com",
|
|
270
|
-
sandboxApi: "https://sandbox.api.sgroup.qq.com",
|
|
271
|
-
tokenApi: "",
|
|
272
|
-
sandbox: false,
|
|
273
|
-
qqEnable: true,
|
|
274
|
-
guildEnable: true,
|
|
275
|
-
guildMode: 0,
|
|
276
|
-
exclude: [],
|
|
277
|
-
regex: [
|
|
278
|
-
{
|
|
279
|
-
reg: "^/",
|
|
280
|
-
rep: "#"
|
|
281
|
-
}
|
|
282
|
-
],
|
|
283
|
-
markdown: {
|
|
284
|
-
mode: 0,
|
|
285
|
-
id: "",
|
|
286
|
-
kv: [
|
|
287
|
-
"text_start",
|
|
288
|
-
"img_dec",
|
|
289
|
-
"img_url",
|
|
290
|
-
"text_end"
|
|
291
|
-
]
|
|
292
|
-
},
|
|
293
|
-
event: {
|
|
294
|
-
type: 0,
|
|
295
|
-
wsUrl: "",
|
|
296
|
-
wsToken: ""
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
];
|
|
300
|
-
setTimeout(() => {
|
|
301
|
-
watch(`${dirConfig}/config.json`, (old, now) => {
|
|
302
|
-
cache2 = formatConfig(now);
|
|
303
|
-
cache2.forEach((v) => {
|
|
304
|
-
cacheMap[v.appId] = v;
|
|
305
|
-
});
|
|
306
|
-
const result = common2.diffArray(old, now);
|
|
307
|
-
if (result.removed.length > 0) {
|
|
308
|
-
result.removed.forEach((v) => {
|
|
309
|
-
if (v.event.type !== 2) return;
|
|
310
|
-
stopWebSocketConnection(v.appId);
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
if (result.added.length > 0) {
|
|
314
|
-
const appids = result.added.map((v) => v.appId);
|
|
315
|
-
cache2.forEach((v) => {
|
|
316
|
-
if (!appids.includes(v.appId)) return;
|
|
317
|
-
if (v.event.type === 0) return;
|
|
318
|
-
createBot(v);
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
}, 2e3);
|
|
323
|
-
|
|
324
|
-
// src/utils/logger.ts
|
|
325
|
-
import { logger as logger2 } from "node-karin";
|
|
326
|
-
var logMethods = {
|
|
327
|
-
trace: (...args) => logger2.trace("[QQBot]", ...args),
|
|
328
|
-
debug: (...args) => logger2.debug("[QQBot]", ...args),
|
|
329
|
-
info: (...args) => logger2.info("[QQBot]", ...args),
|
|
330
|
-
warn: (...args) => logger2.warn("[QQBot]", ...args),
|
|
331
|
-
error: (...args) => logger2.error("[QQBot]", ...args),
|
|
332
|
-
fatal: (...args) => logger2.fatal("[QQBot]", ...args),
|
|
333
|
-
mark: (...args) => logger2.mark("[QQBot]", ...args)
|
|
334
|
-
};
|
|
335
|
-
function log(level, ...args) {
|
|
336
|
-
logMethods[level](...args);
|
|
337
|
-
}
|
|
338
|
-
Object.assign(log, logMethods);
|
|
339
|
-
|
|
340
|
-
// src/core/api/index.ts
|
|
341
|
-
import FormData from "form-data";
|
|
342
|
-
import lodash2 from "node-karin/lodash";
|
|
343
|
-
import { AxiosError } from "node-karin/axios";
|
|
344
|
-
var QQBotApi = class {
|
|
345
|
-
/** axios 实例 */
|
|
346
|
-
axios;
|
|
347
|
-
constructor(axios2) {
|
|
348
|
-
this.axios = axios2;
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* 发送get请求
|
|
352
|
-
* @param path 请求路径
|
|
353
|
-
* @returns 请求结果
|
|
354
|
-
*/
|
|
355
|
-
async get(path2) {
|
|
356
|
-
try {
|
|
357
|
-
const { data } = await this.axios.get(path2);
|
|
358
|
-
return data;
|
|
359
|
-
} catch (error) {
|
|
360
|
-
this.handleError(path2, {}, error);
|
|
361
|
-
throw error;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* 发送post请求
|
|
366
|
-
* @param path 请求路径
|
|
367
|
-
* @param options 请求数据
|
|
368
|
-
* @param headers 请求头
|
|
369
|
-
*/
|
|
370
|
-
async post(path2, options = {}, headers) {
|
|
371
|
-
try {
|
|
372
|
-
const result = await this.axios.post(path2, options, { headers });
|
|
373
|
-
return result.data;
|
|
374
|
-
} catch (error) {
|
|
375
|
-
this.handleError(path2, options, error);
|
|
376
|
-
throw error;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* 处理请求错误
|
|
381
|
-
* @param error 错误信息
|
|
382
|
-
*/
|
|
383
|
-
handleError(path2, options, error) {
|
|
384
|
-
var _a, _b;
|
|
385
|
-
if (error instanceof AxiosError) {
|
|
386
|
-
throw new Error([
|
|
387
|
-
"[axios] \u8BF7\u6C42\u5931\u8D25",
|
|
388
|
-
`\u8BF7\u6C42\u8DEF\u5F84: ${path2}`,
|
|
389
|
-
`\u8BF7\u6C42\u6570\u636E: ${lodash2.truncate(JSON.stringify(options), { length: 500 })}`,
|
|
390
|
-
`\u54CD\u5E94\u6570\u636E: ${JSON.stringify((_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data)}`
|
|
391
|
-
].join("\n"));
|
|
392
|
-
}
|
|
393
|
-
if (error.request) throw ((_b = error.request) == null ? void 0 : _b.message) || error.request;
|
|
394
|
-
throw (error == null ? void 0 : error.message) || (error == null ? void 0 : error.stack) || error;
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* 发送单聊消息
|
|
398
|
-
* @param targetId 目标QQ用户的 openid
|
|
399
|
-
* @param options 消息参数
|
|
400
|
-
*/
|
|
401
|
-
sendFriendMsg(targetId, options) {
|
|
402
|
-
return this.post(`/v2/users/${targetId}/messages`, options);
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* 发送群聊消息
|
|
406
|
-
* @param targetId 目标QQ群的 openid
|
|
407
|
-
* @param options 消息参数
|
|
408
|
-
*/
|
|
409
|
-
sendGroupMsg(targetId, options) {
|
|
410
|
-
return this.post(`/v2/groups/${targetId}/messages`, options);
|
|
411
|
-
}
|
|
412
|
-
QQdMsgOptions(type, data, keyboard) {
|
|
413
|
-
switch (type) {
|
|
414
|
-
case "text":
|
|
415
|
-
return { msg_type: 0, content: data };
|
|
416
|
-
case "markdown":
|
|
417
|
-
return { msg_type: 2, markdown: data, keyboard };
|
|
418
|
-
case "ark":
|
|
419
|
-
return { msg_type: 3, ark: data };
|
|
420
|
-
case "media":
|
|
421
|
-
return { msg_type: 7, media: { file_info: data }, content: "" };
|
|
422
|
-
default:
|
|
423
|
-
throw new Error("\u672A\u77E5\u7684\u6D88\u606F\u7C7B\u578B");
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
GuildMsgOptions(type, data, image) {
|
|
427
|
-
switch (type) {
|
|
428
|
-
case "text":
|
|
429
|
-
return { type: "text", content: data, image };
|
|
430
|
-
case "image":
|
|
431
|
-
return { type: "image", image: data };
|
|
432
|
-
case "embed":
|
|
433
|
-
return { type: "embed", embed: data };
|
|
434
|
-
case "ark":
|
|
435
|
-
return { type: "ark", ark: data };
|
|
436
|
-
case "markdown":
|
|
437
|
-
return { type: "markdown", markdown: data };
|
|
438
|
-
default:
|
|
439
|
-
throw new Error("\u672A\u77E5\u7684\u6D88\u606F\u7C7B\u578B");
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
uploadMedia(scene, targetId, type, data, srvSendMsg = false) {
|
|
443
|
-
const map = {
|
|
444
|
-
image: 1,
|
|
445
|
-
video: 2,
|
|
446
|
-
record: 3,
|
|
447
|
-
file: 4
|
|
448
|
-
};
|
|
449
|
-
const options = {
|
|
450
|
-
file_type: map[type],
|
|
451
|
-
srv_send_msg: srvSendMsg
|
|
452
|
-
};
|
|
453
|
-
if (data.startsWith("http")) {
|
|
454
|
-
options.url = data;
|
|
455
|
-
} else {
|
|
456
|
-
options.file_data = data.replace(/^data:image\/\w+;base64,|^base64:\/\//g, "");
|
|
457
|
-
}
|
|
458
|
-
return this.post(`/v2/${scene}s/${targetId}/files`, options);
|
|
459
|
-
}
|
|
460
|
-
async recallMsg(type, targetId, messageId, hidetip = false) {
|
|
461
|
-
let url;
|
|
462
|
-
if (type === "user") {
|
|
463
|
-
url = `/v2/users/${targetId}/messages/${messageId}`;
|
|
464
|
-
} else if (type === "group") {
|
|
465
|
-
url = `/v2/groups/${targetId}/messages/${messageId}`;
|
|
466
|
-
} else if (type === "channels") {
|
|
467
|
-
url = ` /channels/${targetId}/messages/${messageId}?hidetip=${hidetip}`;
|
|
468
|
-
} else if (type === "dms") {
|
|
469
|
-
url = `/dms/${targetId}/messages/${messageId}?hidetip=${hidetip}`;
|
|
470
|
-
} else {
|
|
471
|
-
throw new Error("\u672A\u77E5\u7684\u64A4\u56DE\u6D88\u606F\u7C7B\u578B");
|
|
472
|
-
}
|
|
473
|
-
return this.get(url).then(() => true).catch(() => false);
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* 发送文字子频道消息
|
|
477
|
-
* @param targetId 目标子频道的id
|
|
478
|
-
* @param options 消息参数
|
|
479
|
-
*/
|
|
480
|
-
sendChannelMsg(targetId, options) {
|
|
481
|
-
const headers = options instanceof FormData ? options.getHeaders() : void 0;
|
|
482
|
-
return this.post(`/channels/${targetId}/messages`, options, headers);
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* 发送频道私信消息
|
|
486
|
-
* @param targetId 目标的id
|
|
487
|
-
* @param data 源频道的id
|
|
488
|
-
* @param options 消息参数
|
|
489
|
-
*/
|
|
490
|
-
async sendDmsMsg(targetId, data, options) {
|
|
491
|
-
if (typeof data === "string") {
|
|
492
|
-
const { guild_id: guildId } = await this.dms(targetId, data);
|
|
493
|
-
const headers2 = options instanceof FormData ? options.getHeaders() : void 0;
|
|
494
|
-
return this.post(`/dms/${guildId}/messages`, options, headers2);
|
|
495
|
-
}
|
|
496
|
-
const headers = data instanceof FormData ? data.getHeaders() : void 0;
|
|
497
|
-
return this.post(`/dms/${targetId}/messages`, data, headers);
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* 获取当前机器人详情
|
|
501
|
-
*/
|
|
502
|
-
getMe() {
|
|
503
|
-
return this.get("/users/@me");
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* 创建私信会话
|
|
507
|
-
* @param recipientID 接受者id
|
|
508
|
-
* @param srcGuildID 源频道id
|
|
509
|
-
*/
|
|
510
|
-
dms(recipientID, srcGuildID) {
|
|
511
|
-
return this.post("/users/@me/dms", { recipient_id: recipientID, source_guild_id: srcGuildID });
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
// src/core/index.ts
|
|
516
|
-
import { logger as logger4, registerBot } from "node-karin";
|
|
517
|
-
|
|
518
|
-
// src/core/adapter/normal.ts
|
|
519
|
-
import FormData2 from "form-data";
|
|
520
|
-
import { common as common3, fileToUrl } from "node-karin";
|
|
521
|
-
|
|
522
|
-
// src/core/adapter/adapter.ts
|
|
523
|
-
import { AdapterBase, logger as logger3, karinToQQBot } from "node-karin";
|
|
524
|
-
var AdapterQQBot = class extends AdapterBase {
|
|
525
|
-
super;
|
|
526
|
-
constructor(QQBot) {
|
|
527
|
-
super();
|
|
528
|
-
this.super = QQBot;
|
|
529
|
-
this.adapter.name = "@karinjs/qqbot";
|
|
530
|
-
this.adapter.protocol = "qqbot";
|
|
531
|
-
this.adapter.platform = "qq";
|
|
532
|
-
this.adapter.standard = "other";
|
|
533
|
-
}
|
|
534
|
-
logger(level, ...args) {
|
|
535
|
-
logger3.bot(level, this.selfId, ...args);
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* 被动消息结构
|
|
539
|
-
* @param type 消息类型
|
|
540
|
-
*/
|
|
541
|
-
pasmsg(type) {
|
|
542
|
-
if (type === "qq") {
|
|
543
|
-
return { type: "msg", msg_id: "", msg_seq: random(1, 9999999) };
|
|
544
|
-
}
|
|
545
|
-
return { type: "msg", msg_id: "" };
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* 撤回消息
|
|
549
|
-
* @param contact 联系人
|
|
550
|
-
* @param messageId 消息id
|
|
551
|
-
*/
|
|
552
|
-
async recallMsg(contact, messageId) {
|
|
553
|
-
try {
|
|
554
|
-
if (contact.scene === "friend") {
|
|
555
|
-
await this.super.recallMsg("user", contact.peer, messageId);
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
if (contact.scene === "group") {
|
|
559
|
-
await this.super.recallMsg("group", contact.peer, messageId);
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
if (contact.scene === "direct") {
|
|
563
|
-
await this.super.recallMsg("dms", contact.peer, messageId);
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
if (contact.scene === "guild") {
|
|
567
|
-
await this.super.recallMsg("channels", contact.peer, messageId);
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
} catch (error) {
|
|
571
|
-
logger3.error("\u64A4\u56DE\u6D88\u606F\u5931\u8D25:", error);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* 初始化消息分类对象
|
|
576
|
-
*/
|
|
577
|
-
initList(type) {
|
|
578
|
-
const list = {
|
|
579
|
-
content: [],
|
|
580
|
-
image: [],
|
|
581
|
-
button: [],
|
|
582
|
-
keyboard: [],
|
|
583
|
-
markdown: [],
|
|
584
|
-
markdownTpl: [],
|
|
585
|
-
imageUrls: [],
|
|
586
|
-
imageFiles: [],
|
|
587
|
-
reply: { message_id: "" },
|
|
588
|
-
pasmsg: this.pasmsg(type),
|
|
589
|
-
list: [],
|
|
590
|
-
markdownToButton: (type2, list2) => this.markdownToButton(type2, list2)
|
|
591
|
-
};
|
|
592
|
-
return list;
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* 初始化发送消息返回值
|
|
596
|
-
*/
|
|
597
|
-
initSendMsgResults() {
|
|
598
|
-
return {
|
|
599
|
-
messageId: "",
|
|
600
|
-
message_id: "",
|
|
601
|
-
time: 0,
|
|
602
|
-
messageTime: 0,
|
|
603
|
-
rawData: []
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* 处理返回值
|
|
608
|
-
* @param data 返回值
|
|
609
|
-
*/
|
|
610
|
-
handleResponse(data) {
|
|
611
|
-
const { id, timestamp } = data.rawData[0];
|
|
612
|
-
data.messageId = id;
|
|
613
|
-
data.message_id = id;
|
|
614
|
-
data.messageTime = timestamp;
|
|
615
|
-
data.messageTime = typeof timestamp === "string" ? new Date(timestamp).getTime() : timestamp;
|
|
616
|
-
return data;
|
|
617
|
-
}
|
|
618
|
-
/**
|
|
619
|
-
* - 处理按钮、markdown
|
|
620
|
-
* - 统一格式后推入待发送消息列表
|
|
621
|
-
* @param type 消息类型
|
|
622
|
-
* @param button 按钮
|
|
623
|
-
* @param keyboard 键盘
|
|
624
|
-
* @param markdown markdown
|
|
625
|
-
* @param markdownTpl markdown模板
|
|
626
|
-
* @returns 消息列表
|
|
627
|
-
*/
|
|
628
|
-
markdownToButton(type, list) {
|
|
629
|
-
const rows = [];
|
|
630
|
-
if (list.button.length) {
|
|
631
|
-
list.button.forEach((v) => {
|
|
632
|
-
rows.push(...karinToQQBot(v));
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
if (list.keyboard.length) {
|
|
636
|
-
list.keyboard.forEach((v) => {
|
|
637
|
-
rows.push(...karinToQQBot(v));
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
list.markdown.forEach((v) => {
|
|
641
|
-
const item = type === "guild" ? this.super.GuildMsgOptions("markdown", { content: v.markdown }) : this.super.QQdMsgOptions("markdown", { content: v.markdown });
|
|
642
|
-
if (rows.length) item.keyboard = { content: { rows } };
|
|
643
|
-
list.list.push(item);
|
|
644
|
-
});
|
|
645
|
-
list.markdownTpl.forEach((v) => {
|
|
646
|
-
const item = type === "guild" ? this.super.GuildMsgOptions("markdown", {
|
|
647
|
-
custom_template_id: v.templateId,
|
|
648
|
-
params: v.params
|
|
649
|
-
}) : this.super.QQdMsgOptions("markdown", {
|
|
650
|
-
custom_template_id: v.templateId,
|
|
651
|
-
params: v.params
|
|
652
|
-
});
|
|
653
|
-
if (rows.length) item.keyboard = { content: { rows } };
|
|
654
|
-
list.list.push(item);
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
};
|
|
658
|
-
|
|
659
|
-
// src/core/adapter/normal.ts
|
|
660
|
-
var AdapterQQBotNormal = class extends AdapterQQBot {
|
|
661
|
-
async srcReply(e, elements) {
|
|
662
|
-
return this.sendMsg(e.contact, elements);
|
|
663
|
-
}
|
|
664
|
-
async sendMsg(contact, elements, retryCount) {
|
|
665
|
-
if (contact.scene === "direct" || contact.scene === "guild") {
|
|
666
|
-
return this.sendGuildMsg(contact, elements, retryCount);
|
|
667
|
-
} else if (contact.scene === "group" || contact.scene === "friend") {
|
|
668
|
-
return this.sendQQMsg(contact, elements, retryCount);
|
|
669
|
-
}
|
|
670
|
-
throw new Error("\u4E0D\u652F\u6301\u7684\u6D88\u606F\u7C7B\u578B");
|
|
671
|
-
}
|
|
672
|
-
/**
|
|
673
|
-
* 处理文本 将文本中的链接转为二维码
|
|
674
|
-
* @param text 文本
|
|
675
|
-
* @returns 处理后的文本和二维码 二维码为不带`base64://`的字符串
|
|
676
|
-
*/
|
|
677
|
-
async hendleText(text) {
|
|
678
|
-
const urls = handleUrl(text);
|
|
679
|
-
if (!urls.length) return { text, qr: null };
|
|
680
|
-
urls.forEach((url) => {
|
|
681
|
-
text = text.replace(new RegExp(url, "g"), "[\u8BF7\u626B\u7801\u67E5\u770B]");
|
|
682
|
-
});
|
|
683
|
-
const list = await qrs(urls);
|
|
684
|
-
if (list.length === 1) return { text, qr: list[0] };
|
|
685
|
-
const result = await common3.mergeImage(list, 3);
|
|
686
|
-
return { text, qr: result.base64 };
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* 发送QQ私聊、群聊消息
|
|
690
|
-
* @param contact 联系人
|
|
691
|
-
* @param elements 消息元素
|
|
692
|
-
* @param retryCount 重试次数
|
|
693
|
-
*/
|
|
694
|
-
async sendQQMsg(contact, elements, retryCount) {
|
|
695
|
-
const list = this.initList("qq");
|
|
696
|
-
const target = contact.scene === "friend" ? "user" : "group";
|
|
697
|
-
for (const v of elements) {
|
|
698
|
-
if (v.type === "text") {
|
|
699
|
-
const { text, qr } = await this.hendleText(v.text);
|
|
700
|
-
list.content.push(text);
|
|
701
|
-
if (qr) list.image.push(qr);
|
|
702
|
-
continue;
|
|
703
|
-
}
|
|
704
|
-
if (v.type === "image") {
|
|
705
|
-
list.image.push(v.file);
|
|
706
|
-
continue;
|
|
707
|
-
}
|
|
708
|
-
if (v.type === "pasmsg") {
|
|
709
|
-
if (v.source === "event") list.pasmsg.type = "event";
|
|
710
|
-
list.pasmsg.msg_id = v.id;
|
|
711
|
-
continue;
|
|
712
|
-
}
|
|
713
|
-
if (v.type === "keyboard") {
|
|
714
|
-
list.keyboard.push(v);
|
|
715
|
-
continue;
|
|
716
|
-
}
|
|
717
|
-
if (v.type === "button") {
|
|
718
|
-
list.button.push(v);
|
|
719
|
-
continue;
|
|
720
|
-
}
|
|
721
|
-
if (v.type === "markdown") {
|
|
722
|
-
list.markdown.push(v);
|
|
723
|
-
continue;
|
|
724
|
-
}
|
|
725
|
-
if (v.type === "markdownTpl") {
|
|
726
|
-
list.markdownTpl.push(v);
|
|
727
|
-
continue;
|
|
728
|
-
}
|
|
729
|
-
if (v.type === "video" || v.type === "record") {
|
|
730
|
-
let url;
|
|
731
|
-
if (v.file.startsWith("http")) {
|
|
732
|
-
url = v.file;
|
|
733
|
-
} else {
|
|
734
|
-
const data = await fileToUrl(v.type, v.file, `${v.type}.${v.type === "record" ? "mp3" : "mp4"}`);
|
|
735
|
-
url = data.url;
|
|
736
|
-
}
|
|
737
|
-
const res = await this.super.uploadMedia(target, contact.peer, v.type, url, false);
|
|
738
|
-
list.list.push(this.super.QQdMsgOptions("media", res.file_info));
|
|
739
|
-
continue;
|
|
740
|
-
}
|
|
741
|
-
this.logger("debug", `[QQBot][${v.type}] \u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B`);
|
|
742
|
-
}
|
|
743
|
-
if (list.content.length) {
|
|
744
|
-
list.list.unshift(this.super.QQdMsgOptions("text", list.content.join("")));
|
|
745
|
-
}
|
|
746
|
-
for (const url of list.image) {
|
|
747
|
-
const base64 = await common3.base64(url);
|
|
748
|
-
const result = await this.super.uploadMedia(target, contact.peer, "image", base64, false);
|
|
749
|
-
list.list.push(this.super.QQdMsgOptions("media", result.file_info));
|
|
750
|
-
}
|
|
751
|
-
list.markdownToButton("qq", list);
|
|
752
|
-
const rawData = this.initSendMsgResults();
|
|
753
|
-
const pasmsg = (() => {
|
|
754
|
-
if (!list.pasmsg.msg_id) return () => "";
|
|
755
|
-
list.pasmsg.msg_seq++;
|
|
756
|
-
if (list.pasmsg.type === "msg") {
|
|
757
|
-
return (item) => {
|
|
758
|
-
item.msg_seq = list.pasmsg.msg_seq;
|
|
759
|
-
item.msg_id = list.pasmsg.msg_id;
|
|
760
|
-
};
|
|
761
|
-
}
|
|
762
|
-
return (item) => {
|
|
763
|
-
item.msg_seq = list.pasmsg.msg_seq;
|
|
764
|
-
item.event_id = list.pasmsg.msg_id;
|
|
765
|
-
};
|
|
766
|
-
})();
|
|
767
|
-
const send = (() => {
|
|
768
|
-
if (contact.scene === "friend") {
|
|
769
|
-
return (peer, item) => this.super.sendFriendMsg(peer, item);
|
|
770
|
-
}
|
|
771
|
-
return (peer, item) => this.super.sendGroupMsg(peer, item);
|
|
772
|
-
})();
|
|
773
|
-
if (!list.list.length) {
|
|
774
|
-
list.list.push(this.super.QQdMsgOptions("text", "\u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B"));
|
|
775
|
-
}
|
|
776
|
-
for (const item of list.list) {
|
|
777
|
-
pasmsg(item);
|
|
778
|
-
const res = await send(contact.peer, item);
|
|
779
|
-
rawData.rawData.push(res);
|
|
780
|
-
}
|
|
781
|
-
return this.handleResponse(rawData);
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* 发送频道消息
|
|
785
|
-
* @param contact 联系人
|
|
786
|
-
* @param elements 消息元素
|
|
787
|
-
* @param retryCount 重试次数
|
|
788
|
-
*/
|
|
789
|
-
async sendGuildMsg(contact, elements, retryCount) {
|
|
790
|
-
const list = this.initList("guild");
|
|
791
|
-
for (const v of elements) {
|
|
792
|
-
if (v.type === "text") {
|
|
793
|
-
const { text, qr } = await this.hendleText(v.text);
|
|
794
|
-
list.content.push(text);
|
|
795
|
-
if (qr) list.image.push(qr);
|
|
796
|
-
continue;
|
|
797
|
-
}
|
|
798
|
-
if (v.type === "image") {
|
|
799
|
-
v.file.startsWith("http") ? list.imageUrls.push(v.file) : list.imageFiles.push(v.file);
|
|
800
|
-
continue;
|
|
801
|
-
}
|
|
802
|
-
if (v.type === "at") {
|
|
803
|
-
if (contact.scene === "guild") list.content.push(v.targetId === "all" ? "@everyone" : `<@${v.targetId}>`);
|
|
804
|
-
continue;
|
|
805
|
-
}
|
|
806
|
-
if (v.type === "pasmsg") {
|
|
807
|
-
if (v.source === "event") list.pasmsg.type = "event";
|
|
808
|
-
list.pasmsg.msg_id = v.id;
|
|
809
|
-
continue;
|
|
810
|
-
}
|
|
811
|
-
if (v.type === "reply") {
|
|
812
|
-
list.reply.message_id = v.messageId;
|
|
813
|
-
continue;
|
|
814
|
-
}
|
|
815
|
-
if (v.type === "face") {
|
|
816
|
-
list.content.push(`<emoji:${v.id}>`);
|
|
817
|
-
continue;
|
|
818
|
-
}
|
|
819
|
-
if (v.type === "keyboard") {
|
|
820
|
-
list.keyboard.push(v);
|
|
821
|
-
continue;
|
|
822
|
-
}
|
|
823
|
-
if (v.type === "button") {
|
|
824
|
-
list.button.push(v);
|
|
825
|
-
continue;
|
|
826
|
-
}
|
|
827
|
-
if (v.type === "markdown") {
|
|
828
|
-
list.markdown.push(v);
|
|
829
|
-
continue;
|
|
830
|
-
}
|
|
831
|
-
if (v.type === "markdownTpl") {
|
|
832
|
-
list.markdownTpl.push(v);
|
|
833
|
-
continue;
|
|
834
|
-
}
|
|
835
|
-
this.logger("debug", `[QQBot][${v.type}] \u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B`);
|
|
836
|
-
}
|
|
837
|
-
if (list.content.length) {
|
|
838
|
-
if (list.imageUrls.length) {
|
|
839
|
-
const url = list.imageUrls.shift();
|
|
840
|
-
list.list.unshift(this.super.GuildMsgOptions("text", list.content.join(""), url));
|
|
841
|
-
}
|
|
842
|
-
if (list.imageFiles.length) {
|
|
843
|
-
const buffer = await common3.buffer(list.imageFiles.shift());
|
|
844
|
-
const formData = new FormData2();
|
|
845
|
-
formData.append("content", list.content.join(""));
|
|
846
|
-
formData.append("file_image", buffer);
|
|
847
|
-
list.list.unshift(formData);
|
|
848
|
-
} else {
|
|
849
|
-
list.list.unshift(this.super.GuildMsgOptions("text", list.content.join("")));
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
for (const url of list.imageUrls) {
|
|
853
|
-
list.list.push(this.super.GuildMsgOptions("image", url));
|
|
854
|
-
}
|
|
855
|
-
for (const file of list.imageFiles) {
|
|
856
|
-
const buffer = await common3.buffer(file);
|
|
857
|
-
const formData = new FormData2();
|
|
858
|
-
formData.append("file_image", buffer);
|
|
859
|
-
list.list.push(formData);
|
|
860
|
-
}
|
|
861
|
-
list.markdownToButton("guild", list);
|
|
862
|
-
const rawData = this.initSendMsgResults();
|
|
863
|
-
const send = (() => {
|
|
864
|
-
if (contact.scene === "guild") {
|
|
865
|
-
return (peer, subPeer, item) => this.super.sendChannelMsg(subPeer, item);
|
|
866
|
-
}
|
|
867
|
-
return (peer, subPeer, item) => this.super.sendDmsMsg(peer, item);
|
|
868
|
-
})();
|
|
869
|
-
const pasmsg = (() => {
|
|
870
|
-
if (!list.pasmsg.msg_id) return () => "";
|
|
871
|
-
if (list.pasmsg.type === "msg") {
|
|
872
|
-
return (item) => {
|
|
873
|
-
if (item instanceof FormData2) {
|
|
874
|
-
return item.append("msg_id", list.pasmsg.msg_id);
|
|
875
|
-
}
|
|
876
|
-
item.msg_id = list.pasmsg.msg_id;
|
|
877
|
-
};
|
|
878
|
-
}
|
|
879
|
-
return (item) => {
|
|
880
|
-
if (item instanceof FormData2) {
|
|
881
|
-
return item.append("event_id", list.pasmsg.msg_id);
|
|
882
|
-
}
|
|
883
|
-
item.event_id = list.pasmsg.msg_id;
|
|
884
|
-
};
|
|
885
|
-
})();
|
|
886
|
-
if (!list.list.length) {
|
|
887
|
-
list.list.push(this.super.GuildMsgOptions("text", "\u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B"));
|
|
888
|
-
}
|
|
889
|
-
for (const item of list.list) {
|
|
890
|
-
pasmsg(item);
|
|
891
|
-
const res = await send(contact.peer, contact.subPeer, item);
|
|
892
|
-
rawData.rawData.push(res);
|
|
893
|
-
}
|
|
894
|
-
return this.handleResponse(rawData);
|
|
895
|
-
}
|
|
896
|
-
};
|
|
897
|
-
|
|
898
|
-
// src/core/adapter/markdown.ts
|
|
899
|
-
import FormData3 from "form-data";
|
|
900
|
-
import { common as common4, fileToUrl as fileToUrl2, buttonHandle } from "node-karin";
|
|
901
|
-
var AdapterQQBotMarkdown = class extends AdapterQQBot {
|
|
902
|
-
_config;
|
|
903
|
-
markdown;
|
|
904
|
-
constructor(QQBot, markdown, config2) {
|
|
905
|
-
super(QQBot);
|
|
906
|
-
this.markdown = markdown;
|
|
907
|
-
this._config = config2;
|
|
908
|
-
}
|
|
909
|
-
async srcReply(e, elements) {
|
|
910
|
-
const list = await buttonHandle(e.msg, { e });
|
|
911
|
-
return this.sendMsg(e.contact, [...elements, ...list]);
|
|
912
|
-
}
|
|
913
|
-
async sendMsg(contact, elements, retryCount) {
|
|
914
|
-
if (contact.scene === "direct" || contact.scene === "guild") {
|
|
915
|
-
return this.sendGuildMsg(contact, elements, retryCount);
|
|
916
|
-
} else if (contact.scene === "group" || contact.scene === "friend") {
|
|
917
|
-
return this.sendQQMsg(contact, elements, retryCount);
|
|
918
|
-
}
|
|
919
|
-
throw new Error("\u4E0D\u652F\u6301\u7684\u6D88\u606F\u7C7B\u578B");
|
|
920
|
-
}
|
|
921
|
-
/**
|
|
922
|
-
* 处理文本 将文本中的链接转为二维码
|
|
923
|
-
* @param text 文本
|
|
924
|
-
* @returns 处理后的文本和二维码 二维码为不带`base64://`的字符串
|
|
925
|
-
*/
|
|
926
|
-
async hendleText(text) {
|
|
927
|
-
const urls = handleUrl(text);
|
|
928
|
-
if (!urls.length) return { text, qr: null };
|
|
929
|
-
urls.forEach((url) => {
|
|
930
|
-
text = text.replace(new RegExp(url, "g"), "[\u8BF7\u626B\u7801\u67E5\u770B]");
|
|
931
|
-
});
|
|
932
|
-
const list = await qrs(urls);
|
|
933
|
-
if (list.length === 1) return { text, qr: list[0] };
|
|
934
|
-
const result = await common4.mergeImage(list, 3);
|
|
935
|
-
return { text, qr: result.base64 };
|
|
936
|
-
}
|
|
937
|
-
/**
|
|
938
|
-
* 发送QQ私聊、群聊消息
|
|
939
|
-
* @param contact 联系人
|
|
940
|
-
* @param elements 消息元素
|
|
941
|
-
* @param retryCount 重试次数
|
|
942
|
-
*/
|
|
943
|
-
async sendQQMsg(contact, elements, retryCount) {
|
|
944
|
-
const list = this.initList("qq");
|
|
945
|
-
const target = contact.scene === "friend" ? "user" : "group";
|
|
946
|
-
for (const v of elements) {
|
|
947
|
-
if (v.type === "text") {
|
|
948
|
-
const { text, buttons } = textToButton(v.text, contact.scene === "friend");
|
|
949
|
-
list.content.push(text);
|
|
950
|
-
if (buttons) list.button.push(...buttons);
|
|
951
|
-
continue;
|
|
952
|
-
}
|
|
953
|
-
if (v.type === "at") {
|
|
954
|
-
if (contact.scene === "friend") continue;
|
|
955
|
-
list.content.push(v.targetId === "all" ? "<qqbot-at-everyone />" : `<qqbot-at-user id="${v.targetId}" />`);
|
|
956
|
-
}
|
|
957
|
-
if (v.type === "image") {
|
|
958
|
-
list.image.push(v.file);
|
|
959
|
-
continue;
|
|
960
|
-
}
|
|
961
|
-
if (v.type === "pasmsg") {
|
|
962
|
-
if (v.source === "event") list.pasmsg.type = "event";
|
|
963
|
-
list.pasmsg.msg_id = v.id;
|
|
964
|
-
continue;
|
|
965
|
-
}
|
|
966
|
-
if (v.type === "keyboard") {
|
|
967
|
-
list.keyboard.push(v);
|
|
968
|
-
continue;
|
|
969
|
-
}
|
|
970
|
-
if (v.type === "button") {
|
|
971
|
-
list.button.push(v);
|
|
972
|
-
continue;
|
|
973
|
-
}
|
|
974
|
-
if (v.type === "markdown") {
|
|
975
|
-
list.markdown.push(v);
|
|
976
|
-
continue;
|
|
977
|
-
}
|
|
978
|
-
if (v.type === "markdownTpl") {
|
|
979
|
-
list.markdownTpl.push(v);
|
|
980
|
-
continue;
|
|
981
|
-
}
|
|
982
|
-
if (v.type === "video" || v.type === "record") {
|
|
983
|
-
let url;
|
|
984
|
-
if (v.file.startsWith("http")) {
|
|
985
|
-
url = v.file;
|
|
986
|
-
} else {
|
|
987
|
-
const data = await fileToUrl2(v.type, v.file, `${v.type}.${v.type === "record" ? "mp3" : "mp4"}`);
|
|
988
|
-
url = data.url;
|
|
989
|
-
}
|
|
990
|
-
const res = await this.super.uploadMedia(target, contact.peer, v.type, url, false);
|
|
991
|
-
list.list.push(this.super.QQdMsgOptions("media", res.file_info));
|
|
992
|
-
continue;
|
|
993
|
-
}
|
|
994
|
-
this.logger("debug", `[QQBot][${v.type}] \u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B`);
|
|
995
|
-
}
|
|
996
|
-
const pasmsg = (() => {
|
|
997
|
-
if (!list.pasmsg.msg_id) return () => "";
|
|
998
|
-
list.pasmsg.msg_seq++;
|
|
999
|
-
if (list.pasmsg.type === "msg") {
|
|
1000
|
-
return (item) => {
|
|
1001
|
-
item.msg_seq = list.pasmsg.msg_seq;
|
|
1002
|
-
item.msg_id = list.pasmsg.msg_id;
|
|
1003
|
-
};
|
|
1004
|
-
}
|
|
1005
|
-
return (item) => {
|
|
1006
|
-
item.msg_seq = list.pasmsg.msg_seq;
|
|
1007
|
-
item.event_id = list.pasmsg.msg_id;
|
|
1008
|
-
};
|
|
1009
|
-
})();
|
|
1010
|
-
const send = (() => {
|
|
1011
|
-
if (contact.scene === "friend") {
|
|
1012
|
-
return (peer, item) => this.super.sendFriendMsg(peer, item);
|
|
1013
|
-
}
|
|
1014
|
-
return (peer, item) => this.super.sendGroupMsg(peer, item);
|
|
1015
|
-
})();
|
|
1016
|
-
return this.markdown("qq", this, list, contact, pasmsg, send);
|
|
1017
|
-
}
|
|
1018
|
-
/**
|
|
1019
|
-
* 发送频道消息
|
|
1020
|
-
* @param contact 联系人
|
|
1021
|
-
* @param elements 消息元素
|
|
1022
|
-
* @param retryCount 重试次数
|
|
1023
|
-
*/
|
|
1024
|
-
async sendGuildMsg(contact, elements, retryCount) {
|
|
1025
|
-
const list = this.initList("guild");
|
|
1026
|
-
for (const v of elements) {
|
|
1027
|
-
if (v.type === "text") {
|
|
1028
|
-
const { text, buttons } = textToButton(v.text, contact.scene === "direct");
|
|
1029
|
-
list.content.push(text);
|
|
1030
|
-
if (buttons) list.button.push(...buttons);
|
|
1031
|
-
continue;
|
|
1032
|
-
}
|
|
1033
|
-
if (v.type === "image") {
|
|
1034
|
-
list.image.push(v.file);
|
|
1035
|
-
continue;
|
|
1036
|
-
}
|
|
1037
|
-
if (v.type === "at") {
|
|
1038
|
-
if (contact.scene === "guild") {
|
|
1039
|
-
list.content.push(v.targetId === "all" ? "<qqbot-at-everyone />" : `<qqbot-at-user id="${v.targetId}" />`);
|
|
1040
|
-
}
|
|
1041
|
-
continue;
|
|
1042
|
-
}
|
|
1043
|
-
if (v.type === "pasmsg") {
|
|
1044
|
-
if (v.source === "event") list.pasmsg.type = "event";
|
|
1045
|
-
list.pasmsg.msg_id = v.id;
|
|
1046
|
-
continue;
|
|
1047
|
-
}
|
|
1048
|
-
if (v.type === "reply") {
|
|
1049
|
-
list.reply.message_id = v.messageId;
|
|
1050
|
-
continue;
|
|
1051
|
-
}
|
|
1052
|
-
if (v.type === "face") {
|
|
1053
|
-
list.content.push(`<emoji:${v.id}>`);
|
|
1054
|
-
continue;
|
|
1055
|
-
}
|
|
1056
|
-
if (v.type === "keyboard") {
|
|
1057
|
-
list.keyboard.push(v);
|
|
1058
|
-
continue;
|
|
1059
|
-
}
|
|
1060
|
-
if (v.type === "button") {
|
|
1061
|
-
list.button.push(v);
|
|
1062
|
-
continue;
|
|
1063
|
-
}
|
|
1064
|
-
if (v.type === "markdown") {
|
|
1065
|
-
list.markdown.push(v);
|
|
1066
|
-
continue;
|
|
1067
|
-
}
|
|
1068
|
-
if (v.type === "markdownTpl") {
|
|
1069
|
-
list.markdownTpl.push(v);
|
|
1070
|
-
continue;
|
|
1071
|
-
}
|
|
1072
|
-
this.logger("debug", `[QQBot][${v.type}] \u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B`);
|
|
1073
|
-
}
|
|
1074
|
-
const send = (() => {
|
|
1075
|
-
if (contact.scene === "guild") {
|
|
1076
|
-
return (peer, subPeer, item) => this.super.sendChannelMsg(subPeer, item);
|
|
1077
|
-
}
|
|
1078
|
-
return (peer, subPeer, item) => this.super.sendDmsMsg(peer, item);
|
|
1079
|
-
})();
|
|
1080
|
-
const pasmsg = (() => {
|
|
1081
|
-
if (!list.pasmsg.msg_id) return () => "";
|
|
1082
|
-
if (list.pasmsg.type === "msg") {
|
|
1083
|
-
return (item) => {
|
|
1084
|
-
if (item instanceof FormData3) {
|
|
1085
|
-
return item.append("msg_id", list.pasmsg.msg_id);
|
|
1086
|
-
}
|
|
1087
|
-
item.msg_id = list.pasmsg.msg_id;
|
|
1088
|
-
};
|
|
1089
|
-
}
|
|
1090
|
-
return (item) => {
|
|
1091
|
-
if (item instanceof FormData3) {
|
|
1092
|
-
return item.append("event_id", list.pasmsg.msg_id);
|
|
1093
|
-
}
|
|
1094
|
-
item.event_id = list.pasmsg.msg_id;
|
|
1095
|
-
};
|
|
1096
|
-
})();
|
|
1097
|
-
return this.markdown("guild", this, list, contact, pasmsg, send);
|
|
1098
|
-
}
|
|
1099
|
-
};
|
|
1100
|
-
|
|
1101
|
-
// src/core/internal/axios.ts
|
|
1102
|
-
import axios from "node-karin/axios";
|
|
1103
|
-
var BotMap = /* @__PURE__ */ new Map();
|
|
1104
|
-
var getAccessToken = async (url, appId, secret) => {
|
|
1105
|
-
const response = await axios.post(url, {
|
|
1106
|
-
appId: String(appId),
|
|
1107
|
-
clientSecret: secret
|
|
1108
|
-
});
|
|
1109
|
-
const { access_token: accessToken, expires_in: expiresIn } = response.data;
|
|
1110
|
-
if (!accessToken || !expiresIn) {
|
|
1111
|
-
throw new Error(`\u83B7\u53D6\u8C03\u7528\u51ED\u8BC1\u5931\u8D25: ${JSON.stringify(response.data)}`);
|
|
1112
|
-
}
|
|
1113
|
-
BotMap.set(appId, accessToken);
|
|
1114
|
-
setTimeout(() => {
|
|
1115
|
-
getAccessToken(url, appId, secret);
|
|
1116
|
-
}, Number(expiresIn) * 1e3 - 5e4);
|
|
1117
|
-
return { accessToken, expiresIn };
|
|
1118
|
-
};
|
|
1119
|
-
var createAxiosInstance = (url, appId) => {
|
|
1120
|
-
const instance = axios.create({
|
|
1121
|
-
baseURL: url,
|
|
1122
|
-
headers: {
|
|
1123
|
-
"Content-Type": "application/json"
|
|
1124
|
-
},
|
|
1125
|
-
timeout: 5500
|
|
1126
|
-
});
|
|
1127
|
-
instance.interceptors.request.use(
|
|
1128
|
-
(config2) => {
|
|
1129
|
-
config2.headers.Authorization = `QQBot ${BotMap.get(appId)}`;
|
|
1130
|
-
return config2;
|
|
1131
|
-
}
|
|
1132
|
-
);
|
|
1133
|
-
return instance;
|
|
1134
|
-
};
|
|
1135
|
-
|
|
1136
|
-
// src/core/adapter/handler.ts
|
|
1137
|
-
import { common as common5, fileToUrl as fileToUrl3, segment as segment2 } from "node-karin";
|
|
1138
|
-
var rawMarkdown = async (type, ctx, list, contact, pasmsg, send) => {
|
|
1139
|
-
await Promise.all(list.image.map(async (file) => {
|
|
1140
|
-
if (file.startsWith("http")) {
|
|
1141
|
-
const { width: width2, height: height2 } = await getImageSize(file);
|
|
1142
|
-
list.content.push(``);
|
|
1143
|
-
return;
|
|
1144
|
-
}
|
|
1145
|
-
const { url, width, height } = await fileToUrl3("image", file, "image.jpg");
|
|
1146
|
-
list.content.push(``);
|
|
1147
|
-
}));
|
|
1148
|
-
list.markdown.push(segment2.markdown(list.content.join("")));
|
|
1149
|
-
list.markdownToButton(type, list);
|
|
1150
|
-
const rawData = ctx.initSendMsgResults();
|
|
1151
|
-
if (type === "qq") {
|
|
1152
|
-
if (!list.list.length) {
|
|
1153
|
-
const options = ctx.super.QQdMsgOptions("text", "\u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B");
|
|
1154
|
-
list.list.push(options);
|
|
1155
|
-
}
|
|
1156
|
-
for (const item of list.list) {
|
|
1157
|
-
pasmsg(item);
|
|
1158
|
-
const res = await send(contact.peer, item);
|
|
1159
|
-
rawData.rawData.push(res);
|
|
1160
|
-
}
|
|
1161
|
-
return ctx.handleResponse(rawData);
|
|
1162
|
-
}
|
|
1163
|
-
if (!list.list.length) {
|
|
1164
|
-
const options = ctx.super.GuildMsgOptions("text", "\u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B");
|
|
1165
|
-
list.list.push(options);
|
|
1166
|
-
}
|
|
1167
|
-
for (const item of list.list) {
|
|
1168
|
-
pasmsg(item);
|
|
1169
|
-
const res = await send(contact.peer, contact.subPeer, item);
|
|
1170
|
-
rawData.rawData.push(res);
|
|
1171
|
-
}
|
|
1172
|
-
return ctx.handleResponse(rawData);
|
|
1173
|
-
};
|
|
1174
|
-
var GraphicTemplateMarkdown = async (type, ctx, list, contact, pasmsg, send) => {
|
|
1175
|
-
const KV = (index, value) => {
|
|
1176
|
-
return { key: kv[index], values: [value] };
|
|
1177
|
-
};
|
|
1178
|
-
const tpl = (content2, desc, url) => {
|
|
1179
|
-
if (desc && url) {
|
|
1180
|
-
return segment2.markdownTpl(id, [KV(0, content2), KV(1, desc), KV(2, url)]);
|
|
1181
|
-
}
|
|
1182
|
-
if (desc) {
|
|
1183
|
-
return segment2.markdownTpl(id, [KV(1, content2), KV(2, desc)]);
|
|
1184
|
-
}
|
|
1185
|
-
return segment2.markdownTpl(id, [KV(0, content2)]);
|
|
1186
|
-
};
|
|
1187
|
-
const imageHandler = async (file) => {
|
|
1188
|
-
if (file.startsWith("http")) {
|
|
1189
|
-
const { width, height } = await getImageSize(file);
|
|
1190
|
-
return { url: file, width, height };
|
|
1191
|
-
}
|
|
1192
|
-
const data = await fileToUrl3("image", file, "image.jpg");
|
|
1193
|
-
return data;
|
|
1194
|
-
};
|
|
1195
|
-
const { kv, id } = ctx._config.markdown;
|
|
1196
|
-
const content = escapeMarkdown(list.content.join(""));
|
|
1197
|
-
const img = list.image.shift();
|
|
1198
|
-
if (img) {
|
|
1199
|
-
const { url, width, height } = await imageHandler(img);
|
|
1200
|
-
list.markdownTpl.push(tpl(content, `karin #${width}px #${height}px`, url));
|
|
1201
|
-
} else {
|
|
1202
|
-
list.markdownTpl.push(tpl(content));
|
|
1203
|
-
}
|
|
1204
|
-
await Promise.all(list.image.map(async (file, index) => {
|
|
1205
|
-
await common5.sleep(index * 100);
|
|
1206
|
-
const { url, width, height } = await imageHandler(file);
|
|
1207
|
-
list.markdownTpl.push(tpl(`karin #${width}px #${height}px`, url));
|
|
1208
|
-
}));
|
|
1209
|
-
list.markdownToButton(type, list);
|
|
1210
|
-
const rawData = ctx.initSendMsgResults();
|
|
1211
|
-
if (type === "qq") {
|
|
1212
|
-
if (!list.list.length) {
|
|
1213
|
-
const options = ctx.super.QQdMsgOptions("text", "\u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B");
|
|
1214
|
-
list.list.push(options);
|
|
1215
|
-
}
|
|
1216
|
-
for (const item of list.list) {
|
|
1217
|
-
pasmsg(item);
|
|
1218
|
-
const res = await send(contact.peer, item);
|
|
1219
|
-
rawData.rawData.push(res);
|
|
1220
|
-
}
|
|
1221
|
-
return ctx.handleResponse(rawData);
|
|
1222
|
-
}
|
|
1223
|
-
if (!list.list.length) {
|
|
1224
|
-
const options = ctx.super.GuildMsgOptions("text", "\u4E0D\u652F\u6301\u53D1\u9001\u7684\u6D88\u606F\u7C7B\u578B");
|
|
1225
|
-
list.list.push(options);
|
|
1226
|
-
}
|
|
1227
|
-
for (const item of list.list) {
|
|
1228
|
-
pasmsg(item);
|
|
1229
|
-
const res = await send(contact.peer, contact.subPeer, item);
|
|
1230
|
-
rawData.rawData.push(res);
|
|
1231
|
-
}
|
|
1232
|
-
return ctx.handleResponse(rawData);
|
|
1233
|
-
};
|
|
1234
|
-
|
|
1235
|
-
// src/core/event/conver.ts
|
|
1236
|
-
import { segment as segment3 } from "node-karin";
|
|
1237
|
-
var QQBotConvertKarin = (appid, event2, subBotID) => {
|
|
1238
|
-
var _a, _b;
|
|
1239
|
-
const elements = [];
|
|
1240
|
-
const data = event2.d;
|
|
1241
|
-
const mentions = {};
|
|
1242
|
-
if (event2.t === "MESSAGE_CREATE" /* MESSAGE_CREATE */ || event2.t === "AT_MESSAGE_CREATE" /* AT_MESSAGE_CREATE */) {
|
|
1243
|
-
(_a = event2.d.mentions) == null ? void 0 : _a.forEach((v) => {
|
|
1244
|
-
mentions[v.id] = v;
|
|
1245
|
-
});
|
|
1246
|
-
}
|
|
1247
|
-
for (const v of data.attachments || []) {
|
|
1248
|
-
if (v.content_type === "file") {
|
|
1249
|
-
console.log(v);
|
|
1250
|
-
continue;
|
|
1251
|
-
}
|
|
1252
|
-
const url = v.url.startsWith("http") ? v.url : `https://${v.url}`;
|
|
1253
|
-
elements.push(segment3.image(url, {
|
|
1254
|
-
subType: v.content_type.split("/")[1],
|
|
1255
|
-
name: v.filename,
|
|
1256
|
-
width: v.width,
|
|
1257
|
-
height: v.height
|
|
1258
|
-
}));
|
|
1259
|
-
}
|
|
1260
|
-
const regex = /<faceType=\d+,faceId="\d+",ext="[^"]+">|<@!\d+>|[^<]+/g;
|
|
1261
|
-
const result = ((_b = data == null ? void 0 : data.content) == null ? void 0 : _b.match(regex)) || [];
|
|
1262
|
-
result.forEach((v) => {
|
|
1263
|
-
var _a2;
|
|
1264
|
-
if (v.startsWith("<faceType=")) {
|
|
1265
|
-
const Match = v.match(/faceId="(\d+)"/);
|
|
1266
|
-
elements.push(segment3.face(Number(Match[1])));
|
|
1267
|
-
}
|
|
1268
|
-
if (v.startsWith("<@!")) {
|
|
1269
|
-
const id = v.replace(/^<@!|>$/g, "");
|
|
1270
|
-
const name = ((_a2 = mentions[id]) == null ? void 0 : _a2.username) || "";
|
|
1271
|
-
elements.push(segment3.at(id === subBotID ? appid : id, name));
|
|
1272
|
-
} else {
|
|
1273
|
-
const cfg = getConfig(appid);
|
|
1274
|
-
if (cfg == null ? void 0 : cfg.regex) {
|
|
1275
|
-
for (const r of cfg.regex) {
|
|
1276
|
-
const reg = r.reg instanceof RegExp ? r.reg : new RegExp(r.reg);
|
|
1277
|
-
v = v.trim().replace(reg, r.rep);
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
elements.push(segment3.text(v));
|
|
1281
|
-
}
|
|
1282
|
-
});
|
|
1283
|
-
if (event2.t === "GROUP_AT_MESSAGE_CREATE" /* GROUP_AT_MESSAGE_CREATE */) {
|
|
1284
|
-
elements.unshift(segment3.at(appid));
|
|
1285
|
-
}
|
|
1286
|
-
return elements;
|
|
1287
|
-
};
|
|
1288
|
-
|
|
1289
|
-
// src/core/event/message.ts
|
|
1290
|
-
import {
|
|
1291
|
-
karin,
|
|
1292
|
-
createGroupMessage,
|
|
1293
|
-
createFriendMessage,
|
|
1294
|
-
segment as segment4,
|
|
1295
|
-
createGuildMessage,
|
|
1296
|
-
createDirectMessage
|
|
1297
|
-
} from "node-karin";
|
|
1298
|
-
var onGroupMsg = (client, event2) => {
|
|
1299
|
-
const selfId = client.selfId;
|
|
1300
|
-
const userId = event2.d.author.member_openid;
|
|
1301
|
-
const contact = karin.contactGroup(event2.d.group_id);
|
|
1302
|
-
const sender = karin.groupSender(userId, "unknown");
|
|
1303
|
-
const e = createGroupMessage({
|
|
1304
|
-
bot: client,
|
|
1305
|
-
elements: QQBotConvertKarin(selfId, event2, client.selfSubId("id")),
|
|
1306
|
-
eventId: event2.id,
|
|
1307
|
-
messageId: event2.d.id,
|
|
1308
|
-
messageSeq: 0,
|
|
1309
|
-
rawEvent: event2,
|
|
1310
|
-
time: Number(event2.d.timestamp),
|
|
1311
|
-
contact,
|
|
1312
|
-
sender,
|
|
1313
|
-
srcReply: (elements) => client.srcReply(e, [...elements, segment4.pasmsg(event2.d.id)])
|
|
1314
|
-
});
|
|
1315
|
-
};
|
|
1316
|
-
var onFriendMsg = (client, event2) => {
|
|
1317
|
-
const selfId = client.selfId;
|
|
1318
|
-
const userId = event2.d.author.user_openid;
|
|
1319
|
-
const contact = karin.contactFriend(userId);
|
|
1320
|
-
const sender = karin.friendSender(userId, "");
|
|
1321
|
-
const e = createFriendMessage({
|
|
1322
|
-
bot: client,
|
|
1323
|
-
elements: QQBotConvertKarin(selfId, event2, client.selfSubId("id")),
|
|
1324
|
-
eventId: event2.id,
|
|
1325
|
-
messageId: event2.d.id,
|
|
1326
|
-
messageSeq: 0,
|
|
1327
|
-
rawEvent: event2,
|
|
1328
|
-
time: Number(event2.d.timestamp),
|
|
1329
|
-
contact,
|
|
1330
|
-
sender,
|
|
1331
|
-
srcReply: (elements) => client.srcReply(e, [...elements, segment4.pasmsg(event2.d.id)])
|
|
1332
|
-
});
|
|
1333
|
-
};
|
|
1334
|
-
var onChannelMsg = (client, event2) => {
|
|
1335
|
-
const selfId = client.selfId;
|
|
1336
|
-
const userId = event2.d.author.id;
|
|
1337
|
-
const contact = karin.contact("guild", event2.d.guild_id, event2.d.channel_id);
|
|
1338
|
-
const sender = karin.groupSender(userId, "unknown", event2.d.author.username);
|
|
1339
|
-
const e = createGuildMessage({
|
|
1340
|
-
bot: client,
|
|
1341
|
-
elements: QQBotConvertKarin(selfId, event2, client.selfSubId("id")),
|
|
1342
|
-
eventId: event2.id,
|
|
1343
|
-
messageId: event2.d.id,
|
|
1344
|
-
messageSeq: 0,
|
|
1345
|
-
rawEvent: event2,
|
|
1346
|
-
time: Number(event2.d.timestamp),
|
|
1347
|
-
contact,
|
|
1348
|
-
sender,
|
|
1349
|
-
srcReply: (elements) => client.srcReply(e, [...elements, segment4.pasmsg(event2.d.id)])
|
|
1350
|
-
});
|
|
1351
|
-
};
|
|
1352
|
-
var onDirectMsg = (client, event2) => {
|
|
1353
|
-
const selfId = client.selfId;
|
|
1354
|
-
const userId = event2.d.author.id;
|
|
1355
|
-
const contact = karin.contact("direct", event2.d.guild_id, event2.d.channel_id);
|
|
1356
|
-
const sender = karin.friendSender(userId, event2.d.author.username);
|
|
1357
|
-
const e = createDirectMessage({
|
|
1358
|
-
bot: client,
|
|
1359
|
-
elements: QQBotConvertKarin(selfId, event2, client.selfSubId("id")),
|
|
1360
|
-
eventId: event2.id,
|
|
1361
|
-
messageId: event2.d.id,
|
|
1362
|
-
messageSeq: 0,
|
|
1363
|
-
rawEvent: event2,
|
|
1364
|
-
time: Number(event2.d.timestamp),
|
|
1365
|
-
contact,
|
|
1366
|
-
sender,
|
|
1367
|
-
srcGuildId: event2.d.src_guild_id,
|
|
1368
|
-
srcReply: (elements) => client.srcReply(e, [...elements, segment4.pasmsg(event2.d.id)])
|
|
1369
|
-
});
|
|
1370
|
-
};
|
|
1371
|
-
|
|
1372
|
-
// src/core/event/notice.ts
|
|
1373
|
-
import {
|
|
1374
|
-
karin as karin2,
|
|
1375
|
-
segment as segment5,
|
|
1376
|
-
createGroupMemberAddNotice,
|
|
1377
|
-
createGroupMemberDelNotice,
|
|
1378
|
-
createFriendIncreaseNotice,
|
|
1379
|
-
createFriendDecreaseNotice
|
|
1380
|
-
} from "node-karin";
|
|
1381
|
-
var onGroupAddRobot = (client, event2) => {
|
|
1382
|
-
const selfId = client.selfId;
|
|
1383
|
-
const userId = event2.d.op_member_openid;
|
|
1384
|
-
const groupId = event2.d.group_openid;
|
|
1385
|
-
const contact = karin2.contactGroup(groupId);
|
|
1386
|
-
const sender = karin2.groupSender(userId, "unknown");
|
|
1387
|
-
const eventId = event2.id;
|
|
1388
|
-
const srcReply = (elements) => client.sendMsg(contact, [...elements, segment5.pasmsg(eventId, "event")]);
|
|
1389
|
-
createGroupMemberAddNotice({
|
|
1390
|
-
contact,
|
|
1391
|
-
eventId,
|
|
1392
|
-
sender,
|
|
1393
|
-
srcReply,
|
|
1394
|
-
bot: client,
|
|
1395
|
-
rawEvent: event2,
|
|
1396
|
-
time: event2.d.timestamp,
|
|
1397
|
-
content: { operatorId: userId, targetId: selfId, type: "invite" }
|
|
1398
|
-
});
|
|
1399
|
-
};
|
|
1400
|
-
var onGroupDelRobot = (client, event2) => {
|
|
1401
|
-
const selfId = client.selfId;
|
|
1402
|
-
const userId = event2.d.op_member_openid;
|
|
1403
|
-
const groupId = event2.d.group_openid;
|
|
1404
|
-
const contact = karin2.contactGroup(groupId);
|
|
1405
|
-
const sender = karin2.groupSender(userId, "unknown");
|
|
1406
|
-
const eventId = event2.id;
|
|
1407
|
-
const srcReply = (elements) => client.sendMsg(contact, [...elements, segment5.pasmsg(eventId, "event")]);
|
|
1408
|
-
createGroupMemberDelNotice({
|
|
1409
|
-
contact,
|
|
1410
|
-
eventId,
|
|
1411
|
-
sender,
|
|
1412
|
-
srcReply,
|
|
1413
|
-
bot: client,
|
|
1414
|
-
rawEvent: event2,
|
|
1415
|
-
time: event2.d.timestamp,
|
|
1416
|
-
content: { operatorId: userId, targetId: selfId, type: "kick" }
|
|
1417
|
-
});
|
|
1418
|
-
};
|
|
1419
|
-
|
|
1420
|
-
// src/core/index.ts
|
|
1421
|
-
var initQQBotAdapter = async () => {
|
|
1422
|
-
const cfg = config();
|
|
1423
|
-
cfg.forEach((bot) => createBot(bot));
|
|
1424
|
-
};
|
|
1425
|
-
var createBot = async (bot) => {
|
|
1426
|
-
if (bot.event.type === 0) {
|
|
1427
|
-
log("debug", `${bot.appId}: bot\u5DF2\u5173\u95ED\uFF0C\u8DF3\u8FC7\u521D\u59CB\u5316`);
|
|
1428
|
-
return;
|
|
1429
|
-
}
|
|
1430
|
-
const appId = String(bot.appId);
|
|
1431
|
-
await getAccessToken(bot.tokenApi, appId, bot.secret);
|
|
1432
|
-
const url = bot.sandbox ? bot.sandboxApi : bot.prodApi;
|
|
1433
|
-
const axios2 = createAxiosInstance(url, appId);
|
|
1434
|
-
const api = new QQBotApi(axios2);
|
|
1435
|
-
const data = await api.getMe();
|
|
1436
|
-
const { id, username, avatar } = data;
|
|
1437
|
-
const client = createClient(bot, api);
|
|
1438
|
-
client.account.name = username;
|
|
1439
|
-
client.account.avatar = avatar;
|
|
1440
|
-
client.account.selfId = appId;
|
|
1441
|
-
const qq = new URL(data.share_url).searchParams.get("robot_uin");
|
|
1442
|
-
client.account.subId.id = id;
|
|
1443
|
-
client.account.subId.qq = qq;
|
|
1444
|
-
client.account.subId.appid = appId;
|
|
1445
|
-
client.account.subId.union_openid = data.union_openid;
|
|
1446
|
-
event.on(appId, (event2) => createEvent(client, event2));
|
|
1447
|
-
client.adapter.address = url;
|
|
1448
|
-
client.adapter.secret = bot.secret;
|
|
1449
|
-
client.adapter.version = pkg().version;
|
|
1450
|
-
if (bot.event.type === 1) {
|
|
1451
|
-
client.adapter.index = registerBot("webSocketClient", client);
|
|
1452
|
-
createWebSocketConnection(bot);
|
|
1453
|
-
} else {
|
|
1454
|
-
client.adapter.index = registerBot("http", client);
|
|
1455
|
-
}
|
|
1456
|
-
};
|
|
1457
|
-
var createClient = (cfg, api) => {
|
|
1458
|
-
var _a;
|
|
1459
|
-
const mode = Number((_a = cfg.markdown) == null ? void 0 : _a.mode) || 0;
|
|
1460
|
-
if (mode === 0) {
|
|
1461
|
-
return new AdapterQQBotNormal(api);
|
|
1462
|
-
}
|
|
1463
|
-
if (mode === 1) {
|
|
1464
|
-
return new AdapterQQBotMarkdown(api, rawMarkdown, cfg);
|
|
1465
|
-
}
|
|
1466
|
-
if (mode >= 3 && mode <= 5) {
|
|
1467
|
-
return new AdapterQQBotMarkdown(api, GraphicTemplateMarkdown, cfg);
|
|
1468
|
-
}
|
|
1469
|
-
return new AdapterQQBotNormal(api);
|
|
1470
|
-
};
|
|
1471
|
-
var createEvent = (client, event2) => {
|
|
1472
|
-
switch (event2.t) {
|
|
1473
|
-
case "GROUP_AT_MESSAGE_CREATE" /* GROUP_AT_MESSAGE_CREATE */:
|
|
1474
|
-
return onGroupMsg(client, event2);
|
|
1475
|
-
case "C2C_MESSAGE_CREATE" /* C2C_MESSAGE_CREATE */:
|
|
1476
|
-
return onFriendMsg(client, event2);
|
|
1477
|
-
case "MESSAGE_CREATE" /* MESSAGE_CREATE */:
|
|
1478
|
-
case "AT_MESSAGE_CREATE" /* AT_MESSAGE_CREATE */:
|
|
1479
|
-
return onChannelMsg(client, event2);
|
|
1480
|
-
case "DIRECT_MESSAGE_CREATE" /* DIRECT_MESSAGE_CREATE */:
|
|
1481
|
-
return onDirectMsg(client, event2);
|
|
1482
|
-
case "GROUP_ADD_ROBOT" /* GROUP_ADD_ROBOT */:
|
|
1483
|
-
return onGroupAddRobot(client, event2);
|
|
1484
|
-
case "GROUP_DEL_ROBOT" /* GROUP_DEL_ROBOT */:
|
|
1485
|
-
return onGroupDelRobot(client, event2);
|
|
1486
|
-
default:
|
|
1487
|
-
logger4.error(`\u672A\u77E5\u4E8B\u4EF6\u7C7B\u578B: ${JSON.stringify(event2)}`);
|
|
1488
|
-
}
|
|
1489
|
-
};
|
|
1490
|
-
|
|
1491
|
-
export {
|
|
1492
|
-
basename,
|
|
1493
|
-
sign,
|
|
1494
|
-
event,
|
|
1495
|
-
fakeEvent,
|
|
1496
|
-
initQQBotAdapter,
|
|
1497
|
-
pkg,
|
|
1498
|
-
getConfig,
|
|
1499
|
-
writeConfig,
|
|
1500
|
-
config_exports
|
|
1501
|
-
};
|