mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-03 00:06:46 +01:00
Add:Next chapter button plays next item in queue #3299
This commit is contained in:
parent
f9f89e1e51
commit
1320b6d785
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
@ -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')
|
||||||
|
@ -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)
|
||||||
|
@ -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",
|
||||||
|
Loading…
Reference in New Issue
Block a user