soumyadeepdas/TbhRichBotPublic · Community Store Listing

Rich Message Demo [TBH]

ProfileTelegram
17 commands0 envUpdated 5d agoCreated Jul 16, 2026
Back to folder

commands/_handle_guest_message.js

javascript · 329 lines · click line # to share

1/**#command2name: /handle_guest_message3answer: 4keyboard: 5parse_mode: 6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12// Command: *13 14// Handle only guest messages15if (!update.guest_message) {16  return17}18 19let msg = update.guest_message20let userText = msg.text || ""21 22// Skip non-text messages23if (!msg.text) {24  return25}26 27// =======================28// REMOVE BOT USERNAME FROM TEXT29// =======================30// Try multiple ways to get bot username31let botUsername = ""32 33// Method 1: Try from global bot object34if (typeof bot !== 'undefined' && bot.username) {35  botUsername = bot.username36}37// Method 2: Try from update (if available)38else if (update.bot && update.bot.username) {39  botUsername = update.bot.username40}41// Method 3: Hardcode your bot's username (REPLACE WITH YOUR ACTUAL BOT USERNAME)42else {43  botUsername = "pyralbot" // Change this to your bot's actual username without @44}45 46let botMention = "@" + botUsername47 48// Remove bot mention from text49if (userText.startsWith(botMention)) {50  userText = userText.substring(botMention.length).trim()51} else {52  // Also handle cases where there's a space after mention53  let regex = new RegExp('^@' + botUsername + '\\s*', 'i')54  userText = userText.replace(regex, '').trim()55}56 57// If text is empty after removing mention, return58if (!userText) {59  await Api.call("answerGuestQuery", {60    guest_query_id: msg.guest_query_id,61    result: JSON.stringify({62      type: "article",63      id: String(Date.now()),64      title: "Rich Echo",65      input_message_content: {66        message_text: "Please type something after @bot",67        parse_mode: "HTML"68      }69    })70  })71  return72}73 74// =======================75// MARKDOWN TO HTML CONVERTER (IMPROVED)76// =======================77function markdownToHtml(text) {78  let html = text79 80  // ===== HEADINGS =====81  html = html.replace(/^###### (.*$)/gm, '<h6>$1</h6>')82  html = html.replace(/^##### (.*$)/gm, '<h5>$1</h5>')83  html = html.replace(/^#### (.*$)/gm, '<h4>$1</h4>')84  html = html.replace(/^### (.*$)/gm, '<h3>$1</h3>')85  html = html.replace(/^## (.*$)/gm, '<h2>$1</h2>')86  html = html.replace(/^# (.*$)/gm, '<h1>$1</h1>')87 88  // ===== TEXT FORMATTING =====89  // Bold90  html = html.replace(/\*\*(.*?)\*\*/g, '<b>$1</b>')91  html = html.replace(/__(.*?)__/g, '<b>$1</b>')92  93  // Italic94  html = html.replace(/\*(.*?)\*/g, '<i>$1</i>')95  html = html.replace(/_(.*?)_/g, '<i>$1</i>')96  97  // Strikethrough98  html = html.replace(/~~(.*?)~~/g, '<s>$1</s>')99  100  // Highlight101  html = html.replace(/==(.*?)==/g, '<mark>$1</mark>')102  103  // Spoiler104  html = html.replace(/\|\|(.*?)\|\|/g, '<tg-spoiler>$1</tg-spoiler>')105  106  // Inline Code107  html = html.replace(/`(.*?)`/g, '<code>$1</code>')108 109  // ===== CODE BLOCKS =====110  html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, function(match, lang, code) {111    if (lang) {112      return `<pre><code class="language-${lang}">${code.trim()}</code></pre>`113    }114    return `<pre><code>${code.trim()}</code></pre>`115  })116 117  // ===== LINKS & IMAGES =====118  // Images119  html = html.replace(/!\[(.*?)\]\((.*?)\)/g, '<img src="$2" alt="$1"/>')120  121  // Links122  html = html.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2">$1</a>')123 124  // ===== BLOCKQUOTES =====125  html = html.replace(/^> (.*$)/gm, '<blockquote>$1</blockquote>')126  html = html.replace(/<\/blockquote>\n<blockquote>/g, '<br>')127  128  // Fix: Properly wrap blockquotes129  let blockquoteRegex = /(<blockquote>.*?<\/blockquote>)/gs130  let matches = html.match(blockquoteRegex)131  if (matches) {132    for (let match of matches) {133      let content = match.replace(/<blockquote>/g, '').replace(/<\/blockquote>/g, '')134      html = html.replace(match, `<blockquote>${content}</blockquote>`)135    }136  }137 138  // ===== LISTS =====139  // Unordered lists140  html = html.replace(/^- (.*$)/gm, '<li>$1</li>')141  html = html.replace(/^\* (.*$)/gm, '<li>$1</li>')142  html = html.replace(/^\+ (.*$)/gm, '<li>$1</li>')143  144  // Wrap consecutive list items145  html = html.replace(/(<li>.*<\/li>\n?)+/g, function(match) {146    return `<ul>${match.trim()}</ul>`147  })148 149  // Ordered lists150  html = html.replace(/^\d+\. (.*$)/gm, '<li>$1</li>')151  html = html.replace(/(<li>.*<\/li>\n?)+/g, function(match) {152    return `<ol>${match.trim()}</ol>`153  })154 155  // Task lists156  html = html.replace(/- \[x\] (.*$)/g, '<li><input type="checkbox" checked disabled> $1</li>')157  html = html.replace(/- \[ \] (.*$)/g, '<li><input type="checkbox" disabled> $1</li>')158 159  // ===== DIVIDERS =====160  html = html.replace(/^---$/gm, '<hr/>')161  html = html.replace(/^\*\*\*$/gm, '<hr/>')162 163  // ===== MATH =====164  // Inline math165  html = html.replace(/\$(.*?)\$/g, '<tg-math>$1</tg-math>')166  167  // Block math168  html = html.replace(/\$\$([\s\S]*?)\$\$/g, '<tg-math-block>$1</tg-math-block>')169 170  // ===== TABLES =====171  let tableRows = html.match(/\|.*\|/g)172  if (tableRows && tableRows.length > 1) {173    let tableHtml = '<table>'174    let isHeader = true175    176    for (let row of tableRows) {177      let cells = row.split('|').filter(cell => cell.trim())178      let isSeparator = cells.every(cell => /^[\s\-:]+$/.test(cell))179      180      if (isSeparator) continue181      182      tableHtml += '<tr>'183      for (let cell of cells) {184        let align = ''185        let cleanCell = cell.trim()186        187        if (cleanCell.startsWith(':') && cleanCell.endsWith(':')) {188          align = ' align="center"'189        } else if (cleanCell.startsWith(':')) {190          align = ' align="left"'191        } else if (cleanCell.endsWith(':')) {192          align = ' align="right"'193        }194        195        let tag = isHeader ? 'th' : 'td'196        let content = cleanCell.replace(/^:|:$/g, '').trim()197        tableHtml += `<${tag}${align}>${content}</${tag}>`198      }199      tableHtml += '</tr>'200      isHeader = false201    }202    203    tableHtml += '</table>'204    205    // Remove original table markdown206    html = html.replace(/\|.*\|\n?/g, '')207    html = html.replace(/\|---\|/g, '')208    html = html + tableHtml209  }210 211  // ===== COLLAPSIBLE DETAILS =====212  html = html.replace(/<details>/g, '<details>')213  html = html.replace(/<\/details>/g, '</details>')214  html = html.replace(/<summary>(.*?)<\/summary>/g, '<summary>$1</summary>')215 216  // ===== CLEANUP =====217  // Convert double newlines to paragraphs218  html = html.replace(/\n\n/g, '</p><p>')219  html = '<p>' + html + '</p>'220  221  // Remove empty paragraphs222  html = html.replace(/<p><\/p>/g, '')223  224  // Clean up nested block elements225  html = html.replace(/<p>\s*<h/g, '<h')226  html = html.replace(/<\/h\d>\s*<\/p>/g, '</h>')227  html = html.replace(/<p>\s*<ul/g, '<ul')228  html = html.replace(/<\/ul>\s*<\/p>/g, '</ul>')229  html = html.replace(/<p>\s*<ol/g, '<ol')230  html = html.replace(/<\/ol>\s*<\/p>/g, '</ol>')231  html = html.replace(/<p>\s*<blockquote/g, '<blockquote')232  html = html.replace(/<\/blockquote>\s*<\/p>/g, '</blockquote>')233  html = html.replace(/<p>\s*<table/g, '<table')234  html = html.replace(/<\/table>\s*<\/p>/g, '</table>')235  html = html.replace(/<p>\s*<pre/g, '<pre')236  html = html.replace(/<\/pre>\s*<\/p>/g, '</pre>')237  html = html.replace(/<p>\s*<hr/g, '<hr')238  html = html.replace(/<hr\/>\s*<\/p>/g, '<hr/>')239  html = html.replace(/<p>\s*<tg-math/g, '<tg-math')240  html = html.replace(/<\/tg-math>\s*<\/p>/g, '</tg-math>')241  html = html.replace(/<p>\s*<tg-math-block/g, '<tg-math-block')242  html = html.replace(/<\/tg-math-block>\s*<\/p>/g, '</tg-math-block>')243 244  return html245}246 247// =======================248// VALIDATE AND FIX HTML249// =======================250function validateAndFixHtml(html) {251  // Remove empty tags that cause errors252  html = html.replace(/<tg-math>\s*<\/tg-math>/g, '')253  html = html.replace(/<tg-math-block>\s*<\/tg-math-block>/g, '')254  html = html.replace(/<tg-emoji>\s*<\/tg-emoji>/g, '')255  html = html.replace(/<tg-time>\s*<\/tg-time>/g, '')256  html = html.replace(/<tg-reference>\s*<\/tg-reference>/g, '')257  258  // Fix: tg-time needs valid attributes259  html = html.replace(/<tg-time[^>]*>/g, function(match) {260    if (match.includes('unix=') && match.includes('format=')) {261      return match262    }263    return '' // Remove invalid tg-time264  })265  266  // Fix: tg-emoji needs emoji-id267  html = html.replace(/<tg-emoji[^>]*>/g, function(match) {268    if (match.includes('emoji-id=')) {269      return match270    }271    return '' // Remove invalid tg-emoji272  })273  274  // Fix: tg-reference needs name275  html = html.replace(/<tg-reference[^>]*>/g, function(match) {276    if (match.includes('name=')) {277      return match278    }279    return '' // Remove invalid tg-reference280  })281  282  // Fix: math tags need content283  html = html.replace(/<tg-math>\s*<\/tg-math>/g, '')284  html = html.replace(/<tg-math-block>\s*<\/tg-math-block>/g, '')285  286  return html287}288 289// =======================290// PROCESS USER INPUT291// =======================292let finalHtml = userText293 294// Check if it's pure HTML295let isHTML = userText.includes("<") && userText.includes(">") && 296             (userText.includes("</") || userText.includes("<br>") || 297              userText.includes("<b>") || userText.includes("<i>") ||298              userText.includes("<u>") || userText.includes("<code>") ||299              userText.includes("<h1>") || userText.includes("<p>"))300 301// If not HTML, convert markdown to HTML302if (!isHTML) {303  finalHtml = markdownToHtml(userText)304}305 306// Validate and fix any issues307finalHtml = validateAndFixHtml(finalHtml)308 309// =======================310// BUILD RICH MESSAGE311// =======================312let richMessage = {313  html: finalHtml314}315 316// =======================317// SEND RICH MESSAGE318// =======================319await Api.call("answerGuestQuery", {320  guest_query_id: msg.guest_query_id,321  result: JSON.stringify({322    type: "article",323    id: String(Date.now()),324    title: "Rich Echo",325    input_message_content: {326      rich_message: richMessage327    }328  })329})