mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 10:31:47 +00:00
Merge pull request #243 from Araxeus/custom-electron-prompt
Custom Prompt for changing options
This commit is contained in:
@ -30,6 +30,7 @@ const defaultConfig = {
|
||||
// Disabled plugins
|
||||
shortcuts: {
|
||||
enabled: false,
|
||||
overrideMediaKeys: false,
|
||||
},
|
||||
downloader: {
|
||||
enabled: false,
|
||||
@ -59,9 +60,8 @@ const defaultConfig = {
|
||||
steps: 1, //percentage of volume to change
|
||||
arrowsShortcut: true, //enable ArrowUp + ArrowDown local shortcuts
|
||||
globalShortcuts: {
|
||||
enabled: false, // enable global shortcuts
|
||||
volumeUp: "Shift+PageUp", // Keybind default can be changed
|
||||
volumeDown: "Shift+PageDown"
|
||||
volumeUp: "",
|
||||
volumeDown: ""
|
||||
},
|
||||
savedVolume: undefined //plugin save volume between session here
|
||||
},
|
||||
|
||||
@ -8,6 +8,27 @@ const migrations = {
|
||||
store.set("plugins.discord.listenAlong", true);
|
||||
}
|
||||
},
|
||||
">=1.12.0": (store) => {
|
||||
const options = store.get("plugins.shortcuts")
|
||||
let updated = false;
|
||||
for (const optionType of ["global", "local"]) {
|
||||
if (Array.isArray(options[optionType])) {
|
||||
const updatedOptions = {};
|
||||
for (const optionObject of options[optionType]) {
|
||||
if (optionObject.action && optionObject.shortcut) {
|
||||
updatedOptions[optionObject.action] = optionObject.shortcut;
|
||||
}
|
||||
}
|
||||
|
||||
options[optionType] = updatedOptions;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
store.set("plugins.shortcuts", options);
|
||||
}
|
||||
},
|
||||
">=1.11.0": (store) => {
|
||||
if (store.get("options.resumeOnStart") === undefined) {
|
||||
store.set("options.resumeOnStart", true);
|
||||
|
||||
6
index.js
6
index.js
@ -39,7 +39,9 @@ if (config.get("options.proxy")) {
|
||||
}
|
||||
|
||||
// Adds debug features like hotkeys for triggering dev tools and reload
|
||||
require("electron-debug")();
|
||||
require("electron-debug")({
|
||||
showDevTools: false //disable automatic devTools on new window
|
||||
});
|
||||
|
||||
// Prevent window being garbage collected
|
||||
let mainWindow;
|
||||
@ -60,7 +62,7 @@ function onClosed() {
|
||||
|
||||
function loadPlugins(win) {
|
||||
injectCSS(win.webContents, path.join(__dirname, "youtube-music.css"));
|
||||
win.webContents.on("did-finish-load", () => {
|
||||
win.webContents.once("did-finish-load", () => {
|
||||
if (is.dev()) {
|
||||
console.log("did finish load");
|
||||
win.webContents.openDevTools();
|
||||
|
||||
33
menu.js
33
menu.js
@ -7,6 +7,9 @@ const is = require("electron-is");
|
||||
const { getAllPlugins } = require("./plugins/utils");
|
||||
const config = require("./config");
|
||||
|
||||
const prompt = require("custom-electron-prompt");
|
||||
const promptOptions = require("./providers/prompt-options");
|
||||
|
||||
// true only if in-app-menu was loaded on launch
|
||||
const inAppMenuActive = config.plugins.isEnabled("in-app-menu");
|
||||
|
||||
@ -149,6 +152,14 @@ const mainMenuTemplate = (win) => {
|
||||
{
|
||||
label: "Advanced options",
|
||||
submenu: [
|
||||
{
|
||||
label: "Proxy",
|
||||
type: "checkbox",
|
||||
checked: !!config.get("options.proxy"),
|
||||
click: (item) => {
|
||||
setProxy(item, win);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Disable hardware acceleration",
|
||||
type: "checkbox",
|
||||
@ -275,3 +286,25 @@ module.exports.setApplicationMenu = (win) => {
|
||||
const menu = Menu.buildFromTemplate(menuTemplate);
|
||||
Menu.setApplicationMenu(menu);
|
||||
};
|
||||
|
||||
async function setProxy(item, win) {
|
||||
const output = await prompt({
|
||||
title: 'Set Proxy',
|
||||
label: 'Enter Proxy Address: (leave empty to disable)',
|
||||
value: config.get("options.proxy"),
|
||||
type: 'input',
|
||||
inputAttrs: {
|
||||
type: 'url',
|
||||
placeholder: "Example: 'socks5://127.0.0.1:9999"
|
||||
},
|
||||
width: 450,
|
||||
...promptOptions()
|
||||
}, win);
|
||||
|
||||
if (typeof output === "string") {
|
||||
config.set("options.proxy", output);
|
||||
item.checked = output !== "";
|
||||
} else { //user pressed cancel
|
||||
item.checked = !item.checked; //reset checkbox
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,6 +70,7 @@
|
||||
"YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.9.0",
|
||||
"async-mutex": "^0.3.2",
|
||||
"browser-id3-writer": "^4.4.0",
|
||||
"custom-electron-prompt": "^1.1.0",
|
||||
"chokidar": "^3.5.2",
|
||||
"custom-electron-titlebar": "^3.2.7",
|
||||
"discord-rpc": "^3.2.0",
|
||||
|
||||
@ -12,9 +12,7 @@ module.exports = (options) => {
|
||||
|
||||
setupLocalArrowShortcuts(options);
|
||||
|
||||
if (options.globalShortcuts?.enabled) {
|
||||
setupGlobalShortcuts(options);
|
||||
}
|
||||
setupGlobalShortcuts(options);
|
||||
|
||||
firstRun(options);
|
||||
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
const { enabled } = require("./back");
|
||||
const { setOptions } = require("../../config/plugins");
|
||||
const prompt = require("custom-electron-prompt");
|
||||
const promptOptions = require("../../providers/prompt-options");
|
||||
|
||||
|
||||
module.exports = (win, options) => [
|
||||
{
|
||||
label: "Arrowkeys controls",
|
||||
label: "Local Arrowkeys Controls",
|
||||
type: "checkbox",
|
||||
checked: !!options.arrowsShortcut,
|
||||
click: (item) => {
|
||||
// Dynamically change setting if plugin enabled
|
||||
click: item => {
|
||||
// Dynamically change setting if plugin is enabled
|
||||
if (enabled()) {
|
||||
win.webContents.send("setArrowsShortcut", item.checked);
|
||||
} else { // Fallback to usual method if disabled
|
||||
@ -15,5 +18,61 @@ module.exports = (win, options) => [
|
||||
setOptions("precise-volume", options);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Global Hotkeys",
|
||||
type: "checkbox",
|
||||
checked: !!options.globalShortcuts.volumeUp || !!options.globalShortcuts.volumeDown,
|
||||
click: item => promptGlobalShortcuts(win, options, item)
|
||||
},
|
||||
{
|
||||
label: "Set Custom Volume Steps",
|
||||
click: () => promptVolumeSteps(win, options)
|
||||
}
|
||||
];
|
||||
|
||||
// Helper function for globalShortcuts prompt
|
||||
const kb = (label_, value_, default_) => { return { value: value_, label: label_, default: default_ || undefined }; };
|
||||
|
||||
async function promptVolumeSteps(win, options) {
|
||||
const output = await prompt({
|
||||
title: "Volume Steps",
|
||||
label: "Choose Volume Increase/Decrease Steps",
|
||||
value: options.steps || 1,
|
||||
type: "counter",
|
||||
counterOptions: { minimum: 0, maximum: 100, multiFire: true },
|
||||
width: 380,
|
||||
...promptOptions()
|
||||
}, win)
|
||||
|
||||
if (output || output === 0) { // 0 is somewhat valid
|
||||
options.steps = output;
|
||||
setOptions("precise-volume", options);
|
||||
}
|
||||
}
|
||||
|
||||
async function promptGlobalShortcuts(win, options, item) {
|
||||
const output = await prompt({
|
||||
title: "Global Volume Keybinds",
|
||||
label: "Choose Global Volume Keybinds:",
|
||||
type: "keybind",
|
||||
keybindOptions: [
|
||||
kb("Increase Volume", "volumeUp", options.globalShortcuts?.volumeUp),
|
||||
kb("Decrease Volume", "volumeDown", options.globalShortcuts?.volumeDown)
|
||||
],
|
||||
...promptOptions()
|
||||
}, win)
|
||||
|
||||
if (output) {
|
||||
for (const { value, accelerator } of output) {
|
||||
options.globalShortcuts[value] = accelerator;
|
||||
}
|
||||
|
||||
setOptions("precise-volume", options);
|
||||
|
||||
item.checked = !!options.globalShortcuts.volumeUp || !!options.globalShortcuts.volumeDown;
|
||||
} else {
|
||||
// Reset checkbox if prompt was canceled
|
||||
item.checked = !item.checked;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,9 +21,12 @@ function registerShortcuts(win, options) {
|
||||
const songControls = getSongControls(win);
|
||||
const { playPause, next, previous, search } = songControls;
|
||||
|
||||
_registerGlobalShortcut(win.webContents, "MediaPlayPause", playPause);
|
||||
_registerGlobalShortcut(win.webContents, "MediaNextTrack", next);
|
||||
_registerGlobalShortcut(win.webContents, "MediaPreviousTrack", previous);
|
||||
if (options.overrideMediaKeys) {
|
||||
_registerGlobalShortcut(win.webContents, "MediaPlayPause", playPause);
|
||||
_registerGlobalShortcut(win.webContents, "MediaNextTrack", next);
|
||||
_registerGlobalShortcut(win.webContents, "MediaPreviousTrack", previous);
|
||||
}
|
||||
|
||||
_registerLocalShortcut(win, "CommandOrControl+F", search);
|
||||
_registerLocalShortcut(win, "CommandOrControl+L", search);
|
||||
|
||||
@ -44,24 +47,31 @@ function registerShortcuts(win, options) {
|
||||
}
|
||||
|
||||
const { global, local } = options;
|
||||
(global || []).forEach(({ shortcut, action }) => {
|
||||
console.debug("Registering global shortcut", shortcut, ":", action);
|
||||
if (!action || !songControls[action]) {
|
||||
console.warn("Invalid action", action);
|
||||
return;
|
||||
}
|
||||
const shortcutOptions = { global, local };
|
||||
|
||||
_registerGlobalShortcut(win.webContents, shortcut, songControls[action]);
|
||||
});
|
||||
(local || []).forEach(({ shortcut, action }) => {
|
||||
console.debug("Registering local shortcut", shortcut, ":", action);
|
||||
if (!action || !songControls[action]) {
|
||||
console.warn("Invalid action", action);
|
||||
return;
|
||||
}
|
||||
for (const optionType in shortcutOptions) {
|
||||
registerAllShortcuts(shortcutOptions[optionType], optionType);
|
||||
}
|
||||
|
||||
_registerLocalShortcut(win, shortcut, songControls[action]);
|
||||
});
|
||||
function registerAllShortcuts(container, type) {
|
||||
for (const action in container) {
|
||||
if (!container[action]) {
|
||||
continue; // Action accelerator is empty
|
||||
}
|
||||
|
||||
console.debug(`Registering ${type} shortcut`, container[action], ":", action);
|
||||
if (!songControls[action]) {
|
||||
console.warn("Invalid action", action);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type === "global") {
|
||||
_registerGlobalShortcut(win.webContents, container[action], songControls[action]);
|
||||
} else { // type === "local"
|
||||
_registerLocalShortcut(win, local[action], songControls[action]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = registerShortcuts;
|
||||
|
||||
53
plugins/shortcuts/menu.js
Normal file
53
plugins/shortcuts/menu.js
Normal file
@ -0,0 +1,53 @@
|
||||
const { setOptions } = require("../../config/plugins");
|
||||
const prompt = require("custom-electron-prompt");
|
||||
const promptOptions = require("../../providers/prompt-options");
|
||||
|
||||
module.exports = (win, options) => [
|
||||
{
|
||||
label: "Set Global Song Controls",
|
||||
click: () => promptKeybind(options, win)
|
||||
},
|
||||
{
|
||||
label: "Override MediaKeys",
|
||||
type: "checkbox",
|
||||
checked: options.overrideMediaKeys,
|
||||
click: item => setOption(options, "overrideMediaKeys", item.checked)
|
||||
}
|
||||
];
|
||||
|
||||
function setOption(options, key = null, newValue = null) {
|
||||
if (key && newValue !== null) {
|
||||
options[key] = newValue;
|
||||
}
|
||||
|
||||
setOptions("shortcuts", options);
|
||||
}
|
||||
|
||||
// Helper function for keybind prompt
|
||||
const kb = (label_, value_, default_) => { return { value: value_, label: label_, default: default_ }; };
|
||||
|
||||
async function promptKeybind(options, win) {
|
||||
const output = await prompt({
|
||||
title: "Global Keybinds",
|
||||
label: "Choose Global Keybinds for Songs Control:",
|
||||
type: "keybind",
|
||||
keybindOptions: [ // If default=undefined then no default is used
|
||||
kb("Previous", "previous", options.global?.previous),
|
||||
kb("Play / Pause", "playPause", options.global?.playPause),
|
||||
kb("Next", "next", options.global?.next)
|
||||
],
|
||||
height: 270,
|
||||
...promptOptions()
|
||||
}, win);
|
||||
|
||||
if (output) {
|
||||
if (!options.global) {
|
||||
options.global = {};
|
||||
}
|
||||
for (const { value, accelerator } of output) {
|
||||
options.global[value] = accelerator;
|
||||
}
|
||||
setOption(options);
|
||||
}
|
||||
// else -> pressed cancel
|
||||
}
|
||||
14
providers/prompt-custom-titlebar.js
Normal file
14
providers/prompt-custom-titlebar.js
Normal file
@ -0,0 +1,14 @@
|
||||
const customTitlebar = require("custom-electron-titlebar");
|
||||
|
||||
module.exports = () => {
|
||||
new customTitlebar.Titlebar({
|
||||
backgroundColor: customTitlebar.Color.fromHex("#050505"),
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
menu: null
|
||||
});
|
||||
const mainStyle = document.querySelector("#container").style;
|
||||
mainStyle.width = "100%";
|
||||
mainStyle.position = "fixed";
|
||||
mainStyle.border = "unset";
|
||||
};
|
||||
18
providers/prompt-options.js
Normal file
18
providers/prompt-options.js
Normal file
@ -0,0 +1,18 @@
|
||||
const path = require("path");
|
||||
const is = require("electron-is");
|
||||
|
||||
const iconPath = path.join(__dirname, "..", "assets", "youtube-music-tray.png");
|
||||
const customTitlebarPath = path.join(__dirname, "prompt-custom-titlebar.js");
|
||||
|
||||
const promptOptions = is.macOS() ? {
|
||||
customStylesheet: "dark",
|
||||
icon: iconPath
|
||||
} : {
|
||||
customStylesheet: "dark",
|
||||
// The following are used for custom titlebar
|
||||
frame: false,
|
||||
customScript: customTitlebarPath,
|
||||
enableRemoteModule: true
|
||||
};
|
||||
|
||||
module.exports = () => promptOptions;
|
||||
@ -2960,6 +2960,11 @@ cssstyle@^2.2.0:
|
||||
dependencies:
|
||||
cssom "~0.3.6"
|
||||
|
||||
custom-electron-prompt@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/custom-electron-prompt/-/custom-electron-prompt-1.1.0.tgz#611b790047c91f6b532c7861355a0e1f9a81aef2"
|
||||
integrity sha512-YZYmwZnMOdoWROUlJ+rEMHYsp4XJNNqLj6sZnx5aKBJ8cprEjKP4L5wfo6U+yyX/L9fxVOtvYD0Mp8ki5I9Kow==
|
||||
|
||||
custom-electron-titlebar@^3.2.7:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/custom-electron-titlebar/-/custom-electron-titlebar-3.2.7.tgz#fb249d6180cbda074b1d392bea755fa0743012a8"
|
||||
|
||||
Reference in New Issue
Block a user