import { Api } from "telegram"; function escapeHtml(text) { return text .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } export function entitiesToHtml(text, entities) { if (!text || !entities || entities.length === 0) { return escapeHtml(text || ""); } const buf = Buffer.from(text, "utf16le"); const insertions = []; for (const ent of entities) { const start = ent.offset * 2; const end = (ent.offset + ent.length) * 2; let openTag = ""; let closeTag = ""; if (ent instanceof Api.MessageEntityBold) { openTag = ""; closeTag = ""; } else if (ent instanceof Api.MessageEntityItalic) { openTag = ""; closeTag = ""; } else if (ent instanceof Api.MessageEntityCode) { openTag = ""; closeTag = ""; } else if (ent instanceof Api.MessageEntityPre) { const lang = ent.language || ""; openTag = lang ? `
`
        : "
";
      closeTag = "
"; } else if (ent instanceof Api.MessageEntityStrike) { openTag = ""; closeTag = ""; } else if (ent instanceof Api.MessageEntityUnderline) { openTag = ""; closeTag = ""; } else if (ent instanceof Api.MessageEntitySpoiler) { openTag = ''; closeTag = ""; } else if (ent instanceof Api.MessageEntityTextUrl) { openTag = ``; closeTag = ""; } if (openTag) { insertions.push({ start, end, openTag, closeTag }); } } // Build open/close maps by byte position const opens = new Map(); const closes = new Map(); for (const { start, end, openTag, closeTag } of insertions) { if (!opens.has(start)) opens.set(start, []); opens.get(start).push(openTag); if (!closes.has(end)) closes.set(end, []); closes.get(end).unshift(closeTag); } const positions = [ ...new Set([...opens.keys(), ...closes.keys(), buf.length]), ].sort((a, b) => a - b); const result = []; let pos = 0; for (const target of positions) { if (target > pos) { const chunk = buf.subarray(pos, target).toString("utf16le"); result.push(escapeHtml(chunk)); pos = target; } for (const tag of closes.get(target) || []) result.push(tag); for (const tag of opens.get(target) || []) result.push(tag); } if (pos < buf.length) { result.push(escapeHtml(buf.subarray(pos).toString("utf16le"))); } return result.join(""); } export function mediaType(message) { const media = message.media; if (!media) return null; if (media instanceof Api.MessageMediaPhoto) return "photo"; if (media instanceof Api.MessageMediaDocument) { const doc = media.document; if (doc && doc.attributes) { for (const attr of doc.attributes) { if (attr instanceof Api.DocumentAttributeVideo) return "video"; if (attr instanceof Api.DocumentAttributeAudio) return "audio"; if (attr instanceof Api.DocumentAttributeSticker) return "sticker"; if (attr instanceof Api.DocumentAttributeAnimated) return "animation"; } return "document"; } } if (media instanceof Api.MessageMediaWebPage) return "webpage"; return "unknown"; } export function mediaSize(message) { const media = message.media; if (media instanceof Api.MessageMediaDocument && media.document) { return Number(media.document.size || 0); } if (media instanceof Api.MessageMediaPhoto && media.photo) { const sizes = media.photo.sizes || []; for (let i = sizes.length - 1; i >= 0; i--) { if (sizes[i].size != null) return Number(sizes[i].size); } return 0; } return 0; } function chatType(chat) { if (chat instanceof Api.Channel) { return chat.megagroup ? "supergroup" : "channel"; } if (chat instanceof Api.Chat) return "group"; return "private"; } function toNum(v) { return typeof v === "bigint" ? Number(v) : v; } export async function formatMessage(client, message, accountId = "") { let sender = null; if (message.senderId) { try { sender = await client.getEntity(message.senderId); } catch {} } let chat = null; try { chat = await client.getEntity(message.chatId); } catch {} // from (sender) const fromObj = {}; if (sender) { fromObj.id = toNum(sender.id); fromObj.is_bot = sender.bot || false; fromObj.first_name = sender.firstName || ""; if (sender.lastName) fromObj.last_name = sender.lastName; if (sender.username) fromObj.username = sender.username; } // chat const chatObj = { id: toNum(message.chatId), type: chat ? chatType(chat) : "unknown", }; if (chat) { if (chat.title) chatObj.title = chat.title; if (chat.username) chatObj.username = chat.username; } // message body const text = message.message || ""; const msgObj = { message_id: message.id, from: fromObj, chat: chatObj, date: message.date, text, text_html: entitiesToHtml(text, message.entities), }; // reply if (message.replyTo) { msgObj.reply_to_message = { message_id: message.replyTo.replyToMsgId, }; } // media const mt = mediaType(message); if (mt && mt !== "webpage") { msgObj.media_type = mt; msgObj.has_media = true; msgObj.media_size = mediaSize(message); } const result = { update: { update_id: message.id, message: msgObj, }, }; if (accountId) result.accountId = accountId; return result; }