Adds a --init mode that seeds the database with past shows from a given anchor episode/date forward, batch-fetching likes from SoundCloud and partitioning them into weekly buckets. Episode numbers are tracked in the shows table and auto-incremented by the poller for new shows. Includes full API documentation (docs/api.md) and updated README. Made-with: Cursor
6.6 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/{show_id}
Returns a specific show with its full track listing.
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" |
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" |
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 |