mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			156 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div style="min-height: 200px">
 | |
|     <template v-if="!podcastFeedUrl">
 | |
|       <div class="py-8">
 | |
|         <widgets-alert type="error">{{ $strings.MessagePodcastHasNoRSSFeedForMatching }}</widgets-alert>
 | |
|       </div>
 | |
|     </template>
 | |
|     <template v-else>
 | |
|       <form @submit.prevent="submitForm">
 | |
|         <div class="flex mb-2">
 | |
|           <ui-text-input-with-label v-model="episodeTitle" :disabled="isProcessing" :label="$strings.LabelEpisodeTitle" class="pr-1" />
 | |
|           <ui-btn class="mt-5 ml-1" :loading="isProcessing" type="submit">{{ $strings.ButtonSearch }}</ui-btn>
 | |
|         </div>
 | |
|       </form>
 | |
|       <div v-if="!isProcessing && searchedTitle && !episodesFound.length" class="w-full py-8">
 | |
|         <p class="text-center text-lg">{{ $strings.MessageNoEpisodeMatchesFound }}</p>
 | |
|       </div>
 | |
|       <div v-for="(episode, index) in episodesFound" :key="index" class="w-full py-4 border-b border-white border-opacity-5 hover:bg-gray-300 hover:bg-opacity-10 cursor-pointer px-2" @click.stop="selectEpisode(episode)">
 | |
|         <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-400">Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }}</p>
 | |
|       </div>
 | |
|     </template>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| export default {
 | |
|   props: {
 | |
|     processing: Boolean,
 | |
|     libraryItem: {
 | |
|       type: Object,
 | |
|       default: () => {}
 | |
|     },
 | |
|     episode: {
 | |
|       type: Object,
 | |
|       default: () => {}
 | |
|     }
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       episodeTitle: '',
 | |
|       searchedTitle: '',
 | |
|       episodesFound: []
 | |
|     }
 | |
|   },
 | |
|   watch: {
 | |
|     episode: {
 | |
|       immediate: true,
 | |
|       handler(newVal) {
 | |
|         if (newVal) this.init()
 | |
|       }
 | |
|     }
 | |
|   },
 | |
|   computed: {
 | |
|     isProcessing: {
 | |
|       get() {
 | |
|         return this.processing
 | |
|       },
 | |
|       set(val) {
 | |
|         this.$emit('update:processing', val)
 | |
|       }
 | |
|     },
 | |
|     episodeId() {
 | |
|       return this.episode ? this.episode.id : null
 | |
|     },
 | |
|     media() {
 | |
|       return this.libraryItem ? this.libraryItem.media || {} : {}
 | |
|     },
 | |
|     mediaMetadata() {
 | |
|       return this.media.metadata || {}
 | |
|     },
 | |
|     podcastFeedUrl() {
 | |
|       return this.mediaMetadata.feedUrl
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     getUpdatePayload(episodeData) {
 | |
|       var updatePayload = {}
 | |
|       for (const key in episodeData) {
 | |
|         if (key === 'enclosure') {
 | |
|           if (!this.episode.enclosure || JSON.stringify(this.episode.enclosure) !== JSON.stringify(episodeData.enclosure)) {
 | |
|             updatePayload[key] = {
 | |
|               ...episodeData.enclosure
 | |
|             }
 | |
|           }
 | |
|         } else if (episodeData[key] != this.episode[key]) {
 | |
|           updatePayload[key] = episodeData[key]
 | |
|         }
 | |
|       }
 | |
|       return updatePayload
 | |
|     },
 | |
|     selectEpisode(episode) {
 | |
|       const episodeData = {
 | |
|         title: episode.title || '',
 | |
|         subtitle: episode.subtitle || '',
 | |
|         description: episode.description || '',
 | |
|         enclosure: episode.enclosure || null,
 | |
|         episode: episode.episode || '',
 | |
|         episodeType: episode.episodeType || '',
 | |
|         season: episode.season || '',
 | |
|         pubDate: episode.pubDate || '',
 | |
|         publishedAt: episode.publishedAt
 | |
|       }
 | |
|       const updatePayload = this.getUpdatePayload(episodeData)
 | |
|       if (!Object.keys(updatePayload).length) {
 | |
|         return this.$toast.info('No updates are necessary')
 | |
|       }
 | |
|       console.log('Episode update payload', updatePayload)
 | |
| 
 | |
|       this.isProcessing = true
 | |
|       this.$axios
 | |
|         .$patch(`/api/podcasts/${this.libraryItem.id}/episode/${this.episodeId}`, updatePayload)
 | |
|         .then(() => {
 | |
|           this.isProcessing = false
 | |
|           this.$toast.success('Podcast episode updated')
 | |
|           this.$emit('selectTab', 'details')
 | |
|         })
 | |
|         .catch((error) => {
 | |
|           var errorMsg = error.response && error.response.data ? error.response.data : 'Failed to update episode'
 | |
|           console.error('Failed update episode', error)
 | |
|           this.isProcessing = false
 | |
|           this.$toast.error(errorMsg)
 | |
|         })
 | |
|     },
 | |
|     submitForm() {
 | |
|       if (!this.episodeTitle || !this.episodeTitle.length) {
 | |
|         this.$toast.error('Must enter an episode title')
 | |
|         return
 | |
|       }
 | |
|       this.searchedTitle = this.episodeTitle
 | |
|       this.isProcessing = true
 | |
|       this.$axios
 | |
|         .$get(`/api/podcasts/${this.libraryItem.id}/search-episode?title=${this.$encodeUriPath(this.episodeTitle)}`)
 | |
|         .then((results) => {
 | |
|           this.episodesFound = results.episodes.map((ep) => ep.episode)
 | |
|           console.log('Episodes found', this.episodesFound)
 | |
|           this.isProcessing = false
 | |
|         })
 | |
|         .catch((error) => {
 | |
|           console.error('Failed to search for episode', error)
 | |
|           var errMsg = error.response ? error.response.data || '' : ''
 | |
|           this.$toast.error(errMsg || 'Failed to search for episode')
 | |
|           this.isProcessing = false
 | |
|         })
 | |
|     },
 | |
|     init() {
 | |
|       this.searchedTitle = null
 | |
|       this.episodesFound = []
 | |
|       this.episodeTitle = this.episode ? this.episode.title || '' : ''
 | |
|     }
 | |
|   },
 | |
|   mounted() {}
 | |
| }
 | |
| </script> |