238 lines
8.1 KiB
Markdown
238 lines
8.1 KiB
Markdown
# EmperorFred
|
|
|
|
Multi-platform moderation bot for Twitch and Discord. This repository contains two separate bots (Twitch and Discord) that can be run concurrently in a single Python process using asyncio.
|
|
|
|
The project uses:
|
|
- Python 3.13+
|
|
- discord.py (Discord bot)
|
|
- TwitchIO v3 with EventSub over WebSocket (Twitch bot)
|
|
- SQLAlchemy (database)
|
|
- python-dotenv (env config)
|
|
- requests
|
|
- uv as the package manager (pyproject.toml + uv.lock)
|
|
|
|
|
|
## Overview
|
|
|
|
Entry point: `bot.py`
|
|
|
|
`bot.py` loads environment variables (via `python-dotenv`), then starts both bots concurrently:
|
|
- Discord bot class: `discord_bot.bot.EmperorFredDiscordBot`
|
|
- Twitch bot class: `twitch_bot.bot.TwitchBot`
|
|
|
|
Both bots expose simple commands and support a controlled in-process restart via a shared `RestartController`.
|
|
|
|
|
|
## Requirements
|
|
|
|
- Python 3.13 or newer
|
|
- uv (recommended) or pip
|
|
|
|
Project dependencies are declared in `pyproject.toml`. A lockfile `uv.lock` is present.
|
|
|
|
|
|
## Setup
|
|
|
|
1) Clone the repository
|
|
```
|
|
git clone <your-fork-or-origin>
|
|
cd EmperorFred
|
|
```
|
|
|
|
2) Create a virtual environment and install dependencies
|
|
|
|
- Using uv (recommended):
|
|
```
|
|
uv venv
|
|
source .venv/bin/activate
|
|
uv pip install -r <(uv pip compile pyproject.toml)
|
|
```
|
|
|
|
- Or using pip:
|
|
```
|
|
python -m venv .venv
|
|
source .venv/bin/activate
|
|
pip install -r <(pip-compile pyproject.toml) # if you use pip-tools
|
|
# or simply
|
|
pip install -e .
|
|
```
|
|
|
|
Note: If you don't use pip-tools, you can install directly from the project metadata:
|
|
```
|
|
pip install .
|
|
```
|
|
|
|
3) Configure environment variables
|
|
|
|
Create a `.env` file in the project root (or export variables in your shell). See the full list in the next section.
|
|
|
|
|
|
## Configuration (Environment Variables)
|
|
|
|
Environment variables are read in `discord_bot/config.py` and `twitch_bot/config.py`, and shared DB settings in both.
|
|
|
|
Required/optional variables:
|
|
|
|
Discord
|
|
- `DISCORD_TOKEN` — Discord bot token (required to run Discord bot)
|
|
- `DISCORD_COMMAND_PREFIX` — e.g. `!` (optional; defaults handled by code to `!` if unset)
|
|
- `DISCORD_GUILD_ID` — guild/server ID used by the app in some contexts (optional)
|
|
|
|
Twitch
|
|
- `TWITCH_CLIENT_ID` — Twitch application client ID (required for Twitch operations)
|
|
- `TWITCH_CLIENT_SECRET` — Twitch application client secret (required)
|
|
- `TWITCH_TOKEN` — OAuth token for Twitch bot account; if missing the Twitch bot will not start
|
|
- `TWITCH_CHANNEL` — channel name (used for logs/hints)
|
|
- `TWITCH_BOT_ID` — numeric user ID for the bot account (required to subscribe to chat messages)
|
|
- `TWITCH_OWNER_ID` — numeric broadcaster (channel) user ID (required to subscribe)
|
|
- `TWITCH_COMMAND_PREFIX` — e.g. `!` (optional)
|
|
- `TWITCH_REDIRECT_URL` — redirect URI used during OAuth flows (optional)
|
|
|
|
Database
|
|
- `DB_CONN_STR` — SQLAlchemy connection string (required). Example for SQLite file DB:
|
|
- `sqlite:///data/bot.db`
|
|
|
|
Notes
|
|
- The project uses `python-dotenv`, so variables defined in `.env` are loaded automatically by `bot.py`.
|
|
- TwitchIO v3 relies on EventSub for chat subscriptions. Ensure `TWITCH_OWNER_ID` and `TWITCH_BOT_ID` are set.
|
|
- A tokens file may be referenced by the Twitch bot startup path (see `bot.py`, currently opens `.tio.tokens.json`).
|
|
|
|
TODOs
|
|
- Document the full OAuth/token provisioning flow for Twitch, including generating and storing tokens in `.tio.tokens.json` (or the expected file name) and required scopes.
|
|
|
|
|
|
## Running
|
|
|
|
Run both bots together (recommended during development):
|
|
```
|
|
python bot.py
|
|
```
|
|
|
|
Behavior:
|
|
- If `DISCORD_TOKEN` is set, the Discord bot starts.
|
|
- If `TWITCH_TOKEN` is NOT set, the Twitch bot will log a warning and skip starting.
|
|
- On successful Twitch start, the bot subscribes to EventSub ChatMessage for the configured broadcaster/user IDs.
|
|
|
|
Select which bot to run (CLI):
|
|
- Both (default):
|
|
```
|
|
python bot.py
|
|
```
|
|
- Discord only:
|
|
```
|
|
python bot.py --bot discord
|
|
```
|
|
- Twitch only:
|
|
```
|
|
python bot.py --bot twitch
|
|
```
|
|
- Short flag works too (values: `discord`, `twitch`, `both`):
|
|
```
|
|
python bot.py -b both
|
|
```
|
|
|
|
|
|
## Commands
|
|
|
|
Discord (`discord_bot/cogs`):
|
|
- `!ping` — replies with a health check message.
|
|
- `!restart` — owner-only; gracefully restarts the Discord bot instance.
|
|
|
|
Twitch (`twitch_bot/commands`):
|
|
- `!ping` — replies with a health check message including the chatter name.
|
|
- `!restart` — moderator-only; gracefully restarts the Twitch bot instance.
|
|
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
.
|
|
├─ bot.py # Entry point; runs both bots concurrently
|
|
├─ pyproject.toml # Project metadata and dependencies
|
|
├─ uv.lock # Lockfile for uv (package manager)
|
|
├─ data/
|
|
│ ├─ bot.db # Example SQLite database (if used)
|
|
│ └─ models/
|
|
│ ├─ DiscordCog.py # Tracks Discord cog activation flags
|
|
│ ├─ TwitchComponent.py # Tracks Twitch command components and active flags
|
|
│ └─ TwitchLiveNotification.py
|
|
├─ libs/
|
|
│ ├─ Db.py # SQLAlchemy setup, model base, auto-create tables
|
|
│ ├─ Cog.py # Base for Discord cogs
|
|
│ ├─ RestartController.py # Simple restart signaling between loops
|
|
│ ├─ Channels.py, Guilds.py, Twitch.py, __init__.py
|
|
├─ discord_bot/
|
|
│ ├─ bot.py # Discord bot class (loads cogs dynamically)
|
|
│ ├─ config.py, config.json # Config loader + example JSON (not auto-loaded)
|
|
│ ├─ cogs/
|
|
│ │ ├─ ping.py # !ping command
|
|
│ │ └─ restart.py # !restart (owner-only)
|
|
│ └─ embeds/
|
|
│ └─ TwitchGameNotificationEmbed.py
|
|
└─ twitch_bot/
|
|
├─ bot.py # Twitch bot class (EventSub subscription; dynamic components)
|
|
├─ config.py # Twitch env config
|
|
└─ commands/
|
|
├─ ping.py # !ping command
|
|
└─ restart.py # !restart (moderator-only)
|
|
├─ tests/ # Pytest-based unit tests (offline)
|
|
│ ├─ conftest.py # Fixtures and env setup
|
|
│ ├─ test_db_and_models.py
|
|
│ ├─ test_discord_bot_load_cogs.py
|
|
│ ├─ test_twitch_bot_load_commands.py
|
|
│ └─ test_restart_controller.py
|
|
```
|
|
|
|
|
|
## Database
|
|
|
|
The project uses SQLAlchemy. `libs/Db.py`:
|
|
- Creates an engine from `DB_CONN_STR`
|
|
- Defines a `Db.Model` declarative base for models under `data/models`
|
|
- Imports all models from `data/models` and creates tables on startup
|
|
|
|
Models
|
|
- `data/models/TwitchComponent.py` maintains component activation flags for Twitch command modules. When `twitch_bot.bot.TwitchBot.load_commands()` scans `twitch_bot/commands`, it checks the DB record to decide whether to load a component.
|
|
- `data/models/DiscordCog.py` maintains activation flags for Discord cogs. When `discord_bot.bot.EmperorFredDiscordBot.load_cogs()` scans `discord_bot/cogs`, it checks the DB record to decide whether to load a cog.
|
|
- `data/models/TwitchLiveNotification.py` stores usernames for Discord-side Twitch live notifications (used by the `TwitchNotificationsCog`).
|
|
|
|
|
|
## Scripts
|
|
|
|
There are no custom CLI scripts or `tool` entries defined in `pyproject.toml`. Use `python bot.py` to run the application. Managing dependencies is done via uv/pip as described above.
|
|
|
|
|
|
## Testing
|
|
|
|
The project uses pytest.
|
|
|
|
How to run tests:
|
|
```
|
|
pip install pytest
|
|
pytest -q
|
|
```
|
|
|
|
Notes
|
|
- Tests are offline and avoid network calls. They focus on:
|
|
- `libs/RestartController` behavior
|
|
- Database/model initialization and defaults
|
|
- Discord cogs loading (registering `ping` and `restart`)
|
|
- Twitch components loading and honoring DB activation flags
|
|
- A temporary SQLite database is used per test via `DB_CONN_STR` provided by a pytest fixture.
|
|
|
|
TODOs
|
|
- Add integration tests (e.g., with mocked Discord/Twitch clients or local simulators).
|
|
|
|
|
|
## Development Notes
|
|
|
|
- Code style follows the surrounding modules; there is no configured formatter/linter in `pyproject.toml`.
|
|
- Consider adding Ruff/Black/mypy configuration and pre-commit hooks. (TODO)
|
|
|
|
|
|
## License
|
|
|
|
No license file is included in this repository.
|
|
|
|
TODO
|
|
- Choose and add a LICENSE (e.g., MIT, Apache-2.0) and update this section. |