Идея создания бота пришла после замедления YouTube в России. Многие блогеры стали активно призывать подписчиков переходить в Telegram, чтобы не потерять связь с аудиторией. Я решил сделать удобный инструмент для быстрого поиска Telegram-каналов любимых авторов.
Что я использовал?
Поскольку опыта в разработке у меня было мало, я выбрал следующий стек технологий:
-
Node.js с библиотекой telegraf.js для работы с Telegram API
-
MongoDB и mongoose для работы с базой данных
-
Express.js для создания веб-сервера
-
Google API для работы с YouTube
-
Lemnos API для получения дополнительной информации о каналах
Реализация
1. Основные команды бота
Начнем с главной команды /start
, которая инициализирует работу с ботом:
bot.start(async (ctx) => { 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) => { 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) => { ctx.answerCbQuery(); await find_channels(ctx) }) bot.command('find_channels', async (ctx) => { await find_channels(ctx) })
3. Дополнительные команды
Бот также имеет несколько дополнительных команд для удобства использования:
// Команда FAQ bot.command('faq', async (ctx) => { ctx.replyWithMarkdown(` **Ответы на вопросы о проекте:** Какова цель проекта? — Максимально упростить поиск Телеграмм каналов ваших любимых авторов. У меня не украдут Google Аккаунт? — Нет, бот имеет открытый исходный код, который может посмотреть каждый желающий на Github - https://github.com/VitoSperansky/FromYoutubeToTelegram. Как работает бот? — Бот просит вас авторизоваться в свой Google аккаунт, чтобы получить список ваших подписок на YouTube. Затем система обращается к своей базе данных, где хранятся соответствия YouTube-каналов и их Телеграмм-каналов. Если бот находит соответствия в базе данных, он записывает их в список найденных каналов. Если YouTube-каналы, на которые вы подписаны, отсутствуют в нашей базе данных, бот отправляет запрос в YouTube на получение ссылок социальных сетей, привязанных к каналу. Среди этих ссылок бот ищет ссылку на Телеграмм. Найдя новую ссылку на Телеграмм-канал, бот добавляет её в базу данных. В итоге, пользователь получает список YouTube-каналов с их Телеграмм-каналами. Остались вопросы? - Пишите @vitosperansky `); }); // Команда для рассылки сообщений (только для администратора) bot.command('send', async (ctx) => { 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 < 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. Процесс включал несколько этапов:
-
Создание логотипа: Первая версия логотипа была отклонена из-за слишком явного использования элементов YouTube и Telegram. Пришлось создать более оригинальный дизайн.
-
Разработка сайта: Потребовалось создать сайт с политикой конфиденциальности и пользовательским соглашением. При этом возникли следующие требования:
-
Необходимость владения доменом
-
Настройка SSL-сертификатов через certbot
-
Корректная политика конфиденциальности
-
-
Демонстрация работы: Создание демо-видео для показа функционала бота. (пришлось им видео записать под смешную музыку)
Продвижение проекта
Потом я решил продвинуть бота и записал два смешных shorts:
-
https://youtu.be/N0IGLuufSCE — text to speech (elevenlabs)
-
https://youtu.be/MlXEUIDBhE0 — Speech to speech моей записи на ии оригинального голоса Рика из Рика и Морти (сделал на этом сайте).
Полезные ссылки
-
Исходный код: https://github.com/VitoSperansky/FromYoutubeToTelegram
-
Сайт: fytt.tech:3000
-
Контакты для связи: https://t.me/vitosperansky
Планы на будущее
-
Улучшение алгоритма поиска каналов
-
Оптимизация работы с базой данных
-
Добавление новых функций по запросам пользователей
-
Настройка правильной маршрутизации портов на сервере
Заключение
Проект показал, что даже с минимальным опытом разработки можно создать полезный инструмент, который решает реальную проблему пользователей. Открытый исходный код и прозрачность работы позволили завоевать доверие пользователей, а интеграция с популярными платформами обеспечила удобство использования.
ссылка на оригинал статьи https://habr.com/ru/articles/855558/
Добавить комментарий