diff --git a/components/app/AudioPlayerContainer.vue b/components/app/AudioPlayerContainer.vue
index c2f36aa1..0e92314e 100644
--- a/components/app/AudioPlayerContainer.vue
+++ b/components/app/AudioPlayerContainer.vue
@@ -204,6 +204,7 @@ export default {
message: `Cannot cast downloaded media items. Confirm to close cast and play on your device.`
})
if (!value) {
+ this.$store.commit('setPlayerDoneStartingPlayback')
return
}
}
@@ -217,6 +218,7 @@ export default {
} else if (this.$refs.audioPlayer) {
this.$refs.audioPlayer.play()
}
+ this.$store.commit('setPlayerDoneStartingPlayback')
return
}
@@ -254,6 +256,9 @@ export default {
console.error('Failed', error)
this.$toast.error('Failed to play')
})
+ .finally(() => {
+ this.$store.commit('setPlayerDoneStartingPlayback')
+ })
},
pauseItem() {
if (this.$refs.audioPlayer && this.$refs.audioPlayer.isPlaying) {
diff --git a/components/cards/LazyBookCard.vue b/components/cards/LazyBookCard.vue
index 8a743f68..21bc72d9 100644
--- a/components/cards/LazyBookCard.vue
+++ b/components/cards/LazyBookCard.vue
@@ -46,8 +46,13 @@
-
-
{{ streamIsPlaying ? 'pause_circle' : 'play_circle_filled' }}
+
+
{{ streamIsPlaying ? 'pause_circle' : 'play_circle_filled' }}
+
@@ -322,6 +327,14 @@ export default {
streamIsPlaying() {
return this.store.state.playerIsPlaying && this.isStreaming
},
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.store.state.playerIsStartingPlayback
+ },
+ playerIsStartingForThisMedia() {
+ const mediaId = this.store.state.playerStartingPlaybackMediaId
+ return mediaId === this.recentEpisode?.id
+ },
isMissing() {
return this._libraryItem.isMissing
},
@@ -447,6 +460,8 @@ export default {
},
async play() {},
async playEpisode() {
+ if (this.playerIsStartingPlayback) return
+
await this.$hapticsImpact()
const eventBus = this.$eventBus || this.$nuxt.$eventBus
if (this.streamIsPlaying) {
@@ -454,6 +469,7 @@ export default {
return
}
+ this.store.commit('setPlayerIsStartingPlayback', this.recentEpisode.id)
if (this.localEpisode) {
// Play episode locally
eventBus.$emit('play-item', {
diff --git a/components/cards/LazyListBookCard.vue b/components/cards/LazyListBookCard.vue
index 1e4a9433..3b46b9a4 100644
--- a/components/cards/LazyListBookCard.vue
+++ b/components/cards/LazyListBookCard.vue
@@ -176,7 +176,7 @@ export default {
return this.mediaMetadata.series
},
seriesSequence() {
- return this.series ? this.series.sequence : null
+ return this.series?.sequence || null
},
collapsedSeries() {
// Only added to item object when collapseSeries is enabled
@@ -209,10 +209,10 @@ export default {
return this.store.getters['user/getUserMediaProgress'](this.libraryItemId)
},
userProgressPercent() {
- return this.userProgress ? this.userProgress.progress || 0 : 0
+ return this.userProgress?.progress || 0
},
itemIsFinished() {
- return this.userProgress ? !!this.userProgress.isFinished : false
+ return !!this.userProgress?.isFinished
},
showError() {
return this.numMissingParts || this.isMissing || this.isInvalid
diff --git a/components/tables/playlist/ItemTableRow.vue b/components/tables/playlist/ItemTableRow.vue
index 40fda325..6631dc84 100644
--- a/components/tables/playlist/ItemTableRow.vue
+++ b/components/tables/playlist/ItemTableRow.vue
@@ -13,8 +13,11 @@
-
@@ -117,6 +120,15 @@ export default {
streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming
},
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
+ },
+ playerIsStartingForThisMedia() {
+ const mediaId = this.$store.state.playerStartingPlaybackMediaId
+ let thisMediaId = this.episodeId || this.libraryItem.id
+ return mediaId === thisMediaId
+ },
userItemProgress() {
return this.$store.getters['user/getUserMediaProgress'](this.libraryItem.id, this.episodeId)
},
@@ -142,10 +154,14 @@ export default {
this.$emit('showMore', playlistItem)
},
async playClick() {
+ if (this.playerIsStartingPlayback) return
+
await this.$hapticsImpact()
+ let mediaId = this.episodeId || this.libraryItem.id
if (this.streamIsPlaying) {
this.$eventBus.$emit('pause-item')
} else if (this.localLibraryItem) {
+ this.$store.commit('setPlayerIsStartingPlayback', mediaId)
this.$eventBus.$emit('play-item', {
libraryItemId: this.localLibraryItem.id,
episodeId: this.localEpisode?.id,
@@ -153,6 +169,7 @@ export default {
serverEpisodeId: this.episodeId
})
} else {
+ this.$store.commit('setPlayerIsStartingPlayback', mediaId)
this.$eventBus.$emit('play-item', {
libraryItemId: this.libraryItem.id,
episodeId: this.episodeId
diff --git a/components/tables/podcast/EpisodeRow.vue b/components/tables/podcast/EpisodeRow.vue
index 2916eb60..8380f060 100644
--- a/components/tables/podcast/EpisodeRow.vue
+++ b/components/tables/podcast/EpisodeRow.vue
@@ -29,7 +29,10 @@
-
{{ streamIsPlaying ? 'pause' : 'play_arrow' }}
+
{{ streamIsPlaying ? 'pause' : 'play_arrow' }}
+
{{ timeRemaining }}
@@ -118,6 +121,14 @@ export default {
streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming
},
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
+ },
+ playerIsStartingForThisMedia() {
+ const mediaId = this.$store.state.playerStartingPlaybackMediaId
+ return mediaId === this.episode?.id
+ },
itemProgress() {
if (this.isLocal) return this.$store.getters['globals/getLocalMediaProgressById'](this.libraryItemId, this.episode.id)
return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId, this.episode.id)
@@ -227,10 +238,14 @@ export default {
}
},
async playClick() {
+ if (this.playerIsStartingPlayback) return
+
await this.$hapticsImpact()
if (this.streamIsPlaying) {
this.$eventBus.$emit('pause-item')
} else {
+ this.$store.commit('setPlayerIsStartingPlayback', this.episode.id)
+
if (this.localEpisode && this.localLibraryItemId) {
console.log('Play local episode', this.localEpisode.id, this.localLibraryItemId)
diff --git a/components/tables/podcast/LatestEpisodeRow.vue b/components/tables/podcast/LatestEpisodeRow.vue
index 0194618d..2c99fd93 100644
--- a/components/tables/podcast/LatestEpisodeRow.vue
+++ b/components/tables/podcast/LatestEpisodeRow.vue
@@ -29,7 +29,10 @@
-
{{ streamIsPlaying ? 'pause' : 'play_arrow' }}
+
{{ streamIsPlaying ? 'pause' : 'play_arrow' }}
+
{{ timeRemaining }}
@@ -122,6 +125,15 @@ export default {
streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming
},
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
+ },
+ playerIsStartingForThisMedia() {
+ if (!this.episode?.id) return false
+ const mediaId = this.$store.state.playerStartingPlaybackMediaId
+ return mediaId === this.episode.id
+ },
itemProgress() {
if (this.isLocal) return this.$store.getters['globals/getLocalMediaProgressById'](this.libraryItemId, this.episode.id)
return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId, this.episode.id)
@@ -135,10 +147,10 @@ export default {
}
},
itemProgressPercent() {
- return this.itemProgress ? this.itemProgress.progress : 0
+ return this.itemProgress?.progress || 0
},
userIsFinished() {
- return this.itemProgress ? !!this.itemProgress.isFinished : false
+ return !!this.itemProgress?.isFinished
},
timeRemaining() {
if (this.streamIsPlaying) return 'Playing'
@@ -154,7 +166,7 @@ export default {
return this.$store.getters['globals/getDownloadItem'](this.libraryItemId, this.episode.id)
},
localEpisodeId() {
- return this.localEpisode ? this.localEpisode.id : null
+ return this.localEpisode?.id || null
},
podcast() {
return this.episode.podcast || {}
@@ -238,10 +250,14 @@ export default {
}
},
async playClick() {
+ if (this.playerIsStartingPlayback) return
+
await this.$hapticsImpact()
if (this.streamIsPlaying) {
this.$eventBus.$emit('pause-item')
} else {
+ this.$store.commit('setPlayerIsStartingPlayback', this.episode.id)
+
if (this.localEpisode && this.localLibraryItemId) {
console.log('Play local episode', this.localEpisode.id, this.localLibraryItemId)
diff --git a/pages/collection/_id.vue b/pages/collection/_id.vue
index 0babb957..fe9b0c2b 100644
--- a/pages/collection/_id.vue
+++ b/pages/collection/_id.vue
@@ -12,7 +12,7 @@
{{ collectionName }}
-
+
play_arrow
{{ streaming ? $strings.ButtonPlaying : $strings.ButtonPlay }}
@@ -53,6 +53,7 @@ export default {
},
data() {
return {
+ mediaIdStartingPlayback: null,
processingRemove: false
}
},
@@ -77,17 +78,30 @@ export default {
streaming() {
return !!this.playableBooks.find((b) => this.$store.getters['getIsMediaStreaming'](b.id))
},
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
+ },
+ playerIsStartingForThisMedia() {
+ if (!this.mediaIdStartingPlayback) return false
+ const mediaId = this.$store.state.playerStartingPlaybackMediaId
+ return mediaId === this.mediaIdStartingPlayback
+ },
showPlayButton() {
return this.playableBooks.length
}
},
methods: {
clickPlay() {
+ if (this.playerIsStartingPlayback) return
+
var nextBookNotRead = this.playableBooks.find((pb) => {
var prog = this.$store.getters['user/getUserMediaProgress'](pb.id)
- return !prog || !prog.isFinished
+ return !prog?.isFinished
})
if (nextBookNotRead) {
+ this.mediaIdStartingPlayback = nextBookNotRead.id
+ this.$store.commit('setPlayerIsStartingPlayback', nextBookNotRead.id)
this.$eventBus.$emit('play-item', { libraryItemId: nextBookNotRead.id })
}
}
diff --git a/pages/item/_id/_episode/index.vue b/pages/item/_id/_episode/index.vue
index 90d5227f..43200a4a 100644
--- a/pages/item/_id/_episode/index.vue
+++ b/pages/item/_id/_episode/index.vue
@@ -29,7 +29,7 @@
-
+
{{ playerIsPlaying ? 'pause' : 'play_arrow' }}
{{ playerIsPlaying ? $strings.ButtonPause : localEpisodeId ? $strings.ButtonPlay : $strings.ButtonStream }}
@@ -210,6 +210,15 @@ export default {
playerIsPlaying() {
return this.$store.state.playerIsPlaying && this.isPlaying
},
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
+ },
+ playerIsStartingForThisMedia() {
+ if (!this.serverEpisodeId) return false
+ const mediaId = this.$store.state.playerStartingPlaybackMediaId
+ return mediaId === this.serverEpisodeId
+ },
userItemProgress() {
if (this.isLocal) return this.localItemProgress
return this.serverItemProgress
@@ -332,10 +341,14 @@ export default {
}
},
async playClick() {
+ if (this.playerIsStartingPlayback) return
+
await this.$hapticsImpact()
if (this.playerIsPlaying) {
this.$eventBus.$emit('pause-item')
} else {
+ this.$store.commit('setPlayerIsStartingPlayback', this.serverEpisodeId)
+
if (this.localEpisodeId && this.localLibraryItemId && !this.isLocal) {
console.log('Play local episode', this.localEpisodeId, this.localLibraryItemId)
diff --git a/pages/item/_id/index.vue b/pages/item/_id/index.vue
index f340421f..55476524 100644
--- a/pages/item/_id/index.vue
+++ b/pages/item/_id/index.vue
@@ -45,7 +45,7 @@
-
+
{{ playerIsPlaying ? 'pause' : 'play_arrow' }}
{{ playerIsPlaying ? $strings.ButtonPause : isPodcast ? $strings.ButtonNextEpisode : hasLocal ? $strings.ButtonPlay : $strings.ButtonStream }}
@@ -205,7 +205,8 @@ export default {
coverBgIsLight: false,
windowWidth: 0,
descriptionClamped: false,
- showFullDescription: false
+ showFullDescription: false,
+ episodeStartingPlayback: null
}
},
computed: {
@@ -393,6 +394,19 @@ export default {
playerIsPlaying() {
return this.$store.state.playerIsPlaying && (this.isStreaming || this.isPlaying)
},
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
+ },
+ playerIsStartingForThisMedia() {
+ const mediaId = this.$store.state.playerStartingPlaybackMediaId
+ if (this.isPodcast) {
+ if (!this.episodeStartingPlayback) return false
+ return mediaId === this.episodeStartingPlayback
+ } else {
+ return mediaId === this.serverLibraryItemId
+ }
+ },
tracks() {
return this.media.tracks || []
},
@@ -488,6 +502,8 @@ export default {
}
},
async play(startTime = null) {
+ if (this.playerIsStartingPlayback) return
+
if (this.isPodcast) {
this.episodes.sort((a, b) => {
return String(b.publishedAt).localeCompare(String(a.publishedAt), undefined, { numeric: true, sensitivity: 'base' })
@@ -500,7 +516,7 @@ export default {
} else {
podcastProgress = this.$store.getters['globals/getLocalMediaProgressById'](this.libraryItemId, ep.id)
}
- return !podcastProgress || !podcastProgress.isFinished
+ return !podcastProgress?.isFinished
})
if (!episode) episode = this.episodes[0]
@@ -515,6 +531,8 @@ export default {
}
const serverEpisodeId = !this.isLocal ? episodeId : localEpisode?.serverEpisodeId || null
+ this.episodeStartingPlayback = serverEpisodeId
+ this.$store.commit('setPlayerIsStartingPlayback', serverEpisodeId)
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 })
@@ -543,6 +561,7 @@ export default {
if (!value) return
}
+ this.$store.commit('setPlayerIsStartingPlayback', this.serverLibraryItemId)
this.$eventBus.$emit('play-item', { libraryItemId, serverLibraryItemId: this.serverLibraryItemId, startTime })
}
},
diff --git a/pages/localMedia/folders/_id.vue b/pages/localMedia/folders/_id.vue
index a7bc5d82..3c722b6c 100644
--- a/pages/localMedia/folders/_id.vue
+++ b/pages/localMedia/folders/_id.vue
@@ -110,9 +110,6 @@ export default {
this.$router.replace('/localMedia/folders')
}
},
- play(mediaItem) {
- this.$eventBus.$emit('play-item', { libraryItemId: mediaItem.id })
- },
async init() {
var folder = await this.$db.getLocalFolder(this.folderId)
this.folder = folder
diff --git a/pages/localMedia/item/_id.vue b/pages/localMedia/item/_id.vue
index 10dc2fca..71f7fbb4 100644
--- a/pages/localMedia/item/_id.vue
+++ b/pages/localMedia/item/_id.vue
@@ -232,6 +232,10 @@ export default {
}
]
}
+ },
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
}
},
methods: {
@@ -279,7 +283,9 @@ export default {
this.showDialog = true
},
async play() {
+ if (this.playerIsStartingPlayback) return
await this.$hapticsImpact()
+ this.$store.commit('setPlayerIsStartingPlayback', this.localLibraryItemId)
this.$eventBus.$emit('play-item', { libraryItemId: this.localLibraryItemId })
},
getCapImageSrc(contentUrl) {
diff --git a/pages/media/_id/history.vue b/pages/media/_id/history.vue
index 9914248f..3a4e5415 100644
--- a/pages/media/_id/history.vue
+++ b/pages/media/_id/history.vue
@@ -39,8 +39,7 @@ export default {
},
data() {
return {
- onMediaItemHistoryUpdatedListener: null,
- startingPlayback: false
+ onMediaItemHistoryUpdatedListener: null
}
},
computed: {
@@ -123,21 +122,21 @@ export default {
})
return groups
+ },
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
}
},
methods: {
async clickPlaybackTime(time) {
- if (this.startingPlayback) return
- this.startingPlayback = true
- await this.$hapticsImpact()
- console.log('Click playback time', time)
- this.playAtTime(time)
+ if (this.playerIsStartingPlayback) return
- setTimeout(() => {
- this.startingPlayback = false
- }, 1000)
+ await this.$hapticsImpact()
+ this.playAtTime(time)
},
playAtTime(startTime) {
+ this.$store.commit('setPlayerIsStartingPlayback', this.mediaItemEpisodeId || this.mediaItemLibraryItemId)
if (this.mediaItemIsLocal) {
// Local only
this.$eventBus.$emit('play-item', { libraryItemId: this.mediaItemLibraryItemId, episodeId: this.mediaItemEpisodeId, startTime })
diff --git a/pages/playlist/_id.vue b/pages/playlist/_id.vue
index 8ece676b..14be40d3 100644
--- a/pages/playlist/_id.vue
+++ b/pages/playlist/_id.vue
@@ -10,7 +10,7 @@
{{ playlistName }}
-
+
play_arrow
{{ streaming ? $strings.ButtonPlaying : $strings.ButtonPlay }}
@@ -76,7 +76,8 @@ export default {
showMoreMenu: false,
processing: false,
selectedLibraryItem: null,
- selectedEpisode: null
+ selectedEpisode: null,
+ mediaIdStartingPlayback: null
}
},
computed: {
@@ -108,6 +109,15 @@ export default {
},
showPlayButton() {
return this.playableItems.length
+ },
+ playerIsStartingPlayback() {
+ // Play has been pressed and waiting for native play response
+ return this.$store.state.playerIsStartingPlayback
+ },
+ playerIsStartingForThisMedia() {
+ if (!this.mediaIdStartingPlayback) return false
+ const mediaId = this.$store.state.playerStartingPlaybackMediaId
+ return mediaId === this.mediaIdStartingPlayback
}
},
methods: {
@@ -122,6 +132,8 @@ export default {
return !prog?.isFinished
})
if (nextItem) {
+ this.mediaIdStartingPlayback = nextItem.episodeId || nextItem.libraryItemId
+ this.$store.commit('setPlayerIsStartingPlayback', this.mediaIdStartingPlayback)
if (nextItem.localLibraryItem) {
this.$eventBus.$emit('play-item', { libraryItemId: nextItem.localLibraryItem.id, episodeId: nextItem.localEpisode?.id, serverLibraryItemId: nextItem.libraryItemId, serverEpisodeId: nextItem.episodeId })
} else {
diff --git a/store/index.js b/store/index.js
index 847c23f2..edb089e6 100644
--- a/store/index.js
+++ b/store/index.js
@@ -7,6 +7,8 @@ export const state = () => ({
currentPlaybackSession: null,
playerIsPlaying: false,
playerIsFullscreen: false,
+ playerIsStartingPlayback: false, // When pressing play before native play response
+ playerStartingPlaybackMediaId: null,
isCasting: false,
isCastAvailable: false,
attemptingConnection: false,
@@ -131,6 +133,14 @@ export const mutations = {
setPlayerFullscreen(state, val) {
state.playerIsFullscreen = val
},
+ setPlayerIsStartingPlayback(state, mediaId) {
+ state.playerStartingPlaybackMediaId = mediaId
+ state.playerIsStartingPlayback = true
+ },
+ setPlayerDoneStartingPlayback(state) {
+ state.playerStartingPlaybackMediaId = null
+ state.playerIsStartingPlayback = false
+ },
setHasStoragePermission(state, val) {
state.hasStoragePermission = val
},