« get me outta code hell

Make pickers slightly more self-contained; add new pickers and change old ones, which now support just about any spelling variant - http-music - Command-line music player + utils (not a server!)
about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorrie <towerofnix@gmail.com>2017-08-10 23:15:00 -0300
committerFlorrie <towerofnix@gmail.com>2017-08-10 23:15:00 -0300
commit9fa3021cd8424f2e82a6b48aaf85db6fd5d27659 (patch)
treea8edebb0973d02e056ed5112768082a65095e2a5
parent4f1e01fd16fdb229bd109fbe2259bbe59826abef (diff)
Make pickers slightly more self-contained; add new pickers and change old ones, which now support just about any spelling variant
-rw-r--r--src/pickers.js85
-rwxr-xr-xsrc/play.js15
-rw-r--r--todo.txt4
3 files changed, 89 insertions, 15 deletions
diff --git a/src/pickers.js b/src/pickers.js
index 014eee8..ec4d629 100644
--- a/src/pickers.js
+++ b/src/pickers.js
@@ -2,7 +2,25 @@
 
 const { flattenGrouplike } = require('./playlist-utils')
 
-function makeOrderedPlaylistPicker(grouplike) {
+function makeLoopingOrderedPlaylistPicker(grouplike) {
+  // Looping ordered playlist picker - this plays all the tracks in a group
+  // in order, while looping the same order forever.
+
+  const flatGroup = flattenGrouplike(grouplike)
+  let index = 0
+
+  return function() {
+    if (index >= flatGroup.items.length) {
+      index = 0
+    }
+
+    const picked = flatGroup.items[index]
+    index++
+    return picked
+  }
+}
+
+function makeNonLoopingOrderedPlaylistPicker(grouplike) {
   // Ordered playlist picker - this plays all the tracks in a group in
   // order, after flattening it.
 
@@ -20,7 +38,7 @@ function makeOrderedPlaylistPicker(grouplike) {
   }
 }
 
-function makeShufflePlaylistPicker(grouplike) {
+function makeLoopingShufflePlaylistPicker(grouplike) {
   // Shuffle playlist picker - this selects a random track at any index in
   // the playlist, after flattening it.
 
@@ -29,15 +47,70 @@ function makeShufflePlaylistPicker(grouplike) {
   return function() {
     if (flatGroup.items.length) {
       const index = Math.floor(Math.random() * flatGroup.items.length)
-      const picked = flatGroup.items[index]
-      return picked
+      return flatGroup.items[index]
+    } else {
+      return null
+    }
+  }
+}
+
+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
     }
   }
 }
 
+function shuffleArray(array) {
+  // Shuffles the items in an array. Super-interesting post on how it works:
+  // https://bost.ocks.org/mike/shuffle/
+
+  const workingArray = array.slice(0)
+
+  let m = array.length
+
+  while (m) {
+    let i = Math.floor(Math.random() * m)
+    m--
+
+    // Stupid lol; avoids the need of a temporary variable!
+    Object.assign(workingArray, {
+      [m]: workingArray[i],
+      [i]: workingArray[m]
+    })
+  }
+
+  return workingArray
+}
+
 module.exports = {
-  makeOrderedPlaylistPicker,
-  makeShufflePlaylistPicker
+  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,
+  }
 }
diff --git a/src/play.js b/src/play.js
index 1416420..50be20e 100755
--- a/src/play.js
+++ b/src/play.js
@@ -7,7 +7,7 @@ const clone = require('clone')
 const fs = require('fs')
 const fetch = require('node-fetch')
 const commandExists = require('./command-exists')
-const pickers = require('./pickers')
+const { byName: pickersByName } = require('./pickers')
 const startLoopPlay = require('./loop-play')
 const processArgv = require('./process-argv')
 const processSmartPlaylist = require('./smart-playlist')
@@ -307,18 +307,15 @@ async function main(args) {
   }
 
   if (willPlay || (willPlay === null && shouldPlay)) {
-    let picker
-    if (pickerType === 'shuffle') {
-      console.log("Using shuffle picker.")
-      picker = pickers.makeShufflePlaylistPicker(activePlaylist)
-    } else if (pickerType === 'ordered') {
-      console.log("Using ordered picker.")
-      picker = pickers.makeOrderedPlaylistPicker(activePlaylist)
-    } else {
+    if (!Object.keys(pickersByName).includes(pickerType)) {
       console.error("Invalid picker type: " + pickerType)
       return
     }
 
+    console.log(`Using ${pickerType} picker.`)
+
+    const picker = pickersByName[pickerType](activePlaylist)
+
     console.log(`Using ${playerCommand} player.`)
 
     const {
diff --git a/todo.txt b/todo.txt
index 534d1ee..5501926 100644
--- a/todo.txt
+++ b/todo.txt
@@ -300,3 +300,7 @@ TODO: safeUnlink probably shouldn't throw/reject if it fails to delete its
       given file (e.g. if a temporary file was automatically purged by the
       system before safeUnlink). Having a warning might be better? (Since
       *most* of the time it's probably a bug.)
+
+TODO: A shuffle-groups picker would be fun! (That is, it would take a
+      grouplike, then shuffle all the items on the TOP level; so it would
+      play random (top-level) groups at a time.)