mirror of
https://github.com/heyarne/airsonic-ui.git
synced 2026-05-07 02:33:39 +02:00
Remove current song
This commit is contained in:
parent
0eec1df70f
commit
065b3a6647
7 changed files with 72 additions and 7 deletions
|
|
@ -1,7 +1,12 @@
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
const configuration = {
|
const configuration = {
|
||||||
browsers: ['ChromeHeadless'],
|
browsers: ['ChromeHeadless'],
|
||||||
autoWatchBatchDelay: 1000,
|
// The tests are sometimes run before the tests were completely written
|
||||||
|
// to disc; this is a known problem unfortunately. This is a hack to at
|
||||||
|
// least keep the browsers connected so the tests are compiled and run
|
||||||
|
// again even if a developer isn't aware of this
|
||||||
|
autoWatchBatchDelay: 100,
|
||||||
|
browserNoActivityTimeout: 60 * 1000 * 10,
|
||||||
// The directory where the output file lives
|
// The directory where the output file lives
|
||||||
basePath: 'public/test',
|
basePath: 'public/test',
|
||||||
// The file itself
|
// The file itself
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,8 @@
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(when-let [audio @audio]
|
(when-let [audio @audio]
|
||||||
(.pause audio)
|
(.pause audio)
|
||||||
(set! (.-currentTime audio) 0))))
|
(set! (.-currentTime audio) 0)
|
||||||
|
(set! (.-src audio) ""))))
|
||||||
|
|
||||||
(rf/reg-fx
|
(rf/reg-fx
|
||||||
:audio/toggle-play-pause
|
:audio/toggle-play-pause
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,9 @@
|
||||||
(enqueue-next [this song])
|
(enqueue-next [this song])
|
||||||
|
|
||||||
(move-song [this from-idx to-idx]
|
(move-song [this from-idx to-idx]
|
||||||
"Allows you to move a song in a playlist"))
|
"Allows you to move a song in a playlist")
|
||||||
|
(remove-song [this song-idx]
|
||||||
|
"Removes a song from the playlist"))
|
||||||
|
|
||||||
;; helpers to manage creating playlists
|
;; helpers to manage creating playlists
|
||||||
|
|
||||||
|
|
@ -142,7 +144,15 @@
|
||||||
(= from-idx current-idx) (assoc result :current-idx to-idx)
|
(= from-idx current-idx) (assoc result :current-idx to-idx)
|
||||||
(<= to-idx current-idx from-idx) (update result :current-idx inc)
|
(<= to-idx current-idx from-idx) (update result :current-idx inc)
|
||||||
(>= to-idx current-idx from-idx) (update result :current-idx dec)
|
(>= to-idx current-idx from-idx) (update result :current-idx dec)
|
||||||
:else result))))
|
:else result)))
|
||||||
|
|
||||||
|
(remove-song [this song-idx]
|
||||||
|
(cond-> (update this :items #(let [n-items (count %)]
|
||||||
|
(-> (reduce (fn [items idx]
|
||||||
|
(assoc items idx (get items (inc idx))))
|
||||||
|
% (range song-idx n-items))
|
||||||
|
(dissoc (dec n-items)))))
|
||||||
|
(= song-idx current-idx) (assoc :current-idx -1))))
|
||||||
|
|
||||||
;; constructor wrapper
|
;; constructor wrapper
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,14 @@
|
||||||
(fn [_ _]
|
(fn [_ _]
|
||||||
{:audio/toggle-play-pause nil}))
|
{:audio/toggle-play-pause nil}))
|
||||||
|
|
||||||
|
(defn remove-song [{:keys [db]} [_ song-idx]]
|
||||||
|
(let [song-removed (update-in db [:audio :current-playlist] #(playlist/remove-song % song-idx))]
|
||||||
|
(cond-> {:db song-removed}
|
||||||
|
(nil? (playlist/current-song (get-in song-removed [:audio :current-playlist])))
|
||||||
|
(assoc :audio/stop nil))))
|
||||||
|
|
||||||
|
(rf/reg-event-fx :audio-player/remove-song remove-song)
|
||||||
|
|
||||||
(defn audio-update
|
(defn audio-update
|
||||||
"Reacts to audio events fired by the HTML5 audio player and plays the next
|
"Reacts to audio events fired by the HTML5 audio player and plays the next
|
||||||
track if necessary."
|
track if necessary."
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@
|
||||||
(r/as-element [:span.is-size-7.has-text-grey-lighter
|
(r/as-element [:span.is-size-7.has-text-grey-lighter
|
||||||
[icon :elevator]]))))
|
[icon :elevator]]))))
|
||||||
|
|
||||||
(defn song-actions []
|
(defn song-actions [{:keys [song idx]}]
|
||||||
;; TODO: Implement both of these
|
;; TODO: Implement both of these
|
||||||
[dropdown {:items [{:label "Remove from queue"
|
[dropdown {:items [{:label "Remove from queue"
|
||||||
:event []}
|
:event [:audio-player/remove-song idx]}
|
||||||
{:label "Go to source"
|
{:label "Go to source"
|
||||||
:event []}]}])
|
:event []}]}])
|
||||||
|
|
||||||
|
|
@ -62,7 +62,8 @@
|
||||||
[:td.song-artist [artist-link song]]
|
[:td.song-artist [artist-link song]]
|
||||||
[:td.song-title [song-link song idx]]
|
[:td.song-title [song-link song idx]]
|
||||||
[:td.song-duration (helpers/format-duration (:duration song) :brief? true)]
|
[:td.song-duration (helpers/format-duration (:duration song) :brief? true)]
|
||||||
[:td.song-actions.is-narrow [song-actions]]])
|
[:td.song-actions.is-narrow [song-actions {:song song
|
||||||
|
:idx idx}]]])
|
||||||
|
|
||||||
:on-sort-end
|
:on-sort-end
|
||||||
(fn [{:keys [old-idx new-idx]}]
|
(fn [{:keys [old-idx new-idx]}]
|
||||||
|
|
|
||||||
|
|
@ -309,3 +309,33 @@
|
||||||
(is (= 3 (-> (playlist/set-current-song playlist 3)
|
(is (= 3 (-> (playlist/set-current-song playlist 3)
|
||||||
(playlist/move-song 4 7)
|
(playlist/move-song 4 7)
|
||||||
:current-idx))))))))
|
:current-idx))))))))
|
||||||
|
|
||||||
|
(deftest remove-song
|
||||||
|
(with-redefs [shuffle identity]
|
||||||
|
(testing "Should remove a single song from the playlist"
|
||||||
|
(doseq [playback-mode [:linear :shuffled]
|
||||||
|
repeat-mode [:repeat-none :repeat-all :repeat-single]]
|
||||||
|
(let [n-songs 10
|
||||||
|
queue (song-queue n-songs)
|
||||||
|
playlist (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode)
|
||||||
|
first-removed (playlist/remove-song playlist 0)
|
||||||
|
middle-removed (playlist/remove-song playlist 5)
|
||||||
|
last-removed (playlist/remove-song playlist 9)
|
||||||
|
song-not-in-list? (fn [song playlist]
|
||||||
|
(every? #(not (same-song? % song))
|
||||||
|
(vals (:items playlist))))]
|
||||||
|
(is (= 9 (count first-removed) (count middle-removed) (count last-removed)))
|
||||||
|
(is (song-not-in-list? (first queue) first-removed))
|
||||||
|
(is (same-song? (second queue) (get (:items first-removed) 0)))
|
||||||
|
(is (song-not-in-list? (nth queue 5) middle-removed))
|
||||||
|
(is (same-song? (nth queue 6) (get (:items middle-removed) 5)))
|
||||||
|
(is (song-not-in-list? (last queue) last-removed)))))
|
||||||
|
(testing "Should pause if the currently playing song is removed"
|
||||||
|
(doseq [playback-mode [:linear :shuffled]
|
||||||
|
repeat-mode [:repeat-none :repeat-all :repeat-single]]
|
||||||
|
(let [n-songs 10
|
||||||
|
queue (song-queue n-songs)]
|
||||||
|
(is (nil? (-> (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode)
|
||||||
|
(playlist/set-current-song 5)
|
||||||
|
(playlist/remove-song 5)
|
||||||
|
(playlist/current-song)))))))))
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,13 @@
|
||||||
(:current-idx)))
|
(:current-idx)))
|
||||||
(str "for playback-mode " playback-mode " and repeat-mode " repeat-mode))
|
(str "for playback-mode " playback-mode " and repeat-mode " repeat-mode))
|
||||||
(is (contains? effects :audio/play))))))
|
(is (contains? effects :audio/play))))))
|
||||||
|
|
||||||
|
(deftest removing-currently-playing-song
|
||||||
|
(testing "Should stop all audio when removing the currently playing song"
|
||||||
|
(doseq [playback-mode [:linear :shuffled]
|
||||||
|
repeat-mode [:repeat-none :repeat-single :repeat-all]]
|
||||||
|
(let [n-songs 100
|
||||||
|
fixture {:db {:credentials fixtures/credentials
|
||||||
|
:audio {:current-playlist (playlist/->playlist (song-queue n-songs) :playback-mode playback-mode :repeat-mode repeat-mode)}}}]
|
||||||
|
(is (contains? (events/remove-song fixture [:audio/remove-song 0]) :audio/stop))
|
||||||
|
(is (not (contains? (events/remove-song fixture [:audio/remove-song 99]) :audio/stop)))))))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue