diff --git a/config/index.js b/config/index.js index c77e4d00..cf33369e 100644 --- a/config/index.js +++ b/config/index.js @@ -1,11 +1,17 @@ const defaultConfig = require("./defaults"); const plugins = require("./plugins"); const store = require("./store"); +const { restart } = require("../providers/app-controls"); const set = (key, value) => { store.set(key, value); }; +function setMenuOption(key, value) { + set(key, value); + if (store.get("options.restartOnConfigChanges")) restart(); +} + const get = (key) => { return store.get(key); }; @@ -14,6 +20,7 @@ module.exports = { defaultConfig, get, set, + setMenuOption, edit: () => store.openInEditor(), watch: (cb) => { store.onDidChange("options", cb); diff --git a/config/plugins.js b/config/plugins.js index 7a73335c..b8c00f83 100644 --- a/config/plugins.js +++ b/config/plugins.js @@ -1,4 +1,5 @@ const store = require("./store"); +const { restart } = require("../providers/app-controls"); function getEnabled() { const plugins = store.get("plugins"); @@ -24,16 +25,21 @@ function setOptions(plugin, options) { }); } +function setMenuOptions(plugin, options) { + setOptions(plugin, options); + if (store.get("options.restartOnConfigChanges")) restart(); +} + function getOptions(plugin) { return store.get("plugins")[plugin]; } function enable(plugin) { - setOptions(plugin, { enabled: true }); + setMenuOptions(plugin, { enabled: true }); } function disable(plugin) { - setOptions(plugin, { enabled: false }); + setMenuOptions(plugin, { enabled: false }); } module.exports = { @@ -42,5 +48,6 @@ module.exports = { enable, disable, setOptions, + setMenuOptions, getOptions, }; diff --git a/index.js b/index.js index 8360f147..d4ce9d0e 100644 --- a/index.js +++ b/index.js @@ -26,6 +26,22 @@ unhandled({ process.env.NODE_OPTIONS = ""; const app = electron.app; +// Prevent window being garbage collected +let mainWindow; +autoUpdater.autoDownload = false; + +if(config.get("options.singleInstanceLock")){ + const gotTheLock = app.requestSingleInstanceLock(); + if (!gotTheLock) app.quit(); + + app.on('second-instance', () => { + if (!mainWindow) return; + if (mainWindow.isMinimized()) mainWindow.restore(); + if (!mainWindow.isVisible()) mainWindow.show(); + mainWindow.focus(); + }); +} + app.commandLine.appendSwitch( "js-flags", // WebAssembly flags @@ -54,10 +70,6 @@ require("electron-debug")({ showDevTools: false //disable automatic devTools on new window }); -// Prevent window being garbage collected -let mainWindow; -autoUpdater.autoDownload = false; - let icon = "assets/youtube-music.png"; if (process.platform == "win32") { icon = "assets/generated/icon.ico"; @@ -160,22 +172,39 @@ function createMainWindow() { win.on("closed", onClosed); win.on("move", () => { + if (win.isMaximized()) return; let position = win.getPosition(); - config.set("window-position", { x: position[0], y: position[1] }); + lateSave("window-position", { x: position[0], y: position[1] }); }); + let winWasMaximized; + win.on("resize", () => { const windowSize = win.getSize(); - config.set("window-maximized", win.isMaximized()); - if (!win.isMaximized()) { - config.set("window-size", { + const isMaximized = win.isMaximized(); + if (winWasMaximized !== isMaximized) { + winWasMaximized = isMaximized; + config.set("window-maximized", isMaximized); + } + if (!isMaximized) { + lateSave("window-size", { width: windowSize[0], height: windowSize[1], }); } }); + let savedTimeouts = {}; + function lateSave(key, value) { + if (savedTimeouts[key]) clearTimeout(savedTimeouts[key]); + + savedTimeouts[key] = setTimeout(() => { + config.set(key, value); + savedTimeouts[key] = undefined; + }, 1000) + } + win.webContents.on("render-process-gone", (event, webContents, details) => { showUnresponsiveDialog(win, details); }); @@ -325,12 +354,6 @@ app.on("ready", () => { mainWindow = createMainWindow(); setApplicationMenu(mainWindow); - if (config.get("options.restartOnConfigChanges")) { - config.watch(() => { - app.relaunch(); - app.exit(); - }); - } setUpTray(app, mainWindow); // Autostart at login diff --git a/menu.js b/menu.js index 0a62249b..d630db6b 100644 --- a/menu.js +++ b/menu.js @@ -68,7 +68,7 @@ const mainMenuTemplate = (win) => { type: "checkbox", checked: config.get("options.autoUpdates"), click: (item) => { - config.set("options.autoUpdates", item.checked); + config.setMenuOption("options.autoUpdates", item.checked); }, }, { @@ -76,7 +76,7 @@ const mainMenuTemplate = (win) => { type: "checkbox", checked: config.get("options.resumeOnStart"), click: (item) => { - config.set("options.resumeOnStart", item.checked); + config.setMenuOption("options.resumeOnStart", item.checked); }, }, { @@ -84,7 +84,20 @@ const mainMenuTemplate = (win) => { type: "checkbox", checked: config.get("options.removeUpgradeButton"), click: (item) => { - config.set("options.removeUpgradeButton", item.checked); + config.setMenuOption("options.removeUpgradeButton", item.checked); + }, + }, + { + label: "Single instance lock", + type: "checkbox", + checked: config.get("options.singleInstanceLock"), + click: (item) => { + config.set("options.singleInstanceLock", item.checked); + if (item.checked && !app.hasSingleInstanceLock()) { + app.requestSingleInstanceLock(); + } else if (!item.checked && app.hasSingleInstanceLock()) { + app.releaseSingleInstanceLock(); + } }, }, ...(is.windows() || is.linux() @@ -94,7 +107,7 @@ const mainMenuTemplate = (win) => { type: "checkbox", checked: config.get("options.hideMenu"), click: (item) => { - config.set("options.hideMenu", item.checked); + config.setMenuOption("options.hideMenu", item.checked); if (item.checked && !config.get("options.hideMenuWarned")) { dialog.showMessageBox(win, { type: 'info', title: 'Hide Menu Enabled', @@ -114,7 +127,7 @@ const mainMenuTemplate = (win) => { type: "checkbox", checked: config.get("options.startAtLogin"), click: (item) => { - config.set("options.startAtLogin", item.checked); + config.setMenuOption("options.startAtLogin", item.checked); }, }, ] @@ -127,8 +140,8 @@ const mainMenuTemplate = (win) => { type: "radio", checked: !config.get("options.tray"), click: () => { - config.set("options.tray", false); - config.set("options.appVisible", true); + config.setMenuOption("options.tray", false); + config.setMenuOption("options.appVisible", true); }, }, { @@ -137,8 +150,8 @@ const mainMenuTemplate = (win) => { checked: config.get("options.tray") && config.get("options.appVisible"), click: () => { - config.set("options.tray", true); - config.set("options.appVisible", true); + config.setMenuOption("options.tray", true); + config.setMenuOption("options.appVisible", true); }, }, { @@ -147,8 +160,8 @@ const mainMenuTemplate = (win) => { checked: config.get("options.tray") && !config.get("options.appVisible"), click: () => { - config.set("options.tray", true); - config.set("options.appVisible", false); + config.setMenuOption("options.tray", true); + config.setMenuOption("options.appVisible", false); }, }, { type: "separator" }, @@ -157,7 +170,7 @@ const mainMenuTemplate = (win) => { type: "checkbox", checked: config.get("options.trayClickPlayPause"), click: (item) => { - config.set("options.trayClickPlayPause", item.checked); + config.setMenuOption("options.trayClickPlayPause", item.checked); }, }, ], @@ -166,20 +179,20 @@ const mainMenuTemplate = (win) => { { label: "Advanced options", submenu: [ - { - label: "Proxy", - type: "checkbox", - checked: !!config.get("options.proxy"), - click: (item) => { - setProxy(item, win); - }, - }, + { + label: "Proxy", + type: "checkbox", + checked: !!config.get("options.proxy"), + click: (item) => { + setProxy(item, win); + }, + }, { label: "Disable hardware acceleration", type: "checkbox", checked: config.get("options.disableHardwareAcceleration"), click: (item) => { - config.set("options.disableHardwareAcceleration", item.checked); + config.setMenuOption("options.disableHardwareAcceleration", item.checked); }, }, { @@ -187,7 +200,7 @@ const mainMenuTemplate = (win) => { type: "checkbox", checked: config.get("options.restartOnConfigChanges"), click: (item) => { - config.set("options.restartOnConfigChanges", item.checked); + config.setMenuOption("options.restartOnConfigChanges", item.checked); }, }, { @@ -195,7 +208,7 @@ const mainMenuTemplate = (win) => { type: "checkbox", checked: config.get("options.autoResetAppCache"), click: (item) => { - config.set("options.autoResetAppCache", item.checked); + config.setMenuOption("options.autoResetAppCache", item.checked); }, }, { type: "separator" }, @@ -316,7 +329,7 @@ async function setProxy(item, win) { }, win); if (typeof output === "string") { - config.set("options.proxy", output); + config.setMenuOption("options.proxy", output); item.checked = output !== ""; } else { //user pressed cancel item.checked = !item.checked; //reset checkbox diff --git a/plugins/discord/menu.js b/plugins/discord/menu.js index 812fc704..8dba9ffa 100644 --- a/plugins/discord/menu.js +++ b/plugins/discord/menu.js @@ -1,5 +1,6 @@ -const { setOptions } = require("../../config/plugins"); const prompt = require("custom-electron-prompt"); + +const { setMenuOptions } = require("../../config/plugins"); const promptOptions = require("../../providers/prompt-options"); const { clear, connect, registerRefresh, isConnected } = require("./back"); @@ -27,7 +28,7 @@ module.exports = (win, options, refreshMenu) => { checked: options.activityTimoutEnabled, click: (item) => { options.activityTimoutEnabled = item.checked; - setOptions('discord', options); + setMenuOptions('discord', options); }, }, { @@ -36,7 +37,7 @@ module.exports = (win, options, refreshMenu) => { checked: options.listenAlong, click: (item) => { options.listenAlong = item.checked; - setOptions('discord', options); + setMenuOptions('discord', options); }, }, { @@ -59,6 +60,6 @@ async function setInactivityTimeout(win, options) { if (output) { options.activityTimoutTime = Math.round(output * 1e3); - setOptions("discord", options); + setMenuOptions("discord", options); } } diff --git a/plugins/downloader/menu.js b/plugins/downloader/menu.js index 94d12488..622370a2 100644 --- a/plugins/downloader/menu.js +++ b/plugins/downloader/menu.js @@ -7,7 +7,7 @@ const ytpl = require("ytpl"); const chokidar = require('chokidar'); const filenamify = require('filenamify'); -const { setOptions } = require("../../config/plugins"); +const { setMenuOptions } = require("../../config/plugins"); const { sendError } = require("./back"); const { defaultMenuDownloadLabel, getFolder, presets, setBadge } = require("./utils"); @@ -49,7 +49,7 @@ module.exports = (win, options) => { }); if (result) { options.downloadFolder = result[0]; - setOptions("downloader", options); + setMenuOptions("downloader", options); } // else = user pressed cancel }, }, @@ -60,7 +60,7 @@ module.exports = (win, options) => { type: "radio", click: () => { options.preset = preset; - setOptions("downloader", options); + setMenuOptions("downloader", options); }, checked: options.preset === preset || presets[preset] === undefined, })), diff --git a/plugins/notifications/utils.js b/plugins/notifications/utils.js index 34c73a77..7cb9e61e 100644 --- a/plugins/notifications/utils.js +++ b/plugins/notifications/utils.js @@ -1,4 +1,4 @@ -const { setOptions } = require("../../config/plugins"); +const { setMenuOptions } = require("../../config/plugins"); const path = require("path"); const { app } = require("electron"); const fs = require("fs"); @@ -15,7 +15,7 @@ module.exports.icons = { module.exports.setOption = (options, option, value) => { options[option] = value; - setOptions("notifications", options) + setMenuOptions("notifications", options) } module.exports.urgencyLevels = [ diff --git a/plugins/precise-volume/front.js b/plugins/precise-volume/front.js index a5356dec..3b1e34f1 100644 --- a/plugins/precise-volume/front.js +++ b/plugins/precise-volume/front.js @@ -1,7 +1,7 @@ const { ipcRenderer } = require("electron"); const { globalShortcut } = require('@electron/remote'); -const { setOptions, isEnabled } = require("../../config/plugins"); +const { setOptions, setMenuOptions, isEnabled } = require("../../config/plugins"); function $(selector) { return document.querySelector(selector); } let api; @@ -48,7 +48,7 @@ function firstRun(options) { for (option in newOptions) { options[option] = newOptions[option]; } - setOptions("precise-volume", options); + setMenuOptions("precise-volume", options); }); } diff --git a/plugins/precise-volume/menu.js b/plugins/precise-volume/menu.js index c3d56f8f..74f7b14a 100644 --- a/plugins/precise-volume/menu.js +++ b/plugins/precise-volume/menu.js @@ -1,5 +1,5 @@ const { enabled } = require("./back"); -const { setOptions } = require("../../config/plugins"); +const { setMenuOptions } = require("../../config/plugins"); const prompt = require("custom-electron-prompt"); const promptOptions = require("../../providers/prompt-options"); @@ -11,7 +11,7 @@ function changeOptions(changedOptions, options, win) { if (enabled()) { win.webContents.send("setOptions", changedOptions); } else { // Fallback to usual method if disabled - setOptions("precise-volume", options); + setMenuOptions("precise-volume", options); } } diff --git a/plugins/shortcuts/menu.js b/plugins/shortcuts/menu.js index 20f21233..df9db161 100644 --- a/plugins/shortcuts/menu.js +++ b/plugins/shortcuts/menu.js @@ -1,4 +1,4 @@ -const { setOptions } = require("../../config/plugins"); +const { setMenuOptions } = require("../../config/plugins"); const prompt = require("custom-electron-prompt"); const promptOptions = require("../../providers/prompt-options"); @@ -20,7 +20,7 @@ function setOption(options, key = null, newValue = null) { options[key] = newValue; } - setOptions("shortcuts", options); + setMenuOptions("shortcuts", options); } // Helper function for keybind prompt diff --git a/plugins/video-toggle/menu.js b/plugins/video-toggle/menu.js index a73407ca..fb539405 100644 --- a/plugins/video-toggle/menu.js +++ b/plugins/video-toggle/menu.js @@ -1,4 +1,4 @@ -const { setOptions } = require("../../config/plugins"); +const { setMenuOptions } = require("../../config/plugins"); module.exports = (win, options) => [ { @@ -7,7 +7,7 @@ module.exports = (win, options) => [ checked: options.forceHide, click: item => { options.forceHide = item.checked; - setOptions("video-toggle", options); + setMenuOptions("video-toggle", options); } } ]; diff --git a/providers/app-controls.js b/providers/app-controls.js new file mode 100644 index 00000000..9faded69 --- /dev/null +++ b/providers/app-controls.js @@ -0,0 +1,6 @@ +const app = require("electron").app || require('@electron/remote').app; + +module.exports.restart = () => { + app.relaunch(); + app.exit(); +};