# Архитектура системы Документ описывает внутреннюю архитектуру и принципы работы Telegram Video Download Bot. ## Общая архитектура Система состоит из микросервисной архитектуры с раздельными сервисами для каждого источника видео: 1. **Основной бот** (`bot.py` в корне проекта) — Telegram бот, обрабатывающий запросы пользователей и оркестрирующий запросы к сервисам 2. **YouTube Downloader Service** (`youtube-downloader/`) — микросервис для скачивания видео с YouTube 3. **Instagram Downloader Service** (`instagram-downloader/`) — микросервис для скачивания видео с Instagram 4. **VK Downloader Service** (`vk-downloader/`) — микросервис для скачивания видео с VK ``` ┌─────────────────┐ │ Telegram User │ └────────┬────────┘ │ ▼ ┌─────────────────────────────────────┐ │ Основной бот (bot.py) │ │ ┌───────────────────────────────┐ │ │ │ Message Handler │ │ │ │ - URL extraction │ │ │ │ - Source detection │ │ │ └───────────────────────────────┘ │ │ ┌───────────────────────────────┐ │ │ │ HTTP API Clients │──┼──┐ │ │ - YouTube API Client │ │ │ │ │ - Instagram API Client │ │ │ │ │ - VK API Client │ │ │ │ └───────────────────────────────┘ │ │ │ ┌───────────────────────────────┐ │ │ │ │ SQLite Database │ │ │ │ │ - Users │ │ │ │ │ - Stats │ │ │ │ └───────────────────────────────┘ │ │ │ ┌───────────────────────────────┐ │ │ │ │ Video Storage │ │ │ │ │ - video/ directory │ │ │ │ └───────────────────────────────┘ │ │ └─────────────────────────────────────┘ │ │ HTTP API │ POST /download/stream │ ┌──────────────────────────────────┼──────────────────┐ │ │ │ ▼ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ YouTube Downloader│ │Instagram Download│ │ VK Downloader │ │ Service │ │ Service │ │ Service │ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │ ┌──────────────┐│ │ │ Flask API │ │ │ │ Flask API │ │ │ │ Flask API ││ │ └──────────────┘ │ │ └──────────────┘ │ │ └──────────────┘│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │ ┌──────────────┐│ │ │ yt-dlp │ │ │ │ yt-dlp │ │ │ │ yt-dlp ││ │ │ (YouTube) │ │ │ │ (Instagram) │ │ │ │ (VK only) ││ │ └──────────────┘ │ │ └──────────────┘ │ │ └──────────────┘│ │ Port: 5557 │ │ Port: 5556 │ │ Port: 5555 │ └──────────────────┘ └──────────────────┘ └──────────────────┘ ``` ## Компоненты системы ### 1. Основной бот (bot.py) **Расположение:** Корень проекта **Технологии:** - `python-telegram-bot` (v20.7) — асинхронный фреймворк для Telegram Bot API - `httpx` — асинхронный HTTP клиент для запросов к сервисам загрузчиков - `sqlite3` — база данных для хранения статистики **Архитектурные решения:** #### Обработка сообщений - Асинхронная обработка через `asyncio` - Каждый пользовательский запрос обрабатывается независимой корутиной - Параллельная обработка нескольких запросов - Автоматическое извлечение URL из текста сообщений (работа в группах) #### Скачивание видео - **Все источники**: HTTP запросы к соответствующим микросервисам через `httpx` - **YouTube**: `POST http://youtube-downloader:5000/download/stream` - **Instagram**: `POST http://instagram-downloader:5000/download/stream` - **VK**: `POST http://vk-downloader:5000/download/stream` - Получение бинарных данных и сохранение во временный файл - Отправка через Telegram API #### Хранение видео - Все скачанные видео сохраняются в папке `video/` на хосте - Файлы не удаляются автоматически (сохраняются для пользователей) - Автоматическая очистка только `.part` файлов (недокачанные) #### База данных - SQLite с двумя таблицами: - `users` — информация о пользователях (chat_id, username, first_name, first_seen, last_seen) - `stats` — статистика (total_downloads) - Инициализация при запуске через `init_database()` - Файл базы: `data/bot.db` #### Обработка ошибок - Retry механизм для всех источников (3 попытки по умолчанию) - Логирование всех ошибок - Информативные сообщения пользователю - Автоматическая очистка `.part` файлов при ошибках ### 2. YouTube Downloader Service **Расположение:** `youtube-downloader/` **Технологии:** - Flask — веб-фреймворк для REST API - `yt-dlp` — библиотека для скачивания видео с YouTube - Flask-CORS — для поддержки CORS **API Endpoints:** 1. `GET /health` — проверка работоспособности сервиса - Возвращает: `{"status": "ok", "service": "youtube-downloader"}` 2. `POST /download/stream` — скачивание видео - Request: `{"url": "https://youtube.com/watch?v=..."}` - Response: Бинарные данные видео (200 OK) или JSON с ошибкой (400/500) **Особенности:** - Использует специальные настройки yt-dlp для YouTube (player_client, headers) - Поддержка различных форматов видео (mp4, webm, mkv) - Временные файлы сохраняются в `downloads/` и удаляются после отправки **Порт:** 5557 (внешний) → 5000 (внутренний) ### 3. Instagram Downloader Service **Расположение:** `instagram-downloader/` **Технологии:** - Flask — веб-фреймворк для REST API - `yt-dlp` — библиотека для скачивания видео с Instagram - Flask-CORS — для поддержки CORS **API Endpoints:** 1. `GET /health` — проверка работоспособности сервиса - Возвращает: `{"status": "ok", "service": "instagram-downloader"}` 2. `POST /download/stream` — скачивание видео - Request: `{"url": "https://instagram.com/p/..."}` - Response: Бинарные данные видео (200 OK) или JSON с ошибкой (400/500) **Особенности:** - Требует файл с cookies Instagram (`instagram_cookies.txt` в папке сервиса) - Автоматическая проверка срока действия cookies - Поддержка CSRF токенов и session cookies - Скрипты для получения/обновления cookies в папке сервиса **Порт:** 5556 (внешний) → 5000 (внутренний) ### 4. VK Downloader Service **Расположение:** `vk-downloader/` **Технологии:** - Flask — веб-фреймворк для REST API - `yt-dlp` — библиотека для скачивания видео с VK - Flask-CORS — для поддержки CORS **API Endpoints:** 1. `GET /health` — проверка работоспособности сервиса - Возвращает: `{"status": "ok", "service": "vk-downloader"}` 2. `POST /download/stream` — скачивание видео - Request: `{"url": "https://vk.com/clip-..."}` - Response: Бинарные данные видео (200 OK) или JSON с ошибкой (400/500) **Особенности:** - Специальные заголовки для VK (User-Agent, Referer) - Обработка кириллицы в именах файлов - Временные файлы сохраняются в `downloads/` и удаляются после отправки **Порт:** 5555 (внешний) → 5000 (внутренний) ### 5. Определение источника видео Функция `detect_video_source(url)` анализирует домен URL: ```python - youtube.com / youtu.be → 'youtube' - instagram.com → 'instagram' - vk.com / vkontakte.ru → 'vk' - иначе → 'unknown' ``` ### 6. Потоки данных #### Общий поток скачивания ``` User → Bot → extract_urls_from_text() → detect_video_source() ↓ HTTP POST /download/stream → [YouTube/Instagram/VK] Service ↓ yt-dlp → video file → HTTP Response (binary) ↓ Bot receives binary → saves to video/ → Telegram API → User ``` #### Детальный поток для каждого источника **YouTube:** ``` User → Bot → download_youtube_video() ↓ httpx.AsyncClient → POST http://youtube-downloader:5000/download/stream ↓ YouTube Service → yt-dlp → binary data ↓ Bot saves to video/ → sends to User ``` **Instagram:** ``` User → Bot → download_instagram_video() ↓ httpx.AsyncClient → POST http://instagram-downloader:5000/download/stream ↓ Instagram Service → yt-dlp (with cookies) → binary data ↓ Bot saves to video/ → sends to User ``` **VK:** ``` User → Bot → download_vk_video() ↓ httpx.AsyncClient → POST http://vk-downloader:5000/download/stream ↓ VK Service → yt-dlp → binary data ↓ Bot saves to video/ → sends to User ``` ### 7. База данных **Схема:** ```sql CREATE TABLE users ( chat_id INTEGER PRIMARY KEY, username TEXT, first_name TEXT, first_seen TEXT NOT NULL, last_seen TEXT NOT NULL ); CREATE TABLE stats ( id INTEGER PRIMARY KEY CHECK (id = 1), total_downloads INTEGER DEFAULT 0 ); ``` **Операции:** - `add_user()` — добавление/обновление пользователя (при каждом взаимодействии) - `get_total_users()` — получение количества уникальных пользователей - `increment_downloads()` — увеличение счетчика скачанных видео - `get_total_downloads()` — получение количества скачанных видео **Персистентность:** - База хранится в `data/bot.db` на хосте - Монтируется как volume в Docker - Сохраняется между перезапусками контейнера ## Docker архитектура ### Основной бот **Расположение:** Корень проекта **Образ:** - Базовый: `python:3.11-slim` - Python пакеты из `requirements.txt` (python-telegram-bot, httpx) **Volumes:** - `./video:/app/video` — сохраненные видео (не удаляются) - `./data:/app/data:Z` — база данных (SELinux relabel) **Network:** - `network_mode: host` — для доступа к сервисам по localhost или IP **Запуск:** ```bash docker compose up -d ``` ### YouTube Downloader Service **Расположение:** `youtube-downloader/` **Образ:** - Базовый: `python:3.11-slim` - Зависимости: `ffmpeg`, `wget` - Python пакеты: Flask, flask-cors, yt-dlp **Volumes:** - `./downloads:/app/downloads` — временные файлы **Ports:** - `5557:5000` — внешний порт 5557, внутренний 5000 **Запуск:** ```bash cd youtube-downloader && docker compose up -d ``` ### Instagram Downloader Service **Расположение:** `instagram-downloader/` **Образ:** - Базовый: `python:3.11-slim` - Зависимости: `ffmpeg`, `wget` - Python пакеты: Flask, flask-cors, yt-dlp **Volumes:** - `./downloads:/app/downloads` — временные файлы - `./instagram_cookies.txt:/app/instagram_cookies.txt:ro` — cookies (read-only) **Environment:** - `INSTAGRAM_COOKIES_FILE=/app/instagram_cookies.txt` **Ports:** - `5556:5000` — внешний порт 5556, внутренний 5000 **Запуск:** ```bash cd instagram-downloader && docker compose up -d ``` ### VK Downloader Service **Расположение:** `vk-downloader/` **Образ:** - Базовый: `python:3.11-slim` - Зависимости: `ffmpeg`, `wget` - Python пакеты: Flask, flask-cors, yt-dlp, requests **Volumes:** - `./downloads:/app/downloads` — временные файлы **Ports:** - `5555:5000` — внешний порт 5555, внутренний 5000 **Запуск:** ```bash cd vk-downloader && docker compose up -d ``` ## Безопасность ### Переменные окружения - Токен бота хранится в `.env` (не коммитится в Git) - Cookies для Instagram хранятся в файле `instagram-downloader/instagram_cookies.txt` (не коммитится) - URL сервисов настраиваются через `.env` ### Ограничения доступа - Сервисы загрузчиков доступны только по указанным IP/URL - Нет аутентификации между ботом и сервисами (можно добавить API key) - Cookies файл монтируется read-only ### Файловая система - Видео сохраняются в `video/` и не удаляются автоматически - Временные файлы в сервисах удаляются после отправки - Автоматическая очистка только `.part` файлов ## Масштабирование ### Текущие ограничения 1. **Основной бот:** - Один экземпляр (можно запустить несколько с разными токенами) - Параллельная обработка запросов через asyncio - Ограничения: ресурсы CPU/сети 2. **Сервисы загрузчиков:** - Flask dev server — последовательная обработка - Один экземпляр контейнера каждого сервиса - Можно масштабировать горизонтально ### Рекомендации для масштабирования 1. **Сервисы загрузчиков:** - Использовать Gunicorn с несколькими worker'ами: ```bash gunicorn -w 4 -b 0.0.0.0:5000 app:app ``` - Горизонтальное масштабирование: несколько контейнеров за nginx/HAProxy - Load balancing для распределения нагрузки 2. **Основной бот:** - Webhook режим вместо polling (для больших нагрузок) - Кеширование информации о видео - Очередь задач (Celery) для скачивания 3. **База данных:** - Миграция на PostgreSQL для многопользовательской нагрузки - Connection pooling ## Мониторинг ### Логирование - Все компоненты логируют в stdout/stderr - Docker автоматически собирает логи - Уровни: INFO, WARNING, ERROR ### Метрики (можно добавить) - Количество запросов в секунду - Время обработки запроса - Количество ошибок - Размер скачанных файлов ### Health checks - Все сервисы: `GET /health` - Основной бот: проверка через статус контейнера ## Производительность ### Оптимизации 1. **Асинхронная обработка:** - Основной бот использует asyncio для неблокирующих операций - HTTP запросы к сервисам через httpx (асинхронный) 2. **Хранение видео:** - Видео сохраняются на хосте (volume), не в образе контейнера - Файлы доступны для пользователей после скачивания 3. **Кеширование:** - Можно добавить кеш информации о видео (title, duration) - Кеш для часто запрашиваемых видео ### Узкие места 1. **Сервисы загрузчиков:** - Последовательная обработка запросов (Flask dev server) - Скачивание файла перед отправкой (занимает память) 2. **Сеть:** - Зависимость от скорости интернета - Задержки при обращении к внешним сервисам - Задержки между ботом и сервисами загрузчиков ## Развертывание ### Локальная разработка ```bash # Запуск сервисов загрузчиков (каждый в своей папке) cd youtube-downloader && docker compose up -d cd ../instagram-downloader && docker compose up -d cd ../vk-downloader && docker compose up -d # Запуск основного бота (из корня проекта) cd .. docker compose up -d ``` ### Продакшен (раздельное развертывание) **Хост 1 (с VPN для YouTube/Instagram):** - Основной бот - YouTube сервис (порт 5557) - Instagram сервис (порт 5556) - VPN для доступа к YouTube/Instagram - `.env`: - `YOUTUBE_DOWNLOADER_URL=http://localhost:5557` - `INSTAGRAM_DOWNLOADER_URL=http://localhost:5556` - `VK_DOWNLOADER_URL=http://:5555` **Хост 2 (без VPN для VK):** - VK Downloader Service (порт 5555) - Доступен по IP для хоста 1 - Можно масштабировать горизонтально ### CI/CD (опционально) 1. Автоматический build Docker образов 2. Тестирование перед деплоем 3. Автоматический деплой при коммите в main ## Будущие улучшения 1. **Аутентификация между сервисами:** - API key для сервисов загрузчиков - JWT токены 2. **Очередь задач:** - Celery/RQ для фоновой обработки - Retry механизм через очередь 3. **Мониторинг:** - Prometheus метрики - Grafana дашборды 4. **Улучшение сервисов:** - Переход на FastAPI (более производительный) - Поддержка WebSockets для прогресса - Stream ответа вместо полной загрузки в память 5. **Хранение видео:** - Организация по датам/пользователям - Автоматическая очистка старых файлов (опционально) - Интеграция с облачным хранилищем