IRC song request plugin with iTunes validation, HTMX web dashboard, WebSocket real-time updates, moderation, rate limiting, and history. Made-with: Cursor
116 lines
5.6 KiB
Markdown
116 lines
5.6 KiB
Markdown
# 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 - Title` patterns in chat and validates against Apple Music
|
|
- **Explicit command** — `!request Artist - Title` for 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
|
|
|
|
```bash
|
|
pip install aiohttp
|
|
```
|
|
|
|
## Installation
|
|
|
|
1. Copy the `SongRequest/` directory into your Limnoria plugins directory (or add its parent to `config directories.plugins`).
|
|
|
|
2. Load the plugin:
|
|
```
|
|
@load SongRequest
|
|
```
|
|
|
|
3. Configure enabled channels:
|
|
```
|
|
@config plugins.SongRequest.enabledChannels #music #requests
|
|
```
|
|
|
|
4. Set a web dashboard auth token:
|
|
```
|
|
@config plugins.SongRequest.webAuthToken your-secret-token-here
|
|
```
|
|
|
|
5. Access the dashboard at `http://<bot-host>:8888/` (default port, configurable via `webPort`).
|
|
|
|
## 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
|
|
|
|
1. The bot watches messages in `enabledChannels` for lines matching `Something - Something`
|
|
2. Lines starting with bot command prefixes (`!`, `.`, `@`, etc.) or URLs are skipped
|
|
3. The extracted text is searched against the iTunes Search API
|
|
4. If no song matches, the message is silently ignored (primary false-positive filter)
|
|
5. If one match, it's queued automatically
|
|
6. If multiple matches, the user is presented with choices
|
|
|
|
## Running Tests
|
|
|
|
```bash
|
|
pip install limnoria aiohttp pytest
|
|
python -m pytest SongRequest/test.py -v
|
|
```
|