09e3b6ca66
Build and Push Image / build (push) Has been cancelled
Co-authored-by: Cursor <cursoragent@cursor.com>
169 lines
7.1 KiB
Markdown
169 lines
7.1 KiB
Markdown
# Stoat Role Bot
|
||
|
||
Self-hosted bot for **[Stoat](https://stoat.chat)** (open-source chat platform at [stoat.chat](https://stoat.chat)) that gives members **roles** via **reactions** or **text commands** in server channels.
|
||
|
||
Stoat is the rebrand of Revolt and uses the same API; this bot works with Stoat and Revolt instances.
|
||
|
||
## Features
|
||
|
||
- **Reaction roles**: Users react to a specific message with an emoji to get (or remove) a role.
|
||
- **Text commands**: Users run `!role add <name>` / `!role remove <name>` for self-assignable roles; `!roles` lists them.
|
||
- **Admin commands**: Configure reaction-role message and assignable role list from the chat (or via `config/roles.json`).
|
||
|
||
## Quick start (Docker)
|
||
|
||
1. **Create a bot on your Stoat server**
|
||
- In Stoat, open your server → **Settings** → **Bots** (or equivalent).
|
||
- Create a bot and copy its **token**.
|
||
- Ensure the bot has **Assign Roles** permission (and that its role is above any roles it should assign).
|
||
|
||
2. **Configure and run**
|
||
```bash
|
||
cp .env.example .env
|
||
# Edit .env and set STOAT_BOT_TOKEN=your_bot_token
|
||
cp config/roles.json.example config/roles.json
|
||
# Edit config/roles.json: replace YOUR_SERVER_ID and MESSAGE_ID (see below)
|
||
docker compose up -d
|
||
```
|
||
|
||
3. **Server ID**: In Stoat, enable developer mode if available, then right‑click your server → copy ID. Use that in `roles.json` as `YOUR_SERVER_ID`.
|
||
|
||
4. **Reaction-role message**: Send a message in the channel (e.g. “React to get roles”), then copy that message’s ID. Put it under `reaction_roles` in `roles.json` with emoji → role name. When users add/remove reactions, the bot will add/remove the role.
|
||
|
||
## Configuration
|
||
|
||
- **Environment**
|
||
- `STOAT_BOT_TOKEN` or `REVOLT_BOT_TOKEN` (required): Bot token from your Stoat/Revolt server.
|
||
- `PREFIX` (optional): Command prefix (default `!`).
|
||
- `CONFIG_PATH` (optional): Path to config dir inside container (default `/app/config`).
|
||
|
||
- **`config/roles.json`**
|
||
- `servers.<SERVER_ID>.reaction_roles.<MESSAGE_ID>`: map emoji (unicode or custom emoji ID) → role name.
|
||
- `servers.<SERVER_ID>.assignable_roles`: list of role names that can be used with `!role add/remove`.
|
||
|
||
Example:
|
||
|
||
```json
|
||
{
|
||
"servers": {
|
||
"01ABC123DEF456": {
|
||
"reaction_roles": {
|
||
"01MSG789XYZ": {
|
||
"👍": "Notifications",
|
||
"🔔": "Announcements"
|
||
}
|
||
},
|
||
"assignable_roles": ["Notifications", "Announcements", "Gamer"]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
The bot writes updated config when admins use the admin commands below, so the container needs write access to the mounted `config` directory.
|
||
|
||
## Commands
|
||
|
||
| Command | Who | Description |
|
||
|--------|-----|-------------|
|
||
| `!roles` | Everyone | List self-assignable roles. |
|
||
| `!role add <name>` | Everyone | Give yourself a self-assignable role. |
|
||
| `!role remove <name>` | Everyone | Remove a self-assignable role. |
|
||
| `!setreactionroles <message_id> emoji=RoleName ...` | Admin (Manage Role) | Set which message and emoji→role pairs are used for reaction roles. |
|
||
| `!setassignableroles Role1, Role2, Role3` | Admin (Manage Role) | Set the list of self-assignable roles (comma-separated names). |
|
||
|
||
For **custom server emojis** in reaction roles, use the emoji’s ID in `roles.json` (see Stoat/Revolt docs for how to get it). Unicode emojis (e.g. 👍) can be used as-is.
|
||
|
||
## Setting up reaction roles in config
|
||
|
||
1. **Create the message in Stoat**
|
||
In the channel where you want reaction roles, send a message (e.g. "React below to get roles"). That message must stay there; the bot will watch reactions on it.
|
||
|
||
2. **Get the message ID**
|
||
In Stoat, enable developer mode if available, then **right-click that message** and copy its ID. It's a long string like `01ABC123MSG456...`.
|
||
|
||
3. **Edit `config/roles.json`**
|
||
Under your server (same `SERVER_ID` you use for `assignable_roles`), add a `reaction_roles` block. The key is the **message ID**; the value is an object mapping **emoji to role name** (role names must match your server's roles exactly):
|
||
|
||
```json
|
||
"reaction_roles": {
|
||
"01ABC123MSG456": {
|
||
"👍": "FFXIV",
|
||
"🎮": "Minecraft",
|
||
"🃏": "MtG"
|
||
}
|
||
}
|
||
```
|
||
|
||
- **Unicode emojis** (👍, 🎮, etc.): use the character as the key.
|
||
- **Custom server emojis**: use the emoji's ID as the key.
|
||
|
||
4. **Save the file.** The bot reloads config on each reaction; restart the container only if needed.
|
||
|
||
5. **Add the reactions to the message**
|
||
Add the same emojis to the message. When users click a reaction they get the role; when they remove it they lose the role.
|
||
|
||
**Example** for your server (replace `PASTE_MESSAGE_ID_HERE` with the real message ID):
|
||
|
||
```json
|
||
"01KHEGSQZB7HXG0YCKMCA2W5PW": {
|
||
"reaction_roles": {
|
||
"PASTE_MESSAGE_ID_HERE": {
|
||
"👍": "FFXIV",
|
||
"🎮": "Minecraft",
|
||
"🃏": "MtG"
|
||
}
|
||
},
|
||
"assignable_roles": ["FFXIV", "Ascension", "Tarnished", "Minecraft", "Tabletop", "MtG", "Smash", "Soul Calibur", "Hearthstone", "Degenerate"]
|
||
}
|
||
```
|
||
|
||
**Alternative:** An admin can set reaction roles from chat:
|
||
`!setreactionroles <message_id> 👍=FFXIV 🎮=Minecraft 🃏=MtG`
|
||
|
||
## Self-hosted Stoat / custom API URL
|
||
|
||
If you run your own Stoat (or Revolt) instance, point the bot at your API and WebSocket. Set the client configuration when building the bot (revolt.js accepts a `configuration` object with `revolt` and `ws` URLs). The default in revolt.js is the public Revolt/Stoat API (`api.revolt.chat` / `wss://ws.revolt.chat`). To use a different instance you would need to pass a custom configuration to the `Client` constructor; see [revolt.js](https://revolt.js.org/) and [Stoat developers](https://developers.stoat.chat/).
|
||
|
||
## Hosting the image on Gitea (automated pull on NAS)
|
||
|
||
**New to Gitea?** See **[docs/GITEA-SETUP.md](docs/GITEA-SETUP.md)** for a simple step-by-step guide.
|
||
|
||
To build in Gitea and pull the image on your NAS:
|
||
|
||
1. **Push this repo to your Gitea** (e.g. `myuser/stoat-role-bot`).
|
||
|
||
2. **Enable Gitea Actions** and add **Secrets** for the container registry:
|
||
- **Settings → Secrets**: `REGISTRY_USER` = your Gitea username, `REGISTRY_PASSWORD` = your password or a Personal Access Token (with package write).
|
||
|
||
3. **On every push to `main`**, the workflow in `.gitea/workflows/docker.yml` builds and pushes the image to your Gitea Container Registry. The image will be at:
|
||
`{your-gitea-host}/{owner}/stoat-role-bot:latest`
|
||
(e.g. `gitea.example.com/myuser/stoat-role-bot:latest`).
|
||
|
||
4. **On your NAS**, use the image from Gitea instead of building locally:
|
||
- Create `.env` with `GITEA_IMAGE=gitea.example.com/myuser/stoat-role-bot:latest`, plus `STOAT_BOT_TOKEN`, etc.
|
||
- Run: `docker compose -f docker-compose.pull.yml pull && docker compose -f docker-compose.pull.yml up -d`
|
||
- To **auto-update**: use [Watchtower](https://containers.dev/run/watchtower) or a cron job that runs `docker compose -f docker-compose.pull.yml pull` and restarts the container.
|
||
|
||
**Manual push** (from your PC, without Actions):
|
||
```bash
|
||
export GITEA_REGISTRY=gitea.example.com
|
||
export GITEA_OWNER=myuser
|
||
./push-to-gitea.sh
|
||
```
|
||
|
||
## Run without Docker
|
||
|
||
Requires Node.js 22+.
|
||
|
||
```bash
|
||
npm install
|
||
cp .env.example .env
|
||
# Set STOAT_BOT_TOKEN in .env
|
||
export CONFIG_PATH=./config
|
||
node bot/index.js
|
||
```
|
||
|
||
## License
|
||
|
||
MIT.
|