diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 67cd76a..c3abcb6 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -84,6 +84,7 @@ manga/ | Изображения | `Pillow==10.3.0` | Открытие/конвертация для PDF | | PDF | `img2pdf==0.5.1` (fallback: Pillow) | Склейка изображений в PDF | | EPUB | `ebooklib==0.18` | Сборка EPUB3-файла | +| Расписание | `croniter==3.0.3` | Парсинг cron-выражений для планировщика | | Логирование | `loguru==0.7.2` | Удобные форматированные логи | | Фронтенд | Tailwind CSS (CDN) + Vanilla JS | SPA без сборщика | @@ -368,9 +369,11 @@ ws_manager: ConnectionManager # set активных WebSocket-соедине #### `update_scheduler()` -Через 5 минут после старта, затем каждые `UPDATE_INTERVAL_HOURS` (по умолчанию 6 ч): -- Вызывает `check_for_updates()` для каждой манги с `auto_update=1`. -- При нахождении новых глав — добавляет задачу в очередь с флагом `is_update=True`. +Через 5 минут после старта, затем по расписанию `UPDATE_SCHEDULE` (cron-синтаксис): +- Читает расписание через `_parse_schedule()`: приоритет `UPDATE_SCHEDULE` (cron-строка) → `UPDATE_INTERVAL_HOURS` (legacy, число часов → конвертируется в cron автоматически). Если обе переменные пусты — планировщик не запускается. +- Вычисляет время до следующего слота через `croniter.get_next()` и спит ровно до него. +- Запускает `_run_auto_updates_with_retry()` — обёртка с **тремя попытками**: при ошибке ждёт 5 минут и повторяет; после трёх неудач логирует и ждёт следующего слота. Цикл **никогда не прерывается**. +- `_run_auto_updates()` — сама логика: вызывает `check_for_updates()` для каждой манги с `auto_update=1`, ставит новые главы в очередь. #### `_enrich_manga(m, db)` @@ -546,3 +549,82 @@ DOMContentLoaded ### Позиции в очереди Отображаются на карточке как «Позиция в очереди: N». Обновляются в реальном времени через событие `queue_positions` (не перерендер всего списка, а точечное обновление через `updateMangaRow`). Событие рассылается сервером при каждом изменении состояния очереди. + +--- + +## 12. Конфигурация + +### Переменные окружения + +| Переменная | Default | Описание | +|------------|---------|---------| +| `CHAPTER_CONCURRENCY` | `3` | Кол-во глав, загружаемых параллельно | +| `UPDATE_SCHEDULE` | — | Расписание авто-проверки (cron-синтаксис). Пример: `0 */6 * * *`. Если пусто — планировщик отключён | +| `UPDATE_INTERVAL_HOURS` | — | Устаревший аналог `UPDATE_SCHEDULE`: число часов → конвертируется в cron автоматически | +| `AUTH_LOGIN` / `AUTH_PASSWORD` | — | Логин и пароль для веб-интерфейса. Если оба заданы — включается авторизация | +| `PYTHONUNBUFFERED` | `1` | Немедленный вывод логов (Docker) | + +### Пути (hardcoded в коде) + +| Константа | Путь | +|-----------|------| +| `OUTPUT_DIR` | `/app/output` | +| `FRONTEND_DIR` | `/app/frontend` | +| `DB_PATH` | `/app/state/progress.db` | +| Лог | `/app/state/manga.log` (ротация 10 МБ) | + +--- + +## 13. Docker-инфраструктура + +### Dockerfile + +``` +FROM mcr.microsoft.com/playwright/python:v1.44.0-jammy + └── Ubuntu 22.04 + Python + все системные зависимости для Chromium + +RUN pip install -r requirements.txt +RUN playwright install chromium --with-deps + +CMD uvicorn src.api:app --host 0.0.0.0 --port 8000 +``` + +### docker-compose.yml + +```yaml +volumes: + - ./output:/app/output # CBZ/PDF/EPUB файлы + - ./state:/app/state # БД и логи + +ports: + - "8000:8000" # Веб-интерфейс + +shm_size: "2gb" # Chromium требует shared memory +environment: + - UPDATE_SCHEDULE=0 */6 * * * # каждые 6 часов (cron) + - AUTH_LOGIN=... + - AUTH_PASSWORD=... + +restart: unless-stopped # Автоперезапуск при падении +``` + +### CLI-режим (через compose run) + +```bash +# Скачать мангу без веб-интерфейса +docker compose run --rm --entrypoint "" manga \ + python -m src.cli download https://3.readmanga.ru/magicheskaia_bitva --format cbz + +# Анализ +docker compose run --rm --entrypoint "" manga \ + python -m src.cli analyze https://3.readmanga.ru/magicheskaia_bitva +``` + +### Хранение данных + +После остановки контейнера все данные сохраняются на хосте: +- `./output/` — скачанные файлы. +- `./state/progress.db` — состояние БД (что скачано, что в очереди). +- `./state/manga.log` — логи. + +При следующем запуске `startup_event` восстанавливает незавершённые задачи из БД в очередь. diff --git a/README.md b/README.md index 1690ed2..f853092 100644 --- a/README.md +++ b/README.md @@ -103,12 +103,37 @@ output/ --- +## Авторизация + +Задайте в `docker-compose.yml`: + +```yaml +- AUTH_LOGIN=ваш_логин +- AUTH_PASSWORD=ваш_пароль +``` + +Если оба параметра заданы — интерфейс будет защищён формой входа. Сессия сохраняется в браузере на 30 дней, повторный вход не требуется. + +--- + ## Конфигурация (docker-compose.yml) | Переменная | Default | Описание | |------------|---------|---------| | `CHAPTER_CONCURRENCY` | `3` | Глав загружается параллельно | -| `UPDATE_INTERVAL_HOURS` | `6` | Интервал авто-проверки новых глав (часы) | +| `UPDATE_SCHEDULE` | — | Расписание авто-проверки новых глав (cron-синтаксис). Если пусто — отключено | +| `UPDATE_INTERVAL_HOURS` | — | Устаревший формат: число часов (конвертируется в cron автоматически) | +| `AUTH_LOGIN` / `AUTH_PASSWORD` | — | Логин и пароль для веб-интерфейса | + +### Примеры расписания (`UPDATE_SCHEDULE`) + +``` +0 */6 * * * — каждые 6 часов +0 3 * * * — каждый день в 03:00 UTC +0 3 * * MON — каждый понедельник в 03:00 +*/30 * * * * — каждые 30 минут + — (пусто) — планировщик отключён +``` --- diff --git a/docker-compose.yml b/docker-compose.yml index 34ac73b..7b5a448 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,14 @@ services: - ./state:/app/state environment: - PYTHONUNBUFFERED=1 - - UPDATE_INTERVAL_HOURS=6 + # Расписание авто-проверки новых глав (cron-синтаксис). + # Примеры: "0 */6 * * *" — каждые 6 ч | "0 3 * * *" — каждый день в 03:00 + # Оставьте пустым чтобы отключить планировщик. + # Устаревший формат UPDATE_INTERVAL_HOURS=6 тоже поддерживается. + - UPDATE_SCHEDULE=0 */6 * * * + # Авторизация (оба параметра должны быть заданы чтобы включить защиту) + - AUTH_LOGIN=StenFredd + - AUTH_PASSWORD=111111 ports: - "8000:8000" shm_size: "2gb" diff --git a/frontend/index.html b/frontend/index.html index f19c438..1a80227 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -50,22 +50,53 @@ .pulse-dot { width:8px; height:8px; border-radius:50%; background:#3b82f6; animation:pulse 1.5s infinite; } @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.3} } ::-webkit-scrollbar { width:6px; } ::-webkit-scrollbar-track { background:#0f1117; } ::-webkit-scrollbar-thumb { background:#2d3148; border-radius:3px; } + /* Login screen */ + #login-screen { position:fixed; inset:0; z-index:9999; background:#0f1117; display:flex; align-items:center; justify-content:center; } + #login-screen.hidden { display:none; } + .login-card { background:#1a1d2e; border:1px solid #2d3148; border-radius:16px; padding:40px; width:100%; max-width:380px; }
+ +