Привет, Хабр! Сегодня хочу поделиться с сообществом 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. Спасибо тем кто дочитал до конца. Буду признателен за идеи и комментарии.
Комментарии (7)
pol_pot
21.08.2025 13:09yt-dlp умеет скачивать отдельную аудиодорожку. у меня бот так скачивает лучшую из аудиодорожек без видео, затем пережимает в opus 24kb и еще ускоряет до 1.5х, получается хорошее качество и очень маленький размер файла. 1.5х - личные предпочтения, я почти всегда на такой скорости речь слушаю.
Скачивать видео целиком пробовал но телеграм не пропускает больше 50мб в сторону юзера без танцев с бубном, надо или юзербота использовать или их специальный прокси которому надо дохрена памяти, на дешевой впс не получится такое использовать.
xman12 Автор
21.08.2025 13:09для того чтобы телеграмм пропускал файлы более 50мг нужен TelegramBotAPIServer https://github.com/tdlib/telegram-bot-api , я его как раз использую и он идет в сборке, никаких танцев с бубном не нужно чтобы им пользоваться, если говорить о коде то единственное отличие с ним и без него
if apiURL := os.Getenv("TELEGRAM_API_URL"); apiURL != "" { bot, _ = tgbotapi.NewBotAPIWithAPIEndpoint(os.Getenv("TELEGRAM_API_TOKEN"), apiURL+"/bot%s/%s") } else { bot, _ = tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_API_TOKEN")) }
по поводу того почему качаю видео а потом достаю от туда аудио – делается это потому что собирается база fileId и складывается и когда в след раз кто-то захочет скачать повторно тот же файл я достану fileId и отдам файл без скачивания самого файла, поэтому при первой загрузке делается сразу полная скачка всего.
LesnoyChelovek
Сейчас, вроде, YouTube без валидных cookies не пускает на сайт, предлагая авторизоваться, доказав, что не бот. Как вы это обошли в своём боте?
xman12 Автор
Ничего не обходил, вся работа происходит в рамках yt-dlp. Единственное, что тут предпринято для "обхода" это http прокси, еще давно я подсчитывал 1-ого прокси хватает примерно на 300 скачиваний, потом просит ввести каптчу это единственное ограничение которое я заметил.
tagabenz
вроде как не для каждого видео это нужно