Add:Bookmarks icon btn on library item page and ability to open player at specified time #796

This commit is contained in:
advplyr 2022-07-29 19:06:52 -05:00
parent 45cd39ac0c
commit a8c7905f6d
5 changed files with 64 additions and 24 deletions

View File

@ -381,7 +381,7 @@ export default {
if (this.$refs.audioPlayer) this.$refs.audioPlayer.checkUpdateChapterTrack()
})
this.playerHandler.load(libraryItem, episodeId, true, this.initialPlaybackRate)
this.playerHandler.load(libraryItem, episodeId, true, this.initialPlaybackRate, payload.startTime)
},
pauseItem() {
this.playerHandler.pause()
@ -393,11 +393,13 @@ export default {
},
mounted() {
this.$eventBus.$on('cast-session-active', this.castSessionActive)
this.$eventBus.$on('playback-seek', this.seek)
this.$eventBus.$on('play-item', this.playLibraryItem)
this.$eventBus.$on('pause-item', this.pauseItem)
},
beforeDestroy() {
this.$eventBus.$off('cast-session-active', this.castSessionActive)
this.$eventBus.$off('playback-seek', this.seek)
this.$eventBus.$off('play-item', this.playLibraryItem)
this.$eventBus.$off('pause-item', this.pauseItem)
}

View File

@ -1,6 +1,11 @@
<template>
<modals-modal v-model="show" name="bookmarks" :width="500" :height="'unset'">
<div ref="container" class="w-full rounded-lg bg-primary box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
<template #outer>
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
<p class="font-book text-3xl text-white truncate">Your Bookmarks</p>
</div>
</template>
<div ref="container" class="w-full rounded-lg bg-bg box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
<div v-if="show" class="w-full h-full">
<template v-for="bookmark in bookmarks">
<modals-bookmarks-bookmark-item :key="bookmark.id" :highlight="currentTime === bookmark.time" :bookmark="bookmark" @click="clickBookmark" @update="submitUpdateBookmark" @delete="deleteBookmark" />
@ -8,8 +13,8 @@
<div v-if="!bookmarks.length" class="flex h-32 items-center justify-center">
<p class="text-xl">No Bookmarks</p>
</div>
<div class="w-full h-px bg-white bg-opacity-10" />
<form @submit.prevent="submitCreateBookmark">
<div v-if="!hideCreate" class="w-full h-px bg-white bg-opacity-10" />
<form v-if="!hideCreate" @submit.prevent="submitCreateBookmark">
<div v-show="canCreateBookmark" class="flex px-4 py-2 items-center text-center border-b border-white border-opacity-10 text-white text-opacity-80">
<div class="w-16 max-w-16 text-center">
<p class="text-sm font-mono text-gray-400">
@ -39,7 +44,8 @@ export default {
type: Number,
default: 0
},
libraryItemId: String
libraryItemId: String,
hideCreate: Boolean
},
data() {
return {

View File

@ -1,6 +1,5 @@
<template>
<div class="flex items-center px-4 py-4 justify-start relative hover:bg-bg" :class="wrapperClass" @click="click" @mouseover="mouseover" @mouseleave="mouseleave">
<!-- <span class="material-icons" :class="highlight ? 'text-success' : 'text-white text-opacity-80'">{{ highlight ? 'bookmark' : 'bookmark_border' }}</span> -->
<div class="flex items-center px-4 py-4 justify-start relative bg-primary hover:bg-opacity-25" :class="wrapperClass" @click="click" @mouseover="mouseover" @mouseleave="mouseleave">
<div class="w-16 max-w-16 text-center">
<p class="text-sm font-mono text-gray-400">
{{ this.$secondsToTimestamp(bookmark.time) }}

View File

@ -11,7 +11,7 @@
<!-- Item Cover Overlay -->
<div class="absolute top-0 left-0 w-full h-full z-10 bg-black bg-opacity-30 opacity-0 hover:opacity-100 transition-opacity" @mousedown.prevent @mouseup.prevent>
<div v-show="showPlayButton && !streaming" class="h-full flex items-center justify-center pointer-events-none">
<div v-show="showPlayButton && !isStreaming" class="h-full flex items-center justify-center pointer-events-none">
<div class="hover:text-white text-gray-200 hover:scale-110 transform duration-200 pointer-events-auto cursor-pointer" @click.stop.prevent="startStream">
<span class="material-icons text-4xl">play_circle_filled</span>
</div>
@ -129,12 +129,12 @@
<!-- Icon buttons -->
<div class="flex items-center justify-center md:justify-start pt-4">
<ui-btn v-if="showPlayButton" :disabled="streaming" color="success" :padding-x="4" small class="flex items-center h-9 mr-2" @click="startStream">
<span v-show="!streaming" class="material-icons -ml-2 pr-1 text-white">play_arrow</span>
{{ streaming ? 'Playing' : 'Play' }}
<ui-btn v-if="showPlayButton" :disabled="isStreaming" color="success" :padding-x="4" small class="flex items-center h-9 mr-2" @click="startStream">
<span v-show="!isStreaming" class="material-icons -ml-2 pr-1 text-white">play_arrow</span>
{{ isStreaming ? 'Playing' : 'Play' }}
</ui-btn>
<ui-btn v-else-if="isMissing || isInvalid" color="error" :padding-x="4" small class="flex items-center h-9 mr-2">
<span v-show="!streaming" class="material-icons -ml-2 pr-1 text-white">error</span>
<span v-show="!isStreaming" class="material-icons -ml-2 pr-1 text-white">error</span>
{{ isMissing ? 'Missing' : 'Incomplete' }}
</ui-btn>
@ -160,7 +160,11 @@
<ui-icon-btn icon="search" class="mx-0.5" :loading="fetchingRSSFeed" outlined @click="findEpisodesClick" />
</ui-tooltip>
<!-- Experimental RSS feed open -->
<ui-tooltip v-if="bookmarks.length" text="Your Bookmarks" direction="top">
<ui-icon-btn :icon="bookmarks.length ? 'bookmarks' : 'bookmark_border'" class="mx-0.5" @click="clickBookmarksBtn" />
</ui-tooltip>
<!-- RSS feed -->
<ui-tooltip v-if="showRssFeedBtn" text="Open RSS Feed" direction="top">
<ui-icon-btn icon="rss_feed" class="mx-0.5" :bg-color="rssFeedUrl ? 'success' : 'primary'" outlined @click="clickRSSFeed" />
</ui-tooltip>
@ -189,6 +193,7 @@
<modals-podcast-episode-feed v-model="showPodcastEpisodeFeed" :library-item="libraryItem" :episodes="podcastFeedEpisodes" />
<modals-rssfeed-view-modal v-model="showRssFeedModal" :library-item="libraryItem" :feed-url="rssFeedUrl" />
<modals-bookmarks-modal v-model="showBookmarksModal" :bookmarks="bookmarks" :library-item-id="libraryItemId" hide-create @select="selectBookmark" />
</div>
</template>
@ -222,7 +227,8 @@ export default {
podcastFeedEpisodes: [],
episodesDownloading: [],
episodeDownloadsQueued: [],
showRssFeedModal: false
showRssFeedModal: false,
showBookmarksModal: false
}
},
computed: {
@ -296,6 +302,10 @@ export default {
chapters() {
return this.media.chapters || []
},
bookmarks() {
if (this.isPodcast) return []
return this.$store.getters['user/getUserBookmarksForItem'](this.libraryItemId)
},
tracks() {
return this.media.tracks || []
},
@ -389,7 +399,7 @@ export default {
streamLibraryItem() {
return this.$store.state.streamLibraryItem
},
streaming() {
isStreaming() {
return this.streamLibraryItem && this.streamLibraryItem.id === this.libraryItemId
},
userCanUpdate() {
@ -409,6 +419,23 @@ export default {
}
},
methods: {
clickBookmarksBtn() {
this.showBookmarksModal = true
},
selectBookmark(bookmark) {
if (!bookmark) return
console.log('Select bookmark', bookmark)
if (this.isStreaming) {
this.$eventBus.$emit('playback-seek', bookmark.time)
} else if (this.streamLibraryItem) {
if (confirm(`Are you sure you want to play ${this.title} @ ${this.$secondsToTimestamp(bookmark.time)}?`)) {
this.startStream(bookmark.time)
}
} else {
this.startStream(bookmark.time)
}
this.showBookmarksModal = false
},
clearDownloadQueue() {
if (confirm('Are you sure you want to clear episode download queue?')) {
this.$axios
@ -470,7 +497,7 @@ export default {
this.$toast.error(`Failed to mark as ${updatePayload.isFinished ? 'Finished' : 'Not Finished'}`)
})
},
startStream() {
startStream(startTime = null) {
var episodeId = null
if (this.isPodcast) {
var episode = this.podcastEpisodes.find((ep) => {
@ -483,7 +510,8 @@ export default {
this.$eventBus.$emit('play-item', {
libraryItemId: this.libraryItem.id,
episodeId
episodeId,
startTime
})
},
editClick() {

View File

@ -18,6 +18,7 @@ export default class PlayerHandler {
this.isHlsTranscode = false
this.isVideo = false
this.currentSessionId = null
this.startTimeOverride = undefined // Used for starting playback at a specific time (i.e. clicking bookmark from library item page)
this.startTime = 0
this.failedProgressSyncs = 0
@ -51,12 +52,13 @@ export default class PlayerHandler {
return this.libraryItem.media.episodes.find(ep => ep.id === this.episodeId)
}
load(libraryItem, episodeId, playWhenReady, playbackRate) {
load(libraryItem, episodeId, playWhenReady, playbackRate, startTimeOverride = undefined) {
this.libraryItem = libraryItem
this.episodeId = episodeId
this.playWhenReady = playWhenReady
this.initialPlaybackRate = playbackRate
this.isVideo = libraryItem.mediaType === 'video'
this.startTimeOverride = (startTimeOverride == null || isNaN(startTimeOverride)) ? undefined : Number(startTimeOverride)
if (!this.player) this.switchPlayer(playWhenReady)
else this.prepare()
@ -142,11 +144,13 @@ export default class PlayerHandler {
} else {
this.stopPlayInterval()
}
if (this.playerState === 'LOADED' || this.playerState === 'PLAYING') {
this.ctx.setDuration(this.getDuration())
}
if (this.playerState !== 'LOADING') {
this.ctx.setCurrentTime(this.player.getCurrentTime())
if (this.player) {
if (this.playerState === 'LOADED' || this.playerState === 'PLAYING') {
this.ctx.setDuration(this.getDuration())
}
if (this.playerState !== 'LOADING') {
this.ctx.setCurrentTime(this.player.getCurrentTime())
}
}
this.ctx.setPlaying(this.playerState === 'PLAYING')
@ -183,13 +187,14 @@ export default class PlayerHandler {
this.isVideo = session.libraryItem.mediaType === 'video'
this.playWhenReady = false
this.initialPlaybackRate = playbackRate
this.startTimeOverride = undefined
this.prepareSession(session)
}
prepareSession(session) {
this.failedProgressSyncs = 0
this.startTime = session.currentTime
this.startTime = this.startTimeOverride !== undefined ? this.startTimeOverride : session.currentTime
this.currentSessionId = session.id
this.displayTitle = session.displayTitle
this.displayAuthor = session.displayAuthor