diff --git a/app/client/src/App.vue b/app/client/src/App.vue index 5e03f8d..ae85407 100644 --- a/app/client/src/App.vue +++ b/app/client/src/App.vue @@ -255,7 +255,7 @@ - {{$duration($root.position)}} {{qualityText}} + {{$duration($root.position())}} {{qualityText}} @@ -562,8 +562,8 @@ export default { this.volume = this.$root.volume; }, //Update position - '$root.position'() { - this.position = (this.$root.position / this.$root.duration()) * 100; + '$root.positionVal'() { + this.position = (this.$root.position() / this.$root.duration()) * 100; }, //Global snackbar '$root.globalSnackbar'() { diff --git a/app/client/src/components/AlbumTile.vue b/app/client/src/components/AlbumTile.vue index 223124f..69a998f 100644 --- a/app/client/src/components/AlbumTile.vue +++ b/app/client/src/components/AlbumTile.vue @@ -134,8 +134,8 @@ export default { source: 'album', data: album.id }; - this.$root.replaceQueue(album.tracks); - this.$root.playIndex(0); + await this.$root.replaceQueue(album.tracks); + await this.$root.playIndex(0); }, //Add to queue async addQueue() { diff --git a/app/client/src/components/LibraryHistory.vue b/app/client/src/components/LibraryHistory.vue index 1e8fbb4..e85f6bc 100644 --- a/app/client/src/components/LibraryHistory.vue +++ b/app/client/src/components/LibraryHistory.vue @@ -54,14 +54,14 @@ export default { this.loading = false; }, //Load as queue and play - play(index) { + async play(index) { this.$root.queue.source = { text: this.$t('History'), source: 'history', data: null }; - this.$root.replaceQueue(this.tracks); - this.$root.playIndex(index); + await this.$root.replaceQueue(this.tracks); + await this.$root.playIndex(index); } }, mounted() { diff --git a/app/client/src/components/LibraryTracks.vue b/app/client/src/components/LibraryTracks.vue index 8719836..621938a 100644 --- a/app/client/src/components/LibraryTracks.vue +++ b/app/client/src/components/LibraryTracks.vue @@ -112,13 +112,13 @@ export default { source: 'playlist', data: this.$root.profile.favoritesPlaylist }; - this.$root.replaceQueue(this.tracks); - this.$root.playIndex(this.tracks.findIndex(t => t.id == id)); + await this.$root.replaceQueue(this.tracks); + await this.$root.playIndex(this.tracks.findIndex(t => t.id == id)); //Load all tracks if (this.tracks.length < this.count) { - this.loadAll().then(() => { - this.$root.replaceQueue(this.tracks); + this.loadAll().then(async () => { + await this.$root.replaceQueue(this.tracks); }); } }, diff --git a/app/client/src/components/Lyrics.vue b/app/client/src/components/Lyrics.vue index 4552e09..4d6e681 100644 --- a/app/client/src/components/Lyrics.vue +++ b/app/client/src/components/Lyrics.vue @@ -71,19 +71,19 @@ export default { }, //Wether current lyric is playing rn playingNow(i) { - if (!this.$root.audio) return false; + if (!this.$root.playback || !this.$root.playback.audio) return false; //First & last lyric check if (i == this.lyrics.lyrics.length - 1) { - if (this.lyrics.lyrics[i].offset <= this.$root.position) return true; + if (this.lyrics.lyrics[i].offset <= this.$root.position()) return true; return false; } - if (this.$root.position >= this.lyrics.lyrics[i].offset && this.$root.position < this.lyrics.lyrics[i+1].offset) return true; + if (this.$root.position() >= this.lyrics.lyrics[i].offset && this.$root.position() < this.lyrics.lyrics[i+1].offset) return true; return false; }, //Get index of current lyric currentLyric() { - if (!this.$root.audio) return 0; + if (!this.$root.playback || !this.$root.playback.audio) return 0; return this.lyrics.lyrics.findIndex((l) => { return this.playingNow(this.lyrics.lyrics.indexOf(l)); }); @@ -118,7 +118,7 @@ export default { this.load(); } }, - '$root.position'() { + '$root.positionVal'() { this.scrollLyric(); } } diff --git a/app/client/src/components/PlaylistTile.vue b/app/client/src/components/PlaylistTile.vue index 4f6f987..3ca8fc4 100644 --- a/app/client/src/components/PlaylistTile.vue +++ b/app/client/src/components/PlaylistTile.vue @@ -146,8 +146,8 @@ export default { source: 'playlist', data: playlist.id }; - this.$root.replaceQueue(playlist.tracks); - this.$root.playIndex(0); + await this.$root.replaceQueue(playlist.tracks); + await this.$root.playIndex(0); //Load all tracks if (playlist.tracks.length != playlist.trackCount) { diff --git a/app/client/src/components/SmartTrackList.vue b/app/client/src/components/SmartTrackList.vue index e6ad5a0..1d180c9 100644 --- a/app/client/src/components/SmartTrackList.vue +++ b/app/client/src/components/SmartTrackList.vue @@ -40,8 +40,8 @@ export default { source: 'smarttracklist', data: this.stl.id }; - this.$root.replaceQueue(res.data); - this.$root.playIndex(0); + await this.$root.replaceQueue(res.data); + await this.$root.playIndex(0); this.loading = false; } diff --git a/app/client/src/components/TrackTile.vue b/app/client/src/components/TrackTile.vue index 03afe80..c659ae3 100644 --- a/app/client/src/components/TrackTile.vue +++ b/app/client/src/components/TrackTile.vue @@ -198,8 +198,8 @@ export default { }, methods: { //Add track next to queue - playNext() { - this.$root.addTrackIndex(this.track, this.$root.queue.index+1); + async playNext() { + await this.$root.addTrackIndex(this.track, this.$root.queue.index + 1); }, addQueue() { this.$root.queue.data.push(this.track); @@ -250,8 +250,8 @@ export default { source: 'trackmix', data: this.track.id }; - this.$root.replaceQueue(res.data); - this.$root.playIndex(0); + await this.$root.replaceQueue(res.data); + await this.$root.playIndex(0); }, //Copy link share() { diff --git a/app/client/src/main.js b/app/client/src/main.js index ea4d49b..2d3fe17 100644 --- a/app/client/src/main.js +++ b/app/client/src/main.js @@ -69,15 +69,15 @@ new Vue({ downloads: {}, + cancelSource: axios.CancelToken.source(), + //Player track: null, - audio: null, + playback: null, volume: 0.00, - //0 = Stopped, 1 = Paused, 2 = Playing, 3 = Loading - state: 0, - loaders: 0, + loading: false, playbackInfo: {}, - position: 0, + positionVal: 0, muted: false, //Gapless playback meta gapless: { @@ -88,7 +88,7 @@ new Vue({ }, //0 - normal, 1 - repeat list, 2 - repeat track - repeat: 0, + repeatMode: 0, shuffled: false, //Library cache @@ -122,64 +122,110 @@ new Vue({ methods: { // PLAYBACK METHODS isPlaying() { - return this.state == 2; + return this.playback && this.playback.state >= 1; }, - play() { - if (!this.audio || this.state != 1) return; - this.audio.play(); - this.state = 2; + //Repeat button click + async repeatClick() { + if (this.repeatMode == 2) { + if (this.playback) this.playback.audio.loop = false; + this.repeatMode = 0; + await this.savePlaybackInfo(); + return; + } + this.repeatMode += 1; + if (this.repeatMode == 2) { + if (this.playback) this.playback.audio.loop = true; + } + await this.savePlaybackInfo(); + }, + + async play(playback) { + playback = playback || this.playback; + if (!playback || playback.state != 0) return; + playback.state = 1; + if(playback.audio) { + if (playback.position) { + playback.audio.currentTime = playback.position / 1000; + playback.position = null; + } + await playback.audio.play(); + if (playback.state == 0) playback.audio.pause(); + else playback.state = 2; + } }, - pause() { - if (!this.audio || this.state != 2) return; - this.audio.pause(); - this.state = 1; + + pause(playback) { + playback = playback || this.playback; + if (!playback || playback.state == 0) return; + if (playback.state == 2) playback.audio.pause(); + playback.state = 0; }, toggle() { if (this.isPlaying()) return this.pause(); this.play(); }, seek(t) { - if (!this.audio || isNaN(t) || !t) return; + if (isNaN(t) || (!t && t !== 0) || !this.playback) return; + if (!this.playback.audio) { + this.playback.position = t; + return; + } //ms -> s - this.audio.currentTime = (t / 1000); - this.position = t; - + this.playback.audio.currentTime = t / 1000; + this.positionVal = t; this.updateState(); }, + position() { + if (!this.playback) return 0; + if (!this.playback.audio) return this.playback.position; + return this.playback.audio.currentTime * 1000; + }, + //Current track duration duration() { //Prevent 0 division - if (!this.audio) return 1; - return this.audio.duration * 1000; + if (!this.playback || !this.playback.audio || !this.playback.audio.duration) + return (this.track ? this.track.duration : 0) || 1; + return this.playback.audio.duration * 1000; }, //Replace queue, has to make clone of data to not keep references - replaceQueue(newQueue) { + async replaceQueue(newQueue) { this.queue.data = Object.assign([], newQueue); + await this.savePlaybackInfo(); }, + //Add track to queue at index - addTrackIndex(track, index) { + async addTrackIndex(track, index) { this.queue.data.splice(index, 0, track); + await this.savePlaybackInfo(); }, //Play at index in queue async playIndex(index) { if (index >= this.queue.data.length || index < 0) return; this.queue.index = index; - await this.playTrack(this.queue.data[this.queue.index]); - this.play(); - this.savePlaybackInfo(); + await this.playTrack(this.queue.data[this.queue.index], true); + await this.savePlaybackInfo(); }, //Skip n tracks, can be negative async skip(n) { let newIndex = this.queue.index + n; + // Loop entire list + if (this.repeatMode == 1) { + newIndex %= this.queue.data.length; + while (newIndex < 0) newIndex += this.queue.data.length; + } //Out of bounds - if (newIndex < 0 || newIndex >= this.queue.data.length) return; - await this.playIndex(newIndex); + if (newIndex >= this.queue.data.length) return; + // Just seek to track start if attempting to skip -1 on the first track + if (newIndex < 0) await this.seek(0); + else await this.playIndex(newIndex); }, - shuffle() { + + async shuffle() { if (!this.shuffled) { //Save positions for (let i=0; i t.id == this.track.id); this.shuffled = true; + await this.savePlaybackInfo(); return; - } - //Restore unshuffled queue - if (this.shuffled) { + } else { + //Restore unshuffled queue this.queue.data.sort((a, b) => (a._position || 10000) - (b._position || 10000)); this.queue.index = this.queue.data.findIndex(t => t.id == this.track.id); this.shuffled = false; + await this.savePlaybackInfo(); return; } }, //Skip wrapper - skipNext() { - this.skip(1); - this.savePlaybackInfo(); + async skipNext() { + await this.skip(1); + await this.savePlaybackInfo(); }, + async skipPrev() { + if (this.position() >= 10000) await this.seek(0); + else await this.skip(-1); + await this.savePlaybackInfo(); + }, + toggleMute() { - if (this.audio) this.audio.muted = !this.audio.muted; + if (this.playback && this.playback.audio) this.playback.audio.muted = !this.playback.audio.muted; this.muted = !this.muted; }, - async playTrack(track) { + async playTrack(track, autoplay) { if (!track || !track.streamUrl) return; + if (this.loading) { + this.cancelSource.cancel(); + this.cancelSource = axios.CancelToken.source(); + } this.resetGapless(); - this.track = track; - this.loaders++; - this.state = 3; + this.loading = true; //Stop audio - let autoplay = (this.state == 2); - if (this.audio) this.audio.pause(); - if (this.audio) this.audio.currentTime = 0; + if (this.playback && this.playback.audio) { + this.pause(); + this.playback.audio.removeEventListener('timeupdate', this.onTimeUpdate); + this.playback.audio.removeEventListener('ended', this.onEnded); + } + this.playback = { + audio: null, + state: autoplay ? 1 : 0, + }; + this.track = track; + this.positionVal = 0; //Load track meta - let playbackInfo = await this.loadPlaybackInfo(track.streamUrl, track.duration); - if (!playbackInfo) { - this.loaders--; - this.skipNext(); + let playbackInfo; + try { + playbackInfo = await this.loadPlaybackInfo(track.streamUrl, track.duration, this.cancelSource.token); + if (!playbackInfo) { + this.loading = false; + this.skipNext(); + return; + } + } catch (err) { // canceled return; } this.playbackInfo = playbackInfo; @@ -242,108 +310,105 @@ new Vue({ else url = this.playbackInfo.direct; //Cancel loading - this.loaders--; - if (this.loaders > 0) { - return; - } - + this.loading = false; //Audio - this.audio = new Audio(url); + autoplay = this.playback.state >= 1; + let position = this.playback.position; + this.playback = { + state: 0, + audio: new Audio(url), + position, + }; this.configureAudio(); - this.state = 1; - if (autoplay) this.play(); //MediaSession this.updateMediaSession(); - + if (autoplay) + await this.play(); //Loads more tracks if end of list this.loadSTL(); }, //Configure html audio element configureAudio() { + this.playback.audio.loop = this.repeatMode == 2; + this.playback.audio.muted = this.muted; + this.playback.audio.volume = this.volume * this.volume; + //Listen position updates - this.audio.addEventListener('timeupdate', async () => { - this.position = this.audio.currentTime * 1000; + this.playback.audio.addEventListener('timeupdate', this.onTimeUpdate); + this.playback.audio.addEventListener('ended', this.onEnded); + }, + async onTimeUpdate() { + this.positionVal = this.position(); + //Gapless playback + if (this.position() >= (this.duration() - (this.settings.crossfadeDuration + 10000)) && this.isPlaying()) { + this.loadGapless(); + } - //Gapless playback - if (this.position >= (this.duration() - (this.settings.crossfadeDuration + 7500)) && this.state == 2) { - if (this.repeat != 2) - this.loadGapless(); + //Crossfade + if (this.settings.crossfadeDuration > 0 && this.position() >= (this.duration() - this.settings.crossfadeDuration) && this.isPlaying() && this.gapless.audio && !this.gapless.crossfade && this.gapless.track) { + this.gapless.crossfade = true; + let oldPlayback = this.playback; + if (!oldPlayback) return; + let currentVolume = oldPlayback.audio.volume; + let playback = { + audio: this.gapless.audio, + state: 0, // start as paused + }; + this.playback = playback; + await this.play(playback); + + //Update meta + this.playbackInfo = this.gapless.info; + this.track = this.gapless.track; + this.queue.index = this.gapless.index; + + this.configureAudio(); + this.updateMediaSession(); + + playback.audio.volume = 0.0; + let volumeStep = currentVolume / (this.settings.crossfadeDuration / 50); + for (let i = 0; i < this.settings.crossfadeDuration / 50; i++) { + oldPlayback.audio.volume = Math.max(oldPlayback.audio.volume - volumeStep, 0); + if (playback.audio.volume + volumeStep >= Math.min(1.0, currentVolume)) + break; + playback.audio.volume += volumeStep; + await new Promise(res => setTimeout(() => res(), 50)); } - - //Crossfade - if (this.settings.crossfadeDuration > 0 && this.position >= (this.duration() - this.settings.crossfadeDuration) && this.state == 2 && this.gapless.audio && !this.gapless.crossfade && this.gapless.track) { - this.gapless.crossfade = true; - let currentVolume = this.audio.volume; - let oldAudio = this.audio; - this.audio = this.gapless.audio; - this.audio.play(); - - //Update meta - this.playbackInfo = this.gapless.info; - this.track = this.gapless.track; - this.queue.index = this.gapless.index; - - this.configureAudio(); - this.updateMediaSession(); - - this.audio.volume = 0.0; - let volumeStep = currentVolume / (this.settings.crossfadeDuration / 50); - for (let i=0; i<(this.settings.crossfadeDuration / 50); i++) { - if ((oldAudio.volume - volumeStep) > 0) - oldAudio.volume -= volumeStep; - if ((this.audio.volume + volumeStep) >= 1.0 || (this.audio.volume + volumeStep) >= currentVolume) - break; - this.audio.volume += volumeStep; - await new Promise((res) => setTimeout(() => res(), 50)); - } - //Restore original volume - this.audio.voume = currentVolume; - - oldAudio.pause(); - + //Restore original volume + playback.audio.volume = currentVolume; + await this.pause(oldPlayback); + + if (this.playback === playback) { this.resetGapless(); this.updateState(); //Save await this.savePlaybackInfo(); } + } - //Scrobble/LogListen - if (this.position >= this.duration() * 0.75) { - this.logListen(); - } - }); - this.audio.muted = this.muted; - //Set volume - this.audio.volume = this.volume * this.volume; - - this.audio.addEventListener('ended', async () => { - if (this.gapless.crossfade) return; - - //Repeat track - if (this.repeat == 2) { - this.seek(0); - this.audio.play(); - this.updateState(); - return; - } + //Scrobble/LogListen + if (this.position() >= this.duration() * 0.75) { + this.logListen(); + } + }, + async onEnded() { + if (this.gapless.crossfade) return; - //Repeat list - if (this.repeat == 1 && this.queue.index == this.queue.data.length - 1) { - this.skip(-(this.queue.data.length - 1)); - return; - } + //Repeat track + if (this.repeatMode == 2) { + this.updateState(); + return; + } - //End of queue - if (this.queue.index+1 == this.queue.data.length) { - this.state = 1; - return; - } + //End of queue + if (this.repeatMode == 0 && this.queue.index + 1 == this.queue.data.length) { + return; + } - //Skip to next track - this.skip(1); - this.savePlaybackInfo(); - }); + //Skip to next track + this.skip(1); + this.savePlaybackInfo(); }, //Update media session with current track metadata updateMediaSession() { @@ -360,24 +425,27 @@ new Vue({ ] }); //Controls - navigator.mediaSession.setActionHandler('play', this.play); - navigator.mediaSession.setActionHandler('pause', this.pause); - navigator.mediaSession.setActionHandler('nexttrack', this.skipNext); - navigator.mediaSession.setActionHandler('previoustrack', () => this.skip(-1)); + navigator.mediaSession.setActionHandler('play', async () => await this.play()); + navigator.mediaSession.setActionHandler('pause', () => this.pause()); + navigator.mediaSession.setActionHandler('nexttrack', () => this.skipNext()); + navigator.mediaSession.setActionHandler('previoustrack', () => this.skipPrev()); }, //Get Deezer CDN image url getImageUrl(img, size = 256) { return `https://e-cdns-images.dzcdn.net/images/${img.type}/${img.hash}/${size}x${size}-000000-80-0-0.jpg` }, - async loadPlaybackInfo(streamUrl, duration) { + async loadPlaybackInfo(streamUrl, duration, cancelToken) { //Get playback info let quality = this.settings.streamQuality; let infoUrl = `/streaminfo/${streamUrl}?q=${quality}`; let res; try { - res = await this.$axios.get(infoUrl); - } catch (_) { + res = await this.$axios.get(infoUrl, cancelToken ? { cancelToken } : { }); + } catch (err) { + if (axios.isCancel(err)) { + throw err; + } return null; } @@ -399,19 +467,19 @@ new Vue({ //Reset gapless playback meta resetGapless() { - this.gapless = {crossfade: false,promise: null,audio: null,info: null,track: null,index:null}; + this.gapless = { crossfade: false, promise: null, audio: null, info: null, track: null, index: null }; }, //Load next track for gapless async loadGapless() { - if (this.loaders != 0 || this.gapless.promise || this.gapless.audio || this.gapless.crossfade) return; + if (this.repeatMode == 2 || this.loading || this.gapless.promise || this.gapless.audio || this.gapless.crossfade) return; //Repeat list - if (this.repeat == 1 && this.queue.index == this.queue.data.length - 1) { + if (this.repeatMode == 1 && this.queue.index == this.queue.data.length - 1) { this.gapless.track = this.queue.data[0]; this.gapless.index = 0; } else { //Last song - if (this.queue.index+1 >= this.queue.data.length) return; + if (this.queue.index + 1 >= this.queue.data.length) return; //Next song this.gapless.track = this.queue.data[this.queue.index + 1]; this.gapless.index = this.queue.index + 1; @@ -446,7 +514,7 @@ new Vue({ if (data.data) { this.queue.data = this.queue.data.concat(data.data); } - this.savePlaybackInfo(); + await this.savePlaybackInfo(); } }, @@ -464,9 +532,9 @@ new Vue({ async savePlaybackInfo() { let data = { queue: this.queue, - position: this.position, + position: this.position(), track: this.track, - repeat: this.repeat, + repeatMode: this.repeatMode, shuffled: this.shuffled } await this.$axios.post('/playback', data); @@ -503,22 +571,22 @@ new Vue({ //Send state update to integrations async updateState() { //Wait for duration - if (this.state == 2 && (this.duration() == null || isNaN(this.duration()))) { + if (this.isPlaying() && (this.duration() == null || isNaN(this.duration()))) { setTimeout(() => { this.updateState(); }, 500); return; } this.$io.emit('stateChange', { - position: this.position, + position: this.position(), duration: this.duration(), - state: this.state, + playing: this.isPlaying(), track: this.track }); //Update in electron if (this.settings.electron) { - ipcRenderer.send('playing', this.state == 2); + ipcRenderer.send('playing', this.isPlaying()); } }, updateLanguage(l) { @@ -574,10 +642,10 @@ new Vue({ if (pd.data != {}) { if (pd.data.queue) this.queue = pd.data.queue; if (pd.data.track) this.track = pd.data.track; - if (pd.data.repeat) this.repeat = pd.data.repeat; + if (pd.data.repeatMode) this.repeatMode = pd.data.repeatMode; if (pd.data.shuffled) this.shuffled = pd.data.shuffled; - this.playTrack(this.track).then(() => { - this.seek(pd.data.position); + this.playTrack(this.track).then(async () => { + await this.seek(pd.data.position); }); } @@ -607,10 +675,10 @@ new Vue({ this.toggle(); }); ipcRenderer.on('skipNext', () => { - this.skip(1); + this.skipNext(); }); ipcRenderer.on('skipPrev', () => { - this.skip(-1); + this.skipPrev(); }) } @@ -694,13 +762,13 @@ new Vue({ //K toggle playback if (e.code == "KeyK" || e.code == "Space") this.$root.toggle(); //L +10s (from YT) - if (e.code == "KeyL") this.$root.seek((this.position + 10000)); + if (e.code == "KeyL") this.$root.seek(this.position() + 10000); //J -10s (from YT) - if (e.code == "KeyJ") this.$root.seek((this.position - 10000)); + if (e.code == "KeyJ") this.$root.seek(this.position() - 10000); //-> +5s (from YT) - if (e.code == "ArrowRight") this.$root.seek((this.position + 5000)); + if (e.code == "ArrowRight") this.$root.seek(this.position() + 5000); //<- -5s (from YT) - if (e.code == "ArrowLeft") this.$root.seek((this.position - 5000)); + if (e.code == "ArrowLeft") this.$root.seek(this.position() - 5000); // ^ v - Volume if (e.code == 'ArrowUp') { if ((this.volume + 0.05) > 1) { @@ -727,8 +795,8 @@ new Vue({ }, //Update volume with curve volume() { - if (this.audio) - this.audio.volume = this.volume * this.volume; + if (this.playback && this.playback.audio) + this.playback.audio.volume = this.volume * this.volume; } }, diff --git a/app/client/src/views/AlbumPage.vue b/app/client/src/views/AlbumPage.vue index 6dcc72f..4cd2312 100644 --- a/app/client/src/views/AlbumPage.vue +++ b/app/client/src/views/AlbumPage.vue @@ -93,18 +93,18 @@ export default { }, methods: { //Load album and play at index - playTrack(index) { + async playTrack(index) { this.$root.queue.source = { text: this.album.title, source: 'album', data: this.album.id }; - this.$root.replaceQueue(this.album.tracks); - this.$root.playIndex(index); + await this.$root.replaceQueue(this.album.tracks); + await this.$root.playIndex(index); }, //Play from beggining - play() { - this.playTrack(0); + async play() { + await this.playTrack(0); }, //Add to library async library() { diff --git a/app/client/src/views/ArtistPage.vue b/app/client/src/views/ArtistPage.vue index 8e045fc..c0a3ace 100644 --- a/app/client/src/views/ArtistPage.vue +++ b/app/client/src/views/ArtistPage.vue @@ -142,17 +142,17 @@ export default { artistData: Object }, methods: { - playIndex(index) { + async playIndex(index) { this.$root.queue.source = { text: this.artist.name, source: 'top', data: this.artist.id }; - this.$root.replaceQueue(this.artist.topTracks); - this.$root.playIndex(index); + await this.$root.replaceQueue(this.artist.topTracks); + await this.$root.playIndex(index); }, - play() { - this.playIndex(0); + async play() { + await this.playIndex(0); }, //Add to library async library() { @@ -212,8 +212,8 @@ export default { source: 'radio', data: this.artist.id }; - this.$root.replaceQueue(res.data); - this.$root.playIndex(0); + await this.$root.replaceQueue(res.data); + await this.$root.playIndex(0); } }, //On scroll load more albums diff --git a/app/client/src/views/FullscreenPlayer.vue b/app/client/src/views/FullscreenPlayer.vue index 29d9d31..bf5b352 100644 --- a/app/client/src/views/FullscreenPlayer.vue +++ b/app/client/src/views/FullscreenPlayer.vue @@ -51,7 +51,7 @@ - + mdi-skip-previous @@ -73,10 +73,10 @@
- - mdi-repeat - mdi-repeat - mdi-repeat-once + + mdi-repeat + mdi-repeat + mdi-repeat-once mdi-shuffle @@ -261,10 +261,10 @@ export default { data() { return { //Position used in seconds, because of CPU usage - position: this.$root.position / 1000, + position: this.$root.position() / 1000, seeking: false, tab: null, - inLibrary: this.$root.track.library ? true:false, + inLibrary: this.$root.track.library ? true : false, playlistPopup: false, downloadDialog: false, //For reloading queue @@ -313,14 +313,6 @@ export default { updateVolume(v) { this.$root.volume = v; }, - //Repeat button click - repeatClick() { - if (this.$root.repeat == 2) { - this.$root.repeat = 0; - return; - } - this.$root.repeat += 1; - }, //Copy link share() { let copyElem = document.createElement('input'); @@ -368,10 +360,8 @@ export default { '$root.track'() { this.inLibrary = this.$root.libraryTracks.includes(this.$root.track.id); }, - '$root.position'() { - if (!this.seeking) { - this.position = this.$root.position / 1000; - } + '$root.positionVal'() { + this.position = this.$root.position() / 1000; }, //Force update queue '$root.shuffled'() { diff --git a/app/client/src/views/Library.vue b/app/client/src/views/Library.vue index a5dc267..9dda0d5 100644 --- a/app/client/src/views/Library.vue +++ b/app/client/src/views/Library.vue @@ -88,8 +88,8 @@ export default { source: 'playlist', data: 0 }; - this.$root.replaceQueue(res.data); - this.$root.playIndex(0); + await this.$root.replaceQueue(res.data); + await this.$root.playIndex(0); } } }, diff --git a/app/client/src/views/PlaylistPage.vue b/app/client/src/views/PlaylistPage.vue index f211033..4762521 100644 --- a/app/client/src/views/PlaylistPage.vue +++ b/app/client/src/views/PlaylistPage.vue @@ -159,13 +159,13 @@ export default { source: 'playlist', data: this.playlist.id }; - this.$root.replaceQueue(this.playlist.tracks); - this.$root.playIndex(index); + await this.$root.replaceQueue(this.playlist.tracks); + await this.$root.playIndex(index); //Load rest of tracks on background if (this.playlist.tracks.length < this.playlist.trackCount) { - this.loadAllTracks().then(() => { - this.$root.replaceQueue(this.playlist.tracks); + this.loadAllTracks().then(async () => { + await this.$root.replaceQueue(this.playlist.tracks); }); } }, diff --git a/app/client/src/views/Search.vue b/app/client/src/views/Search.vue index ecc67c3..e7579bc 100644 --- a/app/client/src/views/Search.vue +++ b/app/client/src/views/Search.vue @@ -128,14 +128,14 @@ export default { }); }, //On click for track tile - playTrack(i) { + async playTrack(i) { this.$root.queue.source = { text: this.$t("Search"), source: "search", data: this.query }; - this.$root.replaceQueue(this.data.tracks); - this.$root.playIndex(i); + await this.$root.replaceQueue(this.data.tracks); + await this.$root.playIndex(i); } }, watch: { diff --git a/app/src/integrations.js b/app/src/integrations.js index 5276176..93c1da4 100644 --- a/app/src/integrations.js +++ b/app/src/integrations.js @@ -104,7 +104,7 @@ class Integrations extends EventEmitter { //Called when playback state changed async updateState(data) { if (this.discordReady) { - if (data.state == 2){ + if (data.playing){ let richPresence = { state: data.track.artistString, details: data.track.title, @@ -112,7 +112,7 @@ class Integrations extends EventEmitter { instance: true, } //Show timestamp only if playing - if (data.state == 2) { + if (data.playing) { Object.assign(richPresence, { startTimestamp: Date.now() - data.position, endTimestamp: (Date.now() - data.position) + data.duration,