« get me outta code hell

http-music - Command-line music player + utils (not a server!)
about summary refs log tree commit diff
path: root/src/pickers.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/pickers.js')
-rw-r--r--src/pickers.js154
1 files changed, 82 insertions, 72 deletions
diff --git a/src/pickers.js b/src/pickers.js
index ec4d629..6a30c37 100644
--- a/src/pickers.js
+++ b/src/pickers.js
@@ -2,71 +2,100 @@
 
 const { flattenGrouplike } = require('./playlist-utils')
 
-function makeLoopingOrderedPlaylistPicker(grouplike) {
-  // Looping ordered playlist picker - this plays all the tracks in a group
-  // in order, while looping the same order forever.
+function makePicker(grouplike, sort, loop) {
+  // Options to take into consideration:
+  // - How should the top-level be sorted?
+  //   (e.g. "order", "shuffle", "shuffle-groups")
+  // - How should looping be handled?
+  //   (e.g. "loop", "no-loop")
+  // - Also keep in mind aliases for all of the above.
+  //   (e.g. "ordered", "shuffled", "noloop")
+  //
+  // What about a shuffle-mode that should simply pick a random track every
+  // time?
+  //
+  // What about a shuffle-mode that re-shuffles the list every time a loop
+  // happens?
+  //
+  // Both of those options could probably be handled via the 'loop' option.
+
+  const topLevel = {items: []}
+
+  let generateTopLevel = () => {
+    if (sort === 'order') {
+      topLevel.items = flattenGrouplike(grouplike).items
+    }
 
-  const flatGroup = flattenGrouplike(grouplike)
-  let index = 0
+    if (sort === 'shuffle') {
+      topLevel.items = shuffleArray(flattenGrouplike(grouplike).items)
+    }
 
-  return function() {
-    if (index >= flatGroup.items.length) {
-      index = 0
+    if (sort === 'shuffle-top-level' || sort === 'shuffle-groups') {
+      topLevel.items = flattenGrouplike(shuffleArray(grouplike.items))
     }
 
-    const picked = flatGroup.items[index]
-    index++
-    return picked
+    console.log(topLevel.items.map(require('./playlist-utils').getItemPathString).join('\n'))
   }
-}
 
-function makeNonLoopingOrderedPlaylistPicker(grouplike) {
-  // Ordered playlist picker - this plays all the tracks in a group in
-  // order, after flattening it.
+  generateTopLevel()
 
-  const flatGroup = flattenGrouplike(grouplike)
   let index = 0
 
   return function() {
-    if (index < flatGroup.items.length) {
-      const picked = flatGroup.items[index]
-      index++
-      return picked
-    } else {
-      return null
+    if (index === topLevel.items.length) {
+      if (loop === 'loop-same-order' || loop === 'loop') {
+        index = 0
+      }
+
+      if (loop === 'loop-regenerate') {
+        generateTopLevel()
+        index = 0
+      }
+
+      if (loop === 'no-loop' || loop === 'no') {
+        // Returning null means the picker is done picking.
+        // (In theory, we could use an ES2015 generator intead, but this works
+        // well enough.)
+        return null
+      }
     }
-  }
-}
-
-function makeLoopingShufflePlaylistPicker(grouplike) {
-  // Shuffle playlist picker - this selects a random track at any index in
-  // the playlist, after flattening it.
-
-  const flatGroup = flattenGrouplike(grouplike)
 
-  return function() {
-    if (flatGroup.items.length) {
-      const index = Math.floor(Math.random() * flatGroup.items.length)
-      return flatGroup.items[index]
-    } else {
-      return null
+    if (index > topLevel.items.length) {
+      throw new Error(
+        "Picker index is greater than total item count?" +
+        `(${index} > ${topLevel.items.length}`
+      )
     }
-  }
-}
-
-function makeNonLoopingShufflePlaylistPicker(grouplike) {
-  // No-loop shuffle playlist picker - this takes a playlist and randomly
-  // shuffles the order of the items in it, then uses that as an "ordered"
-  // playlist (i.e. it plays all the items in it then stops).
-
-  const flatGroup = flattenGrouplike(grouplike)
-  const items = shuffleArray(flatGroup.items)
 
-  return function() {
-    if (items.length) {
-      return items.splice(0, 1)[0]
-    } else {
-      return null
+    if (index < topLevel.items.length) {
+      // Pick-random is a special exception - in this case we don't actually
+      // care about the value of the index variable; instead we just pick a
+      // random track from the generated top level.
+      //
+      // Loop=pick-random is different from sort=shuffle. Sort=shuffle always
+      // ensures the same song doesn't play twice in a single shuffle. It's
+      // like how when you shuffle a deck of cards, you'll still never pick
+      // the same card twice, until you go all the way through the deck and
+      // re-shuffle the deck!
+      //
+      // Loop=pick-random instead picks a random track every time the picker
+      // is called. It's more like you reshuffle the complete deck every time
+      // you pick something.
+      //
+      // Now, how should pick-random work when dealing with groups, such as
+      // when using sort=shuffle-groups? (If I can't find a solution, I'd say
+      // that's alright.)
+      if (loop === 'pick-random') {
+        const pickedIndex = Math.floor(Math.random() * topLevel.items.length)
+        return topLevel.items[pickedIndex]
+      }
+
+      // If we're using any other mode, we just want to get the current item
+      // in the playlist, and increment the index variable by one (note i++
+      // and not ++i; i++ increments AFTER getting i so it gets us the range
+      // 0..length-1, whereas ++i increments BEFORE, which gets us the range
+      // 1..length.
+      return topLevel.items[index++]
     }
   }
 }
@@ -93,24 +122,5 @@ function shuffleArray(array) {
   return workingArray
 }
 
-module.exports = {
-  makeLoopingOrderedPlaylistPicker,
-  makeNonLoopingOrderedPlaylistPicker,
-  makeLoopingShufflePlaylistPicker,
-  makeNonLoopingShufflePlaylistPicker,
-
-  byName: {
-    'order':           makeNonLoopingOrderedPlaylistPicker,
-    'ordered':         makeNonLoopingOrderedPlaylistPicker,
-    'order-loop':      makeLoopingOrderedPlaylistPicker,
-    'ordered-loop':    makeLoopingOrderedPlaylistPicker,
-    'order-noloop':    makeNonLoopingOrderedPlaylistPicker,
-    'ordered-noloop':  makeNonLoopingOrderedPlaylistPicker,
-    'order-no-loop':   makeNonLoopingOrderedPlaylistPicker,
-    'ordered-no-loop': makeNonLoopingOrderedPlaylistPicker,
-    'shuffle':         makeLoopingShufflePlaylistPicker,
-    'shuffle-loop':    makeLoopingShufflePlaylistPicker,
-    'shuffle-noloop':  makeNonLoopingShufflePlaylistPicker,
-    'shuffle-no-loop': makeNonLoopingShufflePlaylistPicker,
-  }
-}
+
+module.exports = makePicker