Идея создания бота пришла после замедления 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
Планы на будущее
Улучшение алгоритма поиска каналов
Оптимизация работы с базой данных
Добавление новых функций по запросам пользователей
Настройка правильной маршрутизации портов на сервере
Заключение
Проект показал, что даже с минимальным опытом разработки можно создать полезный инструмент, который решает реальную проблему пользователей. Открытый исходный код и прозрачность работы позволили завоевать доверие пользователей, а интеграция с популярными платформами обеспечила удобство использования.
Комментарии (6)
Metotron0
02.11.2024 08:59У меня из 20-30 подписок около 15 — это музыкальные группы или каналы, которые просто выкладывают музыку, штук 10 давно уже ничего не выкладывают, но лежат, дабы не потерять годноту, остальное не особо помню. Ну, там, Внеземной подкаст, Вселенная плюс, и тот канал, где учёные выбирают собеседника-учёного, у них три выпуска вышло. У этих вполне могут быть и телеграмы, это да. Но их я руками открою.
Не сомневаюсь, что кому-то нужен бот, все пользуются ютубом по-разному.
Такой вопрос: почему, когда один человек делает сайт/приложение, он часто пишет "мы", "наш"? От чьего лица он говорит? От какой-то юридической компании или команды разработчиков? Я понимаю, если юр. лицо из одного человека что-то выпустило, там с натяжкой может быть "наш", но когда "я создал", а потом "в нашем сервисе", то что получается, писал на заказ? Или написал и отдал в коллективное владение? Или автор принципиально против частной собственности?
VitoSperansky Автор
02.11.2024 08:59"в нашем сервисе", я написал только в приветственном сообщение самого бота, а в статье везде я пишу: "я создал". Причины писать в боте от 3 лица простая - это просто легче воспринимается людьми, по-моему мнению. Ну не писать же: "Приветствую тебя в моей сервиса", тогда, такие уникальные люди как ты подумают, что я крайне высокомерен и подчеркиваю свое владение этим. Да и вообще как можно было за это зацепиться заняться не чем что ли.
Про применение - согласен, очень маленькому количество людей оно пригодиться, но я и делал его больше для себя, мне это было интересно.Metotron0
02.11.2024 08:59Зачем вообще писать, чей это сервис? Или "Добро пожаловать в сервис", или "Сервис приветствует вас".
ritorichesky_echpochmak
02.11.2024 08:59https://youtu.be/N0IGLuufSCE - text to speech (elevenlabs)
Ммм... "Знаменитые" в узких кругах ElevenLabs, из-за которых загнулся Omnivore
Dynasaur
этож скока надо иметь подписок, чтобы ботом их разыскивать?
VitoSperansky Автор
50-1000000000000000000