« get me outta code hell

mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--backend.js41
-rw-r--r--todo.txt5
-rw-r--r--ui.js2
3 files changed, 30 insertions, 18 deletions
diff --git a/backend.js b/backend.js
index 41107d7..36344be 100644
--- a/backend.js
+++ b/backend.js
@@ -434,27 +434,19 @@ class QueuePlayer extends EventEmitter {
 
     if (playingThisTrack) {
       this.playedTrackToEnd = true
-      if (!this.playNext(item)) {
-        switch (this.queueEndMode) {
-          case 'loop':
-            this.playFirst()
-            break
-          case 'shuffle':
-            this.clearPlayingTrack()
-            this.shuffleQueue()
-            this.playFirst()
-            break
-          case 'end':
-          default:
-            this.clearPlayingTrack()
-        }
-      }
+      this.playNext(item)
     }
   }
 
   playNext(track, automaticallyQueueNextTrack = false) {
     if (!track) return false
 
+    // Auto-queue is nice but it should only happen when the queue hasn't been
+    // explicitly set to loop.
+    automaticallyQueueNextTrack = (
+      automaticallyQueueNextTrack &&
+      this.queueEndMode === 'end')
+
     const queue = this.queueGrouplike
     let queueIndex = queue.items.indexOf(track)
     if (queueIndex === -1) return false
@@ -473,7 +465,7 @@ class QueuePlayer extends EventEmitter {
         this.queue(nextItem)
         queueIndex = queue.items.length - 1
       } else {
-        return false
+        return this.playNextAtQueueEnd()
       }
     }
 
@@ -519,6 +511,23 @@ class QueuePlayer extends EventEmitter {
     return false
   }
 
+  playNextAtQueueEnd() {
+    switch (this.queueEndMode) {
+      case 'loop':
+        this.playFirst()
+        return true
+      case 'shuffle':
+        this.clearPlayingTrack()
+        this.shuffleQueue()
+        this.playFirst()
+        return true
+      case 'end':
+      default:
+        this.clearPlayingTrack()
+        return false
+    }
+  }
+
   async playOrSeek(item, time) {
     if (!isTrack(item)) {
       // This only makes sense to call with individual tracks!
diff --git a/todo.txt b/todo.txt
index 90ed41b..a6ce5ef 100644
--- a/todo.txt
+++ b/todo.txt
@@ -577,8 +577,9 @@ TODO: "BAM #45.3 - no" displays as "BAM #45.no" in the queue? Seems wrong!
 TODO: "Challenge 1 (Tricks)" etc in FP World 3 are "Challenge (Tricks)"! Bad.
       (Done!)
 
-TODO: Pressing next track (shift+N) on the last track should start the first
-      track, if the queue is being looped.
+TODO: Pressing next track (N) on the last track should start the first track,
+      if the queue is being looped.
+      (Done!)
 
 TODO: Timestamp files. Oh heck yes.
       (Done!)
diff --git a/ui.js b/ui.js
index bf67b8e..b8dd63c 100644
--- a/ui.js
+++ b/ui.js
@@ -361,6 +361,8 @@ class AppElement extends FocusElement {
           {divider: true},
           previous && {label: `Previous (${previous.name})`, action: () => this.SQP.playPrevious(playingTrack)},
           next && {label: `Next (${next.name})`, action: () => this.SQP.playNext(playingTrack)},
+          !next && this.SQP.queueEndMode === 'loop' &&
+          {label: `Next (loop queue)`, action: () => this.SQP.playNext(playingTrack)},
           next && {label: '- Play later', action: () => this.playLater(next)}
         ]
       }},