Add OBS actions, refactor some code and add configuration panel
This commit is contained in:
parent
d4029c8ef0
commit
3efa1beb4d
17 changed files with 449 additions and 47 deletions
94
package-lock.json
generated
94
package-lock.json
generated
|
@ -15,6 +15,7 @@
|
||||||
"materialize-css": "^1.0.0-rc.2",
|
"materialize-css": "^1.0.0-rc.2",
|
||||||
"morgan": "~1.9.1",
|
"morgan": "~1.9.1",
|
||||||
"node-sass-middleware": "0.11.0",
|
"node-sass-middleware": "0.11.0",
|
||||||
|
"obs-websocket-js": "^4.0.2",
|
||||||
"pug": "2.0.0-beta11",
|
"pug": "2.0.0-beta11",
|
||||||
"socket.io": "^3.1.2"
|
"socket.io": "^3.1.2"
|
||||||
},
|
},
|
||||||
|
@ -1308,6 +1309,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||||
},
|
},
|
||||||
|
"node_modules/isomorphic-ws": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"ws": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/isstream": {
|
"node_modules/isstream": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||||
|
@ -1726,6 +1735,38 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/obs-websocket-js": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/obs-websocket-js/-/obs-websocket-js-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-e+tGp0DQNXSnitc5lfuzEC1dG3VdWy7VLePUVb6aq7bC33Sgjoi695k0eOg4UPTIQI71Z9aJ+yn3nvBX9dQkEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.1.0",
|
||||||
|
"isomorphic-ws": "^4.0.1",
|
||||||
|
"sha.js": "^2.4.9",
|
||||||
|
"ws": "^7.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/obs-websocket-js/node_modules/debug": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/obs-websocket-js/node_modules/ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
"node_modules/on-finished": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
@ -2332,6 +2373,18 @@
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/sha.js": {
|
||||||
|
"version": "2.4.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||||
|
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sha.js": "bin.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/signal-exit": {
|
"node_modules/signal-exit": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
||||||
|
@ -4042,6 +4095,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||||
},
|
},
|
||||||
|
"isomorphic-ws": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"isstream": {
|
"isstream": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||||
|
@ -4377,6 +4436,32 @@
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||||
},
|
},
|
||||||
|
"obs-websocket-js": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/obs-websocket-js/-/obs-websocket-js-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-e+tGp0DQNXSnitc5lfuzEC1dG3VdWy7VLePUVb6aq7bC33Sgjoi695k0eOg4UPTIQI71Z9aJ+yn3nvBX9dQkEg==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.1.0",
|
||||||
|
"isomorphic-ws": "^4.0.1",
|
||||||
|
"sha.js": "^2.4.9",
|
||||||
|
"ws": "^7.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"on-finished": {
|
"on-finished": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
@ -4877,6 +4962,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
||||||
},
|
},
|
||||||
|
"sha.js": {
|
||||||
|
"version": "2.4.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||||
|
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
||||||
|
"requires": {
|
||||||
|
"inherits": "^2.0.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"signal-exit": {
|
"signal-exit": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"materialize-css": "^1.0.0-rc.2",
|
"materialize-css": "^1.0.0-rc.2",
|
||||||
"morgan": "~1.9.1",
|
"morgan": "~1.9.1",
|
||||||
"node-sass-middleware": "0.11.0",
|
"node-sass-middleware": "0.11.0",
|
||||||
|
"obs-websocket-js": "^4.0.2",
|
||||||
"pug": "2.0.0-beta11",
|
"pug": "2.0.0-beta11",
|
||||||
"socket.io": "^3.1.2"
|
"socket.io": "^3.1.2"
|
||||||
},
|
},
|
||||||
|
|
67
public/javascripts/settings/config.js
Normal file
67
public/javascripts/settings/config.js
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import { formMaker, inputFieldMaker } from "/javascripts/tools/formMaker.js"
|
||||||
|
const socket = io();
|
||||||
|
const collapsible = document.querySelector(".collapsible");
|
||||||
|
|
||||||
|
socket.on("connected", () => {
|
||||||
|
console.log("Connected !");
|
||||||
|
socket.emit("getType");
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("getType", data => {
|
||||||
|
collapsible.innerHTML = "";
|
||||||
|
for (const type of data)
|
||||||
|
if (type.configuration) {
|
||||||
|
const [formRow, form] = formMaker();
|
||||||
|
for (const [name, conf] of Object.entries(type.configuration)) {
|
||||||
|
let secondRow = document.createElement("div");
|
||||||
|
secondRow.classList.add("row");
|
||||||
|
form.insertAdjacentElement("beforeend", secondRow);
|
||||||
|
secondRow.insertAdjacentElement("beforeend", inputFieldMaker(type.type, conf.type, name, conf));
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = document.createElement("a");
|
||||||
|
save.classList.add("waves-effect", "waves-light", "btn", "blue");
|
||||||
|
save.innerText = "Save";
|
||||||
|
save.addEventListener("click", ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
let data = {};
|
||||||
|
for (const e of new FormData(form))
|
||||||
|
data[e[0]] = e[1];
|
||||||
|
socket.emit("setTypeConfig", {type: type.type, configuration: data})
|
||||||
|
});
|
||||||
|
formRow.insertAdjacentElement("beforeend", save);
|
||||||
|
|
||||||
|
addCollapsible(type.name, formRow);
|
||||||
|
}
|
||||||
|
M.updateTextFields();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("setTypeConfig", data => {
|
||||||
|
if (data && data.configuration) {
|
||||||
|
for (const [name, value] of Object.entries(data.configuration))
|
||||||
|
document.getElementById(data.type + "-" + name).value = value;
|
||||||
|
M.updateTextFields();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function addCollapsible(title, content) {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
const divTitle = document.createElement("div");
|
||||||
|
divTitle.classList.add("collapsible-header");
|
||||||
|
divTitle.innerText = title;
|
||||||
|
li.insertAdjacentElement("beforeend", divTitle);
|
||||||
|
const divContent = document.createElement("div");
|
||||||
|
divContent.classList.add("collapsible-body");
|
||||||
|
if (content)
|
||||||
|
if (typeof content !== "string")
|
||||||
|
divContent.insertAdjacentElement("beforeend", content);
|
||||||
|
else
|
||||||
|
divContent.insertAdjacentHTML("beforeend", content);
|
||||||
|
li.insertAdjacentElement("beforeend", divContent);
|
||||||
|
collapsible.insertAdjacentElement("beforeend", li);
|
||||||
|
return li;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
M.AutoInit();
|
||||||
|
});
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { inputFieldMaker } from "/javascripts/tools/formMaker.js"
|
||||||
|
|
||||||
const socket = io();
|
const socket = io();
|
||||||
const deckSelect = document.getElementById("deck-select");
|
const deckSelect = document.getElementById("deck-select");
|
||||||
const deck = document.getElementById("deck");
|
const deck = document.getElementById("deck");
|
||||||
|
@ -217,37 +219,13 @@ function customFields(values) {
|
||||||
customs.innerHTML = "";
|
customs.innerHTML = "";
|
||||||
let t = types.find(v => v.type === type.value);
|
let t = types.find(v => v.type === type.value);
|
||||||
for (const [name, field] of Object.entries(t.fields)) {
|
for (const [name, field] of Object.entries(t.fields)) {
|
||||||
let e;
|
if (values && name in values)
|
||||||
switch (field.type) {
|
field.value = values[name];
|
||||||
case "text":
|
customs.insertAdjacentElement("beforeend", inputFieldMaker(type.value, field.type, name, field));
|
||||||
e = document.createElement("input");
|
|
||||||
e.type = "text";
|
|
||||||
break;
|
|
||||||
case "select":
|
|
||||||
e = document.createElement("select");
|
|
||||||
for (let option of field.options)
|
|
||||||
e.insertAdjacentHTML("beforeend", `<option value="${option}">${option}</option>`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
e.name = name;
|
|
||||||
e.id = name;
|
|
||||||
e.required = true;
|
|
||||||
e.classList.add("validate");
|
|
||||||
let d = document.createElement("div");
|
|
||||||
d.classList.add("input-field");
|
|
||||||
d.insertAdjacentElement("beforeend", e);
|
|
||||||
d.insertAdjacentHTML("beforeend", `<label for="${name}">${field.name}</label>`);
|
|
||||||
if (field.helper)
|
|
||||||
d.insertAdjacentHTML("beforeend", `<span class="helper-text">${field.helper}</span>`);
|
|
||||||
customs.insertAdjacentElement("beforeend", d);
|
|
||||||
if (values && name in values) {
|
|
||||||
e.value = values[name];
|
|
||||||
if (field.type === "select")
|
|
||||||
e.querySelector(`option[value=${values[name]}]`).selected = true;
|
|
||||||
}
|
|
||||||
if (field.type === "select") {
|
if (field.type === "select") {
|
||||||
M.FormSelect.init(e);
|
const sel = customs.querySelector("select");
|
||||||
e.style.display = "none";
|
M.FormSelect.init(sel);
|
||||||
|
sel.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
M.updateTextFields();
|
M.updateTextFields();
|
||||||
|
|
63
public/javascripts/tools/formMaker.js
Normal file
63
public/javascripts/tools/formMaker.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
export function inputFieldMaker(Type, type, name, options) {
|
||||||
|
const inputField = document.createElement("div");
|
||||||
|
inputField.classList.add("input-field", "col", "s12");
|
||||||
|
|
||||||
|
let input;
|
||||||
|
switch (type) {
|
||||||
|
case "text":
|
||||||
|
input = document.createElement("input");
|
||||||
|
input.type = "text";
|
||||||
|
break;
|
||||||
|
case "select":
|
||||||
|
input = document.createElement("select");
|
||||||
|
for (const option of options.options) {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.value = opt.innerText = option;
|
||||||
|
input.insertAdjacentElement("beforeend", opt);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "number":
|
||||||
|
input = document.createElement("input");
|
||||||
|
input.type = "number";
|
||||||
|
break;
|
||||||
|
case "password":
|
||||||
|
input = document.createElement("input");
|
||||||
|
input.type = "password";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
input.id = Type + "-" + name;
|
||||||
|
input.name = name;
|
||||||
|
input.classList.add("validate");
|
||||||
|
if (options.required)
|
||||||
|
input.required = true;
|
||||||
|
if (options.value) {
|
||||||
|
input.value = options.value;
|
||||||
|
if (type === "select")
|
||||||
|
input.querySelectorAll(`option[value=${options.value}]`).forEach(o => o.selected = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inputField.insertAdjacentElement("beforeend", input);
|
||||||
|
|
||||||
|
const label = document.createElement("label");
|
||||||
|
label.for = input.id;
|
||||||
|
label.innerText = name;
|
||||||
|
inputField.insertAdjacentElement("beforeend", label);
|
||||||
|
|
||||||
|
if (options.helper) {
|
||||||
|
const helper = document.createElement("span");
|
||||||
|
helper.classList.add("helper-text");
|
||||||
|
helper.innerText = options.helper;
|
||||||
|
inputField.insertAdjacentElement("beforeend", helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputField;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formMaker() {
|
||||||
|
const row = document.createElement("div");
|
||||||
|
row.classList.add("row");
|
||||||
|
const form = document.createElement("form");
|
||||||
|
form.classList.add("col", "s12");
|
||||||
|
row.insertAdjacentElement("beforeend", form);
|
||||||
|
return [row, form];
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/", function(req, res) {
|
router.get("/", (req, res) => {
|
||||||
res.render("settings/decks", { title: "Settings"});
|
res.render("settings/decks", { title: "Decks", path: "/settings"});
|
||||||
|
}).get("/config", (req, res) => {
|
||||||
|
res.render("settings/config", {title:"Configuration", path: "/settings/config"})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
@ -6,6 +6,7 @@ module.exports = socket => {
|
||||||
socket.on("setSlot", require("./setSlot")(socket));
|
socket.on("setSlot", require("./setSlot")(socket));
|
||||||
socket.on("addDeck", require("./addDeck")(socket));
|
socket.on("addDeck", require("./addDeck")(socket));
|
||||||
socket.on("deleteDeck", require("./deleteDeck")(socket));
|
socket.on("deleteDeck", require("./deleteDeck")(socket));
|
||||||
|
socket.on("setTypeConfig", require("./setTypeConfig")(socket));
|
||||||
socket.on("trigger", require("./trigger")(socket));
|
socket.on("trigger", require("./trigger")(socket));
|
||||||
socket.on("uploadImage", require("./uploadImage")(socket));
|
socket.on("uploadImage", require("./uploadImage")(socket));
|
||||||
console.log("New connection !");
|
console.log("New connection !");
|
||||||
|
|
21
sockets/setTypeConfig.js
Normal file
21
sockets/setTypeConfig.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
const { types } = require("../types");
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = socket => {
|
||||||
|
return data => {
|
||||||
|
if (data.type && data.configuration) {
|
||||||
|
try {
|
||||||
|
const type = types[data.type], config = type.config();
|
||||||
|
for (const [name, value] of Object.entries(data.configuration))
|
||||||
|
config[name] = value;
|
||||||
|
type.saveConfig(config);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
socket.emit("setTypeConfig", {error: err.code});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socket.emit("setTypeConfig", data);
|
||||||
|
socket.broadcast.emit("setTypeConfig", data);
|
||||||
|
}
|
||||||
|
};
|
|
@ -21,27 +21,33 @@ class Base {
|
||||||
if (!(position[0] in db.decks[name].rows))
|
if (!(position[0] in db.decks[name].rows))
|
||||||
db.decks[name].rows[position[0]] = {};
|
db.decks[name].rows[position[0]] = {};
|
||||||
db.decks[name].rows[position[0]][position[1]] = this.toJSON();
|
db.decks[name].rows[position[0]][position[1]] = this.toJSON();
|
||||||
Base.#write()
|
Base.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
static saveConfig(type, configuration) {
|
||||||
|
db.types[type] = configuration;
|
||||||
|
Base.write();
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(name, position) {
|
remove(name, position) {
|
||||||
if (position[0] in db.decks[name].rows && position[1] in db.decks[name].rows[position[0]]) {
|
if (position[0] in db.decks[name].rows && position[1] in db.decks[name].rows[position[0]]) {
|
||||||
delete db.decks[name].rows[position[0]][position[1]];
|
delete db.decks[name].rows[position[0]][position[1]];
|
||||||
Base.#write();
|
Base.write();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static #write() {
|
static write() {
|
||||||
fs.writeFileSync("./db.json", JSON.stringify(db));
|
fs.writeFileSync("./db.json", JSON.stringify(db));
|
||||||
}
|
}
|
||||||
|
|
||||||
static staticToJSON(name, type, fields) {
|
static staticToJSON(name, type, fields, config) {
|
||||||
return {
|
return {
|
||||||
"name": name,
|
"name": name,
|
||||||
"type": type,
|
"type": type,
|
||||||
"fields": fields
|
"fields": fields,
|
||||||
|
"configuration": config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,10 @@ class Deck extends Base {
|
||||||
static fields() {
|
static fields() {
|
||||||
return {
|
return {
|
||||||
deck: {
|
deck: {
|
||||||
"type": "select",
|
type: "select",
|
||||||
"options": Object.keys(db.decks),
|
options: Object.keys(db.decks),
|
||||||
"name": "Deck"
|
name: "Deck",
|
||||||
|
required: true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ class ExecCommand extends Base {
|
||||||
static fields = {
|
static fields = {
|
||||||
cmd: {
|
cmd: {
|
||||||
type: "text",
|
type: "text",
|
||||||
name: "Command"
|
name: "Command",
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ class Keys extends Base {
|
||||||
keys: {
|
keys: {
|
||||||
type: "text",
|
type: "text",
|
||||||
name: "Keys",
|
name: "Keys",
|
||||||
|
required: true,
|
||||||
helper: "Key separated by a comma, if combo use +"
|
helper: "Key separated by a comma, if combo use +"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
155
types/OBS.js
Normal file
155
types/OBS.js
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
const Base = require("./Base");
|
||||||
|
const OBSWebSocket = require('obs-websocket-js');
|
||||||
|
const db = require("../db.json");
|
||||||
|
|
||||||
|
class OBS extends Base {
|
||||||
|
static name = "OBS";
|
||||||
|
static type = "obs";
|
||||||
|
static fields = {
|
||||||
|
cmd: {
|
||||||
|
type: "select",
|
||||||
|
options: ["startStreaming", "stopStreaming", "toggleStreaming", "startRecording", "stopRecording", "toggleRecording"],
|
||||||
|
name: "Action",
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static obs = new OBSWebSocket();
|
||||||
|
|
||||||
|
constructor(text, image = null, options = null) {
|
||||||
|
super(text, image, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
static config() {
|
||||||
|
return {
|
||||||
|
host: {
|
||||||
|
type: "text",
|
||||||
|
name: "Address",
|
||||||
|
required: true,
|
||||||
|
value: db.types[OBS.type].host,
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
type: "number",
|
||||||
|
name: "Port",
|
||||||
|
required: true,
|
||||||
|
value: db.types[OBS.type].port,
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: "password",
|
||||||
|
name: "password",
|
||||||
|
value: db.types[OBS.type].password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
static saveConfig(configuration) {
|
||||||
|
super.saveConfig(OBS.type, configuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
static staticToJSON() {
|
||||||
|
return super.staticToJSON(OBS.name, OBS.type, OBS.fields, OBS.config());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return super.toJSON(OBS.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async connect() {
|
||||||
|
const config = OBS.config();
|
||||||
|
try {
|
||||||
|
await OBS.obs.connect({
|
||||||
|
address: config.host.value + ":" + config.port.value,
|
||||||
|
password: config.password.value
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Fail to connect !");
|
||||||
|
console.error(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
async trigger(socket) {
|
||||||
|
try {
|
||||||
|
switch (this.options.cmd) {
|
||||||
|
case "startStreaming":
|
||||||
|
await OBS.obs.send("StartStreaming");
|
||||||
|
break;
|
||||||
|
case "stopStreaming":
|
||||||
|
await OBS.obs.send("StopStreaming");
|
||||||
|
break;
|
||||||
|
case "toggleStreaming":
|
||||||
|
try {
|
||||||
|
await OBS.obs.send("StartStreaming");
|
||||||
|
} catch (err) {
|
||||||
|
if (err.error === "streaming already active")
|
||||||
|
await OBS.obs.send("StopStreaming");
|
||||||
|
else
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "startRecording":
|
||||||
|
await OBS.obs.send("StartRecording");
|
||||||
|
break;
|
||||||
|
case "stopRecording":
|
||||||
|
await OBS.obs.send("StopRecording");
|
||||||
|
break;
|
||||||
|
case "toggleRecording":
|
||||||
|
try {
|
||||||
|
await OBS.obs.send("StartRecording");
|
||||||
|
} catch (err) {
|
||||||
|
if (err.error === "recording already active")
|
||||||
|
await OBS.obs.send("StopRecording");
|
||||||
|
else
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
switch (err.error) {
|
||||||
|
case "There is no Socket connection available.":
|
||||||
|
if (!await OBS.connect())
|
||||||
|
socket.emit("trigger", {error: "failToConnectOBS"});
|
||||||
|
else
|
||||||
|
this.trigger(socket);
|
||||||
|
break;
|
||||||
|
case "streaming already active":
|
||||||
|
console.error("Streaming already active");
|
||||||
|
break;
|
||||||
|
case "streaming not active":
|
||||||
|
console.error("Streaming not active");
|
||||||
|
break;
|
||||||
|
case "recording already active":
|
||||||
|
console.error("Recording already active");
|
||||||
|
break;
|
||||||
|
case "recording not active":
|
||||||
|
console.error("Recording not active");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(OBS.type in db.types)) {
|
||||||
|
db.types[OBS.type] = {};
|
||||||
|
OBS.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBS.obs.on("error", err => {
|
||||||
|
console.error("socket error:", err);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = OBS;
|
|
@ -3,7 +3,8 @@ const db = require("../db.json");
|
||||||
const types = {
|
const types = {
|
||||||
"execCommand": require("./ExecCommand"),
|
"execCommand": require("./ExecCommand"),
|
||||||
"deck": require("./Deck"),
|
"deck": require("./Deck"),
|
||||||
"keys": require("./Keys")
|
"keys": require("./Keys"),
|
||||||
|
"obs": require("./OBS")
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.types = types;
|
module.exports.types = types;
|
||||||
|
|
7
views/settings/config.pug
Normal file
7
views/settings/config.pug
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
extends ./settings
|
||||||
|
|
||||||
|
block settings
|
||||||
|
.container
|
||||||
|
ul.collapsible
|
||||||
|
|
||||||
|
script(src="/javascripts/settings/config.js" type="module")
|
|
@ -1,9 +1,10 @@
|
||||||
extends ./settings
|
extends ./settings
|
||||||
|
|
||||||
block settings
|
block settings
|
||||||
.input-field
|
.container
|
||||||
select#deck-select
|
.input-field
|
||||||
label Deck
|
select#deck-select
|
||||||
|
label Deck
|
||||||
|
|
||||||
.container#deck
|
.container#deck
|
||||||
|
|
||||||
|
@ -70,4 +71,4 @@ block settings
|
||||||
button(data-target="modalAdd")#clearAdd.modal-close.waves-effect.waves-grey.btn-flat Cancel
|
button(data-target="modalAdd")#clearAdd.modal-close.waves-effect.waves-grey.btn-flat Cancel
|
||||||
a#add.waves-effect.waves-green.btn-flat Save
|
a#add.waves-effect.waves-green.btn-flat Save
|
||||||
|
|
||||||
script(src="/javascripts/settings/decks.js")
|
script(src="/javascripts/settings/decks.js" type="module")
|
||||||
|
|
|
@ -5,6 +5,8 @@ block content
|
||||||
.nav-wrapper
|
.nav-wrapper
|
||||||
a.brand-logo.right(href="/") OpenDeck
|
a.brand-logo.right(href="/") OpenDeck
|
||||||
ul#nav-mobile.left.hide-on-med-and-down
|
ul#nav-mobile.left.hide-on-med-and-down
|
||||||
li
|
li(class=path==="/settings"? "active": "")
|
||||||
a(href="/settings") Decks
|
a(href="/settings") Decks
|
||||||
|
li(class=path==="/settings/config"? "active": "")
|
||||||
|
a(href="/settings/config") Configuration
|
||||||
block settings
|
block settings
|
||||||
|
|
Loading…
Reference in a new issue