Fix:Playlist items playing from server and not using local copy #734

This commit is contained in:
advplyr 2023-06-09 17:05:29 -05:00
parent f1411011e6
commit c8b5cefeb5
5 changed files with 55 additions and 10 deletions

View file

@ -91,7 +91,6 @@ data class DeviceInfo(
var deviceId:String, var deviceId:String,
var manufacturer:String, var manufacturer:String,
var model:String, var model:String,
var brand:String,
var sdkVersion:Int, var sdkVersion:Int,
var clientVersion: String var clientVersion: String
) )

View file

@ -922,7 +922,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
appVersion: 0.9.46-beta appVersion: 0.9.46-beta
*/ */
val deviceId = Settings.Secure.getString(ctx.contentResolver, Settings.Secure.ANDROID_ID) val deviceId = Settings.Secure.getString(ctx.contentResolver, Settings.Secure.ANDROID_ID)
return DeviceInfo(deviceId, Build.MANUFACTURER, Build.MODEL, Build.BRAND, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME) return DeviceInfo(deviceId, Build.MANUFACTURER, Build.MODEL, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME)
} }
private val deviceSettings get() = DeviceManager.deviceData.deviceSettings ?: DeviceSettings.default() private val deviceSettings get() = DeviceManager.deviceData.deviceSettings ?: DeviceSettings.default()

View file

@ -47,6 +47,7 @@
<!-- No progress shown for collapsed series in library --> <!-- No progress shown for collapsed series in library -->
<div v-if="!collapsedSeries && (!isPodcast || recentEpisode)" class="absolute bottom-0 left-0 h-1 shadow-sm max-w-full z-10 rounded-b" :class="itemIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: width * userProgressPercent + 'px' }"></div> <div v-if="!collapsedSeries && (!isPodcast || recentEpisode)" class="absolute bottom-0 left-0 h-1 shadow-sm max-w-full z-10 rounded-b" :class="itemIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: width * userProgressPercent + 'px' }"></div>
<!-- Downloaded icon -->
<div v-if="showHasLocalDownload" class="absolute right-0 top-0 z-20" :style="{ top: (isPodcast ? 1.75 : 0.375) * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }"> <div v-if="showHasLocalDownload" class="absolute right-0 top-0 z-20" :style="{ top: (isPodcast ? 1.75 : 0.375) * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }">
<span class="material-icons text-2xl text-success">{{ isLocalOnly ? 'task' : 'download_done' }}</span> <span class="material-icons text-2xl text-success">{{ isLocalOnly ? 'task' : 'download_done' }}</span>
</div> </div>

View file

@ -6,9 +6,9 @@
</div> </div>
<div class="item-table-content h-full px-2 flex items-center"> <div class="item-table-content h-full px-2 flex items-center">
<div class="max-w-full"> <div class="max-w-full">
<p class="truncate block text-sm">{{ itemTitle }}</p> <p class="truncate block text-sm">{{ itemTitle }} <span v-if="localLibraryItem" class="material-icons text-success text-base align-text-bottom">download_done</span></p>
<p class="truncate block text-gray-400 text-xs">{{ bookAuthorName }}</p> <p v-if="authorName" class="truncate block text-gray-300 text-xs">{{ authorName }}</p>
<p class="text-xxs text-gray-500">{{ itemDuration }}</p> <p class="text-xxs text-gray-400">{{ itemDuration }}</p>
</div> </div>
</div> </div>
<div class="w-8 min-w-8 flex justify-center"> <div class="w-8 min-w-8 flex justify-center">
@ -39,11 +39,17 @@ export default {
libraryItem() { libraryItem() {
return this.item.libraryItem || {} return this.item.libraryItem || {}
}, },
localLibraryItem() {
return this.item.localLibraryItem
},
episode() { episode() {
return this.item.episode return this.item.episode
}, },
episodeId() { episodeId() {
return this.episode ? this.episode.id : null return this.episode?.id || null
},
localEpisode() {
return this.item.localEpisode
}, },
media() { media() {
return this.libraryItem.media || {} return this.libraryItem.media || {}
@ -66,6 +72,10 @@ export default {
bookAuthorName() { bookAuthorName() {
return this.bookAuthors.map((au) => au.name).join(', ') return this.bookAuthors.map((au) => au.name).join(', ')
}, },
authorName() {
if (this.episode) return this.mediaMetadata.author
return this.bookAuthorName
},
itemDuration() { itemDuration() {
if (this.episode) return this.$elapsedPretty(this.episode.duration) if (this.episode) return this.$elapsedPretty(this.episode.duration)
return this.$elapsedPretty(this.media.duration) return this.$elapsedPretty(this.media.duration)
@ -92,6 +102,7 @@ export default {
return !this.isMissing && !this.isInvalid && (this.tracks.length || this.episode) return !this.isMissing && !this.isInvalid && (this.tracks.length || this.episode)
}, },
isStreaming() { isStreaming() {
if (this.localLibraryItem && this.$store.getters['getIsEpisodeStreaming'](this.localLibraryItem.id, this.localEpisode?.id)) return true
return this.$store.getters['getIsEpisodeStreaming'](this.libraryItem.id, this.episodeId) return this.$store.getters['getIsEpisodeStreaming'](this.libraryItem.id, this.episodeId)
}, },
streamIsPlaying() { streamIsPlaying() {
@ -103,6 +114,13 @@ export default {
await this.$hapticsImpact() await this.$hapticsImpact()
if (this.streamIsPlaying) { if (this.streamIsPlaying) {
this.$eventBus.$emit('pause-item') this.$eventBus.$emit('pause-item')
} else if (this.localLibraryItem) {
this.$eventBus.$emit('play-item', {
libraryItemId: this.localLibraryItem.id,
episodeId: this.localEpisode?.id,
serverLibraryItemId: this.libraryItem.id,
serverEpisodeId: this.episodeId
})
} else { } else {
this.$eventBus.$emit('play-item', { this.$eventBus.$emit('play-item', {
libraryItemId: this.libraryItem.id, libraryItemId: this.libraryItem.id,

View file

@ -44,6 +44,26 @@ export default {
return redirect('/bookshelf/playlists') return redirect('/bookshelf/playlists')
} }
// Lookup matching local items & episodes and attach to playlist items
if (playlist.items.length) {
const localLibraryItems = (await app.$db.getLocalLibraryItems(playlist.items[0].libraryItem.mediaType)) || []
if (localLibraryItems.length) {
playlist.items.forEach((playlistItem) => {
const matchingLocalLibraryItem = localLibraryItems.find((lli) => lli.libraryItemId === playlistItem.libraryItemId)
if (!matchingLocalLibraryItem) return
if (playlistItem.episode) {
const matchingLocalEpisode = matchingLocalLibraryItem.media.episodes?.find((lep) => lep.serverEpisodeId === playlistItem.episodeId)
if (matchingLocalEpisode) {
playlistItem.localLibraryItem = matchingLocalLibraryItem
playlistItem.localEpisode = matchingLocalEpisode
}
} else {
playlistItem.localLibraryItem = matchingLocalLibraryItem
}
})
}
}
return { return {
playlist playlist
} }
@ -73,7 +93,10 @@ export default {
}) })
}, },
streaming() { streaming() {
return !!this.playableItems.find((i) => this.$store.getters['getIsMediaStreaming'](i.libraryItemId, i.episodeId)) return !!this.playableItems.find((i) => {
if (i.localLibraryItem && this.$store.getters['getIsMediaStreaming'](i.localLibraryItem.id, i.localEpisode?.id)) return true
return this.$store.getters['getIsMediaStreaming'](i.libraryItemId, i.episodeId)
})
}, },
showPlayButton() { showPlayButton() {
return this.playableItems.length return this.playableItems.length
@ -82,11 +105,15 @@ export default {
methods: { methods: {
clickPlay() { clickPlay() {
const nextItem = this.playableItems.find((i) => { const nextItem = this.playableItems.find((i) => {
var prog = this.$store.getters['user/getUserMediaProgress'](i.libraryItemId, i.episodeId) const prog = this.$store.getters['user/getUserMediaProgress'](i.libraryItemId, i.episodeId)
return !prog || !prog.isFinished return !prog?.isFinished
}) })
if (nextItem) { if (nextItem) {
this.$eventBus.$emit('play-item', { libraryItemId: nextItem.libraryItemId, episodeId: nextItem.episodeId }) if (nextItem.localLibraryItem) {
this.$eventBus.$emit('play-item', { libraryItemId: nextItem.localLibraryItem.id, episodeId: nextItem.localEpisode?.id, serverLibraryItemId: nextItem.libraryItemId, serverEpisodeId: nextItem.episodeId })
} else {
this.$eventBus.$emit('play-item', { libraryItemId: nextItem.libraryItemId, episodeId: nextItem.episodeId })
}
} }
} }
}, },