Successfully converted profile.js with all functionality:
- Profile data loading (username, role, join date, last active)
- Listening statistics display
- Recent tracks display
- Top artists display
- Password change form
- Export listening data
- Clear listening history
- Toast notifications
Generated JavaScript working correctly after fixing modulo operator.
Key learning: Use 'rem' instead of '%' for modulo in ParenScript.
Files:
- parenscript/profile.lisp - ParenScript source
- asteroid.asd - Added profile to parenscript module
- asteroid.lisp - Added profile.js to static route interception
- static/js/profile.js - Removed from git (backed up as .original)
- static/js/player.js - Restored (skipped for now, too complex)
Three files successfully converted to ParenScript\!
Moved PARENSCRIPT-EXPERIMENT.org to docs/ directory.
Updates:
- Marked front-page.js as complete in Phase 2
- Removed duplicate front-page.js from Phase 3
- Added conversion progress section with both files
- Documented front-page.js specific patterns:
* Global variables with defvar
* String concatenation with +
* Conditional logic with cond
* Object property access with ps:getprop
- Listed all tested features for front-page.js
Status: 2 of 6 JavaScript files converted successfully
Successfully converted front-page.js with all functionality:
- Stream quality configuration and switching
- Now playing updates (every 10 seconds)
- Pop-out player functionality
- Frameset mode toggle
- Auto-reconnect on stream errors
Generated JavaScript: 6900 characters
No browser errors, all features working
Files:
- parenscript/front-page.lisp - ParenScript source
- asteroid.asd - Added front-page to parenscript module
- asteroid.lisp - Added front-page.js to static route interception
- static/js/front-page.js - Removed from git (backed up as .original)
Two files successfully converted to ParenScript!
ParenScript doesn't support async/await syntax properly. Changed to use
promise chains with .then() which compiles correctly.
Result:
- No JavaScript errors
- Auth UI working correctly
- Generated JS: 1386 characters
- First successful ParenScript replacement complete\!
Next: Can convert more JS files (profile.js, users.js, etc.)
The issue was route ordering. Since Radiance matches routes in load order,
we couldn't override the static file route. Solution: intercept the static
route and check if path is 'js/auth-ui.js', then serve ParenScript-compiled
JavaScript instead.
Changes:
- Compile ParenScript to string at load time (stored in *auth-ui-js*)
- Intercept static route to serve ParenScript for auth-ui.js
- JavaScript successfully generated (1290 chars)
- Ready for browser testing
The ParenScript route must come before the catch-all static route
to properly override /static/js/auth-ui.js with dynamically compiled
JavaScript. Routes are matched in order, so specific routes must
precede general patterns.
- Removed static/js/auth-ui.js (backed up as .original)
- Templates still reference /asteroid/static/js/auth-ui.js
- Route now serves dynamically compiled ParenScript
- Ready to test ParenScript replacement
- Created parenscript/auth-ui.lisp with ParenScript version
- Added route to serve compiled JavaScript at /static/js/auth-ui.js
- Updated asteroid.asd to include parenscript module
- First conversion: auth-ui.js (authentication UI state management)
The ParenScript code compiles to equivalent JavaScript and is served
dynamically. This allows us to write client-side code in Lisp.
- Add parenscript dependency to asteroid.asd
- Create parenscript-utils.lisp with helper functions and macros
- Add PARENSCRIPT-EXPERIMENT.org documenting the conversion plan
- Goal: Replace all JavaScript with ParenScript for full-stack Lisp
This fix some issues where, on the client, `response.message` was `Ok.`
for error responses and real error message needed to be extracted from
`response.data.message`, which made a weird API.
- Auto-detect music library path based on environment
- Check for music/library/ directory for local development
- Default to /app/music/ for production Docker deployment
- Allow MUSIC_LIBRARY_PATH environment variable override
- Fixes scan-library function failing on production server
- Changed hardcoded music/library/ path to /app/music/ (production path)
- Added MUSIC_LIBRARY_PATH environment variable for local dev override
- Fixes scan library function on production server
- Aligns with path structure used in M3U playlists and liquidsoap config
The previous commit used uri-path() which doesn't exist in Radiance.
This caused 'The function ASTEROID::URI-PATH is undefined' errors
when trying to authenticate.
Changed to use radiance:path() which is the correct Radiance API
function for extracting the path component from a URI object.
Fixes authentication in both require-authentication and require-role.
The playlist was stuck on the first track because mode='normal' stops
after playing once. Changed to mode='sequential' which plays through
the entire playlist in order and then loops.
Also improved reload mechanism:
- Use reload_mode='watch' for efficient file change detection
- Increased reload interval to 5 minutes (less disruptive)
The playlist was stuck on the first track because mode='normal' stops
after playing once. Changed to mode='sequential' which plays through
the entire playlist in order and then loops.
Also improved reload mechanism:
- Use reload_mode='watch' for efficient file change detection
- Increased reload interval to 5 minutes (less disruptive)
This commit implements three major refactorings to make the codebase more
idiomatic and maintainable:
1. Template Path Centralization
- Add *template-directory* parameter and helper functions
- Replace 11+ instances of repetitive template loading boilerplate
- New functions: template-path, load-template in template-utils.lisp
2. String Construction with FORMAT
- Replace concatenate with format for external URLs (Icecast, static files)
- Maintain Radiance URI handling for internal routes
- Applied to stream URLs, status endpoints, and API responses
3. Error Handling with Custom Conditions
- NEW FILE: conditions.lisp with comprehensive error hierarchy
- Custom conditions: not-found-error, authentication-error,
authorization-error, validation-error, database-error, asteroid-stream-error
- Helper macros: with-error-handling, with-db-error-handling
- Helper functions: signal-not-found, signal-validation-error, etc.
- Refactored 19 API endpoints and page routes
- Proper HTTP status codes: 404, 401, 403, 400, 500
Changes:
- conditions.lisp: NEW (180+ lines of error handling infrastructure)
- asteroid.asd: Add conditions.lisp to system components
- asteroid.lisp: Refactor 30+ endpoints, eliminate 200+ lines of boilerplate
- template-utils.lisp: Add centralized template loading helpers
- frontend-partials.lisp: Update template loading and string construction
Net result: -97 lines of code, significantly improved error handling,
more maintainable and idiomatic Common Lisp.
All changes tested and verified:
- Clean build
- All endpoints functional
- Error handling returns proper HTTP codes
- No regressions