mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-15 04:11:47 +00:00
337 lines
8.1 KiB
JavaScript
337 lines
8.1 KiB
JavaScript
const fs = require("fs");
|
|
const { ipcRenderer } = require("electron");
|
|
|
|
let promptId = null;
|
|
let promptOptions = null;
|
|
|
|
function $(selector) {
|
|
return document.querySelector(selector);
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", promptRegister);
|
|
|
|
function promptRegister() {
|
|
//get custom session id
|
|
promptId = document.location.hash.replace("#", "");
|
|
|
|
//get options from back
|
|
try {
|
|
promptOptions = JSON.parse(ipcRenderer.sendSync("prompt-get-options:" + promptId));
|
|
} catch (error) {
|
|
return promptError(error);
|
|
}
|
|
|
|
//set label
|
|
if (promptOptions.useHtmlLabel) {
|
|
$("#label").innerHTML = promptOptions.label;
|
|
} else {
|
|
$("#label").textContent = promptOptions.label;
|
|
}
|
|
|
|
//set button label
|
|
if (promptOptions.buttonLabels && promptOptions.buttonLabels.ok) {
|
|
$("#ok").textContent = promptOptions.buttonLabels.ok;
|
|
}
|
|
|
|
if (promptOptions.buttonLabels && promptOptions.buttonLabels.cancel) {
|
|
$("#cancel").textContent = promptOptions.buttonLabels.cancel;
|
|
}
|
|
|
|
//inject custom stylesheet from options
|
|
if (promptOptions.customStylesheet) {
|
|
try {
|
|
const customStyleContent = fs.readFileSync(promptOptions.customStylesheet);
|
|
if (customStyleContent) {
|
|
const customStyle = document.createElement("style");
|
|
customStyle.setAttribute("rel", "stylesheet");
|
|
customStyle.append(document.createTextNode(customStyleContent));
|
|
document.head.append(customStyle);
|
|
}
|
|
} catch (error) {
|
|
return promptError(error);
|
|
}
|
|
}
|
|
|
|
//add button listeners
|
|
$("#form").addEventListener("submit", promptSubmit);
|
|
$("#cancel").addEventListener("click", promptCancel);
|
|
|
|
//create input/select
|
|
const dataContainerElement = $("#data-container");
|
|
let dataElement;
|
|
|
|
switch (promptOptions.type) {
|
|
case "counter":
|
|
dataElement = promptCreateCounter();
|
|
break;
|
|
case "input":
|
|
dataElement = promptCreateInput();
|
|
break;
|
|
case "select":
|
|
dataElement = promptCreateSelect();
|
|
break;
|
|
default:
|
|
return promptError(`Unhandled input type '${promptOptions.type}'`);
|
|
}
|
|
|
|
if (promptOptions.type === "counter") {
|
|
dataContainerElement.append(createMinusButton(dataElement));
|
|
dataContainerElement.append(dataElement);
|
|
dataContainerElement.append(createPlusButton(dataElement));
|
|
} else {
|
|
dataContainerElement.append(dataElement);
|
|
}
|
|
|
|
dataElement.setAttribute("id", "data");
|
|
dataElement.focus();
|
|
|
|
if (promptOptions.type === "input" || promptOptions.type === "counter") {
|
|
dataElement.select();
|
|
}
|
|
|
|
//load custom script from options
|
|
if (promptOptions.customScript) {
|
|
try {
|
|
const customScript = require(promptOptions.customScript);
|
|
customScript();
|
|
} catch (error) {
|
|
return promptError(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
window.addEventListener("error", error => {
|
|
if (promptId) {
|
|
promptError("An error has occured on the prompt window: \n" +
|
|
JSON.stringify(error, ["message", "arguments", "type", "name"])
|
|
);
|
|
}
|
|
});
|
|
|
|
//send error to back
|
|
function promptError(error) {
|
|
if (error instanceof Error) {
|
|
error = error.message;
|
|
}
|
|
|
|
ipcRenderer.sendSync("prompt-error:" + promptId, error);
|
|
}
|
|
|
|
//send to back: input=null
|
|
function promptCancel() {
|
|
ipcRenderer.sendSync("prompt-post-data:" + promptId, null);
|
|
}
|
|
|
|
//transfer input data to back
|
|
function promptSubmit() {
|
|
const dataElement = $("#data");
|
|
let data = null;
|
|
|
|
switch (promptOptions.type) {
|
|
case "input":
|
|
data = dataElement.value;
|
|
break;
|
|
case "counter":
|
|
data = validateCounterInput(dataElement.value);
|
|
break;
|
|
case "select":
|
|
data = promptOptions.selectMultiple ?
|
|
dataElement.querySelectorAll("option[selected]").map(o => o.getAttribute("value")) :
|
|
dataElement.value;
|
|
break;
|
|
default: //will never happen
|
|
return promptError(`Unhandled input type '${promptOptions.type}'`);
|
|
}
|
|
|
|
ipcRenderer.sendSync("prompt-post-data:" + promptId, data);
|
|
}
|
|
|
|
//creates input box
|
|
function promptCreateInput() {
|
|
const dataElement = document.createElement("input");
|
|
dataElement.setAttribute("type", "text");
|
|
|
|
if (promptOptions.value) {
|
|
if (promptOptions.type === "counter") {
|
|
promptOptions.value = validateCounterInput(promptOptions.value);
|
|
}
|
|
dataElement.value = promptOptions.value;
|
|
} else {
|
|
dataElement.value = "";
|
|
}
|
|
|
|
//insert custom input attributes if in options
|
|
if (promptOptions.inputAttrs && typeof (promptOptions.inputAttrs) === "object") {
|
|
for (const k in promptOptions.inputAttrs) {
|
|
if (!Object.prototype.hasOwnProperty.call(promptOptions.inputAttrs, k)) {
|
|
continue;
|
|
}
|
|
|
|
dataElement.setAttribute(k, promptOptions.inputAttrs[k]);
|
|
}
|
|
}
|
|
|
|
//Cancel/Exit on 'Escape'
|
|
dataElement.addEventListener("keyup", event => {
|
|
if (event.key === "Escape") {
|
|
promptCancel();
|
|
}
|
|
});
|
|
|
|
//Confirm on 'Enter'
|
|
dataElement.addEventListener("keypress", event => {
|
|
if (event.key === "Enter") {
|
|
event.preventDefault();
|
|
$("#ok").click();
|
|
}
|
|
});
|
|
|
|
return dataElement;
|
|
}
|
|
|
|
//create multiple select
|
|
function promptCreateSelect() {
|
|
const dataElement = document.createElement("select");
|
|
let optionElement;
|
|
|
|
for (const k in promptOptions.selectOptions) {
|
|
if (!Object.prototype.hasOwnProperty.call(promptOptions.selectOptions, k)) {
|
|
continue;
|
|
}
|
|
|
|
optionElement = document.createElement("option");
|
|
optionElement.setAttribute("value", k);
|
|
optionElement.textContent = promptOptions.selectOptions[k];
|
|
if (k === promptOptions.value) {
|
|
optionElement.setAttribute("selected", "selected");
|
|
}
|
|
|
|
dataElement.append(optionElement);
|
|
}
|
|
|
|
return dataElement;
|
|
}
|
|
|
|
let nextTimeoutID = null;
|
|
|
|
/* Function execute callback in 3 accelerated intervals based on timer.
|
|
* Terminated from document.onmouseup() that is registered from promptCreateCounter()
|
|
* @param {function} callback: function to execute
|
|
* @param {object} timer: {
|
|
* * time: First delay in miliseconds.
|
|
* * limit: First Speed Limit, gets divided by 2 after $20 calls. $number change exponentially
|
|
* * scaleSpeed: Speed change per tick on first acceleration
|
|
* }
|
|
* @param {int} stepArgs: argument for callback representing Initial steps per click, default to 1
|
|
* steps starts to increase when speed is too fast to notice
|
|
* @param {int} counter: used internally to decrease timer.limit
|
|
*/
|
|
function multiFire(callback, timer = { time: 500, scaleSpeed: 140, limit: 100 }, stepsArg = 1, counter = 0) {
|
|
callback(stepsArg);
|
|
|
|
const nextTimeout = timer.time;
|
|
|
|
if (counter > 20) {
|
|
counter = 0 - stepsArg;
|
|
if (timer.limit > 1) {
|
|
timer.limit /= 2;
|
|
} else {
|
|
stepsArg *= 2;
|
|
}
|
|
}
|
|
|
|
if (timer.time !== timer.limit) {
|
|
timer.time = timer.time > timer.limit ?
|
|
timer.time - timer.scaleSpeed :
|
|
timer.limit;
|
|
}
|
|
|
|
nextTimeoutID = setTimeout(
|
|
multiFire, //callback
|
|
nextTimeout, //timer
|
|
//multiFire args:
|
|
callback,
|
|
timer,
|
|
stepsArg,
|
|
counter + 1
|
|
);
|
|
}
|
|
|
|
function createMinusButton(dataElement) {
|
|
function doMinus(steps) {
|
|
dataElement.value = validateCounterInput(parseInt(dataElement.value) - steps);
|
|
}
|
|
|
|
const minusBtn = document.createElement("span");
|
|
minusBtn.textContent = "-";
|
|
minusBtn.classList.add("minus");
|
|
|
|
if (promptOptions.counterOptions?.multiFire) {
|
|
minusBtn.onmousedown = () => {
|
|
multiFire(doMinus);
|
|
};
|
|
} else {
|
|
minusBtn.onmousedown = () => {
|
|
doMinus();
|
|
};
|
|
}
|
|
|
|
return minusBtn;
|
|
}
|
|
|
|
function createPlusButton(dataElement) {
|
|
function doPlus(steps) {
|
|
dataElement.value = validateCounterInput(parseInt(dataElement.value) + steps);
|
|
}
|
|
|
|
const plusBtn = document.createElement("span");
|
|
plusBtn.textContent = "+";
|
|
plusBtn.classList.add("plus");
|
|
|
|
if (promptOptions.counterOptions?.multiFire) {
|
|
plusBtn.onmousedown = () => {
|
|
multiFire(doPlus);
|
|
};
|
|
} else {
|
|
plusBtn.onmousedown = () => {
|
|
doPlus();
|
|
};
|
|
}
|
|
|
|
return plusBtn;
|
|
}
|
|
|
|
function promptCreateCounter() {
|
|
if (promptOptions.counterOptions?.multiFire) {
|
|
document.onmouseup = () => {
|
|
if (nextTimeoutID) {
|
|
clearTimeout(nextTimeoutID)
|
|
nextTimeoutID = null;
|
|
}
|
|
};
|
|
}
|
|
|
|
const dataElement = promptCreateInput();
|
|
|
|
dataElement.style.width = "unset";
|
|
dataElement.style["text-align"] = "center";
|
|
|
|
return dataElement;
|
|
}
|
|
|
|
//validate counter
|
|
function validateCounterInput(input) {
|
|
const min = promptOptions.counterOptions?.minimum;
|
|
const max = promptOptions.counterOptions?.maximum;
|
|
//note that !min/max would proc if min/max are 0
|
|
if (min !== null && min !== undefined && input < min) {
|
|
return min;
|
|
}
|
|
|
|
if (max !== null && max !== undefined && input > max) {
|
|
return max;
|
|
}
|
|
|
|
return input;
|
|
}
|