feat: Add Liquidsoap DJ controls via telnet integration

- Implement 5 DJ control API endpoints (skip, reload, queue, metadata, queue-status)
- Update Liquidsoap config to support dynamic track queuing with request.queue
- Add comprehensive DJ control tests to test-server.sh with dynamic track ID fetching
- Add test result logging with timestamped log files
- Update .gitignore to exclude test result logs
- Change liquidsoap-queue-track to use queue.push command
This commit is contained in:
glenneth 2025-10-12 06:34:37 +03:00 committed by Glenn Thompson
parent 78fa57012b
commit f101ff5757
4 changed files with 110 additions and 6 deletions

1
.gitignore vendored
View File

@ -44,5 +44,6 @@ docker-compose.yml.backup.*
*.log *.log
logs/ logs/
performance-logs/ performance-logs/
test-results-*.log
# Temporary files # Temporary files

View File

@ -334,7 +334,7 @@
(defun liquidsoap-queue-track (file-path) (defun liquidsoap-queue-track (file-path)
"Queue a specific track in Liquidsoap" "Queue a specific track in Liquidsoap"
(liquidsoap-telnet-command (format nil "request.push ~A" file-path))) (liquidsoap-telnet-command (format nil "queue.push ~A" file-path)))
(defun parse-liquidsoap-metadata (metadata-string) (defun parse-liquidsoap-metadata (metadata-string)
"Parse Liquidsoap metadata string into artist/title/album" "Parse Liquidsoap metadata string into artist/title/album"

View File

@ -19,10 +19,13 @@ settings.server.telnet.set(true)
settings.server.telnet.port.set(1234) settings.server.telnet.port.set(1234)
settings.server.telnet.bind_addr.set("0.0.0.0") settings.server.telnet.bind_addr.set("0.0.0.0")
# Create request queue for dynamic track queuing (DJ controls)
queue = request.queue(id="queue")
# Create playlist source from generated M3U file # Create playlist source from generated M3U file
# This file is managed by Asteroid's stream control system # This file is managed by Asteroid's stream control system
# Falls back to directory scan if playlist file doesn't exist playlist_managed = playlist(
radio = playlist( id="managed_playlist",
mode="normal", # Play in order (not randomized) mode="normal", # Play in order (not randomized)
reload=30, # Check for playlist updates every 30 seconds reload=30, # Check for playlist updates every 30 seconds
reload_mode="seconds", # Reload every N seconds (prevents running out of tracks) reload_mode="seconds", # Reload every N seconds (prevents running out of tracks)
@ -30,14 +33,19 @@ radio = playlist(
) )
# Fallback to directory scan if playlist file is empty/missing # Fallback to directory scan if playlist file is empty/missing
radio_fallback = playlist.safe( playlist_fallback = playlist.safe(
id="music",
mode="randomize", mode="randomize",
reload=3600, reload=3600,
"/app/music/" "/app/music/"
) )
# Use main playlist, fall back to directory scan # Combine sources: queue (highest priority), managed playlist, then fallback to directory scan
radio = fallback(track_sensitive=false, [radio, radio_fallback]) radio = fallback(track_sensitive=true, [queue, playlist_managed, playlist_fallback])
# Add some audio processing
radio = amplify(1.0, radio)
radio = normalize(radio)
# Simple crossfade for smooth transitions # Simple crossfade for smooth transitions
radio = crossfade( radio = crossfade(

View File

@ -15,6 +15,7 @@ NC='\033[0m' # No Color
BASE_URL="${ASTEROID_URL:-http://localhost:8080}" BASE_URL="${ASTEROID_URL:-http://localhost:8080}"
API_BASE="${BASE_URL}/api/asteroid" API_BASE="${BASE_URL}/api/asteroid"
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
LOG_FILE="test-results-$(date +%Y%m%d-%H%M%S).log"
# Test counters # Test counters
TESTS_RUN=0 TESTS_RUN=0
@ -22,28 +23,39 @@ TESTS_PASSED=0
TESTS_FAILED=0 TESTS_FAILED=0
# Helper functions # Helper functions
log_to_file() {
# Strip ANSI color codes for log file
echo "$1" | sed 's/\x1b\[[0-9;]*m//g' >> "$LOG_FILE"
}
print_header() { print_header() {
local msg="\n========================================\n$1\n========================================\n"
echo -e "\n${BLUE}========================================${NC}" echo -e "\n${BLUE}========================================${NC}"
echo -e "${BLUE}$1${NC}" echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}========================================${NC}\n" echo -e "${BLUE}========================================${NC}\n"
log_to_file "$msg"
} }
print_test() { print_test() {
echo -e "${YELLOW}TEST:${NC} $1" echo -e "${YELLOW}TEST:${NC} $1"
log_to_file "TEST: $1"
} }
print_pass() { print_pass() {
echo -e "${GREEN}✓ PASS:${NC} $1" echo -e "${GREEN}✓ PASS:${NC} $1"
log_to_file "✓ PASS: $1"
TESTS_PASSED=$((TESTS_PASSED + 1)) TESTS_PASSED=$((TESTS_PASSED + 1))
} }
print_fail() { print_fail() {
echo -e "${RED}✗ FAIL:${NC} $1" echo -e "${RED}✗ FAIL:${NC} $1"
log_to_file "✗ FAIL: $1"
TESTS_FAILED=$((TESTS_FAILED + 1)) TESTS_FAILED=$((TESTS_FAILED + 1))
} }
print_info() { print_info() {
echo -e "${BLUE}INFO:${NC} $1" echo -e "${BLUE}INFO:${NC} $1"
log_to_file "INFO: $1"
} }
# Test function wrapper # Test function wrapper
@ -212,6 +224,66 @@ test_playlist_endpoints() {
print_info "Note: Playlist creation requires authentication" print_info "Note: Playlist creation requires authentication"
} }
# Test DJ Control Endpoints (Liquidsoap telnet integration)
test_dj_control_endpoints() {
print_header "Testing DJ Control Endpoints"
print_info "Note: DJ control endpoints require admin authentication"
# Test metadata endpoint (available to authenticated users)
test_api_endpoint "/dj/metadata" \
"DJ metadata endpoint" \
"metadata"
# Test queue status endpoint
test_api_endpoint "/dj/queue-status" \
"DJ queue status endpoint" \
"queue"
# Test skip track endpoint (requires admin)
run_test "DJ skip track endpoint"
local skip_response=$(curl -s -X POST "${API_BASE}/dj/skip")
if echo "$skip_response" | grep -q "status"; then
print_pass "DJ skip track endpoint responds"
else
print_fail "DJ skip track endpoint not responding"
fi
# Test reload playlist endpoint (requires admin)
run_test "DJ reload playlist endpoint"
local reload_response=$(curl -s -X POST "${API_BASE}/dj/reload-playlist")
if echo "$reload_response" | grep -q "status"; then
print_pass "DJ reload playlist endpoint responds"
else
print_fail "DJ reload playlist endpoint not responding"
fi
# Test queue track endpoint with dynamic track ID
run_test "DJ queue track endpoint"
# Fetch a random track ID from the database
local track_response=$(curl -s "${API_BASE}/tracks?page=1&per-page=1")
# Extract track ID using grep (works without jq)
local track_id=$(echo "$track_response" | grep -o '"id":[0-9]*' | head -1 | grep -o '[0-9]*')
if [ -n "$track_id" ]; then
print_info "Using track ID: $track_id for queue test"
local queue_response=$(curl -s -X POST "${API_BASE}/dj/queue?track-id=${track_id}")
if echo "$queue_response" | grep -q "queued successfully\|Track not found"; then
print_pass "DJ queue track endpoint responds (track ID: $track_id)"
else
print_fail "DJ queue track endpoint not responding properly"
if [ $VERBOSE -eq 1 ]; then
echo "Response: $queue_response"
fi
fi
else
print_info "No tracks available in database, skipping queue test"
fi
}
# Test Page Endpoints (HTML pages) # Test Page Endpoints (HTML pages)
test_page_endpoints() { test_page_endpoints() {
print_header "Testing HTML Page Endpoints" print_header "Testing HTML Page Endpoints"
@ -278,21 +350,42 @@ test_api_format() {
print_summary() { print_summary() {
print_header "Test Summary" print_header "Test Summary"
local summary="Tests Run: $TESTS_RUN\nTests Passed: $TESTS_PASSED\nTests Failed: $TESTS_FAILED"
echo "Tests Run: $TESTS_RUN" echo "Tests Run: $TESTS_RUN"
echo -e "Tests Passed: ${GREEN}$TESTS_PASSED${NC}" echo -e "Tests Passed: ${GREEN}$TESTS_PASSED${NC}"
echo -e "Tests Failed: ${RED}$TESTS_FAILED${NC}" echo -e "Tests Failed: ${RED}$TESTS_FAILED${NC}"
log_to_file "$summary"
if [ $TESTS_FAILED -eq 0 ]; then if [ $TESTS_FAILED -eq 0 ]; then
echo -e "\n${GREEN}✓ All tests passed!${NC}\n" echo -e "\n${GREEN}✓ All tests passed!${NC}\n"
log_to_file "\n✓ All tests passed!\n"
echo -e "${BLUE}Log file saved to: ${LOG_FILE}${NC}\n"
exit 0 exit 0
else else
echo -e "\n${RED}✗ Some tests failed${NC}\n" echo -e "\n${RED}✗ Some tests failed${NC}\n"
log_to_file "\n✗ Some tests failed\n"
echo -e "${BLUE}Log file saved to: ${LOG_FILE}${NC}\n"
exit 1 exit 1
fi fi
} }
# Main test execution # Main test execution
main() { main() {
# Initialize log file with header
cat > "$LOG_FILE" << EOF
╔═══════════════════════════════════════════════════════════════╗
║ Asteroid Radio Server Test Suite ║
║ Test Results Log ║
╚═══════════════════════════════════════════════════════════════╝
Test Run Date: $(date '+%Y-%m-%d %H:%M:%S')
Server URL: ${BASE_URL}
API Base: ${API_BASE}
Verbose Mode: ${VERBOSE}
EOF
echo -e "${BLUE}" echo -e "${BLUE}"
echo "╔═══════════════════════════════════════╗" echo "╔═══════════════════════════════════════╗"
echo "║ Asteroid Radio Server Test Suite ║" echo "║ Asteroid Radio Server Test Suite ║"
@ -301,6 +394,7 @@ main() {
print_info "Testing server at: ${BASE_URL}" print_info "Testing server at: ${BASE_URL}"
print_info "Verbose mode: ${VERBOSE}" print_info "Verbose mode: ${VERBOSE}"
print_info "Log file: ${LOG_FILE}"
echo "" echo ""
# Run all test suites # Run all test suites
@ -310,6 +404,7 @@ main() {
test_track_endpoints test_track_endpoints
test_player_endpoints test_player_endpoints
test_playlist_endpoints test_playlist_endpoints
test_dj_control_endpoints
test_admin_endpoints test_admin_endpoints
test_page_endpoints test_page_endpoints
test_static_files test_static_files