Commit Graph

326 Commits

Author SHA1 Message Date
glenneth eb03947f7f refactor: Listening history to data-model + frame player favorites sync
- Refactor listening history functions to use data-model interface:
  - record-listen, get-listening-history, get-listening-stats
  - get-top-artists, clear-listening-history, get-listening-activity
  - Updated API endpoints to use dm:field
- Refactor get-user-avatar to use data-model
- Add postMessage sync between front page and frame player for favorites
- Add credentials:include to frame player fetch calls for session cookies
2025-12-28 09:58:33 -05:00
glenneth ccce10db50 feat: Sync favorites between front page and frame player via postMessage 2025-12-28 09:58:33 -05:00
Luis Pereira 2effe3bdef fix: listening history using integers 2025-12-27 17:02:31 -05:00
Luis Pereira 554f23ac40 fix: move playlist functions to data-model 2025-12-27 17:02:31 -05:00
Brian O'Reilly 4a79558c75 Merge branch 'glenneth1-glenneth/user-profile-enhancements'
Summary

This PR fixes several issues with the favorites feature:
Fixes

    Favorites star UI - Star now stays solid after favoriting a track (both main player and frame player)
        Fixed race condition where cache was checked before reload completed
        Cache now calls check-favorite-status after loading

    Track-id lookup - find-track-by-title now parses 'Artist - Title' format from Icecast metadata and searches both artist and title columns

    NIL user-id guards - All favorites functions now return early if user-id is NIL, preventing PostgreSQL errors when API is called without authentication

    Favorites API alist keys - Fixed Postmodern key names (TRACK-TITLE not TRACK_TITLE)

Files Changed

    user-profile.lisp - NIL guards and aget-profile helper
    frontend-partials.lisp - find-track-by-title improvement
    parenscript/front-page.lisp - Cache loading fix
    parenscript/stream-player.lisp - Cache loading fix for frame player
2025-12-27 14:00:02 -05:00
glenneth 9a767a7550 Merge remote-tracking branch 'upstream/main' into glenneth/user-profile-enhancements 2025-12-27 21:37:35 +03:00
Luis Pereira 820228bac1 feat: set bigger rate limit for now-playing api route 2025-12-27 13:28:10 -05:00
Luis Pereira b32e0bdbb0 fix: include http error code on json api format 2025-12-27 13:28:10 -05:00
Luis Pereira 6499c0a9ab feat: move routes to use rate-limit macros 2025-12-27 13:28:10 -05:00
Luis Pereira 8ae905a2c1 feat: add limit extension macros for define-page and define-api 2025-12-27 13:28:10 -05:00
Luis Pereira 1a39e0c6d2 fix: move copy files to admin role 2025-12-27 13:28:10 -05:00
glenneth 753ff822ce fix: Add NIL user-id guards to favorites functions
Prevents PostgreSQL errors when favorites API is called without
authentication. Functions now return early (nil or 0) instead of
generating invalid SQL with NIL in WHERE clause.
2025-12-27 20:33:40 +03:00
glenneth 25a6341a7b Merge upstream/main into glenneth/user-profile-enhancements
Resolved conflicts keeping our fixes:
- find-track-by-title: parses 'Artist - Title' format
- favorites cache: calls check-favorite-status after load
- toggle-favorite: uses load-favorites-cache instead of update-now-playing
- aget-profile: uses correct Postmodern key names (TRACK-TITLE, -ID)
2025-12-27 20:19:06 +03:00
glenneth 116d9ceebf fix: Favorites star UI and track-id lookup
- Fix find-track-by-title to parse 'Artist - Title' format from Icecast
  and search both artist and title columns in tracks table
- Fix favorites API alist key mismatch (TRACK-TITLE not TRACK_TITLE)
- Fix favorites cache to update UI after loading
- Fix race condition where star reverted after clicking
- Add aget-profile helper for Postmodern uppercase key lookup
2025-12-27 20:06:37 +03:00
Glenn Thompson 827d090a7e Fix: Use integer values for completed column in listening_history
The migration defines 'completed' as INTEGER but the code was inserting
TRUE/FALSE boolean values. PostgreSQL rejects this type mismatch.

Changed (if completed "TRUE" "FALSE") to (if completed 1 0)
2025-12-24 10:48:37 -05:00
glenneth c01d99da85 chore: Add .jj/ to gitignore for Jujutsu VCS 2025-12-22 21:42:06 -05:00
glenneth 20e5c37beb feat: Add YP directory listings for internet-radio.com and xiph.org
- Add internet-radio.com YP directory entry
- Add xiph.org (Icecast official) YP directory entry
- All mount points already have public=true in Liquidsoap config
2025-12-22 21:42:06 -05:00
glenneth 01b00d448c docs: Update TODO-next-features.org with completed tasks
- Mark Internet-Radio.com listing as complete
- Mark Listener Requests (library tracks, add to library) as complete
- Mark all Themed streams as complete (low orbit, deep space, darker ambient, underworld)
2025-12-22 21:42:06 -05:00
glenneth 868b13af3d feat: Custom user playlists with submission and admin review
- Add user playlist creation, editing, and track management
- Add library browser for adding tracks to playlists
- Add playlist submission workflow for station airing
- Add admin review interface with preview, approve, reject
- Generate M3U files on approval in playlists/user-submissions/
- Include user-submissions in playlist scheduler dropdown
- Use playlist description as PHASE tag in M3U
- Add database migration for user_playlists table
- Update TODO-next-features.org to mark feature complete
2025-12-22 21:42:06 -05:00
glenneth 7351d7f800 refactor: Remove Recently Played section from profile page
Removed the Recently Played UI section from profile as redundant.
The listening history backend and APIs remain intact for future use.
Previous commit (0359e59) preserves the full implementation.
2025-12-22 21:42:06 -05:00
glenneth 62dde5e3cf feat: Track requests, listening history, and profile enhancements
Track Requests:
- Database table for user track requests (migration 007)
- API endpoints for submit, approve, reject, play
- Front page UI for submitting requests
- Shows recently played requests section

Listening History:
- Auto-records tracks when playing (with 60s deduplication)
- Recently Played section on profile (has date formatting issues)
- Activity chart showing listening patterns by day
- Load More Tracks pagination

Profile Improvements:
- Fixed 401 errors returning proper JSON
- Fixed PostgreSQL boolean type for completed column
- Added offset parameter to recent-tracks API

Note: Recently Played section has date formatting issues showing
'20397 days ago' - may be removed in future commit if not needed.
The listening history backend works correctly.

For production: run migrations/007-track-requests.sql
2025-12-22 21:42:06 -05:00
glenneth adce831a95 feat: Add avatar upload and fix authentication errors
Avatars:
- Add avatar_path column to USERS table (migration 006)
- Upload API endpoint /api/asteroid/user/avatar/upload
- Profile page shows avatar with hover-to-change overlay
- Default SVG avatar for users without uploaded image
- Avatars stored in static/avatars/ directory

Fixes:
- 401 errors now return proper JSON instead of 500
- SQL escaping for history recording (single quotes)
- Added debug logging for history/record API
- Avatar container has background color for visibility

For production: run migrations/006-user-avatars.sql
2025-12-22 21:42:06 -05:00
glenneth 00ec59014d feat: Add listening activity chart to profile page
- New API endpoint /api/asteroid/user/activity for daily aggregation
- Bar chart showing tracks played per day (last 30 days)
- Hover tooltips show exact date and count
- Total tracks summary below chart
- Green gradient bars matching site theme
2025-12-22 21:42:06 -05:00
glenneth 254106de75 feat: Add listening history tracking and fix favorites
Listening History:
- Auto-record tracks when they change (logged-in users only)
- Track stored by title (no tracks table dependency)
- Profile page shows real recent tracks, top artists, listening stats
- APIs: /api/asteroid/user/history, /user/listening-stats, /user/recent-tracks, /user/top-artists

Favorites Fixes:
- Remove favorite now uses title instead of track-id
- Fixed response parsing to show green success message
- Profile page remove button works correctly

Migration Script Updated:
- track_title column added to both tables
- track-id now optional (nullable)
- Unique index on (user-id, track_title)
- No foreign key to tracks table (title-based storage)

For production: run migrations/005-user-favorites-history.sql
2025-12-22 21:42:06 -05:00
glenneth bfc33c8d4e feat: Add track favorites feature with star button
- Add user_favorites and listening_history database tables
- Add migration 005-user-favorites-history.sql
- Create user-profile.lisp with favorites/history API endpoints
- Add star button (☆/★) to Now Playing on main page
- Add star button to frame player bar
- Add Favorites section to profile page
- Show login prompt when unauthenticated user clicks star
- Use gold color (#ffcc00) for favorited state (space theme)
- Fix require-authentication to properly detect API routes
- Support title-based favorites (no track DB required)
2025-12-22 21:42:06 -05:00
glenneth f5ff17b510 chore: Add .jj/ to gitignore for Jujutsu VCS 2025-12-22 05:52:39 +03:00
glenneth bf5793bf8e feat: Add YP directory listings for internet-radio.com and xiph.org
- Add internet-radio.com YP directory entry
- Add xiph.org (Icecast official) YP directory entry
- All mount points already have public=true in Liquidsoap config
2025-12-22 04:57:36 +03:00
glenneth 02f9255a7c docs: Update TODO-next-features.org with completed tasks
- Mark Internet-Radio.com listing as complete
- Mark Listener Requests (library tracks, add to library) as complete
- Mark all Themed streams as complete (low orbit, deep space, darker ambient, underworld)
2025-12-21 19:24:40 +03:00
glenneth 02e585bd5b feat: Custom user playlists with submission and admin review
- Add user playlist creation, editing, and track management
- Add library browser for adding tracks to playlists
- Add playlist submission workflow for station airing
- Add admin review interface with preview, approve, reject
- Generate M3U files on approval in playlists/user-submissions/
- Include user-submissions in playlist scheduler dropdown
- Use playlist description as PHASE tag in M3U
- Add database migration for user_playlists table
- Update TODO-next-features.org to mark feature complete
2025-12-21 18:45:35 +03:00
glenneth 2c49092c01 refactor: Remove Recently Played section from profile page
Removed the Recently Played UI section from profile as redundant.
The listening history backend and APIs remain intact for future use.
Previous commit (0359e59) preserves the full implementation.
2025-12-21 12:53:10 +03:00
glenneth 0359e5909a feat: Track requests, listening history, and profile enhancements
Track Requests:
- Database table for user track requests (migration 007)
- API endpoints for submit, approve, reject, play
- Front page UI for submitting requests
- Shows recently played requests section

Listening History:
- Auto-records tracks when playing (with 60s deduplication)
- Recently Played section on profile (has date formatting issues)
- Activity chart showing listening patterns by day
- Load More Tracks pagination

Profile Improvements:
- Fixed 401 errors returning proper JSON
- Fixed PostgreSQL boolean type for completed column
- Added offset parameter to recent-tracks API

Note: Recently Played section has date formatting issues showing
'20397 days ago' - may be removed in future commit if not needed.
The listening history backend works correctly.

For production: run migrations/007-track-requests.sql
2025-12-21 12:45:49 +03:00
glenneth 8f5fe7534d feat: Add avatar upload and fix authentication errors
Avatars:
- Add avatar_path column to USERS table (migration 006)
- Upload API endpoint /api/asteroid/user/avatar/upload
- Profile page shows avatar with hover-to-change overlay
- Default SVG avatar for users without uploaded image
- Avatars stored in static/avatars/ directory

Fixes:
- 401 errors now return proper JSON instead of 500
- SQL escaping for history recording (single quotes)
- Added debug logging for history/record API
- Avatar container has background color for visibility

For production: run migrations/006-user-avatars.sql
2025-12-21 09:07:56 +03:00
glenneth a2ebc415f2 feat: Add listening activity chart to profile page
- New API endpoint /api/asteroid/user/activity for daily aggregation
- Bar chart showing tracks played per day (last 30 days)
- Hover tooltips show exact date and count
- Total tracks summary below chart
- Green gradient bars matching site theme
2025-12-21 08:43:36 +03:00
glenneth 7600ea6bed feat: Add listening history tracking and fix favorites
Listening History:
- Auto-record tracks when they change (logged-in users only)
- Track stored by title (no tracks table dependency)
- Profile page shows real recent tracks, top artists, listening stats
- APIs: /api/asteroid/user/history, /user/listening-stats, /user/recent-tracks, /user/top-artists

Favorites Fixes:
- Remove favorite now uses title instead of track-id
- Fixed response parsing to show green success message
- Profile page remove button works correctly

Migration Script Updated:
- track_title column added to both tables
- track-id now optional (nullable)
- Unique index on (user-id, track_title)
- No foreign key to tracks table (title-based storage)

For production: run migrations/005-user-favorites-history.sql
2025-12-21 08:35:35 +03:00
glenneth 5225a07b8b feat: Add track favorites feature with star button
- Add user_favorites and listening_history database tables
- Add migration 005-user-favorites-history.sql
- Create user-profile.lisp with favorites/history API endpoints
- Add star button (☆/★) to Now Playing on main page
- Add star button to frame player bar
- Add Favorites section to profile page
- Show login prompt when unauthenticated user clicks star
- Use gold color (#ffcc00) for favorited state (space theme)
- Fix require-authentication to properly detect API routes
- Support title-based favorites (no track DB required)
2025-12-21 08:15:52 +03:00
glenneth 349fa31d8f Fix last-login timezone handling
- Add cl-time-to-unix helper to convert CL universal time to Unix epoch
- Store last-login as UTC time for correct timezone conversion
- Handle Unix epoch in JavaScript (detect seconds vs milliseconds)
2025-12-19 18:00:30 -05:00
glenneth bc7da82d84 Fix playlist display polling and add footer links
- Add /api/asteroid/channel-name endpoint for live channel name updates
- Update front-page.js and stream-player.js to poll server for channel name
  instead of relying on localStorage (fixes issue where listeners don't see
  playlist changes until page refresh)
- Add footer with Internet Radio directory link and craftering webring links
- Fix last-login display bug: use proper ISO 8601 timestamp format and
  parse as Date string instead of Unix epoch
2025-12-19 18:00:30 -05:00
glenneth b415ca9530 feat: Add database persistence and editable UI for playlist schedule
- Store schedule in PostgreSQL (playlist_schedule table)
- Load schedule from database on startup
- Admin UI: add/update schedule entries with hour and playlist dropdowns
- Admin UI: delete buttons for each schedule entry
- Available playlists populated from playlists directory
- Changes persist across server restarts
2025-12-17 20:48:07 -05:00
glenneth e2e3dbfbe0 fix: Load current scheduled playlist on startup
The scheduler now loads the appropriate playlist immediately when the
server starts, not just at the next scheduled time. This ensures the
stream plays the correct time-based playlist right away.
2025-12-17 20:48:07 -05:00
glenneth 6a80072075 feat: Add admin UI for playlist scheduler with server time display
- Add server time info (UTC) to scheduler status API
- Add scheduler section to admin.ctml with:
  - Server time display (UTC)
  - Current playlist indicator
  - Enable/Disable/Load Current buttons
  - Schedule table showing all time slots
- Add ParenScript functions for scheduler controls
- Auto-refresh scheduler status every 30 seconds
- Highlight active playlist in schedule table
2025-12-17 20:48:07 -05:00
glenneth 923b1dc4ea feat: Add automatic playlist scheduler with cl-cron
- Add playlist-scheduler.lisp with cl-cron based scheduling
- Schedule playlists at 00:00, 06:00, 12:00, 18:00 UTC
- Auto-start scheduler on database connection
- Add API endpoints for admin control:
  - /api/asteroid/scheduler/status
  - /api/asteroid/scheduler/enable
  - /api/asteroid/scheduler/disable
  - /api/asteroid/scheduler/load-current
  - /api/asteroid/scheduler/schedule
  - /api/asteroid/scheduler/update
  - /api/asteroid/scheduler/remove
- Add cl-cron dependency to asteroid.asd
- Extend morning-drift.m3u to ~6 hours (101 tracks)
2025-12-17 20:48:07 -05:00
Brian O'Reilly f1ba25c6bf New playlists in support of variety
as well as scheduled playback of 'shows'. First steps toward a more
dynamic future! h/t glenneth.
2025-12-16 20:52:52 -05:00
Glenn Thompson cb76c02e63 Remove debug logging from channel name update code 2025-12-14 19:08:41 -05:00
Glenn Thompson 987d01beaa Dynamic channel name updates and playlist crossfade transition
- Fix channel name not updating in frame player when playlist changes
- Use localStorage polling (2s interval) for cross-frame communication
- Fix API response access: use bracket notation for 'channel-name' property
- Add skip command after playlist load to trigger crossfade to new playlist
- Add #PHASE metadata to Asteroid-Low-Orbit.m3u playlist
2025-12-14 19:08:41 -05:00
Glenn Thompson 18c251c8c4 Fix toggleCountryCities bug - use let* for sequential binding
The arrow variable was referencing country-row before it was defined
because let binds all variables simultaneously. Changed to let* for
sequential binding so country-row is available when binding arrow.
2025-12-14 19:08:41 -05:00
Glenn Thompson 93140f8f24 Add channel/quality selector separation with dynamic playlist phase names
- Separate Channel selector (Curated/Shuffle) from Quality selector (bitrate)
- Add channel selector to frame player, front page, and popout player
- Dynamic curated channel name from playlist #PHASE: metadata
- Channel selection syncs across all player contexts via localStorage
- Quality selector disabled when Shuffle channel selected (fixed bitrate)
- Fix reconnectStream to use channel-aware config
- Consistent CSS styling for selector heights
2025-12-14 19:08:41 -05:00
Glenn Thompson 55d63770d2 Add shuffle mount to admin dashboard listener stats
- Add Shuffle column to Current Listeners table
- Display listener count for /asteroid-shuffle.mp3 mount
- Include shuffle listeners in total count
2025-12-14 15:43:29 -05:00
Glenn Thompson 4f1a60328b Add shuffle stream mount with separate recently-played tracking
- Add shuffle source to Liquidsoap config (96kbps MP3)
- Add shuffle option to all UI quality selectors (frame, popout, front page)
- Make now-playing APIs mount-aware for correct metadata display
- Implement separate recently-played lists for curated vs shuffle streams
- Speed up now-playing and recently-played refresh on stream change
- Fix clean shutdown of stats polling thread (positional timeout arg)
- Widen quality selector dropdown for shuffle label
2025-12-14 14:02:01 -05:00
Brian O'Reilly 4166f1c898 Revert "Glenneth's rundown of the state of the project"
This reverts commit 99cf4f69bc.
2025-12-14 12:50:53 -05:00
Brian O'Reilly 99cf4f69bc Glenneth's rundown of the state of the project
potential next moves, features, growth strategy. Relates to
TODO-nest-features.org, but more information and more descriptive.
2025-12-14 12:47:23 -05:00