Reflects all changes since the initial README: Bearer auth on internal endpoints, public index page and /public/* API, dashboard enhancements (announced checkbox, ping button, tabbed UI, copy-to-clipboard), .env file support, and new config variables. Made-with: Cursor
Important
This project was developed entirely with AI coding assistance (Claude Opus 4.6 via Cursor IDE) and has not undergone rigorous review. It is provided as-is and may require adjustments for other environments.
NtR SoundCloud Fetcher
Fetches SoundCloud likes from NicktheRat's profile, builds weekly playlists aligned to the Wednesday 22:00 ET show schedule, and serves them via a JSON API.
Quick Start
pip install -e ".[dev]"
cp .env.example .env # edit with your settings
ntr-fetcher
The API starts at http://127.0.0.1:8000.
Historical Backfill
Seed the database with past shows by providing an anchor episode and its air date:
NTR_ADMIN_TOKEN=token ntr-fetcher --init --show 521 --aired 2026-01-07
This computes every weekly show from the anchor forward to today, batch-fetches the corresponding likes from SoundCloud, and populates the database. Episode numbers are assigned automatically (521, 522, ...). After backfill completes, the normal server mode will auto-increment from the latest episode.
API
Full documentation: docs/api.md
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/ |
GET | -- | Public index page |
/health |
GET | -- | Service health check |
/public/playlist |
GET | -- | Current week's playlist (unannounced tracks censored) |
/public/shows |
GET | -- | List all shows (paginated) |
/public/shows/{show_id} |
GET | -- | Past show with full tracklist |
/playlist |
GET | Bearer | Current week's full playlist |
/playlist/{position} |
GET | Bearer | Single track by position (1-indexed) |
/shows |
GET | Bearer | List all shows (paginated) |
/shows/by-episode/{episode_number} |
GET | Bearer | Look up show by episode number |
/shows/{show_id} |
GET | Bearer | Specific show by internal ID |
/login |
GET/POST | -- | Login page |
/logout |
GET | Session | Clear session |
/dashboard |
GET | Session | Live playlist dashboard |
/admin/refresh |
POST | Bearer | Trigger immediate SoundCloud fetch |
/admin/tracks |
POST | Bearer | Add track to current show |
/admin/tracks/{track_id} |
DELETE | Bearer | Remove track from current show |
/admin/tracks/{track_id}/position |
PUT | Bearer | Move track to new position |
/admin/announce |
POST | Bearer/Session | Announce track to IRC |
/admin/announced |
POST | Bearer/Session | Toggle track announced state |
/admin/ping |
POST | Bearer/Session | Send IRC message via connected bots |
/ws/announce |
WS | Bearer | Bot WebSocket for announcements |
/ws/public |
WS | -- | Public WebSocket for live track reveals |
Configuration
All settings are read from environment variables (prefix NTR_). A .env
file in the project root is loaded automatically. See
.env.example for a template with all available variables.
| Variable | Default | Description |
|---|---|---|
NTR_PORT |
8000 |
API port |
NTR_HOST |
127.0.0.1 |
Bind address |
NTR_DB_PATH |
./ntr_fetcher.db |
SQLite database path |
NTR_POLL_INTERVAL_SECONDS |
3600 |
How often to check SoundCloud (seconds) |
NTR_ADMIN_TOKEN |
(required) | Bearer token for admin endpoints |
NTR_SOUNDCLOUD_USER |
nicktherat |
SoundCloud username to track |
NTR_SHOW_DAY |
2 |
Day of week for show (0=Mon, 2=Wed) |
NTR_SHOW_HOUR |
22 |
Hour (Eastern Time) when the show starts |
NTR_SHOW_ROTATION_DELAY_HOURS |
0 |
Hours to wait after the show boundary before rotating to the next episode (recommended 2 for live recording window) |
NTR_PING_TARGET |
(empty) | Default nick/target for the dashboard ping feature |
NTR_PING_MESSAGE |
(empty) | Default message for the dashboard ping feature |
Public Index Page
The root URL (/) serves a public-facing page showing the current show's
playlist. Unannounced tracks are hidden behind silhouette cards until the
admin announces them from the dashboard. Reveals happen in real time over
WebSocket (/ws/public), so listeners following along see tracks appear
as they are played.
Past episodes are browsable from the same page with their full tracklists visible.
Dashboard
An optional web dashboard for managing tracks during live shows. Features:
- Tabbed show interface -- switch between the current and previous week's playlists in one view.
- Announce button -- push a track to IRC via connected bot plugins. Also reveals the track on the public index page in real time.
- Announced checkbox -- persistent per-track flag, auto-checked on announce. Can be toggled manually.
- Copy to clipboard -- one-click copy of a formatted track line.
- Send IRC Message -- ping a nick or channel with a custom message through
all connected bots. Default target and message are configurable via
NTR_PING_TARGET/NTR_PING_MESSAGE.
Enable by setting these environment variables:
| Variable | Default | Description |
|---|---|---|
NTR_WEB_USER |
(required) | Dashboard login username |
NTR_WEB_PASSWORD |
(required) | Dashboard login password |
NTR_SECRET_KEY |
(required) | Secret key for cookie signing |
IRC Commands
Both Sopel and Limnoria plugins expose the same commands:
| Command | Description |
|---|---|
!1, !2, ... !N |
Track by position in the current week's playlist |
!song <episode> <position> |
Track from a specific episode's playlist |
!playlist [episode] |
Current week's playlist, or a specific episode |
!lastshow <position> |
Track from the previous week's show |
!status |
API health, poller status, and track count |
!refresh |
Trigger a manual SoundCloud fetch (admin only) |
IRC Plugin Setup
Both plugins require the websocket-client package for live announcements:
pip install websocket-client
Sopel
Copy plugins/sopel/ntr_playlist.py into your Sopel plugins directory
(typically ~/.sopel/plugins/). Add a [ntr_playlist] section to your
Sopel config:
| Setting | Default | Description |
|---|---|---|
api_base_url |
http://127.0.0.1:8000 |
NtR API base URL |
admin_token |
(empty) | Bearer token for admin commands |
admin_nicks |
(empty) | Comma-separated list of admin nicknames |
display_timezone |
America/New_York |
Timezone for displayed timestamps |
ws_url |
ws://127.0.0.1:8000/ws/announce |
WebSocket endpoint for announcements |
announce_channel |
#sewerchat |
Channel to send announcements to |
client_id |
sopel |
Identifier for this bot in status messages |
Limnoria
Copy the plugins/limnoria/NtrPlaylist/ directory into your Limnoria bot's
plugins folder. Configure via the Limnoria registry:
| Registry Value | Default | Description |
|---|---|---|
apiBaseUrl |
http://127.0.0.1:8000 |
NtR API base URL |
adminToken |
(empty) | Bearer token for admin commands |
adminNicks |
(empty) | Space-separated list of admin nicknames |
displayTimezone |
America/New_York |
Timezone for displayed timestamps |
wsUrl |
ws://127.0.0.1:8000/ws/announce |
WebSocket endpoint for announcements |
announceChannel |
#sewerchat |
Channel to send announcements to |
clientId |
limnoria |
Identifier for this bot in status messages |
Development
pip install -e ".[dev]"
pytest
ruff check src/ tests/