diff --git a/index.js b/index.js index 814f3b76..39d077bc 100644 --- a/index.js +++ b/index.js @@ -28,8 +28,6 @@ if (config.get("options.disableHardwareAcceleration")) { // Adds debug features like hotkeys for triggering dev tools and reload require("electron-debug")(); -// these are the providers for the plugins, this shouldn't be hardcoded but it's temporarily -const providers = ["song-info"]; // Prevent window being garbage collected let mainWindow; autoUpdater.autoDownload = false; @@ -56,15 +54,6 @@ function loadPlugins(win) { } }); - providers.forEach(provider => { - console.log("Loaded provider - " + provider); - const providerPath = path.join(__dirname, "providers", provider, "back.js"); - fileExists(providerPath, () => { - const handle = require(providerPath); - handle(win); - }); - }); - config.plugins.getEnabled().forEach(([plugin, options]) => { console.log("Loaded plugin - " + plugin); const pluginPath = path.join(__dirname, "plugins", plugin, "back.js"); @@ -86,12 +75,21 @@ function createMainWindow() { backgroundColor: "#000", show: false, webPreferences: { - nodeIntegration: isTesting(), // Only necessary when testing with Spectron + // TODO: re-enable contextIsolation once it can work with ffmepg.wasm + // Possible bundling? https://github.com/ffmpegwasm/ffmpeg.wasm/issues/126 + contextIsolation: false, preload: path.join(__dirname, "preload.js"), nodeIntegrationInSubFrames: true, nativeWindowOpen: true, // window.open return Window object(like in regular browsers), not BrowserWindowProxy enableRemoteModule: true, affinity: "main-window", // main window, and addition windows should work in one process + ...(isTesting() + ? { + // Only necessary when testing with Spectron + contextIsolation: false, + nodeIntegration: true, + } + : undefined), }, frame: !is.macOS(), titleBarStyle: is.macOS() ? "hiddenInset" : "default", diff --git a/package.json b/package.json index 8a6afb8d..dda5ca6a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "youtube-music", "productName": "YouTube Music", - "version": "1.7.5", + "version": "1.8.2", "description": "YouTube Music Desktop App - including custom plugins", "license": "MIT", "repository": "th-ch/youtube-music", @@ -18,7 +18,8 @@ "icon": "assets/generated/icons/mac/icon.icns" }, "win": { - "icon": "assets/generated/icons/win/icon.ico" + "icon": "assets/generated/icons/win/icon.ico", + "target": ["nsis", "portable"] }, "linux": { "icon": "assets/generated/icons/png", @@ -55,9 +56,9 @@ "npm": "Please use yarn and not npm" }, "dependencies": { - "@cliqz/adblocker-electron": "^1.18.8", - "@ffmpeg/core": "^0.8.4", - "@ffmpeg/ffmpeg": "^0.9.5", + "@cliqz/adblocker-electron": "^1.19.0", + "@ffmpeg/core": "^0.8.5", + "@ffmpeg/ffmpeg": "^0.9.6", "YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.8.0", "discord-rpc": "^3.1.4", "downloads-folder": "^3.0.1", @@ -65,20 +66,20 @@ "electron-is": "^3.0.0", "electron-localshortcut": "^3.2.1", "electron-store": "^6.0.1", - "electron-updater": "^4.3.5", + "electron-updater": "^4.3.6", "filenamify": "^4.2.0", "node-fetch": "^2.6.1", - "ytdl-core": "^4.1.1" + "ytdl-core": "^4.1.2" }, "devDependencies": { - "electron": "^10.1.3", + "electron": "^11.1.1", "electron-builder": "^22.8.1", "electron-devtools-installer": "^3.1.1", "electron-icon-maker": "0.0.5", "get-port": "^5.1.1", "jest": "^26.4.2", "rimraf": "^3.0.2", - "spectron": "^12.0.0", + "spectron": "^13.0.0", "xo": "^0.33.1" }, "resolutions": { diff --git a/plugins/discord-rpc/back.js b/plugins/discord-rpc/back.js index d984a300..3e4ab629 100644 --- a/plugins/discord-rpc/back.js +++ b/plugins/discord-rpc/back.js @@ -1,41 +1,51 @@ -const Discord = require('discord-rpc'); +const Discord = require("discord-rpc"); + +const getSongInfo = require("../../providers/song-info"); + const rpc = new Discord.Client({ - transport: 'ipc' + transport: "ipc", }); -const clientId = '790655993809338398'; +// Application ID registered by @semvis123 +const clientId = "790655993809338398"; + +module.exports = (win) => { + const registerCallback = getSongInfo(win); -module.exports = win => { // If the page is ready, register the callback - win.on('ready-to-show', () => { - // Startup the rpc client - rpc.login({ - clientId - }).catch(console.error); + win.on("ready-to-show", () => { + rpc.on("ready", () => { + // Register the callback + registerCallback((songInfo) => { + // Song information changed, so lets update the rich presence + const activityInfo = { + details: songInfo.title, + state: songInfo.artist, + largeImageKey: "logo", + largeImageText: songInfo.views + " - " + songInfo.likes, + }; - // Register the callback - global.songInfo.onNewData(songInfo => { - // Song information changed, so lets update the rich presence + if (songInfo.isPaused) { + // Add an idle icon to show that the song is paused + activityInfo.smallImageKey = "idle"; + activityInfo.smallImageText = "idle/paused"; + } else { + // Add the start and end time of the song + const songStartTime = Date.now() - songInfo.elapsedSeconds * 1000; + activityInfo.startTimestamp = songStartTime; + activityInfo.endTimestamp = + songStartTime + songInfo.songDuration * 1000; + } - const activityInfo = { - details: songInfo.title, - state: songInfo.artist, - largeImageKey: 'logo', - largeImageText: songInfo.views + ' - ' + songInfo.likes - }; - - if (songInfo.isPaused) { - // Add an idle icon to show that the song is paused - activityInfo.smallImageKey = 'idle'; - activityInfo.smallImageText = 'idle/paused'; - } else { - // Add the start and end time of the song - const songStartTime = Date.now() - (songInfo.elapsedSeconds * 1000); - activityInfo.startTimestamp = songStartTime; - activityInfo.endTimestamp = songStartTime + (songInfo.songDuration * 1000); - } - - rpc.setActivity(activityInfo); + rpc.setActivity(activityInfo); + }); }); + + // Startup the rpc client + rpc + .login({ + clientId, + }) + .catch(console.error); }); }; diff --git a/plugins/downloader/front.js b/plugins/downloader/front.js index 00459281..732fd161 100644 --- a/plugins/downloader/front.js +++ b/plugins/downloader/front.js @@ -1,3 +1,5 @@ +const { contextBridge } = require("electron"); + const { ElementFromFile, templatePath, triggerAction } = require("../utils"); const { ACTIONS, CHANNEL } = require("./actions.js"); const { downloadVideoToMP3 } = require("./youtube-dl"); @@ -28,6 +30,9 @@ const reinit = () => { } }; +// TODO: re-enable once contextIsolation is set to true +// contextBridge.exposeInMainWorld("downloader", { +// download: () => { global.download = () => { const videoUrl = window.location.href; @@ -48,6 +53,7 @@ global.download = () => { pluginOptions ); }; +// }); function observeMenu(options) { pluginOptions = { ...pluginOptions, ...options }; diff --git a/plugins/downloader/youtube-dl.js b/plugins/downloader/youtube-dl.js index 3b0c7688..28f9836d 100644 --- a/plugins/downloader/youtube-dl.js +++ b/plugins/downloader/youtube-dl.js @@ -54,7 +54,12 @@ const downloadVideoToMP3 = ( .on("info", (info, format) => { videoName = info.videoDetails.title.replace("|", "").toString("ascii"); if (is.dev()) { - console.log("Downloading video - name:", videoName); + console.log( + "Downloading video - name:", + videoName, + "- quality:", + format.audioBitrate + "kbits/s" + ); } }) .on("error", sendError) @@ -73,6 +78,7 @@ const toMP3 = async ( options ) => { const safeVideoName = randomBytes(32).toString("hex"); + const extension = options.extension || "mp3"; try { if (!ffmpeg.isLoaded()) { @@ -87,15 +93,17 @@ const toMP3 = async ( await ffmpeg.run( "-i", safeVideoName, - ...options.ffmpegArgs, - safeVideoName + ".mp3" + ...(options.ffmpegArgs || []), + safeVideoName + "." + extension ); const folder = options.downloadFolder || downloadsFolder(); - const filename = filenamify(videoName + ".mp3", { replacement: "_" }); + const filename = filenamify(videoName + "." + extension, { + replacement: "_", + }); writeFileSync( join(folder, filename), - ffmpeg.FS("readFile", safeVideoName + ".mp3") + ffmpeg.FS("readFile", safeVideoName + "." + extension) ); reinit(); diff --git a/plugins/navigation/actions.js b/plugins/navigation/actions.js index 83947a63..69c8536b 100644 --- a/plugins/navigation/actions.js +++ b/plugins/navigation/actions.js @@ -1,24 +1,24 @@ -const { triggerAction } = require('../utils'); +const { triggerAction } = require("../utils"); const CHANNEL = "navigation"; const ACTIONS = { - NEXT: "next", - BACK: 'back', -} + NEXT: "next", + BACK: "back", +}; function goToNextPage() { - triggerAction(CHANNEL, ACTIONS.NEXT); + triggerAction(CHANNEL, ACTIONS.NEXT); } function goToPreviousPage() { - triggerAction(CHANNEL, ACTIONS.BACK); + triggerAction(CHANNEL, ACTIONS.BACK); } module.exports = { - CHANNEL: CHANNEL, - ACTIONS: ACTIONS, - global: { - goToNextPage: goToNextPage, - goToPreviousPage: goToPreviousPage, - } + CHANNEL: CHANNEL, + ACTIONS: ACTIONS, + actions: { + goToNextPage: goToNextPage, + goToPreviousPage: goToPreviousPage, + }, }; diff --git a/plugins/navigation/back.js b/plugins/navigation/back.js index 54ee18a7..6d0d0a2a 100644 --- a/plugins/navigation/back.js +++ b/plugins/navigation/back.js @@ -1,23 +1,23 @@ const path = require("path"); const { injectCSS, listenAction } = require("../utils"); -const { ACTIONS, CHANNEL } = require("./actions.js"); +const { ACTIONS, CHANNEL } = require("./actions.js"); function handle(win) { injectCSS(win.webContents, path.join(__dirname, "style.css")); listenAction(CHANNEL, (event, action) => { switch (action) { - case ACTIONS.NEXT: + case ACTIONS.NEXT: if (win.webContents.canGoForward()) { win.webContents.goForward(); } break; - case ACTIONS.BACK: + case ACTIONS.BACK: if (win.webContents.canGoBack()) { win.webContents.goBack(); } break; - default: + default: console.log("Unknown action: " + action); } }); diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js index ac5e6660..d70898cc 100644 --- a/plugins/notifications/back.js +++ b/plugins/notifications/back.js @@ -1,27 +1,31 @@ -const {Notification} = require('electron'); +const { Notification } = require("electron"); -const notify = info => { - let notificationImage = 'assets/youtube-music.png'; +const getSongInfo = require("../../providers/song-info"); + +const notify = (info) => { + let notificationImage = "assets/youtube-music.png"; if (info.image) { - notificationImage = info.image.resize({height: 256, width: 256}); + notificationImage = info.image.resize({ height: 256, width: 256 }); } // Fill the notification with content const notification = { - title: info.title || 'Playing', + title: info.title || "Playing", body: info.artist, icon: notificationImage, - silent: true + silent: true, }; // Send the notification new Notification(notification).show(); }; -module.exports = win => { - win.on('ready-to-show', () => { +module.exports = (win) => { + const registerCallback = getSongInfo(win); + + win.on("ready-to-show", () => { // Register the callback for new song information - global.songInfo.onNewData(songInfo => { + registerCallback((songInfo) => { // If song is playing send notification if (!songInfo.isPaused) { notify(songInfo); diff --git a/plugins/shortcuts/back.js b/plugins/shortcuts/back.js index 5a25a379..36efd0bc 100644 --- a/plugins/shortcuts/back.js +++ b/plugins/shortcuts/back.js @@ -1,12 +1,7 @@ const { globalShortcut } = require("electron"); const electronLocalshortcut = require("electron-localshortcut"); -const { - playPause, - nextTrack, - previousTrack, - startSearch -} = require("./youtube.js"); +const getSongControls = require("../../providers/song-controls"); function _registerGlobalShortcut(webContents, shortcut, action) { globalShortcut.register(shortcut, () => { @@ -21,11 +16,13 @@ function _registerLocalShortcut(win, shortcut, action) { } function registerShortcuts(win) { + const { playPause, next, previous, search } = getSongControls(win); + _registerGlobalShortcut(win.webContents, "MediaPlayPause", playPause); - _registerGlobalShortcut(win.webContents, "MediaNextTrack", nextTrack); - _registerGlobalShortcut(win.webContents, "MediaPreviousTrack", previousTrack); - _registerLocalShortcut(win, "CommandOrControl+F", startSearch); - _registerLocalShortcut(win, "CommandOrControl+L", startSearch); + _registerGlobalShortcut(win.webContents, "MediaNextTrack", next); + _registerGlobalShortcut(win.webContents, "MediaPreviousTrack", previous); + _registerLocalShortcut(win, "CommandOrControl+F", search); + _registerLocalShortcut(win, "CommandOrControl+L", search); } module.exports = registerShortcuts; diff --git a/plugins/shortcuts/youtube.js b/plugins/shortcuts/youtube.js deleted file mode 100644 index 6dd26199..00000000 --- a/plugins/shortcuts/youtube.js +++ /dev/null @@ -1,29 +0,0 @@ -function _keyboardInput(webContents, key) { - return webContents.sendInputEvent({ - type : "keydown", - keyCode: key - }); -} - -function playPause(webContents) { - return _keyboardInput(webContents, "Space"); -} - -function nextTrack(webContents) { - return _keyboardInput(webContents, "j"); -} - -function previousTrack(webContents) { - return _keyboardInput(webContents, "k"); -} - -function startSearch(webContents) { - return _keyboardInput(webContents, "/"); -} - -module.exports = { - playPause : playPause, - nextTrack : nextTrack, - previousTrack: previousTrack, - startSearch : startSearch -}; diff --git a/plugins/touchbar/back.js b/plugins/touchbar/back.js index 5e0a41bf..87240ed0 100644 --- a/plugins/touchbar/back.js +++ b/plugins/touchbar/back.js @@ -1,15 +1,18 @@ -const {TouchBar} = require('electron'); +const { TouchBar } = require("electron"); const { TouchBarButton, TouchBarLabel, TouchBarSpacer, TouchBarSegmentedControl, - TouchBarScrubber + TouchBarScrubber, } = TouchBar; +const getSongInfo = require("../../providers/song-info"); +const getSongControls = require("../../providers/song-controls"); + // Songtitle label const songTitle = new TouchBarLabel({ - label: '' + label: "", }); // This will store the song controls once available let controls = []; @@ -22,23 +25,23 @@ const pausePlayButton = new TouchBarButton(); // The song control buttons (control functions are in the same order) const buttons = new TouchBarSegmentedControl({ - mode: 'buttons', + mode: "buttons", segments: [ new TouchBarButton({ - label: '⏮' + label: "⏮", }), pausePlayButton, new TouchBarButton({ - label: '⏭' + label: "⏭", }), new TouchBarButton({ - label: '👎' + label: "👎", }), new TouchBarButton({ - label: '👍' - }) + label: "👍", + }), ], - change: i => controls[i]() + change: (i) => controls[i](), }); // This is the touchbar object, this combines everything with proper layout @@ -46,38 +49,37 @@ const touchBar = new TouchBar({ items: [ new TouchBarScrubber({ items: [songImage, songTitle], - continuous: false + continuous: false, }), new TouchBarSpacer({ - size: 'flexible' + size: "flexible", }), - buttons - ] + buttons, + ], }); -module.exports = win => { +module.exports = (win) => { + const registerCallback = getSongInfo(win); + const { playPause, next, previous, like, dislike } = getSongControls(win); + // If the page is ready, register the callback - win.on('ready-to-show', () => { - controls = [ - global.songControls.previous, - global.songControls.pause, - global.songControls.next, - global.songControls.like, - global.songControls.dislike - ]; + win.on("ready-to-show", () => { + controls = [previous, playPause, next, like, dislike]; // Register the callback - global.songInfo.onNewData(songInfo => { + registerCallback((songInfo) => { // Song information changed, so lets update the touchBar // Set the song title songTitle.label = songInfo.title; // Changes the pause button if paused - pausePlayButton.label = songInfo.isPaused ? '▶️' : '⏸'; + pausePlayButton.label = songInfo.isPaused ? "▶️" : "⏸"; // Get image source - songImage.icon = songInfo.image ? songInfo.image.resize({height: 23}) : null; + songImage.icon = songInfo.image + ? songInfo.image.resize({ height: 23 }) + : null; win.setTouchBar(touchBar); }); diff --git a/preload.js b/preload.js index 362c9170..c3d51d16 100644 --- a/preload.js +++ b/preload.js @@ -1,6 +1,6 @@ const path = require("path"); -const { remote } = require("electron"); +const { contextBridge, remote } = require("electron"); const config = require("./config"); const { fileExists } = require("./plugins/utils"); @@ -10,7 +10,10 @@ const plugins = config.plugins.getEnabled(); plugins.forEach(([plugin, options]) => { const pluginPath = path.join(__dirname, "plugins", plugin, "actions.js"); fileExists(pluginPath, () => { - const actions = require(pluginPath).global || {}; + const actions = require(pluginPath).actions || {}; + + // TODO: re-enable once contextIsolation is set to true + // contextBridge.exposeInMainWorld(plugin + "Actions", actions); Object.keys(actions).forEach((actionName) => { global[actionName] = actions[actionName]; }); diff --git a/providers/song-controls.js b/providers/song-controls.js new file mode 100644 index 00000000..20946a38 --- /dev/null +++ b/providers/song-controls.js @@ -0,0 +1,18 @@ +// This is used for to control the songs +const pressKey = (window, key) => { + window.webContents.sendInputEvent({ + type: "keydown", + keyCode: key, + }); +}; + +module.exports = (win) => { + return { + previous: () => pressKey(win, "k"), + next: () => pressKey(win, "j"), + playPause: () => pressKey(win, "space"), + like: () => pressKey(win, "_"), + dislike: () => pressKey(win, "+"), + search: () => pressKey(win, "/"), + }; +}; diff --git a/providers/song-info.js b/providers/song-info.js new file mode 100644 index 00000000..4ddf9cab --- /dev/null +++ b/providers/song-info.js @@ -0,0 +1,137 @@ +const { nativeImage } = require("electron"); + +const fetch = require("node-fetch"); + +// This selects the song title +const titleSelector = ".title.style-scope.ytmusic-player-bar"; + +// This selects the song image +const imageSelector = + "#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > img"; + +// This selects the song subinfo, this includes artist, views, likes +const subInfoSelector = + "#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.content-info-wrapper.style-scope.ytmusic-player-bar > span"; + +// This selects the progress bar, used for songlength and current progress +const progressSelector = "#progress-bar"; + +// Grab the title using the selector +const getTitle = (win) => { + return win.webContents + .executeJavaScript( + "document.querySelector('" + titleSelector + "').innerText" + ) + .catch((error) => { + console.log(error); + }); +}; + +// Grab the image src using the selector +const getImageSrc = (win) => { + return win.webContents + .executeJavaScript("document.querySelector('" + imageSelector + "').src") + .catch((error) => { + console.log(error); + }); +}; + +// Grab the subinfo using the selector +const getSubInfo = async (win) => { + // Get innerText of subinfo element + const subInfoString = await win.webContents.executeJavaScript( + 'document.querySelector("' + subInfoSelector + '").innerText' + ); + + // Split and clean the string + const splittedSubInfo = subInfoString.replaceAll("\n", "").split(" • "); + + // Make sure we always return 3 elements in the aray + const subInfo = []; + for (let i = 0; i < 3; i++) { + // Fill array with empty string if not defined + subInfo.push(splittedSubInfo[i] || ""); + } + + return subInfo; +}; + +// Grab the progress using the selector +const getProgress = async (win) => { + // Get max value of the progressbar element + const songDuration = await win.webContents.executeJavaScript( + 'document.querySelector("' + progressSelector + '").max' + ); + // Get current value of the progressbar element + const elapsedSeconds = await win.webContents.executeJavaScript( + 'document.querySelector("' + progressSelector + '").value' + ); + + return { songDuration, elapsedSeconds }; +}; + +// Grab the native image using the src +const getImage = async (src) => { + const result = await fetch(src); + const buffer = await result.buffer(); + return nativeImage.createFromBuffer(buffer); +}; + +const getPausedStatus = async (win) => { + const title = await win.webContents.executeJavaScript("document.title"); + return !title.includes("-"); +}; + +// Fill songInfo with empty values +const songInfo = { + title: "", + artist: "", + views: "", + likes: "", + imageSrc: "", + image: null, + isPaused: true, + songDuration: 0, + elapsedSeconds: 0, +}; + +const registerProvider = (win) => { + // This variable will be filled with the callbacks once they register + const callbacks = []; + + // This function will allow plugins to register callback that will be triggered when data changes + const registerCallback = (callback) => { + callbacks.push(callback); + }; + + win.on("page-title-updated", async () => { + // Save the old title temporarily + const oldTitle = songInfo.title; + // Get and set the new data + songInfo.title = await getTitle(win); + songInfo.isPaused = await getPausedStatus(win); + + const { songDuration, elapsedSeconds } = await getProgress(win); + songInfo.songDuration = songDuration; + songInfo.elapsedSeconds = elapsedSeconds; + + // If title changed then we do need to update other info + if (oldTitle !== songInfo.title) { + const subInfo = await getSubInfo(win); + songInfo.artist = subInfo[0]; + songInfo.views = subInfo[1]; + songInfo.likes = subInfo[2]; + songInfo.imageSrc = await getImageSrc(win); + songInfo.image = await getImage(songInfo.imageSrc); + } + + // Trigger the callbacks + callbacks.forEach((c) => { + c(songInfo); + }); + }); + + return registerCallback; +}; + +module.exports = registerProvider; diff --git a/providers/song-info/back.js b/providers/song-info/back.js deleted file mode 100644 index 117ec947..00000000 --- a/providers/song-info/back.js +++ /dev/null @@ -1,141 +0,0 @@ -const {nativeImage} = require('electron'); -const fetch = require('node-fetch'); - -// This selects the song title -const titleSelector = '.title.style-scope.ytmusic-player-bar'; - -// This selects the song image -const imageSelector = '#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > img'; - -// This selects the song subinfo, this includes artist, views, likes -const subInfoSelector = '#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.content-info-wrapper.style-scope.ytmusic-player-bar > span'; - -// This selects the progress bar, used for songlength and current progress -const progressSelector = '#progress-bar'; - -// This is used for to control the songs -const presskey = (window, key) => { - window.webContents.sendInputEvent({ - type: 'keydown', - keyCode: key - }); -}; - -// Grab the title using the selector -const getTitle = win => { - return win.webContents.executeJavaScript( - 'document.querySelector(\'' + titleSelector + '\').innerText' - ).catch(error => { - console.log(error); - }); -}; - -// Grab the image src using the selector -const getImageSrc = win => { - return win.webContents.executeJavaScript( - 'document.querySelector(\'' + imageSelector + '\').src' - ).catch(error => { - console.log(error); - }); -}; - -// Grab the subinfo using the selector -const getSubInfo = async win => { - // Get innerText of subinfo element - const subInfoString = await win.webContents.executeJavaScript( - 'document.querySelector("' + subInfoSelector + '").innerText'); - - // Split and clean the string - const splittedSubInfo = subInfoString.replaceAll('\n', '').split(' • '); - - // Make sure we always return 3 elements in the aray - const subInfo = []; - for (let i = 0; i < 3; i++) { - // Fill array with empty string if not defined - subInfo.push(splittedSubInfo[i] || ''); - } - - return subInfo; -}; - -// Grab the progress using the selector -const getProgress = async win => { - // Get max value of the progressbar element - const songDuration = await win.webContents.executeJavaScript( - 'document.querySelector("' + progressSelector + '").max'); - // Get current value of the progressbar element - const elapsedSeconds = await win.webContents.executeJavaScript( - 'document.querySelector("' + progressSelector + '").value'); - - return {songDuration, elapsedSeconds}; -}; - -// Grab the native image using the src -const getImage = async src => { - const result = await fetch(src); - const buffer = await result.buffer(); - return nativeImage.createFromBuffer(buffer); -}; - -const getPausedStatus = async win => { - const title = await win.webContents.executeJavaScript('document.title'); - return !title.includes('-'); -}; - -// This variable will be filled with the callbacks once they register -const callbacks = []; - -module.exports = win => { - // Fill songInfo with empty values - global.songInfo = { - title: '', - artist: '', - views: '', - likes: '', - imageSrc: '', - image: null, - isPaused: true, - songDuration: 0, - elapsedSeconds: 0 - }; - // The song control functions - global.songControls = { - previous: () => presskey(win, 'k'), - next: () => presskey(win, 'j'), - pause: () => presskey(win, 'space'), - like: () => presskey(win, '_'), - dislike: () => presskey(win, '+') - }; - - // This function will allow plugins to register callback that will be triggered when data changes - global.songInfo.onNewData = callback => { - callbacks.push(callback); - }; - - win.on('page-title-updated', async () => { - // Save the old title temporarily - const oldTitle = global.songInfo.title; - // Get and set the new data - global.songInfo.title = await getTitle(win); - global.songInfo.isPaused = await getPausedStatus(win); - - const {songDuration, elapsedSeconds} = await getProgress(win); - global.songInfo.songDuration = songDuration; - global.songInfo.elapsedSeconds = elapsedSeconds; - - // If title changed then we do need to update other info - if (oldTitle !== global.songInfo.title) { - const subInfo = await getSubInfo(win); - global.songInfo.artist = subInfo[0]; - global.songInfo.views = subInfo[1]; - global.songInfo.likes = subInfo[2]; - global.songInfo.imageSrc = await getImageSrc(win); - global.songInfo.image = await getImage(global.songInfo.imageSrc); - } - - // Trigger the callbacks - callbacks.forEach(c => { - c(global.songInfo); - }); - }); -}; diff --git a/readme.md b/readme.md index a391f529..7df27f0c 100644 --- a/readme.md +++ b/readme.md @@ -43,6 +43,7 @@ Install the `youtube-music-bin` package from the AUR. For AUR installation instr - **Auto confirm when paused**: when the "Continue Watching?" modal appears, automatically click "Yes" - **Hide video player**: no video in the interface when playing music - **Notifications**: display a notification when a song starts playing +- **Touchbar**: custom TouchBar layout for macOS ## Dev diff --git a/yarn.lock b/yarn.lock index 6ffdc3ec..f6cc45c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -372,36 +372,36 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@cliqz/adblocker-content@^1.18.8": - version "1.18.8" - resolved "https://registry.yarnpkg.com/@cliqz/adblocker-content/-/adblocker-content-1.18.8.tgz#96473f14c098a20091298d34a6addcd430aceebd" - integrity sha512-YZ1xYBVG3LmxsdTYvTs/Bc7pzCw/Dy4HFo6N+oIuGP+Le/0aGSkACUl3ue5I2+Cx0WmL0Z8I4QonTKDc06HR+A== +"@cliqz/adblocker-content@^1.19.0": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@cliqz/adblocker-content/-/adblocker-content-1.19.0.tgz#c3e8ce50a719905cfcb66b114882c086b5074131" + integrity sha512-sciMicb+zmN5+iKCiDnWPegepgI32XzX4Snf1VxR+HAFwYGJmfk25vpL6ONd6hOlpmumxHkE/y5l7suH0ziP5g== -"@cliqz/adblocker-electron-preload@^1.18.8": - version "1.18.8" - resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron-preload/-/adblocker-electron-preload-1.18.8.tgz#c2058647e015b6f61c222e7d58040347324c63b0" - integrity sha512-/FAzyhNUj+8fwqSGth7ndaC+8huEANvVquYkDVmjM38uryxFgcJJI6Bij1l1zABIbskAaSN4G4RI3oERyd9/KQ== +"@cliqz/adblocker-electron-preload@^1.19.0": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron-preload/-/adblocker-electron-preload-1.19.0.tgz#960332fb3bc6e68e13596bc280f68aa9ee5e3170" + integrity sha512-ns+VCyb+H8U5rKC4lfvAbb1KxZiIKFs3F8HvivRkGBFqjEzaCUC4s/kf6P+tWCLC69lVgrZUDIzFHkKmGG9LPA== dependencies: - "@cliqz/adblocker-content" "^1.18.8" + "@cliqz/adblocker-content" "^1.19.0" -"@cliqz/adblocker-electron@^1.18.8": - version "1.18.8" - resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron/-/adblocker-electron-1.18.8.tgz#5f697c5dc65cd936b3908078a6e4516ec995567a" - integrity sha512-CrsFjSwenWQogsAg4sHFaXZbu7hzs9dMdsZM5wxb+5QfZ3MSH3PBYAeAUnsmP3UOTZ423+6ErOUE1vzj3UrK9w== +"@cliqz/adblocker-electron@^1.19.0": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron/-/adblocker-electron-1.19.0.tgz#9be5e10e93cd0488b79c54e44a265687b3d07a87" + integrity sha512-UFhhHAQUI02HXWEX0Yjw+sCzJrdLbcGjCdjbaPjkYSv/w+uGaq7TahE1IXGALkS8vXHenA2iJdJglt2mh96Uuw== dependencies: - "@cliqz/adblocker" "^1.18.8" - "@cliqz/adblocker-electron-preload" "^1.18.8" + "@cliqz/adblocker" "^1.19.0" + "@cliqz/adblocker-electron-preload" "^1.19.0" tldts-experimental "^5.6.21" -"@cliqz/adblocker@^1.18.8": - version "1.18.8" - resolved "https://registry.yarnpkg.com/@cliqz/adblocker/-/adblocker-1.18.8.tgz#f6e5724fe6573c2e68f2545d90bcce3e1ecfbae9" - integrity sha512-19m0GhlOcdSvQ/BqVuaMgbYkgQ4ys8koBRW4K7Ua4V5fFWL0t8ckdcZ/gBOqwECS2m8agXSpEbbyJjNmHBHpMQ== +"@cliqz/adblocker@^1.19.0": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@cliqz/adblocker/-/adblocker-1.19.0.tgz#1521673172998d0a691aeb1f2b2c1732c9b8c6ab" + integrity sha512-sy/aBjPoQsqLI5XYHAaZfgi+7HpddJmoHn/UMyX0dx0/jnnaM2/Z2LGylOsGwjW97GsNvvqSwXgxsEH2R0K9SQ== dependencies: "@remusao/guess-url-type" "^1.1.2" "@remusao/small" "^1.1.2" "@remusao/smaz" "^1.7.1" - "@types/chrome" "^0.0.126" + "@types/chrome" "^0.0.127" "@types/firefox-webext-browser" "^82.0.0" tldts-experimental "^5.6.21" @@ -469,15 +469,15 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@ffmpeg/core@^0.8.4": - version "0.8.4" - resolved "https://registry.yarnpkg.com/@ffmpeg/core/-/core-0.8.4.tgz#69062a9b257792a9a8445e1f01e68c3e5e7fe58b" - integrity sha512-gEr4qXZpShZpIVUO3hc5Vz7bkk/jLYuzVVQtHluUwrui5eAooQwExOGiEovzLVkRwjJ707/qqfmTrK3r80UkWw== +"@ffmpeg/core@^0.8.5": + version "0.8.5" + resolved "https://registry.yarnpkg.com/@ffmpeg/core/-/core-0.8.5.tgz#2d0b7d4409a4348fa6a1888c247de706ffc0e63f" + integrity sha512-hemVFmhVLbD/VZaCG2BvCzFglKytMIMJ5aJfc12eXN4O4cG0wXnGTMVzlK1KKW/6viHhJMPkc9h4UDnJW8Uivg== -"@ffmpeg/ffmpeg@^0.9.5": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@ffmpeg/ffmpeg/-/ffmpeg-0.9.5.tgz#6624747dc331632bc7c581e8d4f2046abc933798" - integrity sha512-Vtxgi5C89n36pJ3I1/l6xd2qSwn+s1tAtLvFJ98N9P2ZorBvxXCEwTkt2yL7GuOUX9wpdG/vLFqp7iLso8LDwg== +"@ffmpeg/ffmpeg@^0.9.6": + version "0.9.6" + resolved "https://registry.yarnpkg.com/@ffmpeg/ffmpeg/-/ffmpeg-0.9.6.tgz#b44fa1ab34dd860785bb7c317dbfbe8b9ded7036" + integrity sha512-ov5FAV3dHRJ/+ZxQH9V5GvY/iczwq5vrKWeu4tpytxZewTSAhZ1aKD/sFBzd79nQNF+CTktxUp3LWuGECXBNeA== dependencies: is-url "^1.2.4" node-fetch "^2.6.1" @@ -1100,10 +1100,10 @@ "@types/node" "*" "@types/responselike" "*" -"@types/chrome@^0.0.126": - version "0.0.126" - resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.126.tgz#f9f3436712f0c7c12ea9798abc9b95575ad7b23a" - integrity sha512-191z7uoyfbGU+z7/m45j9XbWugWqVHVPMM4hJV5cZ+3YzGCT9wFjMUHO3Wr3Xvo8aVodvRNu28u7lvEaAnfbzg== +"@types/chrome@^0.0.127": + version "0.0.127" + resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.127.tgz#9e29f351d558f60e95326ceadc586fdcc824151b" + integrity sha512-hBB9EApLYKKn2GvklVkTxVP6vZvxsH9okyIRUinNtMzZHIgIKWQk/ESbX+O5g4Bihfy38+aFGn7Kl7Cxou5JUg== dependencies: "@types/filesystem" "*" "@types/har-format" "*" @@ -1244,10 +1244,17 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.1.tgz#be148756d5480a84cde100324c03a86ae5739fb5" integrity sha512-2zs+O+UkDsJ1Vcp667pd3f8xearMdopz/z54i99wtRDI5KLmngk7vlrYZD0ZjKHaROR03EznlBbVY9PfAEyJIQ== -"@types/puppeteer@^3.0.1": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-3.0.2.tgz#20085220593b560c7332b6d46aecaf81ae263540" - integrity sha512-JRuHPSbHZBadOxxFwpyZPeRlpPTTeMbQneMdpFd8LXdyNfFSiX950CGewdm69g/ipzEAXAmMyFF1WOWJOL/nKw== +"@types/puppeteer-core@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@types/puppeteer-core/-/puppeteer-core-5.4.0.tgz#880a7917b4ede95cbfe2d5e81a558cfcb072c0fb" + integrity sha512-yqRPuv4EFcSkTyin6Yy17pN6Qz2vwVwTCJIDYMXbE3j8vTPhv0nCQlZOl5xfi0WHUkqvQsjAR8hAfjeMCoetwg== + dependencies: + "@types/puppeteer" "*" + +"@types/puppeteer@*": + version "5.4.2" + resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-5.4.2.tgz#80f3a1f54dedbbf750779716de81401549062072" + integrity sha512-yjbHoKjZFOGqA6bIEI2dfBE5UPqU0YGWzP+ipDVP1iGzmlhksVKTBVZfT3Aj3wnvmcJ2PQ9zcncwOwyavmafBw== dependencies: "@types/node" "*" @@ -1258,12 +1265,10 @@ dependencies: "@types/node" "*" -"@types/semver@^7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.1.tgz#7a9a5d595b6d873f338c867dcef64df289468cfa" - integrity sha512-ooD/FJ8EuwlDKOI6D9HWxgIgJjMg2cuziXm/42npDC8y4NjxplBUn9loewZiBNCt44450lHAU0OSb51/UqXeag== - dependencies: - "@types/node" "*" +"@types/semver@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb" + integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ== "@types/stack-utils@^1.0.1": version "1.0.1" @@ -1356,43 +1361,43 @@ dependencies: eslint-visitor-keys "^1.1.0" -"@wdio/config@6.4.7": - version "6.4.7" - resolved "https://registry.yarnpkg.com/@wdio/config/-/config-6.4.7.tgz#f2402a6067b15fdc61e9701458f60adc388ae75c" - integrity sha512-wtcj9yKm5+SivwhsgpusBrFR7a3rpDsN/WH6ekoqlZFs7oCpJeTLwawWnoX6MJQy2no5o00lGxDDJnqjaBdiiQ== +"@wdio/config@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@wdio/config/-/config-6.11.0.tgz#ba6b0ef72d9f40bd577da16602de84390c3dcdb4" + integrity sha512-aNkH5sPEybOf7ND1JrAlCsKZow6KMAaY3Wyf9yHralQ3xmclmswFKU/DseP7go17Ivc2KHLl7MMkNaqVY90siw== dependencies: - "@wdio/logger" "6.4.7" + "@wdio/logger" "6.10.10" deepmerge "^4.0.0" glob "^7.1.2" -"@wdio/logger@6.4.7": - version "6.4.7" - resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-6.4.7.tgz#6d83033a0d7ef20f3b2cc2420956105903a6a4e7" - integrity sha512-Mm/rsRa/1u/l8/IrNKM2c9tkvLE90i83d3KZ0Ujh4cicYJv+lNi9whsCi+p3QNFCo64nJ6bfC+0Ho5VgD3MiKw== +"@wdio/logger@6.10.10": + version "6.10.10" + resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-6.10.10.tgz#1e07cf32a69606ddb94fa9fd4b0171cb839a5980" + integrity sha512-2nh0hJz9HeZE0VIEMI+oPgjr/Q37ohrR9iqsl7f7GW5ik+PnKYCT9Eab5mR1GNMG60askwbskgGC1S9ygtvrSw== dependencies: chalk "^4.0.0" loglevel "^1.6.0" loglevel-plugin-prefix "^0.8.4" strip-ansi "^6.0.0" -"@wdio/protocols@6.3.6": - version "6.3.6" - resolved "https://registry.yarnpkg.com/@wdio/protocols/-/protocols-6.3.6.tgz#fc408b4441d9701bdd370b0981cf243862ce7e19" - integrity sha512-cocBRkv5sYUBxXResuxskQhIkKgDgE/yAtgMGR5wXLrtG/sMpZ2HVy6LOcOeARidAaRwbav80M2ZHjTCjPn53w== +"@wdio/protocols@6.10.6": + version "6.10.6" + resolved "https://registry.yarnpkg.com/@wdio/protocols/-/protocols-6.10.6.tgz#8d1deed6651a5ca0a185ea334fc1a371dc4c700c" + integrity sha512-CLLVdc82S+Zij7f9djL90JC1bE5gtaOn+EF2pY4n8XdypqPUa1orQip8stQtX/wXEX0Ak45MEcSU9nCY+CzNnQ== -"@wdio/repl@6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@wdio/repl/-/repl-6.5.0.tgz#1e3ef2dfbc1ead1280b21bb053ad509816722466" - integrity sha512-qKm2j0qY7mrZQipHv4PhKpAL7pkyxCzW1XDoEjp09OHLvmGvvCwY6aEBuLziD9BaiR30BXVNLIKPZfM4Xl2Zfg== +"@wdio/repl@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@wdio/repl/-/repl-6.11.0.tgz#5b1eab574b6b89f7f7c383e7295c06af23c3818e" + integrity sha512-FxrFKiTkFyELNGGVEH1uijyvNY7lUpmff6x+FGskFGZB4uSRs0rxkOMaEjxnxw7QP1zgQKr2xC7GyO03gIGRGg== dependencies: - "@wdio/utils" "6.5.0" + "@wdio/utils" "6.11.0" -"@wdio/utils@6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-6.5.0.tgz#46398b08e6741eb97a57089b2c909622c480ea22" - integrity sha512-k5RxRj/re/BbK76SjWSmyhJFHWnXD74vl/doCAQNuOaKFBd2dqMCs3GiFjYCyLcU37XGMAnRvI3tKHflyLGJYw== +"@wdio/utils@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-6.11.0.tgz#878c2500efb1a325bf5a66d2ff3d08162f976e8c" + integrity sha512-vf0sOQzd28WbI26d6/ORrQ4XKWTzSlWLm9W/K/eJO0NASKPEzR+E+Q2kaa+MJ4FKXUpjbt+Lxfo+C26TzBk7tg== dependencies: - "@wdio/logger" "6.4.7" + "@wdio/logger" "6.10.10" "YoutubeNonStop@git://github.com/lawfx/YoutubeNonStop.git#v0.8.0": version "0.0.0" @@ -2091,6 +2096,14 @@ builder-util-runtime@8.7.2: debug "^4.1.1" sax "^1.2.4" +builder-util-runtime@8.7.3: + version "8.7.3" + resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.3.tgz#0aaafa52d25295c939496f62231ca9ff06c30e40" + integrity sha512-1Q2ReBqFblimF5g/TLg2+0M5Xzv0Ih5LxJ/BMWXvEy/e6pQKeeEpbkPMGsN6OiQgkygaZo5VXCXIjOkOQG5EoQ== + dependencies: + debug "^4.3.2" + sax "^1.2.4" + builder-util@22.8.1: version "22.8.1" resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-22.8.1.tgz#efdfb327dbc22c59aa1e2f55adbe0e771086e839" @@ -2624,6 +2637,11 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== +css-shorthand-properties@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz#1c808e63553c283f289f2dd56fcee8f3337bd935" + integrity sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A== + css-value@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea" @@ -2690,6 +2708,13 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" +debug@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -2850,16 +2875,17 @@ devtools-protocol@0.0.799653: resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.799653.tgz#86fc95ce5bf4fdf4b77a58047ba9d2301078f119" integrity sha512-t1CcaZbvm8pOlikqrsIM9GOa7Ipp07+4h/q9u0JXBWjPCjHdBl9KkddX87Vv9vBHoBGtwV79sYQNGnQM6iS5gg== -devtools@6.5.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/devtools/-/devtools-6.5.0.tgz#48f9b72cb8f347c8658b46db940da75288f721c6" - integrity sha512-P/9+jSK+Jq4gWO5a79OLtDsZPcrNZN9JDCqWdCmKcbCCikV3fYic+0wmRzAPff8iYLCdmNXf/no4XMLwXR5LXQ== +devtools@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/devtools/-/devtools-6.11.0.tgz#d20f1d1bb42357d3f2e424d7103fdd3e0d339879" + integrity sha512-fqiRz77IIGkHfHdIkVYIpBNKz7qllJJvHP92NKDo5e41J+sSVKsjzHsPqvYLugRhSGsZKPrJ19Sj8kmPyFi18w== dependencies: - "@wdio/config" "6.4.7" - "@wdio/logger" "6.4.7" - "@wdio/protocols" "6.3.6" - "@wdio/utils" "6.5.0" + "@wdio/config" "6.11.0" + "@wdio/logger" "6.10.10" + "@wdio/protocols" "6.10.6" + "@wdio/utils" "6.11.0" chrome-launcher "^0.13.1" + edge-paths "^2.1.0" puppeteer-core "^5.1.0" ua-parser-js "^0.7.21" uuid "^8.0.0" @@ -2974,6 +3000,11 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +edge-paths@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/edge-paths/-/edge-paths-2.1.0.tgz#f273f3a0fe022422048bb78f83eb61aca29977ef" + integrity sha512-ZpIN1Vm5hlo9dkkST/1s8QqPNne2uwk3Plf6HcVUhnpfal0WnDRLdNj/wdQo3xRc+wnN3C25wPpPlV2E6aOunQ== + ejs@^3.1.3: version "3.1.5" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.5.tgz#aed723844dc20acb4b170cd9ab1017e476a0d93b" @@ -3001,10 +3032,10 @@ electron-builder@^22.8.1: update-notifier "^4.1.0" yargs "^15.4.1" -electron-chromedriver@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-10.0.0.tgz#cea6ee9f2d67f794b7439074fd70060109a7ff56" - integrity sha512-6jvMnQNHsIFTnvSn8kYQk8dRXFjqtp7E4QVIP4Cc6xR7SM8QI0/EmAqfuysd8CGJOpa8wFkEYxCT2dbHGp3bDw== +electron-chromedriver@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-11.0.0.tgz#49b034ed0ad12c12e3522862c7bb46875a0d85e1" + integrity sha512-ayMJPBbB4puU0SqYbcD9XvF3/7GWIhqKE1n5lG2/GQPRnrZkNoPIilsrS0rQcD50Xhl69KowatDqLhUznZWtbA== dependencies: "@electron/get" "^1.12.2" extract-zip "^2.0.0" @@ -3100,23 +3131,23 @@ electron-store@^6.0.1: conf "^7.1.2" type-fest "^0.16.0" -electron-updater@^4.3.5: - version "4.3.5" - resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.5.tgz#4fb36f593a031c87ea07ee141c9f064d5deffb15" - integrity sha512-5jjN7ebvfj1cLI0VZMdCnJk6aC4bP+dy7ryBf21vArR0JzpRVk0OZHA2QBD+H5rm6ZSeDYHOY6+8PrMEqJ4wlQ== +electron-updater@^4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.7.tgz#632434cf1dd856e37f5557a68b55867fae29c39e" + integrity sha512-F7l1ZdslA5Do9kABNhiYKMPzreLulFTv+rsbGUQJ3TnRKrEb3JAi/n/jco3mI8LOEG/pgS5f9ytQ+D+5r/PvQw== dependencies: - "@types/semver" "^7.3.1" - builder-util-runtime "8.7.2" + "@types/semver" "^7.3.4" + builder-util-runtime "8.7.3" fs-extra "^9.0.1" - js-yaml "^3.14.0" + js-yaml "^3.14.1" lazy-val "^1.0.4" lodash.isequal "^4.5.0" - semver "^7.3.2" + semver "^7.3.4" -electron@^10.1.3: - version "10.1.3" - resolved "https://registry.yarnpkg.com/electron/-/electron-10.1.3.tgz#7e276e373bf30078bd4cb1184850a91268dc0e6c" - integrity sha512-CR8LrlG47MdAp317SQ3vGYa2o2cIMdMSMPYH46OVitFLk35dwE9fn3VqvhUIXhCHYcNWIAPzMhkVHpkoFdKWuw== +electron@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/electron/-/electron-11.1.1.tgz#188f036f8282798398dca9513e9bb3b10213e3aa" + integrity sha512-tlbex3xosJgfileN6BAQRotevPRXB/wQIq48QeQ08tUJJrXwE72c8smsM/hbHx5eDgnbfJ2G3a60PmRjHU2NhA== dependencies: "@electron/get" "^1.0.1" "@types/node" "^12.0.12" @@ -4392,11 +4423,6 @@ html-encoding-sniffer@^2.0.1: dependencies: whatwg-encoding "^1.0.5" -html-entities@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" - integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== - html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -5420,6 +5446,14 @@ js-yaml@^3.14.0: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -6245,9 +6279,9 @@ node-modules-regexp@^1.0.0: integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= node-notifier@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" - integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== + version "8.0.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.1.tgz#f86e89bbc925f2b068784b31f382afdc6ca56be1" + integrity sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA== dependencies: growly "^1.3.0" is-wsl "^2.2.0" @@ -7279,7 +7313,7 @@ request-promise-native@^1.0.8: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.81.0, request@^2.87.0, request@^2.88.2: +request@^2.81.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -7380,10 +7414,10 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" -resq@^1.6.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/resq/-/resq-1.8.0.tgz#06c738e122bd024395cd729fb1e07248a1d2c340" - integrity sha512-VObcnfPcE6/EKfHqsi5qoJ0+BF9qfl5181CytP1su3HgzilqF03DrQ+Y7kZQrd+5myfmantl9W3/5uUcpwvKeg== +resq@^1.9.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/resq/-/resq-1.10.0.tgz#40b5e3515ff984668e6b6b7c2401f282b08042ea" + integrity sha512-hCUd0xMalqtPDz4jXIqs0M5Wnv/LZXN8h7unFOo4/nvExT9dDPbhwd3udRxLlp0HgBnHcV009UlduE9NZi7A6w== dependencies: fast-deep-equal "^2.0.1" @@ -7392,10 +7426,10 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -rgb2hex@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.2.0.tgz#801b4887127181d1e691f610df2cecdb77330265" - integrity sha512-cHdNTwmTMPu/TpP1bJfdApd6MbD+Kzi4GNnM6h35mdFChhQPSi9cAI8J7DMn5kQDKX8NuBaQXAyo360Oa7tOEA== +rgb2hex@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.2.3.tgz#8aa464c517b8a26c7a79d767dabaec2b49ee78ec" + integrity sha512-clEe0m1xv+Tva1B/TOepuIcvLAxP0U+sCDfgt1SX1HmI2Ahr5/Cd/nzJM1e78NKVtWdoo0s33YehpFA8UfIShQ== rimraf@2.6.3, rimraf@^2.2.8: version "2.6.3" @@ -7511,12 +7545,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.5.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== - -semver@^5.4.1, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -7526,15 +7555,12 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.1.2, semver@^7.2.1: - version "7.2.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.2.2.tgz#d01432d74ed3010a20ffaf909d63a691520521cd" - integrity sha512-Zo84u6o2PebMSK3zjJ6Zp5wi8VnQZnEaCP13Ul/lt1ANsLACxnJxq4EEm1PY94/por1Hm9+7xpIswdS5AkieMA== - -semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== +semver@^7.1.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" serialize-error@^5.0.0: version "5.0.0" @@ -7750,16 +7776,16 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== -spectron@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/spectron/-/spectron-12.0.0.tgz#8a3454a1366cdb82fbb6be75be0104915b607340" - integrity sha512-ZyDFS7I+4dWa/YXSQ/trbC4s1Rd0Ks5oi4MQ6XSJHULPasJhx5q2bM93Ae7BNUvwrGrbhjk7O6f14JwqJimLyA== +spectron@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/spectron/-/spectron-13.0.0.tgz#16bdfcf9a2b26cb5ee6c3e29b4f08101e339aa4d" + integrity sha512-7RPa6Fp8gqL4V0DubobnqIRFHIijkpjg6MFHcJlxoerWyvLJd+cQvOh756XpB1Z/U3DyA9jPcS+HE2PvYRP5+A== dependencies: dev-null "^0.1.1" - electron-chromedriver "^10.0.0" - request "^2.87.0" - split "^1.0.0" - webdriverio "^6.1.20" + electron-chromedriver "^11.0.0" + request "^2.88.2" + split "^1.0.1" + webdriverio "^6.9.1" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -7768,7 +7794,7 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split@^1.0.0: +split@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== @@ -8530,9 +8556,9 @@ uuid@^3.3.2: integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== uuid@^8.0.0, uuid@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" - integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== v8-compile-cache@^2.0.3: version "2.1.0" @@ -8591,32 +8617,34 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -webdriver@6.5.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-6.5.0.tgz#c2ab978570843c6fe8a778b274d9acf781cfcfd4" - integrity sha512-6iOll9TshD4+2J+em+bLshvM1uXtnotdZ+JaALqRLbkVswLRFU0pTVP1oug0e/IYwL7Me4Cafh9ugQ4PwPuOnA== +webdriver@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-6.11.0.tgz#2997bf4ff6c1dcb4e58b4ae9e2b83af8b938f643" + integrity sha512-31uD1Vi+9QAzDSpN3+0oFFRnzJP8IVp8wRjLVbIOaQGPXV1sKjAP7v6LJcxl1JjcmW8keAIh2eyAgbjZJbcyZw== dependencies: - "@wdio/config" "6.4.7" - "@wdio/logger" "6.4.7" - "@wdio/protocols" "6.3.6" - "@wdio/utils" "6.5.0" + "@wdio/config" "6.11.0" + "@wdio/logger" "6.10.10" + "@wdio/protocols" "6.10.6" + "@wdio/utils" "6.11.0" got "^11.0.2" lodash.merge "^4.6.1" -webdriverio@^6.1.20: - version "6.5.2" - resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-6.5.2.tgz#0c733c293b88a0ee45082bfde9fc3d9a10308216" - integrity sha512-ChAV6RmF10mlyWnAL2y+PdnzAjpxL/UuyAHJsYSuirEeEAAqFWWePxniz67bUEVQPVClVj8Jh7oeoK6rhu4RAA== +webdriverio@^6.9.1: + version "6.11.3" + resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-6.11.3.tgz#043bc98514d7410264fbf14991bc0546fa119779" + integrity sha512-yHS01H0+oz59Y+JLj/u8piLzOhtTiQSeASwb3hHF1EDuIiiK6JgGYFAqCYr26BrlzqzUOQ/9VpJj11LtcKWF/A== dependencies: - "@types/puppeteer" "^3.0.1" - "@wdio/config" "6.4.7" - "@wdio/logger" "6.4.7" - "@wdio/repl" "6.5.0" - "@wdio/utils" "6.5.0" + "@types/puppeteer-core" "^5.4.0" + "@wdio/config" "6.11.0" + "@wdio/logger" "6.10.10" + "@wdio/repl" "6.11.0" + "@wdio/utils" "6.11.0" archiver "^5.0.0" atob "^2.1.2" + css-shorthand-properties "^1.1.1" css-value "^0.0.1" - devtools "6.5.0" + devtools "6.11.0" + fs-extra "^9.0.1" get-port "^5.1.1" grapheme-splitter "^1.0.2" lodash.clonedeep "^4.5.0" @@ -8625,10 +8653,10 @@ webdriverio@^6.1.20: lodash.zip "^4.2.0" minimatch "^3.0.4" puppeteer-core "^5.1.0" - resq "^1.6.0" - rgb2hex "^0.2.0" + resq "^1.9.1" + rgb2hex "0.2.3" serialize-error "^7.0.0" - webdriver "6.5.0" + webdriver "6.11.0" webidl-conversions@^5.0.0: version "5.0.0" @@ -8949,12 +8977,11 @@ yauzl@^2.10.0: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -ytdl-core@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ytdl-core/-/ytdl-core-4.1.1.tgz#191fabf472c44f969fe3eca15cb4d1c094e46282" - integrity sha512-T2VIS64sHKdLLqvuTV7S4WyoUCZLdR7HOP/9jX1CyXKYUjKLFP9UpVIFH0ZUvFSmK48eNFErWLOO5dGouwqztQ== +ytdl-core@^4.1.2: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ytdl-core/-/ytdl-core-4.2.1.tgz#afcc1577a2a35701a5e1369f2ad3b0d1a7d2419d" + integrity sha512-7zAoJiWpaBGgiAUCQuvKBuWom7tmSCV0A70gRdrPxR96yQoJOrCZkW6Wg1CofvPtAeQVWTVWThC8bXRsE+SBeA== dependencies: - html-entities "^1.3.1" m3u8stream "^0.8.3" miniget "^4.0.0" sax "^1.1.3"