(chatId: string, hours: number)
| 554 | ) { |
| 555 | return callWithProtocol("chat", provider, input, timeout); |
| 556 | } |
| 557 | throw error; |
| 558 | } |
| 559 | } |
| 560 | |
| 561 | // 构建群组链接 |
| 562 | function buildChatLink(chatId: string, username?: string): string { |
| 563 | if (username) { |
| 564 | return `https://t.me/${username}`; |
| 565 | } |
| 566 | // 私有群:chatId 格式为 -100xxxxx,需要去掉 -100 前缀 |
| 567 | const numericId = chatId.replace(/^-100/, ""); |
| 568 | return `https://t.me/c/${numericId}`; |
| 569 | } |
| 570 | |
| 571 | // 构建消息链接 |
| 572 | function buildMessageLink( |
| 573 | chatId: string, |
| 574 | messageId: number, |
| 575 | username?: string, |
| 576 | ): string { |
| 577 | if (username) { |
| 578 | return `https://t.me/${username}/${messageId}`; |
| 579 | } |
| 580 | // 私有群:chatId 格式为 -100xxxxx,需要去掉 -100 前缀 |
| 581 | const numericId = chatId.replace(/^-100/, ""); |
| 582 | return `https://t.me/c/${numericId}/${messageId}`; |
| 583 | } |
| 584 | |
| 585 | // 消息数据结构 |
| 586 | type MessageData = { |
| 587 | text: string; // 格式化后的消息文本 |
| 588 | content: string; // 原始消息内容 |
| 589 | telegramLink: string; // Telegram 消息链接 |
| 590 | urls: string[]; // 消息中的所有 URL(包括 entities 中的) |
| 591 | fileName?: string; // 附件文件名(如果有) |
| 592 | }; |
| 593 | |
| 594 | // 从消息 entities 中提取 URL |
| 595 | function extractUrlsFromEntities(message: any): string[] { |
| 596 | const urls: string[] = []; |
| 597 | |
| 598 | // 从 entities 中提取 |
| 599 | if (message.entities && Array.isArray(message.entities)) { |
| 600 | for (const entity of message.entities) { |
| 601 | // TextUrl 类型:[文本](URL) 格式的链接 |
| 602 | if (entity.className === "MessageEntityTextUrl" && entity.url) { |
| 603 | urls.push(entity.url); |
| 604 | } |
| 605 | // Url 类型:消息中的纯文本 URL |
| 606 | if (entity.className === "MessageEntityUrl" && message.message) { |
| 607 | const url = message.message.substring( |
no test coverage detected