Skip to content

Repository files navigation

Discord-бот виджета Breaking Proxy

Лёгкий Python-бот, который периодически читает виджет с breaking.proxy.sqstat.ru, извлекает данные по двум карточкам (RAAS/AAS и SPEC OPS) и обновляет одно сообщение в Discord-канале.

Что делает бот

  • открывает страницу источника и дожидается появления нужных карточек;
  • извлекает онлайн и название карты для RAAS/AAS и SPEC OPS;
  • отправляет служебное сообщение один раз и дальше редактирует его;
  • показывает время последнего успешного обращения к сайту в footer embeds;
  • обновляет содержимое сразу при изменении состояния серверов;
  • поддерживает heartbeat-обновление виджета, даже если состояние не изменилось;
  • хранит message_id и последнее успешное состояние в JSON-файле;
  • пишет короткие и стабильные логи с таймингами этапов.

Что изменено в логике обновления

Текущая логика оптимизирована под меньшую нагрузку на CPU, RAM и Discord API:

  • базовая частота опроса: 30 секунд;
  • если состояние серверов изменилось — сообщение в Discord обновляется сразу;
  • если состояние не изменилось — сообщение не редактируется на каждом цикле;
  • при этом heartbeat сохраняется: footer с временем последнего успешного запроса обновляется периодически, по умолчанию раз в 900 секунд;
  • при повторяющихся ошибках включается простой backoff до заданного предела;
  • Playwright переиспользует браузерный контекст и страницу;
  • отключаются лишние ресурсы браузера (например, изображения, шрифты, трекеры), чтобы снизить нагрузку.

Стек

  • Python 3.11+
  • discord.py
  • playwright
  • python-dotenv

Структура проекта

.
├── bot/
│   ├── config.py          # конфигурация из env/config.json
│   ├── embeds.py          # формирование Discord embeds
│   ├── models.py          # модели данных
│   ├── parser.py          # парсер HTML-карточек
│   ├── state.py           # JSON-хранилище состояния
│   └── widget_updater.py  # цикл обновления и редактирование сообщения
├── main.py                # точка входа
├── requirements.txt
├── .env.example           # пример env-конфига
├── config.json            # альтернативный конфиг (не обязателен)
└── state.json             # файл состояния (можно переопределить через STATE_FILE)

Быстрый старт

  1. Создайте виртуальное окружение и активируйте его:

    python -m venv .venv
    source .venv/bin/activate
  2. Установите зависимости:

    pip install -r requirements.txt
  3. Установите браузер для Playwright:

    python -m playwright install chromium
  4. Настройте конфиг одним из двух способов:

    Вариант A — через .env:

    cp .env.example .env

    После этого заполните минимум:

    • DISCORD_TOKEN
    • CHANNEL_ID

    Вариант B — через config.json:

    • создайте файл config.json в корне проекта;
    • используйте пример из раздела ниже.
  5. Запустите бота:

    python main.py

Конфигурация

Бот поддерживает два источника конфигурации:

  1. переменные окружения (.env);
  2. config.json в корне проекта.

Если значение задано и в .env, и в config.json, используется значение из переменной окружения.

Переменные окружения

Переменная Обязательна По умолчанию Описание
DISCORD_TOKEN токен Discord-бота
CHANNEL_ID ID канала для виджета
UPDATE_INTERVAL_SECONDS 30 базовый интервал опроса сайта, сек
HEARTBEAT_EDIT_INTERVAL_SECONDS 900 как часто обновлять heartbeat в Discord, если данные не изменились
MAX_BACKOFF_SECONDS 300 верхний предел backoff при повторных ошибках
PARSER_TIMEOUT_SECONDS 20 timeout парсера/страницы
BASE_URL https://breaking.proxy.sqstat.ru URL источника данных
STATE_FILE state.json путь к JSON-файлу состояния
LOG_LEVEL INFO уровень логирования (DEBUG, INFO, WARNING, ERROR)

Пример config.json

{
  "DISCORD_TOKEN": "your_discord_bot_token",
  "CHANNEL_ID": "123456789012345678",
  "UPDATE_INTERVAL_SECONDS": 30,
  "HEARTBEAT_EDIT_INTERVAL_SECONDS": 900,
  "MAX_BACKOFF_SECONDS": 300,
  "PARSER_TIMEOUT_SECONDS": 20,
  "BASE_URL": "https://breaking.proxy.sqstat.ru",
  "STATE_FILE": "state.json",
  "LOG_LEVEL": "INFO"
}

Поведение обновлений

Когда виджет редактируется сразу

Сообщение в Discord обновляется немедленно, если изменились:

  • онлайн;
  • карта;
  • изображение карты;
  • или если нужно пересоздать сообщение.

Когда работает heartbeat

Если состояние серверов не изменилось, бот всё равно периодически обновляет embeds, чтобы в footer было видно актуальное время последнего успешного обращения к сайту.

Это позволяет быстро понять:

  • бот жив;
  • сайт доступен;
  • парсинг проходит успешно.

Логи

Логи сделаны в коротком и стабильном формате:

12:30:18 | I | __main__ | Logged in as MyBot#1234 | update_interval_seconds=30 | heartbeat_edit_interval_seconds=900 | max_backoff_seconds=300
12:30:19 | I | bot.parser | Fetched 2 eligible server cards | goto_ms=842 | wait_ms=126 | eval_ms=19 | total_ms=1002
12:30:19 | I | bot.widget_updater | Widget published | reason=state-changed | fetch_ms=1015 | publish_ms=488 | persist_ms=1 | state_saved=True
12:30:49 | I | bot.widget_updater | Widget heartbeat skipped: data unchanged and heartbeat not due | fetch_ms=934

Что важно:

  • время в формате HH:MM:SS;
  • уровень логирования — одной буквой (D/I/W/E);
  • логируются тайминги чтения страницы, публикации и сохранения состояния;
  • heartbeat и реальное изменение данных различаются отдельными сообщениями.

Файл состояния

По умолчанию бот использует state.json.

В нём хранятся:

  • channel_id
  • message_id
  • последнее успешное состояние серверов
  • время последнего успешного обращения к сайту

Файл записывается только при изменении состояния, чтобы уменьшить лишний I/O.

Поведение при ошибках

  • недоступность сайта или ошибка Playwright: ошибка логируется, цикл продолжается;
  • при серии ошибок включается backoff до MAX_BACKOFF_SECONDS;
  • пустой snapshot не публикуется поверх последнего нормального состояния;
  • если message_id больше не существует, создаётся новое сообщение;
  • если канал недоступен или не является текстовым — бот завершится с ошибкой.

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

Если у тебя есть локальные debug-файлы HTML, их можно использовать для анализа DOM и подстройки селекторов/парсинга без запуска полного цикла обновлений.

При необходимости можно удалить state.json, чтобы сбросить сохранённый message_id и заставить бота создать новое сообщение.

Деплой

Примерный порядок для VPS/хостинга:

  1. Установить Python 3.11+.

  2. Загрузить проект.

  3. Установить зависимости:

    pip install -r requirements.txt
  4. Установить Chromium для Playwright:

    python -m playwright install chromium
  5. Создать .env или config.json.

  6. Убедиться, что STATE_FILE доступен для записи.

  7. Запустить:

    python main.py

Лицензия

Укажи нужную лицензию перед публикацией, если репозиторий будет использоваться публично.

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages