audio_from_youtube/youtube_mp3_telegram_service_TZ.md

196 lines
10 KiB
Markdown
Raw Normal View History

# ТЗ: 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` меняет только токены, оба бота всегда работают.