diff --git a/.gitignore b/.gitignore index 16be8f2..97f787e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +.idea /output/ +/state/ diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..a7cd719 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,658 @@ +# Manga Downloader — Архитектура и устройство проекта + +## Содержание + +1. [Общее описание](#1-общее-описание) +2. [Структура файлов](#2-структура-файлов) +3. [Стек технологий](#3-стек-технологий) +4. [Схема архитектуры](#4-схема-архитектуры) +5. [Модули бэкенда](#5-модули-бэкенда) + - [browser.py](#browserpy) + - [scraper.py](#scraperpy) + - [exporter.py](#exporterpy) + - [state.py](#statepy) + - [worker.py](#workerpy) + - [api.py](#apipy) + - [cli.py](#clipy) +6. [База данных](#6-база-данных) +7. [REST API](#7-rest-api) +8. [WebSocket протокол](#8-websocket-протокол) +9. [Фронтенд](#9-фронтенд) +10. [Жизненный цикл загрузки манги](#10-жизненный-цикл-загрузки-манги) +11. [Параллельная загрузка](#11-параллельная-загрузка) +12. [Конфигурация](#12-конфигурация) +13. [Docker-инфраструктура](#13-docker-инфраструктура) + +--- + +## 1. Общее описание + +Приложение скачивает мангу с сайтов типа readmanga.ru, обходя JS-защиту (DDoS-Guard, антибот) с помощью управляемого браузера Chromium. Поддерживает два режима работы: + +- **Веб-интерфейс** — FastAPI-сервер + SPA на чистом JS (порт 8000). Позволяет управлять загрузками через браузер с realtime-прогрессом через WebSocket. +- **CLI** — консольные команды `download` и `analyze` для запуска через `docker compose run`. + +--- + +## 2. Структура файлов + +``` +manga/ +├── src/ # Весь бэкенд-код (Python-пакет) +│ ├── __init__.py +│ ├── api.py # FastAPI-приложение, REST + WebSocket +│ ├── browser.py # Обёртка над Playwright/Chromium +│ ├── cli.py # CLI-команды (click) +│ ├── downloader.py # (legacy, не используется в web-режиме) +│ ├── exporter.py # Экспорт CBZ / PDF / EPUB +│ ├── scraper.py # Парсер страниц readmanga.ru +│ ├── state.py # SQLite ORM (StateDB) +│ └── worker.py # Асинхронный воркер загрузки +│ +├── frontend/ +│ └── index.html # SPA — весь фронтенд в одном файле +│ +├── output/ # Смонтированная папка с CBZ/PDF/EPUB +│ └── <Название манги>/ +│ ├── v01_ch0001.0.cbz +│ └── ... +│ +├── state/ # Смонтированная папка с состоянием +│ ├── progress.db # SQLite база данных +│ └── manga.log # Логи (ротация по 10 МБ) +│ +├── Dockerfile # Сборка образа +├── docker-compose.yml # Конфигурация сервисов +├── requirements.txt # Python-зависимости +├── debug_site.py # Утилита отладки (скриншот страницы) +├── debug_cdn.py # Утилита отладки CDN-запросов +├── analyze_speed.py # Анализ скорости загрузки +├── README.md # Краткое руководство пользователя +└── ARCHITECTURE.md # Этот файл +``` + +--- + +## 3. Стек технологий + +| Компонент | Библиотека | Назначение | +|-----------|------------|------------| +| Браузер | `playwright==1.44.0` (Chromium) | Открытие защищённых JS-страниц | +| Web-фреймворк | `fastapi==0.111.0` + `uvicorn` | REST API и WebSocket | +| БД | SQLite (stdlib `sqlite3`) | Хранение состояния | +| CLI | `click==8.1.7` | Консольные команды | +| Изображения | `Pillow==10.3.0` | Открытие/конвертация для PDF | +| PDF | `img2pdf==0.5.1` (fallback: Pillow) | Склейка изображений в PDF | +| EPUB | `ebooklib==0.18` | Сборка EPUB3-файла | +| Логирование | `loguru==0.7.2` | Удобные форматированные логи | +| Фронтенд | Tailwind CSS (CDN) + Vanilla JS | SPA без сборщика | + +--- + +## 4. Схема архитектуры + +``` +Браузер пользователя + │ + │ HTTP / WebSocket (:8000) + ▼ +┌─────────────────────────────────┐ +│ FastAPI (api.py) │ +│ │ +│ REST endpoints WebSocket /ws │ +│ │ │ │ +│ asyncio.Queue ws_manager │ +│ │ (broadcast) │ +│ ▼ ▲ │ +│ queue_worker() │ │ +│ │ events │ +│ ▼ │ │ +│ download_manga() ────┘ │ ◄── worker.py +│ │ │ +└───────┼─────────────────────────┘ + │ + ├─► BrowserManager (browser.py) + │ └─► Playwright Chromium + │ │ + │ ┌───────────┴──────────┐ + │ ▼ ▼ + │ get_manga_info() get_chapter_images_and_download() + │ (scraper.py) (scraper.py) + │ + ├─► export() (exporter.py) → CBZ / PDF / EPUB + │ + └─► StateDB (state.py) → progress.db +``` + +--- + +## 5. Модули бэкенда + +### browser.py + +**Отвечает за:** запуск и управление Playwright Chromium. + +**Ключевые детали:** + +- `BrowserManager` — контекстный менеджер (`async with BrowserManager() as bm`), запускает/останавливает браузер. +- `new_page()` — создаёт новый `BrowserContext` + `Page`. Каждый контекст независим (отдельные куки, заголовки). +- Браузер запускается с антидетект-настройками: + - `--disable-blink-features=AutomationControlled` + - JavaScript-патч `STEALTH_JS`: скрывает `navigator.webdriver`, подставляет плагины и языки. + - Реалистичный `User-Agent` (Chrome 124 Linux). + - Заголовки `Accept-Language: ru-RU`, `Referer: https://3.readmanga.ru/` — сервер возвращает 404 без Referer. + - `shm_size: 2gb` в Docker — Chromium требует shared memory для рендеринга. + +--- + +### scraper.py + +**Отвечает за:** парсинг страниц манги и скачивание изображений глав. + +#### Модели данных + +```python +@dataclass +class Chapter: + title: str # "Том 1, Глава 5" + url: str # полный URL главы + number: float # 5.0 (из data-num / 10) + volume: int # 1 + +@dataclass +class MangaInfo: + title: str # русский тайтл (для имени папки) + url: str + chapters: list[Chapter] + pub_status: str # "completed" / "ongoing" / "unknown" + title_ru: str # чистый русский тайтл + title_full: str # полный тайтл со страницы +``` + +#### `get_manga_info(page, url)` + +1. Открывает страницу манги через `_navigate()` (3 попытки, задержка 3×N сек). +2. Извлекает тайтл: сначала из DOM (`.names .name`), fallback — парсинг `