feat: add HTML partial hidration for now-playing
This commit is contained in:
parent
136fa2fa74
commit
d0efc89e33
|
|
@ -40,4 +40,5 @@
|
|||
(:file "playlist-management")
|
||||
(:file "stream-control")
|
||||
(:file "auth-routes")
|
||||
(:file "frontend-partials")
|
||||
(:file "asteroid")))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
(in-package :asteroid)
|
||||
|
||||
(defun icecast-now-playing (icecast-base-url)
|
||||
(let* ((icecast-url (concatenate 'string icecast-base-url "/admin/stats.xml"))
|
||||
(response (drakma:http-request icecast-url
|
||||
:want-stream nil
|
||||
:basic-authorization '("admin" "asteroid_admin_2024"))))
|
||||
(when response
|
||||
(let ((xml-string (if (stringp response)
|
||||
response
|
||||
(babel:octets-to-string response :encoding :utf-8))))
|
||||
;; Simple XML parsing to extract source information
|
||||
;; Look for <source mount="/asteroid.mp3"> sections and extract title, listeners, etc.
|
||||
(multiple-value-bind (match-start match-end)
|
||||
(cl-ppcre:scan "<source mount=\"/asteroid\\.mp3\">" xml-string)
|
||||
|
||||
(if match-start
|
||||
(let* ((source-section (subseq xml-string match-start
|
||||
(or (cl-ppcre:scan "</source>" xml-string :start match-start)
|
||||
(length xml-string))))
|
||||
(titlep (cl-ppcre:all-matches "<title>" source-section))
|
||||
(listenersp (cl-ppcre:all-matches "<listeners>" source-section))
|
||||
(title (if titlep (cl-ppcre:regex-replace-all ".*<title>(.*?)</title>.*" source-section "\\1") "Unknown"))
|
||||
(listeners (if listenersp (cl-ppcre:regex-replace-all ".*<listeners>(.*?)</listeners>.*" source-section "\\1") "0")))
|
||||
`((:listenurl . ,(concatenate 'string *stream-base-url* "/asteroid.mp3"))
|
||||
(:title . ,title)
|
||||
(:listeners . ,(parse-integer listeners :junk-allowed t))))
|
||||
`((:listenurl . ,(concatenate 'string *stream-base-url* "/asteroid.mp3"))
|
||||
(:title . "Unknown")
|
||||
(:listeners . "Unknown"))))))))
|
||||
|
||||
(define-api asteroid/partial/now-playing () ()
|
||||
"Get Partial HTML with live status from Icecast server"
|
||||
(handler-case
|
||||
(let ((now-playing-stats (icecast-now-playing *stream-base-url*))
|
||||
(template-path (merge-pathnames "template/partial/now-playing.chtml"
|
||||
(asdf:system-source-directory :asteroid))))
|
||||
(if now-playing-stats
|
||||
(progn
|
||||
;; TODO: it should be able to define a custom api-output for this
|
||||
;; (api-output <clip-parser> :format "html"))
|
||||
(setf (header "Content-Type") "text/html")
|
||||
(clip:process-to-string
|
||||
(plump:parse (alexandria:read-file-into-string template-path))
|
||||
:stats now-playing-stats))
|
||||
(progn
|
||||
(setf (header "Content-Type") "text/html")
|
||||
(clip:process-to-string
|
||||
(plump:parse (alexandria:read-file-into-string template-path))
|
||||
:connection-error t
|
||||
:stats nil))))
|
||||
(error (e)
|
||||
(api-output `(("status" . "error")
|
||||
("message" . ,(format nil "Error loading profile: ~a" e)))
|
||||
:status 500))))
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<h2>Now Playing</h2>
|
||||
<c:if test="stats">
|
||||
<c:then>
|
||||
<c:using value="stats">
|
||||
<!--<p>Artist: <span>The Void</span></p>-->
|
||||
<p>Track: <span lquery="(text title)">The Void - Silence</span></p>
|
||||
<p>Listeners: <span lquery="(text listeners)">1</span></p>
|
||||
</c:using>
|
||||
</c:then>
|
||||
<c:else>
|
||||
<c:if test="connection-error">
|
||||
<c:then>
|
||||
<div class="message error">
|
||||
<span>There was an error trying to get information from stream.</span>
|
||||
</div>
|
||||
</c:then>
|
||||
</c:if>
|
||||
<p>Track: <span>NA</span></p>
|
||||
<p>Listeners: <span>NA</span></p>
|
||||
</c:else>
|
||||
</c:if>
|
||||
Loading…
Reference in New Issue