diff --git a/components/app/AudioPlayerContainer.vue b/components/app/AudioPlayerContainer.vue
index 0516fd98..e7b7d282 100644
--- a/components/app/AudioPlayerContainer.vue
+++ b/components/app/AudioPlayerContainer.vue
@@ -32,7 +32,8 @@ export default {
onMediaPlayerChangedListener: null,
sleepInterval: null,
currentEndOfChapterTime: 0,
- serverLibraryItemId: null
+ serverLibraryItemId: null,
+ serverEpisodeId: null
}
},
watch: {
@@ -173,15 +174,15 @@ export default {
this.$toast.error(`Cannot cast locally downloaded media`)
} else {
// Change to server library item
- this.playServerLibraryItemAndCast(this.serverLibraryItemId)
+ this.playServerLibraryItemAndCast(this.serverLibraryItemId, this.serverEpisodeId)
}
},
- playServerLibraryItemAndCast(libraryItemId) {
+ playServerLibraryItemAndCast(libraryItemId, episodeId) {
var playbackRate = 1
if (this.$refs.audioPlayer) {
playbackRate = this.$refs.audioPlayer.currentPlaybackRate || 1
}
- AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId: null, playWhenReady: false, playbackRate })
+ AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId, playWhenReady: false, playbackRate })
.then((data) => {
if (data.error) {
const errorMsg = data.error || 'Failed to play'
@@ -203,6 +204,7 @@ export default {
// When playing local library item and can also play this item from the server
// then store the server library item id so it can be used if a cast is made
var serverLibraryItemId = payload.serverLibraryItemId || null
+ var serverEpisodeId = payload.serverEpisodeId || null
if (libraryItemId.startsWith('local') && this.$store.state.isCasting) {
const { value } = await Dialog.confirm({
@@ -215,6 +217,7 @@ export default {
}
this.serverLibraryItemId = null
+ this.serverEpisodeId = null
var playbackRate = 1
if (this.$refs.audioPlayer) {
@@ -234,6 +237,11 @@ export default {
} else {
this.serverLibraryItemId = serverLibraryItemId
}
+ if (episodeId && !episodeId.startsWith('local')) {
+ this.serverEpisodeId = episodeId
+ } else {
+ this.serverEpisodeId = serverEpisodeId
+ }
}
})
.catch((error) => {
diff --git a/components/tables/podcast/EpisodeRow.vue b/components/tables/podcast/EpisodeRow.vue
index 0110b1fd..d230670f 100644
--- a/components/tables/podcast/EpisodeRow.vue
+++ b/components/tables/podcast/EpisodeRow.vue
@@ -199,7 +199,9 @@ export default {
this.$eventBus.$emit('play-item', {
libraryItemId: this.localLibraryItemId,
- episodeId: this.localEpisode.id
+ episodeId: this.localEpisode.id,
+ serverLibraryItemId: this.libraryItemId,
+ serverEpisodeId: this.episode.id
})
} else {
this.$eventBus.$emit('play-item', {
diff --git a/pages/item/_id.vue b/pages/item/_id.vue
index 87d0b00e..e2f66a62 100644
--- a/pages/item/_id.vue
+++ b/pages/item/_id.vue
@@ -85,7 +85,7 @@
play_arrow
- {{ isPlaying ? (isStreaming ? 'Streaming' : 'Playing') : hasLocal ? 'Play' : 'Stream' }}
+ {{ isPlaying ? (isStreaming ? 'Streaming' : 'Playing') : isPodcast ? 'Next Episode' : hasLocal ? 'Play' : 'Stream' }}
auto_stories
@@ -305,13 +305,14 @@ export default {
return this.libraryItem.isIncomplete
},
showPlay() {
- return !this.isMissing && !this.isIncomplete && this.numTracks
+ return !this.isMissing && !this.isIncomplete && (this.numTracks || this.episodes.length)
},
showRead() {
return this.ebookFile && this.ebookFormat !== 'pdf'
},
showDownload() {
if (this.isIos) return false
+ if (this.isPodcast) return false
return this.user && this.userCanDownload && this.showPlay && !this.hasLocal
},
ebookFile() {
@@ -368,14 +369,58 @@ export default {
this.$store.commit('openReader', this.libraryItem)
},
playClick() {
- // Todo: Allow playing local or streaming
- if (this.hasLocal && this.serverLibraryItemId && this.isCasting) {
- // If casting and connected to server for local library item then send server library item id
- this.$eventBus.$emit('play-item', { libraryItemId: this.serverLibraryItemId })
- return
+ var episodeId = null
+
+ if (this.isPodcast) {
+ this.episodes.sort((a, b) => {
+ return String(b.publishedAt).localeCompare(String(a.publishedAt), undefined, { numeric: true, sensitivity: 'base' })
+ })
+
+ var episode = this.episodes.find((ep) => {
+ var podcastProgress = null
+ if (!this.isLocal) {
+ podcastProgress = this.$store.getters['user/getUserMediaProgress'](this.libraryItemId, ep.id)
+ } else {
+ podcastProgress = this.$store.getters['globals/getLocalMediaProgressById'](this.libraryItemId, ep.id)
+ }
+ return !podcastProgress || !podcastProgress.isFinished
+ })
+
+ if (!episode) episode = this.episodes[0]
+
+ episodeId = episode.id
+
+ var localEpisode = null
+ if (this.hasLocal && !this.isLocal) {
+ localEpisode = this.localLibraryItem.media.episodes.find((ep) => ep.serverEpisodeId == episodeId)
+ } else if (this.isLocal) {
+ localEpisode = episode
+ }
+ var serverEpisodeId = !this.isLocal ? episodeId : localEpisode ? localEpisode.serverEpisodeId : null
+
+ if (serverEpisodeId && this.serverLibraryItemId && this.isCasting) {
+ // If casting and connected to server for local library item then send server library item id
+ this.$eventBus.$emit('play-item', { libraryItemId: this.serverLibraryItemId, episodeId: serverEpisodeId })
+ return
+ }
+ if (localEpisode) {
+ this.$eventBus.$emit('play-item', { libraryItemId: this.localLibraryItem.id, episodeId: localEpisode.id, serverLibraryItemId: this.serverLibraryItemId, serverEpisodeId })
+ return
+ }
+ } else {
+ // Audiobook
+ if (this.hasLocal && this.serverLibraryItemId && this.isCasting) {
+ // If casting and connected to server for local library item then send server library item id
+ this.$eventBus.$emit('play-item', { libraryItemId: this.serverLibraryItemId })
+ return
+ }
+ if (this.hasLocal) {
+ this.$eventBus.$emit('play-item', { libraryItemId: this.localLibraryItem.id, serverLibraryItemId: this.serverLibraryItemId })
+ return
+ }
}
- if (this.hasLocal) return this.$eventBus.$emit('play-item', { libraryItemId: this.localLibraryItem.id, serverLibraryItemId: this.serverLibraryItemId })
- this.$eventBus.$emit('play-item', { libraryItemId: this.libraryItemId })
+
+ this.$eventBus.$emit('play-item', { libraryItemId: this.libraryItemId, episodeId })
},
async clearProgressClick() {
const { value } = await Dialog.confirm({