From c281b8ba987867c5533b5fd7ad7e057240bd9f40 Mon Sep 17 00:00:00 2001 From: Fermin Cirella Date: Sat, 22 Oct 2022 01:00:15 -0300 Subject: [PATCH 01/14] Plugin: Captions Selector --- plugins/captions-selector/back.js | 15 +++++++++ plugins/captions-selector/front.js | 31 +++++++++++++++++++ .../templates/captionsSettingsTemplate.html | 13 ++++++++ 3 files changed, 59 insertions(+) create mode 100644 plugins/captions-selector/back.js create mode 100644 plugins/captions-selector/front.js create mode 100644 plugins/captions-selector/templates/captionsSettingsTemplate.html diff --git a/plugins/captions-selector/back.js b/plugins/captions-selector/back.js new file mode 100644 index 00000000..533cceca --- /dev/null +++ b/plugins/captions-selector/back.js @@ -0,0 +1,15 @@ +const { ipcMain, dialog } = require("electron"); + +module.exports = () => { + ipcMain.handle('captionsSelector', async (_, captionLabels, currentIndex) => { + return await dialog.showMessageBox({ + type: "question", + buttons: captionLabels, + defaultId: currentIndex, + title: "Choose Caption", + message: "Choose Caption:", + detail: `Current Caption: ${captionLabels[currentIndex]}`, + cancelId: -1 + }) + }) +}; diff --git a/plugins/captions-selector/front.js b/plugins/captions-selector/front.js new file mode 100644 index 00000000..62324514 --- /dev/null +++ b/plugins/captions-selector/front.js @@ -0,0 +1,31 @@ +const { ElementFromFile, templatePath } = require("../utils"); +const { ipcRenderer } = require("electron"); + +const captionsSettingsButton = ElementFromFile( + templatePath(__dirname, "captionsSettingsTemplate.html") +); + +module.exports = () => { + document.addEventListener('apiLoaded', setup, { once: true, passive: true }); +} + +function setup(event) { + const api = event.detail; + + document.querySelector('.right-controls-buttons').append(captionsSettingsButton); + + captionsSettingsButton.onclick = function chooseQuality() { + api.pauseVideo(); + + const currentCaptionTrack = api.getOption("captions", "track"); + const captionTrackList = api.getOption("captions", "tracklist"); + + const currentIndex = captionTrackList.indexOf(captionTrackList.find(track => track.languageCode === currentCaptionTrack.languageCode)); + + ipcRenderer.invoke('captionsSelector', captionTrackList.map(track => track.displayName), currentIndex).then(promise => { + if (promise.response === -1) return; + const newCaptions = captionTrackList[promise.response]; + api.setOption("captions", "track", { languageCode: newCaptions.languageCode }); + }); + } +} diff --git a/plugins/captions-selector/templates/captionsSettingsTemplate.html b/plugins/captions-selector/templates/captionsSettingsTemplate.html new file mode 100644 index 00000000..bfa34e4d --- /dev/null +++ b/plugins/captions-selector/templates/captionsSettingsTemplate.html @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file From f58c10b02d856f36b79bceb736e872f9489f44ec Mon Sep 17 00:00:00 2001 From: Fermin Cirella Date: Sat, 22 Oct 2022 01:01:25 -0300 Subject: [PATCH 02/14] Plugin Captions Selector - Add new line --- .../captions-selector/templates/captionsSettingsTemplate.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/captions-selector/templates/captionsSettingsTemplate.html b/plugins/captions-selector/templates/captionsSettingsTemplate.html index bfa34e4d..16c1b2b6 100644 --- a/plugins/captions-selector/templates/captionsSettingsTemplate.html +++ b/plugins/captions-selector/templates/captionsSettingsTemplate.html @@ -10,4 +10,4 @@ - \ No newline at end of file + From c8a852bf2ece75a4e07039d49d6a425b03deb536 Mon Sep 17 00:00:00 2001 From: Fermin Cirella Date: Sat, 22 Oct 2022 01:13:04 -0300 Subject: [PATCH 03/14] Plugin Captions Selector - Check if there is caption tracks available, add "disable captions" --- plugins/captions-selector/front.js | 33 ++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/plugins/captions-selector/front.js b/plugins/captions-selector/front.js index 62324514..f8c83cb9 100644 --- a/plugins/captions-selector/front.js +++ b/plugins/captions-selector/front.js @@ -15,17 +15,32 @@ function setup(event) { document.querySelector('.right-controls-buttons').append(captionsSettingsButton); captionsSettingsButton.onclick = function chooseQuality() { - api.pauseVideo(); - - const currentCaptionTrack = api.getOption("captions", "track"); const captionTrackList = api.getOption("captions", "tracklist"); - const currentIndex = captionTrackList.indexOf(captionTrackList.find(track => track.languageCode === currentCaptionTrack.languageCode)); + if (captionTrackList?.length) { + api.pauseVideo(); - ipcRenderer.invoke('captionsSelector', captionTrackList.map(track => track.displayName), currentIndex).then(promise => { - if (promise.response === -1) return; - const newCaptions = captionTrackList[promise.response]; - api.setOption("captions", "track", { languageCode: newCaptions.languageCode }); - }); + const currentCaptionTrack = api.getOption("captions", "track"); + const currentIndex = captionTrackList.indexOf(captionTrackList.find(track => track.languageCode === currentCaptionTrack.languageCode)); + + const captionLabels = [ + ...captionTrackList.map(track => track.displayName), + 'None' + ]; + + ipcRenderer.invoke('captionsSelector', captionLabels, currentIndex).then(promise => { + if (promise.response === -1) return; + + const newCaptions = captionTrackList[promise.response]; + if (newCaptions) { + api.loadModule("captions"); + api.setOption("captions", "track", { languageCode: newCaptions.languageCode }); + } else { + api.unloadModule("captions"); + } + + setTimeout(() => api.playVideo()); + }); + } } } From 938210e8f902fe2aae71d07787efb5ec197d4dc2 Mon Sep 17 00:00:00 2001 From: Fermin Cirella Date: Sat, 22 Oct 2022 01:49:16 -0300 Subject: [PATCH 04/14] Plugin Captions Selector - Add disable captions by default --- config/defaults.js | 4 ++++ plugins/captions-selector/back.js | 4 ++-- plugins/captions-selector/front.js | 28 +++++++++++++++++++++------- plugins/captions-selector/menu.js | 12 ++++++++++++ 4 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 plugins/captions-selector/menu.js diff --git a/config/defaults.js b/config/defaults.js index 73c49649..a617c264 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -91,6 +91,10 @@ const defaultConfig = { "saveSize": false, "hotkey": "P" }, + "captions-selector": { + enabled: false, + disableCaptions: false + } }, }; diff --git a/plugins/captions-selector/back.js b/plugins/captions-selector/back.js index 533cceca..de53d85a 100644 --- a/plugins/captions-selector/back.js +++ b/plugins/captions-selector/back.js @@ -1,8 +1,8 @@ const { ipcMain, dialog } = require("electron"); module.exports = () => { - ipcMain.handle('captionsSelector', async (_, captionLabels, currentIndex) => { - return await dialog.showMessageBox({ + ipcMain.handle('captionsSelector', async (_, captionLabels, currentIndex) => { + return await dialog.showMessageBox({ type: "question", buttons: captionLabels, defaultId: currentIndex, diff --git a/plugins/captions-selector/front.js b/plugins/captions-selector/front.js index f8c83cb9..9ae9dbde 100644 --- a/plugins/captions-selector/front.js +++ b/plugins/captions-selector/front.js @@ -1,30 +1,44 @@ const { ElementFromFile, templatePath } = require("../utils"); const { ipcRenderer } = require("electron"); +function $(selector) { return document.querySelector(selector); } + const captionsSettingsButton = ElementFromFile( templatePath(__dirname, "captionsSettingsTemplate.html") ); -module.exports = () => { - document.addEventListener('apiLoaded', setup, { once: true, passive: true }); +module.exports = (options) => { + document.addEventListener('apiLoaded', (event) => setup(event, options), { once: true, passive: true }); } -function setup(event) { +/** + * If captions are disabled by default, + * unload "captions" module when video changes. + */ +const videoChanged = (api, options) => { + if (options.disableCaptions) { + setTimeout(() => api.unloadModule("captions"), 100); + } +} + +function setup(event, options) { const api = event.detail; - document.querySelector('.right-controls-buttons').append(captionsSettingsButton); + $("video").addEventListener("srcChanged", () => videoChanged(api, options)); + + $(".right-controls-buttons").append(captionsSettingsButton); captionsSettingsButton.onclick = function chooseQuality() { + api.loadModule("captions"); + const captionTrackList = api.getOption("captions", "tracklist"); if (captionTrackList?.length) { - api.pauseVideo(); - const currentCaptionTrack = api.getOption("captions", "track"); const currentIndex = captionTrackList.indexOf(captionTrackList.find(track => track.languageCode === currentCaptionTrack.languageCode)); const captionLabels = [ - ...captionTrackList.map(track => track.displayName), + ...captionTrackList.map(track => track.displayName), 'None' ]; diff --git a/plugins/captions-selector/menu.js b/plugins/captions-selector/menu.js new file mode 100644 index 00000000..439ff8b4 --- /dev/null +++ b/plugins/captions-selector/menu.js @@ -0,0 +1,12 @@ +const { setOptions } = require('../../config/plugins'); + +module.exports = (_win, options) => [ + { + label: "No captions by default", + type: "checkbox", + checked: options.disabledCaptions, + click: (item) => { + setOptions("captions-selector", { disableCaptions: item.checked }); + }, + } +]; From bc23131e48027533906f11283515a81a3e6c4d5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Jan 2023 04:35:10 +0000 Subject: [PATCH 05/14] Bump json5 from 1.0.1 to 1.0.2 Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index c5a07fde..b934648a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4294,9 +4294,9 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" From 52b67af59c30e6148f00a485e25ebc8653ce7936 Mon Sep 17 00:00:00 2001 From: TC Date: Sun, 8 Jan 2023 19:17:00 +0100 Subject: [PATCH 06/14] Use same audio context/source everywhere --- package.json | 1 - plugins/audio-compressor/front.js | 13 +-- plugins/skip-silences/front.js | 145 +++++++++++++++++++++--------- preload.js | 26 ++++++ yarn.lock | 12 --- 5 files changed, 135 insertions(+), 62 deletions(-) diff --git a/package.json b/package.json index 9827b524..af2a9dca 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,6 @@ "electron-unhandled": "^4.0.1", "electron-updater": "^4.6.3", "filenamify": "^4.3.0", - "hark": "^1.2.3", "html-to-text": "^8.2.1", "md5": "^2.3.0", "mpris-service": "^2.1.2", diff --git a/plugins/audio-compressor/front.js b/plugins/audio-compressor/front.js index 129073e3..1281cec5 100644 --- a/plugins/audio-compressor/front.js +++ b/plugins/audio-compressor/front.js @@ -1,5 +1,5 @@ -const applyCompressor = () => { - const audioContext = new AudioContext(); +const applyCompressor = (e) => { + const audioContext = e.detail.audioContext; const compressor = audioContext.createDynamicsCompressor(); compressor.threshold.value = -50; @@ -8,10 +8,11 @@ const applyCompressor = () => { compressor.attack.value = 0; compressor.release.value = 0.25; - const source = audioContext.createMediaElementSource(document.querySelector("video")); - - source.connect(compressor); + e.detail.audioSource.connect(compressor); compressor.connect(audioContext.destination); }; -module.exports = () => document.addEventListener('apiLoaded', applyCompressor, { once: true, passive: true }); +module.exports = () => + document.addEventListener("audioCanPlay", applyCompressor, { + passive: true, + }); diff --git a/plugins/skip-silences/front.js b/plugins/skip-silences/front.js index 17a534c9..69a6e919 100644 --- a/plugins/skip-silences/front.js +++ b/plugins/skip-silences/front.js @@ -1,53 +1,112 @@ -const hark = require("hark/hark.bundle.js"); - module.exports = (options) => { let isSilent = false; let hasAudioStarted = false; - document.addEventListener("apiLoaded", () => { - const video = document.querySelector("video"); - const speechEvents = hark(video, { - threshold: -100, // dB (-100 = absolute silence, 0 = loudest) - interval: 2, // ms - }); - const skipSilence = () => { - if (options.onlySkipBeginning && hasAudioStarted) { - return; - } + const smoothing = 0.1; + const threshold = -100; // dB (-100 = absolute silence, 0 = loudest) + const interval = 2; // ms + const history = 10; + const speakingHistory = Array(history).fill(0); - if (isSilent && !video.paused) { - video.currentTime += 0.2; // in s - } - }; + document.addEventListener( + "audioCanPlay", + (e) => { + const video = document.querySelector("video"); + const audioContext = e.detail.audioContext; + const sourceNode = e.detail.audioSource; - speechEvents.on("speaking", function () { - isSilent = false; - hasAudioStarted = true; - }); + // Use an audio analyser similar to Hark + // https://github.com/otalk/hark/blob/master/hark.bundle.js + const analyser = audioContext.createAnalyser(); + analyser.fftSize = 512; + analyser.smoothingTimeConstant = smoothing; + const fftBins = new Float32Array(analyser.frequencyBinCount); - speechEvents.on("stopped_speaking", function () { - if ( - !( - video.paused || - video.seeking || - video.ended || - video.muted || - video.volume === 0 - ) - ) { - isSilent = true; + sourceNode.connect(analyser); + analyser.connect(audioContext.destination); + + const looper = () => { + setTimeout(() => { + const currentVolume = getMaxVolume(analyser, fftBins); + + let history = 0; + if (currentVolume > threshold && isSilent) { + // trigger quickly, short history + for ( + let i = speakingHistory.length - 3; + i < speakingHistory.length; + i++ + ) { + history += speakingHistory[i]; + } + if (history >= 2) { + // Not silent + isSilent = false; + hasAudioStarted = true; + } + } else if (currentVolume < threshold && !isSilent) { + for (let i = 0; i < speakingHistory.length; i++) { + history += speakingHistory[i]; + } + if (history == 0) { + // Silent + if ( + !( + video.paused || + video.seeking || + video.ended || + video.muted || + video.volume === 0 + ) + ) { + isSilent = true; + skipSilence(); + } + } + } + speakingHistory.shift(); + speakingHistory.push(0 + (currentVolume > threshold)); + + looper(); + }, interval); + }; + looper(); + + const skipSilence = () => { + if (options.onlySkipBeginning && hasAudioStarted) { + return; + } + + if (isSilent && !video.paused) { + video.currentTime += 0.2; // in s + } + }; + + video.addEventListener("play", function () { + hasAudioStarted = false; skipSilence(); - } - }); + }); - video.addEventListener("play", function () { - hasAudioStarted = false; - skipSilence(); - }); - - video.addEventListener("seeked", function () { - hasAudioStarted = false; - skipSilence(); - }); - }); + video.addEventListener("seeked", function () { + hasAudioStarted = false; + skipSilence(); + }); + }, + { + passive: true, + } + ); }; + +function getMaxVolume(analyser, fftBins) { + var maxVolume = -Infinity; + analyser.getFloatFrequencyData(fftBins); + + for (var i = 4, ii = fftBins.length; i < ii; i++) { + if (fftBins[i] > maxVolume && fftBins[i] < 0) { + maxVolume = fftBins[i]; + } + } + + return maxVolume; +} diff --git a/preload.js b/preload.js index 2b9122f1..ecfb8e17 100644 --- a/preload.js +++ b/preload.js @@ -90,6 +90,32 @@ function listenForApiLoad() { } function onApiLoaded() { + const video = document.querySelector("video"); + const audioContext = new AudioContext(); + const audioSource = audioContext.createMediaElementSource(video); + + video.addEventListener( + "loadstart", + () => { + // Emit "audioCanPlay" for each video + video.addEventListener( + "canplaythrough", + () => { + document.dispatchEvent( + new CustomEvent("audioCanPlay", { + detail: { + audioContext: audioContext, + audioSource: audioSource, + }, + }) + ); + }, + { once: true } + ); + }, + { passive: true } + ); + document.dispatchEvent(new CustomEvent('apiLoaded', { detail: api })); // Remove upgrade button diff --git a/yarn.lock b/yarn.lock index c5a07fde..b7505584 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3527,13 +3527,6 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -hark@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/hark/-/hark-1.2.3.tgz#959981400f561be5580ecd4321a9f55b16bacbd0" - integrity sha512-u68vz9SCa38ESiFJSDjqK8XbXqWzyot7Cj6Y2b6jk2NJ+II3MY2dIrLMg/kjtIAun4Y1DHF/20hfx4rq1G5GMg== - dependencies: - wildemitter "^1.2.0" - has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -6639,11 +6632,6 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" -wildemitter@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/wildemitter/-/wildemitter-1.2.1.tgz#9da3b5ca498e4378628d1783145493c70a10b774" - integrity sha512-UMmSUoIQSir+XbBpTxOTS53uJ8s/lVhADCkEbhfRjUGFDPme/XGOb0sBWLx5sTz7Wx/2+TlAw1eK9O5lw5PiEw== - word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" From b77c62128eb6dc8ee3223f8f3fbad170dded9c88 Mon Sep 17 00:00:00 2001 From: TC Date: Mon, 9 Jan 2023 09:00:16 +0100 Subject: [PATCH 07/14] Implement visualizer plugin --- config/defaults.js | 66 +++++++++++++++++++ package.json | 4 ++ plugins/visualizer/back.js | 6 ++ plugins/visualizer/empty-player.css | 9 +++ plugins/visualizer/front.js | 61 +++++++++++++++++ plugins/visualizer/menu.js | 23 +++++++ plugins/visualizer/visualizers/butterchurn.js | 46 +++++++++++++ plugins/visualizer/visualizers/vudio.js | 33 ++++++++++ plugins/visualizer/visualizers/wave.js | 31 +++++++++ readme.md | 2 + yarn.lock | 64 +++++++++++++++++- 11 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 plugins/visualizer/back.js create mode 100644 plugins/visualizer/empty-player.css create mode 100644 plugins/visualizer/front.js create mode 100644 plugins/visualizer/menu.js create mode 100644 plugins/visualizer/visualizers/butterchurn.js create mode 100644 plugins/visualizer/visualizers/vudio.js create mode 100644 plugins/visualizer/visualizers/wave.js diff --git a/config/defaults.js b/config/defaults.js index b62432c6..eaefcc24 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -94,6 +94,72 @@ const defaultConfig = { "skip-silences": { onlySkipBeginning: false, }, + visualizer: { + enabled: false, + type: "butterchurn", + // Config per visualizer + butterchurn: { + preset: "martin [shadow harlequins shape code] - fata morgana", + renderingFrequencyInMs: 500, + blendTimeInSeconds: 2.7, + }, + vudio: { + effect: "lighting", + accuracy: 128, + lighting: { + maxHeight: 160, + maxSize: 12, + lineWidth: 1, + color: "#49f3f7", + shadowBlur: 2, + shadowColor: "rgba(244,244,244,.5)", + fadeSide: true, + prettify: false, + horizontalAlign: "center", + verticalAlign: "middle", + dottify: true, + }, + }, + wave: { + animations: [ + { + type: "Cubes", + config: { + bottom: true, + count: 30, + cubeHeight: 5, + fillColor: { gradient: ["#FAD961", "#F76B1C"] }, + lineColor: "rgba(0,0,0,0)", + radius: 20, + }, + }, + { + type: "Cubes", + config: { + top: true, + count: 12, + cubeHeight: 5, + fillColor: { gradient: ["#FAD961", "#F76B1C"] }, + lineColor: "rgba(0,0,0,0)", + radius: 10, + }, + }, + { + type: "Circles", + config: { + lineColor: { + gradient: ["#FAD961", "#FAD961", "#F76B1C"], + rotate: 90, + }, + lineWidth: 4, + diameter: 20, + count: 10, + frequencyBand: "base", + }, + }, + ], + }, + }, }, }; diff --git a/package.json b/package.json index af2a9dca..9086d2e7 100644 --- a/package.json +++ b/package.json @@ -96,9 +96,12 @@ "@cliqz/adblocker-electron": "^1.25.1", "@ffmpeg/core": "^0.11.0", "@ffmpeg/ffmpeg": "^0.11.6", + "@foobar404/wave": "^2.0.4", "Simple-YouTube-Age-Restriction-Bypass": "https://gitpkg.now.sh/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/dist?v2.5.4", "async-mutex": "^0.4.0", "browser-id3-writer": "^4.4.0", + "butterchurn": "^2.6.7", + "butterchurn-presets": "^2.4.7", "chokidar": "^3.5.3", "custom-electron-prompt": "^1.5.0", "custom-electron-titlebar": "^4.1.2", @@ -116,6 +119,7 @@ "mpris-service": "^2.1.2", "node-fetch": "^2.6.7", "node-notifier": "^10.0.1", + "vudio": "^2.1.1", "ytdl-core": "^4.11.1", "ytpl": "^2.3.0" }, diff --git a/plugins/visualizer/back.js b/plugins/visualizer/back.js new file mode 100644 index 00000000..b0f8c42b --- /dev/null +++ b/plugins/visualizer/back.js @@ -0,0 +1,6 @@ +const { injectCSS } = require("../utils"); +const path = require("path"); + +module.exports = (win, options) => { + injectCSS(win.webContents, path.join(__dirname, "empty-player.css")); +}; diff --git a/plugins/visualizer/empty-player.css b/plugins/visualizer/empty-player.css new file mode 100644 index 00000000..dc94788a --- /dev/null +++ b/plugins/visualizer/empty-player.css @@ -0,0 +1,9 @@ +#player { + margin: 0 !important; + background: black; +} + +#song-image, +#song-video { + display: none !important; +} diff --git a/plugins/visualizer/front.js b/plugins/visualizer/front.js new file mode 100644 index 00000000..47522422 --- /dev/null +++ b/plugins/visualizer/front.js @@ -0,0 +1,61 @@ +const defaultConfig = require("../../config/defaults"); + +module.exports = (options) => { + const optionsWithDefaults = { + ...defaultConfig.plugins.visualizer, + ...options, + }; + const VisualizerType = require(`./visualizers/${optionsWithDefaults.type}`); + + document.addEventListener( + "audioCanPlay", + (e) => { + const video = document.querySelector("video"); + const visualizerContainer = document.querySelector("#player"); + + let canvas = document.getElementById("visualizer"); + if (!canvas) { + canvas = document.createElement("canvas"); + canvas.id = "visualizer"; + canvas.style.position = "absolute"; + canvas.style.background = "black"; + visualizerContainer.append(canvas); + } + + const resizeCanvas = () => { + canvas.width = visualizerContainer.clientWidth; + canvas.height = visualizerContainer.clientHeight; + }; + resizeCanvas(); + + const gainNode = e.detail.audioContext.createGain(); + gainNode.gain.value = 1.25; + e.detail.audioSource.connect(gainNode); + + const visualizer = new VisualizerType( + e.detail.audioContext, + e.detail.audioSource, + visualizerContainer, + canvas, + gainNode, + video.captureStream(), + optionsWithDefaults[optionsWithDefaults.type] + ); + + const resizeVisualizer = (width, height) => { + resizeCanvas(); + visualizer.resize(width, height); + }; + resizeVisualizer(canvas.width, canvas.height); + const visualizerContainerObserver = new ResizeObserver((entries) => { + entries.forEach((entry) => { + resizeVisualizer(entry.contentRect.width, entry.contentRect.height); + }); + }); + visualizerContainerObserver.observe(visualizerContainer); + + visualizer.render(); + }, + { passive: true } + ); +}; diff --git a/plugins/visualizer/menu.js b/plugins/visualizer/menu.js new file mode 100644 index 00000000..181a71e7 --- /dev/null +++ b/plugins/visualizer/menu.js @@ -0,0 +1,23 @@ +const { readdirSync } = require("fs"); +const path = require("path"); + +const { setMenuOptions } = require("../../config/plugins"); + +const visualizerTypes = readdirSync(path.join(__dirname, "visualizers")).map( + (filename) => path.parse(filename).name +); + +module.exports = (win, options) => [ + { + label: "Type", + submenu: visualizerTypes.map((visualizerType) => ({ + label: visualizerType, + type: "radio", + checked: options.type === visualizerType, + click: () => { + options.type = visualizerType; + setMenuOptions("visualizer", options); + }, + })), + }, +]; diff --git a/plugins/visualizer/visualizers/butterchurn.js b/plugins/visualizer/visualizers/butterchurn.js new file mode 100644 index 00000000..1c30355d --- /dev/null +++ b/plugins/visualizer/visualizers/butterchurn.js @@ -0,0 +1,46 @@ +const butterchurn = require("butterchurn"); +const butterchurnPresets = require("butterchurn-presets"); + +const presets = butterchurnPresets.getPresets(); + +class ButterchurnVisualizer { + constructor( + audioContext, + audioSource, + visualizerContainer, + canvas, + audioNode, + stream, + options + ) { + this.visualizer = butterchurn.default.createVisualizer( + audioContext, + canvas, + { + width: canvas.width, + height: canvas.height, + } + ); + + const preset = presets[options.preset]; + this.visualizer.loadPreset(preset, options.blendTimeInSeconds); + + this.visualizer.connectAudio(audioNode); + + this.renderingFrequencyInMs = options.renderingFrequencyInMs; + } + + resize(width, height) { + this.visualizer.setRendererSize(width, height); + } + + render() { + const renderVisualizer = () => { + requestAnimationFrame(() => renderVisualizer()); + this.visualizer.render(); + }; + setTimeout(renderVisualizer(), this.renderingFrequencyInMs); + } +} + +module.exports = ButterchurnVisualizer; diff --git a/plugins/visualizer/visualizers/vudio.js b/plugins/visualizer/visualizers/vudio.js new file mode 100644 index 00000000..36cdf2a2 --- /dev/null +++ b/plugins/visualizer/visualizers/vudio.js @@ -0,0 +1,33 @@ +const Vudio = require("vudio/umd/vudio"); + +class VudioVisualizer { + constructor( + audioContext, + audioSource, + visualizerContainer, + canvas, + audioNode, + stream, + options + ) { + this.visualizer = new Vudio(stream, canvas, { + width: canvas.width, + height: canvas.height, + // Visualizer config + ...options, + }); + } + + resize(width, height) { + this.visualizer.setOption({ + width: width, + height: height, + }); + } + + render() { + this.visualizer.dance(); + } +} + +module.exports = VudioVisualizer; diff --git a/plugins/visualizer/visualizers/wave.js b/plugins/visualizer/visualizers/wave.js new file mode 100644 index 00000000..70db7f2a --- /dev/null +++ b/plugins/visualizer/visualizers/wave.js @@ -0,0 +1,31 @@ +const { Wave } = require("@foobar404/wave"); + +class WaveVisualizer { + constructor( + audioContext, + audioSource, + visualizerContainer, + canvas, + audioNode, + stream, + options + ) { + this.visualizer = new Wave( + { context: audioContext, source: audioSource }, + canvas + ); + options.animations.forEach((animation) => { + this.visualizer.addAnimation( + eval(`new this.visualizer.animations.${animation.type}( + ${JSON.stringify(animation.config)} + )`) + ); + }); + } + + resize(width, height) {} + + render() {} +} + +module.exports = WaveVisualizer; diff --git a/readme.md b/readme.md index ed490b31..03f2df33 100644 --- a/readme.md +++ b/readme.md @@ -108,6 +108,8 @@ winget install th-ch.YouTubeMusic - **Video Toggle**: Adds a [button](https://user-images.githubusercontent.com/28893833/173663950-63e6610e-a532-49b7-9afa-54cb57ddfc15.png) to switch between Video/Song mode. can also optionally remove the whole video tab +- **Visualizer**: Different music visualizers + --- - **Auto confirm when paused** (Always Enabled): disable the ["Continue Watching?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png) popup that pause music after a certain time diff --git a/yarn.lock b/yarn.lock index b7505584..7e583ea5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -202,6 +202,13 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.15.tgz#8e66775fb523599acb6a289e12929fa5ab0954d8" integrity sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ== +"@babel/runtime@^7.0.0": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd" + integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ== + dependencies: + regenerator-runtime "^0.13.11" + "@babel/runtime@^7.7.2": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.13.tgz#0a21452352b02542db0ffb928ac2d3ca7cb6d66d" @@ -374,6 +381,11 @@ regenerator-runtime "^0.13.7" resolve-url "^0.2.1" +"@foobar404/wave@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@foobar404/wave/-/wave-2.0.4.tgz#c9bc54c41b18642c6a4587851e28b8f858af98b0" + integrity sha512-FEyg37hDvQtrQVlFxbit7ov5e487BjsR32bZfJ4oAb5i+NnlbGaNyy6iYBZ8ocVHo8fgug+SL+mFdDTzqjvPww== + "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -1364,6 +1376,14 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -1557,6 +1577,23 @@ builtin-modules@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== +butterchurn-presets@^2.4.7: + version "2.4.7" + resolved "https://registry.yarnpkg.com/butterchurn-presets/-/butterchurn-presets-2.4.7.tgz#41e4e37cd3af2aec124fa8062352816100956c29" + integrity sha512-4MdM8ripz/VfH1BCldrIKdAc/1ryJFBDvqlyow6Ivo1frwj0H3duzvSMFC7/wIjAjxb1QpwVHVqGqS9uAFKhpg== + dependencies: + babel-runtime "^6.26.0" + ecma-proposal-math-extensions "0.0.2" + lodash "^4.17.4" + +butterchurn@^2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/butterchurn/-/butterchurn-2.6.7.tgz#1ff0c1365731a4fb7ada7bb16ae1c6f09a110c12" + integrity sha512-BJiRA8L0L2+84uoG2SSfkp0kclBuN+vQKf217pK7pMlwEO2ZEg3MtO2/o+l8Qpr8Nbejg8tmL1ZHD1jmhiaaqg== + dependencies: + "@babel/runtime" "^7.0.0" + ecma-proposal-math-extensions "0.0.2" + cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -1892,6 +1929,11 @@ convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" +core-js@^2.4.0: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -2266,6 +2308,11 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +ecma-proposal-math-extensions@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/ecma-proposal-math-extensions/-/ecma-proposal-math-extensions-0.0.2.tgz#a6a3d64819db70cee0d2e1976b6315d00e4714a0" + integrity sha512-80BnDp2Fn7RxXlEr5HHZblniY4aQ97MOAicdWWpSo0vkQiISSE9wLR4SqxKsu4gCtXFBIPPzy8JMhay4NWRg/Q== + ejs@^3.1.6: version "3.1.7" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.7.tgz#c544d9c7f715783dd92f0bddcf73a59e6962d006" @@ -4525,7 +4572,7 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= -lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.3.0: +lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.3.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5605,6 +5652,16 @@ redent@^4.0.0: indent-string "^5.0.0" strip-indent "^4.0.0" +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" @@ -6582,6 +6639,11 @@ verror@1.10.0, verror@^1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vudio@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/vudio/-/vudio-2.1.1.tgz#af256c4e1c8ae8bdbbba0e718f8106a30a44e96e" + integrity sha512-VkFQcFt/b/kpF5Eg5Sq+oXUo1Zp5aRFF4BSmIrOzau5o+5WMWwX9ae/EGJZstCyZFiCTU5iw1Y+u2BCGW6Y6Jw== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From 8728784c02d4c3d31df05e09239cdff6cec08856 Mon Sep 17 00:00:00 2001 From: MiepHD <63968466+MiepHD@users.noreply.github.com> Date: Mon, 9 Jan 2023 18:16:33 +0100 Subject: [PATCH 08/14] Fixed running before `#main-panel` exists --- plugins/video-toggle/button-switcher.css | 1 - plugins/video-toggle/front.js | 30 ++++++++++++------------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/plugins/video-toggle/button-switcher.css b/plugins/video-toggle/button-switcher.css index 048d1b6a..3bae2fc6 100644 --- a/plugins/video-toggle/button-switcher.css +++ b/plugins/video-toggle/button-switcher.css @@ -22,7 +22,6 @@ color: #fff; padding-right: 120px; position: absolute; - left: var(--align); } .video-switch-button:before { diff --git a/plugins/video-toggle/front.js b/plugins/video-toggle/front.js index 07f966c7..31c1b8f3 100644 --- a/plugins/video-toggle/front.js +++ b/plugins/video-toggle/front.js @@ -31,21 +31,6 @@ module.exports = (_options) => { document.addEventListener("apiLoaded", setup, { once: true, passive: true }); } } - const mainpanel = document.querySelector("#main-panel"); - switch (_options.align) { - case "right": { - mainpanel.style.setProperty("--align", "calc(100% - 240px)"); - return; - } - case "middle": { - mainpanel.style.setProperty("--align", "calc(50% - 120px)"); - return; - } - default: - case "left": { - mainpanel.style.setProperty("--align", "0px"); - } - } }; function setup(e) { @@ -73,6 +58,21 @@ function setup(e) { video.addEventListener('srcChanged', videoStarted); observeThumbnail(); + + switch (options.align) { + case "right": { + switchButtonDiv.style.left = "calc(100% - 240px)"; + return; + } + case "middle": { + switchButtonDiv.style.left = "calc(50% - 120px)"; + return; + } + default: + case "left": { + switchButtonDiv.style.left = "0px"; + } + } } function changeDisplay(showVideo) { From f9820df6c649a01e7cdbff7fe50ac0376d3724e0 Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Thu, 12 Jan 2023 19:18:58 +0200 Subject: [PATCH 09/14] fix PiP button fix #959 --- plugins/picture-in-picture/front.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js index 685b15c1..92b3d17e 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -69,7 +69,9 @@ function observeMenu(options) { listenForToggle(); const minButton = $(".player-minimize-button"); // remove native listeners + const svg = $(".player-minimize-button #icon svg").cloneNode(true); minButton.replaceWith(minButton.cloneNode(true)); + $(".player-minimize-button #icon").appendChild(svg); $(".player-minimize-button").onclick = () => { global.togglePictureInPicture(); setTimeout(() => $('#player').click()); From b3f561cf2f599202a101fe2af4a5ce49fd27d20a Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Thu, 12 Jan 2023 19:53:17 +0200 Subject: [PATCH 10/14] disable maximize button on PiP (doesn't work if `in-app-menu` is enabled) --- plugins/picture-in-picture/back.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/picture-in-picture/back.js b/plugins/picture-in-picture/back.js index fa679d79..d71acd49 100644 --- a/plugins/picture-in-picture/back.js +++ b/plugins/picture-in-picture/back.js @@ -47,6 +47,7 @@ const togglePiP = async () => { win.webContents.on("before-input-event", blockShortcutsInPiP); + win.setMaximizable(false); win.setFullScreenable(false); runAdaptors(); @@ -62,6 +63,7 @@ const togglePiP = async () => { } } else { win.webContents.removeListener("before-input-event", blockShortcutsInPiP); + win.setMaximizable(true); win.setFullScreenable(true); runAdaptors(); From 0e99f96f01803600c5b35de9f4c64169dd1625bd Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Thu, 12 Jan 2023 19:51:38 +0200 Subject: [PATCH 11/14] fix PiP unminimize button hidden --- plugins/picture-in-picture/front.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/plugins/picture-in-picture/front.js b/plugins/picture-in-picture/front.js index 92b3d17e..788a908e 100644 --- a/plugins/picture-in-picture/front.js +++ b/plugins/picture-in-picture/front.js @@ -10,6 +10,21 @@ const pipButton = ElementFromFile( templatePath(__dirname, "picture-in-picture.html") ); +// will also clone +function replaceButton(query, button) { + const svg = button.querySelector("#icon svg").cloneNode(true); + button.replaceWith(button.cloneNode(true)); + button.remove(); + const newButton = $(query); + newButton.querySelector("#icon").appendChild(svg); + return newButton; +} + +function cloneButton(query) { + replaceButton(query, $(query)); + return $(query); +} + const observer = new MutationObserver(() => { if (!menu) { menu = getSongMenu(); @@ -30,9 +45,6 @@ global.togglePictureInPicture = () => { const listenForToggle = () => { const originalExitButton = $(".exit-fullscreen-button"); - const clonedExitButton = originalExitButton.cloneNode(true); - clonedExitButton.onclick = () => togglePictureInPicture(); - const appLayout = $("ytmusic-app-layout"); const expandMenu = $('#expanding-menu'); const middleControls = $('.middle-controls'); @@ -44,7 +56,7 @@ const listenForToggle = () => { ipcRenderer.on('pip-toggle', (_, isPip) => { if (isPip) { - $(".exit-fullscreen-button").replaceWith(clonedExitButton); + replaceButton(".exit-fullscreen-button", originalExitButton).onclick = () => togglePictureInPicture(); player.onDoubleClick_ = () => {}; expandMenu.onmouseleave = () => middleControls.click(); if (!playerPage.playerPageOpen_) { @@ -67,12 +79,8 @@ function observeMenu(options) { "apiLoaded", () => { listenForToggle(); - const minButton = $(".player-minimize-button"); // remove native listeners - const svg = $(".player-minimize-button #icon svg").cloneNode(true); - minButton.replaceWith(minButton.cloneNode(true)); - $(".player-minimize-button #icon").appendChild(svg); - $(".player-minimize-button").onclick = () => { + cloneButton(".player-minimize-button").onclick = () => { global.togglePictureInPicture(); setTimeout(() => $('#player').click()); }; From 3389679287ca5c578336ebcaee79c11f402117f9 Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Sat, 14 Jan 2023 02:08:25 +0000 Subject: [PATCH 12/14] fix: upgrade custom-electron-titlebar from 4.1.3 to 4.1.5 Snyk has created this PR to upgrade custom-electron-titlebar from 4.1.3 to 4.1.5. See this package in npm: See this project in Snyk: https://app.snyk.io/org/th-ch/project/81809c53-bb7b-46b9-a0d7-806d45d74ac6?utm_source=github&utm_medium=referral&page=upgrade-pr --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index af2a9dca..401fb927 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "browser-id3-writer": "^4.4.0", "chokidar": "^3.5.3", "custom-electron-prompt": "^1.5.0", - "custom-electron-titlebar": "^4.1.2", + "custom-electron-titlebar": "^4.1.5", "discord-rpc": "^4.0.1", "electron-better-web-request": "^1.0.1", "electron-debug": "^3.2.0", diff --git a/yarn.lock b/yarn.lock index b7505584..d0a2fb4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1939,10 +1939,10 @@ custom-electron-prompt@^1.5.0: resolved "https://registry.yarnpkg.com/custom-electron-prompt/-/custom-electron-prompt-1.5.0.tgz#b514267f28e9f0d61011e03f76b1e59473af33d4" integrity sha512-DO+CIfO8c5lG+yzAkXD8PbFunPQ+WCJ4QeGN8bCvos7Fxt3xFDW0Qdnm1v9DKkAMj7iG0SujhdfNzsrtA4fl5g== -custom-electron-titlebar@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/custom-electron-titlebar/-/custom-electron-titlebar-4.1.3.tgz#6b5d0527858bae89314f3d0b4e6a0b9be4efad81" - integrity sha512-9tqiRxp7KG3qgS5Qh0ejSTwzqJ/pkB8RXQrvZHmilIzaWFmvjHiaSnHgCj+1iJcnhvzACYXFiFo2fxD64kFi4A== +custom-electron-titlebar@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/custom-electron-titlebar/-/custom-electron-titlebar-4.1.5.tgz#5032759ee5594fd618a62cff0de46150fd8e2b24" + integrity sha512-KpVmO+Fz34zNw/jYbOD6YwxPr6h2hgZmNbjy0AvhlXiH4dxeZJXDlMcBX08NqsESymMQvIWwsGaA//YGW1bXjA== dashdash@^1.12.0: version "1.14.1" From 210a16a32b3be928d808065a9258021ba3fc4efc Mon Sep 17 00:00:00 2001 From: Zohan Subhash Date: Sat, 14 Jan 2023 06:15:51 +0530 Subject: [PATCH 13/14] Update back.js --- plugins/touchbar/back.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/touchbar/back.js b/plugins/touchbar/back.js index 617682f5..02b28cc1 100644 --- a/plugins/touchbar/back.js +++ b/plugins/touchbar/back.js @@ -63,7 +63,7 @@ module.exports = (win) => { // If the page is ready, register the callback win.once("ready-to-show", () => { - controls = [previous, playPause, next, like, dislike]; + controls = [previous, playPause, next, dislike, like]; // Register the callback registerCallback((songInfo) => { From 6e96b355bd822e0105edc7178d536601cbb4c43a Mon Sep 17 00:00:00 2001 From: TC Date: Sat, 14 Jan 2023 14:44:02 +0100 Subject: [PATCH 14/14] Add migration for visualizer plugin --- config/store.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/store.js b/config/store.js index 85097c4e..c528d6a4 100644 --- a/config/store.js +++ b/config/store.js @@ -9,6 +9,9 @@ const setDefaultPluginOptions = (store, plugin) => { } const migrations = { + ">=1.20.0": (store) => { + setDefaultPluginOptions(store, "visualizer"); + }, ">=1.17.0": (store) => { setDefaultPluginOptions(store, "picture-in-picture");