Files
SongRequest/README.md

178 lines
8.8 KiB
Markdown
Raw Normal View History

# 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
- **Feeling Lucky mode** — auto-select the first match, store the rest as alternates (per-channel)
- **Explicit/clean filtering** — prefer explicit tracks, filter out clean duplicates, or vice versa (configurable per-channel)
- **Last.fm spell correction** — optionally correct misspelled artist/track names before searching iTunes
- **Smart search** — dual-strategy iTunes queries with attribute-targeted searches and increased result limits
- **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
- **Bulk actions** — select multiple requests and approve, reject, or mark played in one action
- **Alternate matches** — when disambiguating, unchosen tracks appear as collapsible sub-cards with approve and mark-played buttons
- **Clickable cards** — the entire request card links to Apple Music
- **Session management** — start/stop named sessions, archive them, rename/clear/delete archived sessions
- **Channel grouping** — requests grouped by channel with tab filtering; URL-based channel routing
- **Auth system** — per-admin login via IRC-managed accounts (`addSongAdmin`), admin presence indicator
- **Theme support** — dark/light/system theme toggle
- **Rate limiting** — configurable per-user request limits
- **Ignore list** — block specific users from making requests
- **Auto-approve** — skip the pending queue and auto-approve requests (per-channel)
- **Persistence** — SQLite-backed; survives bot restarts
- **IRC announcements** — configurable delivery: channel, private message, or NOTICE
- **Quiet mode** — suppress the "Queued" IRC confirmation per-channel
- **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
- **Mobile responsive** — optimized layout for phones and tablets
## 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. Add a web dashboard admin (from IRC, requires bot admin):
```
@addsongadmin alice s3cretK3y
```
5. (Optional) Set a Last.fm API key for spell correction:
```
@config plugins.SongRequest.lastfmApiKey YOUR_LASTFM_KEY
```
6. Access the dashboard at `http://<bot-host>:8888/` (default port, configurable via `webPort`).
## Configuration
### Global Settings
| 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) | (Deprecated) Legacy shared auth token; prefer per-admin accounts |
| `lastfmApiKey` | String (private) | (empty) | Last.fm API key for spell correction; empty to disable |
| `announceStatus` | Boolean | True | Master switch for all IRC status announcements |
| `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 |
### Per-Channel Settings
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `requestsOpenOverride` | String | (empty) | `open`, `closed`, or empty for global default |
| `quietQueued` | Boolean | False | Suppress the "Queued: ..." IRC confirmation |
| `queuedReplyMode` | String | `channel` | Queued confirmation delivery: `channel`, `private`, or `notice` |
| `autoApprove` | Boolean | False | Auto-approve requests (skip pending queue) |
| `feelingLucky` | Boolean | False | Auto-select first match; store rest as alternates |
| `explicitMode` | String | `filter` | `off`, `prefer`, `filter`, or `clean` (see below) |
| `announceApproved` | Boolean | True | Announce approved requests in IRC |
| `announceRejected` | Boolean | True | Announce rejected requests in IRC |
| `announceNowPlaying` | Boolean | True | Announce now-playing requests in IRC |
| `announceReplyMode` | String | `channel` | Status announcement delivery: `channel`, `private`, or `notice` |
| `passiveDetection` | Boolean | True | Enable passive pattern matching |
| `requestCommand` | Boolean | True | Enable the `!request` command |
### Explicit Mode
Controls how explicit/clean track versions are handled in search results:
- **`off`** — return results as-is from iTunes
- **`prefer`** — sort explicit tracks first, keep all results
- **`filter`** (default) — drop cleaned versions when an explicit version of the same track exists, sort explicit first
- **`clean`** — drop explicit versions when a clean version exists, sort clean first
## 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 |
| `startsession [name]` | Start a new request session | Admin |
| `stopsession` | Stop and archive the active session | Admin |
| `addsongadmin <user> <key>` | Add a web dashboard admin account | Admin |
| `removesongadmin <user>` | Remove a web dashboard admin account | Admin |
| `listsongadmins` | List all web dashboard admin accounts | Admin |
## Web Dashboard
The dashboard runs on a standalone aiohttp server at the configured `webPort` (default `8888`).
### Authentication
Admins are managed via IRC commands (`addsongadmin`/`removesongadmin`). The dashboard has a login page at `/login`. Non-admins can view the queue and history read-only; admin controls (moderation buttons, session management, export, etc.) are only visible to logged-in admins.
A floating presence indicator shows which admins are currently online.
### Queue View
- **Pending** requests awaiting moderation
- **Approved** requests ready to play
- **Bulk select** mode for mass approve/reject/mark-played
- Action buttons (approve/reject/mark played) positioned in the top-right corner of each card
### History View
- History of played/rejected requests with **Export .md** and **Clear History** buttons
- **Session archives** — previous sessions listed with expand-to-view, plus rename/clear/delete actions
### Other Features
- Channel filter tabs with URL-based routing (`/#channelName` or `/channelName`)
- Dark/light/system theme toggle
- Toast notifications for new requests when viewing history
- Custom themed modals (no native browser prompts)
- Real-time WebSocket connection with auto-reconnect
## 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. If a Last.fm API key is configured, artist/track names are spell-corrected
4. The extracted text is searched against the iTunes Search API (dual-strategy: combined + attribute-targeted)
5. Results are filtered/sorted based on `explicitMode`
6. If no song matches, the message is silently ignored
7. If one match (or `feelingLucky` is on), it's queued automatically
8. If multiple matches, the user is presented with choices
## Running Tests
```bash
pip install limnoria aiohttp pytest
python -m pytest SongRequest/test.py -v
```