Files
NtR-soudcloud-fetcher/docs/api.md
cottongin 0f99e7914b docs: add IRC commands/plugin setup to README, update WebSocket docs
README was missing IRC command reference, plugin installation/config
guidance, and referenced nonexistent plugin READMEs. The WebSocket
docs in api.md were stale — subscribe message now documents role and
client_id fields, status message now includes the clients array.

Made-with: Cursor
2026-03-12 08:26:16 -04:00

10 KiB

NtR SoundCloud Fetcher -- API Reference

Base URL: http://127.0.0.1:8000 (configurable via NTR_HOST / NTR_PORT)


Public Endpoints

GET /health

Service health check.

Response

{
  "status": "ok",
  "poller_alive": true,
  "last_fetch": "2026-03-12T02:00:00+00:00",
  "current_week_track_count": 9
}
Field Type Description
status string Always "ok"
poller_alive boolean Whether the background poller is running
last_fetch string | null ISO 8601 timestamp of last successful poll, or null if never
current_week_track_count integer Number of tracks in the current week's playlist

GET /playlist

Returns the current week's full playlist.

Response

{
  "show_id": 10,
  "episode_number": 530,
  "week_start": "2026-03-05T02:00:00+00:00",
  "week_end": "2026-03-12T02:00:00+00:00",
  "tracks": [
    {
      "show_id": 10,
      "track_id": 12345,
      "position": 1,
      "title": "Night Drive",
      "artist": "SomeArtist",
      "permalink_url": "https://soundcloud.com/someartist/night-drive",
      "artwork_url": "https://i1.sndcdn.com/artworks-...-large.jpg",
      "duration_ms": 245000,
      "license": "cc-by",
      "liked_at": "2026-03-06T14:23:00+00:00",
      "raw_json": "{...}"
    }
  ]
}
Field Type Description
show_id integer Internal database ID for this show
episode_number integer | null Episode number (e.g. 530), or null if not assigned
week_start string ISO 8601 UTC timestamp -- start of the show's like window
week_end string ISO 8601 UTC timestamp -- end of the show's like window
tracks array Ordered list of tracks (see Track Object below)

GET /playlist/{position}

Returns a single track by its position in the current week's playlist. Positions are 1-indexed (matching IRC commands !1, !2, etc.).

Path Parameters

Parameter Type Description
position integer 1-based position in the playlist

Response -- a single Track Object (see below).

Errors

Status Detail
404 "No track at position {n}"

GET /shows

Lists all shows, ordered by week start date (newest first).

Query Parameters

Parameter Type Default Description
limit integer 20 Max number of shows to return
offset integer 0 Number of shows to skip

Response

[
  {
    "id": 10,
    "episode_number": 530,
    "week_start": "2026-03-05T02:00:00+00:00",
    "week_end": "2026-03-12T02:00:00+00:00",
    "created_at": "2026-03-05T03:00:00+00:00"
  }
]

GET /shows/by-episode/{episode_number}

Look up a show by its episode number. This is the recommended endpoint for IRC bot integrations (e.g. !playlist 530).

Path Parameters

Parameter Type Description
episode_number integer The episode number (e.g. 530)

Response

{
  "show_id": 10,
  "episode_number": 530,
  "week_start": "2026-03-05T02:00:00+00:00",
  "week_end": "2026-03-12T02:00:00+00:00",
  "tracks": [...]
}

Errors

Status Detail
404 "No show with episode number {n}"

GET /shows/{show_id}

Returns a specific show by internal database ID.

Path Parameters

Parameter Type Description
show_id integer The show's internal database ID

Response

{
  "show_id": 10,
  "episode_number": 530,
  "week_start": "2026-03-05T02:00:00+00:00",
  "week_end": "2026-03-12T02:00:00+00:00",
  "tracks": [...]
}

Errors

Status Detail
404 "Show not found"

Dashboard Endpoints

These routes are only available when the dashboard is enabled (all three NTR_WEB_* env vars set).

GET /login

Serves the login page.

POST /login

Authenticates with username and password. Sets a session cookie on success, redirects to /dashboard.

Form Data

Field Type Description
username string Dashboard username
password string Dashboard password

GET /logout

Clears the session cookie and redirects to /login.

GET /dashboard

Serves the playlist dashboard page. Requires a valid session cookie (redirects to /login if absent).


Admin Endpoints

All admin endpoints require a bearer token via the Authorization header:

Authorization: Bearer <NTR_ADMIN_TOKEN>

Returns 401 with "Missing or invalid token" if the header is absent or the token doesn't match.


POST /admin/refresh

Triggers an immediate SoundCloud fetch for the current week's show.

Request Body (optional)

{
  "full": false
}
Field Type Default Description
full boolean false Reserved for future use (full vs incremental refresh)

Response

{
  "status": "refreshed",
  "track_count": 9
}

POST /admin/tracks

Manually add a track to the current week's show.

Request Body

{
  "track_id": 12345,
  "position": 3
}
Field Type Required Description
track_id integer yes SoundCloud track ID (must already exist in the tracks table)
position integer no Insert at this position (shifts others down). Omit to append at end.

Response

{
  "status": "added"
}

DELETE /admin/tracks/{track_id}

Remove a track from the current week's show. Remaining positions are re-compacted.

Path Parameters

Parameter Type Description
track_id integer SoundCloud track ID to remove

Response

{
  "status": "removed"
}

Errors

Status Detail
404 "Track not in current show"

PUT /admin/tracks/{track_id}/position

Move a track to a new position within the current week's show.

Path Parameters

Parameter Type Description
track_id integer SoundCloud track ID to move

Request Body

{
  "position": 1
}
Field Type Required Description
position integer yes New 1-based position for the track

Response

{
  "status": "moved"
}

Errors

Status Detail
404 "Track not in current show"

POST /admin/announce

Broadcasts a track announcement to all connected WebSocket subscribers (IRC bots). The announcement is formatted as: Now Playing: Song #N: Title by Artist - URL.

Accepts either a bearer token OR a valid session cookie.

Request Body

Field Type Required Description
show_id integer yes Show database ID
position integer yes Track position in the show

Response

{
  "status": "announced",
  "message": "Now Playing: Song #1: Night Drive by SomeArtist - https://soundcloud.com/..."
}

Errors

Status Detail
401 "Unauthorized"
404 "No track at position {n}"

Track Object

Returned inside playlist and show detail responses.

Field Type Description
show_id integer The show this track belongs to
track_id integer SoundCloud track ID
position integer 1-based position in the playlist
title string Track title
artist string Uploader's SoundCloud username
permalink_url string Full URL to the track on SoundCloud
artwork_url string | null URL to artwork image, or null
duration_ms integer Track duration in milliseconds
license string License string (e.g. "cc-by", "cc-by-sa")
liked_at string ISO 8601 timestamp of when the host liked the track
raw_json string Full SoundCloud API response for this track (JSON string)

Week Boundaries

Shows follow a weekly cadence aligned to Wednesday 22:00 Eastern Time (EST or EDT depending on DST). The like window for a show runs from the previous Wednesday 22:00 ET to the current Wednesday 22:00 ET.

All timestamps in API responses are UTC. The boundary shifts by 1 hour across DST transitions:

Period Eastern UTC boundary
EST (Nov -- Mar) Wed 22:00 Thu 03:00
EDT (Mar -- Nov) Wed 22:00 Thu 02:00

WebSocket

WS /ws/announce

WebSocket endpoint for receiving announce broadcasts. Used by IRC bot plugins.

Authentication

After connecting, send a subscribe message:

{
  "type": "subscribe",
  "token": "<NTR_ADMIN_TOKEN>",
  "role": "bot",
  "client_id": "limnoria"
}
Field Type Required Description
type string yes Must be "subscribe"
token string yes NTR_ADMIN_TOKEN value
role string no Client role, defaults to "bot"
client_id string no Identifier for this client (e.g. "sopel", "limnoria")

Invalid token closes the connection with code 4001.

Messages from server

Announce broadcast:

{"type": "announce", "message": "Now Playing: Song #1: Title by Artist - URL"}

Status update (sent on subscriber connect/disconnect):

{
  "type": "status",
  "subscribers": 2,
  "clients": [
    {
      "client_id": "limnoria",
      "remote_addr": "1.2.3.4",
      "connected_at": "2026-03-12T02:00:00+00:00"
    }
  ]
}
Field Type Description
subscribers integer Number of connected bot clients
clients array List of connected bot clients with their client_id, remote_addr, and connected_at timestamp

Dashboard Configuration

The web dashboard is optional. Enable it by setting all three 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 session cookie signing

If any of these are absent, dashboard routes are not mounted and the API works exactly as before.