diff --git a/client/components/app/MediaPlayerContainer.vue b/client/components/app/MediaPlayerContainer.vue index cbc76803..61508d7e 100644 --- a/client/components/app/MediaPlayerContainer.vue +++ b/client/components/app/MediaPlayerContainer.vue @@ -43,12 +43,14 @@ :sleep-timer-remaining="sleepTimerRemaining" :sleep-timer-type="sleepTimerType" :is-podcast="isPodcast" + :hasNextItemInQueue="hasNextItemInQueue" @playPause="playPause" @jumpForward="jumpForward" @jumpBackward="jumpBackward" @setVolume="setVolume" @setPlaybackRate="setPlaybackRate" @seek="seek" + @nextItemInQueue="playNextItemInQueue" @close="closePlayer" @showBookmarks="showBookmarks" @showSleepTimer="showSleepTimerModal = true" @@ -60,7 +62,7 @@ - + @@ -176,6 +178,16 @@ export default { if (!this.isMusic) return null return this.mediaMetadata.artists.join(', ') }, + hasNextItemInQueue() { + return this.currentPlayerQueueIndex < this.playerQueueItems.length - 1 + }, + currentPlayerQueueIndex() { + if (!this.libraryItemId) return -1 + return this.playerQueueItems.findIndex((i) => { + if (this.streamEpisode?.id) return i.episodeId === this.streamEpisode.id + return i.libraryItemId === this.libraryItemId + }) + }, playerQueueItems() { return this.$store.state.playerQueueItems || [] } @@ -460,6 +472,30 @@ export default { this.playerHandler.switchPlayer() } }, + playNextItemInQueue() { + if (this.hasNextItemInQueue) { + this.playQueueItem({ index: this.currentPlayerQueueIndex + 1 }) + } + }, + /** + * @param {{ index: number }} payload + */ + playQueueItem(payload) { + if (payload?.index === undefined) { + console.error('playQueueItem: No index provided') + return + } + if (!this.playerQueueItems[payload.index]) { + console.error('playQueueItem: No item found at index', payload.index) + return + } + const item = this.playerQueueItems[payload.index] + this.playLibraryItem({ + libraryItemId: item.libraryItemId, + episodeId: item.episodeId || null, + queueItems: this.playerQueueItems + }) + }, async playLibraryItem(payload) { const libraryItemId = payload.libraryItemId const episodeId = payload.episodeId || null @@ -512,6 +548,7 @@ export default { this.$eventBus.$on('cast-session-active', this.castSessionActive) this.$eventBus.$on('playback-seek', this.seek) this.$eventBus.$on('playback-time-update', this.playbackTimeUpdate) + this.$eventBus.$on('play-queue-item', this.playQueueItem) this.$eventBus.$on('play-item', this.playLibraryItem) this.$eventBus.$on('pause-item', this.pauseItem) }, @@ -519,6 +556,7 @@ export default { this.$eventBus.$off('cast-session-active', this.castSessionActive) this.$eventBus.$off('playback-seek', this.seek) this.$eventBus.$off('playback-time-update', this.playbackTimeUpdate) + this.$eventBus.$off('play-queue-item', this.playQueueItem) this.$eventBus.$off('play-item', this.playLibraryItem) this.$eventBus.$off('pause-item', this.pauseItem) } diff --git a/client/components/modals/player/QueueItemsModal.vue b/client/components/modals/player/QueueItemsModal.vue index d7893abd..1dad61d5 100644 --- a/client/components/modals/player/QueueItemsModal.vue +++ b/client/components/modals/player/QueueItemsModal.vue @@ -13,7 +13,7 @@
- + @@ -22,8 +22,7 @@ \ No newline at end of file + diff --git a/client/components/player/PlayerPlaybackControls.vue b/client/components/player/PlayerPlaybackControls.vue index 1a92480b..39ce4f3c 100644 --- a/client/components/player/PlayerPlaybackControls.vue +++ b/client/components/player/PlayerPlaybackControls.vue @@ -20,8 +20,8 @@ forward_media - - @@ -43,7 +43,8 @@ export default { seekLoading: Boolean, playbackRate: Number, paused: Boolean, - hasNextChapter: Boolean + hasNextChapter: Boolean, + hasNextItemInQueue: Boolean }, data() { return {} @@ -62,6 +63,13 @@ export default { }, jumpBackwardText() { return this.getJumpText('jumpBackwardAmount', this.$strings.ButtonJumpBackward) + }, + hasNextLabel() { + if (this.hasNextItemInQueue && !this.hasNextChapter) return this.$strings.ButtonNextItemInQueue + return this.$strings.ButtonNextChapter + }, + hasNext() { + return this.hasNextItemInQueue || this.hasNextChapter } }, methods: { @@ -71,9 +79,9 @@ export default { prevChapter() { this.$emit('prevChapter') }, - nextChapter() { - if (!this.hasNextChapter) return - this.$emit('nextChapter') + next() { + if (!this.hasNext) return + this.$emit('next') }, jumpBackward() { this.$emit('jumpBackward') diff --git a/client/components/player/PlayerUi.vue b/client/components/player/PlayerUi.vue index 68452061..2cfa54fe 100644 --- a/client/components/player/PlayerUi.vue +++ b/client/components/player/PlayerUi.vue @@ -43,7 +43,7 @@ - + @@ -82,7 +82,8 @@ export default { sleepTimerType: String, isPodcast: Boolean, hideBookmarks: Boolean, - hideSleepTimer: Boolean + hideSleepTimer: Boolean, + hasNextItemInQueue: Boolean }, data() { return { @@ -145,7 +146,7 @@ export default { return Math.round((100 * time) / duration) }, currentChapterName() { - return this.currentChapter ? this.currentChapter.title : '' + return this.currentChapter?.title || '' }, currentChapterDuration() { if (!this.currentChapter) return 0 @@ -278,10 +279,13 @@ export default { this.seek(this.currentChapter.start) } }, - nextChapter() { - if (!this.currentChapter || !this.hasNextChapter) return - var nextChapter = this.chapters[this.currentChapterIndex + 1] - this.seek(nextChapter.start) + goToNext() { + if (this.hasNextChapter) { + const nextChapter = this.chapters[this.currentChapterIndex + 1] + this.seek(nextChapter.start) + } else if (this.hasNextItemInQueue) { + this.$emit('nextItemInQueue') + } }, setStreamReady() { if (this.$refs.trackbar) this.$refs.trackbar.setPercentageReady(1) diff --git a/client/strings/en-us.json b/client/strings/en-us.json index 84e31678..7420c1e7 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -46,6 +46,7 @@ "ButtonNevermind": "Nevermind", "ButtonNext": "Next", "ButtonNextChapter": "Next Chapter", + "ButtonNextItemInQueue": "Next Item in Queue", "ButtonOk": "Ok", "ButtonOpenFeed": "Open Feed", "ButtonOpenManager": "Open Manager",