videoDownloadTGbot/ARCHITECTURE.md
vrubelroman 436e0cd541 Рефакторинг: микросервисная архитектура
- Разделение на микросервисы: youtube-downloader, instagram-downloader, vk-downloader
- Основной бот в корне проекта, работает через HTTP API с сервисами
- Каждый сервис запускается отдельно в своей папке
- Видео сохраняются в папке video/ и не удаляются
- Обновлена документация и архитектура
- Скрипты для Instagram cookies перенесены в instagram-downloader/
2025-12-11 01:07:04 +03:00

514 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Архитектура системы
Документ описывает внутреннюю архитектуру и принципы работы 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://<host2_ip>: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. **Хранение видео:**
- Организация по датам/пользователям
- Автоматическая очистка старых файлов (опционально)
- Интеграция с облачным хранилищем