Fix audio playback
This commit is contained in:
parent
cec34d49fa
commit
54a33cd14e
|
@ -14,7 +14,7 @@ import { useIntervalFn, useToggle, useWindowSize } from '@vueuse/core'
|
|||
import { computed, nextTick, onMounted, ref, watchEffect } from 'vue'
|
||||
import { Track } from '~/types'
|
||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
|
||||
import useQueue from '~/composables/useQueue'
|
||||
import useQueue from '~/composables/audio/useQueue'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
const store = useStore()
|
||||
|
|
|
@ -9,8 +9,8 @@ import TrackPlaylistIcon from '~/components/playlists/TrackPlaylistIcon.vue'
|
|||
import Draggable, { } from 'vuedraggable'
|
||||
import { whenever, useTimeoutFn, useWindowScroll, useWindowSize } from '@vueuse/core'
|
||||
import { useGettext } from "vue3-gettext"
|
||||
import useQueue from '~/composables/useQueue'
|
||||
import usePlayer from '~/composables/usePlayer'
|
||||
import useQueue from '~/composables/audio/useQueue'
|
||||
import usePlayer from '~/composables/audio/usePlayer'
|
||||
|
||||
const queueModal = ref()
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
|
|||
import { ref, computed, watch, onMounted, onBeforeUnmount, watchEffect } from 'vue'
|
||||
import { useTimeoutFn, useIntervalFn } from '@vueuse/core'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import useQueue from '~/composables/useQueue'
|
||||
import usePlayer from '~/composables/usePlayer'
|
||||
import useQueue from '~/composables/audio/useQueue'
|
||||
import usePlayer from '~/composables/audio/usePlayer'
|
||||
import useTrackSources, { TrackSource } from '~/composables/audio/useTrackSources'
|
||||
import useSoundCache from '~/composables/audio/useSoundCache'
|
||||
|
||||
|
@ -146,11 +146,7 @@ watch(currentTrack, (track, oldValue) => {
|
|||
})
|
||||
|
||||
const observeProgress = ref(false)
|
||||
useIntervalFn(() => {
|
||||
if (observeProgress.value) {
|
||||
updateProgress()
|
||||
}
|
||||
}, 1000)
|
||||
useIntervalFn(() => observeProgress.value && updateProgress(), 1000)
|
||||
|
||||
watch(playing, async (isPlaying) => {
|
||||
if (currentSound.value) {
|
||||
|
@ -207,6 +203,7 @@ onMounted(() => {
|
|||
// TODO (wvffle): Check if it is needed
|
||||
nextTrackPreloaded.value = false
|
||||
|
||||
// Cache sound if we have currentTrack available
|
||||
if (currentTrack.value) {
|
||||
getSound(currentTrack.value)
|
||||
}
|
||||
|
@ -249,7 +246,7 @@ const getSound = (trackData: Track) => {
|
|||
},
|
||||
|
||||
onload () {
|
||||
const node = (sound as any)._sounds[0].node as HTMLAudioElement
|
||||
const node = (sound as any)._sounds[0]._node as HTMLAudioElement
|
||||
|
||||
node.addEventListener('progress', () => {
|
||||
if (sound !== currentSound.value) {
|
||||
|
@ -261,8 +258,8 @@ const getSound = (trackData: Track) => {
|
|||
},
|
||||
|
||||
onplay () {
|
||||
if (sound !== currentSound.value) {
|
||||
return sound.stop()
|
||||
if (this !== currentSound.value) {
|
||||
return (this as any).stop()
|
||||
}
|
||||
|
||||
const time = currentSound.value.seek()
|
||||
|
@ -277,11 +274,16 @@ const getSound = (trackData: Track) => {
|
|||
store.commit('player/duration', sound.duration())
|
||||
},
|
||||
|
||||
onplayerror (soundId, error) {
|
||||
console.log('play error', soundId, error)
|
||||
},
|
||||
|
||||
onloaderror (soundId, error) {
|
||||
console.log('load error', soundId, error)
|
||||
soundCache.delete(trackData.id)
|
||||
sound.unload()
|
||||
|
||||
if (sound !== currentSound.value) {
|
||||
if (this !== currentSound.value) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -298,6 +300,7 @@ const getSound = (trackData: Track) => {
|
|||
|
||||
return sound
|
||||
}
|
||||
|
||||
const getTrack = async (trackData: Track) => {
|
||||
// use previously fetched trackData
|
||||
if (trackData.uploads.length) {
|
||||
|
@ -372,7 +375,8 @@ const loadSound = async (trackData: Track, oldValue?: Track) => {
|
|||
handleError()
|
||||
}
|
||||
|
||||
currentSound.value = getSound(trackData as Track)
|
||||
currentSound.value = getSound(trackData)
|
||||
|
||||
// TODO (wvffle): #1777
|
||||
soundId.value = currentSound.value.play()
|
||||
store.commit('player/isLoadingAudio', true)
|
||||
|
@ -576,8 +580,11 @@ const switchTab = () => {
|
|||
<span
|
||||
class="start"
|
||||
@click.stop.prevent="setCurrentTime(0)"
|
||||
>{{ currentTimeFormatted }}</span>
|
||||
| <span class="total">{{ durationFormatted }}</span>
|
||||
>
|
||||
{{ currentTimeFormatted }}
|
||||
</span>
|
||||
|
|
||||
<span class="total">{{ durationFormatted }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,41 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useStore } from '~/store'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { useTimeoutFn } from '@vueuse/core'
|
||||
import usePlayer from '~/composables/audio/usePlayer'
|
||||
|
||||
const store = useStore()
|
||||
const { volume, mute, unmute } = usePlayer()
|
||||
|
||||
const expanded = ref(false)
|
||||
const volumeSteps = 100
|
||||
|
||||
const sliderVolume = computed({
|
||||
get: () => volume.value * volumeSteps,
|
||||
set: (value) => store.commit('player/volume', value / volumeSteps)
|
||||
})
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
const labels = computed(() => ({
|
||||
unmute: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Unmute'),
|
||||
mute: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Mute'),
|
||||
slider: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Adjust volume')
|
||||
}))
|
||||
|
||||
const { start, stop } = useTimeoutFn(() => (expanded.value = false), 500, { immediate: false })
|
||||
|
||||
const handleOver = () => {
|
||||
stop()
|
||||
expanded.value = true
|
||||
}
|
||||
|
||||
const handleLeave = () => {
|
||||
stop()
|
||||
start()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
class="circular control button"
|
||||
|
@ -49,52 +87,3 @@
|
|||
</div>
|
||||
</button>
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions } from 'vuex'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
expanded: false,
|
||||
timeout: null,
|
||||
volumeSteps: 100
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
sliderVolume: {
|
||||
get () {
|
||||
return this.$store.state.player.volume * this.volumeSteps
|
||||
},
|
||||
set (v) {
|
||||
this.$store.commit('player/volume', v / this.volumeSteps)
|
||||
}
|
||||
},
|
||||
labels () {
|
||||
return {
|
||||
unmute: this.$pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Unmute'),
|
||||
mute: this.$pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Mute'),
|
||||
slider: this.$pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Adjust volume')
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
mute: 'player/mute',
|
||||
unmute: 'player/unmute',
|
||||
toggleMute: 'player/toggleMute'
|
||||
}),
|
||||
handleOver () {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout)
|
||||
}
|
||||
this.expanded = true
|
||||
},
|
||||
handleLeave () {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout)
|
||||
}
|
||||
this.timeout = setTimeout(() => { this.expanded = false }, 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { computed, watchEffect } from "vue"
|
||||
import { Howler } from 'howler'
|
||||
import useQueue from '~/composables/useQueue'
|
||||
import useQueue from '~/composables/audio/useQueue'
|
||||
import toLinearVolumeScale from '~/composables/audio/toLinearVolumeScale'
|
||||
import store from "~/store"
|
||||
|
||||
|
@ -19,6 +19,10 @@ export default () => {
|
|||
|
||||
watchEffect(() => Howler.volume(toLinearVolumeScale(volume.value)))
|
||||
|
||||
const mute = () => store.dispatch('player/mute')
|
||||
const unmute = () => store.dispatch('player/unmute')
|
||||
const toggleMute = () => store.dispatch('player/toggleMute')
|
||||
|
||||
// Time and duration
|
||||
const duration = computed(() => store.state.player.duration)
|
||||
const currentTime = computed(() => store.state.player.currentTime)
|
||||
|
@ -65,6 +69,9 @@ export default () => {
|
|||
focused,
|
||||
|
||||
volume,
|
||||
mute,
|
||||
unmute,
|
||||
toggleMute,
|
||||
|
||||
duration,
|
||||
currentTime,
|
|
@ -19,11 +19,11 @@ export default (maxPreloaded: MaybeRef<number>) => {
|
|||
if (toRemove > 0 && !cleaningCache.value) {
|
||||
cleaningCache.value = true
|
||||
|
||||
const excess = sortBy(soundCache.values(), [(cached: CachedSound) => cached.date])
|
||||
// TODO (wvffle): Check if works
|
||||
.slice(0, toRemove) as unknown as CachedSound[]
|
||||
const excess = sortBy([...soundCache.values()], [(cached: CachedSound) => cached.date])
|
||||
.slice(0, toRemove)
|
||||
|
||||
for (const cached of excess) {
|
||||
console.log('Removing cached element:', cached)
|
||||
soundCache.delete(cached.id)
|
||||
cached.sound.unload()
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Track } from "~/types"
|
||||
import { useStore } from '~/store'
|
||||
import store from '~/store'
|
||||
import updateQueryString from '~/composables/updateQueryString'
|
||||
|
||||
export interface TrackSource {
|
||||
|
@ -8,7 +8,6 @@ export interface TrackSource {
|
|||
}
|
||||
|
||||
export default (trackData: Track): TrackSource[] => {
|
||||
const store = useStore()
|
||||
const audio = document.createElement('audio')
|
||||
|
||||
const allowed = ['probably', 'maybe']
|
||||
|
|
|
@ -7,11 +7,11 @@ export const install: InitModule = ({ app }) => {
|
|||
// this is needed to unlock audio playing under some browsers,
|
||||
// cf https://github.com/goldfire/howler.js#mobilechrome-playback
|
||||
// but we never actually load those audio files
|
||||
const dummyAudio = new Howl({
|
||||
preload: false,
|
||||
autoplay: false,
|
||||
src: ['noop.webm', 'noop.mp3']
|
||||
})
|
||||
// const dummyAudio = new Howl({
|
||||
// preload: false,
|
||||
// autoplay: false,
|
||||
// src: ['noop.webm', 'noop.mp3']
|
||||
// })
|
||||
|
||||
return dummyAudio
|
||||
// return dummyAudio
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { InitModule } from '~/types'
|
||||
import { whenever } from '@vueuse/core'
|
||||
import useQueue from '~/composables/useQueue'
|
||||
import usePlayer from '~/composables/usePlayer'
|
||||
import useQueue from '~/composables/audio/useQueue'
|
||||
import usePlayer from '~/composables/audio/usePlayer'
|
||||
|
||||
export const install: InitModule = ({ app }) => {
|
||||
const { currentTrack, next, previous } = useQueue()
|
||||
|
|
|
@ -95,10 +95,6 @@ const store: Module<State, RootState> = {
|
|||
},
|
||||
getters: {
|
||||
durationFormatted: state => {
|
||||
if (state.duration % 1 !== 0) {
|
||||
return time.parse(0)
|
||||
}
|
||||
|
||||
return time.parse(Math.round(state.duration))
|
||||
},
|
||||
currentTimeFormatted: state => {
|
||||
|
|
Loading…
Reference in New Issue