mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-17 14:51:55 +00:00
WIP
This commit is contained in:
parent
ebedaeb3b0
commit
51b3f0d465
8 changed files with 157 additions and 200 deletions
|
|
@ -15,29 +15,36 @@
|
|||
</div>
|
||||
|
||||
<div class="flex items-center pt-2">
|
||||
<button class="h-8 px-4 border border-white border-opacity-20 hover:bg-white hover:bg-opacity-10 rounded-full flex items-center justify-center cursor-pointer focus:outline-none" :class="userIsFinished ? 'text-white text-opacity-40' : ''" @click.stop="playClick">
|
||||
<button v-if="episode.audioTrack" class="h-8 px-4 border border-white border-opacity-20 hover:bg-white hover:bg-opacity-10 rounded-full flex items-center justify-center cursor-pointer focus:outline-none" :class="userIsFinished ? 'text-white text-opacity-40' : ''" @click.stop="playClick">
|
||||
<span class="material-icons text-2xl" :class="streamIsPlaying ? '' : 'text-success'">{{ streamIsPlaying ? 'pause' : 'play_arrow' }}</span>
|
||||
<p class="pl-2 pr-1 text-sm font-semibold">{{ timeRemaining }}</p>
|
||||
</button>
|
||||
|
||||
<button v-if="!episode.id && !isDownloading && !isDownloadQueued && userIsAdminOrUp" class="h-8 px-4 border border-white border-opacity-20 hover:bg-white hover:bg-opacity-10 rounded-full flex items-center justify-center cursor-pointer focus:outline-none" :class="userIsFinished ? 'text-white text-opacity-40' : ''" @click.stop="downloadEpisode">
|
||||
<span class="material-icons text-success">download</span>
|
||||
<p class="pl-2 pr-1 text-sm font-semibold">Download</p>
|
||||
</button>
|
||||
|
||||
<!-- <button v-if="libraryItemIdStreaming && !isStreamingFromDifferentLibrary" class="h-8 w-8 flex justify-center items-center mx-2" :class="isQueued ? 'text-success' : ''" @click.stop="queueBtnClick">
|
||||
<span class="material-icons-outlined">{{ isQueued ? 'playlist_add_check' : 'queue' }}</span>
|
||||
</button> -->
|
||||
|
||||
<ui-tooltip v-if="libraryItemIdStreaming && !isStreamingFromDifferentLibrary" :text="isQueued ? $strings.MessageRemoveFromPlayerQueue : $strings.MessageAddToPlayerQueue" :class="isQueued ? 'text-success' : ''" direction="top">
|
||||
<ui-tooltip v-if="episode.id && libraryItemIdStreaming && !isStreamingFromDifferentLibrary" :text="isQueued ? $strings.MessageRemoveFromPlayerQueue : $strings.MessageAddToPlayerQueue" :class="isQueued ? 'text-success' : ''" direction="top">
|
||||
<ui-icon-btn :icon="isQueued ? 'playlist_add_check' : 'playlist_play'" borderless @click="queueBtnClick" />
|
||||
</ui-tooltip>
|
||||
|
||||
<ui-tooltip :text="userIsFinished ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" direction="top">
|
||||
<ui-tooltip v-if="episode.id" :text="userIsFinished ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" direction="top">
|
||||
<ui-read-icon-btn :disabled="isProcessingReadUpdate" :is-read="userIsFinished" borderless class="mx-1 mt-0.5" @click="toggleFinished" />
|
||||
</ui-tooltip>
|
||||
|
||||
<ui-tooltip :text="$strings.LabelYourPlaylists" direction="top">
|
||||
<ui-tooltip v-if="episode.id" :text="$strings.LabelYourPlaylists" direction="top">
|
||||
<ui-icon-btn icon="playlist_add" borderless @click="clickAddToPlaylist" />
|
||||
</ui-tooltip>
|
||||
|
||||
<ui-icon-btn v-if="userCanUpdate" icon="edit" borderless @click="clickEdit" />
|
||||
<ui-icon-btn v-if="userCanDelete" icon="close" borderless @click="removeClick" />
|
||||
<ui-icon-btn v-if="episode.id && userCanUpdate" icon="edit" borderless @click="clickEdit" />
|
||||
<ui-icon-btn v-if="episode.id && userCanDelete" icon="close" borderless @click="removeClick" />
|
||||
<p v-if="isDownloading">Downloading...</p>
|
||||
<p v-if="isDownloadQueued">Queued...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isHovering || isSelected || selectionMode" class="hidden md:block w-12 min-w-12" />
|
||||
|
|
@ -63,14 +70,16 @@ export default {
|
|||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
selectionMode: Boolean
|
||||
selectionMode: Boolean,
|
||||
isDownloading: Boolean,
|
||||
isDownloadQueued: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isProcessingReadUpdate: false,
|
||||
processingRemove: false,
|
||||
isHovering: false,
|
||||
isSelected: false
|
||||
isSelected: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -80,6 +89,9 @@ export default {
|
|||
userCanDelete() {
|
||||
return this.$store.getters['user/getUserCanDelete']
|
||||
},
|
||||
userIsAdminOrUp() {
|
||||
return this.$store.getters['user/getIsAdminOrUp']
|
||||
},
|
||||
audioFile() {
|
||||
return this.episode.audioFile
|
||||
},
|
||||
|
|
@ -202,7 +214,33 @@ export default {
|
|||
// Add to queue
|
||||
this.$emit('addToQueue', this.episode)
|
||||
}
|
||||
}
|
||||
},
|
||||
downloadEpisode() {
|
||||
var episodesToDownload = [this.episode]
|
||||
var payloadSize = JSON.stringify(episodesToDownload).length
|
||||
var sizeInMb = payloadSize / 1024 / 1024
|
||||
var sizeInMbPretty = sizeInMb.toFixed(2) + 'MB'
|
||||
console.log('Request size', sizeInMb)
|
||||
if (sizeInMb > 4.99) {
|
||||
return this.$toast.error(`Request is too large (${sizeInMbPretty}) should be < 5Mb`)
|
||||
}
|
||||
this.processing = true
|
||||
this.$axios
|
||||
.$post(`/api/podcasts/${this.libraryItemId}/download-episodes`, episodesToDownload)
|
||||
.then(() => {
|
||||
this.processing = false
|
||||
this.$toast.success('Started downloading episodes')
|
||||
this.show = false
|
||||
})
|
||||
.catch((error) => {
|
||||
var errorMsg = error.response && error.response.data ? error.response.data : 'Failed to download episodes'
|
||||
console.error('Failed to download episodes', error)
|
||||
this.processing = false
|
||||
this.$toast.error(errorMsg)
|
||||
this.selectedEpisodes = {}
|
||||
this.selectAll = false
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,13 +1,16 @@
|
|||
<template>
|
||||
<div class="w-full py-6">
|
||||
<p class="text-lg mb-2 font-semibold md:hidden">{{ $strings.HeaderEpisodes }}</p>
|
||||
<p v-if="media.podcastFeedDownloadedAt" class="text-sm text-gray-300">Feed last updated {{ $formatDate(media.podcastFeedDownloadedAt, 'MMM do, yyyy HH:mm') }}</p>
|
||||
<div class="flex items-center mb-4">
|
||||
<p class="text-lg mb-0 font-semibold hidden md:block">{{ $strings.HeaderEpisodes }}</p>
|
||||
<ui-icon-btn icon="refresh" class="mx-0.5" outlined @click.stop="refreshPodcastFeed" />
|
||||
<div class="flex-grow hidden md:block" />
|
||||
<template v-if="isSelectionMode">
|
||||
<ui-tooltip :text="selectedIsFinished ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" direction="bottom">
|
||||
<ui-read-icon-btn :disabled="processing" :is-read="selectedIsFinished" @click="toggleBatchFinished" class="mx-1.5" />
|
||||
</ui-tooltip>
|
||||
<ui-btn color="success" :disabled="processing" small class="h-9 mr-1.5" @click="downloadSelectedEpisodes">Download {{ selectedEpisodes.length }} episode(s)</ui-btn>
|
||||
<ui-btn color="error" :disabled="processing" small class="h-9" @click="removeSelectedEpisodes">{{ $getString('MessageRemoveEpisodes', [selectedEpisodes.length]) }}</ui-btn>
|
||||
<ui-btn :disabled="processing" small class="ml-2 h-9" @click="clearSelected">{{ $strings.ButtonCancel }}</ui-btn>
|
||||
</template>
|
||||
|
|
@ -19,10 +22,9 @@
|
|||
</template>
|
||||
</div>
|
||||
<p v-if="!episodes.length" class="py-4 text-center text-lg">{{ $strings.MessageNoEpisodes }}</p>
|
||||
<template v-for="episode in episodesSorted">
|
||||
<tables-podcast-episode-table-row ref="episodeRow" :key="episode.id" :episode="episode" :library-item-id="libraryItem.id" :selection-mode="isSelectionMode" class="item" @play="playEpisode" @remove="removeEpisode" @edit="editEpisode" @view="viewEpisode" @selected="episodeSelected" @addToQueue="addEpisodeToQueue" @addToPlaylist="addToPlaylist" />
|
||||
<template v-for="episode in this.allEpisodes">
|
||||
<tables-podcast-episode-table-row ref="episodeRow" :key="episode.id" :episode="episode" :library-item-id="libraryItem.id" :selection-mode="isSelectionMode" :is-downloading="isDownloading(episode)" :is-download-queued="isDownloadQueued(episode)" class="item" @play="playEpisode" @remove="removeEpisode" @edit="editEpisode" @view="viewEpisode" @selected="episodeSelected" @addToQueue="addEpisodeToQueue" @addToPlaylist="addToPlaylist" />
|
||||
</template>
|
||||
|
||||
<modals-podcast-remove-episode v-model="showPodcastRemoveModal" @input="removeEpisodeModalToggled" :library-item="libraryItem" :episodes="episodesToRemove" @clearSelected="clearSelected" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -33,6 +35,14 @@ export default {
|
|||
libraryItem: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
episodesDownloading: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
episodesQueued: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
@ -54,6 +64,11 @@ export default {
|
|||
handler() {
|
||||
this.init()
|
||||
}
|
||||
},
|
||||
episodesDownloading: {
|
||||
handler() {
|
||||
console.log(this.episodesDownloading)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -137,6 +152,17 @@ export default {
|
|||
return String(a[this.sortKey]).localeCompare(String(b[this.sortKey]), undefined, { numeric: true, sensitivity: 'base' })
|
||||
})
|
||||
},
|
||||
allEpisodes() {
|
||||
const added = new Set()
|
||||
const episodes = []
|
||||
for (const episode of [...this.episodes, ...this.media.podcastFeed.episodes]) {
|
||||
const key = `${episode.pubDate}-${episode.title}`
|
||||
if (added.has(key)) continue
|
||||
episodes.push(episode)
|
||||
added.add(key)
|
||||
}
|
||||
return episodes
|
||||
},
|
||||
selectedIsFinished() {
|
||||
// Find an item that is not finished, if none then all items finished
|
||||
return !this.selectedEpisodes.find((episode) => {
|
||||
|
|
@ -290,6 +316,49 @@ export default {
|
|||
this.$store.commit('globals/setSelectedEpisode', episode)
|
||||
this.$store.commit('globals/setShowViewPodcastEpisodeModal', true)
|
||||
},
|
||||
refreshPodcastFeed() {
|
||||
this.$axios
|
||||
.get(`/api/podcasts/${this.libraryItem.id}/refresh-episodes-list`)
|
||||
.then(() => {
|
||||
this.$toast.success('Fetched episodes!')
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error('Fetching episodes failed')
|
||||
console.error('Fetching episodes failed', error)
|
||||
})
|
||||
},
|
||||
downloadSelectedEpisodes() {
|
||||
var episodesToDownload = this.selectedEpisodes
|
||||
var payloadSize = JSON.stringify(episodesToDownload).length
|
||||
var sizeInMb = payloadSize / 1024 / 1024
|
||||
var sizeInMbPretty = sizeInMb.toFixed(2) + 'MB'
|
||||
console.log('Request size', sizeInMb)
|
||||
if (sizeInMb > 4.99) {
|
||||
return this.$toast.error(`Request is too large (${sizeInMbPretty}) should be < 5Mb`)
|
||||
}
|
||||
this.processing = true
|
||||
this.$axios
|
||||
.$post(`/api/podcasts/${this.libraryItem.id}/download-episodes`, episodesToDownload)
|
||||
.then(() => {
|
||||
this.processing = false
|
||||
this.$toast.success('Started downloading episodes')
|
||||
this.show = false
|
||||
this.clearSelected()
|
||||
})
|
||||
.catch((error) => {
|
||||
var errorMsg = error.response && error.response.data ? error.response.data : 'Failed to download episodes'
|
||||
console.error('Failed to download episodes', error)
|
||||
this.processing = false
|
||||
this.$toast.error(errorMsg)
|
||||
this.clearSelected()
|
||||
})
|
||||
},
|
||||
isDownloading(episode) {
|
||||
return this.episodesDownloading.map(ep => ep.url).includes(episode?.url || episode?.enclosure?.url)
|
||||
},
|
||||
isDownloadQueued(episode) {
|
||||
return this.episodesQueued.map(ep => ep.url).includes(episode?.url || episode?.enclosure?.url)
|
||||
},
|
||||
init() {
|
||||
this.episodesCopy = this.episodes.map((ep) => ({ ...ep }))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue