Tạo bot Telegram đơn giản bằng NodeJS


1044

Bot hoạt động như thế nào

Để có thể nhận cập nhật từ Telegram, bạn cần có token. Tất cả các cập nhật và tương tác với bot được lưu trữ trong Telegram. Và bạn có thể nhận chúng bằng cách gửi request đến URL này với token đó.

https://api.telegram.org/bot<token>/METHOD_NAME

Bot API là một giao diện dựa trên HTTP được tạo cho các developer quan tâm đến việc xây dựng bot cho Telegram.

Bắt đầu

Trước hết, hãy tiếp tục và tạo bot với BotFather– chính là một bot. Bây giờ bạn có token và có thể nhận được các bản cập nhật từ Telegram. Hãy lấy một số thông tin từ Telegram có thể đảm bảo bot hoạt động.

Thay thế URL ở trên bằng token và một phương thức từ API Bot của Telegram. Hãy sử dụng phương thức getMe.

https://api.telegram.org/bot<token>/getMe
// --> {"ok":true,"result":{"id":437852999,"is_bot":true,"first_name":"Reddit Bot","username":"SimpleReddit_Bot"}}

Làm tốt lắm. Nhưng làm thế nào để chúng ta làm điều này trong NodeJS? Về cơ bản nó giống nhau. Mỗi khi cần cập nhật, sẽ gửi request đến URL đó bằng phương thức mong muốn.

Nhưng toàn bộ quá trình thực hiện điều này sẽ rất khó, vì vậy có các khuôn khổ hữu ích cho việc này. Họ xử lý mọi thứ và tập trung vào những gì quan trọng. Có một số framework tốt có sẵn cho NodeJS, trong hướng dẫn này, chúng ta sẽ sử dụng Telegraf.

Bắt dầu code với NodeJS

Khởi tạo dự án và cài đặt Telegraf:

npm init
npm install telegraf --save

Bây giờ hãy thêm nó vào script và tạo một bot đơn giản:

const Telegraf = require('telegraf');
const app = new Telegraf(YOUR_TOKEN_HERE);
app.hears('hi', ctx => {
  return ctx.reply('Hey!');
});
app.startPolling();

Chuyện gì vậy? Telegraf có các phương pháp riêng để xử lý hầu hết công việc cho. Chúng ta có thể sử dụng phương pháp này để trả lời tin nhắn của người dùng:

Reddit bot

Hãy lấy một ví dụ. Chúng ta sẽ gửi bài đăng hàng đầu của subreddit mà người dùng yêu cầu. Cài đặt thư viện axios để đơn giản hóa việc gửi yêu cầu GET và lấy dữ liệu từ Reddit.

npm install axios --save
const axios = require('axios'); // add axios
// handle the reaction everytime user sends a text message
app.on('text', ctx => {
  // ctx object holds the Update object from Telegram API
  // So you can use everything you see there
  // get the text message sent by user
  const subreddit = ctx.message.text;
  // GET the data from Reddit API
  axios
    .get(`https://reddit.com/r/${subreddit}/top.json?limit=10`)
    .then(res => {
      // data recieved from Reddit
      const data = res.data.data;
      // if subbreddit does not exist
      if (data.children.length < 1)
        return ctx.reply("The subreddit couldn't be found.");
      // send the first top post link to the user
      const link = `https://reddit.com/${data.children[0].data.permalink}`;
      return ctx.reply(link);
    })
    // if there's any error in request
    .catch(err => console.log(err));
});

Khi người dùng gửi tên subreddit, chúng ta sẽ lấy bài đăng top của subreddit đó và gửi liên kết của nó cho họ. Đơn giản phải không?

Lưu state

Hãy tưởng tượng người dùng muốn các tùy chọn khác như top, hot và new. Chúng ta cần lưu trữ lệnh gần nhất mà họ đã sử dụng để có thể phản hồi chính xác. Lưu ý rằng chúng ta sử dụng phương thức command thay vì on.

Bạn có thể tạo lệnh trên bot Telegram. Các lệnh bắt đầu bằng ‘/’ và có thể nhấp được. Để thêm lệnh vào bot của bạn, hãy nhắn tin cho BotFather.

let state = {};
app.command('top', ctx => {
  const userId = ctx.message.from.id;
  // if user id does not exist create one
  if (!state[userId]) state[userId] = { id: userId };
  // save/update user last command
  state[userId].command = 'top';
  return ctx.replyWithMarkdown(`Enter a subreddit name to get *top* posts.`);
});
app.command('hot', ctx => {
  const userId = ctx.message.from.id;
  if (!state[userId]) state[userId] = { id: userId };
  state[userId].command = 'hot';
  return ctx.replyWithMarkdown('Enter a subreddit name to get *hot* posts.');
});

Bây giờ có thể gửi bài phù hợp dựa trên bộ lọc. Trong phản hồi văn bản như sau:

const userId = ctx.message.from.id;
// check if state and command exists and set defaults
const type = !state[userId]
  ? 'top'
  : state[userId].command ? state[userId].command : 'top';
axios
  .get(`https://reddit.com/r/${subreddit}/${type}.json?limit=10`)
  .then(res => [
    // do stuff
  ]);
nodejs-reddit-bot-3

Inline buttons

Các bot Telegram có các nút tương tác được gọi là InlineKeyboardMarkup. Chúng ta sẽ thêm một nút next để người dùng có thể nhận được bài đăng tiếp theo trong danh mục đó.

Chúng ta cần trích xuất các phương pháp cụ thể cho các nút từ Telegraf để làm việc với chúng:

const { Markup } = require('telegraf');

Đầu tiên, hãy thêm số bài đăng hiện tại vào state. Mỗi khi người dùng yêu cầu một subreddit, chúng ta cần đặt index thành 0. Trong phương thức texti:

if (!state[userId]) state[userId] = {};
state[userId].index = 0;

Thay vì gửi text thuần túy, chúng ta gửi nó bằng một nút inline trong response axios:

// old response, only text
return ctx.reply(link);
// new response, with inline buttons
return ctx.reply(
  link,
  Markup.inlineKeyboard([
    // first argument is button's text
    // second argument is callback text
    Markup.callbackButton('➡️ Next', subreddit),
  ]).extra(),
);

Chúng ta có thể xử lý lệnh gọi lại với phương thức on, nhưng lần này, phương thức cập nhật là callback_query:

app.on('callback_query', ctx => {
  // get info from callback_query object
  const subreddit = ctx.update.callback_query.data;
  const userId = ctx.update.callback_query.from.id;
  // check if user state and its properties exist
  let type;
  let index;
  try {
    type = state[userId].command ? state[userId].command : 'top';
    index = state[userId].index;
  } catch (err) {
    return ctx.reply('Send a subreddit name.');
  }
  // reply with a popup to callback
  ctx.answerCallbackQuery('Wait...');
  axios
    .get(`https://reddit.com/r/${subreddit}/${type}.json?limit=10`)
    .then(res => {
      const data = res.data.data;
      // check if next one exists
      if (!data.children[index + 1]) return ctx.reply('No more posts!');
      // send next link and update the user state with new index
      const link = `https://reddit.com/${
        data.children[index + 1].data.permalink
      }`;
      state[userId].index = state[userId].index + 1;
      return ctx.reply(
        link,
        Markup.inlineKeyboard([
          Markup.callbackButton('➡️ Next', subreddit),
        ]).extra(),
      );
    })
    .catch(err => console.log(err));
});
nodejs-reddit-bot-4

Kết luận

Như bạn có thể thấy, chúng ta đã tạo bot Telegram đơn giản trong vài phút. Tạo bot trong Telegram dễ dàng, nhưng không dừng lại ở đây. Có rất nhiều thứ khác mà có thể làm với chúng — chẳng hạn như gửi ảnh, video, tài liệu, v.v.

Hãy tưởng tượng tất cả những điều bạn có thể làm với API khổng lồ của Telegram trở nên tốt hơn với mỗi bản cập nhật.

Tham khảo thêm về NodeJS tại đây : Thành thạo REPL NodeJS trong 3 phút


Like it? Share with your friends!

1044