Clean up README.md and requirements.txt

This commit is contained in:
2026-04-12 21:29:33 -07:00
parent a627511467
commit 9c9db344df
2 changed files with 115 additions and 0 deletions

115
README.md
View File

@@ -1,2 +1,117 @@
# Voter-Uptime-Bot
A Discord bot that monitors the availability of web services and reports uptime statistics directly in your server. Built with `discord.py`, `aiohttp`, and `pydantic-settings`, it goes beyond simple HTTP checks — detecting Cloudflare intercept pages and validating real page content so you know your sites are genuinely reachable, not just returning a 200.
---
## Features
- **Periodic polling** — checks all configured sites every 15 minutes
- **Cloudflare intercept detection** — identifies challenge/block pages that return HTTP 200 but serve no real content
- **Keyword content validation** — confirms expected strings are present on the loaded page
- **Retry logic** — re-attempts checks on transient CF intercepts before marking a site degraded
- **Uptime history** — stores all check results in a local SQLite database
- **Discord slash commands** — view live status, 24-hour bars, and monthly summaries per site
---
## Commands
| Command | Description |
|---|---|
| `/uptime now` | Current status of all monitored sites |
| `/uptime day <site>` | 24-hour bar chart (🟩🟨🟥) with uptime % |
| `/uptime month <site>` | Current month summary, one square per day |
| `/uptime summarize` | Monthly uptime % for all sites at once |
---
## Project Structure
```
app/
├── __init__.py
├── bot.py # Discord client, slash commands, polling task
├── checker.py # SiteChecker — HTTP, CF detection, keyword validation
├── config.py # Pydantic Settings — loads all config from .env
├── db.py # SQLite init, insert, and fetch helpers
└── utils.py # check_site wrapper, bar rendering, uptime maths
```
---
## Configuration
All configuration is managed via a `.env` file using `pydantic-settings`. Copy `.env.example` to `.env` and fill in your values.
```env
DISCORD_SECRET_KEY=your-bot-token-here
DISCORD_CLIENT_ID=123456789
DATABASE_PATH=uptime.db
MONITORED_SITES='[
{
"name": "MySite",
"url": "https://example.com",
"timeout_seconds": 10,
"expected_keywords": ["Login", "Vote"],
"max_retries": 1
}
]'
```
### Site config fields
| Field | Required | Default | Description |
|---|---|---|---|
| `name` | ✅ | — | Display name used in Discord |
| `url` | ✅ | — | Full URL to check |
| `timeout_seconds` | | `10` | Request timeout |
| `expected_status` | | `200` | Expected HTTP status code |
| `expected_keywords` | | `[]` | Strings that must appear in the page body |
| `max_retries` | | `1` | Extra attempts on CF intercept before marking degraded |
---
## How Checks Work
Each poll goes through three layers:
1. **HTTP status** — non-2xx/3xx responses are marked degraded or down
2. **Cloudflare detection** — response body is scanned for CF challenge fingerprints; a match is marked `degraded` even if status was 200
3. **Keyword validation** — any `expected_keywords` that are missing from the body mark the site `degraded`
Results are stored with a `detection_reason` (`cf_intercept`, `missing_keywords`, `http_503`, `timeout`, etc.) so you can query historical failure causes.
---
## Result States
| State | Emoji | Meaning |
|---|---|---|
| `up` | 🟩 | HTTP OK, no CF intercept, all keywords present, latency < 3s |
| `degraded` | 🟨 | Reachable but CF intercept, missing content, slow, or 5xx |
| `down` | 🟥 | Timeout, connection failure, SSL error, or unexpected status |
---
## Installation
```bash
pip install -r requirements.txt
```
Run the bot:
```bash
python -m app.bot
```
---
## Requirements
- Python 3.11+
- A Discord bot token with the `applications.commands` scope and `bot` scope enabled
- The bot must be invited to your server with slash command permissions