mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-17 11:29:12 +01:00
Add published at to podcast episode row #428, Fix podcast select episodes, fix save order of podcast episode, fix remove podcast episode
This commit is contained in:
parent
c60807f998
commit
23cc6bb210
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full overflow-y-auto overflow-x-hidden px-4 py-6">
|
<div class="w-full h-full overflow-y-auto overflow-x-hidden px-4 py-6">
|
||||||
<div class="w-full mb-4">
|
<div class="w-full mb-4">
|
||||||
<div class="w-full p-4 bg-primary">
|
<div v-if="chapters.length" class="w-full p-4 bg-primary">
|
||||||
<p>Audiobook Chapters</p>
|
<p>Audiobook Chapters</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!chapters.length" class="flex my-4 text-center justify-center text-xl">No Chapters</div>
|
<div v-if="!chapters.length" class="flex my-4 text-center justify-center text-xl">No Chapters</div>
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<div class="flex justify-end pt-4">
|
<div class="flex justify-end pt-4">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<div class="absolute top-0 left-0 h-full flex items-center p-2">
|
<div class="absolute top-0 left-0 h-full flex items-center p-2">
|
||||||
<ui-checkbox small checkbox-bg="primary" border-color="gray-600" v-on:input="selectedEpisodes = episodes.map(episode => episode.enclosure && itemEpisodeMap[episode.enclosure.url] ? false : !allSelected)" v-bind:value="allSelected" v-bind:disabled="allDownloaded" />
|
<ui-checkbox v-model="selectAll" small checkbox-bg="primary" border-color="gray-600" :disabled="allDownloaded" />
|
||||||
</div>
|
</div>
|
||||||
<div class="px-8 py-2">
|
<div class="px-8 py-2">
|
||||||
<p :class="!allDownloaded ? 'font-semibold text-gray-200' : 'text-gray-400'">Select all episodes</p>
|
<p :class="!allDownloaded ? 'font-semibold text-gray-200' : 'text-gray-400'">Select all episodes</p>
|
||||||
@ -62,6 +62,14 @@ export default {
|
|||||||
selectedEpisodes: {}
|
selectedEpisodes: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
show: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal) this.init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
show: {
|
show: {
|
||||||
get() {
|
get() {
|
||||||
@ -71,23 +79,22 @@ export default {
|
|||||||
this.$emit('input', val)
|
this.$emit('input', val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
selectAll: {
|
||||||
|
get() {
|
||||||
|
return this.episodesSelected.length == this.episodes.length
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
for (const key in this.selectedEpisodes) {
|
||||||
|
this.selectedEpisodes[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
title() {
|
title() {
|
||||||
if (!this.libraryItem) return ''
|
if (!this.libraryItem) return ''
|
||||||
return this.libraryItem.media.metadata.title || 'Unknown'
|
return this.libraryItem.media.metadata.title || 'Unknown'
|
||||||
},
|
},
|
||||||
allSelected() {
|
|
||||||
try {
|
|
||||||
const values = Object.values(this.selectedEpisodes).filter((_, index) => !(this.episodes[index].enclosure && this.itemEpisodeMap[this.episodes[index].enclosure.url]))
|
|
||||||
|
|
||||||
if(!values.length) return false
|
|
||||||
return values.filter(episode => !episode).length === 0
|
|
||||||
} catch(error) {
|
|
||||||
console.error("Error while filtering selected episodes", error);
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
allDownloaded() {
|
allDownloaded() {
|
||||||
return Object.values(this.episodes).filter(episode => !(episode.enclosure && this.itemEpisodeMap[episode.enclosure.url])).length === 0
|
return Object.values(this.episodes).filter((episode) => !(episode.enclosure && this.itemEpisodeMap[episode.enclosure.url])).length === 0
|
||||||
},
|
},
|
||||||
episodesSelected() {
|
episodesSelected() {
|
||||||
return Object.keys(this.selectedEpisodes).filter((key) => !!this.selectedEpisodes[key])
|
return Object.keys(this.selectedEpisodes).filter((key) => !!this.selectedEpisodes[key])
|
||||||
@ -134,6 +141,14 @@ export default {
|
|||||||
this.processing = false
|
this.processing = false
|
||||||
this.$toast.error(errorMsg)
|
this.$toast.error(errorMsg)
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
for (let i = 0; i < this.episodes.length; i++) {
|
||||||
|
var episode = this.episodes[i]
|
||||||
|
if (episode.enclosure && !this.itemEpisodeMap[episode.enclosure.url]) { // Do not include episodes already downloaded
|
||||||
|
this.$set(this.selectedEpisodes, String(i), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {}
|
mounted() {}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto">
|
<div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<div class="absolute top-0 left-0 h-full flex items-center p-2">
|
<div class="absolute top-0 left-0 h-full flex items-center p-2">
|
||||||
<ui-checkbox small checkbox-bg="primary" border-color="gray-600" v-on:input="selectedEpisodes = episodes.map(_ => !allSelected)" v-bind:value="allSelected" />
|
<ui-checkbox v-model="selectAll" small checkbox-bg="primary" border-color="gray-600" />
|
||||||
</div>
|
</div>
|
||||||
<div class="px-8 py-2">
|
<div class="px-8 py-2">
|
||||||
<p class="font-semibold text-gray-200">Select all episodes</p>
|
<p class="font-semibold text-gray-200">Select all episodes</p>
|
||||||
@ -128,6 +128,16 @@ export default {
|
|||||||
this.$emit('input', val)
|
this.$emit('input', val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
selectAll: {
|
||||||
|
get() {
|
||||||
|
return this.episodesSelected.length == this.episodes.length
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
for (const key in this.selectedEpisodes) {
|
||||||
|
this.selectedEpisodes[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
title() {
|
title() {
|
||||||
return this._podcastData.title
|
return this._podcastData.title
|
||||||
},
|
},
|
||||||
@ -157,9 +167,6 @@ export default {
|
|||||||
if (!this.podcastFeedData) return []
|
if (!this.podcastFeedData) return []
|
||||||
return this.podcastFeedData.episodes || []
|
return this.podcastFeedData.episodes || []
|
||||||
},
|
},
|
||||||
allSelected() {
|
|
||||||
return Object.values(this.selectedEpisodes).filter(episode => !episode).length === 0
|
|
||||||
},
|
|
||||||
episodesSelected() {
|
episodesSelected() {
|
||||||
return Object.keys(this.selectedEpisodes).filter((key) => !!this.selectedEpisodes[key])
|
return Object.keys(this.selectedEpisodes).filter((key) => !!this.selectedEpisodes[key])
|
||||||
},
|
},
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
<ui-tooltip :text="userIsFinished ? 'Mark as Not Finished' : 'Mark as Finished'" direction="top">
|
<ui-tooltip :text="userIsFinished ? 'Mark as Not Finished' : 'Mark as Finished'" direction="top">
|
||||||
<ui-read-icon-btn :disabled="isProcessingReadUpdate" :is-read="userIsFinished" borderless class="mx-1 mt-0.5" @click="toggleFinished" />
|
<ui-read-icon-btn :disabled="isProcessingReadUpdate" :is-read="userIsFinished" borderless class="mx-1 mt-0.5" @click="toggleFinished" />
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
|
|
||||||
|
<p v-if="publishedAt" class="px-4 text-sm text-gray-300">Published {{ $formatDate(publishedAt, 'MMM do, yyyy') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-24 min-w-24" />
|
<div class="w-24 min-w-24" />
|
||||||
@ -103,6 +105,9 @@ export default {
|
|||||||
if (this.userIsFinished) return 'Finished'
|
if (this.userIsFinished) return 'Finished'
|
||||||
var remaining = Math.floor(this.itemProgress.duration - this.itemProgress.currentTime)
|
var remaining = Math.floor(this.itemProgress.duration - this.itemProgress.currentTime)
|
||||||
return `${this.$elapsedPretty(remaining)} left`
|
return `${this.$elapsedPretty(remaining)} left`
|
||||||
|
},
|
||||||
|
publishedAt() {
|
||||||
|
return this.episode.publishedAt
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -144,6 +149,7 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
removeClick() {
|
removeClick() {
|
||||||
|
if (confirm(`Are you sure you want to remove episode ${this.title}?\nNote: Does not delete from file system`)) {
|
||||||
this.processingRemove = true
|
this.processingRemove = true
|
||||||
|
|
||||||
this.$axios
|
this.$axios
|
||||||
@ -159,6 +165,7 @@ export default {
|
|||||||
this.processingRemove = false
|
this.processingRemove = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mounted() {}
|
mounted() {}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ class LibraryItemController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PATCH: api/items/:id/episodes
|
// PATCH: api/items/:id/episodes
|
||||||
async updateEpisodes(req, res) {
|
async updateEpisodes(req, res) { // For updating podcast episode order
|
||||||
var libraryItem = req.libraryItem
|
var libraryItem = req.libraryItem
|
||||||
var orderedFileData = req.body.episodes
|
var orderedFileData = req.body.episodes
|
||||||
if (!libraryItem.media.setEpisodeOrder) {
|
if (!libraryItem.media.setEpisodeOrder) {
|
||||||
@ -227,7 +227,7 @@ class LibraryItemController {
|
|||||||
async removeEpisode(req, res) {
|
async removeEpisode(req, res) {
|
||||||
var episodeId = req.params.episodeId
|
var episodeId = req.params.episodeId
|
||||||
var libraryItem = req.libraryItem
|
var libraryItem = req.libraryItem
|
||||||
if (!libraryItem.mediaType !== 'podcast') {
|
if (libraryItem.mediaType !== 'podcast') {
|
||||||
Logger.error(`[LibraryItemController] removeEpisode invalid media type ${libraryItem.id}`)
|
Logger.error(`[LibraryItemController] removeEpisode invalid media type ${libraryItem.id}`)
|
||||||
return res.sendStatus(500)
|
return res.sendStatus(500)
|
||||||
}
|
}
|
||||||
|
@ -198,6 +198,7 @@ class Podcast {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setEpisodeOrder(episodeIds) {
|
setEpisodeOrder(episodeIds) {
|
||||||
|
episodeIds.reverse() // episode Ids will already be in descending order
|
||||||
this.episodes = this.episodes.map(ep => {
|
this.episodes = this.episodes.map(ep => {
|
||||||
var indexOf = episodeIds.findIndex(id => id === ep.id)
|
var indexOf = episodeIds.findIndex(id => id === ep.id)
|
||||||
ep.index = indexOf + 1
|
ep.index = indexOf + 1
|
||||||
|
Loading…
Reference in New Issue
Block a user