Compare commits

..

7 Commits

Author SHA1 Message Date
Glenn Thompson 0805d8e9fa Fix HTML entity decoding in now playing titles
- Use plump:decode-entities to decode HTML entities (&, ", etc.) in track titles from Icecast XML
- Fixes display of artist names and track titles containing ampersands and other special characters
- One-line fix using existing plump library dependency
2025-12-06 19:47:56 +03:00
Glenn Thompson c53ee7d82a Update dropdown colors to match spectrum analyzer theme
- Dropdown boxes now dynamically update their text and border colors to match selected theme
- Prevents color clashing between UI elements and spectrum analyzer
- Colors update both on theme change and on page load
2025-12-06 19:05:14 +03:00
Glenn Thompson dede6fef73 Add monotone theme and dynamic border color
- Add monotone theme with deep blue to cobalt gradient
- Update canvas border color dynamically to match selected theme
- Set initial border color on page load based on saved preference
2025-12-06 18:57:55 +03:00
Glenn Thompson aeea81fbbf Rename recently-played.js to recently-played.js.original
Match naming convention of other original JS files now replaced by parenscript
2025-12-06 18:57:55 +03:00
Glenn Thompson 8f7ce8bc96 Add spectrum analyzer theming and visualization styles
- Add 6 color themes: green, blue, purple, red, amber, rainbow
- Add 3 visualization styles: bars, wave, dots
- Add UI controls (dropdowns) to change theme and style
- Persist user preferences in localStorage
- Remove debug logging from parenscript serving and Icecast stats
- Fix dots visualization with proper Math.PI handling
2025-12-06 18:57:55 +03:00
Glenn Thompson af51f7d6e9 feat: Convert JavaScript to Parenscript with stream fixes and UX improvements
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.
2025-12-06 18:57:55 +03:00
Brian O'Reilly f68c85f0cd asteroid.css is generated on every start. delete it from repository. 2025-12-06 10:25:26 -05:00
6 changed files with 36 additions and 1191 deletions

View File

@ -30,7 +30,7 @@
(multiple-value-bind (match groups) (multiple-value-bind (match groups)
(cl-ppcre:scan-to-strings "<title>(.*?)</title>" source-section) (cl-ppcre:scan-to-strings "<title>(.*?)</title>" source-section)
(if (and match groups) (if (and match groups)
(aref groups 0) (plump:decode-entities (aref groups 0))
"Unknown"))) "Unknown")))
"Unknown"))) "Unknown")))

View File

@ -20,6 +20,7 @@
;; Color themes for spectrum analyzer ;; Color themes for spectrum analyzer
(defvar *themes* (defvar *themes*
(ps:create (ps:create
"monotone" (ps:create "top" "#0047ab" "mid" "#002966" "bottom" "#000d1a")
"green" (ps:create "top" "#00ff00" "mid" "#00aa00" "bottom" "#005500") "green" (ps:create "top" "#00ff00" "mid" "#00aa00" "bottom" "#005500")
"blue" (ps:create "top" "#00ffff" "mid" "#0088ff" "bottom" "#0044aa") "blue" (ps:create "top" "#00ffff" "mid" "#0088ff" "bottom" "#0044aa")
"purple" (ps:create "top" "#ff00ff" "mid" "#aa00aa" "bottom" "#550055") "purple" (ps:create "top" "#ff00ff" "mid" "#aa00aa" "bottom" "#550055")
@ -180,10 +181,26 @@
(setf *animation-id* nil))) (setf *animation-id* nil)))
(defun set-spectrum-theme (theme-name) (defun set-spectrum-theme (theme-name)
"Change the spectrum analyzer color theme" "Change the spectrum analyzer color theme and update dropdown colors"
(when (ps:getprop *themes* theme-name) (when (ps:getprop *themes* theme-name)
(setf *current-theme* theme-name) (setf *current-theme* theme-name)
(ps:chain local-storage (set-item "spectrum-theme" theme-name)) (ps:chain local-storage (set-item "spectrum-theme" theme-name))
(let ((theme (ps:getprop *themes* theme-name)))
;; Update canvas border color to match theme
(when *canvas*
(setf (ps:@ *canvas* style border-color) (ps:@ theme top)))
;; Update dropdown box colors
(let ((theme-selector (ps:chain document (get-element-by-id "spectrum-theme-selector")))
(style-selector (ps:chain document (get-element-by-id "spectrum-style-selector"))))
(when theme-selector
(setf (ps:@ theme-selector style color) (ps:@ theme top))
(setf (ps:@ theme-selector style border-color) (ps:@ theme top)))
(when style-selector
(setf (ps:@ style-selector style color) (ps:@ theme top))
(setf (ps:@ style-selector style border-color) (ps:@ theme top)))))
(ps:chain console (log (+ "Spectrum theme changed to: " theme-name))))) (ps:chain console (log (+ "Spectrum theme changed to: " theme-name)))))
(defun get-available-themes () (defun get-available-themes ()
@ -212,13 +229,23 @@
(when (and saved-style (or (= saved-style "bars") (= saved-style "wave") (= saved-style "dots"))) (when (and saved-style (or (= saved-style "bars") (= saved-style "wave") (= saved-style "dots")))
(setf *current-style* saved-style)) (setf *current-style* saved-style))
;; Update UI selectors if they exist ;; Update UI selectors, canvas border, and dropdown colors
(let ((theme-selector (ps:chain document (get-element-by-id "spectrum-theme-selector"))) (let ((theme-selector (ps:chain document (get-element-by-id "spectrum-theme-selector")))
(style-selector (ps:chain document (get-element-by-id "spectrum-style-selector")))) (style-selector (ps:chain document (get-element-by-id "spectrum-style-selector")))
(canvas (ps:chain document (get-element-by-id "spectrum-canvas")))
(theme (ps:getprop *themes* *current-theme*)))
(when theme-selector (when theme-selector
(setf (ps:@ theme-selector value) *current-theme*)) (setf (ps:@ theme-selector value) *current-theme*)
(setf (ps:@ theme-selector style color) (ps:@ theme top))
(setf (ps:@ theme-selector style border-color) (ps:@ theme top)))
(when style-selector (when style-selector
(setf (ps:@ style-selector value) *current-style*)))) (setf (ps:@ style-selector value) *current-style*)
(setf (ps:@ style-selector style color) (ps:@ theme top))
(setf (ps:@ style-selector style border-color) (ps:@ theme top)))
;; Set initial canvas border color
(when canvas
(setf (ps:@ canvas style border-color) (ps:@ theme top)))))
(let ((audio-element (or (ps:chain document (get-element-by-id "live-audio")) (let ((audio-element (or (ps:chain document (get-element-by-id "live-audio"))
(ps:chain document (get-element-by-id "persistent-audio"))))) (ps:chain document (get-element-by-id "persistent-audio")))))

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@
<label> <label>
Theme: Theme:
<select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;"> <select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="monotone">Monotone</option>
<option value="green">Green</option> <option value="green">Green</option>
<option value="blue">Blue</option> <option value="blue">Blue</option>
<option value="purple">Purple</option> <option value="purple">Purple</option>

View File

@ -38,6 +38,7 @@
<label> <label>
Theme: Theme:
<select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;"> <select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="monotone">Monotone</option>
<option value="green">Green</option> <option value="green">Green</option>
<option value="blue">Blue</option> <option value="blue">Blue</option>
<option value="purple">Purple</option> <option value="purple">Purple</option>

View File

@ -32,6 +32,7 @@
<label> <label>
Theme: Theme:
<select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;"> <select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="monotone">Monotone</option>
<option value="green">Green</option> <option value="green">Green</option>
<option value="blue">Blue</option> <option value="blue">Blue</option>
<option value="purple">Purple</option> <option value="purple">Purple</option>