Skip to content

Egor051/typesh

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

No releases published

Packages

 
 
 

Contributors