14 KiB
14 KiB
Архитектура системы
Документ описывает внутреннюю архитектуру и принципы работы Telegram Video Download Bot.
Общая архитектура
Система состоит из двух основных компонентов:
- Основной бот (
bot.py) — Telegram бот, обрабатывающий запросы пользователей - VK Downloader Service (
vk-downloader/) — отдельный микросервис для скачивания видео с VK
┌─────────────────┐
│ Telegram User │
└────────┬────────┘
│
▼
┌─────────────────────────────────────┐
│ Основной бот (bot.py) │
│ ┌───────────────────────────────┐ │
│ │ YouTube Download Handler │ │
│ └───────────────────────────────┘ │
│ ┌───────────────────────────────┐ │
│ │ Instagram Download Handler │ │
│ └───────────────────────────────┘ │
│ ┌───────────────────────────────┐ │
│ │ VK API Client │──┼──┐
│ └───────────────────────────────┘ │ │
│ ┌───────────────────────────────┐ │ │
│ │ SQLite Database │ │ │
│ │ - Users │ │ │
│ │ - Stats │ │ │
│ └───────────────────────────────┘ │ │
└─────────────────────────────────────┘ │
│ HTTP API
│ POST /download/stream
▼
┌──────────────────────┐
│ VK Downloader │
│ Service │
│ ┌────────────────┐ │
│ │ Flask API │ │
│ └────────────────┘ │
│ ┌────────────────┐ │
│ │ yt-dlp │ │
│ │ (VK only) │ │
│ └────────────────┘ │
└──────────────────────┘
Компоненты системы
1. Основной бот (bot.py)
Технологии:
python-telegram-bot(v20.7) — асинхронный фреймворк для Telegram Bot APIyt-dlp— библиотека для скачивания видеоhttpx— асинхронный HTTP клиент для запросов к VK сервисуsqlite3— база данных для хранения статистики
Архитектурные решения:
Обработка сообщений
- Асинхронная обработка через
asyncio - Каждый пользовательский запрос обрабатывается независимой корутиной
- Параллельная обработка нескольких запросов
Скачивание видео
- YouTube/Instagram: Прямое скачивание через
yt-dlpв executor (не блокирует event loop) - VK: HTTP запрос к внешнему микросервису через
httpx
База данных
- SQLite с двумя таблицами:
users— информация о пользователях (chat_id, username, first_name, first_seen, last_seen)stats— статистика (total_downloads)
- Инициализация при запуске через
init_database() - Файл базы:
data/bot.db
Обработка ошибок
- Retry механизм для всех источников (3 попытки по умолчанию)
- Логирование всех ошибок
- Информативные сообщения пользователю
2. VK Downloader Service
Технологии:
- Flask — веб-фреймворк для REST API
yt-dlp— библиотека для скачивания видео с VK- Flask-CORS — для поддержки CORS (если нужно)
API Endpoints:
-
GET /health— проверка работоспособности сервиса- Возвращает:
{"status": "ok", "service": "vk-downloader"}
- Возвращает:
-
POST /download/stream— скачивание видео- Request:
{"url": "https://vk.com/clip-..."} - Response: Бинарные данные видео (200 OK) или JSON с ошибкой (400/500)
- Request:
Особенности реализации:
Обработка кириллицы
- Имена файлов с кириллицей конвертируются в ASCII для HTTP заголовков
- Оригинальное имя сохраняется в файловой системе
Управление файлами
- Временные файлы сохраняются в
downloads/ - Файлы удаляются после отправки клиенту
- Использование UUID для уникальности имен
Ограничения
- Flask dev server (однопоточный) — обрабатывает запросы последовательно
- Для продакшена рекомендуется использовать Gunicorn с несколькими worker'ами
3. Определение источника видео
Функция detect_video_source(url) анализирует домен URL:
- youtube.com / youtu.be → 'youtube'
- instagram.com → 'instagram'
- vk.com / vkontakte.ru → 'vk'
- иначе → 'unknown'
4. Потоки данных
Скачивание с YouTube/Instagram
User → Bot → detect_video_source() → download_youtube_video() / download_instagram_video()
↓
yt-dlp (executor) → video file → Telegram API → User
Скачивание с VK
User → Bot → detect_video_source() → download_vk_video()
↓
HTTP POST /download/stream → VK Service
↓
yt-dlp → video file → HTTP Response (binary)
↓
Bot receives binary → saves to disk → Telegram API → User
5. База данных
Схема:
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 - Зависимости:
ffmpeg,wget - Python пакеты из
requirements.txt
Volumes:
./video:/app/video— временные файлы видео./instagram_cookies.txt:/app/instagram_cookies.txt— cookies для Instagram./data:/app/data:Z— база данных (SELinux relabel)
Network:
network_mode: host— для доступа к VK сервису через localhost
VK Downloader Service
Образ:
- Базовый:
python:3.11-slim - Зависимости:
ffmpeg,wget - Python пакеты: Flask, flask-cors, yt-dlp, requests
Volumes:
./downloads:/app/downloads— временные файлы
Ports:
5555:5000— внешний порт 5555, внутренний 5000
Network:
- Отдельная сеть
vk_network(можно использовать host network для доступа)
Безопасность
Переменные окружения
- Токен бота хранится в
.env(не коммитится в Git) - Cookies для Instagram хранятся в файле (не коммитится)
Ограничения доступа
- VK сервис доступен только по указанному IP/URL
- Нет аутентификации между ботом и VK сервисом (можно добавить API key)
Файловая система
- Временные файлы удаляются после отправки
- Cookies файл монтируется read-only (опционально)
Масштабирование
Текущие ограничения
-
Основной бот:
- Один экземпляр (можно запустить несколько с разными токенами)
- Параллельная обработка запросов ограничена ресурсами CPU/сети
-
VK сервис:
- Flask dev server — последовательная обработка
- Один экземпляр контейнера
Рекомендации для масштабирования
-
VK сервис:
- Использовать Gunicorn с несколькими worker'ами:
gunicorn -w 4 -b 0.0.0.0:5000 app:app - Горизонтальное масштабирование: несколько контейнеров за nginx/HAProxy
- Load balancing для распределения нагрузки
- Использовать Gunicorn с несколькими worker'ами:
-
Основной бот:
- Webhook режим вместо polling (для больших нагрузок)
- Кеширование информации о видео
- Очередь задач (Celery) для скачивания
-
База данных:
- Миграция на PostgreSQL для многопользовательской нагрузки
- Connection pooling
Мониторинг
Логирование
- Все компоненты логируют в stdout/stderr
- Docker автоматически собирает логи
- Уровни: INFO, WARNING, ERROR
Метрики (можно добавить)
- Количество запросов в секунду
- Время обработки запроса
- Количество ошибок
- Размер скачанных файлов
Health checks
- VK сервис:
GET /health - Основной бот: проверка через статус контейнера
Производительность
Оптимизации
-
Асинхронная обработка:
- Основной бот использует asyncio для неблокирующих операций
- yt-dlp запускается в executor для YouTube/Instagram
-
Временные файлы:
- Хранение в памяти (tmpfs) для быстрого доступа (опционально)
- Автоматическая очистка после отправки
-
Кеширование:
- Можно добавить кеш информации о видео (title, duration)
- Кеш для часто запрашиваемых видео
Узкие места
-
VK сервис:
- Последовательная обработка запросов
- Скачивание файла перед отправкой (занимает память)
-
Сеть:
- Зависимость от скорости интернета
- Задержки при обращении к внешнему VK сервису
Развертывание
Локальная разработка
# Основной бот
docker compose up -d
# VK сервис
cd vk-downloader && docker compose up -d
Продакшен (раздельное развертывание)
Хост 1 (с VPN):
- Основной бот
- VPN для доступа к YouTube/Instagram
.env:VK_DOWNLOADER_URL=http://<host2_ip>:5555
Хост 2 (без VPN):
- VK Downloader Service
- Доступен по IP для хоста 1
- Можно масштабировать горизонтально
CI/CD (опционально)
- Автоматический build Docker образов
- Тестирование перед деплоем
- Автоматический деплой при коммите в main
Будущие улучшения
-
Аутентификация между сервисами:
- API key для VK сервиса
- JWT токены
-
Очередь задач:
- Celery/RQ для фоновой обработки
- Retry механизм через очередь
-
Мониторинг:
- Prometheus метрики
- Grafana дашборды
-
Улучшение VK сервиса:
- Переход на FastAPI (более производительный)
- Поддержка WebSockets для прогресса
- Stream ответа вместо полной загрузки в память