@onebots/adapter-icqq 1.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/lib/bot.js ADDED
@@ -0,0 +1,593 @@
1
+ /**
2
+ * ICQQ Bot 封装
3
+ * 基于 @icqqjs/icqq 库封装的机器人客户端
4
+ */
5
+ import { EventEmitter } from 'events';
6
+ import { createClient, segment as Segment } from '@icqqjs/icqq';
7
+ export class ICQQBot extends EventEmitter {
8
+ config;
9
+ client = null;
10
+ ready = false;
11
+ loginInfo = null;
12
+ constructor(config) {
13
+ super();
14
+ this.config = config;
15
+ }
16
+ /**
17
+ * 获取 ICQQ 客户端实例
18
+ */
19
+ getClient() {
20
+ return this.client;
21
+ }
22
+ /**
23
+ * 是否已就绪
24
+ */
25
+ isReady() {
26
+ return this.ready;
27
+ }
28
+ /**
29
+ * 获取登录信息
30
+ */
31
+ getLoginInfo() {
32
+ return this.loginInfo;
33
+ }
34
+ /**
35
+ * 启动 Bot
36
+ */
37
+ async start() {
38
+ const uin = parseInt(this.config.account_id);
39
+ if (isNaN(uin)) {
40
+ throw new Error('account_id 必须是有效的 QQ 号');
41
+ }
42
+ // 构建 ICQQ 配置
43
+ const protocol = this.config.protocol || {};
44
+ const clientConfig = {
45
+ platform: protocol.platform || 2,
46
+ sign_api_addr: protocol.sign_api_addr,
47
+ data_dir: protocol.data_dir,
48
+ ignore_self: protocol.ignore_self !== false,
49
+ resend: protocol.resend !== false,
50
+ reconn_interval: protocol.reconn_interval || 5,
51
+ cache_group_member: protocol.cache_group_member !== false,
52
+ auto_server: protocol.auto_server !== false,
53
+ };
54
+ if (protocol.ver) {
55
+ clientConfig.ver = protocol.ver;
56
+ }
57
+ if (protocol.log_config) {
58
+ clientConfig.log_config = protocol.log_config;
59
+ }
60
+ if (protocol.ffmpeg_path) {
61
+ clientConfig.ffmpeg_path = protocol.ffmpeg_path;
62
+ }
63
+ if (protocol.ffprobe_path) {
64
+ clientConfig.ffprobe_path = protocol.ffprobe_path;
65
+ }
66
+ // 创建客户端
67
+ this.client = createClient(clientConfig);
68
+ // 绑定事件
69
+ this.setupEventListeners();
70
+ // 登录
71
+ if (this.config.password) {
72
+ // 密码登录
73
+ this.client.login(uin, this.config.password);
74
+ }
75
+ else {
76
+ // 扫码登录
77
+ this.client.login(uin);
78
+ }
79
+ }
80
+ /**
81
+ * 停止 Bot
82
+ */
83
+ async stop() {
84
+ if (this.client) {
85
+ this.client.logout();
86
+ this.client = null;
87
+ }
88
+ this.ready = false;
89
+ this.loginInfo = null;
90
+ this.emit('stop');
91
+ }
92
+ /**
93
+ * 设置事件监听器
94
+ */
95
+ setupEventListeners() {
96
+ if (!this.client)
97
+ return;
98
+ // 登录成功
99
+ this.client.on('system.login.qrcode', (event) => {
100
+ this.emit('qrcode', event);
101
+ });
102
+ this.client.on('system.login.slider', (event) => {
103
+ this.emit('slider', event);
104
+ });
105
+ this.client.on('system.login.device', (event) => {
106
+ this.emit('device', event);
107
+ });
108
+ this.client.on('system.login.error', (event) => {
109
+ this.emit('login_error', event);
110
+ });
111
+ this.client.on('system.online', () => {
112
+ this.ready = true;
113
+ this.loginInfo = {
114
+ user_id: this.client.uin,
115
+ nickname: this.client.nickname,
116
+ avatar: `https://q1.qlogo.cn/g?b=qq&nk=${this.client.uin}&s=640`,
117
+ };
118
+ this.emit('ready', this.loginInfo);
119
+ });
120
+ this.client.on('system.offline', (event) => {
121
+ this.ready = false;
122
+ this.emit('offline', event);
123
+ });
124
+ // 私聊消息
125
+ this.client.on('message.private', (event) => {
126
+ this.emit('private_message', this.convertPrivateMessage(event));
127
+ });
128
+ // 群消息
129
+ this.client.on('message.group', (event) => {
130
+ this.emit('group_message', this.convertGroupMessage(event));
131
+ });
132
+ // 好友申请
133
+ this.client.on('request.friend', (event) => {
134
+ this.emit('friend_request', {
135
+ request_id: event.flag,
136
+ user_id: event.user_id,
137
+ nickname: event.nickname,
138
+ comment: event.comment,
139
+ source: event.source,
140
+ time: event.time || Date.now() / 1000,
141
+ });
142
+ });
143
+ // 群申请/邀请
144
+ this.client.on('request.group', (event) => {
145
+ this.emit('group_request', {
146
+ request_id: event.flag,
147
+ group_id: event.group_id,
148
+ user_id: event.user_id,
149
+ nickname: event.nickname,
150
+ sub_type: event.sub_type,
151
+ comment: event.comment || '',
152
+ time: event.time || Date.now() / 1000,
153
+ });
154
+ });
155
+ // 群成员增加
156
+ this.client.on('notice.group.increase', (event) => {
157
+ this.emit('group_increase', {
158
+ group_id: event.group_id,
159
+ user_id: event.user_id,
160
+ operator_id: undefined,
161
+ time: Date.now() / 1000,
162
+ });
163
+ });
164
+ // 群成员减少
165
+ this.client.on('notice.group.decrease', (event) => {
166
+ this.emit('group_decrease', {
167
+ group_id: event.group_id,
168
+ user_id: event.user_id,
169
+ operator_id: event.operator_id,
170
+ sub_type: event.dismiss ? 'dismiss' : 'leave',
171
+ time: Date.now() / 1000,
172
+ });
173
+ });
174
+ // 群禁言
175
+ this.client.on('notice.group.ban', (event) => {
176
+ this.emit('group_mute', {
177
+ group_id: event.group_id,
178
+ user_id: event.user_id,
179
+ operator_id: event.operator_id,
180
+ duration: event.duration,
181
+ time: Date.now() / 1000,
182
+ });
183
+ });
184
+ // 群管理员变动
185
+ this.client.on('notice.group.admin', (event) => {
186
+ this.emit('group_admin', {
187
+ group_id: event.group_id,
188
+ user_id: event.user_id,
189
+ sub_type: event.set ? 'set' : 'unset',
190
+ time: Date.now() / 1000,
191
+ });
192
+ });
193
+ // 好友消息撤回
194
+ this.client.on('notice.friend.recall', (event) => {
195
+ this.emit('friend_recall', {
196
+ message_id: event.message_id,
197
+ user_id: event.user_id,
198
+ time: event.time,
199
+ });
200
+ });
201
+ // 群消息撤回
202
+ this.client.on('notice.group.recall', (event) => {
203
+ this.emit('group_recall', {
204
+ message_id: event.message_id,
205
+ group_id: event.group_id,
206
+ user_id: event.user_id,
207
+ operator_id: event.operator_id,
208
+ time: event.time,
209
+ });
210
+ });
211
+ // 戳一戳
212
+ this.client.on('notice.friend.poke', (event) => {
213
+ this.emit('poke', {
214
+ operator_id: event.operator_id,
215
+ target_id: event.target_id,
216
+ action: event.action,
217
+ suffix: event.suffix,
218
+ time: Date.now() / 1000,
219
+ });
220
+ });
221
+ this.client.on('notice.group.poke', (event) => {
222
+ this.emit('poke', {
223
+ group_id: event.group_id,
224
+ operator_id: event.operator_id,
225
+ target_id: event.target_id,
226
+ action: event.action,
227
+ suffix: event.suffix,
228
+ time: Date.now() / 1000,
229
+ });
230
+ });
231
+ }
232
+ /**
233
+ * 转换私聊消息
234
+ */
235
+ convertPrivateMessage(event) {
236
+ return {
237
+ message_id: event.message_id,
238
+ user_id: event.user_id,
239
+ message: this.convertMessage(event.message),
240
+ raw_message: event.raw_message,
241
+ time: event.time,
242
+ sender: {
243
+ user_id: event.sender.user_id,
244
+ nickname: event.sender.nickname,
245
+ sex: event.sender.sex,
246
+ age: event.sender.age,
247
+ },
248
+ reply: (message, quote) => {
249
+ return event.reply(message, quote);
250
+ },
251
+ };
252
+ }
253
+ /**
254
+ * 转换群消息
255
+ */
256
+ convertGroupMessage(event) {
257
+ return {
258
+ message_id: event.message_id,
259
+ group_id: event.group_id,
260
+ user_id: event.user_id,
261
+ message: this.convertMessage(event.message),
262
+ raw_message: event.raw_message,
263
+ time: event.time,
264
+ sender: {
265
+ user_id: event.sender.user_id,
266
+ nickname: event.sender.nickname,
267
+ card: event.sender.card,
268
+ sex: event.sender.sex,
269
+ age: event.sender.age,
270
+ role: event.sender.role,
271
+ title: event.sender.title,
272
+ },
273
+ group: {
274
+ group_id: event.group_id,
275
+ group_name: event.group_name,
276
+ },
277
+ atme: event.atme,
278
+ reply: (message, quote) => {
279
+ return event.reply(message, quote);
280
+ },
281
+ };
282
+ }
283
+ /**
284
+ * 转换消息段
285
+ */
286
+ convertMessage(message) {
287
+ return message.map((elem) => {
288
+ switch (elem.type) {
289
+ case 'text':
290
+ return { type: 'text', text: elem.text };
291
+ case 'face':
292
+ return { type: 'face', id: elem.id };
293
+ case 'image':
294
+ return { type: 'image', file: elem.file, url: elem.url };
295
+ case 'record':
296
+ return { type: 'record', file: elem.file, url: elem.url };
297
+ case 'video':
298
+ return { type: 'video', file: elem.file, url: elem.url };
299
+ case 'at':
300
+ return { type: 'at', qq: elem.qq };
301
+ case 'share':
302
+ return { type: 'share', url: elem.url, title: elem.title, content: elem.content, image: elem.image };
303
+ case 'json':
304
+ return { type: 'json', data: elem.data };
305
+ case 'xml':
306
+ return { type: 'xml', data: elem.data };
307
+ case 'poke':
308
+ return { type: 'poke', id: elem.id };
309
+ case 'reply':
310
+ return { type: 'reply', id: elem.id };
311
+ default:
312
+ return { type: 'text', text: `[${elem.type}]` };
313
+ }
314
+ });
315
+ }
316
+ // ============================================
317
+ // 消息发送 API
318
+ // ============================================
319
+ /**
320
+ * 发送私聊消息
321
+ */
322
+ async sendPrivateMessage(userId, message) {
323
+ if (!this.client)
324
+ throw new Error('Bot not connected');
325
+ return this.client.sendPrivateMsg(userId, message);
326
+ }
327
+ /**
328
+ * 发送群消息
329
+ */
330
+ async sendGroupMessage(groupId, message) {
331
+ if (!this.client)
332
+ throw new Error('Bot not connected');
333
+ return this.client.sendGroupMsg(groupId, message);
334
+ }
335
+ /**
336
+ * 撤回消息
337
+ */
338
+ async recallMessage(messageId) {
339
+ if (!this.client)
340
+ throw new Error('Bot not connected');
341
+ return this.client.deleteMsg(messageId);
342
+ }
343
+ /**
344
+ * 获取消息
345
+ */
346
+ async getMessage(messageId) {
347
+ if (!this.client)
348
+ throw new Error('Bot not connected');
349
+ return this.client.getMsg(messageId);
350
+ }
351
+ // ============================================
352
+ // 好友 API
353
+ // ============================================
354
+ /**
355
+ * 获取好友列表
356
+ */
357
+ async getFriendList() {
358
+ if (!this.client)
359
+ throw new Error('Bot not connected');
360
+ const friends = this.client.fl;
361
+ return Array.from(friends.values()).map((friend) => ({
362
+ user_id: friend.user_id,
363
+ nickname: friend.nickname,
364
+ sex: friend.sex,
365
+ remark: friend.remark,
366
+ class_id: friend.class_id,
367
+ }));
368
+ }
369
+ /**
370
+ * 获取陌生人信息
371
+ */
372
+ async getStrangerInfo(userId) {
373
+ if (!this.client)
374
+ throw new Error('Bot not connected');
375
+ const info = await this.client.getStrangerInfo(userId);
376
+ return {
377
+ user_id: info.user_id,
378
+ nickname: info.nickname,
379
+ sex: info.sex,
380
+ age: info.age,
381
+ avatar: `https://q1.qlogo.cn/g?b=qq&nk=${info.user_id}&s=640`,
382
+ };
383
+ }
384
+ /**
385
+ * 处理好友申请
386
+ */
387
+ async handleFriendRequest(flag, approve, remark) {
388
+ if (!this.client)
389
+ throw new Error('Bot not connected');
390
+ return this.client.setFriendAddRequest(flag, approve, remark);
391
+ }
392
+ /**
393
+ * 删除好友
394
+ */
395
+ async deleteFriend(userId) {
396
+ if (!this.client)
397
+ throw new Error('Bot not connected');
398
+ return this.client.deleteFriend(userId);
399
+ }
400
+ // ============================================
401
+ // 群组 API
402
+ // ============================================
403
+ /**
404
+ * 获取群列表
405
+ */
406
+ async getGroupList() {
407
+ if (!this.client)
408
+ throw new Error('Bot not connected');
409
+ const groups = this.client.gl;
410
+ return Array.from(groups.values()).map((group) => ({
411
+ group_id: group.group_id,
412
+ group_name: group.group_name,
413
+ owner_id: group.owner_id,
414
+ member_count: group.member_count,
415
+ max_member_count: group.max_member_count,
416
+ }));
417
+ }
418
+ /**
419
+ * 获取群信息
420
+ */
421
+ async getGroupInfo(groupId) {
422
+ if (!this.client)
423
+ throw new Error('Bot not connected');
424
+ const group = this.client.gl.get(groupId);
425
+ if (!group)
426
+ return undefined;
427
+ return {
428
+ group_id: group.group_id,
429
+ group_name: group.group_name,
430
+ owner_id: group.owner_id,
431
+ member_count: group.member_count,
432
+ max_member_count: group.max_member_count,
433
+ };
434
+ }
435
+ /**
436
+ * 获取群成员列表
437
+ */
438
+ async getGroupMemberList(groupId) {
439
+ if (!this.client)
440
+ throw new Error('Bot not connected');
441
+ const members = await this.client.getGroupMemberList(groupId);
442
+ return Array.from(members.values()).map((member) => ({
443
+ group_id: groupId,
444
+ user_id: member.user_id,
445
+ nickname: member.nickname,
446
+ card: member.card,
447
+ sex: member.sex,
448
+ age: member.age,
449
+ join_time: member.join_time,
450
+ last_sent_time: member.last_sent_time,
451
+ level: member.level,
452
+ role: member.role,
453
+ title: member.title,
454
+ title_expire_time: member.title_expire_time,
455
+ shutup_time: member.shutup_time,
456
+ }));
457
+ }
458
+ /**
459
+ * 获取群成员信息
460
+ */
461
+ async getGroupMemberInfo(groupId, userId) {
462
+ if (!this.client)
463
+ throw new Error('Bot not connected');
464
+ const member = await this.client.getGroupMemberInfo(groupId, userId);
465
+ if (!member)
466
+ return undefined;
467
+ return {
468
+ group_id: groupId,
469
+ user_id: member.user_id,
470
+ nickname: member.nickname,
471
+ card: member.card,
472
+ sex: member.sex,
473
+ age: member.age,
474
+ join_time: member.join_time,
475
+ last_sent_time: member.last_sent_time,
476
+ level: member.level,
477
+ role: member.role,
478
+ title: member.title,
479
+ title_expire_time: member.title_expire_time,
480
+ shutup_time: member.shutup_time,
481
+ };
482
+ }
483
+ /**
484
+ * 处理群申请/邀请
485
+ */
486
+ async handleGroupRequest(flag, approve, reason) {
487
+ if (!this.client)
488
+ throw new Error('Bot not connected');
489
+ await this.client.setGroupAddRequest(flag, approve, reason);
490
+ return true;
491
+ }
492
+ /**
493
+ * 设置群名片
494
+ */
495
+ async setGroupCard(groupId, userId, card) {
496
+ if (!this.client)
497
+ throw new Error('Bot not connected');
498
+ return this.client.setGroupCard(groupId, userId, card);
499
+ }
500
+ /**
501
+ * 踢出群成员
502
+ */
503
+ async kickGroupMember(groupId, userId, rejectAddRequest) {
504
+ if (!this.client)
505
+ throw new Error('Bot not connected');
506
+ await this.client.setGroupKick(groupId, userId, rejectAddRequest);
507
+ return true;
508
+ }
509
+ /**
510
+ * 禁言群成员
511
+ */
512
+ async muteGroupMember(groupId, userId, duration) {
513
+ if (!this.client)
514
+ throw new Error('Bot not connected');
515
+ return this.client.setGroupBan(groupId, userId, duration);
516
+ }
517
+ /**
518
+ * 全员禁言
519
+ */
520
+ async muteGroupAll(groupId, enable) {
521
+ if (!this.client)
522
+ throw new Error('Bot not connected');
523
+ return this.client.setGroupWholeBan(groupId, enable);
524
+ }
525
+ /**
526
+ * 设置群管理员
527
+ */
528
+ async setGroupAdmin(groupId, userId, enable) {
529
+ if (!this.client)
530
+ throw new Error('Bot not connected');
531
+ return this.client.setGroupAdmin(groupId, userId, enable);
532
+ }
533
+ /**
534
+ * 退出群
535
+ */
536
+ async leaveGroup(groupId, dismiss) {
537
+ if (!this.client)
538
+ throw new Error('Bot not connected');
539
+ return this.client.setGroupLeave(groupId);
540
+ }
541
+ /**
542
+ * 设置群名
543
+ */
544
+ async setGroupName(groupId, name) {
545
+ if (!this.client)
546
+ throw new Error('Bot not connected');
547
+ return this.client.setGroupName(groupId, name);
548
+ }
549
+ /**
550
+ * 设置群头像
551
+ */
552
+ async setGroupAvatar(groupId, file) {
553
+ if (!this.client)
554
+ throw new Error('Bot not connected');
555
+ await this.client.setGroupPortrait(groupId, file);
556
+ }
557
+ // ============================================
558
+ // 工具方法
559
+ // ============================================
560
+ /**
561
+ * 提交滑块 ticket
562
+ */
563
+ submitSlider(ticket) {
564
+ if (!this.client)
565
+ throw new Error('Bot not connected');
566
+ this.client.submitSlider(ticket);
567
+ }
568
+ /**
569
+ * 提交短信验证码
570
+ */
571
+ submitSmsCode(code) {
572
+ if (!this.client)
573
+ throw new Error('Bot not connected');
574
+ this.client.submitSmsCode(code);
575
+ }
576
+ /**
577
+ * 扫码登录
578
+ */
579
+ qrcodeLogin() {
580
+ if (!this.client)
581
+ throw new Error('Bot not connected');
582
+ this.client.login();
583
+ }
584
+ /**
585
+ * 获取消息段构造器
586
+ */
587
+ static get segment() {
588
+ return Segment;
589
+ }
590
+ }
591
+ // 导出消息段构造器
592
+ export { Segment as segment };
593
+ //# sourceMappingURL=bot.js.map
package/lib/index.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export type { ICQQConfig, ICQQProtocol, Platform } from './types.js';
2
+ export * from './adapter.js';
3
+ export * from './bot.js';
4
+ //# sourceMappingURL=index.d.ts.map
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './adapter.js';
2
+ export * from './bot.js';
3
+ //# sourceMappingURL=index.js.map