Newer
Older
Eliot Berriot
committed
<i />
</template>
<script>
import {mapState} from 'vuex'
Eliot Berriot
committed
import url from '@/utils/url'
import {Howl} from 'howler'
// import logger from '@/logging'
export default {
props: {
track: {type: Object},
isCurrent: {type: Boolean, default: false},
startTime: {type: Number, default: 0},
autoplay: {type: Boolean, default: false}
Eliot Berriot
committed
sound: null,
isUpdatingTime: false,
progressInterval: null
Eliot Berriot
committed
mounted () {
let self = this
this.sound = new Howl({
src: this.srcs.map((s) => { return s.url }),
format: this.srcs.map((s) => { return s.type }),
Eliot Berriot
committed
autoplay: false,
loop: false,
html5: true,
preload: true,
volume: this.volume,
onend: function () {
self.ended()
},
onunlock: function () {
if (this.$store.state.player.playing) {
self.sound.play()
}
},
onload: function () {
Eliot Berriot
committed
self.$store.commit('player/isLoadingAudio', false)
Eliot Berriot
committed
self.$store.commit('player/resetErrorCount')
self.$store.commit('player/duration', self.sound.duration())
Eliot Berriot
committed
let node = self.sound._sounds[0]._node;
node.addEventListener('progress', () => {
self.updateBuffer(node)
})
Eliot Berriot
committed
}
})
if (this.autoplay) {
Eliot Berriot
committed
self.$store.commit('player/isLoadingAudio', true)
Eliot Berriot
committed
this.sound.play()
this.$store.commit('player/playing', true)
this.observeProgress(true)
}
},
destroyed () {
this.observeProgress(false)
this.sound.unload()
},
computed: {
...mapState({
playing: state => state.player.playing,
currentTime: state => state.player.currentTime,
duration: state => state.player.duration,
volume: state => state.player.volume,
looping: state => state.player.looping
}),
// let file = this.track.files[0]
// if (!file) {
// this.$store.dispatch('player/trackErrored')
// return []
// }
{type: 'mp3', url: this.$store.getters['instance/absoluteUrl'](this.track.listen_url)}
if (this.$store.state.auth.authenticated) {
// we need to send the token directly in url
// so authentication can be checked by the backend
// because for audio files we cannot use the regular Authentication
// header
sources.forEach(e => {
e.url = url.updateQueryString(e.url, 'jwt', this.$store.state.auth.token)
})
Eliot Berriot
committed
},
updateProgressThrottled () {
return _.throttle(this.updateProgress, 250)
}
},
methods: {
Eliot Berriot
committed
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
updateBuffer (node) {
// from https://github.com/goldfire/howler.js/issues/752#issuecomment-372083163
let range = 0;
let bf = node.buffered;
let time = node.currentTime;
try {
while(!(bf.start(range) <= time && time <= bf.end(range))) {
range += 1;
}
} catch (IndexSizeError) {
return
}
let loadPercentage
let start = bf.start(range)
let end = bf.end(range)
if (range === 0) {
// easy case, no user-seek
let loadStartPercentage = start / node.duration;
let loadEndPercentage = end / node.duration;
loadPercentage = loadEndPercentage - loadStartPercentage;
} else {
let loaded = end - start
let remainingToLoad = node.duration - start
// user seeked a specific position in the audio, our progress must be
// computed based on the remaining portion of the track
loadPercentage = loaded / remainingToLoad;
}
this.$store.commit('player/bufferProgress', loadPercentage * 100)
},
Eliot Berriot
committed
updateProgress: function () {
Eliot Berriot
committed
if (this.sound && this.sound.state() === 'loaded') {
this.$store.dispatch('player/updateProgress', this.sound.seek())
Eliot Berriot
committed
this.updateBuffer(this.sound._sounds[0]._node)
Eliot Berriot
committed
},
Eliot Berriot
committed
observeProgress: function (enable) {
let self = this
if (enable) {
if (self.progressInterval) {
clearInterval(self.progressInterval)
}
self.progressInterval = setInterval(() => {
self.updateProgress()
}, 1000)
Eliot Berriot
committed
clearInterval(self.progressInterval)
}
},
setCurrentTime (t) {
if (t < 0 | t > this.duration) {
return
}
Eliot Berriot
committed
if (t === this.sound.seek()) {
Eliot Berriot
committed
return
}
if (t === 0) {
this.updateProgressThrottled.cancel()
}
Eliot Berriot
committed
this.sound.seek(t)
},
ended: function () {
let onlyTrack = this.$store.state.queue.tracks.length === 1
if (this.looping === 1 || (onlyTrack && this.looping === 2)) {
this.sound.seek(0)
this.sound.play()
} else {
this.$store.dispatch('player/trackEnded', this.track)
}
}
},
watch: {
playing: function (newValue) {
if (newValue === true) {
Eliot Berriot
committed
this.sound.play()
Eliot Berriot
committed
this.sound.pause()
Eliot Berriot
committed
}
Eliot Berriot
committed
this.observeProgress(newValue)
Eliot Berriot
committed
},
volume: function (newValue) {
Eliot Berriot
committed
this.sound.volume(newValue)
},
currentTime (newValue) {
if (!this.isUpdatingTime) {
this.setCurrentTime(newValue)
}
this.isUpdatingTime = false
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>