196 lines
10 KiB
Markdown
196 lines
10 KiB
Markdown
|
|
# ТЗ: 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 символов)
|
|||
|
|
- итоговый файл: `<title>.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` меняет только токены, оба бота всегда работают.
|