# RedAirsoft VK to Telegram & MAX Messenger Poster Автоматизированный Docker-сервис для периодического парсинга новых постов из сообщества ВКонтакте (**Red Airsoft | Страйкбол**) и их одновременной публикации в **Telegram** и мессенджер **МАКС** (MAX Messenger) с отчётами администраторам. --- ## 📌 Инфраструктура и Деплой **Актуальный способ деплоя — Coolify**, автодеплой по пушу в `gitea/main`. Старый ручной способ (checkout в `/opt/redairsoft_poster/` + `docker-compose` руками через Proxmox, описанный ниже архивно) больше не используется — тот контейнер (`redairsoft-vk-poster`) был удалён 2026-08-15 как заброшенный. | Параметр | Значение | |---|---| | **Деплой** | Coolify, приложение "RedAirsoft Poster", сервер `redairsoft-poster-lxc` | | **URL** | `http://hjbmqj1ohievdrebpltnzex0.192.168.1.106.sslip.io` | | **Хост контейнера** | Тот же LXC 107 (`192.168.1.106`) — Coolify управляет им напрямую, не через `/opt/redairsoft_poster/` | | **Имя Docker-контейнера** | Динамическое, вида `-`, тег образа = хэш закоммиченного коммита. Смотреть через `docker ps` — актуальный это `Up`, с тегом = последний `git log` хэш | | **Gitea Репозиторий** | `http://192.168.1.135:3000/exostring/redairsoft_vk_gt_max_sender` | | **Хост Proxmox** (для ручной диагностики) | `192.168.1.222` (root SSH через ключ `~/.ssh/id_ed25519_proxmox`) | | **Локальный Telegram Bot API** | Встроен в контейнер (`http://127.0.0.1:8081`), поддерживает загрузку видео до 2 ГБ | | **База данных** | SQLite `/app/data/poster.db` внутри контейнера (персистентный том) | ### Диагностика через SSH (read-only) ```bash # Найти актуальный контейнер (смотреть на тег образа = свежий commit hash): ssh -i ~/.ssh/id_ed25519_proxmox root@192.168.1.222 'pct exec 107 -- docker ps -a' # Логи актуального контейнера: ssh -i ~/.ssh/id_ed25519_proxmox root@192.168.1.222 'pct exec 107 -- docker logs --tail 100 <имя-контейнера>' ``` Деплой новой версии — просто `git push` в `gitea/main`, Coolify подхватывает автоматически. --- ## ⚙️ Как работает сервис 0. **Донор→рецепиент маршруты (`data/routes.json`)**: - Сервис может опрашивать сразу несколько групп ВК ("доноров"), и для каждой отдельно настроено, в какие Telegram и МАКС чаты публиковать ("рецепиенты"), плюс независимые вкл/выкл для TG и МАКС на каждом маршруте. - Список маршрутов хранится в `data/routes.json` (персистентный том, не в git). Если файла нет — при первом запуске он создаётся автоматически из старых `.env`-переменных `VK_SOURCE`/`TG_CHAT_ID`/`MAX_CHAT_ID` (один маршрут с `id: "default"`), так что апгрейд с однo-группового режима ничего не ломает. - Пример формата — [`routes.json.example`](routes.json.example) в корне репозитория. Правка `routes.json` требует перезапуска контейнера, чтобы изменения подхватились. - Маршруты в рамках одного цикла опроса обрабатываются **строго последовательно** (без параллелизма) — это защищает от флуда на VK API, загрузке медиа в Telegram/локальный Bot API и отправке в МАКС, поскольку токены ботов общие на все маршруты. 1. **Опрос стены ВКонтакте**: - Каждые 15 минут (`CHECK_INTERVAL_MINUTES`) делает запрос к методу `wall.get` для каждой группы из `routes.json`. - Фильтрует посты автора (без репостов и рекламы сторонних сообществ). 2. **Защита от спама и режим запуска (`BOOTSTRAP_MODE`)**: - Установлен режим `BOOTSTRAP_MODE=skip_existing`. - При первом запуске или перезапуске сервис запоминает текущие посты стены и **ничего не публикует**, пока в ВК не выйдет новый пост. 3. **Загрузка медиа и поддержка длинных видео**: - Картинки скачиваются в максимальном разрешении. - Видео загружается через `yt-dlp` в качестве до 720p (длительностью до 2 часов и размером до 2000 МБ). - Встроенный в контейнер локальный `telegram-bot-api` загружает тяжелые видеофайлы напрямую в Telegram без ограничений облачного API (20-50 МБ). 4. **Форматирование текста**: - Ссылки ВКонтакте вида `[club123|Название]` и `[id123|Имя]` преобразуются в корректные кликабельные HTML-ссылки. - Первый абзац / заголовок выделяется жирным шрифтом `...`. - Удаляются разделительные полосы (`━━━`, `───`) и лишние переносы строк. 5. **Публикация в мессенджер МАКС**: - Загрузка медиа в МАКС через `/uploads?type=photo` и `/uploads?type=video`. - Поллинг готовности видео (`/videos/{token}`) перед публикацией сообщения. 6. **Отчёты администраторам**: - После успешной публикации или при ошибке бот отправляет отчёт со ссылками на оригинальный пост в ВК, Telegram и МАКС в личные сообщения администраторам (`TG_ADMIN_IDS`). 7. **Очистка диска и кэша**: - Временные файлы удаляются сразу после публикации. - Фоновый воркер `cleaner.py` каждые 15 минут удаляет старые файлы из `/tmp/poster_cache`, гарантируя защиту активных скачиваний через реестр локов. --- ## 🔀 Маршруты донор→рецепиент (`data/routes.json`) Формат одного маршрута: ```json { "id": "redairsoft_main", "name": "Red Airsoft (основная группа)", "vk_source": "public36860851", "tg_chat_id": "-1001303630155", "tg_enabled": true, "max_chat_id": "123456", "max_enabled": true } ``` | Поле | Описание | |---|---| | `id` | Уникальный технический идентификатор маршрута (используется в БД и логах) | | `name` | Человекочитаемое имя для отчётов администраторам | | `vk_source` | Группа-донор ВК: screen name, URL или owner_id | | `tg_chat_id` / `max_chat_id` | Куда публиковать (chat/channel ID) | | `tg_enabled` / `max_enabled` | Переключатель — публиковать ли в эту платформу для этого маршрута (только TG, только МАКС, или оба) | Можно завести несколько маршрутов с разными `vk_source`, каждый — в свои TG/МАКС чаты. Токены ботов (`TG_BOT_TOKEN`, `MAX_BOT_TOKEN`, `VK_ACCESS_TOKEN`) общие на все маршруты — один бот пишет в разные чаты. `vk_source` принимает screen name, полный URL (`vk.com` и `vk.ru`) или `owner_id` — можно указывать как есть, без ручной нормализации. Файл — обычный JSON, но допускает построчные комментарии `// текст`, чтобы подписывать, где какой маршрут (полноценных JSON-комментариев не существует, здесь это добавлено отдельно — строка, у которой после пробелов идёт `//`, вырезается перед парсингом): ```jsonc [ // redairsoft { "id": "redairsoft", "vk_source": "public36860851", "tg_chat_id": "-1001303630155", "max_chat_id": "-69722432869632" }, // strike_expo { "id": "strike_expo", "vk_source": "https://vk.ru/strike_expo", "tg_chat_id": "-1003099077190", "max_chat_id": "-77898705339648" } ] ``` --- ## 🔑 Конфигурация (`.env`) | Переменная | Описание | |---|---| | `VK_ACCESS_TOKEN` | Сервисный токен приложения ВК (`d0a64...`), общий на все маршруты | | `ROUTES_CONFIG_PATH` | Путь к файлу маршрутов, по умолчанию `data/routes.json` | | `VK_SOURCE` / `TG_CHAT_ID` / `MAX_CHAT_ID` | Легаси fallback: используются только для авто-генерации первого маршрута, если `routes.json` ещё не существует | | `TG_BOT_TOKEN` | Токен Telegram бота (от `@BotFather`), общий на все маршруты | | `TG_MEDIA_CHANNEL_ID` | Скрытый канал-хранилище (опционально) | | `TG_ADMIN_IDS` | Telegram ID админов через запятую (например `442509142`) | | `LOCAL_BOT_API_URL` | `http://127.0.0.1:8081` (встроен в контейнер) | | `MAX_BOT_TOKEN` | Токен бота в мессенджере МАКС, общий на все маршруты | | `BOOTSTRAP_MODE` | `skip_existing` | | `CHECK_INTERVAL_MINUTES` | `15` | | `VIDEO_MAX_DURATION_SEC` | `7200` (2 часа) | | `VIDEO_MAX_SIZE_MB_LOCAL` | `2000` (2 ГБ) | --- ## 📁 Структура исходного кода ``` ├── src/ │ ├── config.py # Настройки Pydantic Settings │ ├── routes.py # Загрузка/валидация data/routes.json (донор->рецепиент маршруты) │ ├── database.py # Хранилище SQLite (посты, статусы по route_id, даты) │ ├── vk_client.py # Клиент VK API (wall.get, извлечение медиа) │ ├── media_processor.py # Загрузка фото/видео (yt-dlp, aiohttp) │ ├── text_formatter.py # Конвертер ссылок ВК, очистка текста, HTML │ ├── tg_poster.py # Отправка в Telegram (Rich Message + Local API) │ ├── max_poster.py # Отправка в MAX Messenger (Uploads + Polling) │ ├── cleaner.py # Фоновая очистка временных файлов │ ├── admin_notifier.py # Агрегированные отчёты администраторам по всем маршрутам │ └── main.py # Точка входа, цикл опроса по всем маршрутам ├── Dockerfile # Multi-stage образ: aiogram/telegram-bot-api + python:3.12-slim + ffmpeg ├── docker-compose.yml # Конфигурация запуска сервиса ├── docker-entrypoint.sh # Автозапуск локального Telegram Bot API + постера ├── requirements.txt # Python зависимости (aiogram, yt-dlp, loguru, aiohttp, pydantic) ├── routes.json.example # Пример формата data/routes.json └── .env # Переменные окружения ```