Add:Next chapter button plays next item in queue #3299

This commit is contained in:
advplyr 2024-08-17 13:32:00 -05:00
parent f9f89e1e51
commit 1320b6d785
5 changed files with 71 additions and 23 deletions

View File

@ -43,12 +43,14 @@
:sleep-timer-remaining="sleepTimerRemaining" :sleep-timer-remaining="sleepTimerRemaining"
:sleep-timer-type="sleepTimerType" :sleep-timer-type="sleepTimerType"
:is-podcast="isPodcast" :is-podcast="isPodcast"
:hasNextItemInQueue="hasNextItemInQueue"
@playPause="playPause" @playPause="playPause"
@jumpForward="jumpForward" @jumpForward="jumpForward"
@jumpBackward="jumpBackward" @jumpBackward="jumpBackward"
@setVolume="setVolume" @setVolume="setVolume"
@setPlaybackRate="setPlaybackRate" @setPlaybackRate="setPlaybackRate"
@seek="seek" @seek="seek"
@nextItemInQueue="playNextItemInQueue"
@close="closePlayer" @close="closePlayer"
@showBookmarks="showBookmarks" @showBookmarks="showBookmarks"
@showSleepTimer="showSleepTimerModal = true" @showSleepTimer="showSleepTimerModal = true"
@ -60,7 +62,7 @@
<modals-sleep-timer-modal v-model="showSleepTimerModal" :timer-set="sleepTimerSet" :timer-type="sleepTimerType" :remaining="sleepTimerRemaining" :has-chapters="!!chapters.length" @set="setSleepTimer" @cancel="cancelSleepTimer" @increment="incrementSleepTimer" @decrement="decrementSleepTimer" /> <modals-sleep-timer-modal v-model="showSleepTimerModal" :timer-set="sleepTimerSet" :timer-type="sleepTimerType" :remaining="sleepTimerRemaining" :has-chapters="!!chapters.length" @set="setSleepTimer" @cancel="cancelSleepTimer" @increment="incrementSleepTimer" @decrement="decrementSleepTimer" />
<modals-player-queue-items-modal v-model="showPlayerQueueItemsModal" :library-item-id="libraryItemId" /> <modals-player-queue-items-modal v-model="showPlayerQueueItemsModal" />
<modals-player-settings-modal v-model="showPlayerSettingsModal" /> <modals-player-settings-modal v-model="showPlayerSettingsModal" />
</div> </div>
@ -176,6 +178,16 @@ export default {
if (!this.isMusic) return null if (!this.isMusic) return null
return this.mediaMetadata.artists.join(', ') 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() { playerQueueItems() {
return this.$store.state.playerQueueItems || [] return this.$store.state.playerQueueItems || []
} }
@ -460,6 +472,30 @@ export default {
this.playerHandler.switchPlayer() 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) { async playLibraryItem(payload) {
const libraryItemId = payload.libraryItemId const libraryItemId = payload.libraryItemId
const episodeId = payload.episodeId || null const episodeId = payload.episodeId || null
@ -512,6 +548,7 @@ export default {
this.$eventBus.$on('cast-session-active', this.castSessionActive) this.$eventBus.$on('cast-session-active', this.castSessionActive)
this.$eventBus.$on('playback-seek', this.seek) this.$eventBus.$on('playback-seek', this.seek)
this.$eventBus.$on('playback-time-update', this.playbackTimeUpdate) 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('play-item', this.playLibraryItem)
this.$eventBus.$on('pause-item', this.pauseItem) this.$eventBus.$on('pause-item', this.pauseItem)
}, },
@ -519,6 +556,7 @@ export default {
this.$eventBus.$off('cast-session-active', this.castSessionActive) this.$eventBus.$off('cast-session-active', this.castSessionActive)
this.$eventBus.$off('playback-seek', this.seek) this.$eventBus.$off('playback-seek', this.seek)
this.$eventBus.$off('playback-time-update', this.playbackTimeUpdate) 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('play-item', this.playLibraryItem)
this.$eventBus.$off('pause-item', this.pauseItem) this.$eventBus.$off('pause-item', this.pauseItem)
} }

View File

@ -13,7 +13,7 @@
<div class="flex-grow" /> <div class="flex-grow" />
<ui-checkbox v-model="playerQueueAutoPlay" label="Auto Play" medium checkbox-bg="primary" border-color="gray-600" label-class="pl-2 mb-px" /> <ui-checkbox v-model="playerQueueAutoPlay" label="Auto Play" medium checkbox-bg="primary" border-color="gray-600" label-class="pl-2 mb-px" />
</div> </div>
<modals-player-queue-item-row v-for="(item, index) in playerQueueItems" :key="index" :item="item" :index="index" @play="playItem" @remove="removeItem" /> <modals-player-queue-item-row v-for="(item, index) in playerQueueItems" :key="index" :item="item" :index="index" @play="playItem(index)" @remove="removeItem" />
</div> </div>
</div> </div>
</modals-modal> </modals-modal>
@ -22,8 +22,7 @@
<script> <script>
export default { export default {
props: { props: {
value: Boolean, value: Boolean
libraryItemId: String
}, },
data() { data() {
return {} return {}
@ -50,11 +49,9 @@ export default {
} }
}, },
methods: { methods: {
playItem(item) { playItem(index) {
this.$eventBus.$emit('play-item', { this.$eventBus.$emit('play-queue-item', {
libraryItemId: item.libraryItemId, index
episodeId: item.episodeId || null,
queueItems: this.playerQueueItems
}) })
this.show = false this.show = false
}, },

View File

@ -20,8 +20,8 @@
<span class="material-symbols text-2xl sm:text-3xl">forward_media</span> <span class="material-symbols text-2xl sm:text-3xl">forward_media</span>
</button> </button>
</ui-tooltip> </ui-tooltip>
<ui-tooltip direction="top" :text="$strings.ButtonNextChapter" class="ml-4 lg:ml-8"> <ui-tooltip direction="top" :text="hasNextLabel" class="ml-4 lg:ml-8">
<button :aria-label="$strings.ButtonNextChapter" :disabled="!hasNextChapter" :class="hasNextChapter ? 'text-gray-300' : 'text-gray-500'" @mousedown.prevent @mouseup.prevent @click.stop="nextChapter"> <button :aria-label="hasNextLabel" :disabled="!hasNext" class="text-gray-300 disabled:text-gray-500" @mousedown.prevent @mouseup.prevent @click.stop="next">
<span class="material-symbols text-2xl sm:text-3xl">last_page</span> <span class="material-symbols text-2xl sm:text-3xl">last_page</span>
</button> </button>
</ui-tooltip> </ui-tooltip>
@ -43,7 +43,8 @@ export default {
seekLoading: Boolean, seekLoading: Boolean,
playbackRate: Number, playbackRate: Number,
paused: Boolean, paused: Boolean,
hasNextChapter: Boolean hasNextChapter: Boolean,
hasNextItemInQueue: Boolean
}, },
data() { data() {
return {} return {}
@ -62,6 +63,13 @@ export default {
}, },
jumpBackwardText() { jumpBackwardText() {
return this.getJumpText('jumpBackwardAmount', this.$strings.ButtonJumpBackward) 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: { methods: {
@ -71,9 +79,9 @@ export default {
prevChapter() { prevChapter() {
this.$emit('prevChapter') this.$emit('prevChapter')
}, },
nextChapter() { next() {
if (!this.hasNextChapter) return if (!this.hasNext) return
this.$emit('nextChapter') this.$emit('next')
}, },
jumpBackward() { jumpBackward() {
this.$emit('jumpBackward') this.$emit('jumpBackward')

View File

@ -43,7 +43,7 @@
</ui-tooltip> </ui-tooltip>
</div> </div>
<player-playback-controls :loading="loading" :seek-loading="seekLoading" :playback-rate.sync="playbackRate" :paused="paused" :has-next-chapter="hasNextChapter" @prevChapter="prevChapter" @nextChapter="nextChapter" @jumpForward="jumpForward" @jumpBackward="jumpBackward" @setPlaybackRate="setPlaybackRate" @playPause="playPause" /> <player-playback-controls :loading="loading" :seek-loading="seekLoading" :playback-rate.sync="playbackRate" :paused="paused" :hasNextChapter="hasNextChapter" :hasNextItemInQueue="hasNextItemInQueue" @prevChapter="prevChapter" @next="goToNext" @jumpForward="jumpForward" @jumpBackward="jumpBackward" @setPlaybackRate="setPlaybackRate" @playPause="playPause" />
</div> </div>
<player-track-bar ref="trackbar" :loading="loading" :chapters="chapters" :duration="duration" :current-chapter="currentChapter" :playback-rate="playbackRate" @seek="seek" /> <player-track-bar ref="trackbar" :loading="loading" :chapters="chapters" :duration="duration" :current-chapter="currentChapter" :playback-rate="playbackRate" @seek="seek" />
@ -82,7 +82,8 @@ export default {
sleepTimerType: String, sleepTimerType: String,
isPodcast: Boolean, isPodcast: Boolean,
hideBookmarks: Boolean, hideBookmarks: Boolean,
hideSleepTimer: Boolean hideSleepTimer: Boolean,
hasNextItemInQueue: Boolean
}, },
data() { data() {
return { return {
@ -145,7 +146,7 @@ export default {
return Math.round((100 * time) / duration) return Math.round((100 * time) / duration)
}, },
currentChapterName() { currentChapterName() {
return this.currentChapter ? this.currentChapter.title : '' return this.currentChapter?.title || ''
}, },
currentChapterDuration() { currentChapterDuration() {
if (!this.currentChapter) return 0 if (!this.currentChapter) return 0
@ -278,10 +279,13 @@ export default {
this.seek(this.currentChapter.start) this.seek(this.currentChapter.start)
} }
}, },
nextChapter() { goToNext() {
if (!this.currentChapter || !this.hasNextChapter) return if (this.hasNextChapter) {
var nextChapter = this.chapters[this.currentChapterIndex + 1] const nextChapter = this.chapters[this.currentChapterIndex + 1]
this.seek(nextChapter.start) this.seek(nextChapter.start)
} else if (this.hasNextItemInQueue) {
this.$emit('nextItemInQueue')
}
}, },
setStreamReady() { setStreamReady() {
if (this.$refs.trackbar) this.$refs.trackbar.setPercentageReady(1) if (this.$refs.trackbar) this.$refs.trackbar.setPercentageReady(1)

View File

@ -46,6 +46,7 @@
"ButtonNevermind": "Nevermind", "ButtonNevermind": "Nevermind",
"ButtonNext": "Next", "ButtonNext": "Next",
"ButtonNextChapter": "Next Chapter", "ButtonNextChapter": "Next Chapter",
"ButtonNextItemInQueue": "Next Item in Queue",
"ButtonOk": "Ok", "ButtonOk": "Ok",
"ButtonOpenFeed": "Open Feed", "ButtonOpenFeed": "Open Feed",
"ButtonOpenManager": "Open Manager", "ButtonOpenManager": "Open Manager",