# ТЗ: Telegram-сервис “YouTube → MP3” + Admin bot (Docker Compose, Ubuntu 24.04, Python) ## 0. Цель Нужно реализовать сервис на Python, который состоит из **двух Telegram-ботов**: 1) **User-bot** — принимает от пользователя ссылку на YouTube-видео и возвращает аудио-дорожку в **MP3**. Имя файла должно быть **идентично названию видео на YouTube**. 2) **Admin-bot** — получает **все MP3**, которые были выданы пользователям user-bot, вместе с метаданными: - название файла (title) - Telegram username пользователя (кто запросил) - исходная ссылка на видео Сервис разворачивается в Docker через docker-compose на хосте **Ubuntu 24.04**. --- ## 1. Общие требования - Язык: **Python**. - Сервис работает в Docker. - Используется **docker compose** (актуальная версия). - В репозитории должен быть файл `.env.example`. Реальный `.env` хранится на сервере и находится в `.gitignore`. - При `isProd=true` используются **продовые** токены ботов, при `isProd=false` — **тестовые**. - В обоих режимах всегда запускаются **оба бота** (user + admin), меняются только токены. --- ## 2. Переменные окружения Файл `.env.example` должен содержать: - `IS_PROD=false` (строка `true/false`) Токены 4 ботов: - `TG_USER_BOT_TOKEN_PROD=...` - `TG_ADMIN_BOT_TOKEN_PROD=...` - `TG_USER_BOT_TOKEN_TEST=...` - `TG_ADMIN_BOT_TOKEN_TEST=...` Дополнительно (можно включить, если нужно для реализации): - `ADMIN_CHAT_ID=` (если admin-bot должен отправлять файлы в конкретный чат/пользователю; если не задан — отправлять **все админам admin-бота, которые ему написали /start** и тем самым зарегистрировались) - `WORKDIR=/data` (папка для временных файлов внутри контейнера) - `LOG_LEVEL=INFO` > Важно: логика выбора токенов: - если `IS_PROD=true` → берём `*_PROD` - иначе (`false`) → берём `*_TEST` --- ## 3. Docker / Compose требования ### 3.1 Контейнер В контейнере должны быть установлены: - `yt-dlp` - `ffmpeg` - **опционально** `nodejs` (т.к. YouTube иногда требует JS runtime; установка допускается) ### 3.2 Временное хранение файлов - Все промежуточные файлы (скачанное аудио/MP3) должны храниться во **временной папке**, смонтированной как **volume** на хост. - После успешной отправки MP3 **и пользователю, и в admin-bot** файл должен быть **удалён**. --- ## 4. Очередь и конкурентность - Все запросы на скачивание должны обрабатываться **строго последовательно** (FIFO очередь). - В один момент времени выполняется **только 1 активная загрузка/конвертация** (однопоточно, один worker). - Если несколько пользователей отправляют ссылки одновременно — они “встают в очередь”. - Пользователь должен получать сообщения о статусе: - “Принято в очередь, позиция: N” - “Начинаю обработку” - “Готово, отправляю файл” - “Ошибка: …” --- ## 5. Функционал user-bot ### 5.1 Вход Пользователь отправляет сообщение, содержащее ссылку на YouTube-видео. Поддерживаемые ссылки: - `https://www.youtube.com/...` - `https://youtu.be/...` (это короткий домен YouTube, его тоже нужно поддержать) Если ссылка не похожа на YouTube — отвечаем пользователю: “Пришли ссылку на YouTube-видео.” ### 5.2 Получение названия видео - Бот пытается получить `title` через `yt-dlp` метаданными. - Если **название получить не удалось** (пустое/ошибка/не распарсилось), включается интерактивный шаг: 1) Бот пишет: “Не смог определить название. Введи имя файла (без расширения .mp3).” 2) Бот ждёт ответ пользователя текстом. 3) Полученное имя используется как название выходного mp3. ### 5.3 Формирование корректного имени файла - Название файла должно быть безопасным для файловой системы: - запрещённые символы заменять на `_` - ограничить длину (например, до 150 символов) - итоговый файл: `.mp3` ### 5.4 Скачивание и конвертация Команда yt-dlp должна: - извлечь аудио и сконвертировать в mp3 - использовать ffmpeg Рекомендуемый шаблон: - `yt-dlp -x --audio-format mp3 --audio-quality 0 -o "<path>/%(title)s.%(ext)s" "<URL>"` Но с учётом того, что название может быть задано вручную, реализация может: - скачать во временный файл, - затем переименовать, - либо подставить имя в `-o`. ### 5.5 Выход - User-bot отправляет пользователю MP3 как документ/аудио файл. - Имя файла (filename) в Telegram должно быть `<title>.mp3`. --- ## 6. Функционал admin-bot ### 6.1 Что отправлять На каждый успешный запрос user-bot admin-bot должен получить: - сообщение (текст) с полями: - `title: ...` - `requested_by: @username` (если username отсутствует — использовать user_id) - `url: ...` - затем **сам mp3 файл** (один файл = одно событие) ### 6.2 Куда отправлять Варианты (выбрать и реализовать): - Если задан `ADMIN_CHAT_ID` → отправлять туда. - Иначе: admin-bot должен иметь механизм регистрации администраторов: - любой, кто написал admin-bot `/start`, добавляется в список получателей - всем зарегистрированным администраторам отправлять уведомления и mp3 Список администраторов хранить в простом виде: - JSON файл в volume (`/data/admins.json`) **или** - SQLite в volume --- ## 7. Логирование и наблюдаемость - Логи писать в stdout/stderr (чтобы смотреть через `docker logs`). - Логировать: - входящие запросы (user_id, username, url) - постановку в очередь (позиция) - старт/успех/ошибку обработки - ошибки `yt-dlp` и `ffmpeg` (кратко, но информативно) - Уровень логов через `LOG_LEVEL`. --- ## 8. Обработка ошибок Нужно аккуратно обрабатывать: - yt-dlp не смог скачать (403/geo/timeout и т.п.) - ffmpeg упал - Telegram API ошибка отправки файла - пользователь прислал мусор вместо ссылки - пользователь не ответил на запрос имени файла (можно таймаут, например 5 минут → отмена) Поведение при ошибке: - пользователю отправить сообщение с ошибкой (без гигантского трейсбека, но с причиной) - задачу удалить из очереди и перейти к следующей - временные файлы удалить --- ## 9. Структура проекта (ожидание) В репозитории должны быть: - `docker-compose.yml` - `Dockerfile` - `.env.example` - `.gitignore` (включает `.env` и временные файлы) - `app/` (код) - `README.md` с командами запуска --- ## 10. Команды запуска (описать в README) - `docker compose up -d --build` - просмотр логов: `docker compose logs -f` --- ## 11. Ограничения (сознательно НЕ делаем сейчас) Пока **не вводим**: - лимиты по длительности видео - лимиты по размеру файла - поддержку плейлистов - сложные ACL/авторизации, кроме механизма получателей admin-bot (см. 6.2) --- ## 12. Критерии приёмки 1) Пользователь отправляет YouTube-ссылку → получает mp3 с названием как у видео. 2) Одновременно 5 пользователей отправляют ссылки → задачи встают в очередь, скачивание идёт строго по одной. 3) На каждый успешно выданный mp3 admin-bot получает: - текст с title/username/url - затем mp3 файл 4) После отправки пользователю и в admin-bot временный файл удаляется. 5) Переключение `IS_PROD` меняет только токены, оба бота всегда работают.