Add:Feed podcast episodes select modal #225

This commit is contained in:
advplyr 2022-12-09 18:03:17 -06:00
parent 99217fee48
commit 64325fe2a6
2 changed files with 138 additions and 2 deletions

View file

@ -0,0 +1,92 @@
<template>
<modals-modal v-model="show" width="100%" height="100%" max-width="100%">
<template #outer>
<div class="absolute top-6 left-4 z-40">
<p class="text-white text-2xl truncate">Feed Episodes</p>
</div>
</template>
<div class="w-full h-full overflow-hidden absolute top-0 left-0 flex items-center justify-center" @click="show = false">
<div class="feed-content w-full overflow-x-hidden overflow-y-auto bg-bg rounded-lg border border-white border-opacity-20">
<template v-for="(episode, index) in episodes">
<div :key="index" class="relative" :class="index % 2 == 0 ? 'bg-primary bg-opacity-50' : 'bg-primary bg-opacity-25'">
<div class="absolute top-0 left-0 h-full flex items-center p-2">
<span v-if="itemEpisodeMap[episode.enclosure.url]" class="material-icons text-success text-xl">download_done</span>
<!-- <ui-checkbox v-else v-model="selectedEpisodes[String(index)]" small checkbox-bg="primary" border-color="gray-600" /> -->
</div>
<div class="px-2 py-2 border-b border-white border-opacity-10">
<p v-if="episode.episode" class="font-semibold text-gray-200 text-xs">#{{ episode.episode }}</p>
<p class="break-words mb-1 text-sm">{{ episode.title }}</p>
<p v-if="episode.subtitle" class="break-words mb-1 text-xs text-gray-300 episode-subtitle">{{ episode.subtitle }}</p>
<p class="text-xxs text-gray-300">Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }}</p>
</div>
</div>
</template>
</div>
<div class="absolute bottom-0 left-0 w-full flex items-center" style="height: 50px">
<ui-btn class="w-full" color="success">Download Episodes</ui-btn>
</div>
</div>
</modals-modal>
</template>
<script>
export default {
props: {
value: Boolean,
libraryItem: {
type: Object,
default: () => {}
},
episodes: {
type: Array,
default: () => []
}
},
data() {
return {}
},
watch: {
show: {
immediate: true,
handler(newVal) {
if (newVal) this.init()
}
}
},
computed: {
show: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
itemEpisodes() {
if (!this.libraryItem) return []
return this.libraryItem.media.episodes || []
},
itemEpisodeMap() {
var map = {}
this.itemEpisodes.forEach((item) => {
if (item.enclosure) map[item.enclosure.url] = true
})
return map
}
},
methods: {
init() {
this.episodes.sort((a, b) => (a.publishedAt < b.publishedAt ? 1 : -1))
}
},
mounted() {}
}
</script>
<style>
.feed-content {
height: calc(100vh - 125px);
max-height: calc(100vh - 125px);
margin-top: 20px;
}
</style>

View file

@ -2,7 +2,14 @@
<div class="w-full">
<div class="flex items-center">
<p class="text-lg mb-1 font-semibold">Episodes ({{ episodesFiltered.length }})</p>
<div class="flex-grow" />
<button v-if="isAdminOrUp && !fetchingRSSFeed" class="outline:none mx-1 pt-0.5 relative" @click="searchEpisodes">
<span class="material-icons text-xl text-gray-200">search</span>
</button>
<widgets-loading-spinner v-else-if="fetchingRSSFeed" class="mx-1" />
<button class="outline:none mx-3 pt-0.5 relative" @click="showFilters">
<span class="material-icons text-xl text-gray-200">filter_alt</span>
<div v-show="filterKey !== 'all' && episodesAreFiltered" class="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-success border border-green-300 shadow-sm z-10 pointer-events-none" />
@ -18,11 +25,13 @@
<tables-podcast-episode-row :episode="episode" :local-episode="localEpisodeMap[episode.id]" :library-item-id="libraryItemId" :local-library-item-id="localLibraryItemId" :is-local="isLocal" :key="episode.id" @addToPlaylist="addEpisodeToPlaylist" />
</template>
<!-- What in tarnation is going on here?
<!-- Huhhh?
Without anything below the template it will not re-render -->
<p>&nbsp;</p>
<modals-dialog v-model="showFiltersModal" title="Episode Filter" :items="filterItems" :selected="filterKey" @action="setFilter" />
<modals-podcast-episodes-feed-modal v-model="showPodcastEpisodeFeed" :library-item="libraryItem" :episodes="podcastFeedEpisodes" />
</div>
</template>
@ -86,7 +95,10 @@ export default {
text: 'Complete',
value: 'complete'
}
]
],
fetchingRSSFeed: false,
podcastFeedEpisodes: [],
showPodcastEpisodeFeed: false
}
},
watch: {
@ -98,9 +110,18 @@ export default {
}
},
computed: {
isAdminOrUp() {
return this.$store.getters['user/getIsAdminOrUp']
},
libraryItemId() {
return this.libraryItem ? this.libraryItem.id : null
},
media() {
return this.libraryItem ? this.libraryItem.media || {} : {}
},
mediaMetadata() {
return this.media.metadata || {}
},
episodesAreFiltered() {
return this.episodesFiltered.length !== this.episodesCopy.length
},
@ -146,6 +167,29 @@ export default {
}
},
methods: {
async searchEpisodes() {
if (!this.mediaMetadata.feedUrl) {
return this.$toast.error('Podcast does not have an RSS Feed')
}
this.fetchingRSSFeed = true
const payload = await this.$axios.$post(`/api/podcasts/feed`, { rssFeed: this.mediaMetadata.feedUrl }).catch((error) => {
console.error('Failed to get feed', error)
this.$toast.error('Failed to get podcast feed')
return null
})
this.fetchingRSSFeed = false
if (!payload) return
console.log('Podcast feed', payload)
const podcastfeed = payload.podcast
if (!podcastfeed.episodes || !podcastfeed.episodes.length) {
this.$toast.info('No episodes found in RSS feed')
return
}
this.podcastFeedEpisodes = podcastfeed.episodes
this.showPodcastEpisodeFeed = true
},
addEpisodeToPlaylist(episode) {
this.$store.commit('globals/setSelectedPlaylistItems', [{ libraryItem: this.libraryItem, episode }])
this.$store.commit('globals/setShowPlaylistsAddCreateModal', true)