refactor: improve code consistency and maintainability

- Add /api/asteroid/partial/now-playing-inline endpoint for inline text
- Refactor admin.js to use server-side partial (removes 23 lines of JSON/XML parsing)
- Fix hardcoded path in convert-to-docker-path to use *music-library-path* variable
- Consistent with front-page and player refactoring from upstream
- Improves portability and reduces client-side JavaScript complexity
This commit is contained in:
glenneth 2025-10-17 05:29:47 +03:00 committed by Brian O'Reilly
parent 4d0b54f7d6
commit b3fd00cb4d
3 changed files with 30 additions and 25 deletions

View File

@ -53,3 +53,18 @@
(api-output `(("status" . "error")
("message" . ,(format nil "Error loading profile: ~a" e)))
:status 500))))
(define-api asteroid/partial/now-playing-inline () ()
"Get inline text with now playing info (for admin dashboard and widgets)"
(handler-case
(let ((now-playing-stats (icecast-now-playing *stream-base-url*)))
(if now-playing-stats
(progn
(setf (header "Content-Type") "text/plain")
(cdr (assoc :title now-playing-stats)))
(progn
(setf (header "Content-Type") "text/plain")
"Stream Offline")))
(error (e)
(setf (header "Content-Type") "text/plain")
"Error loading stream info")))

View File

@ -561,35 +561,25 @@ function displayQueueSearchResults(results) {
// Live stream info update
async function updateLiveStreamInfo() {
try {
const response = await fetch('/api/asteroid/icecast-status');
if (!response.ok) {
const response = await fetch('/api/asteroid/partial/now-playing-inline');
const contentType = response.headers.get("content-type");
if (!contentType.includes('text/plain')) {
console.error('Unexpected content type:', contentType);
return;
}
const result = await response.json();
const nowPlayingText = await response.text();
const nowPlayingEl = document.getElementById('live-now-playing');
// Handle Radiance API response format
const data = result.data || result;
// Sources are nested in icestats
const sources = data.icestats?.source;
if (sources) {
const mainStream = Array.isArray(sources)
? sources.find(s => s.listenurl?.includes('/asteroid.aac') || s.listenurl?.includes('/asteroid.mp3'))
: sources;
if (mainStream && mainStream.title) {
const nowPlayingEl = document.getElementById('live-now-playing');
if (nowPlayingEl) {
const parts = mainStream.title.split(' - ');
const artist = parts[0] || 'Unknown';
const track = parts.slice(1).join(' - ') || 'Unknown';
nowPlayingEl.textContent = `${artist} - ${track}`;
}
}
if (nowPlayingEl) {
nowPlayingEl.textContent = nowPlayingText;
}
} catch (error) {
console.error('Could not fetch stream info:', error);
const nowPlayingEl = document.getElementById('live-now-playing');
if (nowPlayingEl) {
nowPlayingEl.textContent = 'Error loading stream info';
}
}
}

View File

@ -72,8 +72,8 @@
(defun convert-to-docker-path (host-path)
"Convert host file path to Docker container path"
;; Replace /home/glenn/Projects/Code/asteroid/music/library/ with /app/music/
(let ((library-prefix "/home/glenn/Projects/Code/asteroid/music/library/"))
;; Replace the music library path with /app/music/
(let ((library-prefix (namestring *music-library-path*)))
(if (and (stringp host-path)
(>= (length host-path) (length library-prefix))
(string= host-path library-prefix :end1 (length library-prefix)))