Commit Graph

355 Commits

Author SHA1 Message Date
glenneth 4622ae2440 Fix notification icon path to use existing asteroid.png 2026-01-18 10:21:21 -05:00
glenneth 849c1c2716 Increase rate limits on polling endpoints
Fix 429 errors caused by aggressive rate limiting on now-playing APIs.
Changed from 2-3 req/sec to 60 req/min for:
- asteroid/partial/now-playing
- asteroid/partial/now-playing-inline
- asteroid/partial/now-playing-json
- asteroid/channel-name

This fixes notifications not working and may resolve auto-reconnect issues.
2026-01-18 10:09:52 -05:00
glenneth 6d4169b707 Add system notifications for track changes
- Implement Web Notifications API in ParenScript
- Add notification toggle button (🔔/🔕) to player frame
- Show 'Artist - Track' notification when track changes
- Store notification preference in localStorage
- Auto-close notifications after 5 seconds
- Click notification to focus browser window
2026-01-18 08:55:53 -05:00
glenneth 7ed11ae2f4 Add sort dropdown for admin geo stats (minutes vs listeners)
- Add dropdown to admin template to choose sort order
- Update get-geo-stats to accept order-by parameter
- Update API endpoint to pass sort-by parameter
- Update ParenScript to read dropdown and pass to API
- Default sort is by minutes (engagement time)
2026-01-18 08:48:34 -05:00
glenneth b68fce817d Fix geo stats ordering to sort by total_minutes instead of total_listeners
Countries with high engagement (listen time) should appear at the top,
not countries with just high unique listener counts.
2026-01-18 08:48:34 -05:00
Luis Pereira ff651e6a36 fix: merged status and status-content 2026-01-15 12:58:45 -05:00
Luis Pereira 2118f4ed5a fix: merged about and about-content 2026-01-15 12:58:45 -05:00
Luis Pereira b862097ca2 fix: merged player and player-content 2026-01-15 12:58:45 -05:00
Luis Pereira 01cb0366c0 fix: merged frontend and frontend-content 2026-01-15 12:58:45 -05:00
Glenn Thompson 151f6c5569 Replace Autechre tracks with flow-state alternatives, add Underworld
- Replace jarring Autechre tracks with smoother ambient alternatives:
  - Labradford, Biosphere, Tycho, Marconi Union, arovane, Four Tet, Brian Eno, Alva Noto, Proem
- Add Underworld - Everything, Everything to all updated playlists
- Improves listener experience for coding/hacking flow state

Affected playlists:
- afternoon-orbit.m3u
- Asteroid-Low-Orbit.m3u
- Asteroid-Low-Orbit-DOCKER.m3u
- escape-velocity.m3u
- geostationary_stream_queue.m3u
- midnight-ambient.m3u
- new-years-eve-2025.m3u
2026-01-12 20:31:46 -05:00
glenneth 249844160f Fix listener minutes tracking for accurate geo stats
- Add register-web-listener to now-playing-json API endpoint
  This keeps listeners registered during continuous playback instead of
  timing out after 5 minutes of inactivity

- Fix listen_minutes calculation to increment by listener_count per poll
  Previously incremented by 1 regardless of how many listeners, now properly
  tracks listener-minutes (1 minute per listener per 60s poll interval)

- Add migration 009 documenting the calculation fix
2026-01-11 13:25:55 -05:00
glenneth 8b6209e4e0 Add mini spectrum analyzer to player frame with theme/style sync
- Remove cross-frame audio access that was breaking audio on navigation
- Add mini spectrum visualizer to persistent player frame
- Mini analyzer syncs theme and style with main analyzer via localStorage
- Add MusicBrainz search link to player frame (updates with track changes)
- Reduce quality selector width from 140px to 55px
- Add search_url to now-playing-json API response

The main analyzer is disabled in frameset mode due to browser restrictions
on cross-frame MediaElementSource, but the mini analyzer in the player
frame provides visualization that persists across content navigation.
2026-01-11 13:25:55 -05:00
Luis Pereira bad9d4294b fix: add api catch all route with 404 2026-01-07 17:39:26 -05:00
glenneth 8e60563e9d Fix stream stall reconnection failure
- Reset *is-reconnecting* flag before play attempt so error handler can
  catch failures and trigger retry with exponential backoff
- Always reconnect on stall event - ready-state check was unreliable
- Add retry logic with backoff when reconnect fails (up to 5 attempts)
- Store stalled timeout reference for proper cancellation

Fixes issue where stream would show 'Stream stalled - reconnecting...'
but never actually reconnect, requiring manual intervention.
2026-01-05 08:35:50 -05:00
glenneth f476b83cbe fix: Preserve playlist selection in scheduler dropdown on refresh 2026-01-04 14:11:15 -05:00
Brian O'Reilly f0f2dd93a4 patch bad change to Makefile to restore build.
take 2.
2026-01-02 19:07:43 -05:00
Luis Pereira f4468212de fix: docker image build configured with posgres 2026-01-02 07:43:47 -05:00
Luis Pereira abb6d97a61 fix: update db seed to match current schema 2026-01-02 07:43:47 -05:00
glenneth be0b622901 fix: Use head/cat instead of sed for multi-line YP snippet insertion 2026-01-02 07:42:11 -05:00
glenneth a52602afda feat: Address PR feedback - rename XML files and add STATION_URL config
- Rename icecast.xml.base -> icecast-base.xml for editor highlighting
- Rename icecast-yp.xml.snippet -> icecast-yp-snippet.xml for editor highlighting
- Add STATION_URL env var to Liquidsoap for YP directory station link
- Production sets STATION_URL=https://asteroid.radio
- Update docker-compose.yml to pass both ICECAST_HOSTNAME and STATION_URL
- Update environment.sh.template with STATION_URL documentation
2026-01-02 07:42:11 -05:00
glenneth 821352edb7 feat: Add ICECAST_HOSTNAME config for YP directory registration
- Add hostname substitution in icecast-entrypoint.sh
- Update environment.sh.template with ICECAST_HOSTNAME option
- Defaults to localhost for dev, production sets ice.asteroid.radio
- Fixes YP directories showing localhost:8000 as stream URL
2026-01-02 07:42:11 -05:00
glenneth 1760fa5768 feat: Make YP directory publishing configurable via ICECAST_ENABLE_YP env var
- Add Dockerfile.icecast with custom entrypoint
- Add icecast-entrypoint.sh to conditionally insert YP config
- Add icecast.xml.base (without YP blocks)
- Add icecast-yp.xml.snippet (YP directory blocks)
- Update docker-compose.yml to build custom icecast image
- Update environment.sh.template with documentation

Dev environments default to YP disabled.
Production sets ICECAST_ENABLE_YP=true to publish to internet-radio.com
2026-01-02 07:42:11 -05:00
Brian O'Reilly 8cbdaef217 we are at a point where there's lots of interstitial files...
ignore them.
2025-12-30 15:26:09 -05:00
Brian O'Reilly 6721d57550 Unneeded things...
no need for the postgres/docker env, and we don't track
playlists/stream-queue.m3u because it is dynamically generated.
2025-12-30 15:24:13 -05:00
Brian O'Reilly 3851857787 update our ignorance. 2025-12-30 15:20:44 -05:00
Brian O'Reilly a8bf864499 Lets institute some operations around here
A directory for ops scripts, plus a script to backup the posgres
database that holds up asteroid.radio.
2025-12-30 13:07:30 -05:00
Glenn Thompson de70fbde5a refactor: Address PR review feedback for timestamp handling
- Rename format-timestamp-for-postgres to format-timestamp-iso8601 (database-agnostic)
- Reuse format-timestamp-iso8601 in authenticate-user instead of inline formatting
- Change listened_at field type from integer to timestamp for consistency
2025-12-29 09:39:51 -05:00
Glenn Thompson debf47c9c7 fix: Use correct table name user_listening_history in user-profile.lisp
- Update all references from listening_history to user_listening_history
- Use correct column names: user_id, listened_at, duration_seconds, track_artist
- Update database.lisp collection definition to match PostgreSQL schema
2025-12-29 09:39:51 -05:00
Glenn Thompson 4b49f63991 fix: Normalize USERS table timestamps before dm:save to prevent PostgreSQL type errors
- Add format-timestamp-for-postgres and normalize-user-timestamps functions in database.lisp
- data-model-save now normalizes timestamp fields for USERS table before saving
- Fix authenticate-user to use data-model-save instead of dm:save directly
- Add global auth state in auth-ui.lisp for other scripts to check login status
- Add auth checks in front-page.lisp and stream-player.lisp to skip API calls when not logged in
- Fix ParenScript parentheses structure in stream-player.lisp DOMContentLoaded handler

Fixes password reset, role update, and last-login update failures caused by
integer timestamps being sent to PostgreSQL TIMESTAMP columns.
2025-12-29 09:39:51 -05:00
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