From f06295a5b39f11493f956a43389e631b9a20218f Mon Sep 17 00:00:00 2001 From: Eliot Berriot <contact@eliotberriot.com> Date: Tue, 23 Oct 2018 20:24:36 +0200 Subject: [PATCH] Fix #586: The progress bar in the player now display loading state / buffer loading --- changes/changelog.d/586.enhancement | 1 + front/src/components/audio/Player.vue | 47 ++++++++++++++++++++++++++- front/src/components/audio/Track.vue | 36 ++++++++++++++++++++ front/src/store/player.js | 8 +++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 changes/changelog.d/586.enhancement diff --git a/changes/changelog.d/586.enhancement b/changes/changelog.d/586.enhancement new file mode 100644 index 00000000..bee8c1c9 --- /dev/null +++ b/changes/changelog.d/586.enhancement @@ -0,0 +1 @@ +The progress bar in the player now display loading state / buffer loading (#586) diff --git a/front/src/components/audio/Player.vue b/front/src/components/audio/Player.vue index 5387d02b..1d622f33 100644 --- a/front/src/components/audio/Player.vue +++ b/front/src/components/audio/Player.vue @@ -51,7 +51,11 @@ <p class="timer total">{{durationFormatted}}</p> </div> </div> - <div ref="progress" class="ui small orange inverted progress" @click="touchProgress"> + <div + ref="progress" + :class="['ui', 'small', 'orange', 'inverted', {'indicating': isLoadingAudio}, 'progress']" + @click="touchProgress"> + <div class="buffer bar" :data-percent="bufferProgress" :style="{ 'width': bufferProgress + '%' }"></div> <div class="bar" :data-percent="progress" :style="{ 'width': progress + '%' }"></div> </div> </div> @@ -301,9 +305,11 @@ export default { ...mapState({ currentIndex: state => state.queue.currentIndex, playing: state => state.player.playing, + isLoadingAudio: state => state.player.isLoadingAudio, volume: state => state.player.volume, looping: state => state.player.looping, duration: state => state.player.duration, + bufferProgress: state => state.player.bufferProgress, queue: state => state.queue }), ...mapGetters({ @@ -522,4 +528,43 @@ export default { margin: 0; } + +@keyframes MOVE-BG { + from { + transform: translateX(0px); + } + to { + transform: translateX(46px); + } +} + +.indicating.progress { + overflow: hidden; +} + +.ui.progress .bar { + transition: none; +} + +.ui.inverted.progress .buffer.bar { + position: absolute; + background-color:rgba(255, 255, 255, 0.15); +} +.indicating.progress .bar { + left: -46px; + width: 200% !important; + color: grey; + background: repeating-linear-gradient( + -55deg, + grey 1px, + grey 10px, + transparent 10px, + transparent 20px, + ) !important; + + animation-name: MOVE-BG; + animation-duration: 2s; + animation-timing-function: linear; + animation-iteration-count: infinite; +} </style> diff --git a/front/src/components/audio/Track.vue b/front/src/components/audio/Track.vue index 5626dd4d..32eb6272 100644 --- a/front/src/components/audio/Track.vue +++ b/front/src/components/audio/Track.vue @@ -44,11 +44,17 @@ export default { } }, onload: function () { + self.$store.commit('player/isLoadingAudio', false) self.$store.commit('player/resetErrorCount') self.$store.commit('player/duration', self.sound.duration()) + let node = self.sound._sounds[0]._node; + node.addEventListener('progress', () => { + self.updateBuffer(node) + }) } }) if (this.autoplay) { + self.$store.commit('player/isLoadingAudio', true) this.sound.play() this.$store.commit('player/playing', true) this.observeProgress(true) @@ -91,10 +97,40 @@ export default { } }, methods: { + 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) + }, updateProgress: function () { this.isUpdatingTime = true if (this.sound && this.sound.state() === 'loaded') { this.$store.dispatch('player/updateProgress', this.sound.seek()) + this.updateBuffer(this.sound._sounds[0]._node) } }, observeProgress: function (enable) { diff --git a/front/src/store/player.js b/front/src/store/player.js index dc01f368..08492541 100644 --- a/front/src/store/player.js +++ b/front/src/store/player.js @@ -8,11 +8,13 @@ export default { maxConsecutiveErrors: 5, errorCount: 0, playing: false, + isLoadingAudio: false, volume: 0.5, tempVolume: 0.5, duration: 0, currentTime: 0, errored: false, + bufferProgress: 0, looping: 0 // 0 -> no, 1 -> on track, 2 -> on queue }, mutations: { @@ -59,12 +61,18 @@ export default { playing (state, value) { state.playing = value }, + bufferProgress (state, value) { + state.bufferProgress = value + }, toggleLooping (state) { if (state.looping > 1) { state.looping = 0 } else { state.looping += 1 } + }, + isLoadingAudio (state, value) { + state.isLoadingAudio = value } }, getters: { -- GitLab