Я создал Telegram-бота (FYTT), который ищет Telegram-каналы всех ваших подписок на YouTube

от автора

Идея создания бота пришла после замедления YouTube в России. Многие блогеры стали активно призывать подписчиков переходить в Telegram, чтобы не потерять связь с аудиторией. Я решил сделать удобный инструмент для быстрого поиска Telegram-каналов любимых авторов.

Что я использовал?

Поскольку опыта в разработке у меня было мало, я выбрал следующий стек технологий:

  • Node.js с библиотекой telegraf.js для работы с Telegram API

  • MongoDB и mongoose для работы с базой данных

  • Express.js для создания веб-сервера

  • Google API для работы с YouTube

  • Lemnos API для получения дополнительной информации о каналах

Реализация

1. Основные команды бота

Начнем с главной команды /start, которая инициализирует работу с ботом:

bot.start(async (ctx) =&gt; {     const chatId = ctx.chat.id;     let chat = await Analytics.findOne({ chatId: chatId })          // Создаем новую запись пользователя, если его нет в базе     if (chat === null) {         try {             let username = ctx.message.chat.username             let newChat = new Analytics({                 chatId: ctx.message.chat.id,                 username: username,                 awatingChannels: true,                 status: "member",                 count: 0             })             await newChat.save()         } catch {             // Если username недоступен, используем first_name             let newChat = new Analytics({                 chatId: ctx.message.chat.id,                 username: ctx.message.chat.first_name,                 awatingChannels: true,                 status: "member",                 count: 0             })             await newChat.save()         }     } else {         chat.awatingChannels = true         await chat.save()     }      // Отправляем приветственное сообщение с кнопками     await setBotCommands()     ctx.replyWithHTML(         '<b>Приветствуем вас в нашем сервисе поиска Telegram-каналов ютуберов!</b>\n' +         'Бот безопасен, так как представляет собой открытый исходный код, ' +         'который может посмотреть каждый желающий. (/faq или пишите @vitosperansky)\n\n' +         'Поддержать проект: https://www.donationalerts.com/r/vitosperansky\n\n' +         'Выберите опцию:',          Markup.inlineKeyboard([             [Markup.button.callback('Найти YouTube-каналы в Telegram', 'find_channels')],             [Markup.button.callback('Связать YouTube-канал с Telegram-каналом', 'link_channel')]         ]), {             disable_web_page_preview: true         }     ); }); 

2. Авторизация через Google

Для работы с YouTube API необходима авторизация через Google. Вот как реализована генерация URL для авторизации:

async function generateAuthUrl(chatId) {     const credentials = JSON.parse(fs.readFileSync(CREDENTIALS_PATH));     const { client_id, client_secret } = credentials.web;     const oAuth2Client = new OAuth2Client(         client_id,          client_secret,          REDIRECT_URL     );     const authUrl = oAuth2Client.generateAuthUrl({         access_type: 'online',         scope: SCOPES,         state: chatId.toString()     });     return authUrl; } 

Когда пользователь нажимает на кнопку поиска каналов, запускается следующий обработчик:

const find_channels = async (ctx) =&gt; {     const chatId = ctx.chat.id;     const authUrl = await generateAuthUrl(chatId, ctx);      ctx.replyWithMarkdown(         '*Нажмите кнопку ниже для авторизации на Youtube и получения списка ваших подписок:*\n\n' +         '❗Авторизация нужна только для получения списка ваших подписок ' +         '(запрашиваются права youtube.readonly - только чтения, подробнее /faq)❗\n\n' +         '_Процесс займет время: ~50 секунд. (в зависимости от количества ваших подписок)_',          {             reply_markup: {                 inline_keyboard: [                     [{ text: 'Авторизоваться и найти подписки', url: authUrl }]                 ]             }         }     ); };  // Обработчики команды поиска каналов bot.action('find_channels', async (ctx) =&gt; {     ctx.answerCbQuery();     await find_channels(ctx) })  bot.command('find_channels', async (ctx) =&gt; {     await find_channels(ctx) }) 

3. Дополнительные команды

Бот также имеет несколько дополнительных команд для удобства использования:

// Команда FAQ bot.command('faq', async (ctx) =&gt; {     ctx.replyWithMarkdown(` **Ответы на вопросы о проекте:**  Какова цель проекта? — Максимально упростить поиск Телеграмм каналов ваших любимых авторов.  У меня не украдут Google Аккаунт? — Нет, бот имеет открытый исходный код, который может посмотреть каждый желающий на Github - https://github.com/VitoSperansky/FromYoutubeToTelegram.  Как работает бот? — Бот просит вас авторизоваться в свой Google аккаунт, чтобы получить список ваших подписок на YouTube.  Затем система обращается к своей базе данных, где хранятся соответствия YouTube-каналов и их Телеграмм-каналов.  Если бот находит соответствия в базе данных, он записывает их в список найденных каналов.  Если YouTube-каналы, на которые вы подписаны, отсутствуют в нашей базе данных, бот отправляет запрос  в YouTube на получение ссылок социальных сетей, привязанных к каналу. Среди этих ссылок бот ищет  ссылку на Телеграмм. Найдя новую ссылку на Телеграмм-канал, бот добавляет её в базу данных.  В итоге, пользователь получает список YouTube-каналов с их Телеграмм-каналами.  Остались вопросы? - Пишите @vitosperansky     `); });  // Команда для рассылки сообщений (только для администратора) bot.command('send', async (ctx) =&gt; {     if (ctx.message.chat.id == MODERATOR_CHAT_ID) {         let chatId = ctx.message.text.replace('/send ', '').replace(/ [\s\S]+/, '');         let text = ctx.message.text.replace('/send ', '').replace(`${chatId} `, '').toString();          if(chatId === 'all') {             let Users = await Analytics.find()             let goodSend = [];             let badSend = [];             ctx.reply("Рассылка началась.")             for (let i = 0; i &lt; Users.length; i++) {                 try {                     await bot.telegram.sendMessage(Users[i].chatId, text, { parse_mode: "HTML" });                     goodSend.push(Users[i]);                 } catch (error) {                     badSend.push(Users[i]);                 }             }             ctx.reply(`Рассылка завершена\n\nУспешно отправлено: ${goodSend.length} сообщений.\n` +                       `Не получилось отправить: ${badSend.length} сообщений.`)         } else {             try {                 await bot.telegram.sendMessage(chatId, text, { parse_mode: "HTML" });                 ctx.reply(`Сообщение успешно отправлено пользователю. \n\nChatId: ${chatId}\nТекст: ${text}`)             } catch {                 ctx.reply("Ошибка при отправке сообщения.")             }         }     } else {         ctx.reply("Вы не админ!")     } }); 

Проблемы и их решения

1. Проблема дублирования запросов

При авторизации в Google-аккаунте возникла проблема с дублированием запросов, если у пользователя несколько аккаунтов. Для решения этой проблемы я использовал флаг awaitingChannels в базе данных, который позволяет отслеживать состояние запроса и избегать дублирования.

2. Ограничение длины сообщений

В первых версиях бот пытался отправить все найденные каналы одним сообщением, но столкнулся с ограничением Telegram на длину сообщения. Решение было простым — разбить информацию на несколько сообщений. (присылать txt файлом к примеру не совсем верно, ведь тогда теряется легкость в переходе на телеграм канал).

3. Сайт

Сайт работает на порту 3000 (fytt.tech:3000), что не совсем стандартно для веб-приложений. Это связано с тем, что порты ниже 1024 по умолчанию закрыты для установки серверов из соображений безопасности. В идеале следовало бы настроить переадресацию с порта 443 (стандартный HTTPS порт) с помощью инструмента вроде ngrok, но поскольку сайт служит в основном для верификации Google, эта задача была отложена.

Процесс верификации Google

Получение доступа к YouTube API потребовало пройти верификацию Google. Процесс включал несколько этапов:

  1. Создание логотипа: Первая версия логотипа была отклонена из-за слишком явного использования элементов YouTube и Telegram. Пришлось создать более оригинальный дизайн.

    1 версия - отклонена (кто-то увидел тут силуэт лица человека xD)

    1 версия — отклонена (кто-то увидел тут силуэт лица человека xD)
    2 версия - принято (на фоне текст fromyoutubetotelegram)

    2 версия — принято (на фоне текст fromyoutubetotelegram)
  2. Разработка сайта: Потребовалось создать сайт с политикой конфиденциальности и пользовательским соглашением. При этом возникли следующие требования:

    • Необходимость владения доменом

    • Настройка SSL-сертификатов через certbot

    • Корректная политика конфиденциальности

  3. Демонстрация работы: Создание демо-видео для показа функционала бота. (пришлось им видео записать под смешную музыку)

Продвижение проекта

Потом я решил продвинуть бота и записал два смешных shorts:

  • https://youtu.be/MlXEUIDBhE0 — Speech to speech моей записи на ии оригинального голоса Рика из Рика и Морти (сделал на этом сайте).

Полезные ссылки

Планы на будущее

  1. Улучшение алгоритма поиска каналов

  2. Оптимизация работы с базой данных

  3. Добавление новых функций по запросам пользователей

  4. Настройка правильной маршрутизации портов на сервере

Заключение

Проект показал, что даже с минимальным опытом разработки можно создать полезный инструмент, который решает реальную проблему пользователей. Открытый исходный код и прозрачность работы позволили завоевать доверие пользователей, а интеграция с популярными платформами обеспечила удобство использования.


ссылка на оригинал статьи https://habr.com/ru/articles/855558/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *