Привет, Хабр! Сегодня хочу поделиться с сообществом TG ботом, которого я написал пару лет назад и который до сих пор актуален и работает.
Немного истории
Свое знакомство с телеграмм ботами я начал как раз с разработки ютуббота, было это около 5 лет назад. Первая версия этого бота была реализована на php, реализовывалась она на коленке и скорее ради интереса пощупать что такое боты и закрыть мою потребность в удобном скачивании роликов с ютуба. Версия на php прожила около 2-х лет, бот рос, был неудобен в плане поддержки и какого то расширения и я решил сделать не рефакторинг, а полное переосмысление бота, но только не на php, а уже на GO, тогда я активно знакомился с языком и мне нужна была какая‑то практика.
Далее буду рассказывать о боте и для контекста оставлю ссылку на его github: https://github.com/xman12/youtube_bot
А что он может?
В боте реализована скачка роликов средствами yt‑dlp. После скачки средствами ffmpeg извлекается аудиодорожка и отправляется пользователю. Так же доступна скачать видео и превью видео по соответствующим кнопкам, ну и все).
А что внутри?
Бот написал на языке GO, база данных Mysql, для статистики и мониторинга используется Prometheus + Grafana и все это упаковано в Docker.
Архитектура


Реализация бэкенда
Бэкенд бота написан на Go и реализует следующую функциональность:
Обработка сообщений Telegram Bot API
Загрузка видео с YouTube через yt-dlp
Управление пользователями, информация о загруженных видео
Сбор метрик для Prometheus
Ротация HTTP-прокси
Вся логика реализована в internal/app/server.go
Хотел бы немного рассказать о ротации проксей. Она происходит таким образом, берется пулл прокси из файла и по очередно происходит выборка прокси и подставляется в yt-dlp
выглядит это так:

По такой логике все прокси из файла получат равномерное количество скачек и равномерно "сдохнут".
В коде это выглядит так:
в server.go
инициализируется структура прокси
proxyKey := youtube.ProxyOption{
Key: 0,
Path: os.Getenv("PATH_TO_PROXY"),
}
ProxyOption передается по ссылке и попадает в функцию
func GetProxy(option *ProxyOption) Proxy {
collection := ParsFile(option.Path)
if len(collection)-1 == option.Key {
proxy := collection[option.Key]
option.Key = 0
return proxy
} else {
proxy := collection[option.Key]
option.Key++
return proxy
}
}
На выходе имеем Объект Proxy и работаем с ним.
proxy := GetProxy(proxyOption)
args := fmt.Sprintf("yt-dlp --no-mtime --proxy %s -o \"%s/%%(id)s.%%(ext)s\" \"%s\" --merge-output-format=\"mp4/mkv\" -f w", proxy.GetProxyString(), pathLoad, urlDownload)
Бот позволяет работать в связке с TelegramBotAPIServer, что позволяет расширять ограничения по загрузке файлов.
Особенности бота
В Docker настроены:
Автоматическое обновление yt-dlp раз в 6 часов
Автоматическое очищение роликов раз в час
Автоматический импорт схемы БД при первом запуске
Возможность создавать бэкапы и их загружать (тут все ручками через bash скрипты)
Возможность ограничить подключение к Mysql, Grafana, Prometheus по IP
Развертывание запустив 1 команду
Метрики
Бот собирает основные метрики:
request_total
– Общее количество запросов к ботуregister_users_total
– Количество зарегистрированных пользователейvideo_loads
– Количество успешных загрузок видеоvideo_loads_error
– Количество ошибок загрузки
Развертывание
Для того, чтобы развернуть проект достаточно выполнить команду в корне проекта:
chmod +x start.sh
./start.sh

Репозиторий: https://github.com/xman12/youtube_bot
PS. Спасибо тем кто дочитал до конца. Буду признателен за идеи и комментарии.