Update:Casting when playing local item if connected to server linked to local item #170, Update:Play button color when playing local item verse server item, Add:Show play method at the top of audio player (Direct, Local, Transcode)

This commit is contained in:
advplyr
2022-05-04 19:31:56 -05:00
parent 0223df4f9e
commit 73d5b19d2b
6 changed files with 74 additions and 27 deletions
+1 -3
View File
@@ -80,11 +80,9 @@ export default {
methods: { methods: {
castClick() { castClick() {
if (this.$store.state.playerIsLocal) { if (this.$store.state.playerIsLocal) {
this.$toast.warn('Cannot cast downloaded media item') this.$eventBus.$emit('cast-local-item')
return return
} }
console.log('Cast Btn Click')
AbsAudioPlayer.requestSession() AbsAudioPlayer.requestSession()
}, },
clickShowSideDrawer() { clickShowSideDrawer() {
+8 -6
View File
@@ -4,7 +4,7 @@
<div class="top-2 left-4 absolute cursor-pointer"> <div class="top-2 left-4 absolute cursor-pointer">
<span class="material-icons text-5xl" @click="collapseFullscreen">expand_more</span> <span class="material-icons text-5xl" @click="collapseFullscreen">expand_more</span>
</div> </div>
<div v-show="showCastBtn" class="top-3.5 right-20 absolute cursor-pointer"> <div v-show="showCastBtn" class="top-4 right-16 absolute cursor-pointer">
<span class="material-icons text-3xl" :class="isCasting ? 'text-success' : ''" @click="castClick">cast</span> <span class="material-icons text-3xl" :class="isCasting ? 'text-success' : ''" @click="castClick">cast</span>
</div> </div>
<div class="top-4 right-4 absolute cursor-pointer"> <div class="top-4 right-4 absolute cursor-pointer">
@@ -12,6 +12,7 @@
<span class="material-icons text-3xl">more_vert</span> <span class="material-icons text-3xl">more_vert</span>
</ui-dropdown-menu> </ui-dropdown-menu>
</div> </div>
<p class="top-2 absolute left-0 right-0 mx-auto text-center uppercase tracking-widest text-opacity-75" style="font-size: 10px" :class="{ 'text-success': isLocalPlayMethod, 'text-accent': !isLocalPlayMethod }">{{ isDirectPlayMethod ? 'Direct' : isLocalPlayMethod ? 'Local' : 'Transcode' }}</p>
</div> </div>
<div v-if="useChapterTrack && showFullscreen" class="absolute total-track w-full px-3 z-30"> <div v-if="useChapterTrack && showFullscreen" class="absolute total-track w-full px-3 z-30">
@@ -63,7 +64,7 @@
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<span v-show="showFullscreen" class="material-icons next-icon text-white text-opacity-75 cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpChapterStart">first_page</span> <span v-show="showFullscreen" class="material-icons next-icon text-white text-opacity-75 cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpChapterStart">first_page</span>
<span class="material-icons jump-icon text-white cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="backward10">replay_10</span> <span class="material-icons jump-icon text-white cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="backward10">replay_10</span>
<div class="play-btn cursor-pointer shadow-sm bg-accent flex items-center justify-center rounded-full text-primary mx-4" :class="seekLoading ? 'animate-spin' : ''" @mousedown.prevent @mouseup.prevent @click.stop="playPauseClick"> <div class="play-btn cursor-pointer shadow-sm flex items-center justify-center rounded-full text-primary mx-4" :class="{ 'animate-spin': seekLoading, 'bg-accent': !isLocalPlayMethod, 'bg-success': isLocalPlayMethod }" @mousedown.prevent @mouseup.prevent @click.stop="playPauseClick">
<span v-if="!isLoading" class="material-icons">{{ seekLoading ? 'autorenew' : !isPlaying ? 'play_arrow' : 'pause' }}</span> <span v-if="!isLoading" class="material-icons">{{ seekLoading ? 'autorenew' : !isPlaying ? 'play_arrow' : 'pause' }}</span>
<widgets-spinner-icon v-else class="h-8 w-8" /> <widgets-spinner-icon v-else class="h-8 w-8" />
</div> </div>
@@ -159,7 +160,7 @@ export default {
return this.showFullscreen ? 200 : 60 return this.showFullscreen ? 200 : 60
}, },
showCastBtn() { showCastBtn() {
return this.$store.state.isCastAvailable && !this.isLocalPlayMethod return this.$store.state.isCastAvailable
}, },
isCasting() { isCasting() {
return this.mediaPlayer === 'cast-player' return this.mediaPlayer === 'cast-player'
@@ -193,6 +194,9 @@ export default {
isLocalPlayMethod() { isLocalPlayMethod() {
return this.playMethod == this.$constants.PlayMethod.LOCAL return this.playMethod == this.$constants.PlayMethod.LOCAL
}, },
isDirectPlayMethod() {
return this.playMethod == this.$constants.PlayMethod.DIRECTPLAY
},
title() { title() {
if (this.playbackSession) return this.playbackSession.displayTitle if (this.playbackSession) return this.playbackSession.displayTitle
return this.mediaMetadata ? this.mediaMetadata.title : 'Title' return this.mediaMetadata ? this.mediaMetadata.title : 'Title'
@@ -269,12 +273,10 @@ export default {
this.showChapterModal = false this.showChapterModal = false
}, },
castClick() { castClick() {
console.log('Cast Btn Click')
if (this.isLocalPlayMethod) { if (this.isLocalPlayMethod) {
this.$toast.warn('Cannot cast downloaded media items') this.$eventBus.$emit('cast-local-item')
return return
} }
AbsAudioPlayer.requestSession() AbsAudioPlayer.requestSession()
}, },
clickContainer() { clickContainer() {
+30
View File
@@ -168,10 +168,36 @@ export default {
this.$refs.audioPlayer.closePlayback() this.$refs.audioPlayer.closePlayback()
} }
}, },
castLocalItem() {
if (!this.serverLibraryItemId) {
this.$toast.error(`Cannot cast locally downloaded media`)
} else {
// Change to server library item
this.playServerLibraryItemAndCast(this.serverLibraryItemId)
}
},
playServerLibraryItemAndCast(libraryItemId) {
var playbackRate = 1
if (this.$refs.audioPlayer) {
playbackRate = this.$refs.audioPlayer.currentPlaybackRate || 1
}
AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId: null, playWhenReady: false, playbackRate })
.then((data) => {
console.log('Library item play response', JSON.stringify(data))
AbsAudioPlayer.requestSession()
})
.catch((error) => {
console.error('Failed', error)
})
},
async playLibraryItem(payload) { async playLibraryItem(payload) {
var libraryItemId = payload.libraryItemId var libraryItemId = payload.libraryItemId
var episodeId = payload.episodeId var episodeId = payload.episodeId
// 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
if (libraryItemId.startsWith('local') && this.$store.state.isCasting) { if (libraryItemId.startsWith('local') && this.$store.state.isCasting) {
const { value } = await Dialog.confirm({ const { value } = await Dialog.confirm({
title: 'Warning', title: 'Warning',
@@ -195,6 +221,8 @@ export default {
console.log('Library item play response', JSON.stringify(data)) console.log('Library item play response', JSON.stringify(data))
if (!libraryItemId.startsWith('local')) { if (!libraryItemId.startsWith('local')) {
this.serverLibraryItemId = libraryItemId this.serverLibraryItemId = libraryItemId
} else {
this.serverLibraryItemId = serverLibraryItemId
} }
}) })
.catch((error) => { .catch((error) => {
@@ -228,6 +256,7 @@ export default {
this.$eventBus.$on('play-item', this.playLibraryItem) this.$eventBus.$on('play-item', this.playLibraryItem)
this.$eventBus.$on('pause-item', this.pauseItem) this.$eventBus.$on('pause-item', this.pauseItem)
this.$eventBus.$on('close-stream', this.closeStreamOnly) this.$eventBus.$on('close-stream', this.closeStreamOnly)
this.$eventBus.$on('cast-local-item', this.castLocalItem)
this.$store.commit('user/addSettingsListener', { id: 'streamContainer', meth: this.settingsUpdated }) this.$store.commit('user/addSettingsListener', { id: 'streamContainer', meth: this.settingsUpdated })
}, },
beforeDestroy() { beforeDestroy() {
@@ -246,6 +275,7 @@ export default {
this.$eventBus.$off('play-item', this.playLibraryItem) this.$eventBus.$off('play-item', this.playLibraryItem)
this.$eventBus.$off('pause-item', this.pauseItem) this.$eventBus.$off('pause-item', this.pauseItem)
this.$eventBus.$off('close-stream', this.closeStreamOnly) this.$eventBus.$off('close-stream', this.closeStreamOnly)
this.$eventBus.$off('cast-local-item', this.castLocalItem)
this.$store.commit('user/removeSettingsListener', 'streamContainer') this.$store.commit('user/removeSettingsListener', 'streamContainer')
} }
} }
-4
View File
@@ -446,10 +446,6 @@ export default {
this.selected = !this.selected this.selected = !this.selected
this.$emit('select', this.libraryItem) this.$emit('select', this.libraryItem)
}, },
play() {
var eventBus = this.$eventBus || this.$nuxt.$eventBus
eventBus.$emit('play-item', { libraryItemId: this.libraryItemId })
},
destroy() { destroy() {
// destroy the vue listeners, etc // destroy the vue listeners, etc
this.$destroy() this.$destroy()
+7 -7
View File
@@ -9,13 +9,13 @@ install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' pod 'CapacitorApp', :path => '..\..\node_modules\@capacitor\app'
pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog' pod 'CapacitorDialog', :path => '..\..\node_modules\@capacitor\dialog'
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' pod 'CapacitorHaptics', :path => '..\..\node_modules\@capacitor\haptics'
pod 'CapacitorNetwork', :path => '../../node_modules/@capacitor/network' pod 'CapacitorNetwork', :path => '..\..\node_modules\@capacitor\network'
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' pod 'CapacitorStatusBar', :path => '..\..\node_modules\@capacitor\status-bar'
pod 'CapacitorStorage', :path => '../../node_modules/@capacitor/storage' pod 'CapacitorStorage', :path => '..\..\node_modules\@capacitor\storage'
pod 'RobingenzCapacitorAppUpdate', :path => '../../node_modules/@robingenz/capacitor-app-update' pod 'RobingenzCapacitorAppUpdate', :path => '..\..\node_modules\@robingenz\capacitor-app-update'
end end
target 'App' do target 'App' do
+28 -7
View File
@@ -6,10 +6,13 @@
<covers-book-cover :library-item="libraryItem" :width="128" :book-cover-aspect-ratio="bookCoverAspectRatio" /> <covers-book-cover :library-item="libraryItem" :width="128" :book-cover-aspect-ratio="bookCoverAspectRatio" />
<div v-if="!isPodcast" class="absolute bottom-0 left-0 h-1.5 shadow-sm z-10" :class="userIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: 128 * progressPercent + 'px' }"></div> <div v-if="!isPodcast" class="absolute bottom-0 left-0 h-1.5 shadow-sm z-10" :class="userIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: 128 * progressPercent + 'px' }"></div>
</div> </div>
<!-- Show an indicator for local library items whether they are linked to a server item and if that server item is connected -->
<p v-if="isLocal && serverLibraryItemId" style="font-size: 10px" class="text-success py-1 uppercase tracking-widest">connected</p>
<p v-else-if="isLocal && libraryItem.serverAddress" style="font-size: 10px" class="text-gray-400 py-1">{{ libraryItem.serverAddress }}</p>
</div> </div>
<div class="flex-grow px-3"> <div class="flex-grow px-3">
<h1 class="text-lg">{{ title }}</h1> <h1 class="text-lg">{{ title }}</h1>
<!-- <h3 v-if="series" class="font-book text-gray-300 text-lg leading-7">{{ seriesText }}</h3> --> <h3 v-if="seriesName" class="text-gray-300 text-sm leading-6">{{ seriesName }}</h3>
<p class="text-sm text-gray-400">by {{ author }}</p> <p class="text-sm text-gray-400">by {{ author }}</p>
<p v-if="numTracks" class="text-gray-300 text-sm my-1"> <p v-if="numTracks" class="text-gray-300 text-sm my-1">
{{ $elapsedPretty(duration) }} {{ $elapsedPretty(duration) }}
@@ -31,7 +34,7 @@
<span v-show="!isPlaying" class="material-icons">play_arrow</span> <span v-show="!isPlaying" class="material-icons">play_arrow</span>
<span class="px-1 text-sm">{{ isPlaying ? 'Playing' : 'Play' }}</span> <span class="px-1 text-sm">{{ isPlaying ? 'Playing' : 'Play' }}</span>
</ui-btn> </ui-btn>
<ui-btn v-if="showRead && isConnected" color="info" class="flex items-center justify-center mr-2" :class="showPlay ? '' : 'flex-grow'" :padding-x="2" @click="readBook"> <ui-btn v-if="showRead" color="info" class="flex items-center justify-center mr-2" :class="showPlay ? '' : 'flex-grow'" :padding-x="2" @click="readBook">
<span class="material-icons">auto_stories</span> <span class="material-icons">auto_stories</span>
<span v-if="!showPlay" class="px-2 text-base">Read {{ ebookFormat }}</span> <span v-if="!showPlay" class="px-2 text-base">Read {{ ebookFormat }}</span>
</ui-btn> </ui-btn>
@@ -133,8 +136,14 @@ export default {
var podcastMedia = this.localLibraryItem.media var podcastMedia = this.localLibraryItem.media
return podcastMedia ? podcastMedia.episodes || [] : [] return podcastMedia ? podcastMedia.episodes || [] : []
}, },
isConnected() { serverLibraryItemId() {
return this.$store.state.socketConnected if (!this.isLocal) return this.libraryItem.id
// Check if local library item is connected to the current server
if (!this.libraryItem.serverAddress || !this.libraryItem.libraryItemId) return null
if (this.$store.getters['user/getServerAddress'] === this.libraryItem.serverAddress) {
return this.libraryItem.libraryItemId
}
return null
}, },
bookCoverAspectRatio() { bookCoverAspectRatio() {
return this.$store.getters['getBookCoverAspectRatio'] return this.$store.getters['getBookCoverAspectRatio']
@@ -167,6 +176,10 @@ export default {
series() { series() {
return this.mediaMetadata.series || [] return this.mediaMetadata.series || []
}, },
seriesName() {
// For books only on toJSONExpanded
return this.mediaMetadata.seriesName || ''
},
duration() { duration() {
return this.media.duration return this.media.duration
}, },
@@ -237,6 +250,9 @@ export default {
}, },
episodes() { episodes() {
return this.media.episodes || [] return this.media.episodes || []
},
isCasting() {
return this.$store.state.isCasting
} }
}, },
methods: { methods: {
@@ -245,7 +261,12 @@ export default {
}, },
playClick() { playClick() {
// Todo: Allow playing local or streaming // Todo: Allow playing local or streaming
if (this.hasLocal) return this.$eventBus.$emit('play-item', { libraryItemId: this.localLibraryItem.id }) 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) 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 })
}, },
async clearProgressClick() { async clearProgressClick() {
@@ -404,11 +425,11 @@ export default {
}, },
mounted() { mounted() {
this.$eventBus.$on('new-local-library-item', this.newLocalLibraryItem) this.$eventBus.$on('new-local-library-item', this.newLocalLibraryItem)
// this.$server.socket.on('item_updated', this.itemUpdated) this.$socket.on('item_updated', this.itemUpdated)
}, },
beforeDestroy() { beforeDestroy() {
this.$eventBus.$off('new-local-library-item', this.newLocalLibraryItem) this.$eventBus.$off('new-local-library-item', this.newLocalLibraryItem)
// this.$server.socket.off('item_updated', this.itemUpdated) this.$socket.off('item_updated', this.itemUpdated)
} }
} }
</script> </script>