Bot to moderate both Twitch and Discord (2 separate bots using asyncio)
Go to file
2025-12-05 20:21:47 -06:00
data initial big push 2025-12-05 20:21:47 -06:00
discord_bot initial big push 2025-12-05 20:21:47 -06:00
libs initial big push 2025-12-05 20:21:47 -06:00
tests initial big push 2025-12-05 20:21:47 -06:00
twitch_bot initial big push 2025-12-05 20:21:47 -06:00
.gitignore initial big push 2025-12-05 20:21:47 -06:00
bot.py initial big push 2025-12-05 20:21:47 -06:00
pyproject.toml initial big push 2025-12-05 20:21:47 -06:00
pytest.ini initial big push 2025-12-05 20:21:47 -06:00
README.md initial big push 2025-12-05 20:21:47 -06:00
uv.lock initial big push 2025-12-05 20:21:47 -06:00

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
  1. 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 .
  1. 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.