Files
SongRequest/README.md
cottongin 6723413250 Initial commit: SongRequest Limnoria plugin
IRC song request plugin with iTunes validation, HTMX web dashboard,
WebSocket real-time updates, moderation, rate limiting, and history.

Made-with: Cursor
2026-03-28 04:43:50 -04:00

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
```