mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-02-08 19:29:39 +00:00
Laying the groundwork for music media type #964
This commit is contained in:
parent
c3717f6979
commit
b884f8fe11
18 changed files with 491 additions and 134 deletions
|
|
@ -16,17 +16,17 @@
|
|||
<nuxt-link v-if="isPodcastLibrary" :to="`/library/${currentLibraryId}/podcast/latest`" class="flex-grow h-full flex justify-center items-center" :class="isPodcastLatestPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<p class="text-sm">{{ $strings.ButtonLatest }}</p>
|
||||
</nuxt-link>
|
||||
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/series`" class="flex-grow h-full flex justify-center items-center" :class="isSeriesPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/series`" class="flex-grow h-full flex justify-center items-center" :class="isSeriesPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<p v-if="isSeriesPage" class="text-sm">{{ $strings.ButtonSeries }}</p>
|
||||
<svg v-else xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" />
|
||||
</svg>
|
||||
</nuxt-link>
|
||||
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="flex-grow h-full flex justify-center items-center" :class="isCollectionsPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="flex-grow h-full flex justify-center items-center" :class="isCollectionsPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<p v-if="isCollectionsPage" class="text-sm">{{ $strings.ButtonCollections }}</p>
|
||||
<span v-else class="material-icons-outlined text-lg">collections_bookmark</span>
|
||||
</nuxt-link>
|
||||
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/authors`" class="flex-grow h-full flex justify-center items-center" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/authors`" class="flex-grow h-full flex justify-center items-center" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<p v-if="isAuthorsPage" class="text-sm">{{ $strings.ButtonAuthors }}</p>
|
||||
<svg v-else class="w-5 h-5" viewBox="0 0 24 24">
|
||||
<path
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
|
||||
<div class="flex-grow hidden sm:inline-block" />
|
||||
|
||||
<ui-checkbox v-if="isLibraryPage && !isPodcastLibrary && !isBatchSelecting" v-model="settings.collapseSeries" :label="$strings.LabelCollapseSeries" checkbox-bg="bg" check-color="white" small class="mr-2" @input="updateCollapseSeries" />
|
||||
<ui-checkbox v-if="isLibraryPage && isBookLibrary && !isBatchSelecting" v-model="settings.collapseSeries" :label="$strings.LabelCollapseSeries" checkbox-bg="bg" check-color="white" small class="mr-2" @input="updateCollapseSeries" />
|
||||
<controls-library-filter-select v-if="isLibraryPage && !isBatchSelecting" v-model="settings.filterBy" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateFilter" />
|
||||
<controls-library-sort-select v-if="isLibraryPage && !isBatchSelecting" v-model="settings.orderBy" :descending.sync="settings.orderDesc" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateOrder" />
|
||||
<controls-library-filter-select v-if="isSeriesPage && !isBatchSelecting" v-model="settings.seriesFilterBy" is-series class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateSeriesFilter" />
|
||||
|
|
@ -153,9 +153,15 @@ export default {
|
|||
currentLibraryMediaType() {
|
||||
return this.$store.getters['libraries/getCurrentLibraryMediaType']
|
||||
},
|
||||
isBookLibrary() {
|
||||
return this.currentLibraryMediaType === 'book'
|
||||
},
|
||||
isPodcastLibrary() {
|
||||
return this.currentLibraryMediaType === 'podcast'
|
||||
},
|
||||
isMusicLibrary() {
|
||||
return this.currentLibraryMediaType === 'music'
|
||||
},
|
||||
isLibraryPage() {
|
||||
return this.page === ''
|
||||
},
|
||||
|
|
@ -184,6 +190,7 @@ export default {
|
|||
return this.totalEntities
|
||||
},
|
||||
entityName() {
|
||||
if (this.isMusicLibrary) return 'Tracks'
|
||||
if (this.isPodcastLibrary) return this.$strings.LabelPodcasts
|
||||
if (!this.page) return this.$strings.LabelBooks
|
||||
if (this.isSeriesPage) return this.$strings.LabelSeries
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<div v-show="showLibrary" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
|
||||
</nuxt-link>
|
||||
|
||||
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/series`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isSeriesPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/series`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isSeriesPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" />
|
||||
</svg>
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
<div v-show="isSeriesPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
|
||||
</nuxt-link>
|
||||
|
||||
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'collections' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'collections' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||
<span class="material-icons-outlined text-2xl">collections_bookmark</span>
|
||||
|
||||
<p class="font-book pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonCollections }}</p>
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
<div v-show="paramId === 'collections'" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
|
||||
</nuxt-link>
|
||||
|
||||
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/authors`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/authors`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||
<svg class="w-6 h-6" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="currentColor"
|
||||
|
|
@ -132,6 +132,9 @@ export default {
|
|||
currentLibraryMediaType() {
|
||||
return this.$store.getters['libraries/getCurrentLibraryMediaType']
|
||||
},
|
||||
isBookLibrary() {
|
||||
return this.currentLibraryMediaType === 'book'
|
||||
},
|
||||
isPodcastLibrary() {
|
||||
return this.currentLibraryMediaType === 'podcast'
|
||||
},
|
||||
|
|
|
|||
|
|
@ -122,6 +122,9 @@ export default {
|
|||
isPodcast() {
|
||||
return this.streamLibraryItem ? this.streamLibraryItem.mediaType === 'podcast' : false
|
||||
},
|
||||
isMusic() {
|
||||
return this.streamLibraryItem ? this.streamLibraryItem.mediaType === 'music' : false
|
||||
},
|
||||
mediaMetadata() {
|
||||
return this.media.metadata || {}
|
||||
},
|
||||
|
|
@ -405,8 +408,8 @@ export default {
|
|||
}
|
||||
},
|
||||
async playLibraryItem(payload) {
|
||||
var libraryItemId = payload.libraryItemId
|
||||
var episodeId = payload.episodeId || null
|
||||
const libraryItemId = payload.libraryItemId
|
||||
const episodeId = payload.episodeId || null
|
||||
|
||||
if (this.playerHandler.libraryItemId == libraryItemId && this.playerHandler.episodeId == episodeId) {
|
||||
if (payload.startTime !== null && !isNaN(payload.startTime)) {
|
||||
|
|
@ -417,11 +420,12 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
var libraryItem = await this.$axios.$get(`/api/items/${libraryItemId}?expanded=1`).catch((error) => {
|
||||
const libraryItem = await this.$axios.$get(`/api/items/${libraryItemId}?expanded=1`).catch((error) => {
|
||||
console.error('Failed to fetch full item', error)
|
||||
return null
|
||||
})
|
||||
if (!libraryItem) return
|
||||
|
||||
this.$store.commit('setMediaPlaying', {
|
||||
libraryItem,
|
||||
episodeId,
|
||||
|
|
|
|||
|
|
@ -190,6 +190,9 @@ export default {
|
|||
isPodcast() {
|
||||
return this.mediaType === 'podcast'
|
||||
},
|
||||
isMusic() {
|
||||
return this.mediaType === 'music'
|
||||
},
|
||||
placeholderUrl() {
|
||||
const config = this.$config || this.$nuxt.$config
|
||||
return `${config.routerBasePath}/book_placeholder.jpg`
|
||||
|
|
@ -305,6 +308,7 @@ export default {
|
|||
return this.store.getters['user/getUserMediaProgress'](this.libraryItemId, this.recentEpisode.id)
|
||||
},
|
||||
userProgress() {
|
||||
if (this.isMusic) return null
|
||||
if (this.episodeProgress) return this.episodeProgress
|
||||
return this.store.getters['user/getUserMediaProgress'](this.libraryItemId)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ export default {
|
|||
value: 'podcast',
|
||||
text: this.$strings.LabelPodcasts
|
||||
}
|
||||
// {
|
||||
// value: 'music',
|
||||
// text: 'Music'
|
||||
// }
|
||||
]
|
||||
},
|
||||
folderPaths() {
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@
|
|||
<span v-show="!isStreaming" class="material-icons text-2xl -ml-2 pr-1 text-white">play_arrow</span>
|
||||
{{ isStreaming ? $strings.ButtonPlaying : $strings.ButtonPlay }}
|
||||
</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="!isStreaming" class="material-icons text-2xl -ml-2 pr-1 text-white">error</span>
|
||||
{{ isMissing ? $strings.LabelMissing : $strings.LabelIncomplete }}
|
||||
|
|
@ -150,11 +151,11 @@
|
|||
<ui-icon-btn icon="edit" class="mx-0.5" @click="editClick" />
|
||||
</ui-tooltip>
|
||||
|
||||
<ui-tooltip v-if="!isPodcast" :text="userIsFinished ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" direction="top">
|
||||
<ui-tooltip v-if="!isPodcast && !isMusic" :text="userIsFinished ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" direction="top">
|
||||
<ui-read-icon-btn :disabled="isProcessingReadUpdate" :is-read="userIsFinished" class="mx-0.5" @click="toggleFinished" />
|
||||
</ui-tooltip>
|
||||
|
||||
<ui-tooltip v-if="!isPodcast && userCanUpdate" :text="$strings.LabelCollections" direction="top">
|
||||
<ui-tooltip v-if="showCollectionsButton" :text="$strings.LabelCollections" direction="top">
|
||||
<ui-icon-btn icon="collections_bookmark" class="mx-0.5" outlined @click="collectionsClick" />
|
||||
</ui-tooltip>
|
||||
|
||||
|
|
@ -263,12 +264,18 @@ export default {
|
|||
isDeveloperMode() {
|
||||
return this.$store.state.developerMode
|
||||
},
|
||||
isBook() {
|
||||
return this.libraryItem.mediaType === 'book'
|
||||
},
|
||||
isPodcast() {
|
||||
return this.libraryItem.mediaType === 'podcast'
|
||||
},
|
||||
isVideo() {
|
||||
return this.libraryItem.mediaType === 'video'
|
||||
},
|
||||
isMusic() {
|
||||
return this.libraryItem.mediaType === 'music'
|
||||
},
|
||||
isMissing() {
|
||||
return this.libraryItem.isMissing
|
||||
},
|
||||
|
|
@ -276,11 +283,12 @@ export default {
|
|||
return this.libraryItem.isInvalid
|
||||
},
|
||||
invalidAudioFiles() {
|
||||
if (this.isPodcast || this.isVideo) return []
|
||||
if (!this.isBook) return []
|
||||
return this.libraryItem.media.audioFiles.filter((af) => af.invalid)
|
||||
},
|
||||
showPlayButton() {
|
||||
if (this.isMissing || this.isInvalid) return false
|
||||
if (this.isMusic) return !!this.audioFile
|
||||
if (this.isVideo) return !!this.videoFile
|
||||
if (this.isPodcast) return this.podcastEpisodes.length
|
||||
return this.tracks.length
|
||||
|
|
@ -374,6 +382,10 @@ export default {
|
|||
videoFile() {
|
||||
return this.media.videoFile
|
||||
},
|
||||
audioFile() {
|
||||
// Music track
|
||||
return this.media.audioFile
|
||||
},
|
||||
showExperimentalReadAlert() {
|
||||
return !this.tracks.length && this.ebookFile && !this.showExperimentalFeatures && !this.enableEReader
|
||||
},
|
||||
|
|
@ -381,6 +393,7 @@ export default {
|
|||
return this.mediaMetadata.description || ''
|
||||
},
|
||||
userMediaProgress() {
|
||||
if (this.isMusic) return null
|
||||
return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId)
|
||||
},
|
||||
userIsFinished() {
|
||||
|
|
@ -425,8 +438,11 @@ export default {
|
|||
return this.userIsAdminOrUp || this.rssFeedUrl
|
||||
},
|
||||
showQueueBtn() {
|
||||
if (this.isPodcast || this.isVideo) return false
|
||||
if (!this.isBook) return false
|
||||
return !this.$store.getters['getIsStreamingFromDifferentLibrary'] && this.streamLibraryItem
|
||||
},
|
||||
showCollectionsButton() {
|
||||
return this.isBook && this.userCanUpdate
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -531,14 +547,14 @@ export default {
|
|||
})
|
||||
},
|
||||
playItem(startTime = null) {
|
||||
var episodeId = null
|
||||
let episodeId = null
|
||||
const queueItems = []
|
||||
if (this.isPodcast) {
|
||||
const episodesInListeningOrder = this.podcastEpisodes.map((ep) => ({ ...ep })).sort((a, b) => String(a.publishedAt).localeCompare(String(b.publishedAt), undefined, { numeric: true, sensitivity: 'base' }))
|
||||
|
||||
// Find most recent episode unplayed
|
||||
var episodeIndex = episodesInListeningOrder.findLastIndex((ep) => {
|
||||
var podcastProgress = this.$store.getters['user/getUserMediaProgress'](this.libraryItemId, ep.id)
|
||||
let episodeIndex = episodesInListeningOrder.findLastIndex((ep) => {
|
||||
const podcastProgress = this.$store.getters['user/getUserMediaProgress'](this.libraryItemId, ep.id)
|
||||
return !podcastProgress || !podcastProgress.isFinished
|
||||
})
|
||||
if (episodeIndex < 0) episodeIndex = 0
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export default class PlayerHandler {
|
|||
this.playerState = 'IDLE'
|
||||
this.isHlsTranscode = false
|
||||
this.isVideo = false
|
||||
this.isMusic = 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
|
||||
|
|
@ -54,10 +55,13 @@ export default class PlayerHandler {
|
|||
|
||||
load(libraryItem, episodeId, playWhenReady, playbackRate, startTimeOverride = undefined) {
|
||||
this.libraryItem = libraryItem
|
||||
this.isVideo = libraryItem.mediaType === 'video'
|
||||
this.isMusic = libraryItem.mediaType === 'music'
|
||||
|
||||
this.episodeId = episodeId
|
||||
this.playWhenReady = playWhenReady
|
||||
this.initialPlaybackRate = playbackRate
|
||||
this.isVideo = libraryItem.mediaType === 'video'
|
||||
this.initialPlaybackRate = this.isMusic ? 1 : playbackRate
|
||||
|
||||
this.startTimeOverride = (startTimeOverride == null || isNaN(startTimeOverride)) ? undefined : Number(startTimeOverride)
|
||||
|
||||
if (!this.player) this.switchPlayer(playWhenReady)
|
||||
|
|
@ -140,12 +144,16 @@ export default class PlayerHandler {
|
|||
playerStateChange(state) {
|
||||
console.log('[PlayerHandler] Player state change', state)
|
||||
this.playerState = state
|
||||
if (this.playerState === 'PLAYING') {
|
||||
this.setPlaybackRate(this.initialPlaybackRate)
|
||||
this.startPlayInterval()
|
||||
} else {
|
||||
this.stopPlayInterval()
|
||||
|
||||
if (!this.isMusic) {
|
||||
if (this.playerState === 'PLAYING') {
|
||||
this.setPlaybackRate(this.initialPlaybackRate)
|
||||
this.startPlayInterval()
|
||||
} else {
|
||||
this.stopPlayInterval()
|
||||
}
|
||||
}
|
||||
|
||||
if (this.player) {
|
||||
if (this.playerState === 'LOADED' || this.playerState === 'PLAYING') {
|
||||
this.ctx.setDuration(this.getDuration())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue