@zhin.js/adapter-icqq 1.0.70 → 1.1.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/CHANGELOG.md +1134 -51
- package/README.md +116 -431
- package/adapters/icqq.js +31 -0
- package/adapters/icqq.ts +42 -0
- package/agent/PERMITS.md +24 -0
- package/agent/prompt-sections/platform.ts +17 -0
- package/commands/endpoint/add/[[id]].js +3 -0
- package/commands/endpoint/add/[[id]].ts +3 -0
- package/commands/endpoint/list.js +3 -0
- package/commands/endpoint/list.ts +3 -0
- package/commands/endpoint/remove/[id].js +3 -0
- package/commands/endpoint/remove/[id].ts +3 -0
- package/lib/client.d.ts +19 -0
- package/lib/client.js +3 -0
- package/lib/cq-message.d.ts +14 -0
- package/lib/cq-message.js +106 -0
- package/lib/endpoint.d.ts +31 -0
- package/lib/endpoint.js +1046 -0
- package/lib/forward-msg.d.ts +6 -0
- package/lib/forward-msg.js +107 -0
- package/lib/icqq-endpoint-commands.d.ts +1 -0
- package/lib/icqq-endpoint-commands.js +26 -0
- package/lib/icqq-guild.d.ts +57 -0
- package/lib/icqq-guild.js +109 -0
- package/lib/icqq-inbound.d.ts +165 -0
- package/lib/icqq-inbound.js +651 -0
- package/lib/icqq-inbox.d.ts +25 -0
- package/lib/icqq-inbox.js +129 -0
- package/lib/icqq-login-assist.d.ts +27 -0
- package/lib/icqq-login-assist.js +109 -0
- package/lib/icqq-runtime-state.d.ts +1 -0
- package/lib/icqq-runtime-state.js +6 -0
- package/lib/index.d.ts +5 -18
- package/lib/index.js +5 -124
- package/lib/outbound-media.d.ts +14 -0
- package/lib/outbound-media.js +76 -0
- package/lib/protocol.d.ts +276 -0
- package/lib/protocol.js +425 -0
- package/lib/types.d.ts +37 -11
- package/lib/types.js +0 -1
- package/package.json +80 -32
- package/plugin.js +19 -0
- package/schema.json +162 -0
- package/src/client.ts +29 -0
- package/src/cq-message.ts +113 -0
- package/src/endpoint.ts +1138 -0
- package/src/forward-msg.ts +112 -0
- package/src/icqq-endpoint-commands.ts +28 -0
- package/src/icqq-guild.ts +154 -0
- package/src/icqq-inbound.ts +814 -0
- package/src/icqq-inbox.ts +147 -0
- package/src/icqq-login-assist.ts +132 -0
- package/src/icqq-runtime-state.ts +7 -0
- package/src/index.ts +30 -149
- package/src/outbound-media.ts +103 -0
- package/src/protocol.ts +575 -0
- package/src/types.ts +40 -11
- package/tools/announce.js +16 -0
- package/tools/announce.ts +15 -0
- package/tools/essence.js +22 -0
- package/tools/essence.ts +20 -0
- package/tools/friend_list.js +18 -0
- package/tools/friend_list.ts +18 -0
- package/tools/group_files.js +22 -0
- package/tools/group_files.ts +20 -0
- package/tools/group_invite.js +23 -0
- package/tools/group_invite.ts +20 -0
- package/tools/group_kick.js +26 -0
- package/tools/group_kick.ts +22 -0
- package/tools/group_list.js +19 -0
- package/tools/group_list.ts +19 -0
- package/tools/group_member_info.js +24 -0
- package/tools/group_member_info.ts +26 -0
- package/tools/group_sign.js +19 -0
- package/tools/group_sign.ts +17 -0
- package/tools/list_muted.js +17 -0
- package/tools/list_muted.ts +16 -0
- package/tools/poke.js +16 -0
- package/tools/poke.ts +15 -0
- package/tools/send_user_like.js +25 -0
- package/tools/send_user_like.ts +22 -0
- package/tools/set_anonymous.js +21 -0
- package/tools/set_anonymous.ts +19 -0
- package/tools/set_mute.js +24 -0
- package/tools/set_mute.ts +21 -0
- package/tools/set_title.js +25 -0
- package/tools/set_title.ts +22 -0
- package/tools/user_info.js +14 -0
- package/tools/user_info.ts +13 -0
- package/LICENSE +0 -21
- package/client/ICQQManagement.tsx +0 -139
- package/client/LoginAssistPanel.tsx +0 -293
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -20
- package/dist/index.js +0 -1
- package/lib/adapter.d.ts +0 -34
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -396
- package/lib/adapter.js.map +0 -1
- package/lib/bot.d.ts +0 -46
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js +0 -457
- package/lib/bot.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js.map +0 -1
- package/skills/icqq/SKILL.md +0 -22
- package/src/adapter.ts +0 -448
- package/src/bot.ts +0 -521
package/src/bot.ts
DELETED
|
@@ -1,521 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ICQQ Bot:继承 icqq Client,实现 zhin Bot 接口
|
|
3
|
-
*/
|
|
4
|
-
import {
|
|
5
|
-
Client,
|
|
6
|
-
PrivateMessageEvent,
|
|
7
|
-
GroupMessageEvent,
|
|
8
|
-
Sendable,
|
|
9
|
-
MessageElem,
|
|
10
|
-
MemberInfo,
|
|
11
|
-
MemberIncreaseEvent,
|
|
12
|
-
MemberDecreaseEvent,
|
|
13
|
-
GroupRecallEvent,
|
|
14
|
-
GroupAdminEvent,
|
|
15
|
-
GroupMuteEvent,
|
|
16
|
-
GroupTransferEvent,
|
|
17
|
-
GroupPokeEvent,
|
|
18
|
-
FriendRecallEvent,
|
|
19
|
-
FriendPokeEvent,
|
|
20
|
-
FriendIncreaseEvent,
|
|
21
|
-
FriendRequestEvent,
|
|
22
|
-
GroupRequestEvent,
|
|
23
|
-
GroupInviteEvent,
|
|
24
|
-
} from "@icqqjs/icqq";
|
|
25
|
-
import path from "path";
|
|
26
|
-
import {
|
|
27
|
-
Bot,
|
|
28
|
-
Message,
|
|
29
|
-
SendOptions,
|
|
30
|
-
MessageSegment,
|
|
31
|
-
SendContent,
|
|
32
|
-
segment,
|
|
33
|
-
Notice,
|
|
34
|
-
Request,
|
|
35
|
-
} from "zhin.js";
|
|
36
|
-
import type { IcqqBotConfig, IcqqSenderInfo } from "./types.js";
|
|
37
|
-
import type { IcqqAdapter } from "./adapter.js";
|
|
38
|
-
|
|
39
|
-
export class IcqqBot
|
|
40
|
-
extends Client
|
|
41
|
-
implements Bot<IcqqBotConfig, PrivateMessageEvent | GroupMessageEvent>
|
|
42
|
-
{
|
|
43
|
-
$connected: boolean = false;
|
|
44
|
-
$config!: IcqqBotConfig;
|
|
45
|
-
|
|
46
|
-
get pluginLogger() {
|
|
47
|
-
return this.adapter.plugin.logger;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
get $id() {
|
|
51
|
-
return this.$config.name;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
constructor(public adapter: IcqqAdapter, config: IcqqBotConfig) {
|
|
55
|
-
if (!config.scope) config.scope = "icqqjs";
|
|
56
|
-
if (!config.data_dir) config.data_dir = path.join(process.cwd(), "data");
|
|
57
|
-
if (config.scope.startsWith("@")) config.scope = config.scope.slice(1);
|
|
58
|
-
super(config);
|
|
59
|
-
this.$config = config;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
private handleIcqqMessage(
|
|
63
|
-
msg: PrivateMessageEvent | GroupMessageEvent,
|
|
64
|
-
): void {
|
|
65
|
-
const message = this.$formatMessage(msg);
|
|
66
|
-
this.adapter.emit("message.receive", message);
|
|
67
|
-
this.pluginLogger.debug(
|
|
68
|
-
`${this.$config.name} recv ${message.$channel.type}(${
|
|
69
|
-
message.$channel.id
|
|
70
|
-
}):${segment.raw(message.$content)}`,
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async $connect(): Promise<void> {
|
|
75
|
-
this.on("message", this.handleIcqqMessage.bind(this));
|
|
76
|
-
this.on("notice.group.increase", (e: MemberIncreaseEvent) => this.handleGroupNotice(e, 'group_member_increase', 'increase'));
|
|
77
|
-
this.on("notice.group.decrease", (e: MemberDecreaseEvent) => this.handleGroupNotice(e, 'group_member_decrease', 'decrease'));
|
|
78
|
-
this.on("notice.group.recall", (e: GroupRecallEvent) => this.handleGroupNotice(e, 'group_recall', 'recall'));
|
|
79
|
-
this.on("notice.group.admin", (e: GroupAdminEvent) => this.handleGroupNotice(e, 'group_admin_change', 'admin'));
|
|
80
|
-
this.on("notice.group.ban", (e: GroupMuteEvent) => this.handleGroupNotice(e, 'group_ban', 'ban'));
|
|
81
|
-
this.on("notice.group.transfer", (e: GroupTransferEvent) => this.handleGroupNotice(e, 'group_transfer', 'transfer'));
|
|
82
|
-
this.on("notice.group.poke", (e: GroupPokeEvent) => this.handleGroupNotice(e, 'group_poke', 'poke'));
|
|
83
|
-
this.on("notice.friend.increase", (e: FriendIncreaseEvent) => this.handleFriendNotice(e, 'friend_add', 'increase'));
|
|
84
|
-
this.on("notice.friend.recall", (e: FriendRecallEvent) => this.handleFriendNotice(e, 'friend_recall', 'recall'));
|
|
85
|
-
this.on("notice.friend.poke", (e: FriendPokeEvent) => this.handleFriendNotice(e, 'friend_poke', 'poke'));
|
|
86
|
-
this.on("request.friend.add", (e: FriendRequestEvent) => this.handleFriendRequest(e));
|
|
87
|
-
this.on("request.group.add", (e: GroupRequestEvent) => this.handleGroupRequest(e, 'group_add'));
|
|
88
|
-
this.on("request.group.invite", (e: GroupInviteEvent) => this.handleGroupRequest(e, 'group_invite'));
|
|
89
|
-
|
|
90
|
-
this.on("system.login.device", async (e) => {
|
|
91
|
-
this.pluginLogger.info(`[${this.$config.name}] 触发设备验证,正在发送短信验证码...`);
|
|
92
|
-
await this.sendSmsCode();
|
|
93
|
-
this.pluginLogger.info(`[${this.$config.name}] 短信验证码已发送,请查收手机短信`);
|
|
94
|
-
this.pluginLogger.info(`[${this.$config.name}] 请在终端输入短信验证码:`);
|
|
95
|
-
process.stdin.once("data", (data: Buffer) => {
|
|
96
|
-
this.pluginLogger.info(`[${this.$config.name}] 正在提交短信验证码...`);
|
|
97
|
-
this.submitSmsCode(data.toString().trim());
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
this.on("system.login.qrcode", async (e: any) => {
|
|
101
|
-
this.pluginLogger.info(`[${this.$config.name}] 触发扫码登录,请使用手机 QQ 扫描二维码`);
|
|
102
|
-
this.pluginLogger.info(`[${this.$config.name}] 扫码完成后按回车继续`);
|
|
103
|
-
process.stdin.once("data", () => {
|
|
104
|
-
this.pluginLogger.info(`[${this.$config.name}] 扫码已确认,正在登录...`);
|
|
105
|
-
this.login();
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
this.on("system.login.slider", async (e: { url: string }) => {
|
|
109
|
-
this.pluginLogger.info(`[${this.$config.name}] 触发滑块验证`);
|
|
110
|
-
this.pluginLogger.info(`[${this.$config.name}] 验证地址: ${e.url}`);
|
|
111
|
-
this.pluginLogger.info(`[${this.$config.name}] 请在浏览器中完成滑块验证后,在终端输入 ticket:`);
|
|
112
|
-
process.stdin.once("data", (data: Buffer) => {
|
|
113
|
-
this.pluginLogger.info(`[${this.$config.name}] 正在提交滑块 ticket...`);
|
|
114
|
-
this.submitSlider(data.toString().trim());
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const LOGIN_TIMEOUT = 120_000; // 2 分钟登录超时
|
|
119
|
-
const loginMode = this.$config.password ? '密码' : '扫码';
|
|
120
|
-
this.pluginLogger.info(`[${this.$config.name}] 正在尝试${loginMode}登录...`);
|
|
121
|
-
|
|
122
|
-
return new Promise<void>((resolve, reject) => {
|
|
123
|
-
const timer = setTimeout(() => {
|
|
124
|
-
cleanup();
|
|
125
|
-
const msg = `[${this.$config.name}] 登录超时(${LOGIN_TIMEOUT / 1000}s),请检查网络或验证流程是否完成`;
|
|
126
|
-
this.pluginLogger.error(msg);
|
|
127
|
-
reject(new Error(msg));
|
|
128
|
-
}, LOGIN_TIMEOUT);
|
|
129
|
-
|
|
130
|
-
const cleanup = () => {
|
|
131
|
-
clearTimeout(timer);
|
|
132
|
-
// once 注册的监听器在触发后会自动移除,这里只清理未触发的
|
|
133
|
-
this.off("system.online" as any);
|
|
134
|
-
this.off("system.login.error" as any);
|
|
135
|
-
this.off("system.offline" as any);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const onOnline = () => {
|
|
139
|
-
cleanup();
|
|
140
|
-
this.$connected = true;
|
|
141
|
-
this.pluginLogger.info(`[${this.$config.name}] 登录成功,已上线`);
|
|
142
|
-
resolve();
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
const onError = (e: { code: number; message: string }) => {
|
|
146
|
-
cleanup();
|
|
147
|
-
const msg = `[${this.$config.name}] 登录失败 (code=${e.code}): ${e.message}`;
|
|
148
|
-
this.pluginLogger.error(msg);
|
|
149
|
-
reject(new Error(msg));
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const onOffline = (e?: { message: string }) => {
|
|
153
|
-
cleanup();
|
|
154
|
-
const msg = `[${this.$config.name}] 登录过程中掉线: ${e?.message ?? '未知原因'}`;
|
|
155
|
-
this.pluginLogger.error(msg);
|
|
156
|
-
reject(new Error(msg));
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
this.once("system.online", onOnline);
|
|
160
|
-
this.once("system.login.error", onError as any);
|
|
161
|
-
this.once("system.offline", onOffline);
|
|
162
|
-
|
|
163
|
-
this.login(Number(this.$config.name), this.$config.password);
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async $disconnect(): Promise<void> {
|
|
168
|
-
await this.logout();
|
|
169
|
-
this.$connected = false;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
$formatMessage(msg: PrivateMessageEvent | GroupMessageEvent) {
|
|
173
|
-
const senderInfo = this.getSenderInfo(msg);
|
|
174
|
-
const result = Message.from(msg, {
|
|
175
|
-
$id: msg.message_id.toString(),
|
|
176
|
-
$adapter: "icqq" as const,
|
|
177
|
-
$bot: `${this.$config.name}`,
|
|
178
|
-
$sender: senderInfo,
|
|
179
|
-
$channel: {
|
|
180
|
-
id:
|
|
181
|
-
msg.message_type === "group"
|
|
182
|
-
? msg.group_id.toString()
|
|
183
|
-
: msg.from_id.toString(),
|
|
184
|
-
type: msg.message_type,
|
|
185
|
-
},
|
|
186
|
-
$content: IcqqBot.toSegments(msg.message),
|
|
187
|
-
$raw: msg.raw_message,
|
|
188
|
-
$timestamp: msg.time*1000,
|
|
189
|
-
$recall: async () => {
|
|
190
|
-
await this.$recallMessage(result.$id);
|
|
191
|
-
},
|
|
192
|
-
$reply: async (
|
|
193
|
-
content: SendContent,
|
|
194
|
-
quote?: boolean | string,
|
|
195
|
-
): Promise<string> => {
|
|
196
|
-
if (!Array.isArray(content)) content = [content];
|
|
197
|
-
if (quote)
|
|
198
|
-
content.unshift({
|
|
199
|
-
type: "reply",
|
|
200
|
-
data: { id: typeof quote === "boolean" ? result.$id : quote },
|
|
201
|
-
});
|
|
202
|
-
return await this.adapter.sendMessage({
|
|
203
|
-
...result.$channel,
|
|
204
|
-
context: "icqq",
|
|
205
|
-
bot: `${this.uin}`,
|
|
206
|
-
content,
|
|
207
|
-
});
|
|
208
|
-
},
|
|
209
|
-
});
|
|
210
|
-
return result;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
private getSenderInfo(
|
|
214
|
-
msg: PrivateMessageEvent | GroupMessageEvent,
|
|
215
|
-
): IcqqSenderInfo {
|
|
216
|
-
const senderInfo: IcqqSenderInfo = {
|
|
217
|
-
id: msg.sender.user_id.toString(),
|
|
218
|
-
name: msg.sender.nickname.toString(),
|
|
219
|
-
};
|
|
220
|
-
if (msg.message_type === "group") {
|
|
221
|
-
const groupMsg = msg as GroupMessageEvent;
|
|
222
|
-
const sender = groupMsg.sender as any;
|
|
223
|
-
if (sender.role) {
|
|
224
|
-
senderInfo.role = sender.role;
|
|
225
|
-
senderInfo.isOwner = sender.role === "owner";
|
|
226
|
-
senderInfo.isAdmin = sender.role === "admin" || sender.role === "owner";
|
|
227
|
-
const perms: string[] = [];
|
|
228
|
-
if (sender.role === "owner") perms.push("owner", "admin");
|
|
229
|
-
else if (sender.role === "admin") perms.push("admin");
|
|
230
|
-
senderInfo.permissions = perms;
|
|
231
|
-
}
|
|
232
|
-
if (sender.card) senderInfo.card = sender.card;
|
|
233
|
-
if (sender.title) senderInfo.title = sender.title;
|
|
234
|
-
}
|
|
235
|
-
return senderInfo;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
private handleGroupNotice(event: any, type: string, subType: string): void {
|
|
239
|
-
const notice = Notice.from(event, {
|
|
240
|
-
$id: `${event.time || Date.now()}_${type}_${event.group_id}`,
|
|
241
|
-
$adapter: 'icqq',
|
|
242
|
-
$bot: this.$config.name,
|
|
243
|
-
$type: type,
|
|
244
|
-
$subType: subType,
|
|
245
|
-
$channel: { id: event.group_id?.toString() || '', type: 'group' },
|
|
246
|
-
$operator: event.operator_id ? { id: event.operator_id.toString(), name: event.operator_id.toString() } : undefined,
|
|
247
|
-
$target: event.user_id ? { id: event.user_id.toString(), name: event.user_id.toString() } : (event.target_id ? { id: event.target_id.toString(), name: event.target_id.toString() } : undefined),
|
|
248
|
-
$timestamp: event.time*1000 || Date.now(),
|
|
249
|
-
});
|
|
250
|
-
this.adapter.emit('notice.receive', notice);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
private handleFriendNotice(event: any, type: string, subType: string): void {
|
|
254
|
-
const notice = Notice.from(event, {
|
|
255
|
-
$id: `${event.time || Date.now()}_${type}_${event.user_id}`,
|
|
256
|
-
$adapter: 'icqq',
|
|
257
|
-
$bot: this.$config.name,
|
|
258
|
-
$type: type,
|
|
259
|
-
$subType: subType,
|
|
260
|
-
$channel: { id: event.user_id?.toString() || '', type: 'private' },
|
|
261
|
-
$operator: event.operator_id ? { id: event.operator_id.toString(), name: event.operator_id.toString() } : undefined,
|
|
262
|
-
$target: event.user_id ? { id: event.user_id.toString(), name: event.user_id.toString() } : undefined,
|
|
263
|
-
$timestamp: event.time*1000 || Date.now(),
|
|
264
|
-
});
|
|
265
|
-
this.adapter.emit('notice.receive', notice);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
private handleFriendRequest(event: FriendRequestEvent): void {
|
|
269
|
-
const request = Request.from(event, {
|
|
270
|
-
$id: event.flag || `${event.time}_friend_add_${event.user_id}`,
|
|
271
|
-
$adapter: 'icqq',
|
|
272
|
-
$bot: this.$config.name,
|
|
273
|
-
$type: 'friend_add',
|
|
274
|
-
$subType: event.sub_type,
|
|
275
|
-
$channel: { id: event.user_id.toString(), type: 'private' },
|
|
276
|
-
$sender: { id: event.user_id.toString(), name: event.nickname || event.user_id.toString() },
|
|
277
|
-
$comment: event.comment,
|
|
278
|
-
$timestamp: event.time*1000 || Date.now(),
|
|
279
|
-
$approve: async () => { await event.approve(true); },
|
|
280
|
-
$reject: async () => { await event.approve(false); },
|
|
281
|
-
});
|
|
282
|
-
this.adapter.emit('request.receive', request);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
private handleGroupRequest(event: GroupRequestEvent | GroupInviteEvent, type: string): void {
|
|
286
|
-
const request = Request.from(event, {
|
|
287
|
-
$id: event.flag || `${event.time}_${type}_${event.user_id}`,
|
|
288
|
-
$adapter: 'icqq',
|
|
289
|
-
$bot: this.$config.name,
|
|
290
|
-
$type: type,
|
|
291
|
-
$subType: event.sub_type,
|
|
292
|
-
$channel: { id: event.group_id.toString(), type: 'group' },
|
|
293
|
-
$sender: { id: event.user_id.toString(), name: event.nickname || event.user_id.toString() },
|
|
294
|
-
$comment: 'comment' in event ? event.comment : undefined,
|
|
295
|
-
$timestamp: event.time*1000 || Date.now(),
|
|
296
|
-
$approve: async () => { await event.approve(true); },
|
|
297
|
-
$reject: async () => { await event.approve(false); },
|
|
298
|
-
});
|
|
299
|
-
this.adapter.emit('request.receive', request);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
async kickMember(groupId: number, userId: number, block?: boolean): Promise<boolean> {
|
|
303
|
-
try {
|
|
304
|
-
const group = this.pickGroup(groupId);
|
|
305
|
-
const result = await group.kickMember(userId, undefined, block);
|
|
306
|
-
this.pluginLogger.info(
|
|
307
|
-
`ICQQ Bot ${this.$id} 踢出成员 ${userId} 从群 ${groupId}${block ? "(已拉黑)" : ""}`,
|
|
308
|
-
);
|
|
309
|
-
return result;
|
|
310
|
-
} catch (error) {
|
|
311
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 踢出成员失败:`, error);
|
|
312
|
-
throw error;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
async muteMember(groupId: number, userId: number, duration: number = 600): Promise<boolean> {
|
|
317
|
-
try {
|
|
318
|
-
const group = this.pickGroup(groupId);
|
|
319
|
-
const result = await group.muteMember(userId, duration);
|
|
320
|
-
this.pluginLogger.info(
|
|
321
|
-
`ICQQ Bot ${this.$id} ${duration > 0 ? `禁言成员 ${userId} ${duration}秒` : `解除成员 ${userId} 禁言`}(群 ${groupId})`,
|
|
322
|
-
);
|
|
323
|
-
return result;
|
|
324
|
-
} catch (error) {
|
|
325
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 禁言操作失败:`, error);
|
|
326
|
-
throw error;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
async muteAll(groupId: number, enable: boolean = true): Promise<boolean> {
|
|
331
|
-
try {
|
|
332
|
-
const group = this.pickGroup(groupId);
|
|
333
|
-
const result = await group.muteAll(enable);
|
|
334
|
-
this.pluginLogger.info(`ICQQ Bot ${this.$id} ${enable ? "开启" : "关闭"}全员禁言(群 ${groupId})`);
|
|
335
|
-
return result;
|
|
336
|
-
} catch (error) {
|
|
337
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 全员禁言操作失败:`, error);
|
|
338
|
-
throw error;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
async setAdmin(groupId: number, userId: number, enable: boolean = true): Promise<boolean> {
|
|
343
|
-
try {
|
|
344
|
-
const group = this.pickGroup(groupId);
|
|
345
|
-
const result = await group.setAdmin(userId, enable);
|
|
346
|
-
this.pluginLogger.info(`ICQQ Bot ${this.$id} ${enable ? "设置" : "取消"}管理员 ${userId}(群 ${groupId})`);
|
|
347
|
-
return result;
|
|
348
|
-
} catch (error) {
|
|
349
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 设置管理员失败:`, error);
|
|
350
|
-
throw error;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
async setCard(groupId: number, userId: number, card: string): Promise<boolean> {
|
|
355
|
-
try {
|
|
356
|
-
const group = this.pickGroup(groupId);
|
|
357
|
-
const result = await group.setCard(userId, card);
|
|
358
|
-
this.pluginLogger.info(`ICQQ Bot ${this.$id} 设置成员 ${userId} 群名片为 "${card}"(群 ${groupId})`);
|
|
359
|
-
return result;
|
|
360
|
-
} catch (error) {
|
|
361
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 设置群名片失败:`, error);
|
|
362
|
-
throw error;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
async setTitle(groupId: number, userId: number, title: string, duration: number = -1): Promise<boolean> {
|
|
367
|
-
try {
|
|
368
|
-
const group = this.pickGroup(groupId);
|
|
369
|
-
const result = await group.setTitle(userId, title, duration);
|
|
370
|
-
this.pluginLogger.info(`ICQQ Bot ${this.$id} 设置成员 ${userId} 头衔为 "${title}"(群 ${groupId})`);
|
|
371
|
-
return result;
|
|
372
|
-
} catch (error) {
|
|
373
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 设置头衔失败:`, error);
|
|
374
|
-
throw error;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
async setGroupName(groupId: number, name: string): Promise<boolean> {
|
|
379
|
-
try {
|
|
380
|
-
const group = this.pickGroup(groupId);
|
|
381
|
-
const result = await group.setName(name);
|
|
382
|
-
this.pluginLogger.info(`ICQQ Bot ${this.$id} 设置群名为 "${name}"(群 ${groupId})`);
|
|
383
|
-
return result;
|
|
384
|
-
} catch (error) {
|
|
385
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 设置群名失败:`, error);
|
|
386
|
-
throw error;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
async sendAnnounce(groupId: number, content: string): Promise<boolean> {
|
|
391
|
-
try {
|
|
392
|
-
const group = this.pickGroup(groupId);
|
|
393
|
-
const result = await group.announce(content);
|
|
394
|
-
this.pluginLogger.info(`ICQQ Bot ${this.$id} 发送群公告(群 ${groupId})`);
|
|
395
|
-
return result;
|
|
396
|
-
} catch (error) {
|
|
397
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 发送群公告失败:`, error);
|
|
398
|
-
throw error;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
async pokeMember(groupId: number, userId: number): Promise<boolean> {
|
|
403
|
-
try {
|
|
404
|
-
const group = this.pickGroup(groupId);
|
|
405
|
-
const result = await group.pokeMember(userId);
|
|
406
|
-
this.pluginLogger.info(`ICQQ Bot ${this.$id} 戳了戳 ${userId}(群 ${groupId})`);
|
|
407
|
-
return result;
|
|
408
|
-
} catch (error) {
|
|
409
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 戳一戳失败:`, error);
|
|
410
|
-
throw error;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
async getMemberList(groupId: number): Promise<Map<number, MemberInfo>> {
|
|
415
|
-
try {
|
|
416
|
-
const group = this.pickGroup(groupId);
|
|
417
|
-
return await group.getMemberMap();
|
|
418
|
-
} catch (error) {
|
|
419
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 获取群成员列表失败:`, error);
|
|
420
|
-
throw error;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
async getMutedMembers(groupId: number): Promise<any[]> {
|
|
425
|
-
try {
|
|
426
|
-
const group = this.pickGroup(groupId);
|
|
427
|
-
return await group.getMuteMemberList();
|
|
428
|
-
} catch (error) {
|
|
429
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 获取禁言列表失败:`, error);
|
|
430
|
-
throw error;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
async setAnonymous(groupId: number, enable: boolean = true): Promise<boolean> {
|
|
435
|
-
try {
|
|
436
|
-
const group = this.pickGroup(groupId);
|
|
437
|
-
const result = await group.allowAnony(enable);
|
|
438
|
-
this.pluginLogger.info(`ICQQ Bot ${this.$id} ${enable ? "开启" : "关闭"}匿名(群 ${groupId})`);
|
|
439
|
-
return result;
|
|
440
|
-
} catch (error) {
|
|
441
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 设置匿名失败:`, error);
|
|
442
|
-
throw error;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
async getGroupFiles(groupId: number): Promise<any> {
|
|
447
|
-
try {
|
|
448
|
-
const group = this.pickGroup(groupId);
|
|
449
|
-
return await group.fs.ls();
|
|
450
|
-
} catch (error) {
|
|
451
|
-
this.pluginLogger.error(`ICQQ Bot ${this.$id} 获取群文件列表失败:`, error);
|
|
452
|
-
throw error;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
async $recallMessage(id: string): Promise<void> {
|
|
457
|
-
await this.deleteMsg(id);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
async $sendMessage(options: SendOptions): Promise<string> {
|
|
461
|
-
switch (options.type) {
|
|
462
|
-
case "private": {
|
|
463
|
-
const result = await this.sendPrivateMsg(
|
|
464
|
-
Number(options.id),
|
|
465
|
-
IcqqBot.toSendable(options.content),
|
|
466
|
-
);
|
|
467
|
-
this.pluginLogger.debug(`${this.$config.name} send ${options.type}(${options.id}):${segment.raw(options.content)}`);
|
|
468
|
-
return result.message_id.toString();
|
|
469
|
-
}
|
|
470
|
-
case "group": {
|
|
471
|
-
const result = await this.sendGroupMsg(
|
|
472
|
-
Number(options.id),
|
|
473
|
-
IcqqBot.toSendable(options.content),
|
|
474
|
-
);
|
|
475
|
-
this.pluginLogger.debug(`${this.$config.name} send ${options.type}(${options.id}):${segment.raw(options.content)}`);
|
|
476
|
-
return result.message_id.toString();
|
|
477
|
-
}
|
|
478
|
-
default:
|
|
479
|
-
throw new Error(`unsupported channel type ${options.type}`);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
export namespace IcqqBot {
|
|
485
|
-
const allowTypes = [
|
|
486
|
-
"text", "face", "image", "record", "audio", "dice", "rps", "video",
|
|
487
|
-
"file", "location", "share", "json", "at", "reply", "long_msg",
|
|
488
|
-
"button", "markdown", "xml",
|
|
489
|
-
];
|
|
490
|
-
|
|
491
|
-
export function toSegments(message: Sendable): MessageSegment[] {
|
|
492
|
-
if (!Array.isArray(message)) message = [message];
|
|
493
|
-
return message
|
|
494
|
-
.filter((item, index) => typeof item === "string" || (item as any).type !== "long_msg" || index !== 0)
|
|
495
|
-
.map((item): MessageSegment => {
|
|
496
|
-
if (typeof item === "string") return { type: "text", data: { text: item } };
|
|
497
|
-
const { type, ...data } = item as any;
|
|
498
|
-
return { type, data };
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
export namespace IcqqBot {
|
|
504
|
-
const allowTypes = [
|
|
505
|
-
"text", "face", "image", "record", "audio", "dice", "rps", "video",
|
|
506
|
-
"file", "location", "share", "json", "at", "reply", "long_msg",
|
|
507
|
-
"button", "markdown", "xml",
|
|
508
|
-
];
|
|
509
|
-
|
|
510
|
-
export function toSendable(content: SendContent): Sendable {
|
|
511
|
-
if (!Array.isArray(content)) content = [content];
|
|
512
|
-
return content.map((seg): MessageElem => {
|
|
513
|
-
if (typeof seg === "string") return { type: "text", text: seg };
|
|
514
|
-
let { type, data } = seg as any;
|
|
515
|
-
if (typeof type === "function") type = type.name;
|
|
516
|
-
if(['image','video','audio'].includes(type)) data.file=data.file||data.url||data.src
|
|
517
|
-
if (!allowTypes.includes(type)) return { type: "text", text: segment.toString(seg) };
|
|
518
|
-
return { type, ...data } as MessageElem;
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
}
|