audiobookshelf/client/components/modals/item/tabs/Schedule.vue

193 lines
6.8 KiB
Vue

<template>
<div class="w-full h-full relative">
<div id="scheduleWrapper" class="w-full overflow-y-auto px-2 py-4 md:px-6 md:py-6">
<template v-if="!feedUrl">
<widgets-alert type="warning" class="text-base mb-4">{{ $strings.ToastPodcastNoRssFeed }}</widgets-alert>
</template>
<template v-if="feedUrl || autoDownloadEpisodes">
<div class="flex items-center justify-between mb-4">
<p class="text-base md:text-xl font-semibold">{{ $strings.HeaderScheduleEpisodeDownloads }}</p>
<ui-checkbox v-model="enableAutoDownloadEpisodes" :label="$strings.LabelEnable" medium checkbox-bg="bg" label-class="pl-2 text-base md:text-lg" />
</div>
<div v-if="enableAutoDownloadEpisodes" class="flex items-center py-2">
<ui-text-input ref="maxEpisodesInput" type="number" v-model="newMaxEpisodesToKeep" no-spinner :padding-x="1" text-center class="w-10 text-base" @change="updatedMaxEpisodesToKeep" />
<ui-tooltip :text="$strings.LabelMaxEpisodesToKeepHelp">
<p class="pl-4 text-base">
{{ $strings.LabelMaxEpisodesToKeep }}
<span class="material-symbols icon-text">info</span>
</p>
</ui-tooltip>
</div>
<div v-if="enableAutoDownloadEpisodes" class="flex items-center py-2">
<ui-text-input ref="maxEpisodesToDownloadInput" type="number" v-model="newMaxNewEpisodesToDownload" no-spinner :padding-x="1" text-center class="w-10 text-base" @change="updateMaxNewEpisodesToDownload" />
<ui-tooltip :text="$strings.LabelUseZeroForUnlimited">
<p class="pl-4 text-base">
{{ $strings.LabelMaxEpisodesToDownloadPerCheck }}
<span class="material-symbols icon-text">info</span>
</p>
</ui-tooltip>
</div>
<widgets-cron-expression-builder ref="cronExpressionBuilder" v-if="enableAutoDownloadEpisodes" v-model="cronExpression" />
</template>
</div>
<div v-if="feedUrl || autoDownloadEpisodes" class="absolute bottom-0 left-0 w-full py-2 md:py-4 bg-bg border-t border-white border-opacity-5">
<div class="flex items-center px-2 md:px-4">
<div class="flex-grow" />
<ui-btn @click="save" :disabled="!isUpdated" :color="isUpdated ? 'success' : 'primary'" class="mx-2">{{ isUpdated ? $strings.ButtonSave : $strings.MessageNoUpdatesWereNecessary }}</ui-btn>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
processing: Boolean,
libraryItem: {
type: Object,
default: () => {}
}
},
data() {
return {
enableAutoDownloadEpisodes: false,
cronExpression: null,
newMaxEpisodesToKeep: 0,
newMaxNewEpisodesToDownload: 0
}
},
watch: {
libraryItem: {
immediate: true,
handler(newVal) {
if (newVal) this.init()
}
}
},
computed: {
isProcessing: {
get() {
return this.processing
},
set(val) {
this.$emit('update:processing', val)
}
},
userIsAdminOrUp() {
return this.$store.getters['user/getIsAdminOrUp']
},
media() {
return this.libraryItem ? this.libraryItem.media || {} : {}
},
mediaMetadata() {
return this.media.metadata || {}
},
libraryItemId() {
return this.libraryItem ? this.libraryItem.id : null
},
feedUrl() {
return this.mediaMetadata.feedUrl
},
autoDownloadEpisodes() {
return !!this.media.autoDownloadEpisodes
},
autoDownloadSchedule() {
return this.media.autoDownloadSchedule
},
maxEpisodesToKeep() {
return this.media.maxEpisodesToKeep
},
maxNewEpisodesToDownload() {
return this.media.maxNewEpisodesToDownload
},
isUpdated() {
return this.autoDownloadSchedule !== this.cronExpression || this.autoDownloadEpisodes !== this.enableAutoDownloadEpisodes || this.maxEpisodesToKeep !== Number(this.newMaxEpisodesToKeep) || this.maxNewEpisodesToDownload !== Number(this.newMaxNewEpisodesToDownload)
}
},
methods: {
updatedMaxEpisodesToKeep() {
if (isNaN(this.newMaxEpisodesToKeep) || this.newMaxEpisodesToKeep < 0) {
this.newMaxEpisodesToKeep = 0
} else {
this.newMaxEpisodesToKeep = Number(this.newMaxEpisodesToKeep)
}
},
updateMaxNewEpisodesToDownload() {
if (isNaN(this.newMaxNewEpisodesToDownload) || this.newMaxNewEpisodesToDownload < 0) {
this.newMaxNewEpisodesToDownload = 0
} else {
this.newMaxNewEpisodesToDownload = Number(this.newMaxNewEpisodesToDownload)
}
},
save() {
// If custom expression input is focused then unfocus it instead of submitting
if (this.$refs.cronExpressionBuilder && this.$refs.cronExpressionBuilder.checkBlurExpressionInput) {
if (this.$refs.cronExpressionBuilder.checkBlurExpressionInput()) {
return
}
}
if (this.$refs.maxEpisodesInput?.isFocused) {
this.$refs.maxEpisodesInput.blur()
}
if (this.$refs.maxEpisodesToDownloadInput?.isFocused) {
this.$refs.maxEpisodesToDownloadInput.blur()
}
const updatePayload = {
autoDownloadEpisodes: this.enableAutoDownloadEpisodes
}
if (this.enableAutoDownloadEpisodes) {
updatePayload.autoDownloadSchedule = this.cronExpression
}
this.newMaxEpisodesToKeep = Number(this.newMaxEpisodesToKeep)
if (this.newMaxEpisodesToKeep !== this.maxEpisodesToKeep) {
updatePayload.maxEpisodesToKeep = this.newMaxEpisodesToKeep
}
this.newMaxNewEpisodesToDownload = Number(this.newMaxNewEpisodesToDownload)
if (this.newMaxNewEpisodesToDownload !== this.maxNewEpisodesToDownload) {
updatePayload.maxNewEpisodesToDownload = this.newMaxNewEpisodesToDownload
}
this.updateDetails(updatePayload)
},
async updateDetails(updatePayload) {
this.isProcessing = true
var updateResult = await this.$axios.$patch(`/api/items/${this.libraryItemId}/media`, updatePayload).catch((error) => {
console.error('Failed to update', error)
return false
})
this.isProcessing = false
if (updateResult) {
if (updateResult.updated) {
this.$toast.success(this.$strings.ToastItemDetailsUpdateSuccess)
return true
} else {
this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary)
}
}
return false
},
init() {
this.enableAutoDownloadEpisodes = this.autoDownloadEpisodes
this.cronExpression = this.autoDownloadSchedule
this.newMaxEpisodesToKeep = this.maxEpisodesToKeep
this.newMaxNewEpisodesToDownload = this.maxNewEpisodesToDownload
}
},
mounted() {
this.init()
}
}
</script>
<style scoped>
#scheduleWrapper {
height: calc(100% - 80px);
max-height: calc(100% - 80px);
}
</style>