Show download icon for queued/downloaded episodes in rss feed modal

This commit is contained in:
advplyr 2025-02-26 17:56:17 -06:00
parent 6674189acd
commit 0ca65d1f79
3 changed files with 64 additions and 19 deletions

View File

@ -16,11 +16,12 @@
v-for="(episode, index) in episodesList" v-for="(episode, index) in episodesList"
:key="index" :key="index"
class="relative" class="relative"
:class="getIsEpisodeDownloaded(episode) ? 'bg-primary bg-opacity-40' : selectedEpisodes[episode.cleanUrl] ? 'cursor-pointer bg-success bg-opacity-10' : index % 2 == 0 ? 'cursor-pointer bg-primary bg-opacity-25 hover:bg-opacity-40' : 'cursor-pointer bg-primary bg-opacity-5 hover:bg-opacity-25'" :class="episode.isDownloaded || episode.isDownloading ? 'bg-primary bg-opacity-40' : selectedEpisodes[episode.cleanUrl] ? 'cursor-pointer bg-success bg-opacity-10' : index % 2 == 0 ? 'cursor-pointer bg-primary bg-opacity-25 hover:bg-opacity-40' : 'cursor-pointer bg-primary bg-opacity-5 hover:bg-opacity-25'"
@click="toggleSelectEpisode(episode)" @click="toggleSelectEpisode(episode)"
> >
<div class="absolute top-0 left-0 h-full flex items-center p-2"> <div class="absolute top-0 left-0 h-full flex items-center p-2">
<span v-if="getIsEpisodeDownloaded(episode)" class="material-symbols text-success text-xl">download_done</span> <span v-if="episode.isDownloaded" class="material-symbols text-success text-xl">download_done</span>
<span v-else-if="episode.isDownloading" class="material-symbols text-warning text-xl">download</span>
<ui-checkbox v-else v-model="selectedEpisodes[episode.cleanUrl]" small checkbox-bg="primary" border-color="gray-600" /> <ui-checkbox v-else v-model="selectedEpisodes[episode.cleanUrl]" small checkbox-bg="primary" border-color="gray-600" />
</div> </div>
<div class="px-8 py-2"> <div class="px-8 py-2">
@ -58,6 +59,14 @@ export default {
episodes: { episodes: {
type: Array, type: Array,
default: () => [] default: () => []
},
downloadQueue: {
type: Array,
default: () => []
},
episodesDownloading: {
type: Array,
default: () => []
} }
}, },
data() { data() {
@ -79,6 +88,21 @@ export default {
handler(newVal) { handler(newVal) {
if (newVal) this.init() if (newVal) this.init()
} }
},
episodes: {
handler(newVal) {
if (newVal) this.updateEpisodeDownloadStatuses()
}
},
episodesDownloading: {
handler(newVal) {
if (newVal) this.updateEpisodeDownloadStatuses()
}
},
downloadQueue: {
handler(newVal) {
if (newVal) this.updateEpisodeDownloadStatuses()
}
} }
}, },
computed: { computed: {
@ -132,6 +156,13 @@ export default {
} }
return false return false
}, },
getIsEpisodeDownloadingOrQueued(episode) {
const episodesToCheck = [...this.episodesDownloading, ...this.downloadQueue]
if (episode.guid) {
return episodesToCheck.some((download) => download.guid === episode.guid)
}
return episodesToCheck.some((download) => this.getCleanEpisodeUrl(download.url) === episode.cleanUrl)
},
/** /**
* UPDATE: As of v2.4.5 guid is used for matching existing downloaded episodes if it is found on the RSS feed. * UPDATE: As of v2.4.5 guid is used for matching existing downloaded episodes if it is found on the RSS feed.
* Fallback to checking the clean url * Fallback to checking the clean url
@ -187,7 +218,7 @@ export default {
this.selectAll = true this.selectAll = true
}, },
toggleSelectEpisode(episode) { toggleSelectEpisode(episode) {
if (this.getIsEpisodeDownloaded(episode)) return if (episode.isDownloaded || episode.isDownloading) return
this.$set(this.selectedEpisodes, episode.cleanUrl, !this.selectedEpisodes[episode.cleanUrl]) this.$set(this.selectedEpisodes, episode.cleanUrl, !this.selectedEpisodes[episode.cleanUrl])
this.checkSetIsSelectedAll() this.checkSetIsSelectedAll()
}, },
@ -223,6 +254,23 @@ export default {
}) })
}, },
init() { init() {
this.updateDownloadedEpisodeMaps()
this.episodesCleaned = this.episodes
.filter((ep) => ep.enclosure?.url)
.map((_ep) => {
return {
..._ep,
cleanUrl: this.getCleanEpisodeUrl(_ep.enclosure.url),
isDownloading: this.getIsEpisodeDownloadingOrQueued(_ep),
isDownloaded: this.getIsEpisodeDownloaded(_ep)
}
})
this.episodesCleaned.sort((a, b) => (a.publishedAt < b.publishedAt ? 1 : -1))
this.selectAll = false
this.selectedEpisodes = {}
},
updateDownloadedEpisodeMaps() {
this.downloadedEpisodeGuidMap = {} this.downloadedEpisodeGuidMap = {}
this.downloadedEpisodeUrlMap = {} this.downloadedEpisodeUrlMap = {}
@ -230,18 +278,16 @@ export default {
if (episode.guid) this.downloadedEpisodeGuidMap[episode.guid] = episode.id if (episode.guid) this.downloadedEpisodeGuidMap[episode.guid] = episode.id
if (episode.enclosure?.url) this.downloadedEpisodeUrlMap[this.getCleanEpisodeUrl(episode.enclosure.url)] = episode.id if (episode.enclosure?.url) this.downloadedEpisodeUrlMap[this.getCleanEpisodeUrl(episode.enclosure.url)] = episode.id
}) })
},
this.episodesCleaned = this.episodes updateEpisodeDownloadStatuses() {
.filter((ep) => ep.enclosure?.url) this.updateDownloadedEpisodeMaps()
.map((_ep) => { this.episodesCleaned = this.episodesCleaned.map((ep) => {
return { return {
..._ep, ...ep,
cleanUrl: this.getCleanEpisodeUrl(_ep.enclosure.url) isDownloading: this.getIsEpisodeDownloadingOrQueued(ep),
} isDownloaded: this.getIsEpisodeDownloaded(ep)
}) }
this.episodesCleaned.sort((a, b) => (a.publishedAt < b.publishedAt ? 1 : -1)) })
this.selectAll = false
this.selectedEpisodes = {}
} }
}, },
mounted() {} mounted() {}

View File

@ -141,7 +141,7 @@
</div> </div>
</div> </div>
<modals-podcast-episode-feed v-model="showPodcastEpisodeFeed" :library-item="libraryItem" :episodes="podcastFeedEpisodes" /> <modals-podcast-episode-feed v-model="showPodcastEpisodeFeed" :library-item="libraryItem" :episodes="podcastFeedEpisodes" :download-queue="episodeDownloadsQueued" :episodes-downloading="episodesDownloading" />
<modals-bookmarks-modal v-model="showBookmarksModal" :bookmarks="bookmarks" :playback-rate="1" :library-item-id="libraryItemId" hide-create @select="selectBookmark" /> <modals-bookmarks-modal v-model="showBookmarksModal" :bookmarks="bookmarks" :playback-rate="1" :library-item-id="libraryItemId" hide-create @select="selectBookmark" />
</div> </div>
</template> </template>
@ -646,13 +646,11 @@ export default {
}, },
rssFeedOpen(data) { rssFeedOpen(data) {
if (data.entityId === this.libraryItemId) { if (data.entityId === this.libraryItemId) {
console.log('RSS Feed Opened', data)
this.rssFeed = data this.rssFeed = data
} }
}, },
rssFeedClosed(data) { rssFeedClosed(data) {
if (data.entityId === this.libraryItemId) { if (data.entityId === this.libraryItemId) {
console.log('RSS Feed Closed', data)
this.rssFeed = null this.rssFeed = null
} }
}, },

View File

@ -43,7 +43,8 @@ class PodcastEpisodeDownload {
season: this.rssPodcastEpisode?.season ?? null, season: this.rssPodcastEpisode?.season ?? null,
episode: this.rssPodcastEpisode?.episode ?? null, episode: this.rssPodcastEpisode?.episode ?? null,
episodeType: this.rssPodcastEpisode?.episodeType ?? 'full', episodeType: this.rssPodcastEpisode?.episodeType ?? 'full',
publishedAt: this.rssPodcastEpisode?.publishedAt ?? null publishedAt: this.rssPodcastEpisode?.publishedAt ?? null,
guid: this.rssPodcastEpisode?.guid ?? null
} }
} }