Разрабатываем Telegram-бота для отслеживания фильмов на NodeJS и TypeScript +10
Node.JS, TypeScript, MongoDB
Рекомендация: подборка платных и бесплатных курсов Python - https://katalog-kursov.ru/
У вас бывало такое, что вы приходите в кино и смотрите трейлеры перед началом фильма, при этом некоторые из них цепляют вас достаточно сильно и вы даете себе обещание посмотреть этот фильм если не в кинотеатре, то хотя бы позже, когда он станет доступен для скачивания? Смею предположить, что да. Но часто заканчивается это тем, что вы успешно забываете про это и, в лучшем случае, случайно находите этот фильм пролистывая список уже вышедших фильмов.
Я достаточно часто сталкивался с такой проблемой и решил ее созданием Eve — Telegram-бота, который помогает мне не забывать про релизы моих любимых фильмов. Что это, как оно работает и как разрабатывалось вы можете почитать под катом!
Предисловие
Данная статья не является подробным гайдом по созданию Telegram-ботов. И хотя по ходу статьи я буду достаточно часто ссылаться на свой проект, целью данного материала является рассказ про разработку в общем, а именно выбор технологий, ключевые моменты и подводные камни, с которыми я столкнулся.
Зачем?
Итак, как я написал выше, я достаточно часто забываю посмотреть те фильмы, трейлер которых мне понравился. Я долго думал над решением этой проблемы. Первое, что пришло мне в голову — создание нативного приложения для смартфонов, но т.к. я никогда не занимался этим раньше, это заняло бы достаточно много времени и не факт, что конечный результат удовлетворял бы мои потребности, а также потребности потенциальных пользователей.
Следующей идеей было создание PWA. Вполне себе интересный вариант для того, чтобы познакомиться с технологией, но ее я решил оставить на будущее. В то же самое время я достаточно давно пользуюсь Telegram и за все это время у меня скопилось достаточное количество ботов, которые периодически делают мою жизнь немного проще. В конечном счете взвесив все плюсы и минусы, я решил, что данная платформа отлично подойдет для данной идеи.
Выбор технологий
Если прошерстить Github на предмет наличия Telegram-ботов, то можно увидеть, что большая часть из них написана на Python. Python действительно замечательный язык и отлично подходит для данной идеи, но мне хотелось реализовать данный проект именно на NodeJS + TypeScript. Применив соответствующие фильтры я наткнулся на 2 достаточно популярных инструмента:
node-telegram-bot-api и
Telegraf.js.
До этого опыта разработки ботов у меня не было, поэтому при выборе из этих двух было не совсем понятно на какие параметры следует смотреть. В итоге посмотрев документацию и полистав issues к каждой из библиотек, я остановился на Telegraf.js. Решающим фактором стало наличие механизма middlewares, который устроен таким же образом, как и в популярном фреймворке Express.js. Также Telegraf.js имеет более частую историю обновлений и хорошо структурированную документацию, из чего можно предположить, что разработчики прикладывают достаточно усилий для улучшения инструмента. Более того, он содержит тайпинги для TypeScript, что определенно является плюсом для выбранного стека.
Telegraf.js
Telegraf.js — основная библиотека, на которой был написан проект. Она использует несколько интересных подходов, которые позволяют создавать сложных ботов с сохранением простоты кода. Ниже представлены наиболее интересные механизмы:
Структура проекта
Есть подозрение, что статья получится достаточно объемной, а потому, чтобы не растягивать ее еще больше, я опущу некоторые моменты. Например, чтобы бот начал работать, необходимо начать с получения Telegram Bot API token. Прочитать о том, как это сделать, можно в официальной
документации Telegram или же в
документации к Telegraf.js.
Файловая структура проекта выглядит следующим образом:
Работает это следующим образом:
- src/controllers — это и есть те самые сцены, про которые было написано выше. В данном проекте каждая сцена представляет из себя отдельный контроллер, который занимается обработкой соответствующих запросов.
- src/locales — переводы для разных языков. Telegraf.js позволяет относительно просто добавить локализацию к боту с использованием middlewares.
- src/models — модели для MongoDB.
- src/types — тайпинги для TypeScript. К сожалению, не все используемые в проекте библиотеки имеют тайпинги по умолчанию.
- src/util — различные функции-помощники, которые используются в разных частях проекта. Здесь можно посмотреть как работает проверка доступности фильма для скачивания, управление сессиями, создание клавиатур, обработчики ошибок и еще много всего интересного.
- src/bot.ts — главный файл, где производится вся подготовка и запуск бота.
- src/telegram.ts — в данном случае мы создаем объект класса Telegram из библиотеки Telegraf.js. С помощью этого объекта мы можем отправлять пользователям сообщения первыми, используя их ID, а не ждать, пока они что-то напишут. Например, в данном проекте мы отправляем пользователю сообщение о том, что фильм, за которым он следил, уже можно скачать. Конечно же, данный объект предоставляет гораздо больше возможностей.
- Все остальное — конфигурации для разных частей проекта, которые не будут рассмотрены в этой статье
Инициализация и запуск
Когда мы разобрались со структурой проекта, давайте посмотрим, как собственно происходит запуск бота. Опять же, в целях сокращения статьи я не буду вставлять сюда код целиком, а расскажу лишь про главные, на мой взгляд, моменты. Полный код вы можете посмотреть в репозитории, ссылка на который доступна в конце статьи.
Начинается все с подключения к БД, где хранится информация о пользователях и отслеживаемых ими фильмах. После успешного подключения мы регистрируем все используемые в проекте сцены, задаем параметры для локализации и добавляем несколько middlewares — обработку сессий, локализацию, настройку сцен, а также несколько собственных. Одна из них, например, получает всю информацию о пользователе в соответствии с его ID и добавляет ее к контексту, который используется в контроллерах. Наконец, после всех основных приготовлений, мы запускаем бота либо в development (long polling), либо в production (Webhooks) режиме.
Важно: если вы используете разные методы получения обновлений (long polling и Webhooks), то при запуске бота в режиме long polling сперва удалите слушающий Webhook с помощью GET запроса на
api.telegram.org/botYOUR_TOKEN/deleteWebhook. В противном случае бот может работать неправильно.
Обрабатываем пользовательский ввод
Ура! Бот работает, подключен к базе данных и готов принимать сообщения от пользователей. Но как правильно это сделать?
В первую очередь, пользователям будет удобно пользоваться встроенной Telegram-клавиатурой. По сути, при нажатии на кнопки этой клавиатуры отправляются сообщения с содержимым этих кнопок. Дальше мы просто добавляем обработчики этого текста и выполняем определенные действия.
В файле
bot.ts как раз стоят такие обработчики. Так как бот поддерживает два языка, то и кнопки могут содержать разный текст — на русском и английском языках. В telegraf-i18n есть функция match, которая умеет обрабатывать нажатие одной и той же кнопки с разными языками.
Большинство обработчиков в bot.ts выполняют единственную функцию — они запускают пользователя в соответствующую сцену. Так, у нас есть несколько разделов — поиск фильмов, моя коллекция, настройки и контакты. Для каждого из разделов есть своя сцена и своя кнопка, при нажатии на которую пользователь перемещается в соответствующую сцену.
Важно: обязательно добавьте обработчик, который будет выпускать пользователя из сцены, иначе они рискуют остаться там навсегда! Также полезным будет сделать одну общую команду (в боте используется /saveme), которая будет добавлена в каждую сцену и в главный файл. Эта команда будет служить выходом из любой сцены, а также сбрасывать пользовательские настройки.
И вот, пользователь хочет перейти к поиску фильмов. Нажатием на соответствующую кнопку мы перемещаем его в сцену поиска. Для удобства, у каждой сцены есть своя папка с файлами, каждый из которых выполняет определенную функцию.
Внутри сцены можно использовать свои middlewares, которые лежат в файле middlewares.ts. Например, используя middleware в сцене поиска, мы можем достаточно просто пробросить всю информацию о фильме в соответствующие методы, а не выполнять одну и ту же функцию каждый раз внутри них.
В Telegram также есть inline-клавиатура. Возможно вы встречали сообщения с голосованиями, под которыми есть несколько полупрозрачных кнопок и при нажатии на одну из них количество голосов меняется. Эти кнопки и есть inline-клавиатура
Вот как это выглядит у Eve
В каждой кнопке содержится информация, при нажатии на кнопку она будет передана в соответствующий обработчик.
Размер передаваемой информации не должен превышать 64 байта! Чтобы научить бота слушать нажатия на кнопки, нам нужно зарегистрировать их с помощью bot.action(/trigger/, callback). В первый параметр попадают все данные, которые были привязаны к кнопке. Я решил использовать нечто вроде Actions из Redux, где к каждой кнопке привязан объект вида {a: actionName, p: payload}. При регистрации listeners мы можем использовать простой RegExp, например: bot.action(/actionName/, callBack). Все обработчики для inline-клавиатуры находятся в файлах actions.ts.
Помимо этого, в некоторых сценах лежат файлы helpers.ts, которые содержат в себе небольшие функции вынесенные туда с целью разгрузить остальные файлы. По большей части там лежат генераторы клавиатур для разных действий со стороны пользователя.
Локализация
Так как это важная тема, я думаю ее стоит упомянуть отдельно. Как я говорил ранее, Telegraf.js содержит довольно большое количество middlewares, одной из которых является
telegraf-i18n. В репозитории присутствует подробная инструкция и особых проблем у меня с этим не возникло, но все же я добавлю пару слов о том, как это работает в данном проекте.
Есть папка locales, где лежат файлы для локализации, которые представляют из себя JSON объект вида { «ключ»: «перевод» }. Далее, везде, где нам нужно использовать разные языки, мы используем метод из этой библиотеки, куда передаем нужный нам перевод по ключу, а на выходе получаем соответствующий перевод. Для хранения информации о выбранном пользователем языке может использоваться сессия. Также еще раз стоит упомянуть про кнопки. В этой же библиотеке есть функция match, поэтому если текст на кнопке меняется в зависимости от языка, то эта функция поможет вам повесить правильный listener.
Важно: если вы собираетесь использовать локализацию и писать бота на TypeScript, не забудьте добавить папку с переводами в tsconfig.json, иначе код не скомпилируется. Например:
"include": ["src/locales/*.json"]
Заключение
Спасибо что дочитали до конца! В этой статье я постарался максимально подробно описать процесс создания Telegram-бота в целом, без сильной привязки к своему проекту. Я надеюсь, что после прочтения этой статьи, а также изучения исходного кода Eve, вы сможете с легкостью создать бота, который сможет помочь вам.
Как и обещал, исходный код вы можете посмотреть на
GitHub, а попробовать Eve в деле
вот здесь. Я буду безмерно благодарен за любую критику и предложения по улучшению.
Отдельно хочу отметить
раздел в документации Telegraf.js с интересными open source проектами, на которые можно посмотреть и вдохновиться архитектурой и решениями. Я, в свою очередь, хочу отметить один из них —
The Guard Bot. Поистине большой и хорошо сделанный бот, откуда я позаимствовал часть решений для своей разработки.
А на данный момент я рассказал все, что хотел, буду рад ответить на ваши вопросы, предложения и комментарии!
К сожалению, не доступен сервер mySQL