mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-07-10 01:15:06 +02:00
Change new podcast modal to remove episode download list #494, Fix error when importing many episodes (set max size to 5MB) #493, show podcast episodes downloading and in queue on podcast landing page
This commit is contained in:
parent
ebc9e1a888
commit
034d858f18
14 changed files with 222 additions and 126 deletions
|
@ -89,9 +89,12 @@ export default {
|
|||
return this.$store.getters['libraries/getCurrentLibraryMediaType'] == 'podcast'
|
||||
},
|
||||
emptyMessage() {
|
||||
if (this.page === 'series') return `You have no series`
|
||||
if (this.page === 'series') return 'You have no series'
|
||||
if (this.page === 'collections') return "You haven't made any collections yet"
|
||||
if (this.hasFilter) return `No Results for filter "${this.filterName}: ${this.filterValue}"`
|
||||
if (this.hasFilter) {
|
||||
if (this.filterName === 'Issues') return 'No Issues'
|
||||
return `No Results for filter "${this.filterName}: ${this.filterValue}"`
|
||||
}
|
||||
return 'No results'
|
||||
},
|
||||
entityName() {
|
||||
|
|
|
@ -272,7 +272,7 @@ export default {
|
|||
return this.userProgress ? !!this.userProgress.isFinished : false
|
||||
},
|
||||
showError() {
|
||||
return this.hasMissingParts || this.hasInvalidParts || this.isMissing || this.isInvalid
|
||||
return this.numMissingParts || this.isMissing || this.isInvalid
|
||||
},
|
||||
isStreaming() {
|
||||
return this.store.getters['getlibraryItemIdStreaming'] === this.libraryItemId
|
||||
|
@ -292,22 +292,19 @@ export default {
|
|||
isInvalid() {
|
||||
return this._libraryItem.isInvalid
|
||||
},
|
||||
hasMissingParts() {
|
||||
return this._libraryItem.hasMissingParts
|
||||
},
|
||||
hasInvalidParts() {
|
||||
return this._libraryItem.hasInvalidParts
|
||||
numMissingParts() {
|
||||
if (this.isPodcast) return 0
|
||||
return this.media.numMissingParts
|
||||
},
|
||||
errorText() {
|
||||
if (this.isMissing) return 'Item directory is missing!'
|
||||
else if (this.isInvalid) return 'Item has no audio tracks & ebook'
|
||||
var txt = ''
|
||||
if (this.hasMissingParts) {
|
||||
txt = `${this.hasMissingParts} missing parts.`
|
||||
else if (this.isInvalid) {
|
||||
if (this.isPodcast) return 'Podcast has no episodes'
|
||||
return 'Item has no audio tracks & ebook'
|
||||
}
|
||||
if (this.hasInvalidParts) {
|
||||
if (this.hasMissingParts) txt += ' '
|
||||
txt += `${this.hasInvalidParts} invalid parts.`
|
||||
var txt = ''
|
||||
if (this.numMissingParts) {
|
||||
txt = `${this.numMissingParts} missing parts.`
|
||||
}
|
||||
return txt || 'Unknown Error'
|
||||
},
|
||||
|
|
|
@ -132,6 +132,11 @@ export default {
|
|||
text: 'Tag',
|
||||
value: 'tags',
|
||||
sublist: true
|
||||
},
|
||||
{
|
||||
text: 'Issues',
|
||||
value: 'issues',
|
||||
sublist: false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -166,26 +171,26 @@ export default {
|
|||
selectedText() {
|
||||
if (!this.selected) return ''
|
||||
var parts = this.selected.split('.')
|
||||
var filterName = this.selectItems.find((i) => i.value === parts[0]);
|
||||
var filterValue = null;
|
||||
var filterName = this.selectItems.find((i) => i.value === parts[0])
|
||||
var filterValue = null
|
||||
if (parts.length > 1) {
|
||||
var decoded = this.$decode(parts[1])
|
||||
if (decoded.startsWith('aut_')) {
|
||||
var author = this.authors.find((au) => au.id == decoded)
|
||||
if (author) filterValue = author.name;
|
||||
if (author) filterValue = author.name
|
||||
} else if (decoded.startsWith('ser_')) {
|
||||
var series = this.series.find((se) => se.id == decoded)
|
||||
if (series) filterValue = series.name
|
||||
} else {
|
||||
filterValue = decoded;
|
||||
filterValue = decoded
|
||||
}
|
||||
}
|
||||
if (filterName && filterValue) {
|
||||
return `${filterName.text}: ${filterValue}`;
|
||||
return `${filterName.text}: ${filterValue}`
|
||||
} else if (filterName) {
|
||||
return filterName.text;
|
||||
return filterName.text
|
||||
} else if (filterValue) {
|
||||
return filterValue;
|
||||
return filterValue
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
|
@ -212,7 +217,7 @@ export default {
|
|||
return ['Finished', 'In Progress', 'Not Started']
|
||||
},
|
||||
missing() {
|
||||
return ['ASIN', 'ISBN', 'Subtitle', 'Author', 'Publish Year', 'Series', 'Volume Number', 'Description', 'Genres', 'Tags', 'Narrator', 'Publisher', 'Language', ]
|
||||
return ['ASIN', 'ISBN', 'Subtitle', 'Author', 'Publish Year', 'Series', 'Volume Number', 'Description', 'Genres', 'Tags', 'Narrator', 'Publisher', 'Language']
|
||||
},
|
||||
sublistItems() {
|
||||
return (this[this.sublist] || []).map((item) => {
|
||||
|
|
|
@ -124,7 +124,13 @@ export default {
|
|||
episodesToDownload = this.episodesSelected.map((episodeIndex) => this.episodes[Number(episodeIndex)])
|
||||
}
|
||||
|
||||
console.log('Podcast payload', episodesToDownload)
|
||||
var payloadSize = JSON.stringify(episodesToDownload).length
|
||||
var sizeInMb = payloadSize / 1024 / 1024
|
||||
var sizeInMbPretty = sizeInMb.toFixed(2) + 'MB'
|
||||
console.log('Request size', sizeInMb)
|
||||
if (sizeInMb > 4.99) {
|
||||
return this.$toast.error(`Request is too large (${sizeInMbPretty}) should be < 5Mb`)
|
||||
}
|
||||
|
||||
this.processing = true
|
||||
this.$axios
|
||||
|
@ -144,7 +150,8 @@ export default {
|
|||
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
|
||||
if (episode.enclosure && !this.itemEpisodeMap[episode.enclosure.url]) {
|
||||
// Do not include episodes already downloaded
|
||||
this.$set(this.selectedEpisodes, String(i), false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,63 +1,42 @@
|
|||
<template>
|
||||
<modals-modal v-model="show" name="new-podcast-modal" :width="1200" :height="'unset'" :processing="processing">
|
||||
<modals-modal v-model="show" name="new-podcast-modal" :width="1000" :height="'unset'" :processing="processing">
|
||||
<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">{{ title }}</p>
|
||||
</div>
|
||||
</template>
|
||||
<div ref="wrapper" id="podcast-wrapper" class="p-4 w-full text-sm py-2 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden">
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-full md:w-1/2 p-4">
|
||||
<p class="text-lg font-semibold mb-2">Details</p>
|
||||
<div class="flex flex-wrap">
|
||||
<div v-if="podcast.imageUrl" class="p-1 w-full">
|
||||
<img :src="podcast.imageUrl" class="h-16 w-16 object-contain" />
|
||||
</div>
|
||||
<div class="p-1 w-full">
|
||||
<ui-text-input-with-label v-model="podcast.title" label="Title" @input="titleUpdated" />
|
||||
</div>
|
||||
<div class="p-1 w-full">
|
||||
<ui-text-input-with-label v-model="podcast.author" label="Author" />
|
||||
</div>
|
||||
<div class="p-1 w-full">
|
||||
<ui-text-input-with-label v-model="podcast.feedUrl" label="Feed URL" readonly />
|
||||
</div>
|
||||
<div class="p-1 w-full">
|
||||
<ui-multi-select v-model="podcast.genres" :items="podcast.genres" label="Genres" />
|
||||
</div>
|
||||
<div class="p-1 w-full">
|
||||
<ui-textarea-with-label v-model="podcast.description" label="Description" />
|
||||
</div>
|
||||
<div class="p-1 w-full">
|
||||
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="processing" label="Folder" @input="folderUpdated" />
|
||||
</div>
|
||||
<div class="p-1 w-full">
|
||||
<ui-text-input-with-label v-model="fullPath" label="Podcast Path" readonly />
|
||||
</div>
|
||||
<div class="w-full p-4">
|
||||
<p class="text-lg font-semibold mb-2">Details</p>
|
||||
|
||||
<div v-if="podcast.imageUrl" class="p-1 w-full">
|
||||
<img :src="podcast.imageUrl" class="h-16 w-16 object-contain" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-text-input-with-label v-model="podcast.title" label="Title" @input="titleUpdated" />
|
||||
</div>
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-text-input-with-label v-model="podcast.author" label="Author" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full md:w-1/2 p-4">
|
||||
<p class="text-lg font-semibold mb-2">Episodes</p>
|
||||
<div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto">
|
||||
<div class="relative">
|
||||
<div class="absolute top-0 left-0 h-full flex items-center p-2">
|
||||
<ui-checkbox v-model="selectAll" small checkbox-bg="primary" border-color="gray-600" />
|
||||
</div>
|
||||
<div class="px-8 py-2">
|
||||
<p class="font-semibold text-gray-200">Select all episodes</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(episode, index) in episodes" :key="index" class="relative cursor-pointer" :class="selectedEpisodes[String(index)] ? 'bg-success bg-opacity-10' : index % 2 == 0 ? 'bg-primary bg-opacity-25 hover:bg-opacity-40' : 'bg-primary bg-opacity-5 hover:bg-opacity-25'" @click="toggleSelectEpisode(index)">
|
||||
<div class="absolute top-0 left-0 h-full flex items-center p-2">
|
||||
<ui-checkbox v-model="selectedEpisodes[String(index)]" small checkbox-bg="primary" border-color="gray-600" />
|
||||
</div>
|
||||
<div class="px-8 py-2">
|
||||
<p v-if="episode.episode" class="font-semibold text-gray-200">#{{ episode.episode }}</p>
|
||||
<p class="break-words mb-1">{{ episode.title }}</p>
|
||||
<p v-if="episode.subtitle" class="break-words mb-1 text-sm text-gray-300 episode-subtitle">{{ episode.subtitle }}</p>
|
||||
<p class="text-xs text-gray-300">Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-text-input-with-label v-model="podcast.feedUrl" label="Feed URL" readonly />
|
||||
</div>
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-multi-select v-model="podcast.genres" :items="podcast.genres" label="Genres" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2 w-full">
|
||||
<ui-textarea-with-label v-model="podcast.description" label="Description" :rows="3" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="processing" label="Folder" @input="folderUpdated" />
|
||||
</div>
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-text-input-with-label v-model="fullPath" label="Podcast Path" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -66,7 +45,7 @@
|
|||
<div class="px-4">
|
||||
<ui-checkbox v-model="podcast.autoDownloadEpisodes" label="Auto Download Episodes" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" />
|
||||
</div>
|
||||
<ui-btn color="success" :disabled="disableSubmit" @click="submit">{{ buttonText }}</ui-btn>
|
||||
<ui-btn color="success" @click="submit">Add Podcast</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</modals-modal>
|
||||
|
@ -104,8 +83,7 @@ export default {
|
|||
itunesId: '',
|
||||
itunesArtistId: '',
|
||||
autoDownloadEpisodes: false
|
||||
},
|
||||
selectedEpisodes: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -127,16 +105,6 @@ export default {
|
|||
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() {
|
||||
return this._podcastData.title
|
||||
},
|
||||
|
@ -166,17 +134,6 @@ export default {
|
|||
if (!this.podcastFeedData) return []
|
||||
return this.podcastFeedData.episodes || []
|
||||
},
|
||||
episodesSelected() {
|
||||
return Object.keys(this.selectedEpisodes).filter((key) => !!this.selectedEpisodes[key])
|
||||
},
|
||||
disableSubmit() {
|
||||
return !this.episodesSelected.length && !this.podcast.autoDownloadEpisodes
|
||||
},
|
||||
buttonText() {
|
||||
if (!this.episodesSelected.length) return 'Add Podcast'
|
||||
if (this.episodesSelected.length == 1) return 'Add Podcast & Download 1 Episode'
|
||||
return `Add Podcast & Download ${this.episodesSelected.length} Episodes`
|
||||
},
|
||||
selectedFolder() {
|
||||
return this.folders.find((f) => f.id === this.selectedFolderId)
|
||||
},
|
||||
|
@ -196,15 +153,7 @@ export default {
|
|||
}
|
||||
this.fullPath = Path.join(this.selectedFolderPath, this.podcast.title)
|
||||
},
|
||||
toggleSelectEpisode(index) {
|
||||
this.selectedEpisodes[String(index)] = !this.selectedEpisodes[String(index)]
|
||||
},
|
||||
submit() {
|
||||
var episodesToDownload = []
|
||||
if (this.episodesSelected.length) {
|
||||
episodesToDownload = this.episodesSelected.map((episodeIndex) => this.episodes[Number(episodeIndex)])
|
||||
}
|
||||
|
||||
const podcastPayload = {
|
||||
path: this.fullPath,
|
||||
folderId: this.selectedFolderId,
|
||||
|
@ -224,8 +173,7 @@ export default {
|
|||
language: this.podcast.language
|
||||
},
|
||||
autoDownloadEpisodes: this.podcast.autoDownloadEpisodes
|
||||
},
|
||||
episodesToDownload
|
||||
}
|
||||
}
|
||||
console.log('Podcast payload', podcastPayload)
|
||||
|
||||
|
@ -260,10 +208,6 @@ export default {
|
|||
this.podcast.language = this._podcastData.language || ''
|
||||
this.podcast.autoDownloadEpisodes = false
|
||||
|
||||
for (let i = 0; i < this.episodes.length; i++) {
|
||||
this.$set(this.selectedEpisodes, String(i), false)
|
||||
}
|
||||
|
||||
if (this.folderItems[0]) {
|
||||
this.selectedFolderId = this.folderItems[0].value
|
||||
this.folderUpdated()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue