import { head, last, each, includes, union, difference, map, shuffle as _shuffle, first } from 'lodash'; export const queueStore = { state: { songs: [], current: null, }, init() { // We don't have anything to do here yet. // How about another song then? // // LITTLE WING // -- by Jimi Fucking Hendrix // // Well she's walking // Through the clouds // With a circus mind // That's running wild // Butterflies and zebras and moonbeams and fairytales // That's all she ever thinks about // Riding with the wind // // When I'm sad // She comes to me // With a thousand smiles // She gives to me free // It's alright she said // It's alright // Take anything you want from me // Anything... }, /** * Get all queued songs. * * @return {Array.} */ get all() { return this.state.songs; }, /** * Set all queued songs. * * @param {Array.} */ set all(songs) { this.state.songs = songs; }, /** * The first song in the queue. * * @return {?Object} */ get first() { return head(this.all); }, /** * The last song in the queue. * * @return {?Object} */ get last() { return last(this.all); }, /** * Determine if the queue contains a song. * * @param {Object} song * * @return {Boolean} */ contains(song) { return includes(this.all, song); }, /** * Add a list of songs to the end of the current queue, * or replace the current queue as a whole if `replace` is true. * * @param {Object|Array.} songs The song, or an array of songs * @param {Boolean} replace Whether to replace the current queue * @param {Boolean} toTop Whether to prepend or append to the queue */ queue(songs, replace = false, toTop = false) { songs = [].concat(songs); if (replace) { this.all = songs; } else { this.all = toTop ? union(songs, this.all) : union(this.all, songs); } }, /** * Queue song(s) to after the current song. * * @param {Array.|Object} songs */ queueAfterCurrent(songs) { songs = [].concat(songs); if (!this.current || !this.all.length) { return this.queue(songs); } // First we unqueue the songs to make sure there are no duplicates. this.unqueue(songs); const head = this.all.splice(0, this.indexOf(this.current) + 1); this.all = head.concat(songs, this.all); }, /** * Unqueue a song, or several songs at once. * * @param {Object|String|Array.} songs The song(s) to unqueue */ unqueue(songs) { this.all = difference(this.all, [].concat(songs)); }, /** * Move some songs to after a target. * * @param {Array.} songs Songs to move * @param {Object} target The target song object */ move(songs, target) { const $targetIndex = this.indexOf(target); each(songs, song => { this.all.splice(this.indexOf(song), 1); this.all.splice($targetIndex, 0, song); }); }, /** * Clear the current queue. */ clear() { this.all = []; this.current = null; }, /** * Get index of a song in the queue. * * @param {Object} song * * @return {?Integer} */ indexOf(song) { return this.all.indexOf(song); }, /** * The next song in queue. * * @return {?Object} */ get next() { if (!this.current) { return first(this.all); } const idx = map(this.all, 'id').indexOf(this.current.id) + 1; return idx >= this.all.length ? null : this.all[idx]; }, /** * The previous song in queue. * * @return {?Object} */ get previous() { if (!this.current) { return last(this.all); } const idx = map(this.all, 'id').indexOf(this.current.id) - 1; return idx < 0 ? null : this.all[idx]; }, /** * The current song. * * @return {Object} */ get current() { return this.state.current; }, /** * Set a song as the current queued song. * * @param {Object} song * * @return {Object} The queued song. */ set current(song) { return this.state.current = song; }, /** * Shuffle the queue. * * @return {Array.} The shuffled array of song objects */ shuffle() { return this.all = _shuffle(this.all); }, };