Membuat Bot Inline Telegram

Bot telah menjadi bagian yang tidak bisa dipisahkan dari Telegram. Dan layaknya setiap hal, selalu ada dua sisi yang bertolak belakang. misalnya, bot selain bisa membantu menghidupkan sebuah grup juga bisa menjadi sosok yang menjengkelkan yang mengganggu segenap penghuni grup. Tidak aneh jika banyak pemilik grup yang kemudian melarang adanya bot di dalam grupnya.

Dan semuanya merasa damai, aman dan tentram.

Sampai 4 Januari 2016, ketika Telegram mengenalkan fitur bot inline.

Umumnya kita bisa berinteraksi dengan bot dengan menghubunginya melalui percakapan pribadi (private chat/message) atau jika berada dalam grup yang sama dengan bot, dengan fitur bot inline semua bisa menggunakan bot dalam grup walau bot tersebut tidak ada dalam grup tersebut.
Menggunakan bot inline semudah memanggil username bot dalam kolom pesan dan memasukkan perintah.
Keren? Bisa dibilang begitu. Kita bisa menggunakan bot di mana saja dan kapan saja.
Menjengkelkan? Pastinya, terutama jika Anda adalah seorang admin. Tidak ada cara untuk mencegah penggunaan bot inline di sebuah grup.

Menyambung pembahasan bot Telegram di blog ini, kini saya akan sedikit menulis mengenai bot inline. Sebelum melanjutkan membaca, disarankan bagi Anda untuk terlebih dahulu membaca artikel saya yang lalu mengenai Telegram bot, yakni Belajar Dasar Bot telegram dan Membuat Bot Telegram Selamat Datang.
Bot yang akan kita buat kali ini masih sama seperti tutorial membuat bot selamat datang; menggunakan bahasa NodeJS dan framework telegraf yang kemudian dipasang di now.

Penjelasan yang mendalam mengenai metode bot inline bisa dibaca langsung di situs core.telegram.org. Kini, seperti biasa kita akan belajar bot Telegram dengan langsung membuat botnya. Sesuai bahasan, bot yang akan kita buat kali ini adalah bot inline.

Jadi, apa guna bot yang akan kita buat kali ini?
Kita akan membuat bot inline untuk mengolah pesan, misal menjadi tebal, miring dan monospace. Sekilas terkesan sia-sia karena kini user bisa langsung mengirim huruf tebal, miring atau monospace. Namun tidak mengapa, niatnya juga untuk belajar. Lain kali jika telah mahir, Anda bisa membuat bot inline yang lebih canggih.
Untuk memberi nilai tambah, kita tambahkan fungsi mengirim pranala (link) dan huruf coret (strikethrough) pada bot.

Mendaftar bot ke @botfather

  • Hubungi @botfather untuk mendaftar bot yang baru.
  • Setelah akun bot didapat, dan masih dalam percakapan dengan @botfather, aktifkan fitur inline-nya dengan cara:
    • Ketik /setinline, kemudian pilih bot yang hendak diatur inline-nya
    • Ketikkan placeholder message. Placeholder message adalah pesan yang akan tampil di samping kanan username bot kita ketika dipanggil dalam kolom pesan. Kali ini dicontohkan placeholder-nya adalah "HTML text here...".
      Telegram inline bot place holder message
    • Pengaturan bot untuk tutor kali ini telah cukup. Sisanya setel pengaturan bot sesuai selera Anda.

Menulis program bot

Saya tidak akan berpanjang kata dalam tutorial kali ini, karena sebagian besar langkahnya sama seperti langkah dalam artikel Membuat Bot Telegram Selamat Datang. Jadi jika ada langkah yang kurang Anda pahami, saya sarankan untuk mencari pencerahan di artikel itu saja.

Langkah demi langkah berikut di bawah saya tulis dengan asumsi Anda menggunakan sistem operasi GNU/Linux, dan di dalamnya telah terpasang NodeJS, npm dan now.

Membuat folder bot

  • Buat folder khusus untuk bot, misal nama folder-nya adalah parsebot, sesuai dengan nama bot yang saya buat; Parse Bot.

    mkdir parsebot
    
  • Mari kita pindah ke folder yang baru saja dibuat tadi.

    cd parsebot
    
  • Mulai proyek NodeJS-nya. Jawab setiap pertanyaan yang diajukan.

    npm init
    

    Perintah ini akan menghasilkan sebuah berkas package.json, yang isinya akan serupa berikut ini:

    {
      "name": "parsebot",
      "version": "1.0.0",
      "description": "A simple Telegram message parser bot",
      "main": "parsebot.js",
      "scripts": {
        "start": "parsebot.js",
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [
        "telegram",
        "bot"
      ],
      "author": "Sahri Riza Umami",
      "license": "AGPL-3.0"
    }
    

    Perhatikan baris main, tiap kali bot mulai dijalankan, NodeJS akan mencari isi baris ini atau baris scripts.start untuk diekseskusi. Dalam contoh di atas nama berkasnya adalah parsebot.js, jadi pastikan nama skrip untuk bot adalah parsebot.js. Sesuaikan jika Anda menggunakan nama lain pada baris tersebut.
    Jangan lupa untuk menambahkan baris start (samakan isinya dengan main), karena now akan menolak memasang bot ini ke server-nya jika baris start tidak ada.

  • Pasang framework telegraf.

    npm i telegraf
    

Menulis skrip bot

Buat berkas skrip (sesuaikan nama berkasnya dengan baris main pada package.json) bot, kemudian isikan kode berikut:

const Telegraf = require('telegraf')
const bot = new Telegraf(process.env.BOT_TOKEN)

function unescapeHtml(str){
  const map = {
    amp: '&',
    lt: '<',
    le: '≤',
    gt: '>',
    ge: '≥',
    quot: '"',
    '#039': "'"
  }
  return str.replace(/&([^;]+);/g, (m, c) => map[c]|| '')
}

function strikethrough(str){
  return str.replace(/./g, chr => {
    return chr + '\u0336';
  });
}

bot.on('inline_query', ctx => {
  let results = []
  if (ctx.inlineQuery.query) {
    const text = ctx.inlineQuery.query.replace(/<br\/>/g, '\n')
    results = [
      {
        type: 'article',
        id: `bold_${ctx.inlineQuery.id}`,
        title: 'Bold',
        input_message_content: {
          message_text: `<b>${text}</b>`,
          parse_mode: 'HTML'
        },
        description: 'The text will be bolded',
        thumb_url: 'https://i.imgur.com/90jd2L8.png'
      },
      {
        type: 'article',
        id: `italic_${ctx.inlineQuery.id}`,
        title: 'Italic',
        input_message_content: {
          message_text: `<i>${text}</i>`,
          parse_mode: 'HTML'
        },
        description: 'The text will be italized',
        thumb_url: 'https://i.imgur.com/3FeoOWE.png'
      },
      {
        type: 'article',
        id: `mono_${ctx.inlineQuery.id}`,
        title: 'Monospace',
        input_message_content: {
          message_text: `<code>${text}</code>`,
          parse_mode: 'HTML'
        },
        description: 'The text will be monospaced',
        thumb_url: 'https://i.imgur.com/s7ctUP8.png'
      },
      {
        type: 'article',
        id: `st_${ctx.inlineQuery.id}`,
        title: 'Strikethrough',
        input_message_content: {
          message_text: `${strikethrough(text)}`,
        },
        description: 'The text will be striketrough',
        thumb_url: 'https://i.imgur.com/bTc8EHC.png'
      },
      {
        type: 'article',
        id: `custom_${ctx.inlineQuery.id}`,
        title: 'Custom',
        input_message_content: {
          message_text: `${unescapeHtml(text)}`,
          parse_mode: 'HTML',
          disable_web_page_preview: true
        },
        description: 'The text will be sent as custom HTML formatted text',
        thumb_url: 'https://i.imgur.com/7WgtmoK.png'
      }
    ]
  }
  return ctx.answerInlineQuery(results).catch(error => {
    ctx.answerInlineQuery([{
      type: 'article',
      id: `error_${ctx.inlineQuery.id}`,
      title: '⚠️ Error',
      message_text: `${error}`,
      description: `${error}`
    }])
  })
})

const secret = Math.random().toString(36).slice(2)
bot.telegram.setWebhook(`${process.env.NOW_URL}/${secret}`)
bot.startWebhook(`/${secret}`, null, process.env.PORT, process.env.HOST)

Berikut penjelasan skrip di atas:

  • Muat framework telegraf ke dalam skrip.

    const Telegraf = require('telegraf')
    
  • telegraf kemudian akan memproses bot berdasar token yang diberikan dan memaparkan hasilnya ke dalam constant bot. Token sengaja tidak dituliskan langsung di sini karena bot yang kita pasang secara gratis di now dapat diakses siapa saja. Token akan kita jadikan sebagai environment variable, sebagaimana bisa dilihat pada langkah akhir tutorial ini.

    const bot = new Telegraf(process.env.BOT_TOKEN)
    
  • telegraf (atau mungkin Telegram, saya kurang tahu pasti) akan mengamankan (escape) inlineQuery dari karakter-karakter yang menyerupai tag HTML. Misal karakter "<" akan digantikan "&lt;", karakter "&" digantikan "&amp;", dan sebagainya.
    Kita buat sebuah fungsi bernama unescapeHtml yang akan mengembalikan escaped characters tersebut ke karakter semula. Misal "&gt;" menjadi ">", dan seterusnya.

    function unescapeHtml(str){
      ...
    }
    
  • Selain fungsi dasar menjadikan huruf tebal, miring, monospace dan pranala, kita juga akan menambah fitur strike through (huruf coret) pada bot. Contoh hurufnya seperti ini: huruf coret.

    function strikethrough(str){
      ...
    }
    
  • Untuk mengolah pesan inline, telegraf menyediakan field inline_query pada konteks ctx yang selanjutnya bisa kita olah.

    bot.on('inline_query', ctx => {
    
  • Sebelum mengolah pesan, kita akan siapkan sebuah variable bernama results untuk menyimpan hasil yang kemudian akan dikirimkan oleh answerInlineQuery.

    let results = []
    
  • Telegram akan mengirimkan setiap ketikan karakter yang dimasukkan user ke bot inline. Baris berikut untuk memastikan skrip hanya akan mengolah query yang ada karakternya, jika tidak telegraf akan crash karena mendapati string yang kosong.

    if (ctx.inlineQuery.query) {
    
  • Pada saat mencoba bot ini, saya mendapati sedikit keanehan; Telegram akan mengganti baris baru (newline) pada pesan yang diketikkan user dengan tag <br/> (break). <br/> memang tag HTML yang sah, namun parser HTML Telegram sendiri tidak akan mengolah tag ini. Error yang muncul adalah error 400 karena parser HTML Telegram tidak bisa menemukan tag penutup.
    Jadi sebagai jalan keluarnya, konstan text ini akan mengganti tiap tag <br/> dengan tag \n.

    const text = ctx.inlineQuery.query.replace(/<br\/>/g, '\n')
    
  • Ketika user memberikan permintaan, bot akan mengolah permintaan ini dan menyajikannya sebagai jawaban (answerInlineQuery) pada array results. Bot hanya diizinkan memberikan maksimal 50 jawaban per query.

    results = [
      {
        ...
      }
      ...
    ]
    
  • Setiap jawaban kita tuliskan sebagai objek pada array results. Misal, dalam contoh skrip di atas kita mengajukan sebuah jawaban apakah user ingin mengirim teks pesannya sebagai huruf tebal:

    {
      type: 'article',
      id: `bold_${ctx.inlineQuery.id}`,
      title: 'Bold',
      input_message_content: {
        message_text: `<b>${text}</b>`,
        parse_mode: 'HTML'
      },
      description: 'The text will be bolded',
      thumb_url: 'https://i.imgur.com/90jd2L8.png'
    }
    
    • Ada banyak InlineQueryResult untuk menjawab query. Dalam skrip kita kali ini, karena jawabannya diberikan berupa teks, maka kita cukup menggunakan article (InlineQueryResultArticle) sebagai type-nya.
    • input_message_content.message_text adalah pesan teks yang dikirimkan bot ketika user menekan kolom jawaban.
    • id adalah penanda unik untuk jawaban yang kita berikan.

    Untuk lebih jelasnya tentang title, description dan thumb_url, silakan amati gambar berikut.

    InlineQueryResultArticle structure
  • Ketika user menekan kolom jawaban, bot akan mengirimkan objek yang sesuai dari array result menggunakan answerInlineQuery.

    return ctx.answerInlineQuery(results).catch(error => {
    

    .catch akan menangkap galat dan mengolahnya lebih lanjut.

  • Tiga baris terakhir di bawah ini untuk menetapkan dan menjalankan webhook.

    const secret = Math.random().toString(36).slice(2)
    bot.telegram.setWebhook(`${process.env.NOW_URL}/${secret}`)
    bot.startWebhook(`/${secret}`, null, process.env.PORT, process.env.HOST)
    

Memasang bot ke now

Masih dalam folder bot, kita jalankan now agar ia memasang seluruh isi folder bot ke server-nya.

now --public -e BOT_TOKEN=<token>

Ganti <token> dengan token bot Anda.

Bot kini siap untuk digunakan.

Saya telah memasang bot (Parse Bot) hasil tutorial ini di now, silakan untuk mencobanya dengan cara mengetikkan @parsebot di kolom pesan.