@zhin.js/adapter-telegram 5.0.2 → 5.0.3
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 +41 -0
- package/README.md +61 -144
- package/adapters/telegram.ts +27 -0
- package/agent/tools/create_invite.ts +2 -2
- package/agent/tools/list_admins.ts +2 -2
- package/agent/tools/member_count.ts +2 -2
- package/agent/tools/pin_message.ts +2 -2
- package/agent/tools/react.ts +2 -2
- package/agent/tools/send_poll.ts +2 -2
- package/agent/tools/send_sticker.ts +2 -2
- package/agent/tools/set_description.ts +2 -2
- package/agent/tools/set_permissions.ts +2 -2
- package/agent/tools/unpin_message.ts +2 -2
- package/lib/endpoint.d.ts +65 -0
- package/lib/endpoint.js +332 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +4 -0
- package/lib/platform-permit.d.ts +18 -0
- package/lib/{src/platform-permit.js → platform-permit.js} +1 -2
- package/lib/polling.d.ts +9 -0
- package/lib/polling.js +52 -0
- package/lib/protocol.d.ts +250 -0
- package/lib/protocol.js +324 -0
- package/lib/telegram-agent-deps.d.ts +28 -0
- package/lib/telegram-agent-deps.js +30 -0
- package/lib/webhook.d.ts +13 -0
- package/lib/webhook.js +45 -0
- package/package.json +43 -40
- package/plugin.ts +13 -0
- package/schema.json +39 -0
- package/src/endpoint.ts +339 -1103
- package/src/index.ts +40 -186
- package/src/platform-permit.ts +1 -1
- package/src/polling.ts +71 -0
- package/src/protocol.ts +573 -0
- package/src/telegram-agent-deps.ts +52 -11
- package/src/webhook.ts +67 -0
- package/client/Dashboard.tsx +0 -295
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -30
- package/dist/index.js +0 -32
- package/lib/agent/tools/create_invite.js +0 -20
- package/lib/agent/tools/create_invite.js.map +0 -1
- package/lib/agent/tools/list_admins.js +0 -26
- package/lib/agent/tools/list_admins.js.map +0 -1
- package/lib/agent/tools/member_count.js +0 -18
- package/lib/agent/tools/member_count.js.map +0 -1
- package/lib/agent/tools/pin_message.js +0 -21
- package/lib/agent/tools/pin_message.js.map +0 -1
- package/lib/agent/tools/react.js +0 -20
- package/lib/agent/tools/react.js.map +0 -1
- package/lib/agent/tools/send_poll.js +0 -32
- package/lib/agent/tools/send_poll.js.map +0 -1
- package/lib/agent/tools/send_sticker.js +0 -19
- package/lib/agent/tools/send_sticker.js.map +0 -1
- package/lib/agent/tools/set_description.js +0 -19
- package/lib/agent/tools/set_description.js.map +0 -1
- package/lib/agent/tools/set_permissions.js +0 -34
- package/lib/agent/tools/set_permissions.js.map +0 -1
- package/lib/agent/tools/unpin_message.js +0 -21
- package/lib/agent/tools/unpin_message.js.map +0 -1
- package/lib/src/adapter.js +0 -58
- package/lib/src/adapter.js.map +0 -1
- package/lib/src/endpoint.js +0 -1046
- package/lib/src/endpoint.js.map +0 -1
- package/lib/src/index.js +0 -215
- package/lib/src/index.js.map +0 -1
- package/lib/src/platform-permit.js.map +0 -1
- package/lib/src/segment-mapper.js +0 -2
- package/lib/src/segment-mapper.js.map +0 -1
- package/lib/src/telegram-agent-deps.js +0 -10
- package/lib/src/telegram-agent-deps.js.map +0 -1
- package/lib/src/types.js +0 -2
- package/lib/src/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -66
- package/src/segment-mapper.ts +0 -1
- package/src/types.ts +0 -32
package/lib/src/endpoint.js
DELETED
|
@@ -1,1046 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telegram Endpoint 实现
|
|
3
|
-
*/
|
|
4
|
-
import { Telegraf } from "telegraf";
|
|
5
|
-
import { Message, segment, expandInteractiveSegmentsInContent, } from 'zhin.js';
|
|
6
|
-
import { normalizeTelegramChatMember } from "./platform-permit.js";
|
|
7
|
-
import { fromCanonicalSegments, toCanonicalSegments } from './segment-mapper.js';
|
|
8
|
-
export class TelegramEndpoint extends Telegraf {
|
|
9
|
-
adapter;
|
|
10
|
-
$config;
|
|
11
|
-
$connected = false;
|
|
12
|
-
/** message_id -> chat_id,用于在仅有 message_id 的场景执行 reaction 操作 */
|
|
13
|
-
messageChatMap = new Map();
|
|
14
|
-
/** reply_to_message 解析结果缓存,供 $getMsg 使用 */
|
|
15
|
-
quotedPayloadCache = new Map();
|
|
16
|
-
get pluginLogger() {
|
|
17
|
-
return this.adapter.plugin.logger;
|
|
18
|
-
}
|
|
19
|
-
get $id() {
|
|
20
|
-
return this.$config.name;
|
|
21
|
-
}
|
|
22
|
-
constructor(adapter, $config) {
|
|
23
|
-
super($config.token);
|
|
24
|
-
this.adapter = adapter;
|
|
25
|
-
this.$config = $config;
|
|
26
|
-
}
|
|
27
|
-
async $connect() {
|
|
28
|
-
try {
|
|
29
|
-
// Set up message handler
|
|
30
|
-
this.on("message", async (ctx) => {
|
|
31
|
-
await this.handleTelegramMessage(ctx);
|
|
32
|
-
});
|
|
33
|
-
// Set up callback query handler (for inline buttons)
|
|
34
|
-
this.on("callback_query", async (ctx) => {
|
|
35
|
-
if (ctx.callbackQuery && "data" in ctx.callbackQuery) {
|
|
36
|
-
try {
|
|
37
|
-
await ctx.answerCbQuery();
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
// already answered
|
|
41
|
-
}
|
|
42
|
-
const message = this.$formatCallbackQuery(ctx);
|
|
43
|
-
this.adapter.emit("message.receive", message);
|
|
44
|
-
this.pluginLogger.debug(`${this.$config.name} recv callback ${message.$channel.type}(${message.$channel.id}): ${segment.raw(message.$content)}`);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
// Start bot with polling or webhook
|
|
48
|
-
if (this.$config.polling !== false) {
|
|
49
|
-
// Use polling by default
|
|
50
|
-
await this.launch({
|
|
51
|
-
allowedUpdates: this.$config.allowedUpdates,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
else if (this.$config.webhook) {
|
|
55
|
-
// Use webhook
|
|
56
|
-
const { domain, path = "/telegram-webhook", port } = this.$config.webhook;
|
|
57
|
-
await this.launch({
|
|
58
|
-
webhook: {
|
|
59
|
-
domain,
|
|
60
|
-
port,
|
|
61
|
-
hookPath: path,
|
|
62
|
-
},
|
|
63
|
-
allowedUpdates: this.$config.allowedUpdates,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
throw new Error("Either polling must be enabled or webhook configuration must be provided");
|
|
68
|
-
}
|
|
69
|
-
this.$connected = true;
|
|
70
|
-
const me = await this.telegram.getMe();
|
|
71
|
-
this.pluginLogger.info(`Telegram endpoint ${this.$config.name} connected successfully as @${me.username}`);
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
this.pluginLogger.error("Failed to connect Telegram bot:", error);
|
|
75
|
-
this.$connected = false;
|
|
76
|
-
throw error;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
async $disconnect() {
|
|
80
|
-
try {
|
|
81
|
-
this.removeAllListeners();
|
|
82
|
-
this.chatMemberCache.clear();
|
|
83
|
-
await this.stop();
|
|
84
|
-
this.$connected = false;
|
|
85
|
-
this.pluginLogger.info(`Telegram endpoint ${this.$config.name} disconnected`);
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
this.pluginLogger.error("Error disconnecting Telegram bot:", error);
|
|
89
|
-
throw error;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
static CHAT_MEMBER_CACHE_TTL_MS = 60_000;
|
|
93
|
-
static CHAT_MEMBER_CACHE_MAX = 2_000;
|
|
94
|
-
chatMemberCache = new Map();
|
|
95
|
-
sweepChatMemberCache(now) {
|
|
96
|
-
const ttl = TelegramEndpoint.CHAT_MEMBER_CACHE_TTL_MS;
|
|
97
|
-
for (const [key, entry] of this.chatMemberCache) {
|
|
98
|
-
if (now - entry.at >= ttl)
|
|
99
|
-
this.chatMemberCache.delete(key);
|
|
100
|
-
}
|
|
101
|
-
if (this.chatMemberCache.size > TelegramEndpoint.CHAT_MEMBER_CACHE_MAX) {
|
|
102
|
-
const excess = this.chatMemberCache.size - TelegramEndpoint.CHAT_MEMBER_CACHE_MAX;
|
|
103
|
-
let removed = 0;
|
|
104
|
-
for (const [key] of this.chatMemberCache) {
|
|
105
|
-
if (removed >= excess)
|
|
106
|
-
break;
|
|
107
|
-
this.chatMemberCache.delete(key);
|
|
108
|
-
removed++;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
async enrichGroupSender(message, msg) {
|
|
113
|
-
if (message.$channel.type !== "group" || !msg.from?.id)
|
|
114
|
-
return;
|
|
115
|
-
const chatId = Number(msg.chat.id);
|
|
116
|
-
const userId = msg.from.id;
|
|
117
|
-
const key = `${chatId}:${userId}`;
|
|
118
|
-
const now = Date.now();
|
|
119
|
-
this.sweepChatMemberCache(now);
|
|
120
|
-
const cached = this.chatMemberCache.get(key);
|
|
121
|
-
if (cached && now - cached.at < TelegramEndpoint.CHAT_MEMBER_CACHE_TTL_MS) {
|
|
122
|
-
message.$sender.role = cached.role;
|
|
123
|
-
message.$sender.permissions = cached.permissions;
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
try {
|
|
127
|
-
const member = await this.getChatMember(chatId, userId);
|
|
128
|
-
const normalized = normalizeTelegramChatMember(member);
|
|
129
|
-
this.chatMemberCache.set(key, { at: now, ...normalized });
|
|
130
|
-
message.$sender.role = normalized.role;
|
|
131
|
-
message.$sender.permissions = normalized.permissions;
|
|
132
|
-
}
|
|
133
|
-
catch {
|
|
134
|
-
// 保守拒绝:无角色快照
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
async handleTelegramMessage(ctx) {
|
|
138
|
-
if (!ctx.message)
|
|
139
|
-
return;
|
|
140
|
-
const message = this.$formatMessage(ctx.message);
|
|
141
|
-
await this.enrichGroupSender(message, ctx.message);
|
|
142
|
-
this.adapter.emit("message.receive", message);
|
|
143
|
-
this.pluginLogger.debug(`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}): ${segment.raw(message.$content)}`);
|
|
144
|
-
}
|
|
145
|
-
$formatMessage(msg) {
|
|
146
|
-
// Determine channel type
|
|
147
|
-
const channelType = msg.chat.type === "private" ? "private" : "group";
|
|
148
|
-
const channelId = msg.chat.id.toString();
|
|
149
|
-
// Parse message content
|
|
150
|
-
const wire = this.parseMessageContent(msg);
|
|
151
|
-
const quoteId = Message.quoteIdFromContent(wire);
|
|
152
|
-
Message.alignReplySegments(wire, quoteId);
|
|
153
|
-
const content = toCanonicalSegments(wire);
|
|
154
|
-
const result = Message.from(msg, {
|
|
155
|
-
$id: msg.message_id.toString(),
|
|
156
|
-
$adapter: "telegram",
|
|
157
|
-
$endpoint: this.$config.name,
|
|
158
|
-
$sender: {
|
|
159
|
-
id: msg.from?.id.toString() || "",
|
|
160
|
-
name: msg.from?.username || msg.from?.first_name || "Unknown",
|
|
161
|
-
},
|
|
162
|
-
$channel: {
|
|
163
|
-
id: channelId,
|
|
164
|
-
type: channelType,
|
|
165
|
-
},
|
|
166
|
-
$content: content,
|
|
167
|
-
$quote_id: quoteId,
|
|
168
|
-
$raw: "text" in msg ? msg.text || "" : "",
|
|
169
|
-
$timestamp: msg.date * 1000,
|
|
170
|
-
$recall: async () => {
|
|
171
|
-
try {
|
|
172
|
-
await this.telegram.deleteMessage(parseInt(channelId), parseInt(result.$id));
|
|
173
|
-
}
|
|
174
|
-
catch (error) {
|
|
175
|
-
this.pluginLogger.error("Error recalling Telegram message:", error);
|
|
176
|
-
throw error;
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
$reply: async (content, quote) => {
|
|
180
|
-
if (!Array.isArray(content))
|
|
181
|
-
content = [content];
|
|
182
|
-
// Handle reply
|
|
183
|
-
if (quote) {
|
|
184
|
-
const replyToMessageId = typeof quote === "boolean" ? result.$id : quote;
|
|
185
|
-
content.unshift({ type: "reply", data: { id: replyToMessageId } });
|
|
186
|
-
}
|
|
187
|
-
return await this.adapter.sendMessage({
|
|
188
|
-
context: "telegram",
|
|
189
|
-
endpoint: this.$config.name,
|
|
190
|
-
id: channelId,
|
|
191
|
-
type: channelType,
|
|
192
|
-
content: content,
|
|
193
|
-
});
|
|
194
|
-
},
|
|
195
|
-
});
|
|
196
|
-
this.messageChatMap.set(result.$id, channelId);
|
|
197
|
-
return result;
|
|
198
|
-
}
|
|
199
|
-
async $getMsg(messageId) {
|
|
200
|
-
const hit = this.quotedPayloadCache.get(messageId);
|
|
201
|
-
if (!hit) {
|
|
202
|
-
throw new Error(`Telegram quoted message ${messageId} is not cached`);
|
|
203
|
-
}
|
|
204
|
-
return hit;
|
|
205
|
-
}
|
|
206
|
-
cacheQuotedTelegramMessage(msg) {
|
|
207
|
-
const segments = this.parseMessageContent(msg);
|
|
208
|
-
const payload = {
|
|
209
|
-
messageId: msg.message_id.toString(),
|
|
210
|
-
sender: msg.from
|
|
211
|
-
? {
|
|
212
|
-
id: msg.from.id.toString(),
|
|
213
|
-
name: msg.from.username || msg.from.first_name,
|
|
214
|
-
}
|
|
215
|
-
: undefined,
|
|
216
|
-
content: segments,
|
|
217
|
-
raw: "text" in msg ? msg.text : undefined,
|
|
218
|
-
time: msg.date,
|
|
219
|
-
};
|
|
220
|
-
this.quotedPayloadCache.set(payload.messageId, payload);
|
|
221
|
-
}
|
|
222
|
-
$formatCallbackQuery(ctx) {
|
|
223
|
-
if (!ctx.callbackQuery || !("data" in ctx.callbackQuery)) {
|
|
224
|
-
throw new Error("Invalid callback query");
|
|
225
|
-
}
|
|
226
|
-
const query = ctx.callbackQuery;
|
|
227
|
-
const msg = query.message;
|
|
228
|
-
const channelType = msg && "chat" in msg && msg.chat.type === "private" ? "private" : "group";
|
|
229
|
-
const channelId = msg && "chat" in msg ? msg.chat.id.toString() : query.from.id.toString();
|
|
230
|
-
const result = Message.from(query, {
|
|
231
|
-
$id: query.id,
|
|
232
|
-
$adapter: "telegram",
|
|
233
|
-
$endpoint: this.$config.name,
|
|
234
|
-
$sender: {
|
|
235
|
-
id: query.from.id.toString(),
|
|
236
|
-
name: query.from.username || query.from.first_name,
|
|
237
|
-
},
|
|
238
|
-
$channel: {
|
|
239
|
-
id: channelId,
|
|
240
|
-
type: channelType,
|
|
241
|
-
},
|
|
242
|
-
$content: [{
|
|
243
|
-
type: "action",
|
|
244
|
-
data: {
|
|
245
|
-
id: query.id,
|
|
246
|
-
payload: query.data,
|
|
247
|
-
sourceMessageId: msg && "message_id" in msg ? String(msg.message_id) : undefined,
|
|
248
|
-
},
|
|
249
|
-
}],
|
|
250
|
-
$raw: query.data,
|
|
251
|
-
$timestamp: Date.now(),
|
|
252
|
-
$recall: async () => {
|
|
253
|
-
// Callback queries cannot be recalled
|
|
254
|
-
},
|
|
255
|
-
$reply: async (content) => {
|
|
256
|
-
if (!Array.isArray(content))
|
|
257
|
-
content = [content];
|
|
258
|
-
const sentMsg = await this.sendContentToChat(parseInt(channelId), content);
|
|
259
|
-
return sentMsg.message_id.toString();
|
|
260
|
-
},
|
|
261
|
-
});
|
|
262
|
-
return result;
|
|
263
|
-
}
|
|
264
|
-
parseMessageContent(msg) {
|
|
265
|
-
const segments = [];
|
|
266
|
-
// Handle text messages
|
|
267
|
-
if ("text" in msg && msg.text) {
|
|
268
|
-
// Check for reply
|
|
269
|
-
if (msg.reply_to_message) {
|
|
270
|
-
this.cacheQuotedTelegramMessage(msg.reply_to_message);
|
|
271
|
-
const replyId = msg.reply_to_message.message_id.toString();
|
|
272
|
-
segments.push({
|
|
273
|
-
type: "reply",
|
|
274
|
-
data: { id: replyId, message_id: replyId },
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
// Parse text with entities
|
|
278
|
-
if (msg.entities && msg.entities.length > 0) {
|
|
279
|
-
segments.push(...this.parseTextWithEntities(msg.text, msg.entities));
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
segments.push({ type: "text", data: { text: msg.text } });
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
// Handle photo
|
|
286
|
-
if ("photo" in msg && msg.photo) {
|
|
287
|
-
const largestPhoto = msg.photo[msg.photo.length - 1];
|
|
288
|
-
segments.push({
|
|
289
|
-
type: "image",
|
|
290
|
-
data: {
|
|
291
|
-
file_id: largestPhoto.file_id,
|
|
292
|
-
file_unique_id: largestPhoto.file_unique_id,
|
|
293
|
-
width: largestPhoto.width,
|
|
294
|
-
height: largestPhoto.height,
|
|
295
|
-
file_size: largestPhoto.file_size,
|
|
296
|
-
},
|
|
297
|
-
});
|
|
298
|
-
if (msg.caption) {
|
|
299
|
-
segments.push({ type: "text", data: { text: msg.caption } });
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
// Handle video
|
|
303
|
-
if ("video" in msg && msg.video) {
|
|
304
|
-
segments.push({
|
|
305
|
-
type: "video",
|
|
306
|
-
data: {
|
|
307
|
-
file_id: msg.video.file_id,
|
|
308
|
-
file_unique_id: msg.video.file_unique_id,
|
|
309
|
-
width: msg.video.width,
|
|
310
|
-
height: msg.video.height,
|
|
311
|
-
duration: msg.video.duration,
|
|
312
|
-
file_size: msg.video.file_size,
|
|
313
|
-
},
|
|
314
|
-
});
|
|
315
|
-
if (msg.caption) {
|
|
316
|
-
segments.push({ type: "text", data: { text: msg.caption } });
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
// Handle audio
|
|
320
|
-
if ("audio" in msg && msg.audio) {
|
|
321
|
-
segments.push({
|
|
322
|
-
type: "audio",
|
|
323
|
-
data: {
|
|
324
|
-
file_id: msg.audio.file_id,
|
|
325
|
-
file_unique_id: msg.audio.file_unique_id,
|
|
326
|
-
duration: msg.audio.duration,
|
|
327
|
-
performer: msg.audio.performer,
|
|
328
|
-
title: msg.audio.title,
|
|
329
|
-
file_size: msg.audio.file_size,
|
|
330
|
-
},
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
// Handle voice
|
|
334
|
-
if ("voice" in msg && msg.voice) {
|
|
335
|
-
segments.push({
|
|
336
|
-
type: "voice",
|
|
337
|
-
data: {
|
|
338
|
-
file_id: msg.voice.file_id,
|
|
339
|
-
file_unique_id: msg.voice.file_unique_id,
|
|
340
|
-
duration: msg.voice.duration,
|
|
341
|
-
file_size: msg.voice.file_size,
|
|
342
|
-
},
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
// Handle document
|
|
346
|
-
if ("document" in msg && msg.document) {
|
|
347
|
-
segments.push({
|
|
348
|
-
type: "file",
|
|
349
|
-
data: {
|
|
350
|
-
file_id: msg.document.file_id,
|
|
351
|
-
file_unique_id: msg.document.file_unique_id,
|
|
352
|
-
file_name: msg.document.file_name,
|
|
353
|
-
mime_type: msg.document.mime_type,
|
|
354
|
-
file_size: msg.document.file_size,
|
|
355
|
-
},
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
// Handle sticker
|
|
359
|
-
if ("sticker" in msg && msg.sticker) {
|
|
360
|
-
segments.push({
|
|
361
|
-
type: "sticker",
|
|
362
|
-
data: {
|
|
363
|
-
file_id: msg.sticker.file_id,
|
|
364
|
-
file_unique_id: msg.sticker.file_unique_id,
|
|
365
|
-
width: msg.sticker.width,
|
|
366
|
-
height: msg.sticker.height,
|
|
367
|
-
is_animated: msg.sticker.is_animated,
|
|
368
|
-
is_video: msg.sticker.is_video,
|
|
369
|
-
emoji: msg.sticker.emoji,
|
|
370
|
-
},
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
// Handle location
|
|
374
|
-
if ("location" in msg && msg.location) {
|
|
375
|
-
segments.push({
|
|
376
|
-
type: "location",
|
|
377
|
-
data: {
|
|
378
|
-
longitude: msg.location.longitude,
|
|
379
|
-
latitude: msg.location.latitude,
|
|
380
|
-
},
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
return segments.length > 0
|
|
384
|
-
? segments
|
|
385
|
-
: [{ type: "text", data: { text: "" } }];
|
|
386
|
-
}
|
|
387
|
-
parseTextWithEntities(text, entities) {
|
|
388
|
-
const segments = [];
|
|
389
|
-
let lastOffset = 0;
|
|
390
|
-
for (const entity of entities) {
|
|
391
|
-
// Add text before entity
|
|
392
|
-
if (entity.offset > lastOffset) {
|
|
393
|
-
const beforeText = text.slice(lastOffset, entity.offset);
|
|
394
|
-
if (beforeText) {
|
|
395
|
-
segments.push({ type: "text", data: { text: beforeText } });
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
const entityText = text.slice(entity.offset, entity.offset + entity.length);
|
|
399
|
-
switch (entity.type) {
|
|
400
|
-
case "mention":
|
|
401
|
-
case "text_mention":
|
|
402
|
-
segments.push({
|
|
403
|
-
type: "at",
|
|
404
|
-
data: {
|
|
405
|
-
id: ("user" in entity && entity.user?.id.toString()) || entityText.slice(1),
|
|
406
|
-
name: ("user" in entity && entity.user?.username) || entityText,
|
|
407
|
-
text: entityText,
|
|
408
|
-
},
|
|
409
|
-
});
|
|
410
|
-
break;
|
|
411
|
-
case "url":
|
|
412
|
-
case "text_link":
|
|
413
|
-
segments.push({
|
|
414
|
-
type: "link",
|
|
415
|
-
data: {
|
|
416
|
-
url: ("url" in entity && entity.url) || entityText,
|
|
417
|
-
text: entityText,
|
|
418
|
-
},
|
|
419
|
-
});
|
|
420
|
-
break;
|
|
421
|
-
case "hashtag":
|
|
422
|
-
segments.push({
|
|
423
|
-
type: "text",
|
|
424
|
-
data: { text: entityText },
|
|
425
|
-
});
|
|
426
|
-
break;
|
|
427
|
-
case "bold":
|
|
428
|
-
case "italic":
|
|
429
|
-
case "code":
|
|
430
|
-
case "pre":
|
|
431
|
-
case "underline":
|
|
432
|
-
case "strikethrough":
|
|
433
|
-
segments.push({
|
|
434
|
-
type: "text",
|
|
435
|
-
data: { text: entityText, format: entity.type },
|
|
436
|
-
});
|
|
437
|
-
break;
|
|
438
|
-
default:
|
|
439
|
-
segments.push({ type: "text", data: { text: entityText } });
|
|
440
|
-
}
|
|
441
|
-
lastOffset = entity.offset + entity.length;
|
|
442
|
-
}
|
|
443
|
-
// Add remaining text
|
|
444
|
-
if (lastOffset < text.length) {
|
|
445
|
-
const remainingText = text.slice(lastOffset);
|
|
446
|
-
if (remainingText) {
|
|
447
|
-
segments.push({ type: "text", data: { text: remainingText } });
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return segments;
|
|
451
|
-
}
|
|
452
|
-
async $sendMessage(options) {
|
|
453
|
-
try {
|
|
454
|
-
const chatId = parseInt(options.id);
|
|
455
|
-
const canonical = expandInteractiveSegmentsInContent(options.content);
|
|
456
|
-
const wire = fromCanonicalSegments(canonical);
|
|
457
|
-
const result = await this.sendContentToChat(chatId, wire);
|
|
458
|
-
this.messageChatMap.set(result.message_id.toString(), options.id);
|
|
459
|
-
this.pluginLogger.debug(`${this.$config.name} send ${options.type}(${options.id}): ${segment.raw(options.content)}`);
|
|
460
|
-
return result.message_id.toString();
|
|
461
|
-
}
|
|
462
|
-
catch (error) {
|
|
463
|
-
this.pluginLogger.error("Failed to send Telegram message:", error);
|
|
464
|
-
throw error;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
async $editMessage(options) {
|
|
468
|
-
const chatId = parseInt(options.id);
|
|
469
|
-
const messageId = parseInt(options.messageId);
|
|
470
|
-
const content = Array.isArray(options.content) ? options.content : [options.content];
|
|
471
|
-
let textContent = "";
|
|
472
|
-
let keyboard;
|
|
473
|
-
for (const seg of content) {
|
|
474
|
-
if (typeof seg === "string") {
|
|
475
|
-
textContent += seg;
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
|
-
if (seg.type === "text")
|
|
479
|
-
textContent += seg.data.text || "";
|
|
480
|
-
if (seg.type === "keyboard") {
|
|
481
|
-
keyboard = {
|
|
482
|
-
inline_keyboard: (seg.data.rows ?? []).map((row) => row.map((btn) => ({
|
|
483
|
-
text: btn.label,
|
|
484
|
-
callback_data: String(btn.payload).slice(0, 64),
|
|
485
|
-
}))),
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
await this.telegram.editMessageText(chatId, messageId, undefined, textContent.trim() || " ", keyboard ? { reply_markup: keyboard } : {});
|
|
490
|
-
}
|
|
491
|
-
async sendContentToChat(chatId, content, extraOptions = {}) {
|
|
492
|
-
if (!Array.isArray(content))
|
|
493
|
-
content = [content];
|
|
494
|
-
let textContent = "";
|
|
495
|
-
let hasMedia = false;
|
|
496
|
-
for (const segment of content) {
|
|
497
|
-
if (typeof segment === "string") {
|
|
498
|
-
textContent += segment;
|
|
499
|
-
continue;
|
|
500
|
-
}
|
|
501
|
-
const { type, data } = segment;
|
|
502
|
-
switch (type) {
|
|
503
|
-
case "text":
|
|
504
|
-
textContent += data.text || "";
|
|
505
|
-
break;
|
|
506
|
-
case "at":
|
|
507
|
-
if (data.id) {
|
|
508
|
-
textContent += `@${data.name || data.id}`;
|
|
509
|
-
}
|
|
510
|
-
break;
|
|
511
|
-
case "image":
|
|
512
|
-
hasMedia = true;
|
|
513
|
-
if (data.file_id) {
|
|
514
|
-
// Send by file_id
|
|
515
|
-
return await this.telegram.sendPhoto(chatId, data.file_id, {
|
|
516
|
-
caption: textContent || undefined,
|
|
517
|
-
...extraOptions,
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
else if (data.url) {
|
|
521
|
-
// Send by URL
|
|
522
|
-
return await this.telegram.sendPhoto(chatId, data.url, {
|
|
523
|
-
caption: textContent || undefined,
|
|
524
|
-
...extraOptions,
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
else if (data.file) {
|
|
528
|
-
// Send by file path
|
|
529
|
-
return await this.telegram.sendPhoto(chatId, { source: data.file }, {
|
|
530
|
-
caption: textContent || undefined,
|
|
531
|
-
...extraOptions,
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
break;
|
|
535
|
-
case "video":
|
|
536
|
-
hasMedia = true;
|
|
537
|
-
if (data.file_id) {
|
|
538
|
-
return await this.telegram.sendVideo(chatId, data.file_id, {
|
|
539
|
-
caption: textContent || undefined,
|
|
540
|
-
...extraOptions,
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
else if (data.url) {
|
|
544
|
-
return await this.telegram.sendVideo(chatId, data.url, {
|
|
545
|
-
caption: textContent || undefined,
|
|
546
|
-
...extraOptions,
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
else if (data.file) {
|
|
550
|
-
return await this.telegram.sendVideo(chatId, { source: data.file }, {
|
|
551
|
-
caption: textContent || undefined,
|
|
552
|
-
...extraOptions,
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
break;
|
|
556
|
-
case "audio":
|
|
557
|
-
hasMedia = true;
|
|
558
|
-
if (data.file_id) {
|
|
559
|
-
return await this.telegram.sendAudio(chatId, data.file_id, {
|
|
560
|
-
caption: textContent || undefined,
|
|
561
|
-
...extraOptions,
|
|
562
|
-
});
|
|
563
|
-
}
|
|
564
|
-
else if (data.url) {
|
|
565
|
-
return await this.telegram.sendAudio(chatId, data.url, {
|
|
566
|
-
caption: textContent || undefined,
|
|
567
|
-
...extraOptions,
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
else if (data.file) {
|
|
571
|
-
return await this.telegram.sendAudio(chatId, { source: data.file }, {
|
|
572
|
-
caption: textContent || undefined,
|
|
573
|
-
...extraOptions,
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
break;
|
|
577
|
-
case "voice":
|
|
578
|
-
hasMedia = true;
|
|
579
|
-
if (data.file_id) {
|
|
580
|
-
return await this.telegram.sendVoice(chatId, data.file_id, {
|
|
581
|
-
caption: textContent || undefined,
|
|
582
|
-
...extraOptions,
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
else if (data.url) {
|
|
586
|
-
return await this.telegram.sendVoice(chatId, data.url, {
|
|
587
|
-
caption: textContent || undefined,
|
|
588
|
-
...extraOptions,
|
|
589
|
-
});
|
|
590
|
-
}
|
|
591
|
-
else if (data.file) {
|
|
592
|
-
return await this.telegram.sendVoice(chatId, { source: data.file }, {
|
|
593
|
-
caption: textContent || undefined,
|
|
594
|
-
...extraOptions,
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
break;
|
|
598
|
-
case "file":
|
|
599
|
-
hasMedia = true;
|
|
600
|
-
if (data.file_id) {
|
|
601
|
-
return await this.telegram.sendDocument(chatId, data.file_id, {
|
|
602
|
-
caption: textContent || undefined,
|
|
603
|
-
...extraOptions,
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
else if (data.url) {
|
|
607
|
-
return await this.telegram.sendDocument(chatId, data.url, {
|
|
608
|
-
caption: textContent || undefined,
|
|
609
|
-
...extraOptions,
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
|
-
else if (data.file) {
|
|
613
|
-
return await this.telegram.sendDocument(chatId, { source: data.file }, {
|
|
614
|
-
caption: textContent || undefined,
|
|
615
|
-
...extraOptions,
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
break;
|
|
619
|
-
case "sticker":
|
|
620
|
-
if (data.file_id) {
|
|
621
|
-
hasMedia = true;
|
|
622
|
-
return await this.telegram.sendSticker(chatId, data.file_id, extraOptions);
|
|
623
|
-
}
|
|
624
|
-
break;
|
|
625
|
-
case "location":
|
|
626
|
-
return await this.telegram.sendLocation(chatId, data.latitude, data.longitude, extraOptions);
|
|
627
|
-
case "reply":
|
|
628
|
-
return await this.telegram.sendMessage(chatId, data.id, {
|
|
629
|
-
reply_parameters: { message_id: parseInt(data.id) },
|
|
630
|
-
...extraOptions,
|
|
631
|
-
});
|
|
632
|
-
case "keyboard": {
|
|
633
|
-
const rows = (data.rows ?? []).map((row) => row.map((btn) => ({
|
|
634
|
-
text: btn.label,
|
|
635
|
-
callback_data: String(btn.payload).slice(0, 64),
|
|
636
|
-
})));
|
|
637
|
-
return await this.telegram.sendMessage(chatId, textContent.trim() || " ", {
|
|
638
|
-
reply_markup: { inline_keyboard: rows },
|
|
639
|
-
...extraOptions,
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
default:
|
|
643
|
-
// Unknown segment type, add as text
|
|
644
|
-
textContent += data.text || `[${type}]`;
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
// If no media was sent, send as text message
|
|
648
|
-
if (!hasMedia && textContent.trim()) {
|
|
649
|
-
return await this.telegram.sendMessage(chatId, textContent.trim(), extraOptions);
|
|
650
|
-
}
|
|
651
|
-
// If neither media nor text was sent, this is an error
|
|
652
|
-
throw new Error("TelegramEndpoint.$sendMessage: No media or text content to send.");
|
|
653
|
-
}
|
|
654
|
-
async $recallMessage(id) {
|
|
655
|
-
// The Endpoint interface only provides message_id, making recall impossible
|
|
656
|
-
// Users should use message.$recall() instead, which has the full context
|
|
657
|
-
throw new Error("TelegramEndpoint.$recallMessage: Message recall not supported without chat_id. " +
|
|
658
|
-
"Use message.$recall() method instead, which contains the required context.");
|
|
659
|
-
}
|
|
660
|
-
resolveTelegramMessageRef(messageId) {
|
|
661
|
-
if (messageId.includes(':')) {
|
|
662
|
-
const [chatIdRaw, msgIdRaw] = messageId.split(':');
|
|
663
|
-
const chatId = Number(chatIdRaw);
|
|
664
|
-
const msgId = Number(msgIdRaw);
|
|
665
|
-
if (Number.isFinite(chatId) && Number.isFinite(msgId)) {
|
|
666
|
-
this.messageChatMap.set(String(msgId), String(chatId));
|
|
667
|
-
return { chatId, msgId };
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
const mappedChatId = this.messageChatMap.get(messageId);
|
|
671
|
-
if (!mappedChatId)
|
|
672
|
-
return null;
|
|
673
|
-
const chatId = Number(mappedChatId);
|
|
674
|
-
const msgId = Number(messageId);
|
|
675
|
-
if (!Number.isFinite(chatId) || !Number.isFinite(msgId))
|
|
676
|
-
return null;
|
|
677
|
-
return { chatId, msgId };
|
|
678
|
-
}
|
|
679
|
-
async $addReaction(messageId, emoji) {
|
|
680
|
-
const ref = this.resolveTelegramMessageRef(messageId);
|
|
681
|
-
if (!ref) {
|
|
682
|
-
this.pluginLogger.warn(`Telegram Endpoint ${this.$id} 无法根据 message_id=${messageId} 定位 chat_id,跳过 addReaction`);
|
|
683
|
-
return null;
|
|
684
|
-
}
|
|
685
|
-
try {
|
|
686
|
-
await this.setMessageReaction(ref.chatId, ref.msgId, emoji);
|
|
687
|
-
return emoji;
|
|
688
|
-
}
|
|
689
|
-
catch (error) {
|
|
690
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 添加 reaction 失败:`, error);
|
|
691
|
-
return null;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
async $removeReaction(messageId, _reactionId) {
|
|
695
|
-
const ref = this.resolveTelegramMessageRef(messageId);
|
|
696
|
-
if (!ref) {
|
|
697
|
-
this.pluginLogger.warn(`Telegram Endpoint ${this.$id} 无法根据 message_id=${messageId} 定位 chat_id,跳过 removeReaction`);
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
try {
|
|
701
|
-
await this.telegram.callApi('setMessageReaction', {
|
|
702
|
-
chat_id: ref.chatId,
|
|
703
|
-
message_id: ref.msgId,
|
|
704
|
-
reaction: [],
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
catch (error) {
|
|
708
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 移除 reaction 失败:`, error);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
// ==================== 群组管理 API ====================
|
|
712
|
-
/**
|
|
713
|
-
* 踢出用户
|
|
714
|
-
* @param chatId 聊天 ID
|
|
715
|
-
* @param userId 用户 ID
|
|
716
|
-
* @param untilDate 封禁截止时间(Unix 时间戳),0 表示永久
|
|
717
|
-
*/
|
|
718
|
-
async kickMember(chatId, userId, untilDate) {
|
|
719
|
-
try {
|
|
720
|
-
await this.telegram.banChatMember(chatId, userId, untilDate);
|
|
721
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 踢出用户 ${userId} 从聊天 ${chatId}`);
|
|
722
|
-
return true;
|
|
723
|
-
}
|
|
724
|
-
catch (error) {
|
|
725
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 踢出用户失败:`, error);
|
|
726
|
-
throw error;
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
/**
|
|
730
|
-
* 解除封禁
|
|
731
|
-
* @param chatId 聊天 ID
|
|
732
|
-
* @param userId 用户 ID
|
|
733
|
-
*/
|
|
734
|
-
async unbanMember(chatId, userId) {
|
|
735
|
-
try {
|
|
736
|
-
await this.telegram.unbanChatMember(chatId, userId, { only_if_banned: true });
|
|
737
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 解除用户 ${userId} 的封禁(聊天 ${chatId})`);
|
|
738
|
-
return true;
|
|
739
|
-
}
|
|
740
|
-
catch (error) {
|
|
741
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 解除封禁失败:`, error);
|
|
742
|
-
throw error;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* 限制用户权限(禁言等)
|
|
747
|
-
* @param chatId 聊天 ID
|
|
748
|
-
* @param userId 用户 ID
|
|
749
|
-
* @param permissions 权限设置
|
|
750
|
-
* @param untilDate 限制截止时间
|
|
751
|
-
*/
|
|
752
|
-
async restrictMember(chatId, userId, permissions, untilDate) {
|
|
753
|
-
try {
|
|
754
|
-
await this.telegram.restrictChatMember(chatId, userId, {
|
|
755
|
-
permissions,
|
|
756
|
-
until_date: untilDate,
|
|
757
|
-
});
|
|
758
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 限制用户 ${userId} 权限(聊天 ${chatId})`);
|
|
759
|
-
return true;
|
|
760
|
-
}
|
|
761
|
-
catch (error) {
|
|
762
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 限制权限失败:`, error);
|
|
763
|
-
throw error;
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* 禁言用户
|
|
768
|
-
* @param chatId 聊天 ID
|
|
769
|
-
* @param userId 用户 ID
|
|
770
|
-
* @param duration 禁言时长(秒),0 表示解除禁言
|
|
771
|
-
*/
|
|
772
|
-
async muteMember(chatId, userId, duration = 600) {
|
|
773
|
-
try {
|
|
774
|
-
if (duration === 0) {
|
|
775
|
-
// 解除禁言 - 恢复发送消息权限
|
|
776
|
-
await this.telegram.restrictChatMember(chatId, userId, {
|
|
777
|
-
permissions: {
|
|
778
|
-
can_send_messages: true,
|
|
779
|
-
can_send_audios: true,
|
|
780
|
-
can_send_documents: true,
|
|
781
|
-
can_send_photos: true,
|
|
782
|
-
can_send_videos: true,
|
|
783
|
-
can_send_video_notes: true,
|
|
784
|
-
can_send_voice_notes: true,
|
|
785
|
-
can_send_polls: true,
|
|
786
|
-
can_send_other_messages: true,
|
|
787
|
-
can_add_web_page_previews: true,
|
|
788
|
-
},
|
|
789
|
-
});
|
|
790
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 解除用户 ${userId} 禁言(聊天 ${chatId})`);
|
|
791
|
-
}
|
|
792
|
-
else {
|
|
793
|
-
const untilDate = Math.floor(Date.now() / 1000) + duration;
|
|
794
|
-
await this.telegram.restrictChatMember(chatId, userId, {
|
|
795
|
-
permissions: {
|
|
796
|
-
can_send_messages: false,
|
|
797
|
-
can_send_audios: false,
|
|
798
|
-
can_send_documents: false,
|
|
799
|
-
can_send_photos: false,
|
|
800
|
-
can_send_videos: false,
|
|
801
|
-
can_send_video_notes: false,
|
|
802
|
-
can_send_voice_notes: false,
|
|
803
|
-
can_send_polls: false,
|
|
804
|
-
can_send_other_messages: false,
|
|
805
|
-
can_add_web_page_previews: false,
|
|
806
|
-
},
|
|
807
|
-
until_date: untilDate,
|
|
808
|
-
});
|
|
809
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 禁言用户 ${userId} ${duration}秒(聊天 ${chatId})`);
|
|
810
|
-
}
|
|
811
|
-
return true;
|
|
812
|
-
}
|
|
813
|
-
catch (error) {
|
|
814
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 禁言操作失败:`, error);
|
|
815
|
-
throw error;
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
/**
|
|
819
|
-
* 提升/降级管理员
|
|
820
|
-
* @param chatId 聊天 ID
|
|
821
|
-
* @param userId 用户 ID
|
|
822
|
-
* @param promote 是否提升为管理员
|
|
823
|
-
*/
|
|
824
|
-
async setAdmin(chatId, userId, promote = true) {
|
|
825
|
-
try {
|
|
826
|
-
if (promote) {
|
|
827
|
-
await this.telegram.promoteChatMember(chatId, userId, {
|
|
828
|
-
can_manage_chat: true,
|
|
829
|
-
can_delete_messages: true,
|
|
830
|
-
can_manage_video_chats: true,
|
|
831
|
-
can_restrict_members: true,
|
|
832
|
-
can_promote_members: false,
|
|
833
|
-
can_change_info: true,
|
|
834
|
-
can_invite_users: true,
|
|
835
|
-
can_pin_messages: true,
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
else {
|
|
839
|
-
await this.telegram.promoteChatMember(chatId, userId, {
|
|
840
|
-
can_manage_chat: false,
|
|
841
|
-
can_delete_messages: false,
|
|
842
|
-
can_manage_video_chats: false,
|
|
843
|
-
can_restrict_members: false,
|
|
844
|
-
can_promote_members: false,
|
|
845
|
-
can_change_info: false,
|
|
846
|
-
can_invite_users: false,
|
|
847
|
-
can_pin_messages: false,
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} ${promote ? '提升' : '降级'}用户 ${userId} 为管理员(聊天 ${chatId})`);
|
|
851
|
-
return true;
|
|
852
|
-
}
|
|
853
|
-
catch (error) {
|
|
854
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置管理员失败:`, error);
|
|
855
|
-
throw error;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
/**
|
|
859
|
-
* 设置聊天标题
|
|
860
|
-
* @param chatId 聊天 ID
|
|
861
|
-
* @param title 新标题
|
|
862
|
-
*/
|
|
863
|
-
async setChatTitle(chatId, title) {
|
|
864
|
-
try {
|
|
865
|
-
await this.telegram.setChatTitle(chatId, title);
|
|
866
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 设置聊天 ${chatId} 标题为 "${title}"`);
|
|
867
|
-
return true;
|
|
868
|
-
}
|
|
869
|
-
catch (error) {
|
|
870
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置标题失败:`, error);
|
|
871
|
-
throw error;
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
/**
|
|
875
|
-
* 设置聊天描述
|
|
876
|
-
* @param chatId 聊天 ID
|
|
877
|
-
* @param description 新描述
|
|
878
|
-
*/
|
|
879
|
-
async setChatDescription(chatId, description) {
|
|
880
|
-
try {
|
|
881
|
-
await this.telegram.setChatDescription(chatId, description);
|
|
882
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 设置聊天 ${chatId} 描述`);
|
|
883
|
-
return true;
|
|
884
|
-
}
|
|
885
|
-
catch (error) {
|
|
886
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置描述失败:`, error);
|
|
887
|
-
throw error;
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
/**
|
|
891
|
-
* 置顶消息
|
|
892
|
-
* @param chatId 聊天 ID
|
|
893
|
-
* @param messageId 消息 ID
|
|
894
|
-
*/
|
|
895
|
-
async pinMessage(chatId, messageId) {
|
|
896
|
-
try {
|
|
897
|
-
await this.telegram.pinChatMessage(chatId, messageId);
|
|
898
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 置顶消息 ${messageId}(聊天 ${chatId})`);
|
|
899
|
-
return true;
|
|
900
|
-
}
|
|
901
|
-
catch (error) {
|
|
902
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 置顶消息失败:`, error);
|
|
903
|
-
throw error;
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* 取消置顶消息
|
|
908
|
-
* @param chatId 聊天 ID
|
|
909
|
-
* @param messageId 消息 ID(可选,不提供则取消所有置顶)
|
|
910
|
-
*/
|
|
911
|
-
async unpinMessage(chatId, messageId) {
|
|
912
|
-
try {
|
|
913
|
-
if (messageId) {
|
|
914
|
-
await this.telegram.unpinChatMessage(chatId, messageId);
|
|
915
|
-
}
|
|
916
|
-
else {
|
|
917
|
-
await this.telegram.unpinAllChatMessages(chatId);
|
|
918
|
-
}
|
|
919
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 取消置顶消息(聊天 ${chatId})`);
|
|
920
|
-
return true;
|
|
921
|
-
}
|
|
922
|
-
catch (error) {
|
|
923
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 取消置顶失败:`, error);
|
|
924
|
-
throw error;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
/**
|
|
928
|
-
* 获取聊天信息
|
|
929
|
-
* @param chatId 聊天 ID
|
|
930
|
-
*/
|
|
931
|
-
async getChatInfo(chatId) {
|
|
932
|
-
try {
|
|
933
|
-
return await this.telegram.getChat(chatId);
|
|
934
|
-
}
|
|
935
|
-
catch (error) {
|
|
936
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 获取聊天信息失败:`, error);
|
|
937
|
-
throw error;
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
/**
|
|
941
|
-
* 获取聊天成员
|
|
942
|
-
* @param chatId 聊天 ID
|
|
943
|
-
* @param userId 用户 ID
|
|
944
|
-
*/
|
|
945
|
-
async getChatMember(chatId, userId) {
|
|
946
|
-
try {
|
|
947
|
-
return await this.telegram.getChatMember(chatId, userId);
|
|
948
|
-
}
|
|
949
|
-
catch (error) {
|
|
950
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 获取成员信息失败:`, error);
|
|
951
|
-
throw error;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
/**
|
|
955
|
-
* 获取管理员列表
|
|
956
|
-
* @param chatId 聊天 ID
|
|
957
|
-
*/
|
|
958
|
-
async getChatAdmins(chatId) {
|
|
959
|
-
try {
|
|
960
|
-
return await this.telegram.getChatAdministrators(chatId);
|
|
961
|
-
}
|
|
962
|
-
catch (error) {
|
|
963
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 获取管理员列表失败:`, error);
|
|
964
|
-
throw error;
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
/**
|
|
968
|
-
* 获取聊天成员数量
|
|
969
|
-
* @param chatId 聊天 ID
|
|
970
|
-
*/
|
|
971
|
-
async getChatMemberCount(chatId) {
|
|
972
|
-
try {
|
|
973
|
-
return await this.telegram.getChatMembersCount(chatId);
|
|
974
|
-
}
|
|
975
|
-
catch (error) {
|
|
976
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 获取成员数量失败:`, error);
|
|
977
|
-
throw error;
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
/**
|
|
981
|
-
* 创建邀请链接
|
|
982
|
-
* @param chatId 聊天 ID
|
|
983
|
-
*/
|
|
984
|
-
async createInviteLink(chatId) {
|
|
985
|
-
try {
|
|
986
|
-
const link = await this.telegram.createChatInviteLink(chatId, {});
|
|
987
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 创建邀请链接(聊天 ${chatId})`);
|
|
988
|
-
return link.invite_link;
|
|
989
|
-
}
|
|
990
|
-
catch (error) {
|
|
991
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 创建邀请链接失败:`, error);
|
|
992
|
-
throw error;
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
async sendPoll(chatId, question, options, isAnonymous = true, allowsMultipleAnswers = false) {
|
|
996
|
-
try {
|
|
997
|
-
const result = await this.telegram.sendPoll(chatId, question, options, {
|
|
998
|
-
is_anonymous: isAnonymous,
|
|
999
|
-
allows_multiple_answers: allowsMultipleAnswers,
|
|
1000
|
-
});
|
|
1001
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 发送投票到 ${chatId}`);
|
|
1002
|
-
return result;
|
|
1003
|
-
}
|
|
1004
|
-
catch (error) {
|
|
1005
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 发送投票失败:`, error);
|
|
1006
|
-
throw error;
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
async setMessageReaction(chatId, messageId, reaction) {
|
|
1010
|
-
try {
|
|
1011
|
-
await this.telegram.callApi('setMessageReaction', {
|
|
1012
|
-
chat_id: chatId,
|
|
1013
|
-
message_id: messageId,
|
|
1014
|
-
reaction: [{ type: 'emoji', emoji: reaction }],
|
|
1015
|
-
});
|
|
1016
|
-
return true;
|
|
1017
|
-
}
|
|
1018
|
-
catch (error) {
|
|
1019
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置反应失败:`, error);
|
|
1020
|
-
throw error;
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
async sendStickerMessage(chatId, sticker) {
|
|
1024
|
-
try {
|
|
1025
|
-
const result = await this.telegram.sendSticker(chatId, sticker);
|
|
1026
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 发送贴纸到 ${chatId}`);
|
|
1027
|
-
return result;
|
|
1028
|
-
}
|
|
1029
|
-
catch (error) {
|
|
1030
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 发送贴纸失败:`, error);
|
|
1031
|
-
throw error;
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
async setChatPermissionsAll(chatId, permissions) {
|
|
1035
|
-
try {
|
|
1036
|
-
await this.telegram.setChatPermissions(chatId, permissions);
|
|
1037
|
-
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 设置聊天 ${chatId} 权限`);
|
|
1038
|
-
return true;
|
|
1039
|
-
}
|
|
1040
|
-
catch (error) {
|
|
1041
|
-
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置聊天权限失败:`, error);
|
|
1042
|
-
throw error;
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
//# sourceMappingURL=endpoint.js.map
|