From 9fa3021cd8424f2e82a6b48aaf85db6fd5d27659 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 10 Aug 2017 23:15:00 -0300 Subject: Make pickers slightly more self-contained; add new pickers and change old ones, which now support just about any spelling variant --- src/pickers.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/play.js | 15 +++++------ todo.txt | 4 +++ 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.) -- cgit 1.3.0-6-gf8a5