From 256906e9547756e7bc5f79a9af64be39d67f5343 Mon Sep 17 00:00:00 2001 From: chayleaf Date: Thu, 12 Aug 2021 12:40:20 +0700 Subject: [PATCH 1/7] fix loop icon not showing sometimes fix $root.repeat becoming something like "function repeat() { [native code] }1111111" for some godawful reason --- app/client/src/main.js | 20 ++++++++++---------- app/client/src/views/FullscreenPlayer.vue | 18 +++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/client/src/main.js b/app/client/src/main.js index ea4d49b..f7d397f 100644 --- a/app/client/src/main.js +++ b/app/client/src/main.js @@ -88,7 +88,7 @@ new Vue({ }, //0 - normal, 1 - repeat list, 2 - repeat track - repeat: 0, + repeat_mode: 0, shuffled: false, //Library cache @@ -266,7 +266,7 @@ new Vue({ //Gapless playback if (this.position >= (this.duration() - (this.settings.crossfadeDuration + 7500)) && this.state == 2) { - if (this.repeat != 2) + if (this.repeat_mode != 2) this.loadGapless(); } @@ -320,16 +320,16 @@ new Vue({ this.audio.addEventListener('ended', async () => { if (this.gapless.crossfade) return; - //Repeat track - if (this.repeat == 2) { + //repeat track + if (this.repeat_mode == 2) { this.seek(0); this.audio.play(); this.updateState(); return; } - //Repeat list - if (this.repeat == 1 && this.queue.index == this.queue.data.length - 1) { + //repeat list + if (this.repeat_mode == 1 && this.queue.index == this.queue.data.length - 1) { this.skip(-(this.queue.data.length - 1)); return; } @@ -405,8 +405,8 @@ new Vue({ async loadGapless() { if (this.loaders != 0 || this.gapless.promise || this.gapless.audio || this.gapless.crossfade) return; - //Repeat list - if (this.repeat == 1 && this.queue.index == this.queue.data.length - 1) { + //repeat list + if (this.repeat_mode == 1 && this.queue.index == this.queue.data.length - 1) { this.gapless.track = this.queue.data[0]; this.gapless.index = 0; } else { @@ -466,7 +466,7 @@ new Vue({ queue: this.queue, position: this.position, track: this.track, - repeat: this.repeat, + repeat_mode: this.repeat_mode, shuffled: this.shuffled } await this.$axios.post('/playback', data); @@ -574,7 +574,7 @@ 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.repeat_mode) this.repeat_mode = pd.data.repeat_mode; if (pd.data.shuffled) this.shuffled = pd.data.shuffled; this.playTrack(this.track).then(() => { this.seek(pd.data.position); diff --git a/app/client/src/views/FullscreenPlayer.vue b/app/client/src/views/FullscreenPlayer.vue index 29d9d31..8249545 100644 --- a/app/client/src/views/FullscreenPlayer.vue +++ b/app/client/src/views/FullscreenPlayer.vue @@ -73,10 +73,10 @@
- - mdi-repeat - mdi-repeat - mdi-repeat-once + + mdi-repeat_mode + mdi-repeat_mode + mdi-repeat_mode-once mdi-shuffle @@ -313,13 +313,13 @@ export default { updateVolume(v) { this.$root.volume = v; }, - //Repeat button click - repeatClick() { - if (this.$root.repeat == 2) { - this.$root.repeat = 0; + //repeat button click + repeat_modeClick() { + if (this.$root.repeat_mode == 2) { + this.$root.repeat_mode = 0; return; } - this.$root.repeat += 1; + this.$root.repeat_mode += 1; }, //Copy link share() { -- 2.25.1 From c32a3ce3e22dbc9382dc18f7a4882661a7a1f3dc Mon Sep 17 00:00:00 2001 From: chayleaf Date: Thu, 12 Aug 2021 13:29:44 +0700 Subject: [PATCH 2/7] change back button behavior and fix some bugs --- app/client/src/main.js | 53 ++++++++++++++--------- app/client/src/views/FullscreenPlayer.vue | 8 ++-- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/app/client/src/main.js b/app/client/src/main.js index f7d397f..d267542 100644 --- a/app/client/src/main.js +++ b/app/client/src/main.js @@ -125,9 +125,11 @@ new Vue({ return this.state == 2; }, - play() { - if (!this.audio || this.state != 1) return; - this.audio.play(); + async play() { + let audio = this.audio; + if (!audio || this.state != 1) return; + await audio.play(); + if(audio != this.audio) audio.pause(); this.state = 2; }, pause() { @@ -135,12 +137,12 @@ new Vue({ this.audio.pause(); this.state = 1; }, - toggle() { + async toggle() { if (this.isPlaying()) return this.pause(); - this.play(); + await this.play(); }, seek(t) { - if (!this.audio || isNaN(t) || !t) return; + if (!this.audio || isNaN(t) || (!t && t !== 0)) return; //ms -> s this.audio.currentTime = (t / 1000); this.position = t; @@ -169,7 +171,7 @@ new Vue({ if (index >= this.queue.data.length || index < 0) return; this.queue.index = index; await this.playTrack(this.queue.data[this.queue.index]); - this.play(); + await this.play(); this.savePlaybackInfo(); }, //Skip n tracks, can be negative @@ -209,6 +211,15 @@ new Vue({ this.skip(1); this.savePlaybackInfo(); }, + + skipPrev() { + if (this.queue.index != 0 && (!this.position || this.position <= 10000)) + this.skip(-1); + else // Rewind to start if more than 10 seconds in, which is the default behavior for most players + this.seek(0); + this.savePlaybackInfo(); + }, + toggleMute() { if (this.audio) this.audio.muted = !this.audio.muted; this.muted = !this.muted; @@ -223,8 +234,10 @@ new Vue({ this.state = 3; //Stop audio let autoplay = (this.state == 2); - if (this.audio) this.audio.pause(); - if (this.audio) this.audio.currentTime = 0; + if (this.audio) { + this.pause(); + this.audio.currentTime = 0; + } //Load track meta let playbackInfo = await this.loadPlaybackInfo(track.streamUrl, track.duration); @@ -251,7 +264,7 @@ new Vue({ this.audio = new Audio(url); this.configureAudio(); this.state = 1; - if (autoplay) this.play(); + if (autoplay) await this.play(); //MediaSession this.updateMediaSession(); @@ -276,7 +289,7 @@ new Vue({ let currentVolume = this.audio.volume; let oldAudio = this.audio; this.audio = this.gapless.audio; - this.audio.play(); + await this.audio.play(); //Update meta this.playbackInfo = this.gapless.info; @@ -297,7 +310,7 @@ new Vue({ await new Promise((res) => setTimeout(() => res(), 50)); } //Restore original volume - this.audio.voume = currentVolume; + this.audio.volume = currentVolume; oldAudio.pause(); @@ -323,7 +336,7 @@ new Vue({ //repeat track if (this.repeat_mode == 2) { this.seek(0); - this.audio.play(); + await this.audio.play(); this.updateState(); return; } @@ -363,7 +376,7 @@ new Vue({ 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('previoustrack', this.skipPrev); }, //Get Deezer CDN image url getImageUrl(img, size = 256) { @@ -603,14 +616,14 @@ new Vue({ }); //Control from electron - ipcRenderer.on('togglePlayback', () => { - this.toggle(); + ipcRenderer.on('togglePlayback', async () => { + await this.toggle(); }); ipcRenderer.on('skipNext', () => { - this.skip(1); + this.skipNext(); }); ipcRenderer.on('skipPrev', () => { - this.skip(-1); + this.skipPrev(); }) } @@ -685,14 +698,14 @@ new Vue({ }); //Keystrokes - document.addEventListener('keyup', (e) => { + document.addEventListener('keyup', async (e) => { //Don't handle keystrokes in text fields if (e.target.tagName == "INPUT") return; //Don't handle if specials if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return; //K toggle playback - if (e.code == "KeyK" || e.code == "Space") this.$root.toggle(); + if (e.code == "KeyK" || e.code == "Space") await this.$root.toggle(); //L +10s (from YT) if (e.code == "KeyL") this.$root.seek((this.position + 10000)); //J -10s (from YT) diff --git a/app/client/src/views/FullscreenPlayer.vue b/app/client/src/views/FullscreenPlayer.vue index 8249545..df0f9f8 100644 --- a/app/client/src/views/FullscreenPlayer.vue +++ b/app/client/src/views/FullscreenPlayer.vue @@ -51,7 +51,7 @@ - + mdi-skip-previous @@ -74,9 +74,9 @@
- mdi-repeat_mode - mdi-repeat_mode - mdi-repeat_mode-once + mdi-repeat + mdi-repeat + mdi-repeat-once mdi-shuffle -- 2.25.1 From 6fe9e312973db895f1a578cac28a75604664de6d Mon Sep 17 00:00:00 2001 From: chayleaf Date: Thu, 12 Aug 2021 13:43:46 +0700 Subject: [PATCH 3/7] improve Russian TL --- app/client/src/locales/ru.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/client/src/locales/ru.json b/app/client/src/locales/ru.json index 69795ca..b40c8eb 100644 --- a/app/client/src/locales/ru.json +++ b/app/client/src/locales/ru.json @@ -5,7 +5,7 @@ "Tracks": "Треки", "Playlists": "Плейлисты", "Albums": "Альбомы", - "Artists": "Артисты", + "Artists": "Исполнители", "More": "Ещё", "Settings": "Настройки", "Downloads": "Загрузки", @@ -20,7 +20,7 @@ "Start downloading": "Начать загрузку", "Cancel": "Отмена", "Stream logging is disabled!": "Отправка статистики отключена!", - "Enable it in settings for history to work properly.": "Включите её в настройках для работы рекомендаций.", + "Enable it in settings for history to work properly.": "Включите её в настройках для работы истории.", "History": "История", "Create new playlist": "Новый плейлист", "TRACKS": "Треки", @@ -48,7 +48,7 @@ "albums": "альбомы", "Play top": "Играть популярные", "Radio": "Радио", - "Show all albums": "Показать все", + "Show all albums": "Показать все альбомы", "Show all singles": "Показать все синглы", "Show more": "Ещё", "Downloaded": "Загрузки", @@ -108,7 +108,7 @@ "Don't minimize to tray": "Не сворачивать в трей", "Close on exit": "Закрывать при выходе", "Settings saved!": "Настройки сохранены!", - "Available only in Electron version!": "Доступно только в версии на Electron!", + "Available only in Electron version!": "Доступно только в версии Electron!", "Crossfade (ms)": "Кроссфейд (мс)", "Select primary color": "Выберите основной цвет", "Light theme": "Светлая тема", @@ -143,7 +143,7 @@ "Art Resolution": "Разрешение обложки", "Public": "Публичный", "Private": "Приватный", - "Collaborative": "Совместное", + "Collaborative": "Совместный", "Edit playlist": "Изменить плейлист", "Save": "Сохранить", "Edit": "Редактировать", @@ -161,11 +161,11 @@ "Artists:": "Исполнители:", "Yes": "Да", "No": "Нет", - "Download Filename": "Скачать шаблон для названия", + "Download Filename": "Шаблон названия файла для скачивания", "Language": "Язык", "Background Image": "Фоновое изображение", "Enter URL or absolute path. WARNING: Requires reload!": "Введите URL или полный путь. ВНИМАНИЕ: Требуется перезагрузка!", "LGBT Mode": "Режим ЛГБТ", - "Native top bar": "Верхнюю панель", + "Native top bar": "Системная верхняя панель", "Requires restart of Freezer!": "Требуется перезагрузка!" } \ No newline at end of file -- 2.25.1 From f4c7a3ce1896591f47aca525d4b288b9d41cf7fe Mon Sep 17 00:00:00 2001 From: chayleaf Date: Thu, 12 Aug 2021 13:47:57 +0700 Subject: [PATCH 4/7] undo stupid changes;consistent case for repeatMode --- app/client/src/main.js | 20 ++++++++++---------- app/client/src/views/FullscreenPlayer.vue | 18 +++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/client/src/main.js b/app/client/src/main.js index d267542..ce46772 100644 --- a/app/client/src/main.js +++ b/app/client/src/main.js @@ -88,7 +88,7 @@ new Vue({ }, //0 - normal, 1 - repeat list, 2 - repeat track - repeat_mode: 0, + repeatMode: 0, shuffled: false, //Library cache @@ -279,7 +279,7 @@ new Vue({ //Gapless playback if (this.position >= (this.duration() - (this.settings.crossfadeDuration + 7500)) && this.state == 2) { - if (this.repeat_mode != 2) + if (this.repeatMode != 2) this.loadGapless(); } @@ -333,16 +333,16 @@ new Vue({ this.audio.addEventListener('ended', async () => { if (this.gapless.crossfade) return; - //repeat track - if (this.repeat_mode == 2) { + //Repeat track + if (this.repeatMode == 2) { this.seek(0); await this.audio.play(); this.updateState(); return; } - //repeat list - if (this.repeat_mode == 1 && this.queue.index == this.queue.data.length - 1) { + //Repeat list + if (this.repeatMode == 1 && this.queue.index == this.queue.data.length - 1) { this.skip(-(this.queue.data.length - 1)); return; } @@ -418,8 +418,8 @@ new Vue({ async loadGapless() { if (this.loaders != 0 || this.gapless.promise || this.gapless.audio || this.gapless.crossfade) return; - //repeat list - if (this.repeat_mode == 1 && this.queue.index == this.queue.data.length - 1) { + //Repeat list + if (this.repeatMode == 1 && this.queue.index == this.queue.data.length - 1) { this.gapless.track = this.queue.data[0]; this.gapless.index = 0; } else { @@ -479,7 +479,7 @@ new Vue({ queue: this.queue, position: this.position, track: this.track, - repeat_mode: this.repeat_mode, + repeatMode: this.repeatMode, shuffled: this.shuffled } await this.$axios.post('/playback', data); @@ -587,7 +587,7 @@ 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_mode) this.repeat_mode = pd.data.repeat_mode; + 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); diff --git a/app/client/src/views/FullscreenPlayer.vue b/app/client/src/views/FullscreenPlayer.vue index df0f9f8..622d767 100644 --- a/app/client/src/views/FullscreenPlayer.vue +++ b/app/client/src/views/FullscreenPlayer.vue @@ -73,10 +73,10 @@
- - mdi-repeat - mdi-repeat - mdi-repeat-once + + mdi-repeat + mdi-repeat + mdi-repeat-once mdi-shuffle @@ -313,13 +313,13 @@ export default { updateVolume(v) { this.$root.volume = v; }, - //repeat button click - repeat_modeClick() { - if (this.$root.repeat_mode == 2) { - this.$root.repeat_mode = 0; + //Repeat button click + repeatClick() { + if (this.$root.repeatMode == 2) { + this.$root.repeatMode = 0; return; } - this.$root.repeat_mode += 1; + this.$root.repeatMode += 1; }, //Copy link share() { -- 2.25.1 From 94e4e799585ca1d894ce18eb7786e26a8d2e5f1f Mon Sep 17 00:00:00 2001 From: chayleaf Date: Thu, 12 Aug 2021 15:47:02 +0700 Subject: [PATCH 5/7] fix multiple tracks playing at the same time --- app/client/src/main.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/app/client/src/main.js b/app/client/src/main.js index ce46772..baae757 100644 --- a/app/client/src/main.js +++ b/app/client/src/main.js @@ -73,7 +73,7 @@ new Vue({ track: null, audio: null, volume: 0.00, - //0 = Stopped, 1 = Paused, 2 = Playing, 3 = Loading + //0 = Stopped, 1 = Paused, 2 = Playing, 3 = Loading, 4 = Starting playing state: 0, loaders: 0, playbackInfo: {}, @@ -122,19 +122,23 @@ new Vue({ methods: { // PLAYBACK METHODS isPlaying() { - return this.state == 2; + return this.state == 2 || this.state == 4; }, async play() { let audio = this.audio; if (!audio || this.state != 1) return; + this.state = 4; await audio.play(); - if(audio != this.audio) audio.pause(); - this.state = 2; + if (this.state == 1 || audio != this.audio) { + audio.pause(); + } else { + this.state = 2 + } }, pause() { - if (!this.audio || this.state != 2) return; - this.audio.pause(); + if (!this.audio || !this.isPlaying()) return; + if (this.state == 2) this.audio.pause(); this.state = 1; }, async toggle() { @@ -231,13 +235,13 @@ new Vue({ this.track = track; this.loaders++; - this.state = 3; //Stop audio - let autoplay = (this.state == 2); + let autoplay = (this.state == 2 || this.state == 4); if (this.audio) { this.pause(); this.audio.currentTime = 0; } + this.state = 3; //Load track meta let playbackInfo = await this.loadPlaybackInfo(track.streamUrl, track.duration); @@ -289,7 +293,8 @@ new Vue({ let currentVolume = this.audio.volume; let oldAudio = this.audio; this.audio = this.gapless.audio; - await this.audio.play(); + this.state = 1; + await this.play(); //Update meta this.playbackInfo = this.gapless.info; @@ -516,7 +521,7 @@ 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); @@ -531,7 +536,7 @@ new Vue({ //Update in electron if (this.settings.electron) { - ipcRenderer.send('playing', this.state == 2); + ipcRenderer.send('playing', this.isPlaying()); } }, updateLanguage(l) { -- 2.25.1 From 00e8760ad6211067326f9e732faa28a07376d917 Mon Sep 17 00:00:00 2001 From: chayleaf Date: Thu, 12 Aug 2021 15:54:11 +0700 Subject: [PATCH 6/7] enable media keys when no track is playing --- app/client/src/main.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/client/src/main.js b/app/client/src/main.js index baae757..0d21652 100644 --- a/app/client/src/main.js +++ b/app/client/src/main.js @@ -365,7 +365,15 @@ new Vue({ }, //Update media session with current track metadata updateMediaSession() { - if (!this.track || !('mediaSession' in navigator)) return; + if (!('mediaSession' in navigator)) return; + + //Controls + navigator.mediaSession.setActionHandler('play', this.play); + navigator.mediaSession.setActionHandler('pause', this.pause); + navigator.mediaSession.setActionHandler('nexttrack', this.skipNext); + navigator.mediaSession.setActionHandler('previoustrack', this.skipPrev); + + if (!this.track) return; // eslint-disable-next-line no-undef navigator.mediaSession.metadata = new MediaMetadata({ @@ -377,11 +385,6 @@ new Vue({ {src: this.getImageUrl(this.track.albumArt, 512), sizes: '512x512', type: 'image/jpeg'} ] }); - //Controls - navigator.mediaSession.setActionHandler('play', 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) { -- 2.25.1 From b3c2b97ec8e841d68966403f41ce339c8a23af4e Mon Sep 17 00:00:00 2001 From: chayleaf Date: Thu, 12 Aug 2021 17:14:45 +0700 Subject: [PATCH 7/7] make media keys actually work on startup; use more mediasession stuff --- app/client/src/main.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/app/client/src/main.js b/app/client/src/main.js index 0d21652..d6a75f6 100644 --- a/app/client/src/main.js +++ b/app/client/src/main.js @@ -125,6 +125,14 @@ new Vue({ return this.state == 2 || this.state == 4; }, + async load() { + let audio = this.audio; + if (!audio || this.state != 1) return; + this.state = 1; + await audio.play(); + audio.pause(); + }, + async play() { let audio = this.audio; if (!audio || this.state != 1) return; @@ -148,6 +156,8 @@ new Vue({ seek(t) { if (!this.audio || isNaN(t) || (!t && t !== 0)) return; //ms -> s + if(t < 0) t = 0; + if(t > this.duration()) t = this.duration(); this.audio.currentTime = (t / 1000); this.position = t; @@ -372,6 +382,15 @@ new Vue({ navigator.mediaSession.setActionHandler('pause', this.pause); navigator.mediaSession.setActionHandler('nexttrack', this.skipNext); navigator.mediaSession.setActionHandler('previoustrack', this.skipPrev); + navigator.mediaSession.setActionHandler('seekbackward', details => { + this.seek(this.position - details.seekOffset * 1000); + }); + navigator.mediaSession.setActionHandler('seekforward', details => { + this.seek(this.position + details.seekOffset * 1000); + }); + navigator.mediaSession.setActionHandler('seekto', details => { + this.seek(details.seekTime * 1000); + }); if (!this.track) return; @@ -530,6 +549,7 @@ new Vue({ }, 500); return; } + this.$io.emit('stateChange', { position: this.position, duration: this.duration(), @@ -537,6 +557,14 @@ new Vue({ track: this.track }); + if (('mediaSession' in navigator) && navigator.mediaSession.setPositionState && this.duration() != null && !isNaN(this.duration())) { + navigator.mediaSession.setPositionState({ + position: this.position / 1000, + duration: this.duration() / 1000, + playbackRate: 1, + }); + } + //Update in electron if (this.settings.electron) { ipcRenderer.send('playing', this.isPlaying()); @@ -599,6 +627,7 @@ new Vue({ if (pd.data.shuffled) this.shuffled = pd.data.shuffled; this.playTrack(this.track).then(() => { this.seek(pd.data.position); + this.load(); }); } -- 2.25.1