diff options
Diffstat (limited to 'backend.js')
-rw-r--r-- | backend.js | 193 |
1 files changed, 157 insertions, 36 deletions
diff --git a/backend.js b/backend.js index 4142026..6576868 100644 --- a/backend.js +++ b/backend.js @@ -7,6 +7,8 @@ import {readFile, writeFile} from 'node:fs/promises' import EventEmitter from 'node:events' import os from 'node:os' +import shortid from 'shortid' + import {getDownloaderFor} from './downloaders.js' import {getMetadataReaderFor} from './metadata-readers.js' import {getPlayer} from './players.js' @@ -58,6 +60,8 @@ class QueuePlayer extends EventEmitter { }) { super() + this.id = shortid.generate() + this.player = null this.playingTrack = null this.queueGrouplike = {name: 'Queue', isTheQueue: true, items: []} @@ -65,6 +69,10 @@ class QueuePlayer extends EventEmitter { this.queueEndMode = 'end' // end, loop, shuffle this.playedTrackToEnd = false this.timeData = null + this.time = null + + this.alwaysStartPaused = false + this.waitWhenDonePlaying = false this.getPlayer = getPlayer this.getRecordFor = getRecordFor @@ -83,7 +91,8 @@ class QueuePlayer extends EventEmitter { if (this.playingTrack) { const oldTimeData = this.timeData this.timeData = data - this.emit('received time data', data, oldTimeData, this) + this.time = data.curSecTotal + this.emit('received time data', data, oldTimeData) } }) @@ -158,6 +167,7 @@ class QueuePlayer extends EventEmitter { } recursivelyAddTracks(topItem) + this.emit('queue', topItem, afterItem, {movePlayingTrack}) this.emitQueueUpdated() // This is the first new track, if a group was queued. @@ -166,9 +176,12 @@ class QueuePlayer extends EventEmitter { return newTrack } - distributeQueue(grouplike, {how = 'evenly', rangeEnd = 'end-of-queue'}) { - if (isTrack(grouplike)) { - grouplike = {items: [grouplike]} + distributeQueue(topItem, {how = 'evenly', rangeEnd = 'end-of-queue'} = {}) { + let grouplike + if (isTrack(topItem)) { + grouplike = {items: [topItem]} + } else { + grouplike = topItem } const { items } = this.queueGrouplike @@ -220,6 +233,7 @@ class QueuePlayer extends EventEmitter { } } + this.emit('distribute queue', topItem, {how, rangeEnd}) this.emitQueueUpdated() } @@ -264,11 +278,17 @@ class QueuePlayer extends EventEmitter { } recursivelyUnqueueTracks(topItem) + this.emit('unqueue', topItem) this.emitQueueUpdated() return focusItem } + replaceAllItems(newItems) { + this.queueGrouplike.items = newItems + this.emitQueueUpdated() + } + clearQueuePast(track) { const { items } = this.queueGrouplike const index = items.indexOf(track) + 1 @@ -281,6 +301,7 @@ class QueuePlayer extends EventEmitter { items.splice(index) } + this.emit('clear queue past', track) this.emitQueueUpdated() } @@ -297,6 +318,7 @@ class QueuePlayer extends EventEmitter { items.splice(startIndex, endIndex - startIndex) } + this.emit('clear queue up to', track) this.emitQueueUpdated() } @@ -329,6 +351,7 @@ class QueuePlayer extends EventEmitter { const remainingItems = queue.items.slice(index) const newItems = initialItems.concat(shuffleArray(remainingItems)) queue.items = newItems + this.emit('shuffle queue') this.emitQueueUpdated() } @@ -337,6 +360,7 @@ class QueuePlayer extends EventEmitter { // the track that's currently playing). this.queueGrouplike.items = this.queueGrouplike.items .filter(item => item === this.playingTrack) + this.emit('clear queue') this.emitQueueUpdated() } @@ -352,8 +376,7 @@ class QueuePlayer extends EventEmitter { this.clearPlayingTrack() } - - async play(item, startTime = 0) { + async play(item, startTime = 0, forceStartPaused = false) { if (this.player === null) { throw new Error('Attempted to play before a player was loaded') } @@ -399,11 +422,15 @@ class QueuePlayer extends EventEmitter { } this.timeData = null + this.time = null this.playingTrack = item - this.emit('playing', this.playingTrack, oldTrack, startTime, this) + this.emit('playing details', this.playingTrack, oldTrack, startTime) + this.emit('playing', this.playingTrack) await this.player.kill() - if (this.playedTrackToEnd) { + if (this.alwaysStartPaused || forceStartPaused) { + this.player.setPause(true) + } else if (this.playedTrackToEnd) { this.player.setPause(this.pauseNextTrack) this.pauseNextTrack = false this.playedTrackToEnd = false @@ -418,7 +445,10 @@ class QueuePlayer extends EventEmitter { if (playingThisTrack) { this.playedTrackToEnd = true - this.playNext(item) + this.emit('done playing', this.playingTrack) + if (!this.waitWhenDonePlaying) { + this.playNext(item) + } } } @@ -537,7 +567,9 @@ class QueuePlayer extends EventEmitter { const oldTrack = this.playingTrack this.playingTrack = null this.timeData = null - this.emit('playing', null, oldTrack, 0, this) + this.time = null + this.emit('playing details', null, oldTrack, 0) + this.emit('playing', null) } } @@ -546,11 +578,25 @@ class QueuePlayer extends EventEmitter { } seekAhead(seconds) { + this.time += seconds this.player.seekAhead(seconds) + this.emit('seek ahead', +seconds) } seekBack(seconds) { + if (this.time < seconds) { + this.time = 0 + } else { + this.time -= seconds + } this.player.seekBack(seconds) + this.emit('seek back', +seconds) + } + + seekTo(timeInSecs) { + this.time = timeInSecs + this.player.seekTo(timeInSecs) + this.emit('seek to', +timeInSecs) } seekTo(seconds) { @@ -563,47 +609,55 @@ class QueuePlayer extends EventEmitter { togglePause() { this.player.togglePause() + this.emit('toggle pause') } setPause(value) { this.player.setPause(value) + this.emit('set pause', !!value) } toggleLoop() { this.player.toggleLoop() + this.emit('toggle loop') } setLoop(value) { this.player.setLoop(value) + this.emit('set loop', !!value) } - volUp(amount = 10) { + volumeUp(amount = 10) { this.player.volUp(amount) + this.emit('volume up', +amount) } - volDown(amount = 10) { + volumeDown(amount = 10) { this.player.volDown(amount) + this.emit('volume down', +amount) } setVolume(value) { this.player.setVolume(value) + this.emit('set volume', +value) } setVolumeMultiplier(value) { - this.player.setVolumeMultiplier(value); + this.player.setVolumeMultiplier(value) } fadeIn() { - return this.player.fadeIn(); + return this.player.fadeIn() } setPauseNextTrack(value) { this.pauseNextTrack = !!value + this.emit('set pause next track', !!value) } setLoopQueueAtEnd(value) { this.loopQueueAtEnd = !!value - this.emit('set-loop-queue-at-end', !!value) + this.emit('set loop queue at end', !!value) } get remainingTracks() { @@ -636,14 +690,24 @@ export default class Backend extends EventEmitter { } = {}) { super() - this.playerName = playerName; - this.playerOptions = playerOptions; + this.playerName = playerName + this.playerOptions = playerOptions if (playerOptions.length && !playerName) { throw new Error(`Must specify playerName to specify playerOptions`); } this.queuePlayers = [] + this.alwaysStartPaused = false + this.waitWhenDonePlaying = false + + this.hasAnnouncedJoin = false + this.sharedSourcesMap = Object.create(null) + this.sharedSourcesGrouplike = { + name: 'Shared Sources', + isPartySources: true, + items: [] + } this.recordStore = new RecordStore() this.throttleMetadata = throttlePromise(10) @@ -675,34 +739,40 @@ export default class Backend extends EventEmitter { return error } + queuePlayer.alwaysStartPaused = this.alwaysStartPaused + queuePlayer.waitWhenDonePlaying = this.waitWhenDonePlaying + this.queuePlayers.push(queuePlayer) this.emit('added queue player', queuePlayer) for (const event of [ - 'playing', + 'clear queue', + 'clear queue past', + 'clear queue up to', + 'distribute queue', 'done playing', + 'playing', + 'playing details', 'queue', - 'distribute-queue', - 'unqueue', - 'clear-queue-past', - 'clear-queue-up-to', - 'shuffle-queue', - 'clear-queue', 'queue updated', - 'seek-ahead', - 'seek-back', - 'toggle-pause', - 'set-pause', - 'toggle-loop', - 'set-loop', - 'vol-up', - 'vol-down', - 'set-volume', - 'set-pause-next-track', - 'set-loop-queue-at-end' + 'received time data', + 'seek ahead', + 'seek back', + 'seek to', + 'set loop', + 'set loop queue at end', + 'set pause', + 'set pause next track', + 'set volume', + 'shuffle queue', + 'toggle loop', + 'toggle pause', + 'unqueue', + 'volume down', + 'volume up', ]) { queuePlayer.on(event, (...data) => { - this.emit(event, queuePlayer, ...data) + this.emit('QP: ' + event, queuePlayer, ...data) }) } @@ -802,6 +872,20 @@ export default class Backend extends EventEmitter { return {seconds, string, noticedMissingMetadata, approxSymbol} } + setAlwaysStartPaused(value) { + this.alwaysStartPaused = !!value + for (const queuePlayer of this.queuePlayers) { + queuePlayer.alwaysStartPaused = !!value + } + } + + setWaitWhenDonePlaying(value) { + this.waitWhenDonePlaying = !!value + for (const queuePlayer of this.queuePlayers) { + queuePlayer.waitWhenDonePlaying = !!value + } + } + async stopPlayingAll() { for (const queuePlayer of this.queuePlayers) { await queuePlayer.stopPlaying() @@ -811,4 +895,41 @@ export default class Backend extends EventEmitter { async download(item) { return download(item, this.getRecordFor(item)) } + + showLogMessage(messageInfo) { + this.emit('log message', messageInfo) + } + + setPartyNickname(nickname) { + this.emit('set party nickname', nickname) + } + + announceJoinParty() { + this.emit('announce join party') + } + + setHasAnnouncedJoin(hasAnnouncedJoin) { + this.hasAnnouncedJoin = hasAnnouncedJoin + } + + loadSharedSources(socketId, sharedSources) { + if (socketId in this.sharedSourcesMap) { + return + } + + this.sharedSourcesMap[socketId] = sharedSources + + sharedSources[parentSymbol] = this.sharedSourcesGrouplike + this.sharedSourcesGrouplike.items.push(sharedSources) + + this.emit('got shared sources', socketId, sharedSources) + } + + sharedSourcesUpdated(socketId, sharedSources) { + this.emit('shared sources updated', socketId, sharedSources) + } + + shareWithParty(item) { + this.emit('share with party', item) + } } |