Commit Graph

25 Commits

Author SHA1 Message Date
cottongin
11f13c86b5 feat: add announced checkbox to track rows
Add a persistent "announced" checkbox after each track's Announce button.
The state is stored in a new `announced` column on `show_tracks` and is
auto-set when the Announce button is pressed. The checkbox is also freely
togglable, and announced tracks have their Announce button disabled.

Also fixes .env leakage in test_config.py (pass _env_file=None) and adds
tests for the new DB method, API endpoint, and announce side-effect.

Made-with: Cursor
2026-04-01 23:00:09 -04:00
cottongin
a5f77187b3 feat: add dashboard ping button and .env file support
Add a "Send IRC Message" section to the admin dashboard that sends a
configurable privmsg to any IRC nick or channel via all connected bots.
New POST /admin/ping endpoint broadcasts a "privmsg" WebSocket message
type, handled by both Limnoria and Sopel plugins.

Also enable pydantic-settings .env file loading (python-dotenv) and
add .env.example documenting all NTR_* configuration variables.

Made-with: Cursor
2026-04-01 22:20:18 -04:00
cottongin
82049ab47f feat: delay show rotation during live recording window
Decouple the like-window boundary (Wed 10pm ET) from when the system
rotates to a new show. NTR_SHOW_ROTATION_DELAY_HOURS=2 keeps the
previous week's show visible during the ~2 hour recording, then creates
the new show at midnight.

Made-with: Cursor
2026-04-01 21:29:42 -04:00
cottongin
a328684af0 fix: handle SoundCloud API 5xx errors with client_id refresh, backoff, and cursor fallback
SoundCloud began rejecting the fabricated pagination cursor with 500
errors. Fixed cursor user_id padding (zfill 22→20) to match the
documented format, added 5xx retry with exponential backoff in _api_get,
and added a fallback in fetch_likes that drops the fabricated cursor
when it causes persistent 500s.

Made-with: Cursor
2026-03-25 08:20:20 -04:00
cottongin
911dd3d5dd feat: tabbed show interface and copy-to-clipboard button
Replace the link column with a Copy button that copies
"Title by Artist - URL" to clipboard. Replace the current/previous
show layout with a horizontal scrollable tab bar showing all shows
from the database, most recent first. Tabs lazy-load and cache
show data on click.

Made-with: Cursor
2026-03-12 08:15:22 -04:00
cottongin
d6d5ac10e6 fix: separate bot vs viewer WebSocket connections, add client identification
The dashboard's own WS connection was being counted as a bot subscriber,
causing "1 bot connected" with no bots actually present. Now WS clients
send a role ("bot" or "viewer") in the subscribe message. Only bots count
toward the subscriber total. Bot plugins also send a configurable client_id
so the dashboard shows which specific bots are connected.

Made-with: Cursor
2026-03-12 07:51:55 -04:00
cottongin
a7849e6cd9 feat: styled login and dashboard pages with Pico CSS dark theme
Made-with: Cursor
2026-03-12 07:21:39 -04:00
cottongin
92136f0508 Wire dashboard into app
- Add web_user, web_password, secret_key as optional params to create_app
- Conditionally mount dashboard router when all three are set
- Pass settings from main.py to create_app
- Add tests for no dashboard/login routes when config absent

Made-with: Cursor
2026-03-12 07:19:01 -04:00
cottongin
e90f44439b Add dashboard router with session auth, announce endpoint, and WebSocket handler
- Login/logout/dashboard with HMAC-signed session cookies
- POST /admin/announce with session or bearer auth
- WS /ws/announce for subscribe/broadcast
- Static stubs: login.html, dashboard.html

Made-with: Cursor
2026-03-12 07:17:20 -04:00
cottongin
788225b3b6 feat: add WebSocket announce manager
Made-with: Cursor
2026-03-12 07:14:04 -04:00
cottongin
7ed7ace578 feat: add optional dashboard config fields
Made-with: Cursor
2026-03-12 07:12:10 -04:00
cottongin
1d08580a45 feat: add GET /shows/by-episode/{episode_number} endpoint
Allows looking up shows by episode number instead of internal DB ID,
enabling IRC bot commands like !playlist 530 to resolve directly.

Made-with: Cursor
2026-03-12 02:33:42 -04:00
cottongin
cb3ae403cf feat: add historical backfill with --init CLI and episode numbering
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
2026-03-12 02:09:15 -04:00
cottongin
c88826ac4d fix: wire show_day/show_hour config into API, simplify AddTrackRequest
- create_app now accepts show_day/show_hour params instead of
  hardcoding Wednesday 22:00
- main.py passes config values through to create_app
- Removed soundcloud_url from AddTrackRequest (not implemented);
  track_id is now required

Made-with: Cursor
2026-03-12 01:46:23 -04:00
cottongin
219e2d4545 feat: add main entry point wiring API server and poller
Made-with: Cursor
2026-03-12 01:41:16 -04:00
cottongin
2e22a2b3ff feat: add FastAPI routes for playlist, shows, admin, and health
Made-with: Cursor
2026-03-12 01:40:04 -04:00
cottongin
ab81ad4fd4 feat: add poller with supervised restart loop
Made-with: Cursor
2026-03-12 01:40:00 -04:00
cottongin
f7dde6781a feat: add user resolution and likes fetching with 401 retry
Made-with: Cursor
2026-03-12 01:36:28 -04:00
cottongin
49846f9d7e feat: add SoundCloud client with client_id extraction
Made-with: Cursor
2026-03-12 01:36:03 -04:00
cottongin
d2ab4e94c0 feat: add database query methods for tracks, shows, and show_tracks
Made-with: Cursor
2026-03-12 01:33:17 -04:00
cottongin
2b38fda25a feat: add database module with schema initialization
Made-with: Cursor
2026-03-12 01:21:33 -04:00
cottongin
537d9ecd8b feat: add data models for Track, Show, ShowTrack
Made-with: Cursor
2026-03-12 01:18:20 -04:00
cottongin
38dda5dda0 feat: add week boundary computation with DST handling
Made-with: Cursor
2026-03-12 01:18:12 -04:00
cottongin
7e41f55e26 feat: add configuration module with pydantic-settings
Made-with: Cursor
2026-03-12 01:16:51 -04:00
cottongin
c40559822e scaffold: project structure with pyproject.toml and test config
Made-with: Cursor
2026-03-12 01:16:16 -04:00