- 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
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.
- Fix listener_count accumulation bug: use GREATEST() instead of + to track
peak concurrent listeners per day rather than cumulative count
- Migrate all inline JavaScript from templates to ParenScript:
- admin.ctml: listener stats, geo stats, password reset -> admin.lisp
- audio-player-frame.ctml: stream player logic -> stream-player.lisp (new)
- popout-player.ctml: popout player logic -> stream-player.lisp (shared)
- frameset-wrapper.ctml: frame-busting -> frameset-utils.lisp (new)
- profile.ctml: removed redundant inline init (already in profile.lisp)
- Fix API route detection: handle URIs with or without leading slash
- Add routes to serve new ParenScript-generated JS files
- Update ASDF system definition with new ParenScript components
Tested locally for 8+ hours with no issues.
- Add Liquidsoap control panel: status display, skip track, reload playlist, restart container
- Add Icecast restart button to System Status section
- Remove redundant Web Player Control section from admin
- Fix music library scan to follow symlinks (truename resolution)
- Fix database timestamp error (let PostgreSQL default handle added-date)
- Update docker-compose mount for stream-queue.m3u
- Clean up playlist path handling
- Add geo IP lookup for listener locations (ip-api.com)
- Add geo stats table with country flags to admin dashboard
- Fix listener stats table alignment with proper centering
- Fix Now Playing display to update without requiring audio playback
- Add caching for geo lookups to reduce API calls
Major Changes:
- Convert all JavaScript files to Parenscript for better maintainability
- Move spectrum-analyzer to parenscript/ directory structure
- Add parenscript-utils.lisp for shared utilities
- Convert admin.js, player.js, front-page.js, auth-ui.js to Parenscript
- Convert profile.js, users.js, recently-played.js to Parenscript
Stream Reconnect Fixes (from merged PR):
- Add reset-spectrum-analyzer function to properly clean up Web Audio API
- Implement reconnect logic for pauses longer than 10 seconds
- Detect stale audio in 'playing' event and force stream reconnection
- Prevent 'Now Playing' updates while stream is paused
- Reduce reconnect delay to 200ms for faster response
- Add proper spectrum analyzer reset/reinit during reconnection
UX Improvements:
- Change live indicator from blink to smooth pulse (2s ease-in-out)
- Pulse animation like old PowerBook/MacBook sleep indicator
- Add MUTED indicator to spectrum analyzer when audio is muted
- Spectrum continues to flow even when muted (data still streaming)
- Red 'MUTED' text displayed in top-right corner of canvas
Technical Details:
- Parenscript files generate JavaScript via API endpoints
- All player modes updated: main player, front page, popout, frame player
- Improved audio context handling to only create once per element
- Added comprehensive error handling and logging
- Updated asteroid.asd to include parenscript module structure
Documentation:
- Updated all documentation dates to 2025-12-06
- Added PARENSCRIPT-EXPERIMENT.org documenting the conversion
- Updated PROJECT-HISTORY.org with Phase 9 (Visual Audio Features)
- Added comprehensive project statistics (408 commits, 9,300 LOC)
This conversion improves code maintainability by using Lisp throughout
the stack and makes it easier to share code between frontend and backend.