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

22 KiB
Raw Blame History

Архитектура системы

Документ описывает внутреннюю архитектуру и принципы работы 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:

- 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. База данных

Схема:

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

Запуск:

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

Запуск:

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

Запуск:

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

Запуск:

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'ами:
      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. Сеть:

    • Зависимость от скорости интернета
    • Задержки при обращении к внешним сервисам
    • Задержки между ботом и сервисами загрузчиков

Развертывание

Локальная разработка

# Запуск сервисов загрузчиков (каждый в своей папке)
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. Хранение видео:

    • Организация по датам/пользователям
    • Автоматическая очистка старых файлов (опционально)
    • Интеграция с облачным хранилищем