diff --git a/src/cljs/airsonic_ui/audio/playlist.cljs b/src/cljs/airsonic_ui/audio/playlist.cljs index f86ac6e..47032ee 100644 --- a/src/cljs/airsonic_ui/audio/playlist.cljs +++ b/src/cljs/airsonic_ui/audio/playlist.cljs @@ -18,8 +18,14 @@ (set-repeat-mode [this repeat-mode] "Allows you to change how the next and previous song are selected") - (enqueue-last [this song]) - (enqueue-next [this song]) + (enqueue-last + [this song source] + [this song] + "Registers a song to be played last, optionally remembering the source route") + (enqueue-next + [this song source] + [this song] + "Registers a song to be played next, optionally remembering the source route") (move-song [this from-idx to-idx] "Allows you to move a song in a playlist") @@ -107,22 +113,28 @@ (set-repeat-mode [playlist repeat-mode] (assoc playlist :repeat-mode repeat-mode)) - (enqueue-last [this song] + (enqueue-last [this song source] (let [order (inc (key (last items)))] ;; Arguably this is a bit weird; but if you want to play something last in ;; a shuffled playlist, you want to play it last I guess. (assoc-in this [:items order] - (vary-meta song assoc :playlist/linear-order order)))) + (vary-meta song assoc + :playlist/linear-order order + :playlist/source source)))) + (enqueue-last [this song] (enqueue-last this song nil)) - (enqueue-next [this song] + (enqueue-next [this song source] ;; we slice the songs up until the currently playing one and increase the ;; order for all the songs after (let [songs (vec (vals items)) reordered (-> (subvec songs 0 (inc current-idx)) - (conj (vary-meta song assoc :playlist/linear-order (inc current-idx))) + (conj (vary-meta song assoc + :playlist/linear-order (inc current-idx) + :playlist/source source)) (concat (subvec songs (inc current-idx))))] (assoc this :items (->> (map-indexed vector reordered) (into (sorted-map)))))) + (enqueue-next [this song] (enqueue-next this song nil)) (move-song [this from-idx to-idx] ;; we have to decide whether we move all items in-between @@ -156,15 +168,29 @@ ;; constructor wrapper +(defn set-item-source + "Can be used to attach a source route to an item" + [item source] + (vary-meta item assoc :playlist/source source)) + +(defn item-source + "Retrieve the source of an item in the playlist" + [item] + (:playlist/source (meta item))) + (defmulti ->playlist "Creates a new playlist that behaves according to the given playback- and repeat-mode parameters." (fn [_ & {:keys [playback-mode]}] playback-mode)) (defmethod ->playlist :linear - [items & {:keys [playback-mode repeat-mode]}] - (->Playlist (linear-queue items) 0 playback-mode repeat-mode)) + [items & {:keys [playback-mode repeat-mode source]}] + (->Playlist (->> (map #(set-item-source % source) items) + (linear-queue)) + 0 playback-mode repeat-mode)) (defmethod ->playlist :shuffled - [items & {:keys [playback-mode repeat-mode]}] - (->Playlist (shuffled-queue items) 0 playback-mode repeat-mode)) + [items & {:keys [playback-mode repeat-mode source]}] + (->Playlist (->> (map #(set-item-source % source) items) + (shuffled-queue)) + 0 playback-mode repeat-mode)) diff --git a/src/cljs/airsonic_ui/components/audio_player/events.cljs b/src/cljs/airsonic_ui/components/audio_player/events.cljs index fc8d87b..c476049 100644 --- a/src/cljs/airsonic_ui/components/audio_player/events.cljs +++ b/src/cljs/airsonic_ui/components/audio_player/events.cljs @@ -3,14 +3,18 @@ [airsonic-ui.audio.playlist :as playlist] [airsonic-ui.api.helpers :as api])) +; sets up the db, starts to play a song and adds the rest to a playlist +(defn play-all-songs [{:keys [db] + :routes/keys [current-route]} [_ songs start-idx]] + (let [playlist (-> (playlist/->playlist songs :playback-mode :linear :repeat-mode :repeat-all :source current-route) + (playlist/set-current-song start-idx))] + {:audio/play (api/stream-url (:credentials db) (playlist/current-song playlist)) + :db (assoc-in db [:audio :current-playlist] playlist)})) + (rf/reg-event-fx - ; sets up the db, starts to play a song and adds the rest to a playlist :audio-player/play-all - (fn [{:keys [db]} [_ songs start-idx]] - (let [playlist (-> (playlist/->playlist songs :playback-mode :linear :repeat-mode :repeat-all) - (playlist/set-current-song start-idx))] - {:audio/play (api/stream-url (:credentials db) (playlist/current-song playlist)) - :db (assoc-in db [:audio :current-playlist] playlist)}))) + [(rf/inject-cofx :routes/current-route)] + play-all-songs) (rf/reg-event-db :audio-player/set-playback-mode @@ -46,15 +50,19 @@ (rf/reg-event-fx :audio-player/set-current-song set-current-song) -(rf/reg-event-db +(rf/reg-event-fx :audio-player/enqueue-next - (fn [db [_ song]] - (update-in db [:audio :current-playlist] #(playlist/enqueue-next % song)))) + [(rf/inject-cofx :routes/current-route)] + (fn [{:keys [db] + :routes/keys [current-route]} [_ song]] + {:db (update-in db [:audio :current-playlist] #(playlist/enqueue-next % song current-route))})) -(rf/reg-event-db +(rf/reg-event-fx :audio-player/enqueue-last - (fn [db [_ song]] - (update-in db [:audio :current-playlist] #(playlist/enqueue-last % song)))) + [(rf/inject-cofx :routes/current-route)] + (fn [{:keys [db] + :routes/keys [current-route]} [_ song]] + {:db (update-in db [:audio :current-playlist] #(playlist/enqueue-last % song current-route))})) (rf/reg-event-db :audio-player/move-song diff --git a/src/cljs/airsonic_ui/components/current_queue/views.cljs b/src/cljs/airsonic_ui/components/current_queue/views.cljs index 27c15dc..9b52ed8 100644 --- a/src/cljs/airsonic_ui/components/current_queue/views.cljs +++ b/src/cljs/airsonic_ui/components/current_queue/views.cljs @@ -5,6 +5,7 @@ [bulma.icon :refer [icon]] [bulma.dropdown.views :refer [dropdown]] [airsonic-ui.helpers :as helpers] + [airsonic-ui.audio.playlist :as playlist] [airsonic-ui.components.collection.views :as collection] [airsonic-ui.components.sortable.views :as sortable] [airsonic-ui.routes :as routes] @@ -22,11 +23,10 @@ [icon :elevator]])))) (defn song-actions [{:keys [song idx]}] - ;; TODO: Implement both of these [dropdown {:items [{:label "Remove from queue" :event [:audio-player/remove-song idx]} {:label "Go to source" - :event []}]}]) + :event [:routes/do-navigation (playlist/item-source song)]}]}]) (defn artist-link [{id :artistId, artist :artist}] (if id