@zhin.js/adapter-telegram 1.0.36 → 1.0.38

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,865 @@
1
+ /**
2
+ * Telegram Bot 实现
3
+ */
4
+ import { Telegraf } from "telegraf";
5
+ import { Message, segment, } from "zhin.js";
6
+ export class TelegramBot extends Telegraf {
7
+ adapter;
8
+ $config;
9
+ $connected = false;
10
+ get pluginLogger() {
11
+ return this.adapter.plugin.logger;
12
+ }
13
+ get $id() {
14
+ return this.$config.name;
15
+ }
16
+ constructor(adapter, $config) {
17
+ super($config.token);
18
+ this.adapter = adapter;
19
+ this.$config = $config;
20
+ }
21
+ async $connect() {
22
+ try {
23
+ // Set up message handler
24
+ this.on("message", async (ctx) => {
25
+ await this.handleTelegramMessage(ctx);
26
+ });
27
+ // Set up callback query handler (for inline buttons)
28
+ this.on("callback_query", async (ctx) => {
29
+ // Handle callback queries as special messages
30
+ if (ctx.callbackQuery && "data" in ctx.callbackQuery) {
31
+ const message = this.$formatCallbackQuery(ctx);
32
+ this.adapter.emit("message.receive", message);
33
+ this.pluginLogger.debug(`${this.$config.name} recv callback ${message.$channel.type}(${message.$channel.id}): ${segment.raw(message.$content)}`);
34
+ }
35
+ });
36
+ // Start bot with polling or webhook
37
+ if (this.$config.polling !== false) {
38
+ // Use polling by default
39
+ await this.launch({
40
+ allowedUpdates: this.$config.allowedUpdates,
41
+ });
42
+ }
43
+ else if (this.$config.webhook) {
44
+ // Use webhook
45
+ const { domain, path = "/telegram-webhook", port } = this.$config.webhook;
46
+ await this.launch({
47
+ webhook: {
48
+ domain,
49
+ port,
50
+ hookPath: path,
51
+ },
52
+ allowedUpdates: this.$config.allowedUpdates,
53
+ });
54
+ }
55
+ else {
56
+ throw new Error("Either polling must be enabled or webhook configuration must be provided");
57
+ }
58
+ this.$connected = true;
59
+ const me = await this.telegram.getMe();
60
+ this.pluginLogger.info(`Telegram bot ${this.$config.name} connected successfully as @${me.username}`);
61
+ }
62
+ catch (error) {
63
+ this.pluginLogger.error("Failed to connect Telegram bot:", error);
64
+ this.$connected = false;
65
+ throw error;
66
+ }
67
+ }
68
+ async $disconnect() {
69
+ try {
70
+ await this.stop();
71
+ this.$connected = false;
72
+ this.pluginLogger.info(`Telegram bot ${this.$config.name} disconnected`);
73
+ }
74
+ catch (error) {
75
+ this.pluginLogger.error("Error disconnecting Telegram bot:", error);
76
+ throw error;
77
+ }
78
+ }
79
+ async handleTelegramMessage(ctx) {
80
+ if (!ctx.message)
81
+ return;
82
+ const message = this.$formatMessage(ctx.message);
83
+ this.adapter.emit("message.receive", message);
84
+ this.pluginLogger.debug(`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}): ${segment.raw(message.$content)}`);
85
+ }
86
+ $formatMessage(msg) {
87
+ // Determine channel type
88
+ const channelType = msg.chat.type === "private" ? "private" : "group";
89
+ const channelId = msg.chat.id.toString();
90
+ // Parse message content
91
+ const content = this.parseMessageContent(msg);
92
+ const result = Message.from(msg, {
93
+ $id: msg.message_id.toString(),
94
+ $adapter: "telegram",
95
+ $bot: this.$config.name,
96
+ $sender: {
97
+ id: msg.from?.id.toString() || "",
98
+ name: msg.from?.username || msg.from?.first_name || "Unknown",
99
+ },
100
+ $channel: {
101
+ id: channelId,
102
+ type: channelType,
103
+ },
104
+ $content: content,
105
+ $raw: "text" in msg ? msg.text || "" : "",
106
+ $timestamp: msg.date * 1000,
107
+ $recall: async () => {
108
+ try {
109
+ await this.telegram.deleteMessage(parseInt(channelId), parseInt(result.$id));
110
+ }
111
+ catch (error) {
112
+ this.pluginLogger.error("Error recalling Telegram message:", error);
113
+ throw error;
114
+ }
115
+ },
116
+ $reply: async (content, quote) => {
117
+ if (!Array.isArray(content))
118
+ content = [content];
119
+ // Handle reply
120
+ if (quote) {
121
+ const replyToMessageId = typeof quote === "boolean" ? result.$id : quote;
122
+ content.unshift({ type: "reply", data: { id: replyToMessageId } });
123
+ }
124
+ return await this.adapter.sendMessage({
125
+ context: "telegram",
126
+ bot: this.$config.name,
127
+ id: channelId,
128
+ type: channelType,
129
+ content: content,
130
+ });
131
+ },
132
+ });
133
+ return result;
134
+ }
135
+ $formatCallbackQuery(ctx) {
136
+ if (!ctx.callbackQuery || !("data" in ctx.callbackQuery)) {
137
+ throw new Error("Invalid callback query");
138
+ }
139
+ const query = ctx.callbackQuery;
140
+ const msg = query.message;
141
+ const channelType = msg && "chat" in msg && msg.chat.type === "private" ? "private" : "group";
142
+ const channelId = msg && "chat" in msg ? msg.chat.id.toString() : query.from.id.toString();
143
+ const result = Message.from(query, {
144
+ $id: query.id,
145
+ $adapter: "telegram",
146
+ $bot: this.$config.name,
147
+ $sender: {
148
+ id: query.from.id.toString(),
149
+ name: query.from.username || query.from.first_name,
150
+ },
151
+ $channel: {
152
+ id: channelId,
153
+ type: channelType,
154
+ },
155
+ $content: [{ type: "text", data: { text: query.data } }],
156
+ $raw: query.data,
157
+ $timestamp: Date.now(),
158
+ $recall: async () => {
159
+ // Callback queries cannot be recalled
160
+ },
161
+ $reply: async (content) => {
162
+ if (!Array.isArray(content))
163
+ content = [content];
164
+ const sentMsg = await this.sendContentToChat(parseInt(channelId), content);
165
+ return sentMsg.message_id.toString();
166
+ },
167
+ });
168
+ return result;
169
+ }
170
+ parseMessageContent(msg) {
171
+ const segments = [];
172
+ // Handle text messages
173
+ if ("text" in msg && msg.text) {
174
+ // Check for reply
175
+ if (msg.reply_to_message) {
176
+ segments.push({
177
+ type: "reply",
178
+ data: {
179
+ id: msg.reply_to_message.message_id.toString(),
180
+ },
181
+ });
182
+ }
183
+ // Parse text with entities
184
+ if (msg.entities && msg.entities.length > 0) {
185
+ segments.push(...this.parseTextWithEntities(msg.text, msg.entities));
186
+ }
187
+ else {
188
+ segments.push({ type: "text", data: { text: msg.text } });
189
+ }
190
+ }
191
+ // Handle photo
192
+ if ("photo" in msg && msg.photo) {
193
+ const largestPhoto = msg.photo[msg.photo.length - 1];
194
+ segments.push({
195
+ type: "image",
196
+ data: {
197
+ file_id: largestPhoto.file_id,
198
+ file_unique_id: largestPhoto.file_unique_id,
199
+ width: largestPhoto.width,
200
+ height: largestPhoto.height,
201
+ file_size: largestPhoto.file_size,
202
+ },
203
+ });
204
+ if (msg.caption) {
205
+ segments.push({ type: "text", data: { text: msg.caption } });
206
+ }
207
+ }
208
+ // Handle video
209
+ if ("video" in msg && msg.video) {
210
+ segments.push({
211
+ type: "video",
212
+ data: {
213
+ file_id: msg.video.file_id,
214
+ file_unique_id: msg.video.file_unique_id,
215
+ width: msg.video.width,
216
+ height: msg.video.height,
217
+ duration: msg.video.duration,
218
+ file_size: msg.video.file_size,
219
+ },
220
+ });
221
+ if (msg.caption) {
222
+ segments.push({ type: "text", data: { text: msg.caption } });
223
+ }
224
+ }
225
+ // Handle audio
226
+ if ("audio" in msg && msg.audio) {
227
+ segments.push({
228
+ type: "audio",
229
+ data: {
230
+ file_id: msg.audio.file_id,
231
+ file_unique_id: msg.audio.file_unique_id,
232
+ duration: msg.audio.duration,
233
+ performer: msg.audio.performer,
234
+ title: msg.audio.title,
235
+ file_size: msg.audio.file_size,
236
+ },
237
+ });
238
+ }
239
+ // Handle voice
240
+ if ("voice" in msg && msg.voice) {
241
+ segments.push({
242
+ type: "voice",
243
+ data: {
244
+ file_id: msg.voice.file_id,
245
+ file_unique_id: msg.voice.file_unique_id,
246
+ duration: msg.voice.duration,
247
+ file_size: msg.voice.file_size,
248
+ },
249
+ });
250
+ }
251
+ // Handle document
252
+ if ("document" in msg && msg.document) {
253
+ segments.push({
254
+ type: "file",
255
+ data: {
256
+ file_id: msg.document.file_id,
257
+ file_unique_id: msg.document.file_unique_id,
258
+ file_name: msg.document.file_name,
259
+ mime_type: msg.document.mime_type,
260
+ file_size: msg.document.file_size,
261
+ },
262
+ });
263
+ }
264
+ // Handle sticker
265
+ if ("sticker" in msg && msg.sticker) {
266
+ segments.push({
267
+ type: "sticker",
268
+ data: {
269
+ file_id: msg.sticker.file_id,
270
+ file_unique_id: msg.sticker.file_unique_id,
271
+ width: msg.sticker.width,
272
+ height: msg.sticker.height,
273
+ is_animated: msg.sticker.is_animated,
274
+ is_video: msg.sticker.is_video,
275
+ emoji: msg.sticker.emoji,
276
+ },
277
+ });
278
+ }
279
+ // Handle location
280
+ if ("location" in msg && msg.location) {
281
+ segments.push({
282
+ type: "location",
283
+ data: {
284
+ longitude: msg.location.longitude,
285
+ latitude: msg.location.latitude,
286
+ },
287
+ });
288
+ }
289
+ return segments.length > 0
290
+ ? segments
291
+ : [{ type: "text", data: { text: "" } }];
292
+ }
293
+ parseTextWithEntities(text, entities) {
294
+ const segments = [];
295
+ let lastOffset = 0;
296
+ for (const entity of entities) {
297
+ // Add text before entity
298
+ if (entity.offset > lastOffset) {
299
+ const beforeText = text.slice(lastOffset, entity.offset);
300
+ if (beforeText) {
301
+ segments.push({ type: "text", data: { text: beforeText } });
302
+ }
303
+ }
304
+ const entityText = text.slice(entity.offset, entity.offset + entity.length);
305
+ switch (entity.type) {
306
+ case "mention":
307
+ case "text_mention":
308
+ segments.push({
309
+ type: "at",
310
+ data: {
311
+ id: ("user" in entity && entity.user?.id.toString()) || entityText.slice(1),
312
+ name: ("user" in entity && entity.user?.username) || entityText,
313
+ text: entityText,
314
+ },
315
+ });
316
+ break;
317
+ case "url":
318
+ case "text_link":
319
+ segments.push({
320
+ type: "link",
321
+ data: {
322
+ url: ("url" in entity && entity.url) || entityText,
323
+ text: entityText,
324
+ },
325
+ });
326
+ break;
327
+ case "hashtag":
328
+ segments.push({
329
+ type: "text",
330
+ data: { text: entityText },
331
+ });
332
+ break;
333
+ case "bold":
334
+ case "italic":
335
+ case "code":
336
+ case "pre":
337
+ case "underline":
338
+ case "strikethrough":
339
+ segments.push({
340
+ type: "text",
341
+ data: { text: entityText, format: entity.type },
342
+ });
343
+ break;
344
+ default:
345
+ segments.push({ type: "text", data: { text: entityText } });
346
+ }
347
+ lastOffset = entity.offset + entity.length;
348
+ }
349
+ // Add remaining text
350
+ if (lastOffset < text.length) {
351
+ const remainingText = text.slice(lastOffset);
352
+ if (remainingText) {
353
+ segments.push({ type: "text", data: { text: remainingText } });
354
+ }
355
+ }
356
+ return segments;
357
+ }
358
+ async $sendMessage(options) {
359
+ try {
360
+ const chatId = parseInt(options.id);
361
+ const result = await this.sendContentToChat(chatId, options.content);
362
+ this.pluginLogger.debug(`${this.$config.name} send ${options.type}(${options.id}): ${segment.raw(options.content)}`);
363
+ return result.message_id.toString();
364
+ }
365
+ catch (error) {
366
+ this.pluginLogger.error("Failed to send Telegram message:", error);
367
+ throw error;
368
+ }
369
+ }
370
+ async sendContentToChat(chatId, content, extraOptions = {}) {
371
+ if (!Array.isArray(content))
372
+ content = [content];
373
+ let textContent = "";
374
+ let hasMedia = false;
375
+ for (const segment of content) {
376
+ if (typeof segment === "string") {
377
+ textContent += segment;
378
+ continue;
379
+ }
380
+ const { type, data } = segment;
381
+ switch (type) {
382
+ case "text":
383
+ textContent += data.text || "";
384
+ break;
385
+ case "at":
386
+ if (data.id) {
387
+ textContent += `@${data.name || data.id}`;
388
+ }
389
+ break;
390
+ case "image":
391
+ hasMedia = true;
392
+ if (data.file_id) {
393
+ // Send by file_id
394
+ return await this.telegram.sendPhoto(chatId, data.file_id, {
395
+ caption: textContent || undefined,
396
+ ...extraOptions,
397
+ });
398
+ }
399
+ else if (data.url) {
400
+ // Send by URL
401
+ return await this.telegram.sendPhoto(chatId, data.url, {
402
+ caption: textContent || undefined,
403
+ ...extraOptions,
404
+ });
405
+ }
406
+ else if (data.file) {
407
+ // Send by file path
408
+ return await this.telegram.sendPhoto(chatId, { source: data.file }, {
409
+ caption: textContent || undefined,
410
+ ...extraOptions,
411
+ });
412
+ }
413
+ break;
414
+ case "video":
415
+ hasMedia = true;
416
+ if (data.file_id) {
417
+ return await this.telegram.sendVideo(chatId, data.file_id, {
418
+ caption: textContent || undefined,
419
+ ...extraOptions,
420
+ });
421
+ }
422
+ else if (data.url) {
423
+ return await this.telegram.sendVideo(chatId, data.url, {
424
+ caption: textContent || undefined,
425
+ ...extraOptions,
426
+ });
427
+ }
428
+ else if (data.file) {
429
+ return await this.telegram.sendVideo(chatId, { source: data.file }, {
430
+ caption: textContent || undefined,
431
+ ...extraOptions,
432
+ });
433
+ }
434
+ break;
435
+ case "audio":
436
+ hasMedia = true;
437
+ if (data.file_id) {
438
+ return await this.telegram.sendAudio(chatId, data.file_id, {
439
+ caption: textContent || undefined,
440
+ ...extraOptions,
441
+ });
442
+ }
443
+ else if (data.url) {
444
+ return await this.telegram.sendAudio(chatId, data.url, {
445
+ caption: textContent || undefined,
446
+ ...extraOptions,
447
+ });
448
+ }
449
+ else if (data.file) {
450
+ return await this.telegram.sendAudio(chatId, { source: data.file }, {
451
+ caption: textContent || undefined,
452
+ ...extraOptions,
453
+ });
454
+ }
455
+ break;
456
+ case "voice":
457
+ hasMedia = true;
458
+ if (data.file_id) {
459
+ return await this.telegram.sendVoice(chatId, data.file_id, {
460
+ caption: textContent || undefined,
461
+ ...extraOptions,
462
+ });
463
+ }
464
+ else if (data.url) {
465
+ return await this.telegram.sendVoice(chatId, data.url, {
466
+ caption: textContent || undefined,
467
+ ...extraOptions,
468
+ });
469
+ }
470
+ else if (data.file) {
471
+ return await this.telegram.sendVoice(chatId, { source: data.file }, {
472
+ caption: textContent || undefined,
473
+ ...extraOptions,
474
+ });
475
+ }
476
+ break;
477
+ case "file":
478
+ hasMedia = true;
479
+ if (data.file_id) {
480
+ return await this.telegram.sendDocument(chatId, data.file_id, {
481
+ caption: textContent || undefined,
482
+ ...extraOptions,
483
+ });
484
+ }
485
+ else if (data.url) {
486
+ return await this.telegram.sendDocument(chatId, data.url, {
487
+ caption: textContent || undefined,
488
+ ...extraOptions,
489
+ });
490
+ }
491
+ else if (data.file) {
492
+ return await this.telegram.sendDocument(chatId, { source: data.file }, {
493
+ caption: textContent || undefined,
494
+ ...extraOptions,
495
+ });
496
+ }
497
+ break;
498
+ case "sticker":
499
+ if (data.file_id) {
500
+ hasMedia = true;
501
+ return await this.telegram.sendSticker(chatId, data.file_id, extraOptions);
502
+ }
503
+ break;
504
+ case "location":
505
+ return await this.telegram.sendLocation(chatId, data.latitude, data.longitude, extraOptions);
506
+ case "reply":
507
+ return await this.telegram.sendMessage(chatId, data.id, {
508
+ reply_parameters: { message_id: parseInt(data.id) },
509
+ ...extraOptions,
510
+ });
511
+ default:
512
+ // Unknown segment type, add as text
513
+ textContent += data.text || `[${type}]`;
514
+ }
515
+ }
516
+ // If no media was sent, send as text message
517
+ if (!hasMedia && textContent.trim()) {
518
+ return await this.telegram.sendMessage(chatId, textContent.trim(), extraOptions);
519
+ }
520
+ // If neither media nor text was sent, this is an error
521
+ throw new Error("TelegramBot.$sendMessage: No media or text content to send.");
522
+ }
523
+ async $recallMessage(id) {
524
+ // Telegram requires both chat_id and message_id to delete a message
525
+ // The Bot interface only provides message_id, making recall impossible
526
+ // Users should use message.$recall() instead, which has the full context
527
+ throw new Error("TelegramBot.$recallMessage: Message recall not supported without chat_id. " +
528
+ "Use message.$recall() method instead, which contains the required context.");
529
+ }
530
+ // ==================== 群组管理 API ====================
531
+ /**
532
+ * 踢出用户
533
+ * @param chatId 聊天 ID
534
+ * @param userId 用户 ID
535
+ * @param untilDate 封禁截止时间(Unix 时间戳),0 表示永久
536
+ */
537
+ async kickMember(chatId, userId, untilDate) {
538
+ try {
539
+ await this.telegram.banChatMember(chatId, userId, untilDate);
540
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 踢出用户 ${userId} 从聊天 ${chatId}`);
541
+ return true;
542
+ }
543
+ catch (error) {
544
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 踢出用户失败:`, error);
545
+ throw error;
546
+ }
547
+ }
548
+ /**
549
+ * 解除封禁
550
+ * @param chatId 聊天 ID
551
+ * @param userId 用户 ID
552
+ */
553
+ async unbanMember(chatId, userId) {
554
+ try {
555
+ await this.telegram.unbanChatMember(chatId, userId, { only_if_banned: true });
556
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 解除用户 ${userId} 的封禁(聊天 ${chatId})`);
557
+ return true;
558
+ }
559
+ catch (error) {
560
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 解除封禁失败:`, error);
561
+ throw error;
562
+ }
563
+ }
564
+ /**
565
+ * 限制用户权限(禁言等)
566
+ * @param chatId 聊天 ID
567
+ * @param userId 用户 ID
568
+ * @param permissions 权限设置
569
+ * @param untilDate 限制截止时间
570
+ */
571
+ async restrictMember(chatId, userId, permissions, untilDate) {
572
+ try {
573
+ await this.telegram.restrictChatMember(chatId, userId, {
574
+ permissions,
575
+ until_date: untilDate,
576
+ });
577
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 限制用户 ${userId} 权限(聊天 ${chatId})`);
578
+ return true;
579
+ }
580
+ catch (error) {
581
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 限制权限失败:`, error);
582
+ throw error;
583
+ }
584
+ }
585
+ /**
586
+ * 禁言用户
587
+ * @param chatId 聊天 ID
588
+ * @param userId 用户 ID
589
+ * @param duration 禁言时长(秒),0 表示解除禁言
590
+ */
591
+ async muteMember(chatId, userId, duration = 600) {
592
+ try {
593
+ if (duration === 0) {
594
+ // 解除禁言 - 恢复发送消息权限
595
+ await this.telegram.restrictChatMember(chatId, userId, {
596
+ permissions: {
597
+ can_send_messages: true,
598
+ can_send_audios: true,
599
+ can_send_documents: true,
600
+ can_send_photos: true,
601
+ can_send_videos: true,
602
+ can_send_video_notes: true,
603
+ can_send_voice_notes: true,
604
+ can_send_polls: true,
605
+ can_send_other_messages: true,
606
+ can_add_web_page_previews: true,
607
+ },
608
+ });
609
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 解除用户 ${userId} 禁言(聊天 ${chatId})`);
610
+ }
611
+ else {
612
+ const untilDate = Math.floor(Date.now() / 1000) + duration;
613
+ await this.telegram.restrictChatMember(chatId, userId, {
614
+ permissions: {
615
+ can_send_messages: false,
616
+ can_send_audios: false,
617
+ can_send_documents: false,
618
+ can_send_photos: false,
619
+ can_send_videos: false,
620
+ can_send_video_notes: false,
621
+ can_send_voice_notes: false,
622
+ can_send_polls: false,
623
+ can_send_other_messages: false,
624
+ can_add_web_page_previews: false,
625
+ },
626
+ until_date: untilDate,
627
+ });
628
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 禁言用户 ${userId} ${duration}秒(聊天 ${chatId})`);
629
+ }
630
+ return true;
631
+ }
632
+ catch (error) {
633
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 禁言操作失败:`, error);
634
+ throw error;
635
+ }
636
+ }
637
+ /**
638
+ * 提升/降级管理员
639
+ * @param chatId 聊天 ID
640
+ * @param userId 用户 ID
641
+ * @param promote 是否提升为管理员
642
+ */
643
+ async setAdmin(chatId, userId, promote = true) {
644
+ try {
645
+ if (promote) {
646
+ await this.telegram.promoteChatMember(chatId, userId, {
647
+ can_manage_chat: true,
648
+ can_delete_messages: true,
649
+ can_manage_video_chats: true,
650
+ can_restrict_members: true,
651
+ can_promote_members: false,
652
+ can_change_info: true,
653
+ can_invite_users: true,
654
+ can_pin_messages: true,
655
+ });
656
+ }
657
+ else {
658
+ await this.telegram.promoteChatMember(chatId, userId, {
659
+ can_manage_chat: false,
660
+ can_delete_messages: false,
661
+ can_manage_video_chats: false,
662
+ can_restrict_members: false,
663
+ can_promote_members: false,
664
+ can_change_info: false,
665
+ can_invite_users: false,
666
+ can_pin_messages: false,
667
+ });
668
+ }
669
+ this.pluginLogger.info(`Telegram Bot ${this.$id} ${promote ? '提升' : '降级'}用户 ${userId} 为管理员(聊天 ${chatId})`);
670
+ return true;
671
+ }
672
+ catch (error) {
673
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 设置管理员失败:`, error);
674
+ throw error;
675
+ }
676
+ }
677
+ /**
678
+ * 设置聊天标题
679
+ * @param chatId 聊天 ID
680
+ * @param title 新标题
681
+ */
682
+ async setChatTitle(chatId, title) {
683
+ try {
684
+ await this.telegram.setChatTitle(chatId, title);
685
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 设置聊天 ${chatId} 标题为 "${title}"`);
686
+ return true;
687
+ }
688
+ catch (error) {
689
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 设置标题失败:`, error);
690
+ throw error;
691
+ }
692
+ }
693
+ /**
694
+ * 设置聊天描述
695
+ * @param chatId 聊天 ID
696
+ * @param description 新描述
697
+ */
698
+ async setChatDescription(chatId, description) {
699
+ try {
700
+ await this.telegram.setChatDescription(chatId, description);
701
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 设置聊天 ${chatId} 描述`);
702
+ return true;
703
+ }
704
+ catch (error) {
705
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 设置描述失败:`, error);
706
+ throw error;
707
+ }
708
+ }
709
+ /**
710
+ * 置顶消息
711
+ * @param chatId 聊天 ID
712
+ * @param messageId 消息 ID
713
+ */
714
+ async pinMessage(chatId, messageId) {
715
+ try {
716
+ await this.telegram.pinChatMessage(chatId, messageId);
717
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 置顶消息 ${messageId}(聊天 ${chatId})`);
718
+ return true;
719
+ }
720
+ catch (error) {
721
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 置顶消息失败:`, error);
722
+ throw error;
723
+ }
724
+ }
725
+ /**
726
+ * 取消置顶消息
727
+ * @param chatId 聊天 ID
728
+ * @param messageId 消息 ID(可选,不提供则取消所有置顶)
729
+ */
730
+ async unpinMessage(chatId, messageId) {
731
+ try {
732
+ if (messageId) {
733
+ await this.telegram.unpinChatMessage(chatId, messageId);
734
+ }
735
+ else {
736
+ await this.telegram.unpinAllChatMessages(chatId);
737
+ }
738
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 取消置顶消息(聊天 ${chatId})`);
739
+ return true;
740
+ }
741
+ catch (error) {
742
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 取消置顶失败:`, error);
743
+ throw error;
744
+ }
745
+ }
746
+ /**
747
+ * 获取聊天信息
748
+ * @param chatId 聊天 ID
749
+ */
750
+ async getChatInfo(chatId) {
751
+ try {
752
+ return await this.telegram.getChat(chatId);
753
+ }
754
+ catch (error) {
755
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 获取聊天信息失败:`, error);
756
+ throw error;
757
+ }
758
+ }
759
+ /**
760
+ * 获取聊天成员
761
+ * @param chatId 聊天 ID
762
+ * @param userId 用户 ID
763
+ */
764
+ async getChatMember(chatId, userId) {
765
+ try {
766
+ return await this.telegram.getChatMember(chatId, userId);
767
+ }
768
+ catch (error) {
769
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 获取成员信息失败:`, error);
770
+ throw error;
771
+ }
772
+ }
773
+ /**
774
+ * 获取管理员列表
775
+ * @param chatId 聊天 ID
776
+ */
777
+ async getChatAdmins(chatId) {
778
+ try {
779
+ return await this.telegram.getChatAdministrators(chatId);
780
+ }
781
+ catch (error) {
782
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 获取管理员列表失败:`, error);
783
+ throw error;
784
+ }
785
+ }
786
+ /**
787
+ * 获取聊天成员数量
788
+ * @param chatId 聊天 ID
789
+ */
790
+ async getChatMemberCount(chatId) {
791
+ try {
792
+ return await this.telegram.getChatMembersCount(chatId);
793
+ }
794
+ catch (error) {
795
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 获取成员数量失败:`, error);
796
+ throw error;
797
+ }
798
+ }
799
+ /**
800
+ * 创建邀请链接
801
+ * @param chatId 聊天 ID
802
+ */
803
+ async createInviteLink(chatId) {
804
+ try {
805
+ const link = await this.telegram.createChatInviteLink(chatId, {});
806
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 创建邀请链接(聊天 ${chatId})`);
807
+ return link.invite_link;
808
+ }
809
+ catch (error) {
810
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 创建邀请链接失败:`, error);
811
+ throw error;
812
+ }
813
+ }
814
+ async sendPoll(chatId, question, options, isAnonymous = true, allowsMultipleAnswers = false) {
815
+ try {
816
+ const result = await this.telegram.sendPoll(chatId, question, options, {
817
+ is_anonymous: isAnonymous,
818
+ allows_multiple_answers: allowsMultipleAnswers,
819
+ });
820
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 发送投票到 ${chatId}`);
821
+ return result;
822
+ }
823
+ catch (error) {
824
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 发送投票失败:`, error);
825
+ throw error;
826
+ }
827
+ }
828
+ async setMessageReaction(chatId, messageId, reaction) {
829
+ try {
830
+ await this.telegram.callApi('setMessageReaction', {
831
+ chat_id: chatId,
832
+ message_id: messageId,
833
+ reaction: [{ type: 'emoji', emoji: reaction }],
834
+ });
835
+ return true;
836
+ }
837
+ catch (error) {
838
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 设置反应失败:`, error);
839
+ throw error;
840
+ }
841
+ }
842
+ async sendStickerMessage(chatId, sticker) {
843
+ try {
844
+ const result = await this.telegram.sendSticker(chatId, sticker);
845
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 发送贴纸到 ${chatId}`);
846
+ return result;
847
+ }
848
+ catch (error) {
849
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 发送贴纸失败:`, error);
850
+ throw error;
851
+ }
852
+ }
853
+ async setChatPermissionsAll(chatId, permissions) {
854
+ try {
855
+ await this.telegram.setChatPermissions(chatId, permissions);
856
+ this.pluginLogger.info(`Telegram Bot ${this.$id} 设置聊天 ${chatId} 权限`);
857
+ return true;
858
+ }
859
+ catch (error) {
860
+ this.pluginLogger.error(`Telegram Bot ${this.$id} 设置聊天权限失败:`, error);
861
+ throw error;
862
+ }
863
+ }
864
+ }
865
+ //# sourceMappingURL=bot.js.map