IRC song request plugin with iTunes validation, HTMX web dashboard, WebSocket real-time updates, moderation, rate limiting, and history. Made-with: Cursor
SongRequest — Limnoria IRC Song Request Plugin
A Limnoria (Supybot) plugin that watches IRC channels for song requests, validates them against the iTunes Search API, and streams them in real time to an HTMX web dashboard via WebSocket.
Features
- Passive detection — recognizes
Artist - Titlepatterns in chat and validates against Apple Music - Explicit command —
!request Artist - Titlefor direct requests - Disambiguation — presents top matches when multiple results found; user picks by number
- Web dashboard — HTMX-powered UI with album art, Apple Music links, and moderation controls
- Real-time updates — WebSocket pushes new requests and status changes to all connected dashboards
- Moderation — approve, reject, or mark requests as played from the web UI
- Rate limiting — configurable per-user request limits
- Ignore list — block specific users from making requests
- Persistence — SQLite-backed; survives bot restarts
- IRC announcements — optionally announces status changes back to the originating channel
- Quiet mode — suppress the "Queued" IRC confirmation per-channel
- Alternate matches — when disambiguating, unchosen tracks appear as collapsible sub-cards
- Clickable cards — the entire request card links to Apple Music
- Export history — download request history as a Markdown file
- Open/close requests — global toggle (with per-channel override) from IRC or the web panel
- Clear history — wipe played/rejected entries from IRC or the web panel
Dependencies
aiohttp— standalone async web server for the dashboard
pip install aiohttp
Installation
-
Copy the
SongRequest/directory into your Limnoria plugins directory (or add its parent toconfig directories.plugins). -
Load the plugin:
@load SongRequest -
Configure enabled channels:
@config plugins.SongRequest.enabledChannels #music #requests -
Set a web dashboard auth token:
@config plugins.SongRequest.webAuthToken your-secret-token-here -
Access the dashboard at
http://<bot-host>:8888/(default port, configurable viawebPort).
Configuration
| Setting | Type | Default | Description |
|---|---|---|---|
enabledChannels |
Space-separated list | (empty) | Channels for passive detection |
ignoredUsers |
Space-separated list | (empty) | Nicks/hostmasks to ignore |
maxRequestsPerUser |
Integer | 10 | Max requests per rate limit window (0 = unlimited) |
rateLimitWindow |
Integer | 3600 | Rate limit window in seconds |
webAuthToken |
String (private) | (empty) | Auth token for web dashboard actions |
announceStatus |
Boolean | True | Announce status changes back to IRC |
maxChoices |
Integer | 3 | Disambiguation choices shown |
webPort |
Integer | 8888 | Port for the web dashboard server |
webHost |
String | 0.0.0.0 | Bind address for the web dashboard server |
requestsOpen |
Boolean | True | Global toggle — accept or reject new requests |
requestsOpenOverride |
String (per-channel) | (empty) | Per-channel override: open, closed, or empty for global |
quietQueued |
Boolean (per-channel) | False | Suppress the "Queued: ..." IRC confirmation |
passiveDetection |
Boolean (per-channel) | True | Enable passive pattern matching |
requestCommand |
Boolean (per-channel) | True | Enable the !request command |
Commands
| Command | Description | Permission |
|---|---|---|
request <text> |
Request a song by artist/title | Anyone |
pick <number> |
Pick from disambiguation choices | Anyone |
ignore <nick> |
Add a nick to the ignore list | Admin |
unignore <nick> |
Remove a nick from the ignore list | Admin |
requeststats |
Show queue statistics | Anyone |
openrequests [channel] |
Open requests globally or per-channel | Admin |
closerequests [channel] |
Close requests globally or per-channel | Admin |
clearhistory |
Clear all played/rejected requests | Admin |
Web Dashboard
The dashboard runs on a standalone aiohttp server (separate from Limnoria's built-in HTTP server) at the configured webPort (default 8888). It shows:
- Pending requests awaiting moderation
- Approved requests ready to play
- History of played/rejected requests
Each request card is a clickable link to Apple Music and displays album art, song title, artist, album name, requester info, and action buttons (Approve / Reject / Mark Played). When a request had disambiguation, the alternate matches appear in a collapsible section below the main card.
The history tab includes Export .md (download as Markdown) and Clear History buttons. A toggle switch in the header opens/closes requests globally (synced in real time across all connected dashboards).
Real-time updates are delivered via WebSocket — the status indicator dot in the header shows green when connected and red when disconnected (with automatic reconnection).
Admin actions require the auth token, which is automatically injected into the dashboard page at serve time.
How Passive Detection Works
- The bot watches messages in
enabledChannelsfor lines matchingSomething - Something - Lines starting with bot command prefixes (
!,.,@, etc.) or URLs are skipped - The extracted text is searched against the iTunes Search API
- If no song matches, the message is silently ignored (primary false-positive filter)
- If one match, it's queued automatically
- If multiple matches, the user is presented with choices
Running Tests
pip install limnoria aiohttp pytest
python -m pytest SongRequest/test.py -v