mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-03-02 22:19:40 +00:00
Merge remote-tracking branch 'remotes/upstream/master'
This commit is contained in:
commit
f5abe92cd3
78 changed files with 1736 additions and 258 deletions
|
|
@ -156,7 +156,7 @@ export default {
|
|||
return this.mediaMetadata.authors || []
|
||||
},
|
||||
libraryId() {
|
||||
return this.streamLibraryItem ? this.streamLibraryItem.libraryId : null
|
||||
return this.streamLibraryItem?.libraryId || null
|
||||
},
|
||||
totalDurationPretty() {
|
||||
// Adjusted by playback rate
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@
|
|||
<div class="w-1/2 px-2">
|
||||
<div v-if="!isPodcast" class="flex items-end">
|
||||
<ui-text-input-with-label v-model.trim="itemData.author" :disabled="processing" :label="$strings.LabelAuthor" />
|
||||
<ui-tooltip :text="$strings.LabelUploaderItemFetchMetadataHelp">
|
||||
<div class="ml-2 mb-1 w-8 h-8 bg-bg border border-white/10 flex items-center justify-center rounded-full hover:bg-primary cursor-pointer" @click="fetchMetadata">
|
||||
<ui-tooltip direction="top" :text="$strings.LabelUploaderItemFetchMetadataHelp">
|
||||
<button type="button" class="ml-2 mb-1 w-8 h-8 bg-bg border border-white/10 flex items-center justify-center rounded-full hover:bg-primary cursor-pointer" @click="fetchMetadata">
|
||||
<span class="text-base text-white/80 font-mono material-symbols">sync</span>
|
||||
</div>
|
||||
</button>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<div v-else class="w-full">
|
||||
|
|
|
|||
|
|
@ -223,8 +223,7 @@ export default {
|
|||
return this.mediaMetadata.explicit || false
|
||||
},
|
||||
placeholderUrl() {
|
||||
const config = this.$config || this.$nuxt.$config
|
||||
return `${config.routerBasePath}/book_placeholder.jpg`
|
||||
return this.store.getters['globals/getPlaceholderCoverSrc']
|
||||
},
|
||||
bookCoverSrc() {
|
||||
return this.store.getters['globals/getLibraryItemCoverSrc'](this._libraryItem, this.placeholderUrl)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="narrators?.length" class="flex py-0.5 mt-4">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelNarrators }}</span>
|
||||
</div>
|
||||
<div class="max-w-[calc(100vw-10rem)] overflow-hidden text-ellipsis">
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div v-if="publishedYear" role="paragraph" class="flex py-0.5">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelPublishYear }}</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div v-if="publisher" role="paragraph" class="flex py-0.5">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelPublisher }}</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div v-if="podcastType" role="paragraph" class="flex py-0.5">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelPodcastType }}</span>
|
||||
</div>
|
||||
<div class="capitalize">
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="flex py-0.5" v-if="genres.length">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelGenres }}</span>
|
||||
</div>
|
||||
<div class="max-w-[calc(100vw-10rem)] overflow-hidden text-ellipsis">
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="flex py-0.5" v-if="tags.length">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelTags }}</span>
|
||||
</div>
|
||||
<div class="max-w-[calc(100vw-10rem)] overflow-hidden text-ellipsis">
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div v-if="language" class="flex py-0.5">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelLanguage }}</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div v-if="tracks.length || (isPodcast && totalPodcastDuration)" role="paragraph" class="flex py-0.5">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelDuration }}</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div role="paragraph" class="flex py-0.5">
|
||||
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
|
||||
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
|
||||
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelSize }}</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ export default {
|
|||
return this.author
|
||||
},
|
||||
placeholderUrl() {
|
||||
const config = this.$config || this.$nuxt.$config
|
||||
return `${config.routerBasePath}/book_placeholder.jpg`
|
||||
const store = this.$store || this.$nuxt.$store
|
||||
return store.getters['globals/getPlaceholderCoverSrc']
|
||||
},
|
||||
fullCoverUrl() {
|
||||
if (!this.libraryItem) return null
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="!imageFailed && showResolution" class="absolute -bottom-5 left-0 right-0 mx-auto text-xs text-gray-300 text-center">{{ resolution }}</p>
|
||||
<p v-if="!imageFailed && showResolution && resolution" class="absolute -bottom-5 left-0 right-0 mx-auto text-xs text-gray-300 text-center">{{ resolution }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -65,11 +65,12 @@ export default {
|
|||
return 0.8 * this.sizeMultiplier
|
||||
},
|
||||
resolution() {
|
||||
if (!this.naturalWidth || !this.naturalHeight) return null
|
||||
return `${this.naturalWidth}×${this.naturalHeight}px`
|
||||
},
|
||||
placeholderUrl() {
|
||||
const config = this.$config || this.$nuxt.$config
|
||||
return `${config.routerBasePath}/book_placeholder.jpg`
|
||||
const store = this.$store || this.$nuxt.$store
|
||||
return store.getters['globals/getPlaceholderCoverSrc']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<div class="w-full h-full overflow-hidden overflow-y-auto px-2 sm:px-4 py-6 relative">
|
||||
<div class="flex flex-col sm:flex-row mb-4">
|
||||
<div class="relative self-center md:self-start">
|
||||
<covers-preview-cover :src="$store.getters['globals/getLibraryItemCoverSrcById'](libraryItemId, libraryItemUpdatedAt, true)" :width="120" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
||||
<covers-preview-cover :src="coverUrl" :width="120" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
||||
|
||||
<!-- book cover overlay -->
|
||||
<div v-if="media.coverPath" class="absolute top-0 left-0 w-full h-full z-10 opacity-0 hover:opacity-100 transition-opacity duration-100">
|
||||
|
|
@ -157,6 +157,12 @@ export default {
|
|||
coverPath() {
|
||||
return this.media.coverPath
|
||||
},
|
||||
coverUrl() {
|
||||
if (!this.coverPath) {
|
||||
return this.$store.getters['globals/getPlaceholderCoverSrc']
|
||||
}
|
||||
return this.$store.getters['globals/getLibraryItemCoverSrcById'](this.libraryItemId, this.libraryItemUpdatedAt, true)
|
||||
},
|
||||
mediaMetadata() {
|
||||
return this.media.metadata || {}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export default {
|
|||
return this.item.coverPath
|
||||
},
|
||||
coverUrl() {
|
||||
if (!this.coverPath) return `${this.$config.routerBasePath}/book_placeholder.jpg`
|
||||
if (!this.coverPath) return this.$store.getters['globals/getPlaceholderCoverSrc']
|
||||
return this.$store.getters['globals/getLibraryItemCoverSrcById'](this.libraryItemId)
|
||||
},
|
||||
bookCoverAspectRatio() {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,12 @@
|
|||
<form @submit.prevent="submit" class="flex grow">
|
||||
<ui-text-input v-model="search" @input="inputUpdate" type="search" :placeholder="$strings.PlaceholderSearchEpisode" class="grow mr-2 text-sm md:text-base" />
|
||||
</form>
|
||||
<ui-btn :padding-x="4" @click="toggleSort">
|
||||
<span class="pr-4">{{ $strings.LabelSortPubDate }}</span>
|
||||
<span class="text-yellow-400 absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<span class="material-symbols text-xl" :aria-label="sortDescending ? $strings.LabelSortDescending : $strings.LabelSortAscending">{{ sortDescending ? 'expand_more' : 'expand_less' }}</span>
|
||||
</span>
|
||||
</ui-btn>
|
||||
</div>
|
||||
<div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto">
|
||||
<div v-for="(episode, index) in episodesList" :key="index" class="relative" :class="episode.isDownloaded || episode.isDownloading ? 'bg-primary/40' : selectedEpisodes[episode.cleanUrl] ? 'cursor-pointer bg-success/10' : index % 2 == 0 ? 'cursor-pointer bg-primary/25 hover:bg-primary/40' : 'cursor-pointer bg-primary/5 hover:bg-primary/25'" @click="toggleSelectEpisode(episode)">
|
||||
|
|
@ -73,7 +79,8 @@ export default {
|
|||
searchTimeout: null,
|
||||
searchText: null,
|
||||
downloadedEpisodeGuidMap: {},
|
||||
downloadedEpisodeUrlMap: {}
|
||||
downloadedEpisodeUrlMap: {},
|
||||
sortDescending: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -141,6 +148,17 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSort() {
|
||||
this.sortDescending = !this.sortDescending
|
||||
this.episodesCleaned = this.episodesCleaned.toSorted((a, b) => {
|
||||
if (this.sortDescending) {
|
||||
return a.publishedAt < b.publishedAt ? 1 : -1
|
||||
}
|
||||
return a.publishedAt > b.publishedAt ? 1 : -1
|
||||
})
|
||||
this.selectedEpisodes = {}
|
||||
this.selectAll = false
|
||||
},
|
||||
getIsEpisodeDownloaded(episode) {
|
||||
if (episode.guid && !!this.downloadedEpisodeGuidMap[episode.guid]) {
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -74,6 +74,9 @@ export default {
|
|||
currentChapterStart() {
|
||||
if (!this.currentChapter) return 0
|
||||
return this.currentChapter.start
|
||||
},
|
||||
isMobile() {
|
||||
return this.$store.state.globals.isMobile
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -145,6 +148,9 @@ export default {
|
|||
})
|
||||
},
|
||||
mousemoveTrack(e) {
|
||||
if (this.isMobile) {
|
||||
return
|
||||
}
|
||||
const offsetX = e.offsetX
|
||||
|
||||
const baseTime = this.useChapterTrack ? this.currentChapterStart : 0
|
||||
|
|
@ -198,6 +204,7 @@ export default {
|
|||
setTrackWidth() {
|
||||
if (this.$refs.track) {
|
||||
this.trackWidth = this.$refs.track.clientWidth
|
||||
this.trackOffsetLeft = this.$refs.track.getBoundingClientRect().left
|
||||
} else {
|
||||
console.error('Track not loaded', this.$refs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,14 +164,15 @@ export default {
|
|||
beforeMount() {
|
||||
this.yearInReviewYear = new Date().getFullYear()
|
||||
|
||||
// When not December show previous year
|
||||
if (new Date().getMonth() < 11) {
|
||||
this.availableYears = this.getAvailableYears()
|
||||
const availableYearValues = this.availableYears.map((y) => y.value)
|
||||
|
||||
// When not December show previous year if data is available
|
||||
if (new Date().getMonth() < 11 && availableYearValues.includes(this.yearInReviewYear - 1)) {
|
||||
this.yearInReviewYear--
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.availableYears = this.getAvailableYears()
|
||||
|
||||
if (typeof navigator.share !== 'undefined' && navigator.share) {
|
||||
this.showShareButton = true
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@
|
|||
<span class="material-symbols text-2xl text-error">error_outline</span>
|
||||
</ui-tooltip>
|
||||
|
||||
<button aria-label="Download Backup" class="inline-flex material-symbols text-xl mx-1 mt-1 text-white/70 hover:text-white/100" @click.stop="downloadBackup(backup)">download</button>
|
||||
<button aria-label="Download backup" class="inline-flex material-symbols text-xl mx-1 mt-1 text-white/70 hover:text-white/100" @click.stop="downloadBackup(backup)">download</button>
|
||||
|
||||
<button aria-label="Delete Backup" class="inline-flex material-symbols text-xl mx-1 text-white/70 hover:text-error" @click.stop="deleteBackupClick(backup)">delete</button>
|
||||
<button aria-label="Delete backup" class="inline-flex material-symbols text-xl mx-1 text-white/70 hover:text-error" @click.stop="deleteBackupClick(backup)">delete</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue