- Create a file named docker-compose.yml in an empty folder with this content:
version: "3.8"
services:
bot:
image: ghcr.io/421p/tod-bot:latest
container_name: tod-bot
environment:
- DISCORD_TOKEN=${DISCORD_TOKEN}
- TOD_STORAGE=sqlite
- TZ=UTC
volumes:
- ./data:/app/data
restart: unless-stopped- Start it
export DISCORD_TOKEN=your_tokendocker compose up -d
- In Discord, in the channel where the bot is present, try a first ToD:
.tod hallate 14:30 Europe/Kyiv
TodBot is a lightweight Discord bot to record boss Time of Death (ToD), show respawn windows, and post reminders when a window opens and closes. Currently supports standard Lineage 2 RB respawn time 12+9.
- Commands:
- .tod [time] [timezone]
- .window or .w
- .del
- .list or .ls or .all or .список
- Per-channel isolation (each Discord channel/server has its own ToD list and reminders)
- Automatic reminders at ToD + 12h (window start) and ToD + 21h (window end)
- User-local time display using Discord dynamic timestamps (tokens like t:UNIX:STYLE)
- Auto-deletes the invoking user message after handling (if the bot has permissions)
- Storage backends: JSON (default) or SQLite
- Translations: English (default), plus Russian, French, Greek, Portuguese, and Ukrainian via environment variable
- Dockerfile and docker-compose included
- Native run:
- PHP 8.4 or newer
- Composer
- pdo_sqlite extension if you use the SQLite backend
- Docker run:
- Docker Engine 24 or newer
- Clone and install dependencies
- git clone
- cd TodBot
- composer install
- Configure environment
- DISCORD_TOKEN: your Discord bot token (required)
- TOD_STORAGE: json or sqlite (default: json)
- TOD_SQLITE: path to SQLite file when TOD_STORAGE=sqlite (default: ./data/tods.sqlite)
- BOT_LOCALE: en (default) or one of ru, fr, el, pt, uk
- TZ: UTC is recommended
- Run
- php bin/bot.php
-
We recommend Docker as the easiest and most reliable way to run the bot.
-
Build locally and run
- docker build -t TodBot:latest .
- docker run -d --name TodBot -e DISCORD_TOKEN=your_token -e TOD_STORAGE=sqlite -e TZ=UTC -v "$(pwd)/data:/app/data" --restart unless-stopped TodBot:latest
-
Using docker-compose (example) Create a docker-compose.yml file with the following content:
version: "3.8" services: bot: image: ghcr.io/421p/tod-bot:latest container_name: tod-bot environment: - DISCORD_TOKEN=${DISCORD_TOKEN} - TOD_STORAGE=sqlite - TZ=UTC volumes: - ./data:/app/data restart: unless-stopped
Then run:
- export DISCORD_TOKEN=your_token
- docker compose up -d
-
Pulling the published image (GitHub Container Registry)
- docker login ghcr.io -u YOUR_GITHUB_USERNAME -p YOUR_GITHUB_TOKEN
- docker pull ghcr.io/421p/tod-bot:latest
- docker run -d
--name TodBot
-e DISCORD_TOKEN=your_token
-e TOD_STORAGE=sqlite
-e TZ=UTC
-v "$(pwd)/data:/app/data"
--restart unless-stopped
ghcr.io/421p/tod-bot:latest
- DISCORD_TOKEN — required
- TOD_STORAGE — json (default) or sqlite
- TOD_SQLITE — path to DB file when using sqlite (default: ./data/tods.sqlite)
- BOT_LOCALE — en (default) or one of: ru, fr, el, pt, uk
- TZ — system timezone; the app itself uses UTC internally
- JSON file: ./data/tods.json
- SQLite file: ./data/tods.sqlite
- Required: Read Messages/View Channel, Send Messages
- Recommended: Manage Messages (to allow the bot to delete user command messages)
Notes
- Boss names are case-insensitive.
- Displayed times are rendered by Discord in each viewer’s local timezone using dynamic timestamp tokens.
- The .tod command accepts flexible time formats and an optional timezone.
- .tod [time] [timezone]
- Sets ToD for a boss. If time is omitted, now is used. If timezone is omitted, UTC is used.
- Examples:
- .tod skylancer
- .tod skylancer now
- .tod skylancer 1700000000 UTC (unix epoch)
- .tod skylancer 14:30 Europe/Kyiv (HH:MM and IANA timezone)
- .tod skylancer 1430 UTC+2 (HHMM and UTC offset)
- .tod skylancer 2025-11-28 14:00 UTC (full date and time)
- .tod skylancer 28.11.2025 14:00 UTC (dd.mm.yyyy HH:MM)
- .tod skylancer 28-11 14:00 UTC (dd-mm HH:MM; current year assumed)
- .tod skylancer 30m ago (relative)
- .tod skylancer 2h (relative; treated as “ago”)
- now
- Unix timestamp (10 digits)
- Relative: examples 30m ago, 2h, -45m
- Clock: HH:MM or HHMM
- Full date-time: Y-m-d H:i, Y/m/d H:i, d.m.Y H:i, d-m-Y H:i, d/m/Y H:i
- Short date-time: d-m H:i, d.m H:i (current year assumed)
- IANA (for example Europe/Kyiv, America/New_York)
- UTC or GMT
- Offsets like UTC+2, +2, GMT-3
- .window (alias: .w)
- Shows last ToD and window start/end for the boss.
- Examples:
- .window behemoth
- .w hellman
- .del
- Deletes the stored ToD.
- Example: .del icarus
- .list (aliases: .ls, .all, .список)
- Lists bosses for the current channel whose window has not yet closed.
- If the window has not started yet, it shows “opens in …”. If it is in progress, it shows “closes in …”.
- Example: .list
- Each channel maintains its own ToDs and reminders. Using the bot on multiple servers/channels keeps data separate.
- Default locale: en
- Supported locales: en, ru, fr, el, pt, uk
- Switch locale: set BOT_LOCALE=
(e.g., BOT_LOCALE=ru) - Translation files:
- translations/messages.en.php
- translations/messages.ru.php
- translations/messages.fr.php
- translations/messages.el.php
- translations/messages.pt.php
- translations/messages.uk.php
- Entry point: bin/bot.php
- Key classes:
- src/Bot/DiscordBot.php — bootstraps Discord client and wires events
- src/Service/CommandHandler.php — parses and responds to commands
- src/Service/ReminderScheduler.php — periodic 60s checks to post start/end reminders
- src/Service/TimeParser.php — parses flexible time inputs into UTC
- src/Service/TimeFormatter.php — formats Discord timestamp tokens
- src/Repository — JSON and SQLite backends implementing the repository interface
- Storage schema basics:
- Primary key: boss + channel (per-channel isolation)
- Flags: start_reminded, end_reminded
- Run all tests: ./vendor/bin/phpunit (or composer test)
- CI: GitHub Actions runs tests on push and PR. On push, a Docker image is also built and published to GHCR if configured.
- DISCORD_TOKEN is not set — export DISCORD_TOKEN=your_token
- Bot does not delete user messages — grant Manage Messages permission
- SQLite errors (native) — enable pdo_sqlite or use the Docker image
- No reminders — the scheduler ticks every 60 seconds; make sure the bot can send messages in the channel where .tod was used
- Time parsing failed — the bot will respond with examples; try another format or specify a timezone