mirror of
https://github.com/heyarne/airsonic-ui.git
synced 2026-05-07 02:33:39 +02:00
144 lines
3.4 KiB
Clojure
144 lines
3.4 KiB
Clojure
(ns airsonic-ui.audio.core
|
|
"This namespace contains some JS interop code to interact with an audio player
|
|
and receive information about the current playback status so we can use it in
|
|
our re-frame app."
|
|
(:require [re-frame.core :as rf]
|
|
[airsonic-ui.audio.playlist :as playlist]
|
|
[goog.functions :refer [throttle]]))
|
|
|
|
(defonce audio (atom nil))
|
|
|
|
(defn normalize-time-ranges [time-ranges]
|
|
(if (> (.-length time-ranges) 0)
|
|
(.end time-ranges (dec (.-length time-ranges)))
|
|
0))
|
|
|
|
(defn ->status
|
|
"Takes an audio object and returns a map describing its current status"
|
|
[elem]
|
|
{:ended? (.-ended elem)
|
|
:paused? (.-paused elem)
|
|
:current-src (.-currentSrc elem)
|
|
:current-time (.-currentTime elem)
|
|
:seekable (normalize-time-ranges (.-seekable elem))
|
|
:buffered (normalize-time-ranges (.-buffered elem))
|
|
:volume (.-volume elem)})
|
|
|
|
; explanation of these events: https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery/Cross-browser_audio_basics
|
|
|
|
(defn attach-listeners! [el]
|
|
(let [emit-audio-update (throttle #(rf/dispatch [:audio/update (->status el)]) 16)]
|
|
(doseq [event ["loadstart" "progress" "play" "timeupdate" "pause" "volumechange"]]
|
|
(.addEventListener el event emit-audio-update))))
|
|
|
|
;; effects to be fired from event handlers
|
|
|
|
(rf/reg-fx
|
|
:audio/play
|
|
(fn [stream-url]
|
|
(when-not @audio
|
|
(reset! audio (js/Audio.))
|
|
(attach-listeners! @audio))
|
|
(.pause @audio)
|
|
(set! (.-src @audio) stream-url)
|
|
(.play @audio)))
|
|
|
|
(rf/reg-fx
|
|
:audio/pause
|
|
(fn [_]
|
|
(some-> @audio .pause)))
|
|
|
|
(rf/reg-fx
|
|
:audio/stop
|
|
(fn [_]
|
|
(when-let [audio @audio]
|
|
(.pause audio)
|
|
(set! (.-currentTime audio) 0))))
|
|
|
|
(rf/reg-fx
|
|
:audio/toggle-play-pause
|
|
(fn [_]
|
|
(if-let [a @audio]
|
|
(if (.-paused a)
|
|
(.play a)
|
|
(.pause a)))))
|
|
|
|
(rf/reg-fx
|
|
:audio/seek
|
|
(fn [[percentage duration]]
|
|
(set! (. @audio -currentTime)
|
|
(* percentage duration))))
|
|
|
|
(defn- set-volume! [volume]
|
|
(set! (.-volume @audio) volume))
|
|
|
|
(rf/reg-fx
|
|
:audio/set-volume
|
|
(fn [percentage]
|
|
(when @audio
|
|
(set-volume! percentage))))
|
|
|
|
(rf/reg-fx
|
|
:audio/increase-volume
|
|
(fn [_]
|
|
(when-let [vol (some-> @audio .-volume)]
|
|
(set-volume! (min 1 (+ vol 0.05))))))
|
|
|
|
(rf/reg-fx
|
|
:audio/decrease-volume
|
|
(fn [_]
|
|
(when-let [vol (some-> @audio .-volume)]
|
|
(set-volume! (max 0 (- vol 0.05))))))
|
|
|
|
;; subscriptions
|
|
|
|
(defn summary
|
|
"Returns all information about audio that we have"
|
|
[db _]
|
|
(:audio db))
|
|
|
|
(rf/reg-sub :audio/summary summary)
|
|
|
|
(defn current-queue
|
|
"Lists the complete current-queue"
|
|
[summary _]
|
|
(:current-queue summary))
|
|
|
|
(rf/reg-sub
|
|
:audio/current-queue
|
|
:<- [:audio/summary]
|
|
current-queue)
|
|
|
|
(defn current-song
|
|
"Gives us information about the currently played song as presented by
|
|
the airsonic api"
|
|
[playlist _]
|
|
(when-not (empty? playlist)
|
|
(playlist/current-song playlist)))
|
|
|
|
|
|
(rf/reg-sub
|
|
:audio/current-song
|
|
:<- [:audio/current-queue]
|
|
current-song)
|
|
|
|
(defn playback-status
|
|
"Gives us information about the most recently fired html 5 audio event"
|
|
[summary _]
|
|
(:playback-status summary))
|
|
|
|
(rf/reg-sub
|
|
:audio/playback-status
|
|
:<- [:audio/summary]
|
|
playback-status)
|
|
|
|
(defn is-playing?
|
|
"Predicate to tell us whether we currently have audio output or not"
|
|
[playback-status _]
|
|
(and (not (:paused? playback-status))
|
|
(not (:ended? playback-status))))
|
|
|
|
(rf/reg-sub
|
|
:audio/is-playing?
|
|
:<- [:audio/playback-status]
|
|
is-playing?)
|