|
|
||
|---|---|---|
| config | ||
| data/sessions | ||
| docker | ||
| docs | ||
| music | ||
| static | ||
| template | ||
| .gitignore | ||
| AAC-STREAMING.org | ||
| LICENSE | ||
| Makefile | ||
| README.org | ||
| SESSION-NOTES-2025-10-12.org | ||
| TODO.org | ||
| analyze-performance.py | ||
| app-utils.lisp | ||
| asteroid-radio.liq | ||
| asteroid.asd | ||
| asteroid.lisp | ||
| auth-routes.lisp | ||
| build-executable.lisp | ||
| comprehensive-performance-test.sh | ||
| database.lisp | ||
| design.org | ||
| module.lisp | ||
| playlist-management.lisp | ||
| playlist.m3u | ||
| project-summary.org | ||
| run-all-tests.sh | ||
| setup-environment.lisp | ||
| simple-analysis.py | ||
| stream-control.lisp | ||
| stream-media.lisp | ||
| stream-queue.m3u | ||
| template-utils.lisp | ||
| test-server.sh | ||
| test-user-api.sh | ||
| user-management.lisp | ||
| users.lisp | ||
README.org
Asteroid Radio - Internet Streaming Platform
- Overview
- Key Features
- Architecture Changes
- Track Upload Workflow
- Icecast2 Integration
- Liquidsoap Integration
- Network Access
- Usage Instructions
- API Endpoints
- Database Schema
- Dependencies
- Development Notes
- Future Enhancements
- Troubleshooting
- License
Overview
Asteroid Radio is a modern, web-based music streaming platform built with Common Lisp and the Radiance framework. It provides a complete internet radio streaming system with live broadcasting, user management, playlist control, and professional audio processing.
Key Features
Live Internet Radio Streaming
- Multiple streaming formats: AAC 96kbps (high efficiency), MP3 128kbps (standard), MP3 64kbps (low bandwidth)
- Professional audio processing with ReplayGain for consistent volume without pumping
- Smooth crossfading between tracks (5 second transitions)
- Dynamic compression to prevent clipping
- Icecast2 streaming server integration
- Liquidsoap audio pipeline with watch-based playlist reloading
Stream Queue Control System
- Curated stream queue management (play tracks in specific order)
- Add tracks to end of queue or as "next to play"
- Add entire playlists to stream queue
- Real-time queue reordering
- Automatic fallback to random playback when queue is empty
- Stream history tracking
- Admin-only queue control via REST API
Music Library Management
- PostgreSQL-backed track storage with metadata extraction
- Support for MP3, FLAC, OGG, and WAV formats
- Automatic metadata extraction using taglib
- Track search, filtering, and sorting capabilities
- Pagination support for large libraries
- Individual track streaming on-demand
User Management System
- User registration and authentication
- Role-based access control (admin/user)
- User profiles and session management
- Personal playlist creation and management
- Admin interface for user administration
Web Interface
- RADIANCE framework with CLIP templating
- Modern admin dashboard with JavaScript controls
- Web player with HTML5 audio controls
- Live stream integration with embedded player
- Dark hacker-themed aesthetic with VT323 font
- Responsive design for desktop and mobile
Network Broadcasting
- Docker-based streaming infrastructure
- WSL-compatible networking for internal network access
- Professional streaming URLs for media players
- Multi-listener support via Icecast2
- Telnet control interface for live DJ operations
Architecture Changes
Framework Migration
- Migrated from Hunchentoot to RADIANCE web framework
- Implemented proper domain routing (
/asteroid/) - CLIP templating system for dynamic content
- Database abstraction layer for track storage
Streaming Stack
- Icecast2: Streaming server (port 8000)
- Liquidsoap: Audio processing and streaming pipeline with telnet control (port 1234)
- RADIANCE: Web server and API (port 8080)
- PostgreSQL: User accounts, track metadata, and playlist storage
- Docker Compose: Container orchestration for streaming services
File Structure
asteroid/
├── asteroid.lisp # Main server with RADIANCE routes
├── asteroid.asd # System definition with dependencies
├── stream-control.lisp # Stream queue management system
├── stream-media.lisp # Media streaming and track management
├── user-management.lisp # User authentication and profiles
├── playlist-management.lisp # User playlist operations
├── auth-routes.lisp # Authentication endpoints
├── stream-queue.m3u # Generated stream queue playlist
├── docker/ # Docker streaming infrastructure
│ ├── docker-compose.yml # Container orchestration
│ ├── asteroid-radio-docker.liq # Liquidsoap configuration
│ └── start.sh # Container startup script
├── template/ # CLIP HTML templates
│ ├── front-page.chtml # Main page with live stream
│ ├── admin.chtml # Admin dashboard with queue controls
│ ├── player.chtml # Web player interface
│ └── login.chtml # User authentication
├── static/ # Frontend assets
│ ├── asteroid.lass # LASS stylesheet source
│ ├── asteroid.css # Compiled CSS
│ └── js/
│ ├── admin.js # Admin interface controls
│ └── player.js # Web player functionality
├── docs/ # Documentation
│ ├── STREAM-CONTROL.org # Queue management guide
│ ├── API-REFERENCE.org # Complete API documentation
│ ├── USER-MANAGEMENT-SYSTEM.org # User system guide
│ └── INSTALLATION.org # Setup instructions
└── music/ # Music library
└── library/ # Music files
Track Upload Workflow
Current Implementation (Manual Upload)
- Copy files to staging: Place MP3/FLAC files in
music/incoming/ - Access admin panel: Navigate to
http://[IP]:8080/asteroid/admin - Process files: Click "Copy Files from Incoming" button
- Database update: Files are moved to
music/library/and metadata extracted - Automatic playlist:
playlist.m3uis regenerated for streaming
File Processing Steps
- Files copied from
music/incoming/tomusic/library/ - Metadata extracted using taglib (title, artist, album, duration, bitrate)
- Database record created with file path and metadata
- Playlist file updated for Liquidsoap streaming
- Files immediately available for on-demand streaming
Supported Formats
- MP3: Primary format, best compatibility
- FLAC: Lossless audio, high quality
- OGG: Open source format
- WAV: Uncompressed audio
Icecast2 Integration
Configuration
- Server: localhost:8000
- Mount point:
/asteroid.mp3 - Password:
b3l0wz3r0(configured in Liquidsoap) - Format: MP3 128kbps stereo
Installation (Ubuntu/Debian)
sudo apt update
sudo apt install icecast2
sudo systemctl enable icecast2
sudo systemctl start icecast2
Stream Access
- Direct URL:
http://[IP]:8000/asteroid.mp3 - Admin interface:
http://[IP]:8000/admin/ - Statistics:
http://[IP]:8000/status.xsl
Liquidsoap Integration
Configuration File: docker/asteroid-radio-docker.liq
#!/usr/bin/liquidsoap
# Allow running as root in Docker
set("init.allow_root", true)
log.level.set(4)
# Enable telnet server for remote control
settings.server.telnet.set(true)
settings.server.telnet.port.set(1234)
settings.server.telnet.bind_addr.set("0.0.0.0")
# Create playlist source from managed stream queue
radio = playlist(
mode="normal", # Play in order (not randomized)
reload=5, # Check for playlist updates every 5 seconds
reload_mode="watch", # Watch file for changes
"/app/stream-queue.m3u"
)
# Fallback to directory scan if queue is empty
radio_fallback = playlist.safe(
mode="randomize",
reload=3600,
"/app/music/"
)
radio = fallback(track_sensitive=false, [radio, radio_fallback])
# Use ReplayGain for consistent volume without pumping
radio = amplify(1.0, override="replaygain", radio)
# Add smooth crossfade between tracks (5 seconds)
radio = crossfade(
duration=5.0,
fade_in=3.0,
fade_out=3.0,
radio
)
# Add compressor to prevent clipping
radio = compress(
ratio=3.0,
threshold=-15.0,
attack=50.0,
release=400.0,
radio
)
# Output to Icecast2 in multiple formats
output.icecast(%mp3(bitrate=128), host="icecast", port=8000,
password="H1tn31EhsyLrfRmo", mount="asteroid.mp3",
name="Asteroid Radio", radio)
output.icecast(%fdkaac(bitrate=96), host="icecast", port=8000,
password="H1tn31EhsyLrfRmo", mount="asteroid.aac",
name="Asteroid Radio (AAC)", radio)
output.icecast(%mp3(bitrate=64), host="icecast", port=8000,
password="H1tn31EhsyLrfRmo", mount="asteroid-low.mp3",
name="Asteroid Radio (Low Quality)", radio)
Installation (Ubuntu/Debian)
sudo apt update
sudo apt install liquidsoap
Features
- Stream queue control: Curated playlist with watch-based reloading (5 second updates)
- Smart fallback: Random playback when queue is empty
- ReplayGain processing: Consistent volume without pumping artifacts
- Crossfading: Smooth 5-second transitions between tracks
- Dynamic compression: Prevents clipping and maintains audio quality
- Multi-format output: AAC 96kbps, MP3 128kbps, MP3 64kbps
- Telnet control: Live DJ operations via port 1234
- Metadata broadcasting: Track info sent to listeners
Network Access
Local Development
- Web Interface:
http://localhost:8080/asteroid/ - Live Stream:
http://localhost:8000/asteroid.mp3 - Admin Panel:
http://localhost:8080/asteroid/admin
WSL Network Access
- WSL IP: Check with
ip addr show eth0 - Web Interface:
http://[WSL-IP]:8080/asteroid/ - Live Stream:
http://[WSL-IP]:8000/asteroid.mp3
Internal Network Broadcasting
- Services bind to all interfaces (0.0.0.0)
- Accessible from any device on local network
- Compatible with media players (VLC, iTunes, etc.)
Usage Instructions
Starting the Radio Station
# Start Docker streaming services
cd docker
docker-compose up -d
# Start Asteroid web application
sbcl --load asteroid.lisp
Stopping the Radio Station
# Stop Docker services
cd docker
docker-compose down
Adding Music
- Copy MP3/FLAC files to
music/incoming/ - Visit admin panel:
http://[IP]:8080/asteroid/admin - Click "Copy Files from Incoming"
- Files are processed and added to streaming playlist
Listening to the Stream
- Web Browser: Visit main page for embedded player
- Media Player: Open
http://[IP]:8000/asteroid.mp3 - Mobile Apps: Use internet radio apps with stream URL
API Endpoints
Track Management
GET /api/asteroid/tracks- List all tracks with paginationGET /api/asteroid/tracks/:id/stream- Stream individual trackPOST /api/asteroid/scan-library- Scan and update music libraryGET /api/asteroid/tracks?search={query}- Search tracks
Stream Queue Control (Admin Only)
GET /api/asteroid/stream/queue- Get current stream queuePOST /api/asteroid/stream/queue/add- Add track to queue (position: end/next)POST /api/asteroid/stream/queue/remove- Remove track from queuePOST /api/asteroid/stream/queue/clear- Clear entire queuePOST /api/asteroid/stream/queue/add-playlist- Add playlist to queuePOST /api/asteroid/stream/queue/reorder- Reorder queue tracksGET /api/asteroid/stream/history- Get stream history
User Management
POST /api/asteroid/auth/register- Register new userPOST /api/asteroid/auth/login- User loginPOST /api/asteroid/auth/logout- User logoutGET /api/asteroid/auth/profile- Get user profileGET /api/asteroid/users- List users (admin only)POST /api/asteroid/users/:id/role- Update user role (admin only)
Playlist Management
GET /api/asteroid/playlists- List user's playlistsPOST /api/asteroid/playlists- Create new playlistGET /api/asteroid/playlists/:id- Get playlist detailsDELETE /api/asteroid/playlists/:id- Delete playlistPOST /api/asteroid/playlists/:id/tracks- Add track to playlistDELETE /api/asteroid/playlists/:id/tracks/:track-id- Remove track from playlist
See docs/API-REFERENCE.org for complete API documentation.
Database Schema
Tracks Table
(db:create "tracks" '((title :text)
(artist :text)
(album :text)
(duration :integer)
(file-path :text)
(format :text)
(bitrate :integer)
(added-date :integer)
(play-count :integer)))
Users Table
(db:create "users" '((username :text)
(email :text)
(password-hash :text)
(role :text) ; "admin" or "user"
(created-at :integer)
(last-login :integer)))
Playlists Table
(db:create "playlists" '((name :text)
(description :text)
(user-id :integer)
(created-at :integer)
(track-ids :text))) ; JSON array of track IDs
Dependencies
Lisp Dependencies (asteroid.asd)
:radiance- Web framework:r-clip- Templating system:lass- CSS generation:cl-json- JSON handling:alexandria- Utilities:local-time- Time handling
System Dependencies
icecast2- Streaming serverliquidsoap- Audio processingtaglib- Metadata extraction (via audio-streams)
Development Notes
RADIANCE Configuration
- Domain: "asteroid"
- Routes use
#@syntax for URL patterns - Database abstraction via
db:functions - CLIP templates with
data-textattributes
Database Queries
- Use quoted symbols for field names:
(:'_id id)= - RADIANCE returns hash tables with string keys
- Primary key is "_id" internally, "id" in JSON responses
Streaming Considerations
- MP3 files with spaces in names require playlist.m3u approach
- Liquidsoap fallback prevents stream silence
- Icecast2 mount points must match Liquidsoap configuration
Future Enhancements
Planned Features
- Web UI for drag-and-drop queue management
- Real-time now-playing display with WebSocket updates
- Direct browser file uploads with progress bars
- Listener statistics and analytics dashboard
- Scheduled programming and automation
- Social features (playlist sharing, discovery)
- Mobile native applications
Technical Improvements
- WebSocket integration for real-time updates
- Telnet integration for skip/next commands from web UI
- Auto-queue filling (add tracks when queue runs low)
- Genre-based smart queues
- Listener request system
- Full-text search capabilities
Troubleshooting
Common Issues
- No audio in stream: Check Liquidsoap logs, verify MP3 files
- Database errors: Ensure proper field name quoting in queries
- Network access: Verify WSL IP and firewall settings
- File upload issues: Check permissions on music directories
Debugging
- Enable Liquidsoap debug logging:
settings.log.level :4= - Check Icecast admin interface for stream status
- Monitor RADIANCE logs for web server issues
- Verify database connectivity and collections
License
This implementation maintains compatibility with the original Asteroid Radio project license while adding comprehensive streaming capabilities for internet radio broadcasting.