continuous-integration/drone/push Build encountered an error
- html/embed.go embeds html/ (pages, css, img, js, video); src/assets.go
serves it, with os.DirFS("html") under -dev. Static assets get an ETag
and Cache-Control: no-cache; HTML pages are still templated (only the
login error message is substituted now).
- Delete the generated src/webUI.go (783 KB base64), src/html-build.go and
cmd/webui-gen; Dockerfile no longer runs a generator.
- Language layer removed: 254 {{.x}} placeholders inlined as English
strings in ts/*.ts and the two auth pages; html/lang/en.json, the
LanguageUI struct and the 'language' setting are gone.
- ts/tsconfig.json + package.json pin typescript 5.9.3; the seven sources
compile (ES2020, global scripts) into one committed html/js/app.js.
Ten unreferenced legacy scripts under html/js/ deleted; all pages load
js/app.js.
- Fix the six type errors that blocked a clean compile, including a real
bug: a missing semicolon in the search shortcut handler made the code
call the result of preventDefault(), so the shortcut threw instead of
focusing the search box.
- /healthz liveness endpoint; Dockerfile healthcheck and README use it.
- Drone: go vet, and a webui-check step that rebuilds the bundle and fails
if the committed app.js is stale.
- README-DEV.md documents build, UI toolchain, -dev, versioning, CI.
3416 lines
137 KiB
JavaScript
3416 lines
137 KiB
JavaScript
class Server {
|
|
constructor(cmd) {
|
|
this.cmd = cmd;
|
|
}
|
|
request(data) {
|
|
if (SERVER_CONNECTION == true) {
|
|
return;
|
|
}
|
|
SERVER_CONNECTION = true;
|
|
console.log(data);
|
|
if (this.cmd != "updateLog") {
|
|
showElement("loading", true);
|
|
UNDO = new Object();
|
|
setConnectionState("busy");
|
|
}
|
|
switch (window.location.protocol) {
|
|
case "http:":
|
|
this.protocol = "ws://";
|
|
break;
|
|
case "https:":
|
|
this.protocol = "wss://";
|
|
break;
|
|
}
|
|
var wsHost = window.location.host;
|
|
if (wsHost == undefined || wsHost.length < 1) {
|
|
wsHost = window.location.hostname;
|
|
}
|
|
var url = this.protocol + wsHost + "/data/" + "?Token=" + getCookie("Token");
|
|
data["cmd"] = this.cmd;
|
|
var requestCmd = data["cmd"];
|
|
var ws = new WebSocket(url);
|
|
var isLogUpdate = data["cmd"] == "updateLog";
|
|
var responseReceived = false;
|
|
var requestFinished = false;
|
|
var timeoutMs = 12000;
|
|
var requestTimeout;
|
|
var finishRequest = function (state, responseSuccess = false) {
|
|
if (requestFinished == true) {
|
|
return;
|
|
}
|
|
requestFinished = true;
|
|
SERVER_CONNECTION = false;
|
|
window.clearTimeout(requestTimeout);
|
|
if (responseSuccess == true) {
|
|
if (state == "online") {
|
|
WS_FAILURE_COUNT = 0;
|
|
}
|
|
}
|
|
else {
|
|
WS_FAILURE_COUNT++;
|
|
}
|
|
if (isLogUpdate == false) {
|
|
showElement("loading", false);
|
|
}
|
|
if (state != "") {
|
|
setConnectionState(state);
|
|
}
|
|
};
|
|
requestTimeout = window.setTimeout(function () {
|
|
console.log("Websocket request timed out.");
|
|
var timeoutState = "offline";
|
|
if (isLogUpdate == true && WS_FAILURE_COUNT < 2) {
|
|
timeoutState = "idle";
|
|
}
|
|
finishRequest(timeoutState, false);
|
|
try {
|
|
ws.close();
|
|
}
|
|
catch (err) {
|
|
console.log(err);
|
|
}
|
|
}, timeoutMs);
|
|
ws.onopen = function () {
|
|
WS_AVAILABLE = true;
|
|
if (data["cmd"] != "updateLog") {
|
|
setConnectionState("busy");
|
|
}
|
|
console.log("REQUEST (JS):");
|
|
console.log(data);
|
|
console.log("REQUEST: (JSON)");
|
|
console.log(JSON.stringify(data));
|
|
this.send(JSON.stringify(data));
|
|
};
|
|
ws.onerror = function (e) {
|
|
console.log("No websocket connection to xTeVe could be established. Check your network configuration.");
|
|
var errorState = "offline";
|
|
if (isLogUpdate == true && WS_FAILURE_COUNT < 2) {
|
|
errorState = "idle";
|
|
}
|
|
finishRequest(errorState, false);
|
|
if (WS_AVAILABLE == false && isLogUpdate == false && requestCmd != "getServerConfig") {
|
|
alert("No websocket connection to xTeVe could be established. Check your network configuration.");
|
|
}
|
|
};
|
|
ws.onmessage = function (e) {
|
|
responseReceived = true;
|
|
finishRequest("online", true);
|
|
console.log("RESPONSE:");
|
|
var response = JSON.parse(e.data);
|
|
console.log(response);
|
|
if (response.hasOwnProperty("token")) {
|
|
document.cookie = "Token=" + response["token"];
|
|
}
|
|
if (response["status"] == false) {
|
|
setConnectionState("offline");
|
|
alert(response["err"]);
|
|
if (response.hasOwnProperty("reload")) {
|
|
location.reload();
|
|
}
|
|
return;
|
|
}
|
|
if (response.hasOwnProperty("logoURL")) {
|
|
var div = document.getElementById("channel-icon");
|
|
div.value = response["logoURL"];
|
|
div.className = "changed";
|
|
return;
|
|
}
|
|
switch (data["cmd"]) {
|
|
case "updateLog":
|
|
SERVER["log"] = response["log"];
|
|
if (document.getElementById("content_log")) {
|
|
showLogs(false);
|
|
}
|
|
return;
|
|
break;
|
|
default:
|
|
SERVER = new Object();
|
|
SERVER = response;
|
|
break;
|
|
}
|
|
if (response.hasOwnProperty("openMenu")) {
|
|
var menu = document.getElementById(response["openMenu"]);
|
|
menu.click();
|
|
showElement("popup", false);
|
|
}
|
|
if (response.hasOwnProperty("openLink")) {
|
|
window.location = response["openLink"];
|
|
}
|
|
if (response.hasOwnProperty("alert")) {
|
|
alert(response["alert"]);
|
|
}
|
|
if (response.hasOwnProperty("reload")) {
|
|
location.reload();
|
|
}
|
|
if (response.hasOwnProperty("wizard")) {
|
|
createLayout();
|
|
configurationWizard[response["wizard"]].createWizard();
|
|
return;
|
|
}
|
|
createLayout();
|
|
};
|
|
ws.onclose = function () {
|
|
if (responseReceived == true) {
|
|
return;
|
|
}
|
|
var closeState = "offline";
|
|
if (isLogUpdate == true && WS_FAILURE_COUNT < 2) {
|
|
closeState = "idle";
|
|
}
|
|
finishRequest(closeState, false);
|
|
};
|
|
}
|
|
}
|
|
var WS_FAILURE_COUNT = 0;
|
|
function getCookie(name) {
|
|
var value = "; " + document.cookie;
|
|
var parts = value.split("; " + name + "=");
|
|
if (parts.length == 2)
|
|
return parts.pop().split(";").shift();
|
|
}
|
|
class MainMenu {
|
|
constructor() {
|
|
this.DocumentID = "main-menu";
|
|
this.HTMLTag = "LI";
|
|
this.ImagePath = "img/";
|
|
}
|
|
createIMG(src) {
|
|
var element = document.createElement("IMG");
|
|
element.setAttribute("src", this.ImagePath + src);
|
|
return element;
|
|
}
|
|
createValue(value) {
|
|
var element = document.createElement("P");
|
|
element.innerHTML = value;
|
|
return element;
|
|
}
|
|
}
|
|
class MainMenuItem extends MainMenu {
|
|
constructor(menuKey, value, image, headline) {
|
|
super();
|
|
this.menuKey = menuKey;
|
|
this.value = value;
|
|
this.imgSrc = image;
|
|
this.headline = headline;
|
|
}
|
|
createItem() {
|
|
var item = document.createElement("LI");
|
|
item.setAttribute("onclick", "javascript: openThisMenu(this)");
|
|
item.setAttribute("id", this.id);
|
|
item.setAttribute("data-menu", this.menuKey);
|
|
var img = this.createIMG(this.imgSrc);
|
|
var value = this.createValue(this.value);
|
|
item.appendChild(img);
|
|
item.appendChild(value);
|
|
var doc = document.getElementById(this.DocumentID);
|
|
doc.appendChild(item);
|
|
switch (this.menuKey) {
|
|
case "playlist":
|
|
this.tableHeader = ["Playlist", "Tuner", "Last Update", "Availability %", "Type", "Streams", "group-title %", "tvg-id %", "Unique ID %"];
|
|
break;
|
|
case "xmltv":
|
|
this.tableHeader = ["Guide", "Last Update", "Availability %", "Channels", "Programs"];
|
|
break;
|
|
case "filter":
|
|
this.tableHeader = ["Filter Name", "Filter Type", "Filter"];
|
|
break;
|
|
case "users":
|
|
this.tableHeader = ["Username", "Password", "WEB", "PMS", "M3U", "XML", "API"];
|
|
break;
|
|
case "mapping":
|
|
this.tableHeader = ["BULK", "Ch. No.", "Logo", "Channel Name", "Playlist", "Group Title", "XMLTV File", "XMLTV ID", "Edit"];
|
|
break;
|
|
}
|
|
//console.log(this.menuKey, this.tableHeader);
|
|
}
|
|
}
|
|
class Content {
|
|
constructor() {
|
|
this.DocumentID = "content";
|
|
this.TableID = "content_table";
|
|
this.headerClass = "content_table_header";
|
|
this.interactionID = "content-interaction";
|
|
}
|
|
createHeadline(value) {
|
|
var element = document.createElement("H3");
|
|
element.innerHTML = value;
|
|
return element;
|
|
}
|
|
createHR() {
|
|
var element = document.createElement("HR");
|
|
return element;
|
|
}
|
|
createInteraction() {
|
|
var element = document.createElement("DIV");
|
|
element.setAttribute("id", this.interactionID);
|
|
return element;
|
|
}
|
|
createDIV() {
|
|
var element = document.createElement("DIV");
|
|
element.id = this.DivID;
|
|
return element;
|
|
}
|
|
createTABLE() {
|
|
var element = document.createElement("TABLE");
|
|
element.id = this.TableID;
|
|
return element;
|
|
}
|
|
createTableRow() {
|
|
var element = document.createElement("TR");
|
|
element.className = this.headerClass;
|
|
return element;
|
|
}
|
|
createTableContent(menuKey) {
|
|
var data = new Object();
|
|
var rows = new Array();
|
|
switch (menuKey) {
|
|
case "playlist":
|
|
var fileTypes = new Array("m3u", "hdhr");
|
|
fileTypes.forEach(fileType => {
|
|
data = SERVER["settings"]["files"][fileType];
|
|
var keys = getObjKeys(data);
|
|
keys.forEach(key => {
|
|
var tr = document.createElement("TR");
|
|
tr.id = key;
|
|
tr.setAttribute('onclick', 'javascript: openPopUp("' + fileType + '", this)');
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["name"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
if (SERVER["settings"]["buffer"] != "-") {
|
|
cell.value = data[key]["tuner"];
|
|
}
|
|
else {
|
|
cell.value = "-";
|
|
}
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["last.update"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["provider.availability"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["type"].toUpperCase();
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["compatibility"]["streams"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["compatibility"]["group.title"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["compatibility"]["tvg.id"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["compatibility"]["stream.id"];
|
|
tr.appendChild(cell.createCell());
|
|
rows.push(tr);
|
|
});
|
|
});
|
|
break;
|
|
case "filter":
|
|
delete SERVER["settings"]["filter"][-1];
|
|
data = SERVER["settings"]["filter"];
|
|
var keys = getObjKeys(data);
|
|
keys.forEach(key => {
|
|
var tr = document.createElement("TR");
|
|
tr.id = key;
|
|
tr.setAttribute('onclick', 'javascript: openPopUp("' + data[key]["type"] + '", this)');
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["name"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
switch (data[key]["type"]) {
|
|
case "custom-filter":
|
|
cell.value = "Custom";
|
|
break;
|
|
case "group-title":
|
|
cell.value = "Group";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["filter"];
|
|
tr.appendChild(cell.createCell());
|
|
rows.push(tr);
|
|
});
|
|
break;
|
|
case "xmltv":
|
|
var fileTypes = new Array("xmltv");
|
|
fileTypes.forEach(fileType => {
|
|
data = SERVER["settings"]["files"][fileType];
|
|
var keys = getObjKeys(data);
|
|
keys.forEach(key => {
|
|
var tr = document.createElement("TR");
|
|
tr.id = key;
|
|
tr.setAttribute('onclick', 'javascript: openPopUp("' + fileType + '", this)');
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["name"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["last.update"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["provider.availability"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["compatibility"]["xmltv.channels"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["compatibility"]["xmltv.programs"];
|
|
tr.appendChild(cell.createCell());
|
|
rows.push(tr);
|
|
});
|
|
});
|
|
break;
|
|
case "users":
|
|
var fileTypes = new Array("users");
|
|
fileTypes.forEach(fileType => {
|
|
data = SERVER[fileType];
|
|
var keys = getObjKeys(data);
|
|
keys.forEach(key => {
|
|
var tr = document.createElement("TR");
|
|
tr.id = key;
|
|
tr.setAttribute('onclick', 'javascript: openPopUp("' + fileType + '", this)');
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["data"]["username"];
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = "******";
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
if (data[key]["data"]["authentication.web"] == true) {
|
|
cell.value = "✓";
|
|
}
|
|
else {
|
|
cell.value = "-";
|
|
}
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
if (data[key]["data"]["authentication.pms"] == true) {
|
|
cell.value = "✓";
|
|
}
|
|
else {
|
|
cell.value = "-";
|
|
}
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
if (data[key]["data"]["authentication.m3u"] == true) {
|
|
cell.value = "✓";
|
|
}
|
|
else {
|
|
cell.value = "-";
|
|
}
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
if (data[key]["data"]["authentication.xml"] == true) {
|
|
cell.value = "✓";
|
|
}
|
|
else {
|
|
cell.value = "-";
|
|
}
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
if (data[key]["data"]["authentication.api"] == true) {
|
|
cell.value = "✓";
|
|
}
|
|
else {
|
|
cell.value = "-";
|
|
}
|
|
tr.appendChild(cell.createCell());
|
|
rows.push(tr);
|
|
});
|
|
});
|
|
break;
|
|
case "mapping":
|
|
BULK_EDIT = false;
|
|
createSearchObj();
|
|
checkUndo("epgMapping");
|
|
console.log("MAPPING");
|
|
data = SERVER["xepg"]["epgMapping"];
|
|
var keys = getObjKeys(data);
|
|
keys.forEach(key => {
|
|
var tr = document.createElement("TR");
|
|
tr.id = key;
|
|
//tr.setAttribute('oncontextmenu', 'javascript: rightClick(this)')
|
|
switch (data[key]["x-active"]) {
|
|
case true:
|
|
tr.className = "activeEPG";
|
|
break;
|
|
case false:
|
|
tr.className = "notActiveEPG";
|
|
break;
|
|
}
|
|
// Bulk
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "BULK";
|
|
cell.value = false;
|
|
tr.appendChild(cell.createCell());
|
|
// Kanalnummer
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "INPUTCHANNEL";
|
|
cell.value = data[key]["x-channelID"];
|
|
//td.setAttribute('onclick', 'javascript: changeChannelNumber("' + key + '", this)')
|
|
tr.appendChild(cell.createCell());
|
|
// Logo
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "IMG";
|
|
cell.imageURL = data[key]["tvg-logo"];
|
|
tr.appendChild(cell.createCell());
|
|
// Kanalname
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.className = data[key]["x-category"];
|
|
cell.value = data[key]["x-name"];
|
|
tr.appendChild(cell.createCell());
|
|
// Playlist
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
//cell.value = data[key]["_file.m3u.name"]
|
|
cell.value = getValueFromProviderFile(data[key]["_file.m3u.id"], "m3u", "name");
|
|
tr.appendChild(cell.createCell());
|
|
// Gruppe (group-title)
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = data[key]["x-group-title"];
|
|
tr.appendChild(cell.createCell());
|
|
// XMLTV Datei
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
if (data[key]["x-xmltv-file"] != "-") {
|
|
cell.value = getValueFromProviderFile(data[key]["x-xmltv-file"], "xmltv", "name");
|
|
}
|
|
else {
|
|
cell.value = data[key]["x-xmltv-file"];
|
|
}
|
|
tr.appendChild(cell.createCell());
|
|
// XMLTV Kanal
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
//var value = str.substring(1, 4);
|
|
var value = data[key]["x-mapping"];
|
|
if (value.length > 20) {
|
|
value = data[key]["x-mapping"].substring(0, 20) + "...";
|
|
}
|
|
cell.value = value;
|
|
tr.appendChild(cell.createCell());
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "EDIT";
|
|
cell.value = "Edit";
|
|
var editTd = cell.createCell();
|
|
var editButton = editTd.firstChild;
|
|
editButton.setAttribute('onclick', 'javascript: openPopUp("mapping", this)');
|
|
editButton.setAttribute("id", key);
|
|
editButton.setAttribute("aria-label", "Edit " + data[key]["x-name"]);
|
|
tr.appendChild(editTd);
|
|
rows.push(tr);
|
|
});
|
|
break;
|
|
case "settings":
|
|
alert();
|
|
break;
|
|
default:
|
|
console.log("Table content (menuKey):", menuKey);
|
|
break;
|
|
}
|
|
return rows;
|
|
}
|
|
}
|
|
class Cell {
|
|
createCell() {
|
|
var td = document.createElement("TD");
|
|
if (this.child == true) {
|
|
var element;
|
|
switch (this.childType) {
|
|
case "P":
|
|
element = document.createElement(this.childType);
|
|
element.innerHTML = this.value;
|
|
element.className = this.className;
|
|
break;
|
|
case "INPUT":
|
|
element = document.createElement(this.childType);
|
|
element.value = this.value;
|
|
element.type = "text";
|
|
break;
|
|
case "INPUTCHANNEL":
|
|
element = document.createElement("INPUT");
|
|
element.setAttribute("onchange", "javscript: changeChannelNumber(this)");
|
|
element.value = this.value;
|
|
element.type = "text";
|
|
break;
|
|
case "BULK":
|
|
element = document.createElement("INPUT");
|
|
element.checked = this.value;
|
|
element.type = "checkbox";
|
|
element.className = "bulk hideBulk";
|
|
element.addEventListener("click", function (event) {
|
|
scheduleChannelRangeSelection(element, event);
|
|
});
|
|
break;
|
|
case "BULK_HEAD":
|
|
element = document.createElement("INPUT");
|
|
element.checked = this.value;
|
|
element.type = "checkbox";
|
|
element.className = "bulk hideBulk";
|
|
element.setAttribute("onclick", "javascript: selectAllChannels()");
|
|
break;
|
|
case "IMG":
|
|
element = document.createElement(this.childType);
|
|
element.setAttribute("src", this.imageURL);
|
|
if (this.imageURL != "") {
|
|
element.setAttribute("onerror", "javascript: this.onerror=null;this.src=''");
|
|
//onerror="this.onerror=null;this.src='missing.gif';"
|
|
}
|
|
break;
|
|
case "EDIT":
|
|
element = document.createElement("INPUT");
|
|
element.type = "button";
|
|
element.value = this.value;
|
|
element.className = "mapping-edit-button";
|
|
break;
|
|
}
|
|
td.appendChild(element);
|
|
}
|
|
else {
|
|
td.innerHTML = this.value;
|
|
}
|
|
if (this.onclick == true) {
|
|
td.setAttribute("onclick", this.onclickFunktion);
|
|
td.className = "pointer";
|
|
}
|
|
if (this.tdClassName != undefined) {
|
|
td.className = this.tdClassName;
|
|
}
|
|
return td;
|
|
}
|
|
}
|
|
class ShowContent extends Content {
|
|
constructor(menuID) {
|
|
super();
|
|
this.menuID = menuID;
|
|
}
|
|
createInput(type, name, value) {
|
|
var input = document.createElement("INPUT");
|
|
input.setAttribute("type", type);
|
|
input.setAttribute("name", name);
|
|
input.setAttribute("value", value);
|
|
return input;
|
|
}
|
|
show() {
|
|
COLUMN_TO_SORT = -1;
|
|
// Alten Inhalt löschen
|
|
var doc = document.getElementById(this.DocumentID);
|
|
doc.innerHTML = "";
|
|
showPreview(false);
|
|
// Überschrift
|
|
var headline = menuItems[this.menuID].headline;
|
|
var menuKey = menuItems[this.menuID].menuKey;
|
|
var h = this.createHeadline(headline);
|
|
doc.appendChild(h);
|
|
var hr = this.createHR();
|
|
doc.appendChild(hr);
|
|
// Interaktion
|
|
var div = this.createInteraction();
|
|
doc.appendChild(div);
|
|
var interaction = document.getElementById(this.interactionID);
|
|
switch (menuKey) {
|
|
case "playlist":
|
|
var input = this.createInput("button", menuKey, "New");
|
|
input.setAttribute("id", "-");
|
|
input.setAttribute("onclick", 'javascript: openPopUp("playlist")');
|
|
interaction.appendChild(input);
|
|
break;
|
|
case "filter":
|
|
var input = this.createInput("button", menuKey, "New");
|
|
input.setAttribute("id", -1);
|
|
input.setAttribute("onclick", 'javascript: openPopUp("filter", this)');
|
|
interaction.appendChild(input);
|
|
break;
|
|
case "xmltv":
|
|
var input = this.createInput("button", menuKey, "New");
|
|
input.setAttribute("id", "xmltv");
|
|
input.setAttribute("onclick", 'javascript: openPopUp("xmltv")');
|
|
interaction.appendChild(input);
|
|
break;
|
|
case "users":
|
|
var input = this.createInput("button", menuKey, "New");
|
|
input.setAttribute("id", "users");
|
|
input.setAttribute("onclick", 'javascript: openPopUp("users")');
|
|
interaction.appendChild(input);
|
|
break;
|
|
case "mapping":
|
|
showElement("loading", true);
|
|
var input = this.createInput("button", menuKey, "Save");
|
|
input.setAttribute("onclick", 'javascript: savePopupData("mapping", "", "")');
|
|
interaction.appendChild(input);
|
|
var input = this.createInput("button", menuKey, "Bulk Edit");
|
|
input.setAttribute("onclick", 'javascript: bulkEdit()');
|
|
interaction.appendChild(input);
|
|
var input = this.createInput("search", "search", "");
|
|
input.setAttribute("id", "searchMapping");
|
|
input.setAttribute("placeholder", "Search");
|
|
input.className = "search";
|
|
input.setAttribute("oninput", 'javascript: searchInMapping()');
|
|
interaction.appendChild(input);
|
|
break;
|
|
case "settings":
|
|
var input = this.createInput("button", menuKey, "Save");
|
|
input.setAttribute("onclick", 'javascript: saveSettings();');
|
|
interaction.appendChild(input);
|
|
var input = this.createInput("button", menuKey, "Backup");
|
|
input.setAttribute("onclick", 'javascript: backup();');
|
|
interaction.appendChild(input);
|
|
var input = this.createInput("button", menuKey, "Restore");
|
|
input.setAttribute("onclick", 'javascript: restore();');
|
|
interaction.appendChild(input);
|
|
var wrapper = document.createElement("DIV");
|
|
wrapper.setAttribute("id", "box-wrapper");
|
|
doc.appendChild(wrapper);
|
|
this.DivID = "content_settings";
|
|
var settings = this.createDIV();
|
|
wrapper.appendChild(settings);
|
|
showSettings();
|
|
return;
|
|
break;
|
|
case "log":
|
|
var input = this.createInput("button", menuKey, "Reset Logs");
|
|
input.setAttribute("onclick", 'javascript: resetLogs();');
|
|
interaction.appendChild(input);
|
|
var wrapper = document.createElement("DIV");
|
|
wrapper.setAttribute("id", "box-wrapper");
|
|
doc.appendChild(wrapper);
|
|
this.DivID = "content_log";
|
|
var logs = this.createDIV();
|
|
wrapper.appendChild(logs);
|
|
showLogs(true);
|
|
return;
|
|
break;
|
|
case "logout":
|
|
location.reload();
|
|
document.cookie = "Token= ; expires = Thu, 01 Jan 1970 00:00:00 GMT";
|
|
break;
|
|
default:
|
|
console.log("Show content (menuKey):", menuKey);
|
|
break;
|
|
}
|
|
// Tabelle erstellen (falls benötigt)
|
|
var tableHeader = menuItems[this.menuID].tableHeader;
|
|
if (tableHeader.length > 0) {
|
|
var wrapper = document.createElement("DIV");
|
|
doc.appendChild(wrapper);
|
|
wrapper.setAttribute("id", "box-wrapper");
|
|
var table = this.createTABLE();
|
|
wrapper.appendChild(table);
|
|
var header = this.createTableRow();
|
|
table.appendChild(header);
|
|
// Kopfzeile der Tablle
|
|
tableHeader.forEach(element => {
|
|
var cell = new Cell();
|
|
cell.child = true;
|
|
cell.childType = "P";
|
|
cell.value = element;
|
|
if (element == "BULK") {
|
|
cell.childType = "BULK_HEAD";
|
|
cell.value = false;
|
|
}
|
|
if (menuKey == "mapping") {
|
|
if (element == "Ch. No.") {
|
|
cell.onclick = true;
|
|
cell.onclickFunktion = "javascript: sortTable(1);";
|
|
cell.tdClassName = "sortThis";
|
|
}
|
|
if (element == "Channel Name") {
|
|
cell.onclick = true;
|
|
cell.onclickFunktion = "javascript: sortTable(3);";
|
|
}
|
|
if (element == "Playlist") {
|
|
cell.onclick = true;
|
|
cell.onclickFunktion = "javascript: sortTable(4);";
|
|
}
|
|
if (element == "Group Title") {
|
|
cell.onclick = true;
|
|
cell.onclickFunktion = "javascript: sortTable(5);";
|
|
}
|
|
}
|
|
header.appendChild(cell.createCell());
|
|
});
|
|
table.appendChild(header);
|
|
// Inhalt der Tabelle
|
|
var rows = this.createTableContent(menuKey);
|
|
rows.forEach(tr => {
|
|
table.appendChild(tr);
|
|
});
|
|
}
|
|
switch (menuKey) {
|
|
case "mapping":
|
|
sortTable(1);
|
|
break;
|
|
case "filter":
|
|
showPreview(true);
|
|
sortTable(0);
|
|
break;
|
|
default:
|
|
COLUMN_TO_SORT = -1;
|
|
sortTable(0);
|
|
break;
|
|
}
|
|
showElement("loading", false);
|
|
}
|
|
}
|
|
var SHELL_LAYOUT_READY = false;
|
|
function setLayoutMenuState(open) {
|
|
if (document.body == null) {
|
|
return;
|
|
}
|
|
if (open == true) {
|
|
document.body.classList.add("menu-open");
|
|
}
|
|
else {
|
|
document.body.classList.remove("menu-open");
|
|
}
|
|
}
|
|
function toggleLayoutMenu() {
|
|
if (document.body == null) {
|
|
return;
|
|
}
|
|
var isOpen = document.body.classList.contains("menu-open");
|
|
setLayoutMenuState(!isOpen);
|
|
}
|
|
function closeLayoutMenuIfMobile() {
|
|
if (window.innerWidth <= 900) {
|
|
setLayoutMenuState(false);
|
|
}
|
|
}
|
|
function setActiveMenu(menuID) {
|
|
ACTIVE_MENU_ID = menuID.toString();
|
|
var menu = document.getElementById("main-menu");
|
|
if (menu == null) {
|
|
return;
|
|
}
|
|
var items = menu.getElementsByTagName("LI");
|
|
for (var i = 0; i < items.length; i++) {
|
|
items[i].classList.remove("menu-active");
|
|
}
|
|
var activeItem = document.getElementById(ACTIVE_MENU_ID);
|
|
var activeMenuKey = "";
|
|
if (activeItem != null) {
|
|
activeItem.classList.add("menu-active");
|
|
var menuKeyValue = activeItem.getAttribute("data-menu");
|
|
if (menuKeyValue != null) {
|
|
activeMenuKey = menuKeyValue;
|
|
}
|
|
}
|
|
if (document.body != null) {
|
|
if (activeMenuKey.length > 0) {
|
|
document.body.setAttribute("data-active-menu", activeMenuKey);
|
|
}
|
|
else {
|
|
document.body.removeAttribute("data-active-menu");
|
|
}
|
|
if (activeMenuKey == "log") {
|
|
document.body.classList.add("menu-log-focus");
|
|
}
|
|
else {
|
|
document.body.classList.remove("menu-log-focus");
|
|
}
|
|
}
|
|
}
|
|
function renderStatusCards() {
|
|
var wrapper = document.getElementById("status-cards");
|
|
if (wrapper == null || SERVER.hasOwnProperty("clientInfo") == false) {
|
|
return;
|
|
}
|
|
var info = SERVER["clientInfo"];
|
|
var errors = parseInt(info["errors"], 10);
|
|
var warnings = parseInt(info["warnings"], 10);
|
|
var cards = [
|
|
{ label: "Streams", value: info["streams"], tone: "ok" },
|
|
{ label: "EPG Source", value: info["epgSource"], tone: "neutral" },
|
|
{ label: "XEPG Channels", value: info["xepg"], tone: "ok" },
|
|
{ label: "Errors", value: info["errors"], tone: errors > 0 ? "error" : "ok" },
|
|
{ label: "Warnings", value: info["warnings"], tone: warnings > 0 ? "warn" : "ok" },
|
|
{ label: "DVR", value: info["DVR"], tone: "neutral" },
|
|
];
|
|
wrapper.innerHTML = "";
|
|
cards.forEach(card => {
|
|
var box = document.createElement("DIV");
|
|
box.className = "status-card status-card-" + card.tone;
|
|
var label = document.createElement("P");
|
|
label.className = "status-card-label";
|
|
label.innerText = card.label;
|
|
var value = document.createElement("P");
|
|
value.className = "status-card-value";
|
|
if (card.value == undefined || card.value == "") {
|
|
value.innerText = "-";
|
|
}
|
|
else {
|
|
value.innerText = card.value;
|
|
}
|
|
box.appendChild(label);
|
|
box.appendChild(value);
|
|
wrapper.appendChild(box);
|
|
});
|
|
}
|
|
function initShellLayout() {
|
|
if (SHELL_LAYOUT_READY == true) {
|
|
return;
|
|
}
|
|
var toggle = document.getElementById("menu-toggle");
|
|
if (toggle != null) {
|
|
toggle.onclick = function () {
|
|
toggleLayoutMenu();
|
|
};
|
|
}
|
|
var overlay = document.getElementById("layout-overlay");
|
|
if (overlay != null) {
|
|
overlay.onclick = function () {
|
|
setLayoutMenuState(false);
|
|
};
|
|
}
|
|
document.addEventListener("keydown", function (event) {
|
|
if (event.key == "Escape") {
|
|
setLayoutMenuState(false);
|
|
showElement("popup", false);
|
|
return;
|
|
}
|
|
if (event.key == "/") {
|
|
var target = event.target;
|
|
var onInput = target.tagName == "INPUT" || target.tagName == "TEXTAREA" || target.tagName == "SELECT";
|
|
if (onInput == true) {
|
|
return;
|
|
}
|
|
var search = document.getElementById("searchMapping");
|
|
if (search != null) {
|
|
event.preventDefault();
|
|
search.focus();
|
|
}
|
|
}
|
|
});
|
|
setConnectionState("idle");
|
|
SHELL_LAYOUT_READY = true;
|
|
}
|
|
function shouldPollLogs() {
|
|
if (document.hidden == true) {
|
|
return false;
|
|
}
|
|
if (document.getElementById("content_log") == null) {
|
|
return false;
|
|
}
|
|
if (ACTIVE_MENU_ID.length < 1) {
|
|
return false;
|
|
}
|
|
var activeItem = document.getElementById(ACTIVE_MENU_ID);
|
|
if (activeItem == null) {
|
|
return false;
|
|
}
|
|
return activeItem.getAttribute("data-menu") == "log";
|
|
}
|
|
function PageReady() {
|
|
initShellLayout();
|
|
var server = new Server("getServerConfig");
|
|
server.request(new Object());
|
|
var bootstrapAttempts = 0;
|
|
var maxBootstrapAttempts = 5;
|
|
var bootstrapTimer = window.setInterval(function () {
|
|
if (SERVER.hasOwnProperty("clientInfo") == true) {
|
|
window.clearInterval(bootstrapTimer);
|
|
return;
|
|
}
|
|
if (SERVER_CONNECTION == true) {
|
|
return;
|
|
}
|
|
bootstrapAttempts++;
|
|
var retryServer = new Server("getServerConfig");
|
|
retryServer.request(new Object());
|
|
if (bootstrapAttempts >= maxBootstrapAttempts) {
|
|
window.clearInterval(bootstrapTimer);
|
|
}
|
|
}, 3000);
|
|
window.addEventListener("resize", function () {
|
|
if (window.innerWidth > 900) {
|
|
setLayoutMenuState(false);
|
|
}
|
|
calculateWrapperHeight();
|
|
}, true);
|
|
setInterval(function () {
|
|
if (shouldPollLogs() == false) {
|
|
return;
|
|
}
|
|
updateLog();
|
|
}, 10000);
|
|
return;
|
|
}
|
|
function isClientInfoHttpURL(value) {
|
|
return /^https?:\/\//i.test(value);
|
|
}
|
|
function setClientInfoValue(key, value) {
|
|
var element = document.getElementById(key);
|
|
if (element == null) {
|
|
return;
|
|
}
|
|
var textValue = "";
|
|
if (value != undefined && value != null) {
|
|
textValue = String(value);
|
|
}
|
|
if ((key == "m3u-url" || key == "xepg-url") && isClientInfoHttpURL(textValue)) {
|
|
element.innerHTML = "";
|
|
var anchor = document.createElement("a");
|
|
anchor.href = textValue;
|
|
anchor.target = "_blank";
|
|
anchor.rel = "noopener noreferrer";
|
|
anchor.textContent = textValue;
|
|
element.appendChild(anchor);
|
|
return;
|
|
}
|
|
element.innerHTML = textValue;
|
|
}
|
|
function createLayout() {
|
|
// Client Info
|
|
var obj = SERVER["clientInfo"];
|
|
var keys = getObjKeys(obj);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
setClientInfoValue(keys[i], obj[keys[i]]);
|
|
}
|
|
renderStatusCards();
|
|
if (!document.getElementById("main-menu")) {
|
|
return;
|
|
}
|
|
// Menü erstellen
|
|
document.getElementById("main-menu").innerHTML = "";
|
|
for (let i = 0; i < menuItems.length; i++) {
|
|
menuItems[i].id = i;
|
|
switch (menuItems[i]["menuKey"]) {
|
|
case "users":
|
|
case "logout":
|
|
if (SERVER["settings"]["authentication.web"] == true) {
|
|
menuItems[i].createItem();
|
|
}
|
|
break;
|
|
case "mapping":
|
|
case "xmltv":
|
|
if (SERVER["clientInfo"]["epgSource"] == "XEPG") {
|
|
menuItems[i].createItem();
|
|
}
|
|
break;
|
|
default:
|
|
menuItems[i].createItem();
|
|
break;
|
|
}
|
|
}
|
|
if (ACTIVE_MENU_ID.length > 0 && document.getElementById(ACTIVE_MENU_ID)) {
|
|
setActiveMenu(ACTIVE_MENU_ID);
|
|
}
|
|
var content = document.getElementById("content");
|
|
var menu = document.getElementById("main-menu");
|
|
if (ACTIVE_MENU_ID.length == 0 && content != null && menu != null) {
|
|
if (content.innerHTML.replace(/\\s/g, "").length == 0) {
|
|
var firstItem = menu.getElementsByTagName("LI")[0];
|
|
if (firstItem != undefined) {
|
|
firstItem.click();
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
function openThisMenu(element) {
|
|
var id = element.id;
|
|
var content = new ShowContent(id);
|
|
setActiveMenu(id);
|
|
content.show();
|
|
closeLayoutMenuIfMobile();
|
|
calculateWrapperHeight();
|
|
return;
|
|
}
|
|
class PopupWindow {
|
|
constructor() {
|
|
this.DocumentID = "popup-custom";
|
|
this.InteractionID = "interaction";
|
|
this.doc = document.getElementById(this.DocumentID);
|
|
}
|
|
createTitle(title) {
|
|
var td = document.createElement("TD");
|
|
td.className = "left";
|
|
td.innerHTML = title + ":";
|
|
return td;
|
|
}
|
|
createContent(element) {
|
|
var td = document.createElement("TD");
|
|
td.appendChild(element);
|
|
return td;
|
|
}
|
|
createInteraction() {
|
|
var div = document.createElement("div");
|
|
div.setAttribute("id", "popup-interaction");
|
|
div.className = "interaction";
|
|
this.doc.appendChild(div);
|
|
}
|
|
}
|
|
class PopupContent extends PopupWindow {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.table = document.createElement("TABLE");
|
|
}
|
|
createHeadline(headline) {
|
|
this.doc.innerHTML = "";
|
|
var element = document.createElement("H3");
|
|
element.innerHTML = headline.toUpperCase();
|
|
this.doc.appendChild(element);
|
|
// Tabelle erstellen
|
|
this.table = document.createElement("TABLE");
|
|
this.doc.appendChild(this.table);
|
|
}
|
|
appendRow(title, element) {
|
|
var tr = document.createElement("TR");
|
|
// Bezeichnung
|
|
if (title.length != 0) {
|
|
tr.appendChild(this.createTitle(title));
|
|
}
|
|
// Content
|
|
tr.appendChild(this.createContent(element));
|
|
this.table.appendChild(tr);
|
|
}
|
|
createInput(type, name, value) {
|
|
var input = document.createElement("INPUT");
|
|
if (value == undefined) {
|
|
value = "";
|
|
}
|
|
input.setAttribute("type", type);
|
|
input.setAttribute("name", name);
|
|
input.setAttribute("value", value);
|
|
return input;
|
|
}
|
|
createCheckbox(name) {
|
|
var input = document.createElement("INPUT");
|
|
input.setAttribute("type", "checkbox");
|
|
input.setAttribute("name", name);
|
|
return input;
|
|
}
|
|
createSelect(text, values, set, dbKey) {
|
|
var select = document.createElement("SELECT");
|
|
select.setAttribute("name", dbKey);
|
|
for (let i = 0; i < text.length; i++) {
|
|
var option = document.createElement("OPTION");
|
|
option.setAttribute("value", values[i]);
|
|
option.innerText = text[i];
|
|
select.appendChild(option);
|
|
}
|
|
if (set != "") {
|
|
select.value = set;
|
|
}
|
|
if (set == undefined) {
|
|
select.value = values[0];
|
|
}
|
|
return select;
|
|
}
|
|
selectOption(select, value) {
|
|
//select.selectedOptions = value
|
|
var s = select;
|
|
s.options[s.selectedIndex].value = value;
|
|
return select;
|
|
}
|
|
description(value) {
|
|
var tr = document.createElement("TR");
|
|
var td = document.createElement("TD");
|
|
var span = document.createElement("PRE");
|
|
span.innerHTML = value;
|
|
tr.appendChild(td);
|
|
tr.appendChild(this.createContent(span));
|
|
this.table.appendChild(tr);
|
|
}
|
|
// Interaktion
|
|
addInteraction(element) {
|
|
var interaction = document.getElementById("popup-interaction");
|
|
interaction.appendChild(element);
|
|
}
|
|
}
|
|
function openPopUp(dataType, element) {
|
|
var data = new Object();
|
|
var id;
|
|
switch (element) {
|
|
case undefined:
|
|
switch (dataType) {
|
|
case "group-title":
|
|
if (id == undefined) {
|
|
id = -1;
|
|
}
|
|
data = getLocalData("filter", id);
|
|
data["type"] = "group-title";
|
|
break;
|
|
case "custom-filter":
|
|
if (id == undefined) {
|
|
id = -1;
|
|
}
|
|
data = getLocalData("filter", id);
|
|
data["type"] = "custom-filter";
|
|
break;
|
|
default:
|
|
data["id.provider"] = "-";
|
|
data["type"] = dataType;
|
|
id = "-";
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
id = element.id;
|
|
data = getLocalData(dataType, id);
|
|
break;
|
|
}
|
|
var content = new PopupContent();
|
|
switch (dataType) {
|
|
case "playlist":
|
|
content.createHeadline("Playlist type");
|
|
// Type
|
|
var text = ["M3U", "HDHomeRun"];
|
|
var values = ["javascript: openPopUp('m3u')", "javascript: openPopUp('hdhr')"];
|
|
var select = content.createSelect(text, values, "", "type");
|
|
select.setAttribute("id", "type");
|
|
select.setAttribute("onchange", 'javascript: changeButtonAction(this, "next", "onclick")'); // changeButtonAction
|
|
content.appendRow("Type", select);
|
|
// Interaktion
|
|
content.createInteraction();
|
|
// Abbrechen
|
|
var input = content.createInput("button", "cancel", "Cancel");
|
|
input.setAttribute("onclick", 'javascript: showElement("popup", false);');
|
|
content.addInteraction(input);
|
|
// Weiter
|
|
var input = content.createInput("button", "next", "Next");
|
|
input.setAttribute("onclick", 'javascript: openPopUp("m3u")');
|
|
input.setAttribute("id", 'next');
|
|
content.addInteraction(input);
|
|
break;
|
|
case "m3u":
|
|
content.createHeadline(dataType);
|
|
// Name
|
|
var dbKey = "name";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Playlist name");
|
|
content.appendRow("Name", input);
|
|
// Beschreibung
|
|
var dbKey = "description";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Description");
|
|
content.appendRow("Description", input);
|
|
// URL
|
|
var dbKey = "file.source";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "File path or URL of the M3U");
|
|
content.appendRow("M3U File", input);
|
|
// Tuner
|
|
if (SERVER["settings"]["buffer"] != "-") {
|
|
var text = new Array();
|
|
var values = new Array();
|
|
for (var i = 1; i <= 100; i++) {
|
|
text.push(i.toString());
|
|
values.push(i.toString());
|
|
}
|
|
var dbKey = "tuner";
|
|
var select = content.createSelect(text, values, data[dbKey], dbKey);
|
|
select.setAttribute("onfocus", "javascript: return;");
|
|
content.appendRow("Tuner / Streams", select);
|
|
}
|
|
else {
|
|
var dbKey = "tuner";
|
|
if (data[dbKey] == undefined) {
|
|
data[dbKey] = 1;
|
|
}
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("readonly", "true");
|
|
input.className = "notAvailable";
|
|
content.appendRow("Tuner / Streams", input);
|
|
}
|
|
content.description("Number of parallel connections that can be established to the provider. <br>Only available with activated buffer.<br>New settings will only be applied after quitting all streams.");
|
|
// Interaktion
|
|
content.createInteraction();
|
|
// Löschen
|
|
if (data["id.provider"] != "-") {
|
|
var input = content.createInput("button", "delete", "Delete");
|
|
input.className = "delete";
|
|
input.setAttribute('onclick', 'javascript: savePopupData("m3u", "' + id + '", true, 0)');
|
|
content.addInteraction(input);
|
|
}
|
|
else {
|
|
var input = content.createInput("button", "back", "Back");
|
|
input.setAttribute("onclick", 'javascript: openPopUp("playlist")');
|
|
content.addInteraction(input);
|
|
}
|
|
// Abbrechen
|
|
var input = content.createInput("button", "cancel", "Cancel");
|
|
input.setAttribute("onclick", 'javascript: showElement("popup", false);');
|
|
content.addInteraction(input);
|
|
// Aktualisieren
|
|
if (data["id.provider"] != "-") {
|
|
var input = content.createInput("button", "update", "Update");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("m3u", "' + id + '", false, 1)');
|
|
content.addInteraction(input);
|
|
}
|
|
// Speichern
|
|
var input = content.createInput("button", "save", "Save");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("m3u", "' + id + '", false, 0)');
|
|
content.addInteraction(input);
|
|
break;
|
|
case "hdhr":
|
|
content.createHeadline(dataType);
|
|
// Name
|
|
var dbKey = "name";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Playlist name");
|
|
content.appendRow("Name", input);
|
|
// Beschreibung
|
|
var dbKey = "description";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Description");
|
|
content.appendRow("Description", input);
|
|
// URL
|
|
var dbKey = "file.source";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "IP address and port (192.168.1.10:5004)");
|
|
content.appendRow("HDHomeRun IP", input);
|
|
// Tuner
|
|
if (SERVER["settings"]["buffer"] != "-") {
|
|
var text = new Array();
|
|
var values = new Array();
|
|
for (var i = 1; i <= 100; i++) {
|
|
text.push(i.toString());
|
|
values.push(i.toString());
|
|
}
|
|
var dbKey = "tuner";
|
|
var select = content.createSelect(text, values, data[dbKey], dbKey);
|
|
select.setAttribute("onfocus", "javascript: return;");
|
|
content.appendRow("Tuner / Streams", select);
|
|
}
|
|
else {
|
|
var dbKey = "tuner";
|
|
if (data[dbKey] == undefined) {
|
|
data[dbKey] = 1;
|
|
}
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("readonly", "true");
|
|
input.className = "notAvailable";
|
|
content.appendRow("Tuner / Streams", input);
|
|
}
|
|
content.description("Number of parallel connections that can be established to the provider. <br>Only available with activated buffer.<br>New settings will only be applied after quitting all streams.");
|
|
// Interaktion
|
|
content.createInteraction();
|
|
// Löschen
|
|
if (data["id.provider"] != "-") {
|
|
var input = content.createInput("button", "delete", "Delete");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("hdhr", "' + id + '", true, 0)');
|
|
input.className = "delete";
|
|
content.addInteraction(input);
|
|
}
|
|
else {
|
|
var input = content.createInput("button", "back", "Back");
|
|
input.setAttribute("onclick", 'javascript: openPopUp("playlist")');
|
|
content.addInteraction(input);
|
|
}
|
|
// Abbrechen
|
|
var input = content.createInput("button", "cancel", "Cancel");
|
|
input.setAttribute("onclick", 'javascript: showElement("popup", false);');
|
|
content.addInteraction(input);
|
|
// Aktualisieren
|
|
if (data["id.provider"] != "-") {
|
|
var input = content.createInput("button", "update", "Update");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("hdhr", "' + id + '", false, 1)');
|
|
content.addInteraction(input);
|
|
}
|
|
// Speichern
|
|
var input = content.createInput("button", "save", "Save");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("hdhr", "' + id + '", false, 0)');
|
|
content.addInteraction(input);
|
|
break;
|
|
case "filter":
|
|
content.createHeadline(dataType);
|
|
// Type
|
|
var dbKey = "type";
|
|
var text = ["M3U: " + "Group Title", "xTeVe: " + "Custom Filter"];
|
|
var values = ["javascript: openPopUp('group-title')", "javascript: openPopUp('custom-filter')"];
|
|
var select = content.createSelect(text, values, "javascript: openPopUp('group-title')", dbKey);
|
|
select.setAttribute("id", id);
|
|
select.setAttribute("onchange", 'javascript: changeButtonAction(this, "next", "onclick");'); // changeButtonAction
|
|
content.appendRow("Type", select);
|
|
// Interaktion
|
|
content.createInteraction();
|
|
// Abbrechen
|
|
var input = content.createInput("button", "cancel", "Cancel");
|
|
input.setAttribute("onclick", 'javascript: showElement("popup", false);');
|
|
content.addInteraction(input);
|
|
// Weiter
|
|
var input = content.createInput("button", "next", "Next");
|
|
input.setAttribute("onclick", 'javascript: openPopUp("group-title")');
|
|
input.setAttribute("id", 'next');
|
|
content.addInteraction(input);
|
|
break;
|
|
case "custom-filter":
|
|
case "group-title":
|
|
switch (dataType) {
|
|
case "custom-filter":
|
|
content.createHeadline("Custom");
|
|
break;
|
|
case "group-title":
|
|
content.createHeadline("Group");
|
|
break;
|
|
}
|
|
// Name
|
|
var dbKey = "name";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Filter name");
|
|
content.appendRow("Filter Name", input);
|
|
// Beschreibung
|
|
var dbKey = "description";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Description");
|
|
content.appendRow("Description", input);
|
|
// Typ
|
|
var dbKey = "type";
|
|
var input = content.createInput("hidden", dbKey, data[dbKey]);
|
|
content.appendRow("", input);
|
|
var filterType = data[dbKey];
|
|
switch (filterType) {
|
|
case "custom-filter":
|
|
// Groß- Kleinschreibung beachten
|
|
var dbKey = "caseSensitive";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
content.appendRow("Case Sensitive", input);
|
|
// Filterregel (Benutzerdefiniert)
|
|
var dbKey = "filter";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Sport {HD} !{ES,IT}");
|
|
content.appendRow("Filter Rule", input);
|
|
break;
|
|
case "group-title":
|
|
//alert(dbKey + " " + filterType)
|
|
// Filter basierend auf den Gruppen in der M3U
|
|
var dbKey = "filter";
|
|
var groupsM3U = getLocalData("m3uGroups", "");
|
|
var text = groupsM3U["text"];
|
|
var values = groupsM3U["value"];
|
|
var select = content.createSelect(text, values, data[dbKey], dbKey);
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
content.appendRow("Group Title", select);
|
|
content.description("Select a M3U group. (Counter)<br>Changing the group title in the M3U invalidates the filter.");
|
|
// Groß- Kleinschreibung beachten
|
|
var dbKey = "caseSensitive";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
content.appendRow("Case Sensitive", input);
|
|
var dbKey = "include";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "FHD,UHD");
|
|
content.appendRow("Include", input);
|
|
content.description("Channel name must include.<br>(Comma separated) Comma means or");
|
|
var dbKey = "exclude";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "ES,IT");
|
|
content.appendRow("Exclude", input);
|
|
content.description("Channel name must not contain.<br>(Comma separated) Comma means or");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// Interaktion
|
|
content.createInteraction();
|
|
// Löschen
|
|
var input = content.createInput("button", "delete", "Delete");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("filter", "' + id + '", true, 0)');
|
|
input.className = "delete";
|
|
content.addInteraction(input);
|
|
// Abbrechen
|
|
var input = content.createInput("button", "cancel", "Cancel");
|
|
input.setAttribute("onclick", 'javascript: showElement("popup", false);');
|
|
content.addInteraction(input);
|
|
// Speichern
|
|
var input = content.createInput("button", "save", "Save");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("filter", "' + id + '", false, 0)');
|
|
content.addInteraction(input);
|
|
break;
|
|
case "xmltv":
|
|
content.createHeadline(dataType);
|
|
// Name
|
|
var dbKey = "name";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Guide name");
|
|
content.appendRow("Name", input);
|
|
// Beschreibung
|
|
var dbKey = "description";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Description");
|
|
content.appendRow("Description", input);
|
|
// URL
|
|
var dbKey = "file.source";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "File path or URL of the XMLTV");
|
|
content.appendRow("XMLTV File", input);
|
|
// Interaktion
|
|
content.createInteraction();
|
|
// Löschen
|
|
if (data["id.provider"] != "-") {
|
|
var input = content.createInput("button", "delete", "Delete");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("xmltv", "' + id + '", true, 0)');
|
|
input.className = "delete";
|
|
content.addInteraction(input);
|
|
}
|
|
// Abbrechen
|
|
var input = content.createInput("button", "cancel", "Cancel");
|
|
input.setAttribute("onclick", 'javascript: showElement("popup", false);');
|
|
content.addInteraction(input);
|
|
// Aktualisieren
|
|
if (data["id.provider"] != "-") {
|
|
var input = content.createInput("button", "update", "Update");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("xmltv", "' + id + '", false, 1)');
|
|
content.addInteraction(input);
|
|
}
|
|
// Speichern
|
|
var input = content.createInput("button", "save", "Save");
|
|
input.setAttribute('onclick', 'javascript: savePopupData("xmltv", "' + id + '", false, 0)');
|
|
content.addInteraction(input);
|
|
break;
|
|
case "users":
|
|
content.createHeadline("Users");
|
|
// Benutzername
|
|
var dbKey = "username";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Username");
|
|
content.appendRow("Username", input);
|
|
// Neues Passwort
|
|
var dbKey = "password";
|
|
var input = content.createInput("password", dbKey, "");
|
|
input.setAttribute("placeholder", "Password");
|
|
content.appendRow("Password", input);
|
|
// Bestätigung
|
|
var dbKey = "confirm";
|
|
var input = content.createInput("password", dbKey, "");
|
|
input.setAttribute("placeholder", "Password confirm");
|
|
content.appendRow("Confirm", input);
|
|
// Berechtigung WEB
|
|
var dbKey = "authentication.web";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
if (data["defaultUser"] == true) {
|
|
input.setAttribute("onclick", "javascript: return false");
|
|
}
|
|
content.appendRow("Web Access", input);
|
|
// Berechtigung PMS
|
|
var dbKey = "authentication.pms";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
content.appendRow("PMS Access", input);
|
|
// Berechtigung M3U
|
|
var dbKey = "authentication.m3u";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
content.appendRow("M3U Access", input);
|
|
// Berechtigung XML
|
|
var dbKey = "authentication.xml";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
content.appendRow("XML Access", input);
|
|
// Berechtigung API
|
|
var dbKey = "authentication.api";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
content.appendRow("API Access", input);
|
|
// Interaktion
|
|
content.createInteraction();
|
|
// Löschen
|
|
if (data["defaultUser"] != true && id != "-") {
|
|
var input = content.createInput("button", "delete", "Delete");
|
|
input.className = "delete";
|
|
input.setAttribute('onclick', 'javascript: savePopupData("' + dataType + '", "' + id + '", true, 0)');
|
|
content.addInteraction(input);
|
|
}
|
|
// Abbrechen
|
|
var input = content.createInput("button", "cancel", "Cancel");
|
|
input.setAttribute("onclick", 'javascript: showElement("popup", false);');
|
|
content.addInteraction(input);
|
|
// Speichern
|
|
var input = content.createInput("button", "save", "Save");
|
|
input.setAttribute("onclick", 'javascript: savePopupData("' + dataType + '", "' + id + '", "false");');
|
|
content.addInteraction(input);
|
|
break;
|
|
case "mapping":
|
|
content.createHeadline("Mapping");
|
|
// Aktiv
|
|
var dbKey = "x-active";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
input.id = "active";
|
|
//input.setAttribute("onchange", "javascript: this.className = 'changed'")
|
|
input.setAttribute("onchange", "javascript: toggleChannelStatus('" + id + "', this)");
|
|
content.appendRow("Active", input);
|
|
// Kanalname
|
|
var dbKey = "x-name";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
if (BULK_EDIT == true) {
|
|
input.style.border = "solid 1px red";
|
|
input.setAttribute("readonly", "true");
|
|
}
|
|
content.appendRow("Channel Name", input);
|
|
content.description(data["name"]);
|
|
// Beschreibung
|
|
var dbKey = "x-description";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("placeholder", "Used by the Dummy as an XML description");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
content.appendRow("Channel Description", input);
|
|
// Aktualisierung des Kanalnamens
|
|
if (data.hasOwnProperty("_uuid.key")) {
|
|
if (data["_uuid.key"] != "") {
|
|
var dbKey = "x-update-channel-name";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
input.checked = data[dbKey];
|
|
content.appendRow("Update Channel Name", input);
|
|
}
|
|
}
|
|
// Logo URL (Kanal)
|
|
var dbKey = "tvg-logo";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
input.setAttribute("id", "channel-icon");
|
|
content.appendRow("Logo URL", input);
|
|
// Aktualisierung des Kanallogos
|
|
var dbKey = "x-update-channel-icon";
|
|
var input = content.createCheckbox(dbKey);
|
|
input.checked = data[dbKey];
|
|
input.setAttribute("id", "update-icon");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'; changeChannelLogo('" + id + "');");
|
|
content.appendRow("Update Channel Logo", input);
|
|
// Erweitern der EPG Kategorie
|
|
var dbKey = "x-category";
|
|
var text = ["-", "Kids (Emby only)", "News", "Movie", "Series", "Sports"];
|
|
var values = ["", "Kids", "News", "Movie", "Series", "Sports"];
|
|
var select = content.createSelect(text, values, data[dbKey], dbKey);
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
content.appendRow("EPG Category", select);
|
|
// M3U Gruppentitel
|
|
var dbKey = "x-group-title";
|
|
var input = content.createInput("text", dbKey, data[dbKey]);
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
content.appendRow("Group Title (xteve.m3u)", input);
|
|
if (data["group-title"] != undefined) {
|
|
content.description(data["group-title"]);
|
|
}
|
|
// XMLTV Datei
|
|
var dbKey = "x-xmltv-file";
|
|
var xmlFile = data[dbKey];
|
|
var xmltv = new XMLTVFile();
|
|
var select = xmltv.getFiles(data[dbKey]);
|
|
select.setAttribute("name", dbKey);
|
|
select.setAttribute("id", "popup-xmltv");
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'; setXmltvChannel('" + id + "',this);");
|
|
content.appendRow("XMLTV File", select);
|
|
var file = data[dbKey];
|
|
// XMLTV Mapping
|
|
var dbKey = "x-mapping";
|
|
var xmltv = new XMLTVFile();
|
|
var select = xmltv.getPrograms(file, data[dbKey]);
|
|
select.setAttribute("name", dbKey);
|
|
select.setAttribute("id", "popup-mapping");
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'; checkXmltvChannel('" + id + "',this,'" + xmlFile + "');");
|
|
sortSelect(select);
|
|
content.appendRow("XMLTV Channel", select);
|
|
// Interaktion
|
|
content.createInteraction();
|
|
// Logo hochladen
|
|
var input = content.createInput("button", "cancel", "Upload Logo");
|
|
input.setAttribute("onclick", 'javascript: uploadLogo();');
|
|
content.addInteraction(input);
|
|
// Abbrechen
|
|
var input = content.createInput("button", "cancel", "Cancel");
|
|
input.setAttribute("onclick", 'javascript: showElement("popup", false);');
|
|
content.addInteraction(input);
|
|
// Fertig
|
|
var ids = new Array();
|
|
ids = getAllSelectedChannels();
|
|
if (ids.length == 0) {
|
|
ids.push(id);
|
|
}
|
|
var input = content.createInput("button", "save", "Done");
|
|
input.setAttribute("onclick", 'javascript: donePopupData("' + dataType + '", "' + ids + '", "false");');
|
|
content.addInteraction(input);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
showPopUpElement('popup-custom');
|
|
}
|
|
class XMLTVFile {
|
|
getFiles(set) {
|
|
var fileIDs = getObjKeys(SERVER["xepg"]["xmltvMap"]);
|
|
var values = new Array("-");
|
|
var text = new Array("-");
|
|
for (let i = 0; i < fileIDs.length; i++) {
|
|
if (fileIDs[i] != "xTeVe Dummy") {
|
|
values.push(getValueFromProviderFile(fileIDs[i], "xmltv", "file.xteve"));
|
|
text.push(getValueFromProviderFile(fileIDs[i], "xmltv", "name"));
|
|
}
|
|
else {
|
|
values.push(fileIDs[i]);
|
|
text.push(fileIDs[i]);
|
|
}
|
|
}
|
|
var select = document.createElement("SELECT");
|
|
for (let i = 0; i < text.length; i++) {
|
|
var option = document.createElement("OPTION");
|
|
option.setAttribute("value", values[i]);
|
|
option.innerText = text[i];
|
|
select.appendChild(option);
|
|
}
|
|
if (set != "") {
|
|
select.value = set;
|
|
}
|
|
return select;
|
|
}
|
|
getPrograms(file, set) {
|
|
//var fileIDs:string[] = getObjKeys(SERVER["xepg"]["xmltvMap"])
|
|
var values = getObjKeys(SERVER["xepg"]["xmltvMap"][file]);
|
|
var text = new Array();
|
|
var displayName;
|
|
for (let i = 0; i < values.length; i++) {
|
|
if (SERVER["xepg"]["xmltvMap"][file][values[i]].hasOwnProperty('display-name') == true) {
|
|
displayName = SERVER["xepg"]["xmltvMap"][file][values[i]]["display-name"];
|
|
}
|
|
else {
|
|
displayName = "-";
|
|
}
|
|
text[i] = displayName + " (" + values[i] + ")";
|
|
}
|
|
text.unshift("-");
|
|
values.unshift("-");
|
|
var select = document.createElement("SELECT");
|
|
for (let i = 0; i < text.length; i++) {
|
|
var option = document.createElement("OPTION");
|
|
option.setAttribute("value", values[i]);
|
|
option.innerText = text[i];
|
|
select.appendChild(option);
|
|
}
|
|
if (set != "") {
|
|
select.value = set;
|
|
}
|
|
if (select.value != set) {
|
|
select.value = "-";
|
|
}
|
|
return select;
|
|
}
|
|
}
|
|
function getValueFromProviderFile(file, fileType, key) {
|
|
if (file == "xTeVe Dummy") {
|
|
return file;
|
|
}
|
|
var fileID;
|
|
var indicator = file.charAt(0);
|
|
switch (indicator) {
|
|
case "M":
|
|
fileType = "m3u";
|
|
fileID = file;
|
|
break;
|
|
case "H":
|
|
fileType = "hdhr";
|
|
fileID = file;
|
|
break;
|
|
case "X":
|
|
fileType = "xmltv";
|
|
fileID = file.substring(0, file.lastIndexOf('.'));
|
|
break;
|
|
}
|
|
if (SERVER["settings"]["files"][fileType].hasOwnProperty(fileID) == true) {
|
|
var data = SERVER["settings"]["files"][fileType][fileID];
|
|
return data[key];
|
|
}
|
|
return;
|
|
}
|
|
function setXmltvChannel(id, element) {
|
|
var xmltv = new XMLTVFile();
|
|
var xmlFile = element.value;
|
|
var tvgId = SERVER["xepg"]["epgMapping"][id]["tvg-id"];
|
|
var td = document.getElementById("popup-mapping").parentElement;
|
|
td.innerHTML = "";
|
|
var select = xmltv.getPrograms(element.value, tvgId);
|
|
select.setAttribute("name", "x-mapping");
|
|
select.setAttribute("id", "popup-mapping");
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'; checkXmltvChannel('" + id + "',this,'" + xmlFile + "');");
|
|
select.className = "changed";
|
|
sortSelect(select);
|
|
td.appendChild(select);
|
|
checkXmltvChannel(id, select, xmlFile);
|
|
}
|
|
function checkXmltvChannel(id, element, xmlFile) {
|
|
var value = element.value;
|
|
var bool;
|
|
var checkbox = document.getElementById('active');
|
|
var channel = SERVER["xepg"]["epgMapping"][id];
|
|
var updateLogo;
|
|
if (value == "-") {
|
|
bool = false;
|
|
}
|
|
else {
|
|
bool = true;
|
|
}
|
|
checkbox.checked = bool;
|
|
checkbox.className = "changed";
|
|
console.log(xmlFile);
|
|
// Kanallogo aktualisieren
|
|
/*
|
|
updateLogo = (document.getElementById("update-icon") as HTMLInputElement).checked
|
|
console.log(updateLogo);
|
|
*/
|
|
if (xmlFile != "xTeVe Dummy" && bool == true) {
|
|
//(document.getElementById("update-icon") as HTMLInputElement).checked = true;
|
|
//(document.getElementById("update-icon") as HTMLInputElement).className = "changed";
|
|
console.log("ID", id);
|
|
changeChannelLogo(id);
|
|
return;
|
|
}
|
|
if (xmlFile == "xTeVe Dummy") {
|
|
document.getElementById("update-icon").checked = false;
|
|
document.getElementById("update-icon").className = "changed";
|
|
}
|
|
return;
|
|
}
|
|
function changeChannelLogo(id) {
|
|
var updateLogo;
|
|
var channel = SERVER["xepg"]["epgMapping"][id];
|
|
var f = document.getElementById("popup-xmltv");
|
|
var xmltvFile = f.options[f.selectedIndex].value;
|
|
var m = document.getElementById("popup-mapping");
|
|
var xMapping = m.options[m.selectedIndex].value;
|
|
var xmltvLogo = SERVER["xepg"]["xmltvMap"][xmltvFile][xMapping]["icon"];
|
|
updateLogo = document.getElementById("update-icon").checked;
|
|
if (updateLogo == true && xmltvFile != "xTeVe Dummy") {
|
|
if (SERVER["xepg"]["xmltvMap"][xmltvFile].hasOwnProperty(xMapping)) {
|
|
var logo = xmltvLogo;
|
|
}
|
|
else {
|
|
logo = channel["tvg-logo"];
|
|
}
|
|
var logoInput = document.getElementById("channel-icon");
|
|
logoInput.value = logo;
|
|
if (BULK_EDIT == false) {
|
|
logoInput.className = "changed";
|
|
}
|
|
}
|
|
}
|
|
function savePopupData(dataType, id, remove, option) {
|
|
if (dataType == "mapping") {
|
|
var data = new Object();
|
|
console.log("Save mapping data");
|
|
cmd = "saveEpgMapping";
|
|
data["epgMapping"] = SERVER["xepg"]["epgMapping"];
|
|
console.log("SEND TO SERVER");
|
|
var server = new Server(cmd);
|
|
server.request(data);
|
|
delete UNDO["epgMapping"];
|
|
return;
|
|
}
|
|
console.log("Save popup data");
|
|
var div = document.getElementById("popup-custom");
|
|
var inputs = div.getElementsByTagName("TABLE")[0].getElementsByTagName("INPUT");
|
|
var selects = div.getElementsByTagName("TABLE")[0].getElementsByTagName("SELECT");
|
|
var input = new Object();
|
|
var confirmMsg;
|
|
for (let i = 0; i < selects.length; i++) {
|
|
var name;
|
|
name = selects[i].name;
|
|
var value = selects[i].value;
|
|
switch (name) {
|
|
case "tuner":
|
|
input[name] = parseInt(value);
|
|
break;
|
|
default:
|
|
input[name] = value;
|
|
break;
|
|
}
|
|
}
|
|
for (let i = 0; i < inputs.length; i++) {
|
|
switch (inputs[i].type) {
|
|
case "checkbox":
|
|
name = inputs[i].name;
|
|
input[name] = inputs[i].checked;
|
|
break;
|
|
case "text":
|
|
case "hidden":
|
|
case "password":
|
|
name = inputs[i].name;
|
|
switch (name) {
|
|
case "tuner":
|
|
input[name] = parseInt(inputs[i].value);
|
|
break;
|
|
default:
|
|
input[name] = inputs[i].value;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
var data = new Object();
|
|
var cmd;
|
|
if (remove == true) {
|
|
input["delete"] = true;
|
|
}
|
|
switch (dataType) {
|
|
case "users":
|
|
confirmMsg = "Delete this user?";
|
|
if (id == "-") {
|
|
cmd = "saveNewUser";
|
|
data["userData"] = input;
|
|
}
|
|
else {
|
|
cmd = "saveUserData";
|
|
var d = new Object();
|
|
d[id] = input;
|
|
data["userData"] = d;
|
|
}
|
|
break;
|
|
case "m3u":
|
|
confirmMsg = "Delete this playlist?";
|
|
switch (option) {
|
|
// Popup: Save
|
|
case 0:
|
|
cmd = "saveFilesM3U";
|
|
break;
|
|
// Popup: Update
|
|
case 1:
|
|
cmd = "updateFileM3U";
|
|
break;
|
|
}
|
|
data["files"] = new Object;
|
|
data["files"][dataType] = new Object;
|
|
data["files"][dataType][id] = input;
|
|
break;
|
|
case "hdhr":
|
|
confirmMsg = "Delete this HDHomeRun tuner?";
|
|
switch (option) {
|
|
// Popup: Save
|
|
case 0:
|
|
cmd = "saveFilesHDHR";
|
|
break;
|
|
// Popup: Update
|
|
case 1:
|
|
cmd = "updateFileHDHR";
|
|
break;
|
|
}
|
|
data["files"] = new Object;
|
|
data["files"][dataType] = new Object;
|
|
data["files"][dataType][id] = input;
|
|
break;
|
|
case "xmltv":
|
|
confirmMsg = "Delete this XMLTV file?";
|
|
switch (option) {
|
|
// Popup: Save
|
|
case 0:
|
|
cmd = "saveFilesXMLTV";
|
|
break;
|
|
// Popup: Update
|
|
case 1:
|
|
cmd = "updateFileXMLTV";
|
|
break;
|
|
}
|
|
data["files"] = new Object;
|
|
data["files"][dataType] = new Object;
|
|
data["files"][dataType][id] = input;
|
|
break;
|
|
case "filter":
|
|
confirmMsg = "Delete this filter?";
|
|
cmd = "saveFilter";
|
|
data["filter"] = new Object;
|
|
data["filter"][id] = input;
|
|
break;
|
|
default:
|
|
console.log(dataType, id);
|
|
return;
|
|
break;
|
|
}
|
|
if (remove == true) {
|
|
if (!confirm(confirmMsg)) {
|
|
showElement("popup", false);
|
|
return;
|
|
}
|
|
}
|
|
console.log("SEND TO SERVER");
|
|
console.log(data);
|
|
var server = new Server(cmd);
|
|
server.request(data);
|
|
}
|
|
function donePopupData(dataType, idsStr) {
|
|
var ids = idsStr.split(',');
|
|
var div = document.getElementById("popup-custom");
|
|
var inputs = div.getElementsByClassName("changed");
|
|
ids.forEach(id => {
|
|
var input = new Object();
|
|
input = SERVER["xepg"]["epgMapping"][id];
|
|
console.log(input);
|
|
for (let i = 0; i < inputs.length; i++) {
|
|
var name;
|
|
var value;
|
|
switch (inputs[i].tagName) {
|
|
case "INPUT":
|
|
switch (inputs[i].type) {
|
|
case "checkbox":
|
|
name = inputs[i].name;
|
|
value = inputs[i].checked;
|
|
input[name] = value;
|
|
break;
|
|
case "text":
|
|
name = inputs[i].name;
|
|
value = inputs[i].value;
|
|
input[name] = value;
|
|
break;
|
|
}
|
|
break;
|
|
case "SELECT":
|
|
name = inputs[i].name;
|
|
value = inputs[i].value;
|
|
input[name] = value;
|
|
break;
|
|
}
|
|
switch (name) {
|
|
case "tvg-logo":
|
|
//(document.getElementById(id).childNodes[2].firstChild as HTMLElement).setAttribute("src", value)
|
|
break;
|
|
case "x-name":
|
|
document.getElementById(id).childNodes[3].firstChild.innerHTML = value;
|
|
break;
|
|
case "x-category":
|
|
document.getElementById(id).childNodes[3].firstChild.className = value;
|
|
break;
|
|
case "x-group-title":
|
|
document.getElementById(id).childNodes[5].firstChild.innerHTML = value;
|
|
break;
|
|
case "x-xmltv-file":
|
|
if (value != "xTeVe Dummy" && value != "-") {
|
|
value = getValueFromProviderFile(value, "xmltv", "name");
|
|
}
|
|
if (value == "-") {
|
|
input["x-active"] = false;
|
|
}
|
|
document.getElementById(id).childNodes[6].firstChild.innerHTML = value;
|
|
break;
|
|
case "x-mapping":
|
|
if (value == "-") {
|
|
input["x-active"] = false;
|
|
}
|
|
document.getElementById(id).childNodes[7].firstChild.innerHTML = value;
|
|
break;
|
|
default:
|
|
}
|
|
createSearchObj();
|
|
searchInMapping();
|
|
}
|
|
if (input["x-active"] == false) {
|
|
document.getElementById(id).className = "notActiveEPG";
|
|
}
|
|
else {
|
|
document.getElementById(id).className = "activeEPG";
|
|
}
|
|
console.log(input["tvg-logo"]);
|
|
document.getElementById(id).childNodes[2].firstChild.setAttribute("src", input["tvg-logo"]);
|
|
});
|
|
showElement("popup", false);
|
|
return;
|
|
}
|
|
function showPreview(element) {
|
|
var div = document.getElementById("myStreamsBox");
|
|
switch (element) {
|
|
case false:
|
|
div.className = "notVisible";
|
|
return;
|
|
break;
|
|
}
|
|
var streams = ["activeStreams", "inactiveStreams"];
|
|
streams.forEach(preview => {
|
|
var table = document.getElementById(preview);
|
|
table.innerHTML = "";
|
|
var obj = SERVER["data"]["StreamPreviewUI"][preview];
|
|
obj.forEach(channel => {
|
|
var tr = document.createElement("TR");
|
|
var tdKey = document.createElement("TD");
|
|
var tdVal = document.createElement("TD");
|
|
tdKey.className = "tdKey";
|
|
tdVal.className = "tdVal";
|
|
switch (preview) {
|
|
case "activeStreams":
|
|
tdKey.innerText = "Channel: (+)";
|
|
break;
|
|
case "inactiveStreams":
|
|
tdKey.innerText = "Channel: (-)";
|
|
break;
|
|
}
|
|
tdVal.innerText = channel;
|
|
tr.appendChild(tdKey);
|
|
tr.appendChild(tdVal);
|
|
table.appendChild(tr);
|
|
});
|
|
});
|
|
showElement("loading", false);
|
|
div.className = "visible";
|
|
return;
|
|
}
|
|
class SettingsCategory {
|
|
constructor() {
|
|
this.DocumentID = "content_settings";
|
|
}
|
|
createCategoryHeadline(value) {
|
|
var element = document.createElement("H4");
|
|
element.innerHTML = value;
|
|
return element;
|
|
}
|
|
createHR() {
|
|
var element = document.createElement("HR");
|
|
return element;
|
|
}
|
|
createSettings(settingsKey) {
|
|
var setting = document.createElement("TR");
|
|
var content = new PopupContent();
|
|
var data = SERVER["settings"][settingsKey];
|
|
switch (settingsKey) {
|
|
// Texteingaben
|
|
case "update":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Schedule for updating (Playlist, XMLTV, Backup)" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "update", data.toString());
|
|
input.setAttribute("placeholder", "0000,1000,2000");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "backup.path":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Location for automatic backups" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "backup.path", data);
|
|
input.setAttribute("placeholder", "/mnt/data/backup/xteve/");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "temp.path":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Location for the temporary files" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "temp.path", data);
|
|
input.setAttribute("placeholder", "/tmp/xteve/");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "user.agent":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "User Agent" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "user.agent", data);
|
|
input.setAttribute("placeholder", "xTeVe");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "plex.url":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Plex Server URL" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "plex.url", data);
|
|
input.setAttribute("placeholder", "http://plex-host:32400");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "plex.token":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Plex API Token" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("password", "plex.token", data);
|
|
input.setAttribute("placeholder", "Plex X-Plex-Token");
|
|
input.setAttribute("autocomplete", "off");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "buffer.timeout":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Timeout for new client connections" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "buffer.timeout", data);
|
|
input.setAttribute("placeholder", "100");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "ffmpeg.path":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "FFmpeg Binary Path" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "ffmpeg.path", data);
|
|
input.setAttribute("placeholder", "/path/to/ffmpeg");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "ffmpeg.options":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "FFmpeg Options" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "ffmpeg.options", data);
|
|
input.setAttribute("placeholder", "Leave blank to set default settings");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "vlc.path":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "VLC / CVLC Binary Path" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "vlc.path", data);
|
|
input.setAttribute("placeholder", "/path/to/cvlc");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "vlc.options":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "VLC / CVLC Options" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "vlc.options", data);
|
|
input.setAttribute("placeholder", "Leave blank to set default settings");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
// Checkboxen
|
|
case "authentication.web":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "WEB Authentication" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "authentication.pms":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "PMS Authentication" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "authentication.m3u":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "M3U Authentication" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "authentication.xml":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "XML Authentication" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "authentication.api":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "API Authentication" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "files.update":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Updates all files at startup" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "cache.images":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Image Caching" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "xepg.replace.missing.images":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Replace missing program images" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "api":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "API Interface" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "use_plexAPI":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Use Plex API Refresh" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createCheckbox(settingsKey);
|
|
input.checked = data;
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
// Select
|
|
case "xepg.missing.epg.mode":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Missing EPG Handling" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var text = ["Strict (deactivate channels)", "Relaxed (keep active / dummy guide)"];
|
|
var values = ["strict", "relaxed"];
|
|
var select = content.createSelect(text, values, data, settingsKey);
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(select);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "tuner":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Number of Tuners" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var text = new Array();
|
|
var values = new Array();
|
|
for (var i = 1; i <= 100; i++) {
|
|
text.push(i);
|
|
values.push(i);
|
|
}
|
|
var select = content.createSelect(text, values, data, settingsKey);
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(select);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "epgSource":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "EPG Source" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var text = ["PMS", "XEPG"];
|
|
var values = ["PMS", "XEPG"];
|
|
var select = content.createSelect(text, values, data, settingsKey);
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(select);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "backup.keep":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Number of backups to keep" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var text = ["5", "10", "20", "30", "40", "50"];
|
|
var values = ["5", "10", "20", "30", "40", "50"];
|
|
var select = content.createSelect(text, values, data, settingsKey);
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(select);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "buffer.size.kb":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Buffer Size" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var text = ["0.5 MB", "1 MB", "2 MB", "3 MB", "4 MB", "5 MB", "6 MB", "7 MB", "8 MB"];
|
|
var values = ["512", "1024", "2048", "3072", "4096", "5120", "6144", "7168", "8192"];
|
|
var select = content.createSelect(text, values, data, settingsKey);
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(select);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "buffer":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "Stream Buffer" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var text = ["No Buffer (Client connects to the streaming server)", "xTeVe: (xTeVe connects to the streaming server)", "FFmpeg: (FFmpeg connects to the streaming server)", "VLC: (VLC connects to the streaming server)"];
|
|
var values = ["-", "xteve", "ffmpeg", "vlc"];
|
|
var select = content.createSelect(text, values, data, settingsKey);
|
|
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(select);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
case "udpxy":
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "UDPxy address" + ":";
|
|
var tdRight = document.createElement("TD");
|
|
var input = content.createInput("text", "udpxy", data);
|
|
input.setAttribute("placeholder", "host:port");
|
|
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
|
tdRight.appendChild(input);
|
|
setting.appendChild(tdLeft);
|
|
setting.appendChild(tdRight);
|
|
break;
|
|
}
|
|
return setting;
|
|
}
|
|
createDescription(settingsKey) {
|
|
var description = document.createElement("TR");
|
|
var text;
|
|
switch (settingsKey) {
|
|
case "authentication.web":
|
|
text = "Access to the web interface only possible with credentials.";
|
|
break;
|
|
case "authentication.m3u":
|
|
text = "Downloading the xteve.m3u file via an HTTP request is only possible with authentication.";
|
|
break;
|
|
case "authentication.pms":
|
|
text = "Plex requests are only possible with authentication. <br><b>Warning!!!</b> After activating this function xTeVe must be delete in the PMS DVR settings and set up again.";
|
|
break;
|
|
case "authentication.xml":
|
|
text = "Downloading the xteve.xml file via an HTTP request is only possible with authentication";
|
|
break;
|
|
case "authentication.api":
|
|
if (SERVER["settings"]["authentication.web"] == true) {
|
|
text = "Access to the API interface is only possible with authentication.";
|
|
}
|
|
break;
|
|
case "backup.keep":
|
|
text = "Number of backups to keep. Older backups are automatically deleted.";
|
|
break;
|
|
case "backup.path":
|
|
text = "Before any update of the provider data by the schedule, xTeVe creates a backup. The path for the automatic backups can be changed. xTeVe requires write permission for this folder.";
|
|
break;
|
|
case "temp.path":
|
|
text = "Location for the buffer files.";
|
|
break;
|
|
case "buffer":
|
|
text = "Functions of the buffer:<br>- The stream is passed from xTeVe, FFmpeg or VLC to Plex, Emby or M3U Player<br>- Small jerking of the streams can be compensated<br>- HLS / M3U8 support<br>- RTP / RTPS support (only FFmpeg or VLC)<br>- Re-streaming<br>- Separate tuner limit for each playlist";
|
|
break;
|
|
case "buffer.size.kb":
|
|
text = "Buffer size in MB.<br>M3U8: If the TS segment smaller then the buffer size, the file size of the segment is used.";
|
|
break;
|
|
case "buffer.timeout":
|
|
text = "The xTeVe buffer waits until new client connections are established. Helpful for fast channel switching. Value in milliseconds.";
|
|
break;
|
|
case "user.agent":
|
|
text = "User Agent for HTTP requests. For every HTTP connection, this value is used for the user agent. Should only be changed if xTeVe is blocked.";
|
|
break;
|
|
case "plex.url":
|
|
text = "Base URL of your Plex server. Example: http://192.168.1.10:32400";
|
|
break;
|
|
case "plex.token":
|
|
text = "Plex token used for authenticated API calls to refresh your DVR guide.";
|
|
break;
|
|
case "ffmpeg.path":
|
|
text = "Path to FFmpeg binary.";
|
|
break;
|
|
case "ffmpeg.options":
|
|
text = "FFmpeg options.<br>Only change if you know what you are doing.<br>Leave blank to set default settings.";
|
|
break;
|
|
case "vlc.path":
|
|
text = "Path to VLC / CVLC binary.";
|
|
break;
|
|
case "vlc.options":
|
|
text = "VLC / CVLC options.<br>Only change if you know what you are doing.<br>Leave blank to set default settings.";
|
|
break;
|
|
case "epgSource":
|
|
text = "PMS:<br>- Use EPG data from Plex or Emby <br><br>XEPG:<br>- Use of one or more XMLTV files<br>- Channel management<br>- M3U / XMLTV export (HTTP link for IPTV apps)";
|
|
break;
|
|
case "tuner":
|
|
text = "Number of parallel connections that can be established to the provider.<br>Available for: Plex, Emby (HDHR), M3U (with active buffer).<br>After a change, xTeVe must be delete in the Plex / Emby DVR settings and set up again.";
|
|
break;
|
|
case "update":
|
|
text = "Time in 24 hour format (0800 = 8:00 am). More times can be entered comma separated. Leave this field empty if no updates are to be carried out.";
|
|
break;
|
|
case "api":
|
|
text = "Via API interface it is possible to send commands to xTeVe. API documentation is <a href='https://github.com/xteve-project/xTeVe-Documentation/blob/master/en/configuration.md#api'>here</a>";
|
|
break;
|
|
case "use_plexAPI":
|
|
text = "When enabled, xTeVe calls Plex directly to refresh DVR guide data after lineup or XEPG updates.";
|
|
break;
|
|
case "files.update":
|
|
text = "Updates all playlists, tuner and XMLTV files at startup.";
|
|
break;
|
|
case "cache.images":
|
|
text = "All images from the XMLTV file are cached, allowing faster rendering of the grid in the client.<br>Downloading the images may take a while and will be done in the background.";
|
|
break;
|
|
case "xepg.replace.missing.images":
|
|
text = "If the poster in the XMLTV program is missing, the channel logo will be used.";
|
|
break;
|
|
case "xepg.missing.epg.mode":
|
|
text = "Strict: channels are deactivated when XMLTV mappings disappear.<br>Relaxed: channels stay active with last-known mappings and fall back to a dummy guide whenever guide data cannot be resolved.";
|
|
break;
|
|
case "udpxy":
|
|
text = "The address of your UDPxy server. If set, and the channel URLs in the m3u is multicast, xTeVe will rewrite it so that it is accessed via the UDPxy service.";
|
|
break;
|
|
default:
|
|
text = "";
|
|
break;
|
|
}
|
|
var tdLeft = document.createElement("TD");
|
|
tdLeft.innerHTML = "";
|
|
var tdRight = document.createElement("TD");
|
|
var pre = document.createElement("PRE");
|
|
pre.innerHTML = text;
|
|
tdRight.appendChild(pre);
|
|
description.appendChild(tdLeft);
|
|
description.appendChild(tdRight);
|
|
return description;
|
|
}
|
|
}
|
|
class SettingsCategoryItem extends SettingsCategory {
|
|
constructor(headline, settingsKeys) {
|
|
super();
|
|
this.headline = headline;
|
|
this.settingsKeys = settingsKeys;
|
|
}
|
|
createCategory() {
|
|
var headline = this.createCategoryHeadline(this.headline);
|
|
var settingsKeys = this.settingsKeys;
|
|
var doc = document.getElementById(this.DocumentID);
|
|
doc.appendChild(headline);
|
|
// Tabelle für die Kategorie erstellen
|
|
var table = document.createElement("TABLE");
|
|
var keys = settingsKeys.split(",");
|
|
keys.forEach(settingsKey => {
|
|
switch (settingsKey) {
|
|
case "authentication.pms":
|
|
case "authentication.m3u":
|
|
case "authentication.xml":
|
|
case "authentication.api":
|
|
if (SERVER["settings"]["authentication.web"] == false) {
|
|
break;
|
|
}
|
|
default:
|
|
var item = this.createSettings(settingsKey);
|
|
var description = this.createDescription(settingsKey);
|
|
table.appendChild(item);
|
|
table.appendChild(description);
|
|
break;
|
|
}
|
|
});
|
|
doc.appendChild(table);
|
|
doc.appendChild(this.createHR());
|
|
}
|
|
}
|
|
function showSettings() {
|
|
console.log("SETTINGS");
|
|
for (let i = 0; i < settingsCategory.length; i++) {
|
|
settingsCategory[i].createCategory();
|
|
}
|
|
}
|
|
function saveSettings() {
|
|
console.log("Save Settings");
|
|
var cmd = "saveSettings";
|
|
var div = document.getElementById("content_settings");
|
|
var settings = div.getElementsByClassName("changed");
|
|
var newSettings = new Object();
|
|
for (let i = 0; i < settings.length; i++) {
|
|
var name;
|
|
var value;
|
|
switch (settings[i].tagName) {
|
|
case "INPUT":
|
|
switch (settings[i].type) {
|
|
case "checkbox":
|
|
name = settings[i].name;
|
|
value = settings[i].checked;
|
|
newSettings[name] = value;
|
|
break;
|
|
case "text":
|
|
name = settings[i].name;
|
|
value = settings[i].value;
|
|
switch (name) {
|
|
case "update":
|
|
value = value.split(",");
|
|
value = value.filter(function (e) { return e; });
|
|
break;
|
|
case "buffer.timeout":
|
|
value = parseFloat(value);
|
|
}
|
|
newSettings[name] = value;
|
|
break;
|
|
}
|
|
break;
|
|
case "SELECT":
|
|
name = settings[i].name;
|
|
value = settings[i].value;
|
|
// Wenn der Wert eine Zahl ist, wird dieser als Zahl gespeichert
|
|
if (isNaN(value)) {
|
|
newSettings[name] = value;
|
|
}
|
|
else {
|
|
newSettings[name] = parseInt(value);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
var data = new Object();
|
|
data["settings"] = newSettings;
|
|
var server = new Server(cmd);
|
|
server.request(data);
|
|
}
|
|
class Log {
|
|
createLog(entry) {
|
|
var element = document.createElement("PRE");
|
|
if (entry.indexOf("WARNING") != -1) {
|
|
element.className = "warningMsg";
|
|
}
|
|
if (entry.indexOf("ERROR") != -1) {
|
|
element.className = "errorMsg";
|
|
}
|
|
if (entry.indexOf("DEBUG") != -1) {
|
|
element.className = "debugMsg";
|
|
}
|
|
element.innerHTML = entry;
|
|
return element;
|
|
}
|
|
}
|
|
function showLogs(bottom) {
|
|
var log = new Log();
|
|
var logs = SERVER["log"]["log"];
|
|
var div = document.getElementById("content_log");
|
|
var wrapper = document.getElementById("box-wrapper");
|
|
var shouldStickToBottom = bottom;
|
|
div.innerHTML = "";
|
|
if (wrapper != null && shouldStickToBottom == false) {
|
|
var distanceToBottom = wrapper.scrollHeight - wrapper.scrollTop - wrapper.clientHeight;
|
|
if (distanceToBottom < 80) {
|
|
shouldStickToBottom = true;
|
|
}
|
|
}
|
|
var keys = getObjKeys(logs);
|
|
keys.forEach(logID => {
|
|
var entry = log.createLog(logs[logID]);
|
|
div.append(entry);
|
|
});
|
|
setTimeout(function () {
|
|
if (shouldStickToBottom == true && wrapper != null) {
|
|
wrapper.scrollTop = wrapper.scrollHeight;
|
|
}
|
|
}, 10);
|
|
}
|
|
function resetLogs() {
|
|
var cmd = "resetLogs";
|
|
var data = new Object();
|
|
var server = new Server(cmd);
|
|
server.request(data);
|
|
}
|
|
var SERVER = new Object();
|
|
var BULK_EDIT = false;
|
|
var COLUMN_TO_SORT;
|
|
var SEARCH_MAPPING = new Object();
|
|
var UNDO = new Object();
|
|
var SERVER_CONNECTION = false;
|
|
var WS_AVAILABLE = false;
|
|
var ACTIVE_MENU_ID = "";
|
|
var LAST_BULK_CHECKBOX = null;
|
|
// Menü
|
|
var menuItems = new Array();
|
|
menuItems.push(new MainMenuItem("playlist", "Playlist", "m3u.png", "Local or remote playlists"));
|
|
//menuItems.push(new MainMenuItem("pmsID", "PMS ID", "number.png", ""))
|
|
menuItems.push(new MainMenuItem("filter", "Filter", "filter.png", "Filter playlist"));
|
|
menuItems.push(new MainMenuItem("xmltv", "XMLTV", "xmltv.png", "Local or remote XMLTV files"));
|
|
menuItems.push(new MainMenuItem("mapping", "Mapping", "mapping.png", "Map playlist channels to EPG channels"));
|
|
menuItems.push(new MainMenuItem("users", "Users", "users.png", "User management"));
|
|
menuItems.push(new MainMenuItem("settings", "Settings", "settings.png", "Settings"));
|
|
menuItems.push(new MainMenuItem("log", "Log", "log.png", "Log"));
|
|
menuItems.push(new MainMenuItem("logout", "Logout", "logout.png", "Logout"));
|
|
// Kategorien für die Einstellungen
|
|
var settingsCategory = new Array();
|
|
settingsCategory.push(new SettingsCategoryItem("General", "tuner,epgSource,api,use_plexAPI,plex.url,plex.token"));
|
|
settingsCategory.push(new SettingsCategoryItem("Files", "update,files.update,temp.path,cache.images,xepg.missing.epg.mode,xepg.replace.missing.images"));
|
|
settingsCategory.push(new SettingsCategoryItem("Streaming", "buffer,udpxy,buffer.size.kb,buffer.timeout,user.agent,ffmpeg.path,ffmpeg.options,vlc.path,vlc.options"));
|
|
settingsCategory.push(new SettingsCategoryItem("Backup", "backup.path,backup.keep"));
|
|
settingsCategory.push(new SettingsCategoryItem("Authentication", "authentication.web,authentication.pms,authentication.m3u,authentication.xml,authentication.api"));
|
|
function showPopUpElement(elm) {
|
|
var allElements = new Array("popup-custom");
|
|
for (var i = 0; i < allElements.length; i++) {
|
|
showElement(allElements[i], false);
|
|
}
|
|
showElement(elm, true);
|
|
setTimeout(function () {
|
|
showElement("popup", true);
|
|
}, 10);
|
|
return;
|
|
}
|
|
function showElement(elmID, type) {
|
|
var cssClass;
|
|
switch (type) {
|
|
case true:
|
|
cssClass = "block";
|
|
break;
|
|
case false:
|
|
cssClass = "none";
|
|
break;
|
|
}
|
|
var element = document.getElementById(elmID);
|
|
if (element == null) {
|
|
return;
|
|
}
|
|
element.className = cssClass;
|
|
}
|
|
function setConnectionState(state, text = "") {
|
|
var label = text;
|
|
if (label == undefined || label.length == 0) {
|
|
switch (state) {
|
|
case "online":
|
|
label = "Connected";
|
|
break;
|
|
case "busy":
|
|
label = "Syncing";
|
|
break;
|
|
case "offline":
|
|
label = "Offline";
|
|
break;
|
|
default:
|
|
label = "Connecting";
|
|
break;
|
|
}
|
|
}
|
|
var indicator = document.getElementById("connection-indicator");
|
|
if (indicator == null) {
|
|
return;
|
|
}
|
|
indicator.className = "status-" + state;
|
|
indicator.innerText = label;
|
|
}
|
|
function changeButtonAction(element, buttonID, attribute) {
|
|
var value = element.options[element.selectedIndex].value;
|
|
document.getElementById(buttonID).setAttribute(attribute, value);
|
|
}
|
|
function getLocalData(dataType, id) {
|
|
var data = new Object();
|
|
switch (dataType) {
|
|
case "m3u":
|
|
data = SERVER["settings"]["files"][dataType][id];
|
|
break;
|
|
case "hdhr":
|
|
data = SERVER["settings"]["files"][dataType][id];
|
|
break;
|
|
case "filter":
|
|
case "custom-filter":
|
|
case "group-title":
|
|
if (id == -1) {
|
|
data["active"] = true;
|
|
data["caseSensitive"] = false;
|
|
data["description"] = "";
|
|
data["exclude"] = "";
|
|
data["filter"] = "";
|
|
data["include"] = "";
|
|
data["name"] = "";
|
|
data["type"] = "group-title";
|
|
SERVER["settings"]["filter"][id] = data;
|
|
}
|
|
data = SERVER["settings"]["filter"][id];
|
|
break;
|
|
case "xmltv":
|
|
data = SERVER["settings"]["files"][dataType][id];
|
|
break;
|
|
case "users":
|
|
data = SERVER["users"][id]["data"];
|
|
break;
|
|
case "mapping":
|
|
data = SERVER["xepg"]["epgMapping"][id];
|
|
break;
|
|
case "m3uGroups":
|
|
data = SERVER["data"]["playlist"]["m3u"]["groups"];
|
|
break;
|
|
}
|
|
return data;
|
|
}
|
|
function getObjKeys(obj) {
|
|
var keys = new Array();
|
|
for (var i in obj) {
|
|
if (obj.hasOwnProperty(i)) {
|
|
keys.push(i);
|
|
}
|
|
}
|
|
return keys;
|
|
}
|
|
function getAllSelectedChannels() {
|
|
var channels = new Array();
|
|
if (BULK_EDIT == false) {
|
|
return channels;
|
|
}
|
|
var trs = document.getElementById("content_table").getElementsByTagName("TR");
|
|
for (var i = 1; i < trs.length; i++) {
|
|
if (trs[i].style.display != "none") {
|
|
if (trs[i].firstChild.firstChild.checked == true) {
|
|
channels.push(trs[i].id);
|
|
}
|
|
}
|
|
}
|
|
return channels;
|
|
}
|
|
function scheduleChannelRangeSelection(checkbox, event) {
|
|
var shiftPressed = false;
|
|
if (event != undefined && event.shiftKey == true) {
|
|
shiftPressed = true;
|
|
}
|
|
// Run after the native checkbox toggle so we copy the final checked state.
|
|
setTimeout(function () {
|
|
selectChannelRange(checkbox, shiftPressed);
|
|
}, 0);
|
|
}
|
|
function selectChannelRange(checkbox, shiftPressed) {
|
|
if (BULK_EDIT == false || checkbox == undefined || checkbox == null) {
|
|
return;
|
|
}
|
|
var table = document.getElementById("content_table");
|
|
if (table == null) {
|
|
return;
|
|
}
|
|
var trs = table.getElementsByTagName("TR");
|
|
var visibleCheckboxes = new Array();
|
|
for (var i = 1; i < trs.length; i++) {
|
|
if (trs[i].style.display != "none") {
|
|
var bulkCheckbox = trs[i].querySelector("input.bulk");
|
|
if (bulkCheckbox != null) {
|
|
visibleCheckboxes.push(bulkCheckbox);
|
|
}
|
|
}
|
|
}
|
|
var currentIndex = visibleCheckboxes.indexOf(checkbox);
|
|
var previousIndex = -1;
|
|
if (LAST_BULK_CHECKBOX != null) {
|
|
previousIndex = visibleCheckboxes.indexOf(LAST_BULK_CHECKBOX);
|
|
}
|
|
if (shiftPressed == true && previousIndex > -1 && currentIndex > -1) {
|
|
var start = Math.min(previousIndex, currentIndex);
|
|
var end = Math.max(previousIndex, currentIndex);
|
|
for (var i = start; i <= end; i++) {
|
|
visibleCheckboxes[i].checked = checkbox.checked;
|
|
}
|
|
}
|
|
LAST_BULK_CHECKBOX = checkbox;
|
|
}
|
|
function selectAllChannels() {
|
|
var bulk = false;
|
|
var trs = document.getElementById("content_table").getElementsByTagName("TR");
|
|
if (trs[0].firstChild.firstChild.checked == true) {
|
|
bulk = true;
|
|
}
|
|
for (var i = 1; i < trs.length; i++) {
|
|
if (trs[i].style.display != "none") {
|
|
switch (bulk) {
|
|
case true:
|
|
trs[i].firstChild.firstChild.checked = true;
|
|
break;
|
|
case false:
|
|
trs[i].firstChild.firstChild.checked = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
LAST_BULK_CHECKBOX = null;
|
|
return;
|
|
}
|
|
function bulkEdit() {
|
|
BULK_EDIT = !BULK_EDIT;
|
|
var className;
|
|
var rows = document.getElementsByClassName("bulk");
|
|
switch (BULK_EDIT) {
|
|
case true:
|
|
className = "bulk showBulk";
|
|
break;
|
|
case false:
|
|
className = "bulk hideBulk";
|
|
break;
|
|
}
|
|
for (var i = 0; i < rows.length; i++) {
|
|
rows[i].className = className;
|
|
rows[i].checked = false;
|
|
}
|
|
LAST_BULK_CHECKBOX = null;
|
|
return;
|
|
}
|
|
function sortTable(column) {
|
|
//console.log(columm);
|
|
if (column == COLUMN_TO_SORT) {
|
|
return;
|
|
}
|
|
var table = document.getElementById("content_table");
|
|
var tableHead = table.getElementsByTagName("TR")[0];
|
|
var tableItems = tableHead.getElementsByTagName("TD");
|
|
var sortObj = new Object();
|
|
var x, xValue;
|
|
var tableHeader;
|
|
var sortByString = false;
|
|
if (column > 0 && COLUMN_TO_SORT > 0) {
|
|
tableItems[COLUMN_TO_SORT].className = "pointer";
|
|
tableItems[column].className = "sortThis";
|
|
}
|
|
COLUMN_TO_SORT = column;
|
|
var rows = table.rows;
|
|
if (rows[1] != undefined) {
|
|
tableHeader = rows[0];
|
|
x = rows[1].getElementsByTagName("TD")[column];
|
|
for (i = 1; i < rows.length; i++) {
|
|
x = rows[i].getElementsByTagName("TD")[column];
|
|
switch (x.childNodes[0].tagName.toLowerCase()) {
|
|
case "input":
|
|
xValue = x.getElementsByTagName("INPUT")[0].value.toLowerCase();
|
|
break;
|
|
case "p":
|
|
xValue = x.getElementsByTagName("P")[0].innerText.toLowerCase();
|
|
break;
|
|
default: console.log(x.childNodes[0].tagName);
|
|
}
|
|
if (xValue == "" || Number.isNaN(xValue)) {
|
|
xValue = i;
|
|
sortObj[i] = rows[i];
|
|
}
|
|
else {
|
|
switch (isNaN(xValue)) {
|
|
case false:
|
|
xValue = parseFloat(xValue);
|
|
sortObj[xValue] = rows[i];
|
|
break;
|
|
case true:
|
|
sortByString = true;
|
|
sortObj[xValue.toLowerCase() + i] = rows[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (table.firstChild) {
|
|
table.removeChild(table.firstChild);
|
|
}
|
|
var sortValues = getObjKeys(sortObj);
|
|
if (sortByString == true) {
|
|
sortValues.sort();
|
|
console.log(sortValues);
|
|
}
|
|
else {
|
|
function sortFloat(a, b) {
|
|
return a - b;
|
|
}
|
|
sortValues.sort(sortFloat);
|
|
}
|
|
table.appendChild(tableHeader);
|
|
for (var i = 0; i < sortValues.length; i++) {
|
|
table.appendChild(sortObj[sortValues[i]]);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
function createSearchObj() {
|
|
SEARCH_MAPPING = new Object();
|
|
var data = SERVER["xepg"]["epgMapping"];
|
|
var channels = getObjKeys(data);
|
|
var channelKeys = ["x-active", "x-channelID", "x-name", "_file.m3u.name", "x-group-title", "x-xmltv-file"];
|
|
channels.forEach(id => {
|
|
channelKeys.forEach(key => {
|
|
if (key == "x-active") {
|
|
switch (data[id][key]) {
|
|
case true:
|
|
SEARCH_MAPPING[id] = "online ";
|
|
break;
|
|
case false:
|
|
SEARCH_MAPPING[id] = "offline ";
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
if (key == "x-xmltv-file") {
|
|
var xmltvFile = getValueFromProviderFile(data[id][key], "xmltv", "name");
|
|
if (xmltvFile != undefined) {
|
|
SEARCH_MAPPING[id] = SEARCH_MAPPING[id] + xmltvFile + " ";
|
|
}
|
|
}
|
|
else {
|
|
SEARCH_MAPPING[id] = SEARCH_MAPPING[id] + data[id][key] + " ";
|
|
}
|
|
}
|
|
});
|
|
});
|
|
return;
|
|
}
|
|
function searchInMapping() {
|
|
var searchValue = document.getElementById("searchMapping").value;
|
|
var trs = document.getElementById("content_table").getElementsByTagName("TR");
|
|
for (var i = 1; i < trs.length; ++i) {
|
|
var id = trs[i].getAttribute("id");
|
|
var element = SEARCH_MAPPING[id];
|
|
switch (element.toLowerCase().includes(searchValue.toLowerCase())) {
|
|
case true:
|
|
document.getElementById(id).style.display = "";
|
|
break;
|
|
case false:
|
|
document.getElementById(id).style.display = "none";
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
function calculateWrapperHeight() {
|
|
var elm = document.getElementById("box-wrapper");
|
|
var content = document.getElementById("content");
|
|
if (elm != null && content != null) {
|
|
var contentTop = content.getBoundingClientRect().top;
|
|
var freeSpace = window.innerHeight - contentTop - 26;
|
|
if (freeSpace < 180) {
|
|
freeSpace = 180;
|
|
}
|
|
elm.style.height = freeSpace + "px";
|
|
}
|
|
return;
|
|
}
|
|
function changeChannelNumber(element) {
|
|
var dbID = element.parentNode.parentNode.id;
|
|
var newNumber = parseFloat(element.value);
|
|
var channelNumbers = [];
|
|
var data = SERVER["xepg"]["epgMapping"];
|
|
var channels = getObjKeys(data);
|
|
if (isNaN(newNumber)) {
|
|
alert("Invalid channel number");
|
|
return;
|
|
}
|
|
channels.forEach(id => {
|
|
var channelNumber = parseFloat(data[id]["x-channelID"]);
|
|
channelNumbers.push(channelNumber);
|
|
});
|
|
for (var i = 0; i < channelNumbers.length; i++) {
|
|
if (channelNumbers.indexOf(newNumber) == -1) {
|
|
break;
|
|
}
|
|
if (Math.floor(newNumber) == newNumber) {
|
|
newNumber = newNumber + 1;
|
|
}
|
|
else {
|
|
newNumber = newNumber + 0.1;
|
|
newNumber.toFixed(1);
|
|
newNumber = Math.round(newNumber * 10) / 10;
|
|
}
|
|
}
|
|
data[dbID]["x-channelID"] = newNumber.toString();
|
|
element.value = newNumber;
|
|
console.log(data[dbID]["x-channelID"]);
|
|
if (COLUMN_TO_SORT == 1) {
|
|
COLUMN_TO_SORT = -1;
|
|
sortTable(1);
|
|
}
|
|
return;
|
|
}
|
|
function backup() {
|
|
var data = new Object();
|
|
console.log("Backup data");
|
|
var cmd = "xteveBackup";
|
|
console.log("SEND TO SERVER");
|
|
console.log(data);
|
|
var server = new Server(cmd);
|
|
server.request(data);
|
|
return;
|
|
}
|
|
function toggleChannelStatus(id) {
|
|
var element;
|
|
var status;
|
|
if (document.getElementById("active")) {
|
|
var checkbox = document.getElementById("active");
|
|
status = (checkbox).checked;
|
|
}
|
|
var ids = getAllSelectedChannels();
|
|
if (ids.length == 0) {
|
|
ids.push(id);
|
|
}
|
|
ids.forEach(id => {
|
|
var channel = SERVER["xepg"]["epgMapping"][id];
|
|
channel["x-active"] = status;
|
|
switch (channel["x-active"]) {
|
|
case true:
|
|
if (channel["x-xmltv-file"] == "-" || channel["x-mapping"] == "-") {
|
|
if (BULK_EDIT == false) {
|
|
alert(channel["x-name"] + ": Missing XMLTV file / channel");
|
|
checkbox.checked = false;
|
|
}
|
|
channel["x-active"] = false;
|
|
}
|
|
break;
|
|
case false:
|
|
// code...
|
|
break;
|
|
}
|
|
if (channel["x-active"] == false) {
|
|
document.getElementById(id).className = "notActiveEPG";
|
|
}
|
|
else {
|
|
document.getElementById(id).className = "activeEPG";
|
|
}
|
|
});
|
|
}
|
|
function restore() {
|
|
if (document.getElementById('upload')) {
|
|
document.getElementById('upload').remove();
|
|
}
|
|
var restore = document.createElement("INPUT");
|
|
restore.setAttribute("type", "file");
|
|
restore.setAttribute("class", "notVisible");
|
|
restore.setAttribute("name", "");
|
|
restore.id = "upload";
|
|
document.body.appendChild(restore);
|
|
restore.click();
|
|
restore.onchange = function () {
|
|
var filename = restore.files[0].name;
|
|
var check = confirm("File: " + filename + "\nAll data will be replaced with those from the backup. Should the files be restored?");
|
|
if (check == true) {
|
|
var reader = new FileReader();
|
|
var file = document.querySelector('input[type=file]').files[0];
|
|
if (file) {
|
|
reader.readAsDataURL(file);
|
|
reader.onload = function () {
|
|
console.log(reader.result);
|
|
var data = new Object();
|
|
var cmd = "xteveRestore";
|
|
data["base64"] = reader.result;
|
|
var server = new Server(cmd);
|
|
server.request(data);
|
|
};
|
|
}
|
|
else {
|
|
alert("File could not be loaded");
|
|
}
|
|
restore.remove();
|
|
return;
|
|
}
|
|
};
|
|
return;
|
|
}
|
|
function uploadLogo() {
|
|
if (document.getElementById('upload')) {
|
|
document.getElementById('upload').remove();
|
|
}
|
|
var upload = document.createElement("INPUT");
|
|
upload.setAttribute("type", "file");
|
|
upload.setAttribute("class", "notVisible");
|
|
upload.setAttribute("name", "");
|
|
upload.id = "upload";
|
|
document.body.appendChild(upload);
|
|
upload.click();
|
|
upload.onblur = function () {
|
|
alert();
|
|
};
|
|
upload.onchange = function () {
|
|
var filename = upload.files[0].name;
|
|
var reader = new FileReader();
|
|
var file = document.querySelector('input[type=file]').files[0];
|
|
if (file) {
|
|
reader.readAsDataURL(file);
|
|
reader.onload = function () {
|
|
console.log(reader.result);
|
|
var data = new Object();
|
|
var cmd = "uploadLogo";
|
|
data["base64"] = reader.result;
|
|
data["filename"] = file.name;
|
|
var server = new Server(cmd);
|
|
server.request(data);
|
|
var updateLogo = document.getElementById('update-icon');
|
|
updateLogo.checked = false;
|
|
updateLogo.className = "changed";
|
|
};
|
|
}
|
|
else {
|
|
alert("File could not be loaded");
|
|
}
|
|
upload.remove();
|
|
return;
|
|
};
|
|
}
|
|
function checkUndo(key) {
|
|
switch (key) {
|
|
case "epgMapping":
|
|
if (UNDO.hasOwnProperty(key)) {
|
|
SERVER["xepg"][key] = JSON.parse(JSON.stringify(UNDO[key]));
|
|
}
|
|
else {
|
|
UNDO[key] = JSON.parse(JSON.stringify(SERVER["xepg"][key]));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
function sortSelect(elem) {
|
|
var tmpAry = [];
|
|
var selectedValue = elem[elem.selectedIndex].value;
|
|
for (var i = 0; i < elem.options.length; i++)
|
|
tmpAry.push(elem.options[i]);
|
|
tmpAry.sort(function (a, b) { return (a.text < b.text) ? -1 : 1; });
|
|
while (elem.options.length > 0)
|
|
elem.options[0] = null;
|
|
var newSelectedIndex = 0;
|
|
for (var i = 0; i < tmpAry.length; i++) {
|
|
elem.options[i] = tmpAry[i];
|
|
if (elem.options[i].value == selectedValue)
|
|
newSelectedIndex = i;
|
|
}
|
|
elem.selectedIndex = newSelectedIndex; // Set new selected index after sorting
|
|
return;
|
|
}
|
|
function updateLog() {
|
|
console.log("TOKEN");
|
|
var server = new Server("updateLog");
|
|
server.request(new Object());
|
|
}
|
|
class WizardCategory {
|
|
constructor() {
|
|
this.DocumentID = "content";
|
|
}
|
|
createCategoryHeadline(value) {
|
|
var element = document.createElement("H4");
|
|
element.innerHTML = value;
|
|
return element;
|
|
}
|
|
}
|
|
class WizardItem extends WizardCategory {
|
|
constructor(key, headline) {
|
|
super();
|
|
this.headline = headline;
|
|
this.key = key;
|
|
}
|
|
createWizard() {
|
|
var headline = this.createCategoryHeadline(this.headline);
|
|
var key = this.key;
|
|
var content = new PopupContent();
|
|
var description;
|
|
var doc = document.getElementById(this.DocumentID);
|
|
doc.innerHTML = "";
|
|
doc.appendChild(headline);
|
|
switch (key) {
|
|
case "tuner":
|
|
var text = new Array();
|
|
var values = new Array();
|
|
for (var i = 1; i <= 100; i++) {
|
|
text.push(i);
|
|
values.push(i);
|
|
}
|
|
var select = content.createSelect(text, values, "1", key);
|
|
select.setAttribute("class", "wizard");
|
|
select.id = key;
|
|
doc.appendChild(select);
|
|
description = "Number of parallel connections that can be established to the provider.<br>Available for: Plex, Emby (HDHR), M3U (with active buffer).<br>After a change, xTeVe must be delete in the Plex / Emby DVR settings and set up again.";
|
|
break;
|
|
case "epgSource":
|
|
var text = ["PMS", "XEPG"];
|
|
var values = ["PMS", "XEPG"];
|
|
var select = content.createSelect(text, values, "XEPG", key);
|
|
select.setAttribute("class", "wizard");
|
|
select.id = key;
|
|
doc.appendChild(select);
|
|
description = "PMS:<br>- Use EPG data from Plex or Emby <br><br>XEPG:<br>- Use of one or more XMLTV files<br>- Channel management<br>- M3U / XMLTV export (HTTP link for IPTV apps)";
|
|
break;
|
|
case "m3u":
|
|
var input = content.createInput("text", key, "");
|
|
input.setAttribute("placeholder", "File path or URL of the M3U");
|
|
input.setAttribute("class", "wizard");
|
|
input.id = key;
|
|
doc.appendChild(input);
|
|
description = "Local or remote playlists";
|
|
break;
|
|
case "xmltv":
|
|
var input = content.createInput("text", key, "");
|
|
input.setAttribute("placeholder", "File path or URL of the XMLTV");
|
|
input.setAttribute("class", "wizard");
|
|
input.id = key;
|
|
doc.appendChild(input);
|
|
description = "Local or remote XMLTV file";
|
|
break;
|
|
default:
|
|
console.log(key);
|
|
break;
|
|
}
|
|
var pre = document.createElement("PRE");
|
|
pre.innerHTML = description;
|
|
doc.appendChild(pre);
|
|
console.log(headline, key);
|
|
}
|
|
}
|
|
function readyForConfiguration(wizard) {
|
|
var server = new Server("getServerConfig");
|
|
server.request(new Object());
|
|
showElement("loading", false);
|
|
configurationWizard[wizard].createWizard();
|
|
}
|
|
function saveWizard() {
|
|
var cmd = "saveWizard";
|
|
var div = document.getElementById("content");
|
|
var config = div.getElementsByClassName("wizard");
|
|
var wizard = new Object();
|
|
for (var i = 0; i < config.length; i++) {
|
|
var name;
|
|
var value;
|
|
switch (config[i].tagName) {
|
|
case "SELECT":
|
|
name = config[i].name;
|
|
value = config[i].value;
|
|
// Wenn der Wert eine Zahl ist, wird dieser als Zahl gespeichert
|
|
if (isNaN(value)) {
|
|
wizard[name] = value;
|
|
}
|
|
else {
|
|
wizard[name] = parseInt(value);
|
|
}
|
|
break;
|
|
case "INPUT":
|
|
switch (config[i].type) {
|
|
case "text":
|
|
name = config[i].name;
|
|
value = config[i].value;
|
|
if (value.length == 0) {
|
|
var msg = name.toUpperCase() + ": " + "Missing input";
|
|
alert(msg);
|
|
return;
|
|
}
|
|
wizard[name] = value;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
// code...
|
|
break;
|
|
}
|
|
}
|
|
var data = new Object();
|
|
data["wizard"] = wizard;
|
|
var server = new Server(cmd);
|
|
server.request(data);
|
|
console.log(data);
|
|
}
|
|
// Wizard
|
|
var configurationWizard = new Array();
|
|
configurationWizard.push(new WizardItem("tuner", "Number of tuners"));
|
|
configurationWizard.push(new WizardItem("epgSource", "EPG Source"));
|
|
configurationWizard.push(new WizardItem("m3u", "M3U Playlist"));
|
|
configurationWizard.push(new WizardItem("xmltv", "XMLTV File"));
|
|
function login() {
|
|
var err = false;
|
|
var data = new Object();
|
|
var div = document.getElementById("content");
|
|
var form = document.getElementById("authentication");
|
|
var inputs = div.getElementsByTagName("INPUT");
|
|
console.log(inputs);
|
|
for (var i = inputs.length - 1; i >= 0; i--) {
|
|
var key = inputs[i].name;
|
|
var value = inputs[i].value;
|
|
if (value.length == 0) {
|
|
inputs[i].style.borderColor = "red";
|
|
err = true;
|
|
}
|
|
else {
|
|
inputs[i].style.borderColor = "";
|
|
}
|
|
data[key] = value;
|
|
}
|
|
if (err == true) {
|
|
data = new Object();
|
|
return;
|
|
}
|
|
if (data.hasOwnProperty("confirm")) {
|
|
if (data["confirm"] != data["password"]) {
|
|
document.getElementById('password').style.borderColor = "red";
|
|
document.getElementById('confirm').style.borderColor = "red";
|
|
document.getElementById("err").innerHTML = "Password does not match";
|
|
return;
|
|
}
|
|
}
|
|
console.log(data);
|
|
form.submit();
|
|
}
|