1
0
Fork 0
mirror of https://github.com/heyarne/airsonic-ui.git synced 2026-05-07 10:43:39 +02:00

Add skipping for linear playlists with all repeat modes

This commit is contained in:
Arne Schlüter 2018-08-07 15:15:13 +02:00
commit d7b8cbcc4e
3 changed files with 99 additions and 32 deletions

View file

@ -11,38 +11,39 @@
(defmulti ->playlist (defmulti ->playlist
"Creates a new playlist that behaves according to the given playback- and "Creates a new playlist that behaves according to the given playback- and
repeat-mode parameters." repeat-mode parameters."
(fn [queue play-idx playback-mode repeat-mode] playback-mode)) (fn [queue playing-idx playback-mode repeat-mode] playback-mode))
(defn- playlist-queue (defn- playlist-queue
[queue play-idx] [queue playing-idx]
(concat (take play-idx queue) (concat (take playing-idx queue)
[(assoc (nth queue play-idx) :currently-playing? true)] [(assoc (nth queue playing-idx) :currently-playing? true)]
(drop (inc play-idx) queue))) (drop (inc playing-idx) queue)))
(defmethod ->playlist (defmethod ->playlist :playback-mode/linear
:playback-mode/linear [queue playing-idx playback-mode repeat-mode]
[queue play-idx playback-mode repeat-mode] (let [queue (->> (playlist-queue queue playing-idx)
(let [queue (->> (playlist-queue queue play-idx) (mapv (fn [order song] (assoc song :order order))
(map (fn [order song] (assoc song :order order))
(range (count queue))))] (range (count queue))))]
(->Playlist queue playback-mode repeat-mode))) (->Playlist queue playback-mode repeat-mode)))
(defmethod ->playlist (defmethod ->playlist :playback-mode/shuffle
:playback-mode/shuffle [queue playing-idx playback-mode repeat-mode]
[queue play-idx playback-mode repeat-mode] (let [queue (->> (playlist-queue queue playing-idx)
(let [queue (->> (playlist-queue queue play-idx) (mapv (fn [order song] (assoc song :order order))
(map (fn [order song] (assoc song :order order))
(shuffle (range (count queue)))))] (shuffle (range (count queue)))))]
(->Playlist queue playback-mode repeat-mode))) (->Playlist queue playback-mode repeat-mode)))
(defn set-playback-mode (defn- current-idx [playlist]
"Changes the playback mode of a playlist and re-suffles it if necessary" (first (keep-indexed (fn [idx item]
[playlist playback-mode]
(let [current-idx (first (keep-indexed (fn [idx item]
(when (:currently-playing? item) (when (:currently-playing? item)
idx)) idx))
(:queue playlist)))] (:queue playlist))))
(->playlist (:queue playlist) current-idx playback-mode (:repeat-mode playlist))))
(defn set-playback-mode
"Changes the playback mode of a playlist and re-shuffles it if necessary"
[playlist playback-mode]
(->playlist (:queue playlist) (current-idx playlist)
playback-mode (:repeat-mode playlist)))
(defn set-repeat-mode (defn set-repeat-mode
"Allows to change the way the next and previous song of a playlist is selected" "Allows to change the way the next and previous song of a playlist is selected"
@ -56,5 +57,38 @@
(filter :currently-playing?) (filter :currently-playing?)
(first))) (first)))
(defn- ?assoc
"Like assoc, but returns coll unchanged if (pref coll) is false"
[coll pred & assog-args]
(if (pred coll) (apply assoc coll assog-args) coll))
(defmulti next-song (juxt :playback-mode :repeat-mode)) (defmulti next-song (juxt :playback-mode :repeat-mode))
(defmethod next-song [:playback-mode/linear :repeat-mode/none]
[playlist]
(let [current-idx (current-idx playlist)
next-idx (inc current-idx)]
(println "next-idx" next-idx "current-idx" current-idx "(< next-idx (count playlist))" (< next-idx (count playlist)))
(update playlist :queue
(fn [queue] (-> (update queue current-idx dissoc :currently-playing?)
(?assoc #(< next-idx (count playlist))
next-idx (assoc (get queue next-idx)
:currently-playing? true)))))))
(defmethod next-song [:playback-mode/linear :repeat-mode/single]
[playlist]
playlist)
(defmethod next-song [:playback-mode/linear :repeat-mode/all]
[playlist]
(let [current-idx (current-idx playlist)
next-idx (mod (inc current-idx) (count playlist))]
(update playlist :queue
(fn [queue] (-> (update queue current-idx dissoc :currently-playing?)
(assoc-in [next-idx :currently-playing?] true))))))
(defmethod next-song [:playback-mode/shuffle :repeat-mode/single]
[playlist]
playlist)
(defmulti previous-song (juxt :playback-mode :repeat-mode)) (defmulti previous-song (juxt :playback-mode :repeat-mode))

View file

@ -3,8 +3,7 @@
[ajax.core :as ajax] [ajax.core :as ajax]
[airsonic-ui.routes :as routes] [airsonic-ui.routes :as routes]
[airsonic-ui.db :as db] [airsonic-ui.db :as db]
[airsonic-ui.utils.api :as api] [airsonic-ui.utils.api :as api]))
[day8.re-frame.tracing :refer-macros [fn-traced defn-traced]])) ; <- useful to debug handlers
(re-frame/reg-fx (re-frame/reg-fx
;; a simple effect to keep println statements out of our event handlers ;; a simple effect to keep println statements out of our event handlers

View file

@ -2,7 +2,8 @@
(:require [cljs.test :refer [deftest testing is]] (:require [cljs.test :refer [deftest testing is]]
[airsonic-ui.audio.playlist :as playlist] [airsonic-ui.audio.playlist :as playlist]
[airsonic-ui.fixtures :as fixtures] [airsonic-ui.fixtures :as fixtures]
[airsonic-ui.test-helpers :as helpers])) [airsonic-ui.test-helpers :as helpers]
[debux.cs.core :refer-macros [dbg]]))
(enable-console-print!) (enable-console-print!)
@ -90,14 +91,47 @@
(str "from " repeat-mode " to " next-repeat-mode))))))) (str "from " repeat-mode " to " next-repeat-mode)))))))
(deftest linear-next-song (deftest linear-next-song
(testing "Should follow the same order as the queue used for creation") (testing "Should follow the same order as the queue used for creation"
(testing "Should go back to the first song when repeat-mode is all") (doseq [repeat-mode [:repeat-mode/none :repeat-mode/all]]
(testing "Should always give the same track when repeat-mode is single")) (let [queue (playing-queue 5)
playlist (playlist/->playlist queue 0 :playback-mode/linear repeat-mode)]
(is (same-song? (nth queue 1) (-> (playlist/next-song playlist)
(playlist/peek)))
(str repeat-mode ", skipped once"))
(is (same-song? (nth queue 2) (-> (playlist/next-song playlist)
(playlist/next-song)
(playlist/peek)))
(str repeat-mode ", skipped twice")))))
(testing "Should go back to the first song when repeat-mode is all and we played the last song")
(testing "Should always give the same track when repeat-mode is single"
(let [queue (playing-queue 3)
playing-idx (rand-int 3)
playlist (playlist/->playlist queue playing-idx :playback-mode/linear :repeat-mode/single)]
(is (same-song? (nth queue playing-idx) (playlist/peek playlist)))
(is (same-song? (nth queue playing-idx)
(-> (playlist/next-song playlist)
(playlist/peek))))
(is (same-song? (nth queue playing-idx)
(-> (playlist/next-song playlist)
(playlist/next-song)
(playlist/peek))))
(is (same-song? (nth queue playing-idx)
(-> (playlist/next-song playlist)
(playlist/next-song)
(playlist/next-song)
(playlist/peek)))
"wrapping around")))
(testing "Should stop playing at the end of the queue when repeat-mode is none"
(is (nil? (-> (playing-queue 1)
(playlist/->playlist 0 :playback-mode/linear :repeat-mode/none)
(playlist/next-song)
(playlist/peek))))))
(deftest shuffled-next-song #_(deftest shuffled-next-song
(testing "Should play every track once when called for the entire queue") (testing "Should play every track once when called for the entire queue")
(testing "Should re-shuffle the playlist when wrapping around and repeat-mode is all") (testing "Should re-shuffle the playlist when wrapping around and repeat-mode is all")
(testing "Should always give the same track when repeat-mode is single")) (testing "Should always give the same track when repeat-mode is single")
(testing "Should stop playing at the end of the queue when repeat-mode is none"))
#_(deftest linear-previous-song) #_(deftest linear-previous-song)
#_(deftest shuffled-previous-song) #_(deftest shuffled-previous-song)