mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-03 19:07:00 -05:00 
			
		
		
		
	* Add: episode edit dropdowns * Update: lazy episode table and row * Various string updates * Batch quick match strings * Author card strings * Update translation key for quick match episodes confirm --------- Co-authored-by: advplyr <advplyr@protonmail.com>
		
			
				
	
	
		
			193 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			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>
 |