From 22b2a2d87e7e914f504997cbc6068b5fff66e562 Mon Sep 17 00:00:00 2001 From: Glenn Thompson Date: Tue, 9 Dec 2025 09:32:30 +0300 Subject: [PATCH] Add Liquidsoap/Icecast controls, fix library scan - Add Liquidsoap control panel: status display, skip track, reload playlist, restart container - Add Icecast restart button to System Status section - Remove redundant Web Player Control section from admin - Fix music library scan to follow symlinks (truename resolution) - Fix database timestamp error (let PostgreSQL default handle added-date) - Update docker-compose mount for stream-queue.m3u - Clean up playlist path handling --- asteroid.lisp | 240 +++++++++++++++ docker/docker-compose.yml | 2 +- parenscript/admin.lisp | 340 +++++++++++++++++--- playlists/Asteroid-Low-Orbit.m3u | 259 ++++++---------- playlists/stream-queue.m3u | 513 +++++++++---------------------- stream-media.lisp | 21 +- template/admin.ctml | 89 ++++-- 7 files changed, 858 insertions(+), 606 deletions(-) diff --git a/asteroid.lisp b/asteroid.lisp index 0926c70..7e23387 100644 --- a/asteroid.lisp +++ b/asteroid.lisp @@ -303,6 +303,246 @@ ("message" . "Queue loaded from M3U file") ("count" . ,count)))))) +;;; Playlist File Management APIs +;;; These manage .m3u files in the playlists/ directory +;;; stream-queue.m3u lives at PROJECT ROOT (for Docker mount), saved playlists in playlists/ + +(defun get-playlists-directory () + "Get the path to the playlists directory (for saved playlists)" + (merge-pathnames "playlists/" (asdf:system-source-directory :asteroid))) + +(defun get-stream-queue-path () + "Get the path to stream-queue.m3u (in playlists/ directory for Docker mount)" + (merge-pathnames "playlists/stream-queue.m3u" (asdf:system-source-directory :asteroid))) + +(defun list-playlist-files () + "List all .m3u files in the playlists directory, excluding stream-queue.m3u" + (let ((playlist-dir (get-playlists-directory))) + (when (probe-file playlist-dir) + (remove-if (lambda (path) + (string= (file-namestring path) "stream-queue.m3u")) + (directory (merge-pathnames "*.m3u" playlist-dir)))))) + +(defun read-m3u-file-paths (filepath) + "Read an m3u file and return list of file paths (excluding comments)" + (when (probe-file filepath) + (with-open-file (stream filepath :direction :input) + (loop for line = (read-line stream nil) + while line + unless (or (string= line "") + (and (> (length line) 0) (char= (char line 0) #\#))) + collect (string-trim '(#\Space #\Tab #\Return #\Newline) line))))) + +(defun copy-playlist-to-stream-queue (source-path) + "Copy a playlist file to stream-queue.m3u at project root" + (let ((dest-path (get-stream-queue-path))) + (with-open-file (in source-path :direction :input) + (with-open-file (out dest-path :direction :output + :if-exists :supersede + :if-does-not-exist :create) + (loop for line = (read-line in nil) + while line + do (write-line line out)))) + t)) + +(define-api asteroid/stream/playlists () () + "List available playlist files (excluding stream-queue.m3u)" + (require-role :admin) + (with-error-handling + (let ((files (list-playlist-files))) + (api-output `(("status" . "success") + ("playlists" . ,(mapcar (lambda (path) + (file-namestring path)) + files))))))) + +(define-api asteroid/stream/playlists/load (name) () + "Load a playlist file into stream-queue.m3u and return its contents" + (require-role :admin) + (with-error-handling + (let* ((playlist-path (merge-pathnames name (get-playlists-directory))) + (stream-queue-path (get-stream-queue-path))) + (if (probe-file playlist-path) + (progn + ;; Copy playlist to stream-queue.m3u + (copy-playlist-to-stream-queue playlist-path) + ;; Load into in-memory queue + (let ((count (load-queue-from-m3u-file))) + (api-output `(("status" . "success") + ("message" . ,(format nil "Loaded playlist: ~a" name)) + ("count" . ,count) + ("paths" . ,(read-m3u-file-paths stream-queue-path)))))) + (api-output `(("status" . "error") + ("message" . "Playlist file not found")) + :status 404))))) + +(define-api asteroid/stream/playlists/save () () + "Save current stream queue to stream-queue.m3u" + (require-role :admin) + (with-error-handling + (regenerate-stream-playlist) + (api-output `(("status" . "success") + ("message" . "Stream queue saved"))))) + +(define-api asteroid/stream/playlists/save-as (name) () + "Save current stream queue to a new playlist file" + (require-role :admin) + (with-error-handling + (let* ((safe-name (if (cl-ppcre:scan "\\.m3u$" name) name (format nil "~a.m3u" name))) + (playlist-path (merge-pathnames safe-name (get-playlists-directory)))) + ;; Generate playlist to the new file + (generate-m3u-playlist *stream-queue* playlist-path) + ;; Also save to stream-queue.m3u + (regenerate-stream-playlist) + (api-output `(("status" . "success") + ("message" . ,(format nil "Saved as: ~a" safe-name))))))) + +(define-api asteroid/stream/playlists/clear () () + "Clear stream-queue.m3u (Liquidsoap will fall back to random)" + (require-role :admin) + (with-error-handling + (let ((stream-queue-path (get-stream-queue-path))) + ;; Write empty m3u file + (with-open-file (out stream-queue-path :direction :output + :if-exists :supersede + :if-does-not-exist :create) + (format out "#EXTM3U~%")) + ;; Clear in-memory queue + (setf *stream-queue* '()) + (api-output `(("status" . "success") + ("message" . "Stream queue cleared - Liquidsoap will use random playback")))))) + +(define-api asteroid/stream/playlists/current () () + "Get current stream-queue.m3u contents with track info" + (require-role :admin) + (with-error-handling + (let* ((stream-queue-path (get-stream-queue-path)) + (paths (read-m3u-file-paths stream-queue-path)) + (all-tracks (dm:get "tracks" (db:query :all)))) + (api-output `(("status" . "success") + ("count" . ,(length paths)) + ("tracks" . ,(mapcar (lambda (docker-path) + (let* ((host-path (convert-from-docker-path docker-path)) + (track (find-if + (lambda (trk) + (string= (dm:field trk "file-path") host-path)) + all-tracks))) + (if track + `(("id" . ,(dm:id track)) + ("title" . ,(dm:field track "title")) + ("artist" . ,(dm:field track "artist")) + ("album" . ,(dm:field track "album")) + ("path" . ,docker-path)) + `(("id" . nil) + ("title" . ,(file-namestring docker-path)) + ("artist" . "Unknown") + ("album" . "Unknown") + ("path" . ,docker-path))))) + paths))))))) + +;;; Liquidsoap Control APIs +;;; Control Liquidsoap via telnet interface on port 1234 + +(defun liquidsoap-command (command) + "Send a command to Liquidsoap via telnet and return the response" + (handler-case + (let ((result (uiop:run-program + (format nil "echo '~a' | nc -q1 127.0.0.1 1234" command) + :output :string + :error-output :string + :ignore-error-status t))) + ;; Remove the trailing "END" line + (let ((lines (cl-ppcre:split "\\n" result))) + (string-trim '(#\Space #\Newline #\Return) + (format nil "~{~a~^~%~}" + (remove-if (lambda (l) (string= (string-trim '(#\Space #\Return) l) "END")) + lines))))) + (error (e) + (format nil "Error: ~a" e)))) + +(defun parse-liquidsoap-metadata (raw-metadata) + "Parse Liquidsoap metadata string and extract current track info" + (when (and raw-metadata (> (length raw-metadata) 0)) + ;; The metadata contains multiple tracks, separated by --- N --- + ;; --- 1 --- is the CURRENT track (most recent), at the end of the output + ;; Split by --- N --- pattern and get the last section + (let* ((sections (cl-ppcre:split "---\\s*\\d+\\s*---" raw-metadata)) + (current-section (car (last sections)))) + (when current-section + (let ((artist (cl-ppcre:register-groups-bind (val) + ("artist=\"([^\"]+)\"" current-section) val)) + (title (cl-ppcre:register-groups-bind (val) + ("title=\"([^\"]+)\"" current-section) val)) + (album (cl-ppcre:register-groups-bind (val) + ("album=\"([^\"]+)\"" current-section) val))) + (if (or artist title) + (format nil "~@[~a~]~@[ - ~a~]~@[ (~a)~]" + artist title album) + "Unknown")))))) + +(defun format-remaining-time (seconds-str) + "Format remaining seconds as MM:SS" + (handler-case + (let ((seconds (parse-integer (cl-ppcre:regex-replace "\\..*" seconds-str "")))) + (format nil "~d:~2,'0d" (floor seconds 60) (mod seconds 60))) + (error () seconds-str))) + +(define-api asteroid/liquidsoap/status () () + "Get Liquidsoap status including uptime and current track" + (require-role :admin) + (with-error-handling + (let ((uptime (liquidsoap-command "uptime")) + (metadata-raw (liquidsoap-command "output.icecast.1.metadata")) + (remaining-raw (liquidsoap-command "output.icecast.1.remaining"))) + (api-output `(("status" . "success") + ("uptime" . ,(string-trim '(#\Space #\Newline #\Return) uptime)) + ("metadata" . ,(parse-liquidsoap-metadata metadata-raw)) + ("remaining" . ,(format-remaining-time + (string-trim '(#\Space #\Newline #\Return) remaining-raw)))))))) + +(define-api asteroid/liquidsoap/skip () () + "Skip the current track in Liquidsoap" + (require-role :admin) + (with-error-handling + (let ((result (liquidsoap-command "stream-queue_m3u.skip"))) + (api-output `(("status" . "success") + ("message" . "Track skipped") + ("result" . ,(string-trim '(#\Space #\Newline #\Return) result))))))) + +(define-api asteroid/liquidsoap/reload () () + "Force Liquidsoap to reload the playlist" + (require-role :admin) + (with-error-handling + (let ((result (liquidsoap-command "stream-queue_m3u.reload"))) + (api-output `(("status" . "success") + ("message" . "Playlist reloaded") + ("result" . ,(string-trim '(#\Space #\Newline #\Return) result))))))) + +(define-api asteroid/liquidsoap/restart () () + "Restart the Liquidsoap Docker container" + (require-role :admin) + (with-error-handling + (let ((result (uiop:run-program + "docker restart asteroid-liquidsoap" + :output :string + :error-output :string + :ignore-error-status t))) + (api-output `(("status" . "success") + ("message" . "Liquidsoap container restarting") + ("result" . ,result)))))) + +(define-api asteroid/icecast/restart () () + "Restart the Icecast Docker container" + (require-role :admin) + (with-error-handling + (let ((result (uiop:run-program + "docker restart asteroid-icecast" + :output :string + :error-output :string + :ignore-error-status t))) + (api-output `(("status" . "success") + ("message" . "Icecast container restarting") + ("result" . ,result)))))) + (defun get-track-by-id (track-id) "Get a track by its ID - handles type mismatches" (dm:get-one "tracks" (db:query (:= '_id track-id)))) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 0fffe6d..db5a919 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -26,7 +26,7 @@ services: volumes: - ${MUSIC_LIBRARY:-../music/library}:/app/music:ro - ./asteroid-radio-docker.liq:/app/asteroid-radio.liq:ro - - ${QUEUE_PLAYLIST:-../stream-queue.m3u}:/app/stream-queue.m3u:ro + - ${QUEUE_PLAYLIST:-../playlists/stream-queue.m3u}:/app/stream-queue.m3u:ro restart: unless-stopped networks: - asteroid-network diff --git a/parenscript/admin.lisp b/parenscript/admin.lisp index 08b6391..a1a58aa 100644 --- a/parenscript/admin.lisp +++ b/parenscript/admin.lisp @@ -23,11 +23,12 @@ "DOMContentLoaded" (lambda () (load-tracks) - (update-player-status) (setup-event-listeners) - (load-stream-queue) - ;; Update player status every 5 seconds - (set-interval update-player-status 5000)))) + (load-playlist-list) + (load-current-queue) + (refresh-liquidsoap-status) + ;; Update Liquidsoap status every 10 seconds + (set-interval refresh-liquidsoap-status 10000)))) ;; Setup all event listeners (defun setup-event-listeners () @@ -70,21 +71,52 @@ ;; Queue controls (let ((refresh-queue-btn (ps:chain document (get-element-by-id "refresh-queue"))) - (load-m3u-btn (ps:chain document (get-element-by-id "load-from-m3u"))) (clear-queue-btn (ps:chain document (get-element-by-id "clear-queue-btn"))) + (save-queue-btn (ps:chain document (get-element-by-id "save-queue-btn"))) + (save-as-btn (ps:chain document (get-element-by-id "save-as-btn"))) (add-random-btn (ps:chain document (get-element-by-id "add-random-tracks"))) - (queue-search-input (ps:chain document (get-element-by-id "queue-track-search")))) + (queue-search-input (ps:chain document (get-element-by-id "queue-track-search"))) + ;; Playlist controls + (playlist-select (ps:chain document (get-element-by-id "playlist-select"))) + (load-playlist-btn (ps:chain document (get-element-by-id "load-playlist-btn"))) + (refresh-playlists-btn (ps:chain document (get-element-by-id "refresh-playlists-btn")))) (when refresh-queue-btn - (ps:chain refresh-queue-btn (add-event-listener "click" load-stream-queue))) - (when load-m3u-btn - (ps:chain load-m3u-btn (add-event-listener "click" load-queue-from-m3u))) + (ps:chain refresh-queue-btn (add-event-listener "click" load-current-queue))) (when clear-queue-btn (ps:chain clear-queue-btn (add-event-listener "click" clear-stream-queue))) + (when save-queue-btn + (ps:chain save-queue-btn (add-event-listener "click" save-stream-queue))) + (when save-as-btn + (ps:chain save-as-btn (add-event-listener "click" save-queue-as-new))) (when add-random-btn (ps:chain add-random-btn (add-event-listener "click" add-random-tracks))) (when queue-search-input - (ps:chain queue-search-input (add-event-listener "input" search-tracks-for-queue))))) + (ps:chain queue-search-input (add-event-listener "input" search-tracks-for-queue))) + ;; Playlist controls + (when load-playlist-btn + (ps:chain load-playlist-btn (add-event-listener "click" load-selected-playlist))) + (when refresh-playlists-btn + (ps:chain refresh-playlists-btn (add-event-listener "click" load-playlist-list)))) + + ;; Liquidsoap controls + (let ((ls-refresh-btn (ps:chain document (get-element-by-id "ls-refresh-status"))) + (ls-skip-btn (ps:chain document (get-element-by-id "ls-skip"))) + (ls-reload-btn (ps:chain document (get-element-by-id "ls-reload"))) + (ls-restart-btn (ps:chain document (get-element-by-id "ls-restart")))) + (when ls-refresh-btn + (ps:chain ls-refresh-btn (add-event-listener "click" refresh-liquidsoap-status))) + (when ls-skip-btn + (ps:chain ls-skip-btn (add-event-listener "click" liquidsoap-skip))) + (when ls-reload-btn + (ps:chain ls-reload-btn (add-event-listener "click" liquidsoap-reload))) + (when ls-restart-btn + (ps:chain ls-restart-btn (add-event-listener "click" liquidsoap-restart)))) + + ;; Icecast restart + (let ((icecast-restart-btn (ps:chain document (get-element-by-id "icecast-restart")))) + (when icecast-restart-btn + (ps:chain icecast-restart-btn (add-event-listener "click" icecast-restart))))) ;; Load tracks from API (defun load-tracks () @@ -406,44 +438,6 @@ (setf html (+ html "")) (setf (ps:@ container inner-h-t-m-l) html)))))) - ;; Clear stream queue - (defun clear-stream-queue () - (unless (confirm "Clear the entire stream queue? This will stop playback until new tracks are added.") - (return)) - - (ps:chain - (fetch "/api/asteroid/stream/queue/clear" (ps:create :method "POST")) - (then (lambda (response) (ps:chain response (json)))) - (then (lambda (result) - (let ((data (or (ps:@ result data) result))) - (if (= (ps:@ data status) "success") - (progn - (alert "Queue cleared successfully") - (load-stream-queue)) - (alert (+ "Error clearing queue: " (or (ps:@ data message) "Unknown error"))))))) - (catch (lambda (error) - (ps:chain console (error "Error clearing queue:" error)) - (alert "Error clearing queue"))))) - - ;; Load queue from M3U file - (defun load-queue-from-m3u () - (unless (confirm "Load queue from stream-queue.m3u file? This will replace the current queue.") - (return)) - - (ps:chain - (fetch "/api/asteroid/stream/queue/load-m3u" (ps:create :method "POST")) - (then (lambda (response) (ps:chain response (json)))) - (then (lambda (result) - (let ((data (or (ps:@ result data) result))) - (if (= (ps:@ data status) "success") - (progn - (alert (+ "Successfully loaded " (ps:@ data count) " tracks from M3U file!")) - (load-stream-queue)) - (alert (+ "Error loading from M3U: " (or (ps:@ data message) "Unknown error"))))))) - (catch (lambda (error) - (ps:chain console (error "Error loading from M3U:" error)) - (alert (+ "Error loading from M3U: " (ps:@ error message))))))) - ;; Move track up in queue (defun move-track-up (index) (when (= index 0) (return)) @@ -610,6 +604,256 @@ (setf html (+ html "")) (setf (ps:@ container inner-h-t-m-l) html)))))) + ;; ======================================== + ;; Playlist File Management + ;; ======================================== + + ;; Load list of available playlists into dropdown + (defun load-playlist-list () + (ps:chain + (fetch "/api/asteroid/stream/playlists") + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (when (= (ps:@ data status) "success") + (let ((select (ps:chain document (get-element-by-id "playlist-select"))) + (playlists (or (ps:@ data playlists) (array)))) + (when select + ;; Clear existing options except the first one + (setf (ps:@ select inner-h-t-m-l) + "") + ;; Add playlist options + (ps:chain playlists + (for-each (lambda (name) + (let ((option (ps:chain document (create-element "option")))) + (setf (ps:@ option value) name) + (setf (ps:@ option text-content) name) + (ps:chain select (append-child option)))))))))))) + (catch (lambda (error) + (ps:chain console (error "Error loading playlists:" error)))))) + + ;; Load selected playlist + (defun load-selected-playlist () + (let* ((select (ps:chain document (get-element-by-id "playlist-select"))) + (name (ps:@ select value))) + (when (= name "") + (alert "Please select a playlist first") + (return)) + + (unless (confirm (+ "Load playlist '" name "'? This will replace the current stream queue.")) + (return)) + + (ps:chain + (fetch (+ "/api/asteroid/stream/playlists/load?name=" (encode-u-r-i-component name)) + (ps:create :method "POST")) + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (if (= (ps:@ data status) "success") + (progn + (show-toast (+ "✓ Loaded " (ps:@ data count) " tracks from " name)) + (load-current-queue)) + (alert (+ "Error loading playlist: " (or (ps:@ data message) "Unknown error"))))))) + (catch (lambda (error) + (ps:chain console (error "Error loading playlist:" error)) + (alert "Error loading playlist")))))) + + ;; Load current queue contents (from stream-queue.m3u) + (defun load-current-queue () + (ps:chain + (fetch "/api/asteroid/stream/playlists/current") + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (when (= (ps:@ data status) "success") + (let ((tracks (or (ps:@ data tracks) (array))) + (count (or (ps:@ data count) 0))) + ;; Update count display + (let ((count-el (ps:chain document (get-element-by-id "queue-count")))) + (when count-el + (setf (ps:@ count-el text-content) count))) + ;; Display tracks + (display-current-queue tracks)))))) + (catch (lambda (error) + (ps:chain console (error "Error loading current queue:" error)) + (let ((container (ps:chain document (get-element-by-id "stream-queue-container")))) + (when container + (setf (ps:@ container inner-h-t-m-l) + "
Error loading queue
"))))))) + + ;; Display current queue contents + (defun display-current-queue (tracks) + (let ((container (ps:chain document (get-element-by-id "stream-queue-container")))) + (when container + (if (= (ps:@ tracks length) 0) + (setf (ps:@ container inner-h-t-m-l) + "
Queue is empty. Liquidsoap will use random playback from the music library.
") + (let ((html "
")) + (ps:chain tracks + (for-each (lambda (track index) + (setf html + (+ html + "
" + "" (+ index 1) "" + "
" + "
" (or (ps:@ track title) "Unknown") "
" + "
" (or (ps:@ track artist) "Unknown Artist") + (if (ps:@ track album) (+ " - " (ps:@ track album)) "") "
" + "
" + "
"))))) + (setf html (+ html "
")) + (setf (ps:@ container inner-h-t-m-l) html)))))) + + ;; Save current queue to stream-queue.m3u + (defun save-stream-queue () + (ps:chain + (fetch "/api/asteroid/stream/playlists/save" (ps:create :method "POST")) + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (if (= (ps:@ data status) "success") + (show-toast "✓ Queue saved") + (alert (+ "Error saving queue: " (or (ps:@ data message) "Unknown error"))))))) + (catch (lambda (error) + (ps:chain console (error "Error saving queue:" error)) + (alert "Error saving queue"))))) + + ;; Save queue as new playlist + (defun save-queue-as-new () + (let* ((input (ps:chain document (get-element-by-id "save-as-name"))) + (name (ps:chain (ps:@ input value) (trim)))) + (when (= name "") + (alert "Please enter a name for the new playlist") + (return)) + + (ps:chain + (fetch (+ "/api/asteroid/stream/playlists/save-as?name=" (encode-u-r-i-component name)) + (ps:create :method "POST")) + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (if (= (ps:@ data status) "success") + (progn + (show-toast (+ "✓ Saved as " name)) + (setf (ps:@ input value) "") + (load-playlist-list)) + (alert (+ "Error saving playlist: " (or (ps:@ data message) "Unknown error"))))))) + (catch (lambda (error) + (ps:chain console (error "Error saving playlist:" error)) + (alert "Error saving playlist")))))) + + ;; Clear stream queue (updated to use new API) + (defun clear-stream-queue () + (unless (confirm "Clear the stream queue? Liquidsoap will fall back to random playback from the music library.") + (return)) + + (ps:chain + (fetch "/api/asteroid/stream/playlists/clear" (ps:create :method "POST")) + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (if (= (ps:@ data status) "success") + (progn + (show-toast "✓ Queue cleared") + (load-current-queue)) + (alert (+ "Error clearing queue: " (or (ps:@ data message) "Unknown error"))))))) + (catch (lambda (error) + (ps:chain console (error "Error clearing queue:" error)) + (alert "Error clearing queue"))))) + + ;; ======================================== + ;; Liquidsoap Control Functions + ;; ======================================== + + ;; Refresh Liquidsoap status + (defun refresh-liquidsoap-status () + (ps:chain + (fetch "/api/asteroid/liquidsoap/status") + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (when (= (ps:@ data status) "success") + (let ((uptime-el (ps:chain document (get-element-by-id "ls-uptime"))) + (remaining-el (ps:chain document (get-element-by-id "ls-remaining"))) + (metadata-el (ps:chain document (get-element-by-id "ls-metadata")))) + (when uptime-el + (setf (ps:@ uptime-el text-content) (or (ps:@ data uptime) "--"))) + (when remaining-el + (setf (ps:@ remaining-el text-content) (or (ps:@ data remaining) "--"))) + (when metadata-el + (setf (ps:@ metadata-el text-content) (or (ps:@ data metadata) "--")))))))) + (catch (lambda (error) + (ps:chain console (error "Error fetching Liquidsoap status:" error)))))) + + ;; Skip current track + (defun liquidsoap-skip () + (ps:chain + (fetch "/api/asteroid/liquidsoap/skip" (ps:create :method "POST")) + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (if (= (ps:@ data status) "success") + (progn + (show-toast "⏭️ Track skipped") + (set-timeout refresh-liquidsoap-status 1000)) + (alert (+ "Error skipping track: " (or (ps:@ data message) "Unknown error"))))))) + (catch (lambda (error) + (ps:chain console (error "Error skipping track:" error)) + (alert "Error skipping track"))))) + + ;; Reload playlist + (defun liquidsoap-reload () + (ps:chain + (fetch "/api/asteroid/liquidsoap/reload" (ps:create :method "POST")) + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (if (= (ps:@ data status) "success") + (show-toast "📂 Playlist reloaded") + (alert (+ "Error reloading playlist: " (or (ps:@ data message) "Unknown error"))))))) + (catch (lambda (error) + (ps:chain console (error "Error reloading playlist:" error)) + (alert "Error reloading playlist"))))) + + ;; Restart Liquidsoap container + (defun liquidsoap-restart () + (unless (confirm "Restart Liquidsoap container? This will cause a brief interruption to the stream.") + (return)) + + (show-toast "🔄 Restarting Liquidsoap...") + (ps:chain + (fetch "/api/asteroid/liquidsoap/restart" (ps:create :method "POST")) + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (if (= (ps:@ data status) "success") + (progn + (show-toast "✓ Liquidsoap restarting") + ;; Refresh status after a delay to let container restart + (set-timeout refresh-liquidsoap-status 5000)) + (alert (+ "Error restarting Liquidsoap: " (or (ps:@ data message) "Unknown error"))))))) + (catch (lambda (error) + (ps:chain console (error "Error restarting Liquidsoap:" error)) + (alert "Error restarting Liquidsoap"))))) + + ;; Restart Icecast container + (defun icecast-restart () + (unless (confirm "Restart Icecast container? This will disconnect all listeners temporarily.") + (return)) + + (show-toast "🔄 Restarting Icecast...") + (ps:chain + (fetch "/api/asteroid/icecast/restart" (ps:create :method "POST")) + (then (lambda (response) (ps:chain response (json)))) + (then (lambda (result) + (let ((data (or (ps:@ result data) result))) + (if (= (ps:@ data status) "success") + (show-toast "✓ Icecast restarting - listeners will reconnect automatically") + (alert (+ "Error restarting Icecast: " (or (ps:@ data message) "Unknown error"))))))) + (catch (lambda (error) + (ps:chain console (error "Error restarting Icecast:" error)) + (alert "Error restarting Icecast"))))) + ;; Make functions globally accessible for onclick handlers (setf (ps:@ window go-to-page) go-to-page) (setf (ps:@ window previous-page) previous-page) diff --git a/playlists/Asteroid-Low-Orbit.m3u b/playlists/Asteroid-Low-Orbit.m3u index 7ff29a2..4950729 100644 --- a/playlists/Asteroid-Low-Orbit.m3u +++ b/playlists/Asteroid-Low-Orbit.m3u @@ -1,163 +1,98 @@ #EXTM3U -#EXTINF:370,Vector Lovers - City Lights From a Train -Vector Lovers/City Lights From a Train.flac -#EXTINF:400,The Black Dog - Psil-Cosyin -The Black Dog/Psil-Cosyin.flac -#EXTINF:320,Plaid - Eyen -Plaid/Eyen.flac -#EXTINF:330,ISAN - Birds Over Barges -ISAN/Birds Over Barges.flac -#EXTINF:360,Ochre - Bluebottle Farm -Ochre/Bluebottle Farm.flac -#EXTINF:390,Arovane - Theme -Arovane/Theme.flac -#EXTINF:380,Proem - Deep Like Airline Failure -Proem/Deep Like Airline Failure.flac -#EXTINF:310,Solvent - My Radio (Remix) -Solvent/My Radio (Remix).flac -#EXTINF:350,Bochum Welt - Marylebone (7th) -Bochum Welt/Marylebone (7th).flac -#EXTINF:290,Mrs Jynx - Shibuya Lullaby -Mrs Jynx/Shibuya Lullaby.flac -#EXTINF:340,Kettel - Whisper Me Wishes -Kettel/Whisper Me Wishes.flac -#EXTINF:360,Christ. - Perlandine Friday -Christ./Perlandine Friday.flac -#EXTINF:330,Cepia - Ithaca -Cepia/Ithaca.flac -#EXTINF:340,Datassette - Vacuform -Datassette/Vacuform.flac -#EXTINF:390,Plant43 - Dreams of the Sentient City -Plant43/Dreams of the Sentient City.flac -#EXTINF:410,Claro Intelecto - Peace of Mind (Electrosoul) -Claro Intelecto/Peace of Mind (Electrosoul).flac -#EXTINF:430,E.R.P. - Evoked -E.R.P./Evoked.flac -#EXTINF:310,Der Zyklus - Formenverwandler -Der Zyklus/Formenverwandler.flac -#EXTINF:330,Dopplereffekt - Infophysix -Dopplereffekt/Infophysix.flac -#EXTINF:350,Drexciya - Wavejumper -Drexciya/Wavejumper.flac -#EXTINF:375,The Other People Place - Sorrow & A Cup of Joe -The Other People Place/Sorrow & A Cup of Joe.flac -#EXTINF:340,Arpanet - Wireless Internet -Arpanet/Wireless Internet.flac -#EXTINF:380,Legowelt - Sturmvogel -Legowelt/Sturmvogel.flac -#EXTINF:310,DMX Krew - Space Paranoia -DMX Krew/Space Paranoia.flac -#EXTINF:360,Skywave Theory - Nova Drift -Skywave Theory/Nova Drift.flac -#EXTINF:460,Pye Corner Audio - Transmission Four -Pye Corner Audio/Transmission Four.flac -#EXTINF:390,B12 - Heaven Sent -B12/Heaven Sent.flac -#EXTINF:450,Higher Intelligence Agency - Tortoise -Higher Intelligence Agency/Tortoise.flac -#EXTINF:420,Biosphere - Kobresia -Biosphere/Kobresia.flac -#EXTINF:870,Global Communication - 14:31 -Global Communication/14:31.flac -#EXTINF:500,Monolake - Cyan -Monolake/Cyan.flac -#EXTINF:660,Deepchord - Electromagnetic -Deepchord/Electromagnetic.flac -#EXTINF:1020,GAS - Pop 4 -GAS/Pop 4.flac -#EXTINF:600,Yagya - Rigning Nýju -Yagya/Rigning Nýju.flac -#EXTINF:990,Voices From The Lake - Velo di Maya -Voices From The Lake/Velo di Maya.flac -#EXTINF:3720,ASC - Time Heals All -ASC/Time Heals All.flac -#EXTINF:540,36 - Room 237 -36/Room 237.flac -#EXTINF:900,Loscil - Endless Falls -Loscil/Endless Falls.flac -#EXTINF:450,Kiasmos - Looped -Kiasmos/Looped.flac -#EXTINF:590,Underworld - Rez -Underworld/Rez.flac -#EXTINF:570,Orbital - Halcyon + On + On -Orbital/Halcyon + On + On.flac -#EXTINF:1080,The Orb - A Huge Ever Growing Pulsating Brain -The Orb/A Huge Ever Growing Pulsating Brain.flac -#EXTINF:360,Autechre - Slip -Autechre/Slip.flac -#EXTINF:400,Labradford - S (Mi Media Naranja) -Labradford/S (Mi Media Naranja).flac -#EXTINF:350,Vector Lovers - Rusting Cars and Wildflowers -Vector Lovers/Rusting Cars and Wildflowers.flac -#EXTINF:390,The Black Dog - Raxmus -The Black Dog/Raxmus.flac -#EXTINF:315,Plaid - Hawkmoth -Plaid/Hawkmoth.flac -#EXTINF:320,ISAN - What This Button Did -ISAN/What This Button Did.flac -#EXTINF:370,Ochre - Circadies -Ochre/Circadies.flac -#EXTINF:420,Arovane - Tides -Arovane/Tides.flac -#EXTINF:370,Proem - Nothing is as It Seems -Proem/Nothing is as It Seems.flac -#EXTINF:300,Solvent - Loss For Words -Solvent/Loss For Words.flac -#EXTINF:340,Bochum Welt - Saint (77sunset) -Bochum Welt/Saint (77sunset).flac -#EXTINF:280,Mrs Jynx - Stay Home -Mrs Jynx/Stay Home.flac -#EXTINF:330,Kettel - Church -Kettel/Church.flac -#EXTINF:370,Christ. - Cordate -Christ./Cordate.flac -#EXTINF:350,Datassette - Computers Elevate -Datassette/Computers Elevate.flac -#EXTINF:420,Plant43 - The Cold Surveyor -Plant43/The Cold Surveyor.flac -#EXTINF:380,Claro Intelecto - Section -Claro Intelecto/Section.flac -#EXTINF:440,E.R.P. - Vox Automaton -E.R.P./Vox Automaton.flac -#EXTINF:300,Dopplereffekt - Z-Boson -Dopplereffekt/Z-Boson.flac -#EXTINF:380,Drexciya - Digital Tsunami -Drexciya/Digital Tsunami.flac -#EXTINF:350,The Other People Place - You Said You Want Me -The Other People Place/You Said You Want Me.flac -#EXTINF:370,Legowelt - Star Gazing -Legowelt/Star Gazing.flac -#EXTINF:440,Pye Corner Audio - Electronic Rhythm Number 3 -Pye Corner Audio/Electronic Rhythm Number 3.flac -#EXTINF:460,B12 - Infinite Lites (Classic Mix) -B12/Infinite Lites (Classic Mix).flac -#EXTINF:390,Biosphere - The Things I Tell You -Biosphere/The Things I Tell You.flac -#EXTINF:580,Global Communication - 9:39 -Global Communication/9:39.flac -#EXTINF:460,Monolake - T-Channel -Monolake/T-Channel.flac -#EXTINF:690,Deepchord - Vantage Isle (Variant) -Deepchord/Vantage Isle (Variant).flac -#EXTINF:840,GAS - Königsforst 5 -GAS/Königsforst 5.flac -#EXTINF:520,Yagya - The Salt on Her Cheeks -Yagya/The Salt on Her Cheeks.flac -#EXTINF:720,Voices From The Lake - Dream State -Voices From The Lake/Dream State.flac -#EXTINF:510,36 - Night Rain -36/Night Rain.flac -#EXTINF:470,Loscil - First Narrows -Loscil/First Narrows.flac -#EXTINF:400,Kiasmos - Burnt -Kiasmos/Burnt.flac -#EXTINF:570,Underworld - Jumbo (Extended) -Underworld/Jumbo (Extended).flac -#EXTINF:480,Orbital - Belfast -Orbital/Belfast.flac -#EXTINF:540,The Orb - Little Fluffy Clouds (Ambient Mix) -The Orb/Little Fluffy Clouds (Ambient Mix).flac -#EXTINF:390,Autechre - Nine -Autechre/Nine.flac -#EXTINF:380,Labradford - G (Mi Media Naranja) -Labradford/G (Mi Media Naranja).flac +#PLAYLIST:Asteroid Low Orbit - Ambient Electronic Journey +#CURATOR:Asteroid Radio + +#EXTINF:-1,Brian Eno - Emerald And Lime +/app/music/Brian Eno/2011 - Small Craft On a Milk Sea/A1 Emerald And Lime.flac +#EXTINF:-1,Brian Eno - Complex Heaven +/app/music/Brian Eno/2011 - Small Craft On a Milk Sea/A2 Complex Heaven.flac +#EXTINF:-1,Brian Eno - Dust Shuffle +/app/music/Brian Eno/2011 - Small Craft On a Milk Sea/B4 Dust Shuffle.flac +#EXTINF:-1,Brian Eno - Garden of Stars +/app/music/Brian Eno/2022 - ForeverAndEverNoMore/04 Garden of Stars.flac +#EXTINF:-1,Brian Eno - There Were Bells +/app/music/Brian Eno/2022 - ForeverAndEverNoMore/06 There Were Bells.flac +#EXTINF:-1,Biosphere - Drifter +/app/music/Biosphere - The Petrified Forest (2017) - CD FLAC/01. Biosphere - Drifter.flac +#EXTINF:-1,Biosphere - Black Mesa +/app/music/Biosphere - The Petrified Forest (2017) - CD FLAC/02. Biosphere - Black Mesa.flac +#EXTINF:-1,Biosphere - Skålbrekka +/app/music/Biosphere - The Senja Recordings (2019) [FLAC]/01 - Skålbrekka.flac +#EXTINF:-1,Biosphere - Bjorvika +/app/music/Biosphere - The Senja Recordings (2019) [FLAC]/04 - Bjorvika.flac +#EXTINF:-1,Biosphere - Out Of The Cradle +/app/music/Biosphere - Departed Glories (2016) - FLAC WEB/01 - Out Of The Cradle.flac +#EXTINF:-1,Biosphere - Down On Ropes +/app/music/Biosphere - Departed Glories (2016) - FLAC WEB/03 - Down On Ropes.flac +#EXTINF:-1,Biosphere - Microtunneling +/app/music/Biosphere - Sound Installations -2000-2009 [FLAC]/Biosphere - Sound Installations -2000-2009- - 04 Microtunneling.flac +#EXTINF:-1,Autechre - Dael +/app/music/Autechre/1995 - Tri Repetae/01 Dael.flac +#EXTINF:-1,Autechre - Further +/app/music/Autechre/1994 - Amber/08 Further.flac +#EXTINF:-1,Autechre - north spiral +/app/music/Autechre - 2018 - NTS Session 1/NTS Session 1-006-Autechre-north spiral.flac +#EXTINF:-1,Four Tet - Alap +/app/music/Four Tet - New Energy {CD} [FLAC] (2017)/01 Alap.flac +#EXTINF:-1,Four Tet - Scientists +/app/music/Four Tet - New Energy {CD} [FLAC] (2017)/06 Scientists.flac +#EXTINF:-1,Four Tet - Green +/app/music/Four Tet - Sixteen Oceans (2020) {Text Records - TEXT051} [CD FLAC]/12 - Four Tet - Green.flac +#EXTINF:-1,Four Tet - Parallel 8 +/app/music/Four Tet - Parallel (2020) - WEB FLAC/08. Parallel 8.flac +#EXTINF:-1,Clark - Spring But Dark +/app/music/Clark - Death Peak (2017) [FLAC]/01 - Spring But Dark.flac +#EXTINF:-1,Clark - Kiri's Glee +/app/music/Clark - Kiri Variations (2019) [WEB FLAC]/04 - Kiri's Glee.flac +#EXTINF:-1,Clark - Primary Pluck +/app/music/Clark - Kiri Variations (2019) [WEB FLAC]/08 - Primary Pluck.flac +#EXTINF:-1,Clark - Cannibal Homecoming +/app/music/Clark - Kiri Variations (2019) [WEB FLAC]/11 - Cannibal Homecoming.flac +#EXTINF:-1,Clark - Absence (Bibio Remix) +/app/music/Clark - Feast Beast (2013) [24 Bit WEB FLAC] [16-44]/1.12. Clark - Absence (Bibio Remix).flac +#EXTINF:-1,Tycho - Glider +/app/music/Tycho - Epoch (Deluxe Version) (2019) [WEB FLAC16-44.1]/01 - Glider.flac +#EXTINF:-1,Tycho - Source +/app/music/Tycho - Epoch (Deluxe Version) (2019) [WEB FLAC16-44.1]/07 - Source.flac +#EXTINF:-1,Tycho - Rings +/app/music/Tycho - Epoch (Deluxe Version) (2019) [WEB FLAC16-44.1]/09 - Rings.flac +#EXTINF:-1,Tycho - Into The Woods +/app/music/Tycho - Simulcast (2020) [WEB FLAC]/04 - Into The Woods.flac +#EXTINF:-1,Tycho - Ascension +/app/music/Thievery Corporation and Tycho - Fragments Ascension EP (flac)/3. Tycho - Ascension.flac +#EXTINF:-1,Ulrich Schnauss - Negative Sunrise (2019 Version) +/app/music/Ulrich Schnauss - No Further Ahead Than Tomorrow (2020) - WEB FLAC/09. Negative Sunrise (2019 Version).flac +#EXTINF:-1,Ulrich Schnauss - Like a Ghost in Your Own Life +/app/music/Ulrich Schnauss - A Long Way To Fall - Rebound (2020) - WEB FLAC/03. Like a Ghost in Your Own Life.flac +#EXTINF:-1,Ulrich Schnauss & Jonas Munk - Solitary Falling +/app/music/Ulrich Schnauss & Jonas Munk - Eight Fragments Of An Illusion (2021) - WEB FLAC/03. Solitary Falling.flac +#EXTINF:-1,Ulrich Schnauss & Jonas Munk - Narkomfin +/app/music/Ulrich Schnauss & Jonas Munk - Eight Fragments Of An Illusion (2021) - WEB FLAC/05. Narkomfin.flac +#EXTINF:-1,Ulrich Schnauss & Jonas Munk - Polychrome +/app/music/Ulrich Schnauss & Jonas Munk - Eight Fragments Of An Illusion (2021) - WEB FLAC/08. Polychrome.flac +#EXTINF:-1,Proem - Winter Wolves +/app/music/Proem - 2018 Modern Rope (WEB)/01. Winter Wolves.flac +#EXTINF:-1,Proem - Modern Rope +/app/music/Proem - 2018 Modern Rope (WEB)/05. Modern Rope.flac +#EXTINF:-1,Proem - Kids That Hate Live Things +/app/music/Proem - Until Here for Years (n5md, 2019) flac/11 - Kids That Hate Live Things.flac +#EXTINF:-1,Proem - End Tail +/app/music/Proem - Twelve Tails-(2021) @FLAC [16-48]/07 - End Tail.flac +#EXTINF:-1,Proem - In a Timeless, Lightless World +/app/music/Proem/2019 - As They Go/Proem - As They Go - 05 In a Timeless, Lightless World.flac +#EXTINF:-1,arovane - komposition no. 1 +/app/music/arovane - Wirkung (2020) [WEB FLAC16]/17. arovane - komposition no. 1.flac +#EXTINF:-1,arovane - hymn +/app/music/arovane - Wirkung (2020) [WEB FLAC16]/12. arovane - hymn.flac +#EXTINF:-1,Aphex Twin - CHEETAHT7b +/app/music/Aphex Twin (2016) Cheetah EP [WEB] [FLAC]/Cheetah EP-002-Aphex Twin-CHEETAHT7b.flac +#EXTINF:-1,Aphex Twin - CHEETA2 ms800 +/app/music/Aphex Twin (2016) Cheetah EP [WEB] [FLAC]/Cheetah EP-004-Aphex Twin-CHEETA2 ms800.flac +#EXTINF:-1,Plaid - Sun Electric - Tee (Plaid Mix) +/app/music/Plaid - Stem Sell (Plaid Remixes) [2021] (WEB - FLAC - Lossless)/17-Sun_Electric-Tee_(Plaid_Mix).flac +#EXTINF:-1,Plaid - Origamibiro - Impressions Of Football (Plaid Remix) +/app/music/Plaid - Stem Sell (Plaid Remixes) [2021] (WEB - FLAC - Lossless)/11-Origamibiro-Impressions_Of_Football_(Plaid_Remix).flac +#EXTINF:-1,Plaid - Ricardo Tobar - After The Movie (Plaid Remix) +/app/music/Plaid - Stem Sell (Plaid Remixes) [2021] (WEB - FLAC - Lossless)/21-Ricardo_Tobar-After_The_Movie_(Plaid_Remix).flac +#EXTINF:-1,Plaid - Esem - Yourturn (Plaid Remix) +/app/music/Plaid - Stem Sell (Plaid Remixes) [2021] (WEB - FLAC - Lossless)/26-Esem-Yourturn_(Plaid_Remix).flac diff --git a/playlists/stream-queue.m3u b/playlists/stream-queue.m3u index 8611479..a126ce4 100644 --- a/playlists/stream-queue.m3u +++ b/playlists/stream-queue.m3u @@ -1,371 +1,144 @@ #EXTM3U -#EXTINF:-1,Underworld - Underworld - Confusion The Waitress -/app/music/Underworld/1996 - Second Toughest In The Infants/03. Underworld - Confusion The Waitress.flac -#EXTINF:-1,The Orb - Towers Of Dub -/app/music/The Orb/1992 - UFOrb/04-Towers Of Dub.mp3 -#EXTINF:-1,Drexciya - Drexciya - Intensified Magnetron -/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/04. Drexciya - Intensified Magnetron.mp3 -#EXTINF:-1,Labradford - Balanced on It's Own Flame -/app/music/Labradford/1995 - A Stable Reference/6 Balanced on It's Own Flame.flac -#EXTINF:-1,Vector Lovers - City Lights From A Train -/app/music/Vector Lovers/2005 - Capsule For One/01 - City Lights From A Train.mp3 -#EXTINF:-1,Labradford - Leta O'Steen. Design assistance by John Piper -/app/music/Labradford/1999 - E luxo so/6. Leta O'Steen. Design assistance by John Piper.flac -#EXTINF:-1,Tape Loop Orchestra - Tape Loop Orchestra - Chapter 1   Reel One -/app/music/Tape Loop Orchestra/2009 - 1953 Culture Festival/01 Tape Loop Orchestra - Chapter 1   Reel One.mp3 -#EXTINF:-1,Orbital - Time Becomes -/app/music/Orbital/1993 - Orbital - Orbital 2 (Brown Album - TRUCD2, 828 386.2)/00. Time Becomes.mp3 -#EXTINF:-1,Proem - Proem - You Shall Have Ever Been - 05 No You Are $ -/app/music/Proem/2006 - You Shall Have Ever Been/Proem - You Shall Have Ever Been - 05 No You Are $.flac -#EXTINF:-1,Pye Corner Audio - Pye Corner Audio - The Simplest Equation -/app/music/Pye Corner Audio/EP's & Singles/2016 - Pye Corner Audio With Dalhous - Run For The Shadows EP (WEB, #LPS13)/02 - Pye Corner Audio - The Simplest Equation.mp3 -#EXTINF:-1,Brian Eno - Emerald and Lime -/app/music/Brian Eno/2024 - Eno (Original Motion Picture Soundtrack)/12. Emerald and Lime.flac -#EXTINF:-1,Bark Psychosis - (07) [Bark Psychosis] A Street Scene -/app/music/Bark Psychosis/1994 - Game Over/(07) [Bark Psychosis] A Street Scene.flac -#EXTINF:-1,Model 500 - model_500-digital_solutions -/app/music/Model 500/2015 - Digital Solutions/08-model_500-digital_solutions.flac -#EXTINF:-1,Labradford - Banco -/app/music/Labradford/1995 - A Stable Reference/4 Banco.flac -#EXTINF:-1,Labradford - Skyward With Motion -/app/music/Labradford/1993 - Prazision LP/11 Skyward With Motion.flac -#EXTINF:-1,Pye Corner Audio - The Mirror Ball Cracked -/app/music/Pye Corner Audio/2012 - Sleep Games (WEB, #GBX017)/08 - The Mirror Ball Cracked.mp3 -#EXTINF:-1,Brian Eno - Foreign Affairs -/app/music/Brian Eno/1978 - After The Heat/01 - Foreign Affairs.flac -#EXTINF:-1,The Other People Place - B1 - Moonlight Rendezvous -/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/B1 - Moonlight Rendezvous.flac -#EXTINF:-1,Drexciya - Unknown Journey IX -/app/music/Drexciya/2013 - Journey of the Deep Sea Dweller IV/10. Unknown Journey IX.mp3 -#EXTINF:-1,Orbital - Crash And Carry -/app/music/Orbital/1994 - Orbital - Snivilisation (TRUCD5, 828 536.2)/04. Crash And Carry.mp3 -#EXTINF:-1,Proem - Proem - Before it finds you - 09 We can watch it burn to the ground -/app/music/Proem/2013 - Before it finds you/Proem - Before it finds you - 09 We can watch it burn to the ground.flac -#EXTINF:-1,Proem - Proem - Before it finds you - 01 Stone into gravel -/app/music/Proem/2013 - Before it finds you/Proem - Before it finds you - 01 Stone into gravel.flac -#EXTINF:-1,Drexciya - Intro (The Unknown Aquazone) -/app/music/Drexciya/2013 - Journey of the Deep Sea Dweller IV/01. Intro (The Unknown Aquazone).mp3 -#EXTINF:-1,Teeth Of The Sea - Get With the Program -/app/music/Teeth Of The Sea/2023 - Hive/02 Get With the Program.flac -#EXTINF:-1,Proem - Proem - Vault ep.4-4 - 02 Little girls -/app/music/Proem/2015 - Vault ep.4-4/Proem - Vault ep.4-4 - 02 Little girls.flac -#EXTINF:-1,Drexciya - Black Sea -/app/music/Drexciya/2013 - Journey of the Deep Sea Dweller IV/14. Black Sea.mp3 -#EXTINF:-1,Autechre - Yulquen -/app/music/Autechre/1994 - Amber/09 Yulquen.flac -#EXTINF:-1,The Other People Place - C2 - Running From Love -/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/C2 - Running From Love.flac -#EXTINF:-1,Brian Eno - D2 Written, Forgotten -/app/music/Brian Eno/2011 - Small Craft On a Milk Sea/D2 Written, Forgotten.flac -#EXTINF:-1,Autechre - Stud -/app/music/Autechre/1995 - Tri Repetae/05 Stud.flac -#EXTINF:-1,Model 500 - model_500-electric_night -/app/music/Model 500/2015 - Digital Solutions/02-model_500-electric_night.flac -#EXTINF:-1,The Orb - Close Encounters -/app/music/The Orb/1992 - UFOrb/05-Close Encounters.mp3 -#EXTINF:-1,Model 500 - model_500-hi_nrg -/app/music/Model 500/2015 - Digital Solutions/01-model_500-hi_nrg.flac -#EXTINF:-1,Brian Eno - B3 Bone Jump -/app/music/Brian Eno/2011 - Small Craft On a Milk Sea/B3 Bone Jump.flac -#EXTINF:-1,Labradford - by Chris Johnston, Craig Markva, Jamie Evans, -/app/music/Labradford/1999 - E luxo so/4. by Chris Johnston, Craig Markva, Jamie Evans,.flac -#EXTINF:-1,The Orb - Star 6 & 7 8 9 -/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/09 Star 6 & 7 8 9.mp3 -#EXTINF:-1,Proem - Proem - Vault ep.1-4 (Noise) - 02 Half a Heart -/app/music/Proem/2016 - Vault ep.1-4 (Noise)/Proem - Vault ep.1-4 (Noise) - 02 Half a Heart.flac -#EXTINF:-1,Dopplereffekt - Spirangle -/app/music/Dopplereffekt/2017 - Cellular Automata/08. Spirangle.flac -#EXTINF:-1,Drexciya - Unknown Journey VII -/app/music/Drexciya/2013 - Journey of the Deep Sea Dweller IV/06. Unknown Journey VII.mp3 -#EXTINF:-1,Drexciya - Mantaray -/app/music/Drexciya/2013 - Journey of the Deep Sea Dweller IV/04. Mantaray.mp3 -#EXTINF:-1,Pye Corner Audio - Pye Corner Audio - Untitled -/app/music/Pye Corner Audio/EP's & Singles/2017 - Pye Corner Audio, Silent Servant, Not Waving - Limited Edition EP (Vinyl, #E031COL)/02 - Pye Corner Audio - Untitled.mp3 -#EXTINF:-1,Underworld - Underworld - Juanita, Kiteless, To Dream Of Love -/app/music/Underworld/1996 - Second Toughest In The Infants/01. Underworld - Juanita, Kiteless, To Dream Of Love.flac -#EXTINF:-1,Proem - Proem - As They Go - 05 In a Timeless, Lightless World -/app/music/Proem/2019 - As They Go/Proem - As They Go - 05 In a Timeless, Lightless World.flac -#EXTINF:-1,Model 500 - model_500-standing_in_tomorow -/app/music/Model 500/2015 - Digital Solutions/03-model_500-standing_in_tomorow.flac -#EXTINF:-1,The Orb - Plum Island -/app/music/The Orb/2001 - Cydonia/09-Plum Island.mp3 -#EXTINF:-1,Orbital - Lush 3-2 -/app/music/Orbital/1993 - Orbital - Orbital 2 (Brown Album - TRUCD2, 828 386.2)/00. Lush 3-2.mp3 -#EXTINF:-1,Dopplereffekt - Exponential Decay -/app/music/Dopplereffekt/2017 - Cellular Automata/09. Exponential Decay.flac -#EXTINF:-1,Brian Eno - Garden of Stars -/app/music/Brian Eno/2022 - ForeverAndEverNoMore/04 Garden of Stars.flac -#EXTINF:-1,The Other People Place - B2 - You Said You Want Me -/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/B2 - You Said You Want Me.flac -#EXTINF:-1,Dopplereffekt - Mandelbrot Set -/app/music/Dopplereffekt/2017 - Cellular Automata/07. Mandelbrot Set.flac -#EXTINF:-1,Autechre - Foil -/app/music/Autechre/1994 - Amber/01 Foil.flac -#EXTINF:-1,Proem - Proem - As They Go - 04 What is Needed -/app/music/Proem/2019 - As They Go/Proem - As They Go - 04 What is Needed.flac -#EXTINF:-1,Vector Lovers - Post Arctic Industries -/app/music/Vector Lovers/2005 - Capsule For One/06 - Post Arctic Industries.mp3 -#EXTINF:-1,Proem - proem - Negativ - 12 Skylup -/app/music/Proem/2001 - Negativ/proem - Negativ - 12 Skylup.flac -#EXTINF:-1,Model 500 - model_500-encounter -/app/music/Model 500/2015 - Digital Solutions/04-model_500-encounter.flac -#EXTINF:-1,Kraftwerk - Pocket Calculator -/app/music/Kraftwerk/1981 - Computer World/02 - Pocket Calculator.flac -#EXTINF:-1,Tape Loop Orchestra - Tape Loop Orchestra - Chapter 13   Reel Two End -/app/music/Tape Loop Orchestra/2009 - 1953 Culture Festival/13 Tape Loop Orchestra - Chapter 13   Reel Two End.mp3 -#EXTINF:-1,Pye Corner Audio - Corrupt Data -/app/music/Pye Corner Audio/2017 - Half-Light (Prower Remixed) (WEB, #MTH011)/01 - Corrupt Data.mp3 -#EXTINF:-1,Kiasmos - Kiasmos - II - 04 Laced -/app/music/Kiasmos/2024 - II/Kiasmos - II - 04 Laced.flac -#EXTINF:-1,Pye Corner Audio - Mindshaft -/app/music/Pye Corner Audio/2019 - Hollow Earth (WEB, #GBX032 DL)/05 - Mindshaft.mp3 -#EXTINF:-1,Labradford - G -/app/music/Labradford/1997 - Mi Media Naranja/2 G.flac -#EXTINF:-1,Dopplereffekt - Isotropy -/app/music/Dopplereffekt/2017 - Cellular Automata/04. Isotropy.flac -#EXTINF:-1,Autechre - Further -/app/music/Autechre/1994 - Amber/08 Further.flac -#EXTINF:-1,Proem - Proem - You Shall Have Ever Been - 02 Eck The Badly Drawn -/app/music/Proem/2006 - You Shall Have Ever Been/Proem - You Shall Have Ever Been - 02 Eck The Badly Drawn.flac -#EXTINF:-1,Autechre - C-Pach -/app/music/Autechre/1995 - Tri Repetae/07 C-Pach.flac -#EXTINF:-1,Kraftwerk - Neon Lights -/app/music/Kraftwerk/1978 - The Man-Machine/05 - Neon Lights.flac -#EXTINF:-1,Labradford - twenty -/app/music/Labradford/2001 - fixed..context/1 twenty.flac -#EXTINF:-1,Bark Psychosis - (01) [Bark Psychosis] Blue -/app/music/Bark Psychosis/1994 - Game Over/(01) [Bark Psychosis] Blue.flac -#EXTINF:-1,Vector Lovers - Substrata -/app/music/Vector Lovers/2005 - Capsule For One/03 - Substrata.mp3 -#EXTINF:-1,Kraftwerk - Computer World -/app/music/Kraftwerk/1981 - Computer World/01 - Computer World.flac -#EXTINF:-1,Underworld - Underworld - Air Towel -/app/music/Underworld/1996 - Second Toughest In The Infants/06. Underworld - Air Towel.flac -#EXTINF:-1,Underworld - Underworld - Blueski -/app/music/Underworld/1996 - Second Toughest In The Infants/07. Underworld - Blueski.flac -#EXTINF:-1,Labradford - Experience The Gated Oscillator -/app/music/Labradford/1993 - Prazision LP/05 Experience The Gated Oscillator.flac -#EXTINF:-1,Dopplereffekt - Gestalt Intelligence -/app/music/Dopplereffekt/2017 - Cellular Automata/03. Gestalt Intelligence.flac -#EXTINF:-1,Labradford - Dulcimers played by Peter Neff. Strings played -/app/music/Labradford/1999 - E luxo so/3. Dulcimers played by Peter Neff. Strings played.flac -#EXTINF:-1,Tape Loop Orchestra - Tape Loop Orchestra - Chapter 14   Tails Out -/app/music/Tape Loop Orchestra/2009 - 1953 Culture Festival/14 Tape Loop Orchestra - Chapter 14   Tails Out.mp3 -#EXTINF:-1,Labradford - up to pizmo -/app/music/Labradford/2001 - fixed..context/2 up to pizmo.flac -#EXTINF:-1,Orbital - Sad But True -/app/music/Orbital/1994 - Orbital - Snivilisation (TRUCD5, 828 536.2)/03. Sad But True.mp3 -#EXTINF:-1,Orbital - Lush 3-1 -/app/music/Orbital/1993 - Orbital - Orbital 2 (Brown Album - TRUCD2, 828 386.2)/00. Lush 3-1.mp3 -#EXTINF:-1,Dopplereffekt - Cellular Automata -/app/music/Dopplereffekt/2017 - Cellular Automata/01. Cellular Automata.flac -#EXTINF:-1,The Orb - Little Fluffy Clouds -/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/01 Little Fluffy Clouds.mp3 -#EXTINF:-1,Bark Psychosis - All Different Things -/app/music/Bark Psychosis/1994 - Independency/03 - All Different Things.flac -#EXTINF:-1,Orbital - Kein Trink Wasser -/app/music/Orbital/1994 - Orbital - Snivilisation (TRUCD5, 828 536.2)/07. Kein Trink Wasser.mp3 -#EXTINF:-1,The Orb - Perpetual Dawn -/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/06 Perpetual Dawn.mp3 -#EXTINF:-1,Underworld - Underworld - Stagger -/app/music/Underworld/1996 - Second Toughest In The Infants/08. Underworld - Stagger.flac -#EXTINF:-1,Dopplereffekt - von Neumann Probe -/app/music/Dopplereffekt/2017 - Cellular Automata/02. von Neumann Probe.flac -#EXTINF:-1,The Orb - EDM -/app/music/The Orb/2001 - Cydonia/12-EDM.mp3 -#EXTINF:-1,Teeth Of The Sea - Reaper -/app/music/Teeth Of The Sea/2013 - Master/02 - Reaper.mp3 -#EXTINF:-1,Drexciya - Drexciya - Aquabahn -/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/03. Drexciya - Aquabahn.mp3 -#EXTINF:-1,Autechre - Rsdio -/app/music/Autechre/1995 - Tri Repetae/10 Rsdio.flac -#EXTINF:-1,Teeth Of The Sea - Transfinite -/app/music/Teeth Of The Sea/2010 - Your Mercury/01 Transfinite.mp3 -#EXTINF:-1,Orbital - Philosophy By Numbers -/app/music/Orbital/1994 - Orbital - Snivilisation (TRUCD5, 828 536.2)/06. Philosophy By Numbers.mp3 -#EXTINF:-1,Autechre - Dael -/app/music/Autechre/1995 - Tri Repetae/01 Dael.flac -#EXTINF:-1,Vector Lovers - Boulevard -/app/music/Vector Lovers/2005 - Capsule For One/09 - Boulevard.mp3 -#EXTINF:-1,Brian Eno - Reflection -/app/music/Brian Eno/2017 - Reflection/01. Reflection.mp3 -#EXTINF:-1,Kiasmos - Thrown -/app/music/Kiasmos/2012 - Thrown EP/01 - Thrown.flac -#EXTINF:-1,The Other People Place - A2 - It's Your Love -/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/A2 - It's Your Love.flac -#EXTINF:-1,Drexciya - Unknown Journey VIII -/app/music/Drexciya/2013 - Journey of the Deep Sea Dweller IV/07. Unknown Journey VIII.mp3 -#EXTINF:-1,Bark Psychosis - I Know -/app/music/Bark Psychosis/1994 - Independency/01 - I Know.flac -#EXTINF:-1,Underworld - Underworld - Rowla -/app/music/Underworld/1996 - Second Toughest In The Infants/04. Underworld - Rowla.flac -#EXTINF:-1,Orbital - Forever -/app/music/Orbital/1994 - Orbital - Snivilisation (TRUCD5, 828 536.2)/01. Forever.mp3 -#EXTINF:-1,Autechre - Clipper -/app/music/Autechre/1995 - Tri Repetae/02 Clipper.flac -#EXTINF:-1,The Other People Place - C1 - Let Me Be Me -/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/C1 - Let Me Be Me.flac -#EXTINF:-1,Kraftwerk - Metropolis -/app/music/Kraftwerk/1978 - The Man-Machine/03 - Metropolis.flac -#EXTINF:-1,Labradford - The Cipher -/app/music/Labradford/1996 - Labradford/4 The Cipher.flac -#EXTINF:-1,Autechre - Silverside -/app/music/Autechre/1994 - Amber/03 Silverside.flac -#EXTINF:-1,Autechre - Nine -/app/music/Autechre/1994 - Amber/07 Nine.flac -#EXTINF:-1,Kraftwerk - Numbers -/app/music/Kraftwerk/1981 - Computer World/03 - Numbers.flac -#EXTINF:-1,Pye Corner Audio - Recrypt -/app/music/Pye Corner Audio/2011 - Black Mill Tapes Volume 2 - Do You Synthesize (WEB, #pca002)/06 - Recrypt.mp3 -#EXTINF:-1,The Other People Place - D1 - Lifestyles Of The Casual -/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/D1 - Lifestyles Of The Casual.flac -#EXTINF:-1,Autechre - Teartear -/app/music/Autechre/1994 - Amber/11 Teartear.flac -#EXTINF:-1,Teeth Of The Sea - in the space capsule (love theme) -/app/music/Teeth Of The Sea/2011 - Hypnoticon/01 in the space capsule (love theme).mp3 -#EXTINF:-1,Kiasmos - Dragged -/app/music/Kiasmos/2014 - Kiasmos/06 - Dragged.flac -#EXTINF:-1,Dopplereffekt - Ulams Spiral -/app/music/Dopplereffekt/2017 - Cellular Automata/06. Ulams Spiral.flac -#EXTINF:-1,Brian Eno - Stiff -/app/music/Brian Eno/2024 - Eno (Original Motion Picture Soundtrack)/11. Stiff.flac -#EXTINF:-1,The Orb - A Huge Ever Growing Pulsating Brain That Rules From The Centre Of The Ultraworld_ Live Mix Mk 10 -/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/10 A Huge Ever Growing Pulsating Brain That Rules From The Centre Of The Ultraworld_ Live Mix Mk 10.mp3 -#EXTINF:-1,The Orb - Sticky End -/app/music/The Orb/1992 - UFOrb/07-Sticky End.mp3 -#EXTINF:-1,Vector Lovers - Microtron -/app/music/Vector Lovers/2005 - Capsule For One/04 - Microtron.mp3 -#EXTINF:-1,Kraftwerk - Home Computer -/app/music/Kraftwerk/1981 - Computer World/06 - Home Computer.flac -#EXTINF:-1,Pye Corner Audio - Foreshadowed -/app/music/Pye Corner Audio/2012 - Black Mill Tapes Volume 3 - All Pathways Open (WEB, #pca003)/08 - Foreshadowed.mp3 -#EXTINF:-1,Tape Loop Orchestra - Tape Loop Orchestra - Chapter 2   Yasujiro Ozu -/app/music/Tape Loop Orchestra/2009 - 1953 Culture Festival/02 Tape Loop Orchestra - Chapter 2   Yasujiro Ozu.mp3 -#EXTINF:-1,Brian Eno - Verdigris -/app/music/Brian Eno/2020 - Roger Eno and Brian Eno - Mixing Colours/08 Verdigris.flac -#EXTINF:-1,Tape Loop Orchestra - The Word On My Lips Is Your Name -/app/music/Tape Loop Orchestra/2012 - The Word On My Lips Is Your Name/Disc 1 - The Word On My Lips Is Your Name/01 - The Word On My Lips Is Your Name.flac -#EXTINF:-1,Vector Lovers - Melodies And Memory -/app/music/Vector Lovers/2005 - Capsule For One/07 - Melodies And Memory.mp3 -#EXTINF:-1,Vector Lovers - To The Stars -/app/music/Vector Lovers/2005 - Capsule For One/12 - To The Stars.mp3 -#EXTINF:-1,Dopplereffekt - Pascal's Recursion -/app/music/Dopplereffekt/2017 - Cellular Automata/05. Pascal's Recursion.flac -#EXTINF:-1,Orbital - Walk Now -/app/music/Orbital/1993 - Orbital - Orbital 2 (Brown Album - TRUCD2, 828 386.2)/00. Walk Now.mp3 -#EXTINF:-1,Orbital - Quality Seconds -/app/music/Orbital/1994 - Orbital - Snivilisation (TRUCD5, 828 536.2)/08. Quality Seconds.mp3 -#EXTINF:-1,Vector Lovers - Nostalgia 4 The Future -/app/music/Vector Lovers/2005 - Capsule For One/05 - Nostalgia 4 The Future.mp3 -#EXTINF:-1,Brian Eno - D3 Late Anthropocene -/app/music/Brian Eno/2011 - Small Craft On a Milk Sea/D3 Late Anthropocene.flac -#EXTINF:-1,Autechre - Gnit -/app/music/Autechre/1995 - Tri Repetae/08 Gnit.flac -#EXTINF:-1,Pye Corner Audio - Electronic Rhythm Number Seven -/app/music/Pye Corner Audio/2011 - Black Mill Tapes Volume 2 - Do You Synthesize (WEB, #pca002)/02 - Electronic Rhythm Number Seven.mp3 -#EXTINF:-1,Proem - Proem - Socially Inept - 05 Pinching Point -/app/music/Proem/2004 - Socially Inept/Proem - Socially Inept - 05 Pinching Point.flac -#EXTINF:-1,Vector Lovers - Empty Buildings, Falling Rain -/app/music/Vector Lovers/2005 - Capsule For One/08 - Empty Buildings, Falling Rain.mp3 -#EXTINF:-1,Model 500 - model_500-control -/app/music/Model 500/2015 - Digital Solutions/09-model_500-control.flac -#EXTINF:-1,Proem - Proem - Vault ep.2-4 (Drone) - 02 Another Dull Moment -/app/music/Proem/2016 - Vault ep.2-4 (Drone)/Proem - Vault ep.2-4 (Drone) - 02 Another Dull Moment.flac -#EXTINF:-1,Teeth Of The Sea - Her Wraith -/app/music/Teeth Of The Sea/2019 - WRAITH/06 - Her Wraith.flac -#EXTINF:-1,Brian Eno - Slow Movement Sand -/app/music/Brian Eno/2020 - Roger Eno and Brian Eno - Mixing Colours/18 Slow Movement Sand.flac -#EXTINF:-1,Drexciya - Drexciya - You Don't Know -/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/13. Drexciya - You Don't Know.mp3 -#EXTINF:-1,Proem - Proem - You Shall Have Ever Been - 07 Reddings -/app/music/Proem/2006 - You Shall Have Ever Been/Proem - You Shall Have Ever Been - 07 Reddings.flac -#EXTINF:-1,Teeth Of The Sea - Fortean Steed -/app/music/Teeth Of The Sea/2019 - WRAITH/04 - Fortean Steed.flac -#EXTINF:-1,Kraftwerk - The Model -/app/music/Kraftwerk/1978 - The Man-Machine/04 - The Model.flac -#EXTINF:-1,Pye Corner Audio - Yesterday's Entertainment -/app/music/Pye Corner Audio/2012 - Sleep Games (WEB, #GBX017)/07 - Yesterday's Entertainment.mp3 -#EXTINF:-1,Brian Eno - B2 Forms Of Anger -/app/music/Brian Eno/2011 - Small Craft On a Milk Sea/B2 Forms Of Anger.flac -#EXTINF:-1,Vector Lovers - Neon Sky Rain -/app/music/Vector Lovers/2005 - Capsule For One/10 - Neon Sky Rain.mp3 -#EXTINF:-1,Vector Lovers - Capsule For One -/app/music/Vector Lovers/2005 - Capsule For One/11 - Capsule For One.mp3 -#EXTINF:-1,Pye Corner Audio - Solar Waves -/app/music/Pye Corner Audio/EP's & Singles/2019 - Dark Phase EP (WEB, #AF025)/02 - Solar Waves.mp3 -#EXTINF:-1,Kraftwerk - Computer Love -/app/music/Kraftwerk/1981 - Computer World/05 - Computer Love.flac -#EXTINF:-1,Kiasmos - Held (Dauwd Remix) -/app/music/Kiasmos/2015 - Looped/02 Held (Dauwd Remix).flac -#EXTINF:-1,Tape Loop Orchestra - Tape Loop Orchestra - Chapter 9   Setsu Ko Hara -/app/music/Tape Loop Orchestra/2009 - 1953 Culture Festival/09 Tape Loop Orchestra - Chapter 9   Setsu Ko Hara.mp3 -#EXTINF:-1,The Orb - Back Side of the Moon -/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/04 Back Side of the Moon.mp3 -#EXTINF:-1,Model 500 - model_500-storm -/app/music/Model 500/2015 - Digital Solutions/05-model_500-storm.flac -#EXTINF:-1,Autechre - Montreal -/app/music/Autechre/1994 - Amber/02 Montreal.flac -#EXTINF:-1,Bark Psychosis - bark psychosis - eyes & smiles -/app/music/Bark Psychosis/1994 - Hex/05 - bark psychosis - eyes & smiles.mp3 -#EXTINF:-1,The Other People Place - D2 - Sunrays -/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/D2 - Sunrays.flac -#EXTINF:-1,Bark Psychosis - (06) [Bark Psychosis] Bloodrush -/app/music/Bark Psychosis/1994 - Game Over/(06) [Bark Psychosis] Bloodrush.flac -#EXTINF:-1,Bark Psychosis - bark psychosis - pendulum man -/app/music/Bark Psychosis/1994 - Hex/07 - bark psychosis - pendulum man.mp3 -#EXTINF:-1,Autechre - Slip -/app/music/Autechre/1994 - Amber/04 Slip.flac -#EXTINF:-1,Kiasmos - Swayed -/app/music/Kiasmos/2014 - Kiasmos/04 - Swayed.flac -#EXTINF:-1,The Other People Place - A1 - Eye Contact -/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/A1 - Eye Contact.flac -#EXTINF:-1,Kiasmos - Rival Consoles - Milo -/app/music/Kiasmos/2009 - 65, Milo (Kiasmos & Rival Consoles) (WEB)/03. Rival Consoles - Milo.flac -#EXTINF:-1,Teeth Of The Sea - Butterfly House -/app/music/Teeth Of The Sea/2023 - Hive/03 Butterfly House.flac -#EXTINF:-1,The Orb - A Mile Long Lump of Lard -/app/music/The Orb/2001 - Cydonia/07-A Mile Long Lump of Lard.mp3 -#EXTINF:-1,Autechre - Eutow -/app/music/Autechre/1995 - Tri Repetae/06 Eutow.flac -#EXTINF:-1,Model 500 - model_500-the_groove -/app/music/Model 500/2015 - Digital Solutions/06-model_500-the_groove.flac -#EXTINF:-1,Bark Psychosis - bark psychosis - big shot -/app/music/Bark Psychosis/1994 - Hex/04 - bark psychosis - big shot.mp3 -#EXTINF:-1,Kiasmos - Rival Consoles - ARP -/app/music/Kiasmos/2009 - 65, Milo (Kiasmos & Rival Consoles) (WEB)/05. Rival Consoles - ARP.flac -#EXTINF:-1,Kraftwerk - Spacelab -/app/music/Kraftwerk/1978 - The Man-Machine/02 - Spacelab.flac -#EXTINF:-1,Brian Eno - Who Gives a Thought -/app/music/Brian Eno/2022 - ForeverAndEverNoMore/01 Who Gives a Thought.flac -#EXTINF:-1,Proem - Proem - Vault ep.4-4 - 04 v. jirku 1 -/app/music/Proem/2015 - Vault ep.4-4/Proem - Vault ep.4-4 - 04 v. jirku 1.flac -#EXTINF:-1,Tape Loop Orchestra - The Burnley Brass Band Plays On In My Heart -/app/music/Tape Loop Orchestra/2012 - The Word On My Lips Is Your Name/Disc 2 - The Burnley Brass Band Plays On In My Heart/01 - The Burnley Brass Band Plays On In My Heart.flac -#EXTINF:-1,Proem - Proem - Before it finds you - 06 Pretense for piano and synth -/app/music/Proem/2013 - Before it finds you/Proem - Before it finds you - 06 Pretense for piano and synth.flac -#EXTINF:-1,Orbital - Remind -/app/music/Orbital/1993 - Orbital - Orbital 2 (Brown Album - TRUCD2, 828 386.2)/00. Remind.mp3 -#EXTINF:-1,Underworld - Underworld - Pearls Girl -/app/music/Underworld/1996 - Second Toughest In The Infants/05. Underworld - Pearls Girl.flac -#EXTINF:-1,Underworld - Underworld - Banstyle Sappys Curry -/app/music/Underworld/1996 - Second Toughest In The Infants/02. Underworld - Banstyle Sappys Curry.flac -#EXTINF:-1,Orbital - Attached -/app/music/Orbital/1994 - Orbital - Snivilisation (TRUCD5, 828 536.2)/10. Attached.mp3 -#EXTINF:-1,Labradford - P -/app/music/Labradford/1997 - Mi Media Naranja/7 P.flac -#EXTINF:-1,Drexciya - Drexciya - Vampire Island -/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/10. Drexciya - Vampire Island.mp3 -#EXTINF:-1,Vector Lovers - Arrival, Metropolis -/app/music/Vector Lovers/2005 - Capsule For One/02 - Arrival, Metropolis.mp3 -#EXTINF:-1,Teeth Of The Sea - Teeth Of The Sea - Highly Deadly Black Tarantula - 03 Field Punishment -/app/music/Teeth Of The Sea/2015 - Highly Deadly Black Tarantula/Teeth Of The Sea - Highly Deadly Black Tarantula - 03 Field Punishment.flac -#EXTINF:-1,Kiasmos - Swept (Tale of Us remix) -/app/music/Kiasmos/2015 - Swept EP/04 - Swept (Tale of Us remix).mp3 -#EXTINF:-1,Proem - Proem - Vault ep.1-4 (Noise) - 05 Only Eat the Grey Wolves -/app/music/Proem/2016 - Vault ep.1-4 (Noise)/Proem - Vault ep.1-4 (Noise) - 05 Only Eat the Grey Wolves.flac -#EXTINF:-1,The Orb - Firestar -/app/music/The Orb/2001 - Cydonia/06-Firestar.mp3 -#EXTINF:-1,Tape Loop Orchestra - Tape Loop Orchestra - Chapter 11   Late Autumn -/app/music/Tape Loop Orchestra/2009 - 1953 Culture Festival/11 Tape Loop Orchestra - Chapter 11   Late Autumn.mp3 -#EXTINF:-1,Kraftwerk - The Man·Machine -/app/music/Kraftwerk/1978 - The Man-Machine/06 - The Man·Machine.flac +#PLAYLIST:Escape Velocity - A Christmas Journey Through Space +#PHASE:Escape Velocity +#DURATION:12 hours (approx) +#CURATOR:Asteroid Radio +#DESCRIPTION:A festive 12-hour voyage blending Christmas classics with ambient, IDM, and space music for the holiday season + +# === PHASE 1: WINTER AWAKENING (Ambient Beginnings) === +#EXTINF:-1,Brian Eno - Snow +/app/music/Brian Eno/2020 - Roger Eno and Brian Eno - Mixing Colours/09 Snow.flac +#EXTINF:-1,Brian Eno - Wintergreen +/app/music/Brian Eno/2020 - Roger Eno and Brian Eno - Mixing Colours/04 Wintergreen.flac +#EXTINF:-1,Proem - Winter Wolves +/app/music/Proem - 2018 Modern Rope (WEB)/01. Winter Wolves.flac +#EXTINF:-1,Tim Hecker - Winter's Coming +/app/music/Tim Hecker - The North Water Original Score (2021 - WEB - FLAC)/Tim Hecker - The North Water (Original Score) - 10 Winter's Coming.flac +#EXTINF:-1,Biosphere - Drifter +/app/music/Biosphere - The Petrified Forest (2017) - CD FLAC/01. Biosphere - Drifter.flac +#EXTINF:-1,Dead Voices On Air - On Winters Gibbet +/app/music/Dead Voices On Air - Ghohst Stories (FLAC)/02 - On Winters Gibbet.flac +#EXTINF:-1,Color Therapy - Wintering +/app/music/Color Therapy - Mr. Wolf Is Dead (2015) WEB FLAC/12 - Wintering.flac + +# === PHASE 2: CHRISTMAS ARRIVAL (TSO Introduction) === +#EXTINF:-1,Trans-Siberian Orchestra - The Ghosts Of Christmas Eve +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/01 The Ghosts Of Christmas Eve.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas In The Air +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/14 Christmas In The Air.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Canon +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/08 Christmas Canon.flac +#EXTINF:-1,Trans-Siberian Orchestra - Appalachian Snowfall +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/11 Appalachian Snowfall.flac +#EXTINF:-1,Trans-Siberian Orchestra - The Snow Came Down +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/13 The Snow Came Down.flac + +# === PHASE 3: AMBIENT INTERLUDE (Space & Atmosphere) === +#EXTINF:-1,Biosphere - 10 Snurp 1937 +/app/music/Biosphere - Sound Installations -2000-2009 [FLAC]/Biosphere - Sound Installations -2000-2009- - 10 Snurp 1937.flac +#EXTINF:-1,Biosphere - 05 Fluvialmorphologie +/app/music/Biosphere - Sound Installations -2000-2009 [FLAC]/Biosphere - Sound Installations -2000-2009- - 05 Fluvialmorphologie.flac +#EXTINF:-1,God is an Astronaut - Winter Dusk-Awakening +/app/music/God is an Astronaut - Epitaph (2018) WEB FLAC/03. Winter Dusk-Awakening.flac +#EXTINF:-1,Proem - Snow Drifts +/app/music/Proem - Twelve Tails-(2021) @FLAC [16-48]/11 - Snow Drifts.flac +#EXTINF:-1,Proem - Stick to Music Snowflake +/app/music/Proem - Until Here for Years (n5md, 2019) flac/04 - Stick to Music Snowflake.flac +#EXTINF:-1,Four Tet - 04 Tremper +/app/music/Four Tet - New Energy {CD} [FLAC] (2017)/04 Tremper.flac + +# === PHASE 4: CHRISTMAS EVE STORIES === +#EXTINF:-1,Trans-Siberian Orchestra - First Snow (Instrumental) +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/Christmas Eve and Other Stories/04 First Snow (Instrumental).flac +#EXTINF:-1,Trans-Siberian Orchestra - The Silent Nutcracker (Instrumental) +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/Christmas Eve and Other Stories/05 The Silent Nutcracker (Instrumental).flac +#EXTINF:-1,Trans-Siberian Orchestra - A Mad Russian's Christmas (Instrumental) +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/Christmas Eve and Other Stories/06 A Mad Russian's Christmas (Instrumental).flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Eve,Sarajevo 12,24 (Instrumental) +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/Christmas Eve and Other Stories/08 Christmas Eve,Sarajevo 12,24 (Instrumental).flac +#EXTINF:-1,Trans-Siberian Orchestra - This Christmas Day +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/Christmas Eve and Other Stories/14 This Christmas Day.flac + +# === PHASE 5: ELECTRONIC DREAMS (IDM & Ambient) === +#EXTINF:-1,Autechre - NTS Session 1-005-Autechre-carefree counter dronal +/app/music/Autechre - 2018 - NTS Session 1/NTS Session 1-005-Autechre-carefree counter dronal.flac +#EXTINF:-1,Clark - Living Fantasy +/app/music/Clark - Death Peak (2017) [FLAC]/08 - Living Fantasy.flac +#EXTINF:-1,Clark - My Machines (Clark Remix) +/app/music/Clark - Feast Beast (2013) [24 Bit WEB FLAC] [16-44]/1.17. Battles - My Machines (Clark Remix).flac +#EXTINF:-1,Plaid - Dancers +/app/music/Plaid - Polymer (2019) [WEB FLAC]/07 - Dancers.flac +#EXTINF:-1,Faux Tales - Avalon +/app/music/Faux Tales - 2015 - Kairos [FLAC] {Kensai Records KNS006 WEB}/3 - Avalon.flac +#EXTINF:-1,Color Therapy - Expect Delays (feat. Ulrich Schnauss) +/app/music/Color Therapy - Mr. Wolf Is Dead (2015) WEB FLAC/11 - Expect Delays (feat. Ulrich Schnauss).flac + +# === PHASE 6: THE LOST CHRISTMAS EVE === +#EXTINF:-1,Trans-Siberian Orchestra - The Lost Christmas Eve +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/02 The Lost Christmas Eve.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Dreams +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/03 Christmas Dreams.flac +#EXTINF:-1,Trans-Siberian Orchestra - Wizards in Winter +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/04 Wizards in Winter.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Concerto +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/07 Christmas Concerto.flac +#EXTINF:-1,Trans-Siberian Orchestra - Queen Of The Winter Night +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/08 Queen Of The Winter Night.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Nights In Blue +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/09 Christmas Nights In Blue.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Jazz +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/10 Christmas Jazz.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Jam +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/11 Christmas Jam.flac + +# === PHASE 7: CLASSICAL WINTER (Nutcracker & More) === +#EXTINF:-1,Various Artists - Dance of the Sugar-Plum Fairy +/app/music/Various Artists - The 50 Darkest Pieces of Classical Music (2011) - FLAC/CD 1/02 - Tchaikovsky - The Nutcracker - Dance of the Sugar-Plum Fairy.flac +#EXTINF:-1,Quaeschning and Ulrich Schnauss - Thirst +/app/music/Quaeschning and Ulrich Schnauss - Synthwaves (2017) {vista003, GER, CD} [FLAC]/06 - Thirst.flac +#EXTINF:-1,Proem - 04. Drawing Room Anguish +/app/music/Proem - 2018 Modern Rope (WEB)/04. Drawing Room Anguish.flac +#EXTINF:-1,Dead Voices On Air - 07. Dogger Doorlopende Split +/app/music/Dead Voices On Air - Frankie Pett En De Onderzeer Boten (2017) web/07. Dogger Doorlopende Split.flac + +# === PHASE 8: WISDOM & REFLECTION === +#EXTINF:-1,Trans-Siberian Orchestra - What Is Christmas +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/13 What Is Christmas.flac +#EXTINF:-1,Trans-Siberian Orchestra - The Wisdom Of Snow +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/15 The Wisdom Of Snow.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Bells, Carousels & Time +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/18 Christmas Bells, Carousels & Time.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas Canon Rock +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Lost Christmas Eve/21 Christmas Canon Rock.flac +#EXTINF:-1,Trans-Siberian Orchestra - Midnight Christmas Eve +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/05 Midnight Christmas Eve.flac +#EXTINF:-1,Trans-Siberian Orchestra - Dream Child (A Christmas Dream) +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/15 Dream Child (A Christmas Dream).flac + +# === PHASE 9: DEEP SPACE JOURNEY (Extended Ambient) === +#EXTINF:-1,Dead Voices On Air - Red Howls +/app/music/Dead Voices On Air - Ghohst Stories (FLAC)/01 - Red Howls.flac +#EXTINF:-1,Cut Copy - Airborne +/app/music/Cut Copy - Haiku From Zero (2017) [FLAC] {2557864014}/05 - Airborne.flac +#EXTINF:-1,Owl City - 01 Hot Air Balloon +/app/music/Owl City - Ocean Eyes (Deluxe Edition) [Flac,Cue,Logs]/Disc 2/01 Hot Air Balloon.flac +#EXTINF:-1,VA - What Is Loneliness (feat. Danny Claire) [Skylex Radio Edit] +/app/music/VA - Melodic Vocal Trance 2017/24. Airborn, Bogdan Vix & KeyPlayer - What Is Loneliness (feat. Danny Claire) [Skylex Radio Edit].flac +#EXTINF:-1,VA - Winter Took Over (Radio Edit) +/app/music/VA - Melodic Vocal Trance 2017/22. Bluskay, KeyPlayer & Esmee Bor Stotijn - Winter Took Over (Radio Edit).flac +#EXTINF:-1,Alison Krauss and Union Station - My Opening Farewell +/app/music/Alison Krauss and Union Station - Paper Airplane (flac)/11 - Alison Krauss & Union Station - My Opening Farewell.flac +#EXTINF:-1,Bedouin Soundclash - Money Worries (E-Clair Refix) +/app/music/Bedouin Soundclash - Sounding a Mosaic (2004) [FLAC] {SD1267}/14 - Money Worries (E-Clair Refix).flac + +# === PHASE 10: RETURN TO WINTER (Closing Circle) === +#EXTINF:-1,Brian Eno - Snow +/app/music/Brian Eno/2020 - Roger Eno and Brian Eno - Mixing Colours/09 Snow.flac +#EXTINF:-1,Proem - Winter Wolves +/app/music/Proem - 2018 Modern Rope (WEB)/01. Winter Wolves.flac +#EXTINF:-1,God is an Astronaut - Winter Dusk-Awakening +/app/music/God is an Astronaut - Epitaph (2018) WEB FLAC/03. Winter Dusk-Awakening.flac +#EXTINF:-1,Trans-Siberian Orchestra - The Snow Came Down +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/13 The Snow Came Down.flac +#EXTINF:-1,Trans-Siberian Orchestra - Christmas In The Air +/app/music/Trans-Siberian Orchestra - The Christmas Trilogy (2004) [FLAC]/The Christmas Attic/14 Christmas In The Air.flac diff --git a/stream-media.lisp b/stream-media.lisp index 3b8b787..5486f56 100644 --- a/stream-media.lisp +++ b/stream-media.lisp @@ -10,13 +10,14 @@ "Recursively scan directory for supported audio files" (when (cl-fad:directory-exists-p directory) (remove-if-not #'supported-audio-file-p - (cl-fad:list-directory directory :follow-symlinks nil)))) + (cl-fad:list-directory directory :follow-symlinks t)))) (defun scan-directory-for-music-recursively (path) "Recursively scan directory and all subdirectories for music files" - (let ((files-in-current-dir (scan-directory-for-music path)) - (files-in-subdirs (loop for directory in (uiop:subdirectories path) - appending (scan-directory-for-music-recursively directory)))) + (let* ((resolved-path (truename path)) + (files-in-current-dir (scan-directory-for-music resolved-path)) + (files-in-subdirs (loop for directory in (uiop:subdirectories resolved-path) + appending (scan-directory-for-music-recursively directory)))) (append files-in-current-dir files-in-subdirs))) (defun extract-metadata-with-taglib (file-path) @@ -92,16 +93,25 @@ (setf (dm:field track "file-path") file-path) (setf (dm:field track "format") (getf metadata :format)) (setf (dm:field track "bitrate") (getf metadata :bitrate)) - (setf (dm:field track "added-date") (local-time:timestamp-to-unix (local-time:now))) + ;; Let database default handle added-date (CURRENT_TIMESTAMP) (setf (dm:field track "play-count") 0) (dm:insert track) t)))) (defun scan-music-library (&optional (directory *music-library-path*)) "Scan music library directory and add tracks to database" + (format t "~%=== SCAN DEBUG ===~%") + (format t "Input directory: ~a~%" directory) + (format t "Directory exists: ~a~%" (probe-file directory)) + (handler-case + (format t "Resolved path: ~a~%" (truename directory)) + (error (e) (format t "Cannot resolve truename: ~a~%" e))) (let ((audio-files (scan-directory-for-music-recursively directory)) (added-count 0) (skipped-count 0)) + (format t "Found ~a audio files~%" (length audio-files)) + (when (> (length audio-files) 0) + (format t "First few files: ~{~a~%~}~%" (subseq audio-files 0 (min 3 (length audio-files))))) (dolist (file audio-files) (let ((metadata (extract-metadata-with-taglib file))) (when metadata @@ -111,6 +121,7 @@ (incf skipped-count)) (error (e) (format t "Error adding ~a: ~a~%" file e)))))) + (format t "Added: ~a, Skipped: ~a~%" added-count skipped-count) added-count)) ;; Initialize music directory structure diff --git a/template/admin.ctml b/template/admin.ctml index 7eb54c9..2c078c5 100644 --- a/template/admin.ctml +++ b/template/admin.ctml @@ -38,6 +38,7 @@

Icecast Status

🔴 Not Running

+
@@ -162,43 +163,91 @@

🎵 Stream Queue Management

-

Manage the live stream playback queue. Changes take effect within 5-10 seconds.

+

Manage the live stream playback queue. Liquidsoap watches stream-queue.m3u and reloads automatically.

-
- - - - + +
+

📋 Load Playlist

+
+ + + +
+

+ Loading a playlist will copy it to stream-queue.m3u and Liquidsoap will start playing it. +

-
+ +
+ + + + +
+ + +
+ + +
+ + +
+ 0 tracks in queue +
+ + +
Loading queue...
-
+

Add Tracks to Queue

- +
-

Player Control

-
-

🎵 Player Control

-
- - - - +

📡 Stream Control (Liquidsoap)

+

Control the live audio stream. Commands are sent directly to Liquidsoap.

+ + +
+
+
+ Uptime: -- +
+
+ Remaining: -- +
-
- Status: Unknown
- Current Track: None +
+ Now Playing: --
+ + +
+ + + + +
+ +

+ Skip Track: Immediately skip to the next track in the playlist.
+ Reload Playlist: Force Liquidsoap to re-read stream-queue.m3u.
+ Restart Container: Restart the Liquidsoap Docker container (causes brief stream interruption). +

+
+ +

👥 User Management

Manage user accounts, roles, and permissions.