Phase 3: embed web UI with go:embed, pinned TypeScript toolchain, drop i18n, add /healthz
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.
This commit is contained in:
2026-09-26 12:46:45 +10:00
parent 51c7830067
commit ddc70e170a
47 changed files with 2208 additions and 7373 deletions
+1 -5
View File
@@ -6,11 +6,7 @@
<title>xTeVe</title>
<link rel="stylesheet" href="css/screen.css" type="text/css">
<link rel="stylesheet" href="css/base.css" type="text/css">
<script language="javascript" type="text/javascript" src="js/configuration_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/network_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/menu_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/settings_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/base_ts.js"></script>
<script src="js/app.js"></script>
</head>
<body class="auth-screen wizard-screen" onload="javascript: readyForConfiguration(0);">
+6 -7
View File
@@ -6,8 +6,7 @@
<title>xTeVe</title>
<link rel="stylesheet" href="css/screen.css" type="text/css">
<link rel="stylesheet" href="css/base.css" type="text/css">
<script language="javascript" type="text/javascript" src="js/network_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/authentication_ts.js"></script>
<script src="js/app.js"></script>
</head>
<body class="auth-screen">
@@ -17,7 +16,7 @@
<main id="box" role="main" aria-labelledby="head-text">
<div id="headline">
<h1 id="head-text" class="center">{{.account.headline}}</h1>
<h1 id="head-text" class="center">Create user account</h1>
</div>
<p id="err" class="errorMsg center" role="alert" aria-live="assertive" aria-atomic="true"></p>
@@ -26,11 +25,11 @@
<form id="authentication" action="" method="post" aria-describedby="err" novalidate>
<label for="username">{{.account.username.title}}:</label>
<label for="username">Username:</label>
<input id="username" type="text" name="username" placeholder="Username" value="" autocomplete="username">
<label for="password">{{.account.password.title}}:</label>
<label for="password">Password:</label>
<input id="password" type="password" name="password" placeholder="Password" value="" autocomplete="new-password">
<label for="confirm">{{.account.confirm.title}}:</label>
<label for="confirm">Confirm:</label>
<input id="confirm" type="password" name="confirm" placeholder="Confirm" value="" autocomplete="new-password">
</form>
@@ -38,7 +37,7 @@
</div>
<div id="box-footer">
<input id="submit" class="" type="button" value="{{.button.craeteAccount}}" aria-label="{{.button.craeteAccount}}" onclick="javascript: login();">
<input id="submit" class="" type="button" value="Create Account" aria-label="Create Account" onclick="javascript: login();">
</div>
+13
View File
@@ -0,0 +1,13 @@
// Package webui embeds the static web interface (HTML, CSS, the compiled
// JavaScript bundle, images and the tuner-limit video) into the binary.
//
// Build the JavaScript bundle with `npm run build` (see README-DEV.md); the
// result, html/js/app.js, is committed so `go build` works from a bare clone.
package webui
import "embed"
// FS holds the web interface files, rooted at the html/ directory.
//
//go:embed *.html css img js video
var FS embed.FS
+1 -6
View File
@@ -6,12 +6,7 @@
<title>xTeVe</title>
<link rel="stylesheet" href="css/screen.css" type="text/css">
<link rel="stylesheet" href="css/base.css" type="text/css">
<script language="javascript" type="text/javascript" src="js/network_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/menu_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/settings_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/logs_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/base_ts.js"></script>
<script src="js/app.js"></script>
</head>
File diff suppressed because it is too large Load Diff
-42
View File
@@ -1,42 +0,0 @@
function createFirstAccount(elm) {
var err = false;
var div = document.getElementById(elm);
console.log(div);
var form = document.getElementById('authentication');
const username = document.getElementById('username');
const password = document.getElementById('password');
const confirm = document.getElementById('confirm');
var inputs = div.getElementsByTagName('INPUT')
console.log(confirm);
switch(confirm) {
case null: break;
default:
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].value.length == 0) {
inputs[i].style.borderColor = 'red';
err = true
}
}
switch(err) {
case true: return; break;
case false:
if (password.value != confirm.value) {
confirm.style.borderColor = 'red';
return;
}
break;
}
}
form.submit();
return;
}
-68
View File
@@ -1,68 +0,0 @@
function login() {
var err = false;
var firstInvalid = null;
var data = new Object();
var div = document.getElementById("content");
var form = document.getElementById("authentication");
var errElement = document.getElementById("err");
if (errElement != null) {
errElement.innerHTML = "";
}
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";
inputs[i].setAttribute("aria-invalid", "true");
if (firstInvalid == null) {
firstInvalid = inputs[i];
}
err = true;
}
else {
inputs[i].style.borderColor = "";
inputs[i].setAttribute("aria-invalid", "false");
}
data[key] = value;
}
if (err == true) {
if (firstInvalid != null) {
firstInvalid.focus();
}
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('password').setAttribute("aria-invalid", "true");
document.getElementById('confirm').setAttribute("aria-invalid", "true");
document.getElementById("err").innerHTML = "{{.account.failed}}";
document.getElementById('password').focus();
return;
}
}
console.log(data);
form.submit();
}
document.addEventListener("DOMContentLoaded", function () {
var form = document.getElementById("authentication");
if (form == null) {
return;
}
var inputs = form.getElementsByTagName("INPUT");
for (var i = 0; i < inputs.length; i++) {
inputs[i].addEventListener("keydown", function (event) {
if (event.key == "Enter") {
event.preventDefault();
login();
}
});
}
if (inputs.length > 0) {
inputs[0].focus();
}
});
-331
View File
@@ -1,331 +0,0 @@
var config = new Object();
var menu = new Object();
var subMenu = new Object();
var activeStreams = new Object();
var xEPG = new Object();
var users = new Object();
var log = new Object();
var undo = new Object();
var webSockets = true;
var closeLog, version, activeMenu;
var columnToSort = 0
if (window.WebSocket === undefined) {
alert("Your browser does not support WebSockets");
webSockets = false;
}
function pageReady() {
var data = new Object();
data["cmd"] = "getServerConfig";
xTeVe(data);
//showLoadingScreen(false);
var resizeHandle = document.getElementById("openStreams");
var box = document.getElementById("myStreamsBox");
resizeHandle.addEventListener("mousedown", initialiseResize, false);
function initialiseResize(e) {
window.addEventListener("mousemove", startResizing, false);
window.addEventListener("mouseup", stopResizing, false);
}
function startResizing(e) {
box.style.height = (e.clientY - box.offsetTop) + "px";
var elm = document.getElementById("allStreams");
if (e.clientY > 120) {
elm.className = "visible";
} else {
elm.className = "notVisible";
}
calculateWrapperHeight();
}
function stopResizing(e) {
window.removeEventListener('mousemove', startResizing, false);
window.removeEventListener('mouseup', stopResizing, false);
calculateWrapperHeight();
}
window.addEventListener("resize", function(){
calculateWrapperHeight();
}, true);
}
function getObjKeys(obj) {
var keys = new Array();
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
keys.push(i);
}
}
return keys;
}
function createElement(item) {
//console.log(item);
var element = document.createElement(item["_element"]);
if (item.hasOwnProperty("_text")) {
//element.innerHTML = "<p>" + item["_text"] + "</p>";
element.innerHTML = item["_text"];
}
var keys = getObjKeys(item);
for (var i = 0; i < keys.length; i++) {
if (keys[i].charAt(0) != "_") {
//console.log(keys[i], item[keys[i]]);
element.setAttribute(keys[i], item[keys[i]]);
}
}
//console.log(element);
return element;
}
function modifyOption(id, options, values) {
var select = document.getElementById(id);
select.innerHTML = "";
for (var i = 0; i < options.length; i++) {
var element = document.createElement("OPTION")
element.value = values[i];
element.innerHTML = options[i];
document.getElementById(id).appendChild(element);
}
}
function startWebSocket() {
if (webSockets == false) {
return;
}
//ws.send('{"cmd": "getServerConfig1"}');
}
function checkErr(obj) {
//alert(obj["err"])
//screenLog(obj["err"], "error")
console.log(obj);
var newObj = new Object();
var newErr = new Object();
newErr["key"] = "Error";
newErr["value"] = obj["err"];
newErr["type"] = "error";
newObj[0] = newErr
showLog(newObj);
return
}
function screenLog(msg, msgType, show) {
return
clearTimeout(closeLog)
var div = document.getElementById("screenLog");
var newMsg = new Object();
newMsg["_element"] = "P";
switch(msgType) {
case "error": newMsg["class"] = "errorMsg"; break;
case "warning": newMsg["class"] = "warningMsg"; break;
//default: newMsg["class"] = "infoMsg"
}
newMsg["_text"] = msg;
div.appendChild(createElement(newMsg));
div.scrollTop = div.scrollHeight;
if (show == false) {
return;
}
div.className = ""
closeLog = setTimeout(closeScreenLog, 10000);
}
function closeScreenLog() {
var div = document.getElementById("screenLog");
div.className = "screenLogHidden"
}
function showScreenLog() {
clearTimeout(closeLog)
var div = document.getElementById("screenLog");
var currentClass = div.className;
div.className = "screenLogHidden"
switch(currentClass) {
case "screenLogHidden": div.className = ""; break;
case "": div.className = "screenLogHidden"; break;
}
}
function showLoadingScreen(elm) {
var div = document.getElementById("loading");
switch(elm) {
case true: div.className = "block"; break;
case false: div.className = "none"; break;
/*
case true: div.style.display = "block"; break;
case false: div.style.display = "none"; break;
*/
}
}
function createClintInfo(obj) {
//console.log(obj);
var keys = getObjKeys(obj);
for (var i = 0; i < keys.length; i++) {
if(document.getElementById(keys[i])){
document.getElementById(keys[i]).innerHTML = obj[keys[i]];
}
}
//document.getElementById("clientInfo").className = "visible";
}
function showElement(elmID, type) {
switch(type) {
case true: cssClass = "block"; break;
case false: cssClass = "none"; break;
}
document.getElementById(elmID).className = cssClass;
}
function showPopUpElement(elm) {
var allElements = new Array("deleteUserDetail", "mapping-detail", "user-detail", "file-detail");
for (var i = 0; i < allElements.length; i++) {
showElement(allElements[i], false)
}
showElement(elm, true)
setTimeout(function(){
showElement("popup", true);
}, 10);
}
// body...
function showStreams(force) {
var elmBox = document.getElementById("myStreamsBox");
var elm = document.getElementById("allStreams");
//console.log(elm);
show = elm.className;
switch(force) {
case true: show = "notVisible"; break;
case false: show = "visible"; break;
}
switch(show) {
case "notVisible":
elm.className = "visible";
elmBox.style.height = "100px";
break;
default:
elm.className = "notVisible";
elmBox.style.height = "20px";
break;
}
var show = elm.style.display; {
//console.log(elm.style.display);
}
calculateWrapperHeight();
}
function xteveBackup() {
console.log("xteveBackup");
var data = new Object();
data["cmd"] = "xteveBackup";
xTeVe(data);
}
function xteveRestore(elm) {
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
//console.log(restore.srcElement.files[0]);
var check = confirm("File: " + filename + "\nAll data will be replaced with those from the backup.\nShould 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();
data["cmd"] = "xteveRestore"
data["base64"] = reader.result
xTeVe(data);
return
};
} else {
alert("File could not be loaded")
}
}
};
}
function getBase64(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function() {
console.log(reader.result);
};
reader.onerror = function(error) {
console.log('Error: ', error);
};
}
function logout() {
document.cookie.split(';').forEach(function(c) {
document.cookie = c.trim().split('=')[0] + '=;' + 'expires=Thu, 01 Jan 1970 00:00:00 UTC;';
});
location.reload();
}
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
function setCookie(token) {
//console.log(token);
document.cookie = "Token=" + token
}
-615
View File
@@ -1,615 +0,0 @@
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_FOCUSED_ELEMENT = null;
var LAST_BULK_CHECKBOX = null;
// Menu
var menuItems = new Array();
menuItems.push(new MainMenuItem("playlist", "{{.mainMenu.item.playlist}}", "m3u.png", "{{.mainMenu.headline.playlist}}"));
//menuItems.push(new MainMenuItem("pmsID", "{{.mainMenu.item.pmsID}}", "number.png", "{{.mainMenu.headline.pmsID}}"))
menuItems.push(new MainMenuItem("filter", "{{.mainMenu.item.filter}}", "filter.png", "{{.mainMenu.headline.filter}}"));
menuItems.push(new MainMenuItem("xmltv", "{{.mainMenu.item.xmltv}}", "xmltv.png", "{{.mainMenu.headline.xmltv}}"));
menuItems.push(new MainMenuItem("mapping", "{{.mainMenu.item.mapping}}", "mapping.png", "{{.mainMenu.headline.mapping}}"));
menuItems.push(new MainMenuItem("users", "{{.mainMenu.item.users}}", "users.png", "{{.mainMenu.headline.users}}"));
menuItems.push(new MainMenuItem("settings", "{{.mainMenu.item.settings}}", "settings.png", "{{.mainMenu.headline.settings}}"));
menuItems.push(new MainMenuItem("log", "{{.mainMenu.item.log}}", "log.png", "{{.mainMenu.headline.log}}"));
menuItems.push(new MainMenuItem("logout", "{{.mainMenu.item.logout}}", "logout.png", "{{.mainMenu.headline.logout}}"));
// Kategorien für die Einstellungen
var settingsCategory = new Array();
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.general}}", "tuner,epgSource,api,use_plexAPI,plex.url,plex.token"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.files}}", "update,files.update,temp.path,cache.images,xepg.missing.epg.mode,xepg.replace.missing.images"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.streaming}}", "buffer,udpxy,buffer.size.kb,buffer.timeout,user.agent,ffmpeg.path,ffmpeg.options,vlc.path,vlc.options"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.backup}}", "backup.path,backup.keep"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.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;
element.setAttribute("aria-hidden", type == true ? "false" : "true");
if (elmID == "loading" && document.body != null) {
document.body.setAttribute("aria-busy", type == true ? "true" : "false");
}
if (elmID == "popup") {
var popupContent_1 = document.getElementById("popup-custom");
if (type == true) {
LAST_FOCUSED_ELEMENT = document.activeElement;
if (popupContent_1 != null) {
setTimeout(function () {
popupContent_1.focus();
}, 20);
}
}
else {
if (LAST_FOCUSED_ELEMENT != null && LAST_FOCUSED_ELEMENT.focus != undefined) {
setTimeout(function () {
LAST_FOCUSED_ELEMENT.focus();
}, 20);
}
LAST_FOCUSED_ELEMENT = null;
}
}
}
function announceToScreenReader(message) {
if (message == undefined || message.length == 0) {
return;
}
var region = document.getElementById("sr-announcer");
if (region == null) {
return;
}
region.innerText = "";
setTimeout(function () {
region.innerText = message;
}, 20);
}
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;
indicator.setAttribute("aria-label", "Connection status: " + label);
announceToScreenReader("Connection status " + 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");
for (var h = 0; h < tableItems.length; h++) {
if (tableItems[h].getAttribute("role") == "columnheader") {
tableItems[h].setAttribute("aria-sort", "none");
}
}
var sortObj = new Object();
var x, xValue;
var tableHeader;
var sortByString = false;
if (column > 0 && COLUMN_TO_SORT > 0) {
tableItems[COLUMN_TO_SORT].classList.remove("sortThis");
tableItems[COLUMN_TO_SORT].classList.add("pointer");
tableItems[column].classList.remove("pointer");
tableItems[column].classList.add("sortThis");
}
COLUMN_TO_SORT = column;
var mobileSort = document.getElementById("mapping-sort-mobile");
if (mobileSort != null && (column == 1 || column == 3 || column == 4 || column == 5)) {
mobileSort.value = column.toString();
}
if (tableItems[column] != undefined && tableItems[column].getAttribute("role") == "columnheader") {
tableItems[column].setAttribute("aria-sort", "ascending");
}
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 == "" || xValue == NaN) {
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(function (id) {
SEARCH_MAPPING[id] = "";
channelKeys.forEach(function (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];
if (element == undefined) {
continue;
}
switch (element.toLowerCase().includes(searchValue.toLowerCase())) {
case true:
document.getElementById(id).style.display = "";
break;
case false:
document.getElementById(id).style.display = "none";
break;
}
}
announceToScreenReader("Search updated");
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("{{.alert.invalidChannelNumber}}");
return;
}
channels.forEach(function (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(function (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 + "\n{{.confirm.restore}}");
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());
}
-40
View File
@@ -1,40 +0,0 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var MainMenu = /** @class */ (function () {
function MainMenu() {
this.DocumentID = "main-menu";
this.HTMLTag = "LI";
}
MainMenu.prototype.create = function () {
console.log(this.DocumentID);
};
return MainMenu;
}());
var MainMenuItem = /** @class */ (function (_super) {
__extends(MainMenuItem, _super);
function MainMenuItem() {
return _super !== null && _super.apply(this, arguments) || this;
}
MainMenuItem.prototype.create2 = function () {
var element = document.createElement(this.HTMLTag);
element.innerText = this.Value;
console.log(element);
};
return MainMenuItem;
}(MainMenu));
function pageReady() {
var item = new MainMenuItem();
item.Value = "Test";
item.create2();
}
-294
View File
@@ -1,294 +0,0 @@
var configMenu = new Object();
var wizard = new Array("key", "tuner", "epgSource", "m3u", "complete");
var activeWizard;
var dvrIP
var configMenu_tuner = new Object();
configMenu_tuner["_element"] = "SELECT";
configMenu_tuner["_menuType"] = "singleInput";
configMenu_tuner["_configKey"] = "tuner";
configMenu_tuner["_label"] = "Available tuners";
configMenu_tuner["name"] = "tuner";
configMenu_tuner["id"] = "Tuner";
configMenu_tuner["placeholder"] = "Tuner";
configMenu_tuner["_usage"] = "This setting is only used by Plex and Emby.<br>The number of concurrent streams allowed by the IPTV provider."
var optionValues = new Array();
for (var i = 1; i <= 100; i++) {
optionValues.push(i)
}
configMenu_tuner["_optionValues"] = optionValues;
var configMenu_epg = new Object();
configMenu_epg["_element"] = "SELECT";
configMenu_epg["_menuType"] = "singleInput";
configMenu_epg["_configKey"] = "epgSource";
configMenu_epg["_label"] = "Selection of the EPG source";
configMenu_epg["name"] = "epgSource";
configMenu_epg["id"] = "EPG source";
configMenu_epg["placeholder"] = "EPG source";
configMenu_epg["_optionValues"] = new Array("PMS", "XEPG");
configMenu_epg["_usage"] = "PMS: Use EPG data from Plex or Emby<br>XEPG: Use of external EPG data (XMLTV)<br> Several XMLTV sources possible<br> Allows editing and order channels<br> M3U / XMLTV export (HTTP link for IPTV apps)"
var configMenu_m3u = new Object();
configMenu_m3u["_element"] = "INPUT";
configMenu_m3u["_menuType"] = "inputArray";
configMenu_m3u["_configKey"] = "file";
configMenu_m3u["_label"] = "M3U File: local or remote";
configMenu_m3u["name"] = "file";
configMenu_m3u["id"] = "m3u";
configMenu_m3u["type"] = "text";
configMenu_m3u["placeholder"] = "M3U File";
configMenu_m3u["_usage"] = "Remote playlist: http://your.provider.com/file.m3u<br>Local playlist: /path/to/file.m3u"
configMenu_m3u["value"] = "http://websrv.local:8080/kabel.m3u";
var configMenu_complete = new Object();
configMenu_complete["_element"] = "H2";
configMenu_complete["_menuType"] = "inputArray";
configMenu_complete["_configKey"] = "file";
configMenu_complete["_text"] = "xTeVe was successfully set up";
configMenu_complete["name"] = "complete";
configMenu_complete["id"] = "complete";
configMenu_complete["type"] = "text";
configMenu_complete["class"] = "center";
configMenu["tuner"] = configMenu_tuner;
configMenu["epgSource"] = configMenu_epg;
configMenu["m3u"] = configMenu_m3u;
configMenu["complete"] = configMenu_complete;
function readyForConfiguration() {
var data = new Object();
data["cmd"] = "getServerConfig";
xTeVe(data);
showLoadingScreen(false);
}
function createConfiguration(elm) {
activeWizard = elm;
var item = configMenu[elm];
var div = document.getElementById("content");
div.innerHTML = "";
div.setAttribute("data-configKey", item["_configKey"]);
div.setAttribute("data-menuType", item["_menuType"]);
switch(item.hasOwnProperty("_label")) {
case true:
var newItem = new Object();
newItem["_element"] = "LABEL";
newItem["_text"] = item["_label"];
newItem["for"] = item["id"];
div.appendChild(createElement(newItem));
break
}
switch(item["_element"]) {
case "SELECT":
div.appendChild(createElement(item));
var selectElement = div.getElementsByTagName("SELECT")[0];
var values = item["_optionValues"];
for (var i = 0; i < values.length; i++) {
var newEntry = new Object;
newEntry["_element"] = "OPTION";
newEntry["_text"] = item["id"] + ": " + values[i];
newEntry["value"] = values[i];
selectElement.appendChild(createElement(newEntry));
}
//return
break;
default:
div.appendChild(createElement(item));
break;
}
//alert()
switch(item.hasOwnProperty("_usage")) {
case true:
var usageItem = new Object();
usageItem["_element"] = "PRE"
usageItem["_text"] = item["_usage"];
div.appendChild(createElement(usageItem));
}
if (activeWizard == "complete") {
document.getElementById("next").value = "Finished"
//document.getElementById("next").setAttribute("onclick", "javascript: location.reload();")
}
//div.appendChild(createElement(item));
}
function saveData() {
var div = document.getElementById("content");
var inputs = div.getElementsByTagName("INPUT");
var selects = div.getElementsByTagName("SELECT");
var value;
var data = new Object();
var valueArr = new Array();
var newData = false;
if (activeWizard == "complete") {
data["cmd"] = "wizardCompleted";
showLoadingScreen(true)
xTeVe(data);
return
}
for (var i = 0; i < inputs.length; i++) {
var menuType = inputs[i].parentElement.getAttribute("data-menutype");
if (inputs[i].value != undefined && inputs[i].value != "" ) {
newData = true;
console.log(inputs[i].id)
switch(inputs[i].id) {
case "m3u":
var newPlaylist = new Object();
newPlaylist["file.source"] = inputs[i].value;
//newPlaylist["name"] = inputs[i].value;
newPlaylist["type"] = "m3u";
newPlaylist["new"] = true;
data["files"] = new Object();
data["files"]["m3u"] = new Object();
data["files"]["m3u"]["-"] = newPlaylist;
data["cmd"] = "saveFilesM3U";
xTeVe(data)
return
}
/*
switch(menuType) {
case "singleInput":
data[inputs[i].name] = inputs[i].value; break;
case "inputArray":
valueArr.push(inputs[i].value);
data[inputs[i].name] = valueArr; break
}
*/
} else {
inputs[i].style.borderBottomColor = "red";
return;
}
}
for (var i = 0; i < selects.length; i++) {
var value = selects[i].options[selects[i].selectedIndex].value;
if (isNaN(value) == false) {
value = parseInt(value);
data[selects[i].name] = value;
newData = true;
break;
}
data[selects[i].name] = value;
newData = true;
}
//console.log(data, newData);
if (newData == true) {
config = data
data["cmd"] = "saveConfig";
xTeVe(data);
}
}
function xTeVe(data) {
if (webSockets == false) {
alert("Your browser does not support WebSockets");
return;
}
if (activeWizard == "m3u" || activeWizard == "epgSource") {
showLoadingScreen(true);
}
var protocolWS
switch(window.location.protocol) {
case "http:": protocolWS = "ws://"; break;
case "https:": protocolWS = "wss://"; break;
}
var ws = new WebSocket(protocolWS + window.location.hostname + ":" + window.location.port + "/data/" + "?Token=" + getCookie("Token"));
ws.onopen = function() {
ws.send(JSON.stringify(data));
}
ws.onmessage = function (e) {
var response = JSON.parse(e.data);
if (response.hasOwnProperty("clientInfo")) {
createClintInfo(response["clientInfo"]);
}
if (response.hasOwnProperty("status")) {
if (response["status"] == false) {
document.getElementById("headline").style.borderColor = "red";
showErr(response["err"]);
showLoadingScreen(false)
return
} else {
document.getElementById("err").innerHTML = "";
document.getElementById("headline").style.borderColor = "lawngreen";
}
dvrIP = response["DVR"]
switch(response["configurationWizard"]) {
case true:
if (activeWizard == undefined) {
activeWizard = wizard[0]
}
var n = wizard.indexOf(activeWizard);
n++;
activeWizard = wizard[n]
if (activeWizard == undefined) {
data["cmd"] = "wizardCompleted";
xTeVe(data)
} else {
//console.log(activeWizard);
createConfiguration(activeWizard);
}
break;
}
switch(response["reload"]) {
case true:
setTimeout(function(){
location.reload();
}, 100);
//location.reload();
break;
}
}
setTimeout(function(){ showLoadingScreen(false); }, 300);
}
}
function showErr(elm) {
document.getElementById("err").innerHTML = elm;
}
-182
View File
@@ -1,182 +0,0 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var WizardCategory = /** @class */ (function () {
function WizardCategory() {
this.DocumentID = "content";
}
WizardCategory.prototype.createCategoryHeadline = function (value) {
var element = document.createElement("H4");
element.innerHTML = value;
return element;
};
return WizardCategory;
}());
var WizardItem = /** @class */ (function (_super) {
__extends(WizardItem, _super);
function WizardItem(key, headline) {
var _this = _super.call(this) || this;
_this.headline = headline;
_this.key = key;
return _this;
}
WizardItem.prototype.createWizard = function () {
var headline = this.createCategoryHeadline(this.headline);
var key = this.key;
var content = new PopupContent();
var description;
var wizardField = null;
var doc = document.getElementById(this.DocumentID);
doc.setAttribute("aria-busy", "true");
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);
wizardField = select;
description = "{{.wizard.tuner.description}}";
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);
wizardField = select;
description = "{{.wizard.epgSource.description}}";
break;
case "m3u":
var input = content.createInput("text", key, "");
input.setAttribute("placeholder", "{{.wizard.m3u.placeholder}}");
input.setAttribute("class", "wizard");
input.id = key;
doc.appendChild(input);
wizardField = input;
description = "{{.wizard.m3u.description}}";
break;
case "xmltv":
var input = content.createInput("text", key, "");
input.setAttribute("placeholder", "{{.wizard.xmltv.placeholder}}");
input.setAttribute("class", "wizard");
input.id = key;
doc.appendChild(input);
wizardField = input;
description = "{{.wizard.xmltv.description}}";
break;
default:
console.log(key);
break;
}
var pre = document.createElement("PRE");
pre.id = "wizard-description-" + key;
pre.innerHTML = description;
doc.appendChild(pre);
if (wizardField != null) {
wizardField.setAttribute("aria-label", this.headline);
wizardField.setAttribute("aria-describedby", pre.id);
setTimeout(function () {
wizardField.focus();
}, 20);
}
doc.setAttribute("aria-busy", "false");
if (typeof announceToScreenReader == "function") {
announceToScreenReader(this.headline + " step");
}
console.log(headline, key);
};
return WizardItem;
}(WizardCategory));
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() + ": " + "{{.alert.missingInput}}";
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", "{{.wizard.tuner.title}}"));
configurationWizard.push(new WizardItem("epgSource", "{{.wizard.epgSource.title}}"));
configurationWizard.push(new WizardItem("m3u", "{{.wizard.m3u.title}}"));
configurationWizard.push(new WizardItem("xmltv", "{{.wizard.xmltv.title}}"));
document.addEventListener("DOMContentLoaded", function () {
var container = document.getElementById("content");
if (container == null) {
return;
}
container.addEventListener("keydown", function (event) {
if (event.key != "Enter") {
return;
}
var target = event.target;
if (target == null || target.tagName != "INPUT") {
return;
}
event.preventDefault();
saveWizard();
});
});
-329
View File
@@ -1,329 +0,0 @@
function showConfig(obj) {
config = obj;
//setMenuItem();
createMenu();
//document.getElementById("page").className = "";
}
showMyStreams
function showMyStreams(allStreamsObj) {
var streamTypeKeys = getObjKeys(allStreamsObj)
for (var s = 0; s < streamTypeKeys.length; s++) {
var streamType = streamTypeKeys[s];
var obj = new Object();
obj = allStreamsObj[streamType];
switch(streamType) {
case "activeStreams": activeStreams = obj; break;
}
document.getElementById(streamType).innerHTML = "";
var streamsObj = new Object();
var streamsNames = new Array();
var keys = getObjKeys(obj)
// Create Object (streamsObj) for the streams and sort by name (streamsNames)
for (var i = 0; i < keys.length; i++) {
var name = obj[keys[i]]["name"];
var tmp = new Object();
var streamKey = getObjKeys(obj[keys[i]]);
for (var j = 0; j < streamKey.length; j++) {
tmp[streamKey[j]] = obj[keys[i]][streamKey[j]];
}
streamsObj[name] = tmp;
streamsNames.push(name)
}
streamsNames.sort();
// Create Table for activeStreams
var table = document.getElementById(streamType);
for (var i = 0; i < streamsNames.length; i++) {
var newEntry = new Object();
newEntry["_element"] = "TR";
table.appendChild(createElement(newEntry));
var line = table.lastChild;
var tmp = streamsObj[streamsNames[i]]
var keys = getObjKeys(tmp)
var newKey = new Object()
newKey["_element"] = "TD";
//newKey["_text"] = streamsNames[i];
switch(streamType) {
case "activeStreams": newKey["_text"] = "Channel (+):"; break;
case "inactiveStreams": newKey["_text"] = "Channel (-):"; break;
}
newKey["class"] = "tdKey";
console.log();
var newVal = new Object()
newVal["_element"] = "TD";
newVal["_text"] = streamsNames[i];
newVal["class"] = "tdVal";
//newVal["_text"] = value;
line.appendChild(createElement(newKey));
line.appendChild(createElement(newVal));
}
}
return
}
function showActiveStreams(obj) {
document.getElementById("activeStreams").innerHTML = "";
activeStreams = obj;
var streamsObj = new Object();
var streamsNames = new Array();
var keys = getObjKeys(obj)
// Create Object (streamsObj) for the streams and sort by name (streamsNames)
for (var i = 0; i < keys.length; i++) {
var name = obj[keys[i]]["name"];
var tmp = new Object();
var streamKey = getObjKeys(obj[keys[i]]);
for (var j = 0; j < streamKey.length; j++) {
tmp[streamKey[j]] = obj[keys[i]][streamKey[j]];
}
streamsObj[name] = tmp;
streamsNames.push(name)
}
streamsNames.sort();
// Create Table for activeStreams
var table = document.getElementById("activeStreams");
for (var i = 0; i < streamsNames.length; i++) {
var newEntry = new Object();
newEntry["_element"] = "TR";
table.appendChild(createElement(newEntry));
var line = table.lastChild;
var tmp = streamsObj[streamsNames[i]]
var keys = getObjKeys(tmp)
var newKey = new Object()
newKey["_element"] = "TD";
//newKey["_text"] = streamsNames[i];
newKey["_text"] = "Channel:";
newKey["class"] = "tdKey";
console.log();
var newVal = new Object()
newVal["_element"] = "TD";
newVal["_text"] = streamsNames[i];
newVal["class"] = "tdVal";
//newVal["_text"] = value;
line.appendChild(createElement(newKey));
line.appendChild(createElement(newVal));
}
}
function parseLogs(obj) {
log = obj
var keys = getObjKeys(obj)
var msgType;
for (var i = 0; i < keys.length; i++) {
switch(keys[i]) {
case "warnings": msgType = "warningMsg"; break;
case "errors": msgType = "errorMsg"; break;
}
switch(obj[keys[i]]) {
case 0: msgType = "tdVal"; break;
default: break;
}
if(document.getElementById(keys[i])){
document.getElementById(keys[i]).className = msgType;
}
}
return
}
function cancelData(element) {
createMenu();
}
function saveData(element) {
var data = new Object();
var div = element.parentNode.parentNode;
var inputs = div.getElementsByTagName("INPUT");
var configKey = div.getAttribute("data-configkey");
var menuType = div.getAttribute("data-menutype");
var value;
var valueArr = new Array();
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type == "text" && inputs[i].value != undefined && inputs[i].value != "" ) {
console.log(inputs[i].value, menuType)
switch(menuType) {
case "inputArray": valueArr.push(inputs[i].value); break;
case "singleInput": value = inputs[i].value; break;
}
}
}
switch(menuType) {
case "inputArray": data[configKey] = valueArr; break;
case "singleInput":
if (isNaN(value) == false) {
value = parseInt(value);
data[configKey] = value;
break;
}
if (value == undefined) {
data["delete"] = configKey;
} else {
data[configKey] = value
}
break;
}
data["cmd"] = "saveConfig";
console.log(data);
xTeVe(data)
}
function xTeVe(data) {
if (webSockets == false) {
alert("Your browser does not support WebSockets");
return;
} else {
if (data["cmd"] != "getLog") {
showLoadingScreen(true)
}
}
delete undo["epgMapping"];
var protocolWS
switch(window.location.protocol) {
case "http:": protocolWS = "ws://"; break;
case "https:": protocolWS = "wss://"; break;
}
var ws = new WebSocket(protocolWS + window.location.hostname + ":" + window.location.port + "/data/" + "?Token=" + getCookie("Token"));
ws.onopen = function() {
console.log(data)
ws.send(JSON.stringify(data));
}
ws.onmessage = function (e) {
var response = JSON.parse(e.data);
console.log(response);
if (response.hasOwnProperty("clientInfo")) {
createClintInfo(response["clientInfo"]);
}
if (response.hasOwnProperty("log")) {
createClintInfo(response["log"]);
}
if (response.hasOwnProperty("status")) {
if (response["status"] == false) {
alert(response["err"])
if(response.hasOwnProperty("reload")) {
location.reload();
}
//checkErr(response)
console.log(response);
updateXteveStatus(response);
setTimeout(function(){ showLoadingScreen(false); }, 300);
return
}
updateXteveStatus(response)
//console.log(data["cmd"]);
switch(data["cmd"]) {
case "saveUserData": createMenu(); break;
case "saveNewUser": createMenu(); break;
case "saveFilesXMLTV": //createMenu(); break;
case "saveFilesM3U": //createMenu(); return; break;
case "saveConfig":
data = new Object();
data["cmd"] = "checkToken";
xTeVe(data);
break;
case "emptyLog": writeLogInDiv(); break;
case "getLog": return; break;
}
}
if (config["files"] == undefined || config["files"].length == 0) {
createMenu();
document.getElementById(10).click()
}
setTimeout(function(){ showLoadingScreen(false); }, 0);
}
}
function updateXteveStatus(response) {
var keys = getObjKeys(response);
//console.log(keys);
for (var i = 0; i < keys.length; i++) {
switch(keys[i]) {
case "alert": alert(response[keys[i]]); break;
case "config": showConfig(response[keys[i]]); break;
case "log": parseLogs(response[keys[i]]); break;
case "myStreams": showMyStreams(response[keys[i]]); break;
case "xEPG": xEPG = response[keys[i]]; break;
case "users": users = response[keys[i]]; break;
case "token": document.cookie = "Token=" + response[keys[i]]; break;
case "reload": location.reload(); break;
case "openLink": window.location = response["openLink"]; break;
//case "version": version = response[keys[i]]; break;
}
}
}
function getValueFromProviderFile(xXmltvFile, fileType, key) {
var fileID = xXmltvFile.substring(0, xXmltvFile.lastIndexOf('.'))
if (config["files"][fileType].hasOwnProperty(fileID) == true) {
var data = config["files"][fileType][fileID];
return data[key]
}
}
-379
View File
@@ -1,379 +0,0 @@
function openFiles(elm, fileType) {
//document.getElementById("settings").innerHTML = "Test";
columnToSort = 0;
var newDiv = document.getElementById("settings");
var newEntry = new Object();
newEntry["_element"] = "HR";
newDiv.appendChild(createElement(newEntry));
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "button";
newEntry["class"] = "button";
newEntry["value"] = "New";
newEntry["onclick"] = 'fileDetail("-", "' + fileType + '")';
newDiv.appendChild(createElement(newEntry));
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "button";
newEntry["class"] = "button";
newEntry["value"] = "Update";
newEntry["onclick"] = "fileDetail(0)";
//newDiv.appendChild(createElement(newEntry));
var div = document.getElementById("settings");
// Build table
var newTable = new Object();
newTable["_element"] = "TABLE";
newTable["id"] = "id_mapping";
newTable["class"] = "table-mapping";
div.appendChild(createElement(newTable));
setTimeout(function(){
createFilesTable(fileType);
}, 10);
}
function createFilesTable(fileType) {
var table = document.getElementById("id_mapping");
var availableFileTypes = new Array();
table.innerHTML = "";
var newTR = new Object();
newTR["_element"] = "TR";
newTR["class"] = "table-mapping-header";
table.appendChild(createElement(newTR));
var tr = table.lastChild;
switch(fileType) {
case "xmltv":
availableFileTypes = new Array("xmltv");
var trHeadlines = new Array("Guide", "Last Update", "Availability %", "Channels", "Programs")
var compatibilityKeys = new Array("xmltv.channels", "xmltv.programs")
break;
case "m3u":
availableFileTypes = new Array("m3u", "hdhr");
var trHeadlines = new Array("Playlist", "Last Update", "Availability %", "Type", "Streams", "group-title %", "tvg-id %", "Unique ID %");
var compatibilityKeys = new Array("streams", "group.title", "tvg.id", "stream.id");
break;
}
for (var i = 0; i < trHeadlines.length; i++) {
var newTD = new Object();
newTD["_element"] = "TD";
newTD["_text"] = trHeadlines[i];
tr.appendChild(createElement(newTD));
}
for (var i = 0; i < availableFileTypes.length; i++) {
var fileType = availableFileTypes[i]
var data = config["files"][fileType];
var allFiles = getObjKeys(data)
for (var f = 0; f < allFiles.length; f++) {
var elm = data[allFiles[f]];
var table = document.getElementById("id_mapping");
var fileID = elm["id.provider"];
var name = elm["name"];
var lastUpdate = elm["last.update"];
var availability = elm["provider.availability"];
var type = elm["type"].toUpperCase();
var compatibility = elm["compatibility"];
// Create TR
var newTR = new Object();
newTR["_element"] = "TR";
newTR["class"] = "";
newTR["id"] = fileID;
newTR["onclick"] = 'javascript: fileDetail("' + fileID + '","' + fileType + '");';
table.appendChild(createElement(newTR));
var tr = table.lastChild;
// Create file name TD
var newTD = new Object();
newTD["_element"] = "P";
newTD["_text"] = name;
createNewTD(newTD, tr);
// Create last update TD
var newTD = new Object();
newTD["_element"] = "P";
newTD["_text"] = lastUpdate;
createNewTD(newTD, tr);
// Create availability TD
var newTD = new Object();
newTD["_element"] = "P";
newTD["_text"] = availability;
createNewTD(newTD, tr);
if (fileType == "m3u" || fileType == "hdhr") {
// Create Type TD
var newTD = new Object();
newTD["_element"] = "P";
newTD["_text"] = type;
createNewTD(newTD, tr);
}
// Create all compatibility TDs
for (var j = 0; j < compatibilityKeys.length; j++) {
var newTD = new Object();
newTD["_element"] = "P";
newTD["_text"] = compatibility[compatibilityKeys[j]];
createNewTD(newTD, tr);
}
}
}
sortTable(0)
// usage Info
var div = document.getElementById("settings");
switch(menu[activeMenu.id].hasOwnProperty("_usage")) {
case true:
var usageItem = new Object();
usageItem["_element"] = "PRE"
usageItem["_text"] = menu[activeMenu.id]["_usage"];
var newHR = new Object();
newHR["_element"] = "HR"
div.appendChild(createElement(newHR));
div.appendChild(createElement(usageItem));
break;
}
calculateWrapperHeight();
return;
}
function fileDetail(fileID, fileType) {
optionsText = new Array("M3U", "HDHomeRun - [Experimental]")
optionsValue = new Array("m3u", "hdhr")
switch (fileType) {
case "m3u":
document.getElementById("name").setAttribute("placeholder", "Playlist name");
document.getElementById("description").setAttribute("placeholder", "Description of this playlist");
document.getElementById("file-detail-headline").innerHTML = "M3U Playlist";
document.getElementById("file-path").innerHTML = "M3U File:";
document.getElementById("file.source").setAttribute("placeholder", "Local or remote");
break;
case "hdhr":
document.getElementById("name").setAttribute("placeholder", "HDHomeRun name");
document.getElementById("description").setAttribute("placeholder", "Description of this HDHomeRun tuner");
document.getElementById("file-detail-headline").innerHTML = "HDHomeRun";
document.getElementById("file-path").innerHTML = "HDHomeRun IP:";
document.getElementById("file.source").setAttribute("placeholder", "IP address and port of the tuner (192.168.1.10:5004)");
break;
case "xmltv":
document.getElementById("name").setAttribute("placeholder", "XMLTV name");
document.getElementById("description").setAttribute("placeholder", "Description of this XMLTV file");
document.getElementById("file-detail-headline").innerHTML = "XMLTV File";
document.getElementById("file-path").innerHTML = "XMLTV File:";
document.getElementById("file.source").setAttribute("placeholder", "Local or remote");
optionsText = new Array("XMLTV")
optionsValue = new Array("xmltv")
break;
}
modifyOption("type", optionsText, optionsValue)
showPopUpElement('file-detail');
document.getElementById("saveFileDetail").setAttribute("onclick", 'javascript: saveFileDetail("' + fileID + '","' + fileType + '", false)');
document.getElementById("updateFileDetail").setAttribute("onclick", 'javascript: updateFile("' + fileID + '","' + fileType + '", false)');
document.getElementById("deleteFileDetail").setAttribute("onclick", 'javascript: saveFileDetail("' + fileID + '","' + fileType + '", true)');
var data = new Object();
switch(fileID) {
case "-": // New file
data["name"] = "";
data["description"] = "";
data["file.source"] = "";
data["type"] = fileType;
document.getElementById("deleteFileDetail").className = "delete";
document.getElementById("type").setAttribute("onchange", "changeFileType(this);")
document.getElementById("type").setAttribute("data-id", fileID)
showElement("deleteFileDetail", false);
showElement("updateFileDetail", false);
if (fileType == "xmltv") {
showElement("type", false);
showElement("file-type", false);
} else {
showElement("type", true);
showElement("file-type", true);
}
break;
default:
data = config["files"][fileType][fileID];
document.getElementById("deleteFileDetail").className = "delete";
showElement("updateFileDetail", true);
showElement("type", false);
showElement("file-type", false);
break;
}
var keys = getObjKeys(data);
for (var i = 0; i < keys.length; i++) {
if(document.getElementById(keys[i])){
document.getElementById(keys[i]).value = data[keys[i]];
}
}
}
function changeFileType(elm) {
var fileID = elm.getAttribute("data-id");
var fileType = elm.options[elm.selectedIndex].value;
fileDetail(fileID, fileType)
}
function saveFileDetail(fileID, fileType, deleteFile) {
if (fileID == undefined) {
alert("ID is missing!!!");
return
}
var inputs = document.getElementById("file-detail").getElementsByTagName("INPUT");
var selects = document.getElementById("file-detail").getElementsByTagName("SELECT");
var newFileData = new Object();
var data = new Object();
for (var i = 0; i < inputs.length; i++) {
switch(inputs[i].type) {
case "text": newFileData[inputs[i].name] = inputs[i].value; break;
}
}
for (var i = 0; i < selects.length; i++) {
newFileData[selects[i].id] = selects[i].options[selects[i].selectedIndex].value;
}
if (deleteFile == true) {
switch(fileType) {
case "m3u": var alertText = "Delete this playlist?"; break;
case "hdhr": var alertText = "Delete this HDHomeRun tuner?"; break;
case "xmltv": var alertText = "Delete this XMLTV file?"; break;
}
if (confirm(alertText)) {
newFileData["delete"] = true
data = buildFilesObj(fileType, fileID, newFileData);
console.log(data);
} else {
showElement("popup", false);
return
}
} else {
switch(config["files"][fileType].hasOwnProperty(fileID)) {
case true:
data = config["files"][fileType][fileID];
if (data["file.source"] != newFileData["file.source"]) {
data["update"] = true
} else {
data["updatePlaylistName"] = true;
}
break;
case false:
newFileData["new"] = true;
data = buildFilesObj(fileType, fileID, newFileData);
break
}
}
switch(fileType) {
case "m3u": data["cmd"] = "saveFilesM3U"; break;
case "hdhr": data["cmd"] = "saveFilesHDHR"; break;
case "xmltv": data["cmd"] = "saveFilesXMLTV"; break;
}
//console.log(data);
xTeVe(data);
return
}
function updateFile(fileID, fileType, allFiles) {
switch(config["files"][fileType].hasOwnProperty(fileID)) {
case true:
var data = new Object();
var data = buildFilesObj(fileType, fileID, config["files"][fileType][fileID])
data["new"] = true
switch(fileType) {
case "m3u": data["cmd"] = "updateFileM3U"; break;
case "hdhr": data["cmd"] = "updateFileHDHR"; break;
case "xmltv": data["cmd"] = "updateFileXMLTV"; break;
}
xTeVe(data);
break;
}
}
function buildFilesObj(fileType, fileID, obj) {
var data = new Object();
data["files"] = new Object();
data["files"][fileType] = new Object();
data["files"][fileType][fileID] = obj
return data
}
-114
View File
@@ -1,114 +0,0 @@
var logInterval
function updateLog() {
var data = new Object();
data["cmd"] = "getLog";
xTeVe(data);
writeLogInDiv();
return
}
function writeLogInDiv() {
var logs = log["log"];
var div = document.getElementById("settings").lastChild.lastChild;
div.innerHTML = "";
var max = 50;
for (var i = 0; i < logs.length; i++) {
var newEntry = new Object();
newEntry["_element"] = "P";
if (logs[i].includes("ERROR")) {
// case "warnings": msgType = "warningMsg"; break;
newEntry["class"] = "errorMsg";
}
if (logs[i].includes("WARNING")) {
// case "warnings": msgType = "warningMsg"; break;
newEntry["class"] = "warningMsg";
}
newEntry["_text"] = logs[i];
div.appendChild(createElement(newEntry));
}
calculateWrapperHeight();
var scrollDiv = document.getElementById("box-wrapper");
scrollDiv.scrollTop = scrollDiv.scrollHeight;
}
function showLog(obj) {
//logInterval = setInterval(updateLog, 5000);
var logs = log["log"];
var div = document.getElementById("settings");
var newEntry = new Object();
newEntry["_element"] = "HR";
div.appendChild(createElement(newEntry));
//div = div.lastChild;
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "button";
newEntry["class"] = "button";
newEntry["value"] = "Empty Log";
newEntry["onclick"] = "emptyLog()";
div.appendChild(createElement(newEntry));
var newEntry = new Object();
newEntry["_element"] = "code";
newEntry["_text"] = "Update Log: ";
div.appendChild(createElement(newEntry));
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "checkbox";
//newEntry["checked"] = "checkbox";
newEntry["onclick"] = "logUpdates(this)";
div.appendChild(createElement(newEntry));
var newEntry = new Object();
newEntry["_element"] = "HR";
div.appendChild(createElement(newEntry));
var newWrapper = new Object();
newWrapper["_element"] = "DIV";
newWrapper["id"] = "box-wrapper";
div.appendChild(createElement(newWrapper));
div = div.lastChild;
var newPre = new Object();
newPre["_element"] = "PRE";
newPre["id"] = "logScreen";
div.appendChild(createElement(newPre));
div = div.lastChild;
writeLogInDiv()
return
}
function emptyLog() {
var data = new Object();
data["cmd"] = "emptyLog";
xTeVe(data);
return
}
function logUpdates(elm) {
switch(elm.checked) {
case false: clearInterval(logInterval); break;
case true: logInterval = setInterval(updateLog, 5000); break;
}
}
-49
View File
@@ -1,49 +0,0 @@
var Log = /** @class */ (function () {
function Log() {
}
Log.prototype.createLog = function (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;
};
return Log;
}());
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(function (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);
}
File diff suppressed because it is too large Load Diff
-754
View File
@@ -1,754 +0,0 @@
function setMenuItem() {
menu = new Object();
subMenu = new Object();
var menu_m3u = new Object();
menu_m3u["_menuType"] = "inputArray";
menu_m3u["_element"] = "LI";
menu_m3u["_configKey"] = "files.m3u";
menu_m3u["_text"] = "Playlist";
menu_m3u["_icon"] = "img/m3u.png";
menu_m3u["_headline"] = "Playlists: Local or remote";
menu_m3u["_usage"] = "<b>Info</b><br>Availability: File availability in percent<br>Streams: Number of streams in the file.<br>group-title: Streams that are assigned to a group. Simplifies filtering streams<br>tvg-id: This ID is used for automatic mapping, must match with the channel ID in the XMLTV file.<br>Unique ID: Streams with a unique ID to identify them. Allows channel name changes in the M3U without losing the XMLTV mapping (PPV / live events).<br><br><b>Usage M3U:</b><br>Remote playlist: http://your.iptv.provider.com/file.m3u<br>Local playlist: /path/to/file.m3u<br><br><b>Usage HDHomeRun:</b><br>IP: 192.168.1.10:5004<br>"
menu_m3u["name"] = "file";
menu_m3u["id"] = "file";
menu_m3u["value"] = menu_m3u["name"];
menu_m3u["placeholder"] = "Playlist: local or remote";
menu_m3u["onclick"] = "javascript: toggleMenu(this);";
menu_m3u["class"] = "menu-notActive";
var menu_filter = new Object();
menu_filter["_menuType"] = "inputArray";
menu_filter["_element"] = "LI";
menu_filter["_configKey"] = "filter";
menu_filter["_text"] = "Filter";
menu_filter["_icon"] = "img/filter.png";
menu_filter["_headline"] = "Filter by M3U parameters, e.g. group-title";
menu_filter["_usage"] = "<b>Usage:</b><br>Sport - All sports channels<br>Sport {HD} - All HD sports channels<br>Sport {HD} !{ES,DE} - All HD sports channels, but no Spanish and German<br><br>To filter the streams of a HDHomeRun, the playlist name can be entered:<br>My tuner {HD}"
//menu_filter["_usage"] = "<b>Usage:</b><br>All sports channels: Sport<br>All HD sports channels: Sport {HD}<br>All HD sports channels, but no Spanish and German: Sport {HD} !{ES,DE}"
menu_filter["name"] = "filter";
menu_filter["id"] = "M3U";
menu_filter["value"] = menu_filter["name"];
menu_filter["placeholder"] = "Filter streams: Sport";
menu_filter["onclick"] = "javascript: toggleMenu(this);";
menu_filter["class"] = "menu-notActive";
var menu_id = new Object();
menu_id["_menuType"] = "inputArray";
menu_id["_element"] = "LI";
menu_id["_configKey"] = "id";
menu_id["_text"] = "PMS ID";
menu_id["_icon"] = "img/number.png";
menu_id["_headline"] = "Setup PMS guide number";
menu_id["_usage"] = 'Some playlists have unique channel IDs.<br>Enter the keyword of the ID. The channel assignment in PMS will change as a result.<br><br>e.g. channelID<br>#EXTINF:0 type="stream" <b>channelId</b>="81", My Streaming Channel HD<br><br>Only enter here if you know what you are doing!'
menu_id["name"] = "id";
menu_id["id"] = "id";
menu_id["value"] = menu_id["name"];
menu_id["placeholder"] = "Unique ID from the M3U file";
menu_id["onclick"] = "javascript: toggleMenu(this);";
menu_id["class"] = "menu-notActive";
var menu_xmltv = new Object();
menu_xmltv["_menuType"] = "inputArray";
menu_xmltv["_element"] = "LI";
menu_xmltv["_configKey"] = "files.xmltv";
menu_xmltv["_text"] = "XMLTV";
menu_xmltv["_icon"] = "img/xmltv.png";
menu_xmltv["_headline"] = "XMLTV files: Local or remote";
menu_xmltv["_usage"] = "<b>Info:</b><br>Availability: File availability in percent<br>Channels: Number of channels in the file<br>Programs: Number of EPG data<br><br><b>Usage:</b><br>Remote XMLTV file: http://your.epg.provider.com/guide.xml<br>Local XMLTV file: /path/to/guide.xml"
menu_xmltv["name"] = "xmltv";
menu_xmltv["id"] = "xmltv";
menu_xmltv["value"] = menu_xmltv["name"];
menu_xmltv["placeholder"] = "XMLTV File: local or remote";
menu_xmltv["onclick"] = "javascript: toggleMenu(this);";
menu_xmltv["class"] = "menu-notActive";
menu_mapping = new Object();
menu_mapping["_element"] = "LI";
menu_mapping["_text"] = "Mapping";
menu_mapping["_icon"] = "img/mapping.png";
menu_mapping["_configKey"] = "mapping";
menu_mapping["_headline"] = "XMLTV assignment and sorting of channels";
menu_mapping["id"] = "mapping";
menu_mapping["onclick"] = "javascript: toggleMenu(this);";
menu_mapping["class"] = "menu-notActive phone";
menu_users = new Object();
menu_users["_element"] = "LI";
menu_users["_text"] = "Users";
menu_users["_icon"] = "img/users.png";
menu_users["_configKey"] = "users";
menu_users["_headline"] = "Administration of users and permissions";
menu_users["id"] = "users";
menu_users["onclick"] = "javascript: toggleMenu(this);";
menu_users["class"] = "menu-notActive";
menu_users["_usage"] = "<b>Authorization groups:</b><br>WEB: Users can log in to the web interface<br>PMS: Programs like Plex can access the channel list. Login via DVR IP: username:password@xteve.ip:port<br>M3U: Allows clients to download the M3U playlist.<br>XML: Allows clients to download the XMLTV file.<br>API: Allows clients to use the API interface.<br><br>!!! For PMS authentication, only the following special characters are valid: !$()=.,-:;<br><br>The individual authentication groups can be activated / deactivated in the settings menu."
menu_settings = new Object();
menu_settings["_element"] = "LI";
menu_settings["_text"] = "Settings";
menu_settings["_icon"] = "img/settings.png";
menu_settings["_configKey"] = "settings";
menu_settings["_headline"] = "Settings";
menu_settings["_subMenu"] = "701,702,703,704,705,706,707,708,799,710,711,712,713,714";
menu_settings["id"] = "settings";
menu_settings["onclick"] = "javascript: toggleMenu(this);";
menu_settings["class"] = "menu-notActive";
menu_log = new Object();
menu_log["_element"] = "LI";
menu_log["_text"] = "Log";
menu_log["_icon"] = "img/log.png";
menu_log["_headline"] = "Log";
menu_log["_configKey"] = "log";
menu_log["id"] = "log";
menu_log["onclick"] = "javascript: toggleMenu(this);";
menu_log["class"] = "menu-notActive";
menu_logout = new Object();
menu_logout["_element"] = "LI";
menu_logout["_text"] = "Logout";
menu_logout["_icon"] = "img/logout.png";
menu_logout["id"] = "logout";
menu_logout["onclick"] = "javascript: logout();";
menu_logout["class"] = "menu-notActive";
var menu_schedule = new Object();
menu_schedule["_menuType"] = "inputArray";
menu_schedule["_element"] = "LI";
menu_schedule["_configKey"] = "update";
menu_schedule["_text"] = "Schedule";
menu_schedule["_icon"] = "img/schedule.png";
menu_schedule["_headline"] = "Schedule for updating M3U, XMLTV files and creating a local backup";
menu_schedule["_usage"] = "<b>Usage:</b><br>0815 = 8:15 am<br>1930 = 7:30 pm"
menu_schedule["name"] = "update";
menu_schedule["id"] = "update";
menu_schedule["value"] = menu_id["name"];
menu_schedule["placeholder"]= "time of day (24-hour clock)";
menu_schedule["onclick"] = "javascript: toggleMenu(this);";
menu_schedule["class"] = "menu-notActive";
var menu_filesUpdate = new Object();
menu_filesUpdate["_element"] = "LI";
menu_filesUpdate["_menuType"] = "checkbox";
menu_filesUpdate["_configKey"] = "files.update";
menu_filesUpdate["_label"] = "Update the provider files at system startup";
menu_filesUpdate["_headline"] = "Update the provider files at system startup";
menu_filesUpdate["_usage"] = "Playlists and XMLTV files are updated by xTeVe at system startup."
menu_filesUpdate["name"] = "files.update";
menu_filesUpdate["id"] = "files.update";
menu_filesUpdate["value"] = menu_filesUpdate["name"];
menu_filesUpdate["onclick"] = "javascript: toggleMenu(this);";
menu_filesUpdate["class"] = "menu-notActive";
var menu_tuner = new Object();
menu_tuner["_element"] = "LI";
menu_tuner["_menuType"] = "select";
menu_tuner["_configKey"] = "tuner";
menu_tuner["_label"] = "Available tuners";
menu_tuner["_text"] = "Tuner";
menu_tuner["_icon"] = "img/tuner.png";
menu_tuner["_headline"] = "Number of tuners";
menu_tuner["_usage"] = "This setting is only used by Plex and Emby.<br>The number of concurrent streams allowed by the IPTV provider.<br>After a change, xTeVe must be delete in the PMS DVR settings and set up again."
menu_tuner["name"] = "tuner";
menu_tuner["id"] = "tuner";
menu_tuner["value"] = menu_tuner["name"];
menu_tuner["placeholder"] = "Number of tuners";
menu_tuner["onclick"] = "javascript: toggleMenu(this);";
menu_tuner["class"] = "menu-notActive";
var optionValues = new Array();
for (var i = 1; i <= 100; i++) {
optionValues.push(i)
}
menu_tuner["_optionValues"] = optionValues;
var menu_epg = new Object();
menu_epg["_element"] = "LI";
menu_epg["_menuType"] = "select";
menu_epg["_configKey"] = "epgSource";
menu_epg["_label"] = "Selection of the EPG source";
menu_epg["_text"] = "EPG source";
menu_epg["_headline"] = "Selection of the EPG source";
menu_epg["_usage"] = "PMS: Use EPG data from Plex or Emby.<br>XEPG: Use of external EPG data (XMLTV).<br> Several XMLTV sources possible.<br> Allows editing and order channels.<br> M3U / XMLTV export (HTTP link for IPTV apps)."
menu_epg["name"] = "epgSource";
menu_epg["id"] = "epgSource";
menu_epg["value"] = menu_epg["name"];
menu_epg["placeholder"] = "EPG source";
menu_epg["onclick"] = "javascript: toggleMenu(this);";
menu_epg["class"] = "menu-notActive";
menu_epg["_optionValues"] = new Array("PMS", "XEPG");
var menu_xepg = new Object();
menu_xepg["_element"] = "LI";
menu_xepg["_menuType"] = "checkbox";
menu_xepg["_configKey"] = "xteveAutoUpdate";
menu_xepg["_label"] = "Automatic update of xTeVe";
menu_xepg["_headline"] = "Automatic update of xTeVe";
menu_xepg["_usage"] = "If a new version of xTeVe is available, it will be automatically installed."
menu_xepg["name"] = "xteveAutoUpdate";
menu_xepg["id"] = "xteveAutoUpdate";
menu_xepg["value"] = menu_xepg["name"];
menu_xepg["onclick"] = "javascript: toggleMenu(this);";
menu_xepg["class"] = "menu-notActive";
var menu_autoBackupPath = new Object();
menu_autoBackupPath["_element"] = "LI";
menu_autoBackupPath["_menuType"] = "singleInput";
menu_autoBackupPath["_configKey"] = "backup.path";
menu_autoBackupPath["_label"] = "Location for automatic backups";
menu_autoBackupPath["_headline"] = "Location for automatic backups";
menu_autoBackupPath["_usage"] = "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."
menu_autoBackupPath["name"] = "backup.path";
menu_autoBackupPath["id"] = "backup.path";
menu_autoBackupPath["value"] = menu_autoBackupPath["name"];
menu_autoBackupPath["onclick"] = "javascript: toggleMenu(this);";
menu_autoBackupPath["class"] = "menu-notActive";
var menu_autoBackupKeep = new Object();
menu_autoBackupKeep["_element"] = "LI";
menu_autoBackupKeep["_menuType"] = "select";
menu_autoBackupKeep["_configKey"] = "backup.keep";
menu_autoBackupKeep["_text"] = "Keep";
menu_autoBackupKeep["_label"] = "Number of backups to keep";
menu_autoBackupKeep["_headline"] = "Number of backups to keep";
menu_autoBackupKeep["_usage"] = ""
menu_autoBackupKeep["name"] = "backup.keep";
menu_autoBackupKeep["id"] = "backup.keep";
menu_autoBackupKeep["value"] = menu_autoBackupKeep["name"];
menu_autoBackupKeep["onclick"] = "javascript: toggleMenu(this);";
menu_autoBackupKeep["class"] = "menu-notActive";
var optionValues = new Array(5, 10, 20, 30, 40, 50);
menu_autoBackupKeep["_optionValues"] = optionValues;
var menu_buffer = new Object();
menu_buffer["_element"] = "LI";
menu_buffer["_menuType"] = "checkbox";
menu_buffer["_configKey"] = "buffer";
menu_buffer["_label"] = "Stream buffering [Experimental]";
menu_buffer["_headline"] = "Stream buffering [Experimental]";
menu_buffer["_usage"] = "With activated buffer, streams can be played and recorded more fluently.<br>The stream is passed from xTeVe to Plex / Emby"
menu_buffer["name"] = "buffer";
menu_buffer["id"] = "buffer";
menu_buffer["value"] = menu_buffer["name"];
menu_buffer["onclick"] = "javascript: toggleMenu(this);";
menu_buffer["class"] = "menu-notActive";
var menu_api = new Object();
menu_api["_element"] = "LI";
menu_api["_menuType"] = "checkbox";
menu_api["_configKey"] = "api";
menu_api["_label"] = "API interface";
menu_api["_headline"] = "API interface";
menu_api["_usage"] = 'Via API interface it is possible to send commands to xTeVe. API documentation is available <a href="https://xteve.de?scroll=api">here</a> '
//menu_api["_usage"] = 'Via API interface it is possible to send commands to xTeVe. API documentation is available <a href="http://localhost:1313?scroll=api">here</a> '
menu_api["name"] = "api";
menu_api["id"] = "api";
menu_api["value"] = menu_api["name"];
menu_api["onclick"] = "javascript: toggleMenu(this);";
menu_api["class"] = "menu-notActive";
var menu_authenticationWeb = new Object();
menu_authenticationWeb["_element"] = "LI";
menu_authenticationWeb["_menuType"] = "checkbox";
menu_authenticationWeb["_configKey"] = "authentication.web";
menu_authenticationWeb["_label"] = "User authentication";
menu_authenticationWeb["_headline"] = "User authentication";
menu_authenticationWeb["_usage"] = "Access to xTeVe requires authentication."
menu_authenticationWeb["name"] = "authentication.web";
menu_authenticationWeb["id"] = "authentication.web";
menu_authenticationWeb["value"] = menu_authenticationWeb["name"];
menu_authenticationWeb["onclick"] = "javascript: toggleMenu(this);";
menu_authenticationWeb["class"] = "menu-notActive";
var menu_authenticationPms = new Object();
menu_authenticationPms["_element"] = "LI";
menu_authenticationPms["_menuType"] = "checkbox";
menu_authenticationPms["_configKey"] = "authentication.pms";
menu_authenticationPms["_label"] = "Plex authentication.";
menu_authenticationPms["_headline"] = "Plex authentication.";
menu_authenticationPms["_usage"] = "Plex requests are only possible with authentication.<br>Warning!!! After activating this function xTeVe must be delete in the PMS DVR settings and set up again."
menu_authenticationPms["name"] = "authentication.pms";
menu_authenticationPms["id"] = "authentication.pms";
menu_authenticationPms["value"] = menu_authenticationPms["name"];
menu_authenticationPms["onclick"] = "javascript: toggleMenu(this);";
menu_authenticationPms["class"] = "menu-notActive";
var menu_authenticationM3u = new Object();
menu_authenticationM3u["_element"] = "LI";
menu_authenticationM3u["_menuType"] = "checkbox";
menu_authenticationM3u["_configKey"] = "authentication.m3u";
menu_authenticationM3u["_label"] = "M3U authentication.";
menu_authenticationM3u["_headline"] = "M3U authentication.";
menu_authenticationM3u["_usage"] = "Downloading the M3U file via an HTTP request is only possible with authentication."
menu_authenticationM3u["name"] = "authentication.m3u";
menu_authenticationM3u["id"] = "authentication.m3u";
menu_authenticationM3u["value"] = menu_authenticationM3u["name"];
menu_authenticationM3u["onclick"] = "javascript: toggleMenu(this);";
menu_authenticationM3u["class"] = "menu-notActive";
var menu_authenticationXml = new Object();
menu_authenticationXml["_element"] = "LI";
menu_authenticationXml["_menuType"] = "checkbox";
menu_authenticationXml["_configKey"] = "authentication.xml";
menu_authenticationXml["_label"] = "XEPG authentication";
menu_authenticationXml["_headline"] = "XEPG authentication";
menu_authenticationXml["_usage"] = "Downloading the XEPG (XMLTV) file via an HTTP request is only possible with authentication."
menu_authenticationXml["name"] = "authentication.xml";
menu_authenticationXml["id"] = "authentication.xml";
menu_authenticationXml["value"] = menu_authenticationXml["name"];
menu_authenticationXml["onclick"] = "javascript: toggleMenu(this);";
menu_authenticationXml["class"] = "menu-notActive";
var menu_authenticationApi = new Object();
menu_authenticationApi["_element"] = "LI";
menu_authenticationApi["_menuType"] = "checkbox";
menu_authenticationApi["_configKey"] = "authentication.api";
menu_authenticationApi["_label"] = "API authentication";
menu_authenticationApi["_headline"] = "API authentication";
menu_authenticationApi["_usage"] = "Access to the API interface is only possible with authentication."
menu_authenticationApi["name"] = "authentication.api";
menu_authenticationApi["id"] = "authentication.api";
menu_authenticationApi["value"] = menu_authenticationApi["name"];
menu_authenticationApi["onclick"] = "javascript: toggleMenu(this);";
menu_authenticationApi["class"] = "menu-notActive";
// Main menu
menu[10] = menu_m3u;
switch(config["epgSource"]) {
case "PMS":
menu[20] = menu_id;
break;
case "XMLTV":
menu[40] = menu_xmltv;
break;
case "XEPG":
menu[40] = menu_xmltv;
menu[50] = menu_mapping;
break;
}
menu[30] = menu_filter;
if (config["authentication.web"] == true) {
menu[60] = menu_users;
}
menu[70] = menu_settings;
menu[80] = menu_log;
if (config["authentication.web"] == true) {
menu[100] = menu_logout;
}
// Sub-Menu
subMenu[701] = menu_schedule;
subMenu[702] = menu_filesUpdate;
subMenu[703] = menu_tuner;
subMenu[704] = menu_epg;
subMenu[705] = menu_xepg;
subMenu[706] = menu_autoBackupPath;
subMenu[707] = menu_autoBackupKeep;
subMenu[708] = menu_buffer;
subMenu[710] = menu_authenticationWeb;
if (config["authentication.web"] == true) {
subMenu[711] = menu_authenticationPms;
subMenu[712] = menu_authenticationM3u;
subMenu[713] = menu_authenticationXml;
subMenu[714] = menu_authenticationApi;
}
subMenu[799] = menu_api;
return
}
function createMenu() {
showElement("popup", false);
//console.log(config);
setMenuItem();
var menuItems = getObjKeys(menu)
var nav = document.getElementsByTagName("NAV")[0];
nav.innerHTML = "";
var newItem = new Object();
for (var i = 0; i < menuItems.length; i++) {
var newItem = menu[menuItems[i]];
newItem["id"] = menuItems[i];
switch(newItem.hasOwnProperty("_icon")) {
case true:
var itemText = newItem["_text"];
delete newItem["_text"]
nav.appendChild(createElement(newItem));
newItem["_text"] = itemText;
var newIcon = new Object();
newIcon["_element"] = "IMG";
newIcon["src"] = newItem["_icon"];
var currentElement = document.getElementById(menuItems[i]);
currentElement.appendChild(createElement(newIcon));
var text = new Object();
text["_element"] = "P"
text["_text"] = itemText;
text["class"] = "nav-text"
currentElement.appendChild(createElement(text));
break;
default:
nav.appendChild(createElement(newIcon));
break;
}
}
if (activeMenu != undefined) {
//console.log(activeMenu);
toggleMenu(activeMenu);
}
return
}
function toggleMenu(elm) {
//showStreams(false);
clearInterval(logInterval)
activeMenu = elm;
var item = menu[elm.id]
var div = document.getElementById("settings");
div.innerHTML = "";
// Set Headline
var headline = new Object();
headline["_element"] = "H4";
headline["_text"] = item["_headline"];
div.appendChild(createElement(headline));
// Sub-Menu
if (item.hasOwnProperty("_subMenu") == true) {
openSubMenu(item);
return
}
// Mapping, Users, Log, Files
switch(item["_configKey"]) {
case "mapping": openMappingEditor(item); return; break;
case "users": openUsers(item); return; break;
case "log": showLog(item); return; break;
case "files.m3u": openFiles(item, "m3u"); return; break;
case "files.xmltv": openFiles(item, "xmltv"); return; break;
case "filter": showStreams(true); break;
}
var newHR = new Object();
newHR["_element"] = "HR"
div.appendChild(createElement(newHR));
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "button";
//newEntry["class"] = "save";
newEntry["value"] = "Save";
newEntry["onclick"] = "saveData2('settings')"
div.appendChild(createElement(newEntry));
var newWrapper = new Object();
newWrapper["_element"] = "DIV";
newWrapper["id"] = "box-wrapper";
div.appendChild(createElement(newWrapper));
div = div.lastChild;
div.appendChild(createMenuItem(item))
// usage Info
switch(menu[activeMenu.id].hasOwnProperty("_usage")) {
case true:
var usageItem = new Object();
usageItem["_element"] = "PRE"
usageItem["_text"] = menu[activeMenu.id]["_usage"];
div.appendChild(createElement(usageItem));
}
calculateWrapperHeight();
}
function createMenuItem(item) {
var element = document.createElement("DIV");
switch(item["_menuType"]) {
case "inputArray":
if (config.hasOwnProperty(item["_configKey"]) == true) {
var value = config[item["_configKey"]];
} else {
var value = new Array();
}
for (var i = 0; i < value.length; i++) {
var newEntry = new Object();
newEntry = item
delete newEntry["onclick"];
newEntry["_element"] = "INPUT";
newEntry["value"] = value[i];
newEntry["type"] = "search";
newEntry["data-menutype"] = item["_menuType"];
newEntry["data-menukey"] = item["_configKey"];
element.appendChild(createElement(newEntry));
}
// New entry for array
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "search";
newEntry["name"] = item["name"];
newEntry["placeholder"] = item["placeholder"];
newEntry["value"] = "";
newEntry["data-menutype"] = item["_menuType"];
newEntry["data-menukey"] = item["_configKey"];
element.appendChild(createElement(newEntry));
break;
case "singleInput":
var value = config[item["_configKey"]];
if (value == undefined) {
value = "";
}
var newEntry = new Object();
newEntry = item;
delete newEntry["onclick"];
newEntry["_element"] = "INPUT";
newEntry["value"] = value;
newEntry["type"] = "search";
newEntry["data-menutype"] = item["_menuType"];
newEntry["data-menukey"] = item["_configKey"];
element.appendChild(createElement(newEntry));
break;
case "checkbox":
var value = config[item["_configKey"]];
if (value == undefined) {
value = false;
}
var newEntry = new Object();
newEntry = item;
delete newEntry["onclick"];
newEntry["_element"] = "INPUT";
newEntry["value"] = value;
newEntry["type"] = "checkbox";
newEntry["data-menutype"] = item["_menuType"];
newEntry["data-menukey"] = item["_configKey"];
element.appendChild(createElement(newEntry));
element.getElementsByTagName("INPUT")[0].checked = value;
break;
case "select":
var value = config[item["_configKey"]];
var newEntry = new Object();
newEntry = item;
delete newEntry["onclick"]
newEntry["_element"] = "SELECT";
element.appendChild(createElement(newEntry));
var selectElement = element.getElementsByTagName("SELECT")[0];
var values = item["_optionValues"];
for (var i = 0; i < values.length; i++) {
var newEntry = new Object;
newEntry["_element"] = "OPTION";
newEntry["_text"] = item["_text"] + ": " + values[i];
newEntry["value"] = values[i];
selectElement.appendChild(createElement(newEntry));
}
selectElement.value = value;
break;
}
return element;
}
function openSubMenu(item) {
var entrys = item["_subMenu"].split(",");
var div = document.getElementById("settings");
var newHR = new Object();
newHR["_element"] = "HR"
div.appendChild(createElement(newHR));
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "button";
//newEntry["class"] = "save";
newEntry["value"] = "Save";
newEntry["onclick"] = "saveData2('settings')"
div.appendChild(createElement(newEntry));
if (item["_configKey"] == "settings") {
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "button";
//newEntry["class"] = "save";
newEntry["value"] = "Backup";
newEntry["onclick"] = "xteveBackup()"
div.appendChild(createElement(newEntry));
}
if (item["_configKey"] == "settings") {
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "button";
//newEntry["class"] = "save";
newEntry["value"] = "Restore";
newEntry["onclick"] = "xteveRestore(this)"
div.appendChild(createElement(newEntry));
}
var newWrapper = new Object();
newWrapper["_element"] = "DIV";
newWrapper["id"] = "box-wrapper";
div.appendChild(createElement(newWrapper));
div = div.lastChild;
for (var i = 0; i < entrys.length; i++) {
var item = subMenu[entrys[i]];
if (item == undefined) {
break;
}
var container = new Object();
container["_element"] = "DIV";
div.appendChild(createElement(container));
var divContainer = div.lastChild;
var headline = new Object();
headline["_element"] = "H5";
headline["_text"] = item["_headline"];
divContainer.appendChild(createElement(headline));
divContainer.appendChild(createMenuItem(item))
switch(item.hasOwnProperty("_usage")) {
case true:
var usageItem = new Object();
usageItem["_element"] = "PRE"
usageItem["_text"] = item["_usage"];
divContainer.appendChild(createElement(usageItem));
}
var hr = new Object();
hr["_element"] = "HR";
divContainer.appendChild(createElement(hr));
}
calculateWrapperHeight();
return
}
function saveData2(elm) {
var div = document.getElementById(elm);
var inputs = div.getElementsByTagName("INPUT");
var selects = div.getElementsByTagName("SELECT");
var value, configKey;
var data = new Object();
var valueArr = new Array();
var newData = false;
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type != "button") {
var menuType = inputs[i].getAttribute("data-menutype");
//console.log(menuType);
switch(menuType) {
case "singleInput":
value = inputs[i].value;
if (value == "" || value == undefined) {
data = new Object();
data["delete"] = inputs[i].name
newData = true;
} else {
newData = true;
data[inputs[i].name] = value;
console.log(data);
}
break;
case "inputArray":
value = inputs[i].value;
if (value != "" && value != undefined) {
newData = true;
valueArr.push(value)
data[inputs[i].name] = valueArr;
configKey = inputs[i].name;
}
break;
case "checkbox":
value = inputs[i].checked
data[inputs[i].name] = value;
}
}
}
// Delete config key
if (valueArr.length == 0 && newData == false) {
newData = true;
data = new Object();
data["delete"] = configKey;
}
for (var i = 0; i < selects.length; i++) {
var value = selects[i].options[selects[i].selectedIndex].value;
switch(isNaN(value)) {
case false: value = parseInt(value); break;
}
data[selects[i].name] = value;
newData = true;
}
//console.log(data, newData);
if (newData == true) {
data["cmd"] = "saveConfig";
if (!data.hasOwnProperty('filter')) {
data["filter"] = config["filter"]
}
var settings = new Object();
settings["cmd"] = data["cmd"];
settings["settings"] = data;
console.log(settings);
xTeVe(settings);
}
}
-172
View File
@@ -1,172 +0,0 @@
var Server = /** @class */ (function () {
function Server(cmd) {
this.cmd = cmd;
}
Server.prototype.request = function (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) {
if (responseSuccess === void 0) { 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);
};
};
return Server;
}());
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();
}
-557
View File
@@ -1,557 +0,0 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var SettingsCategory = /** @class */ (function () {
function SettingsCategory() {
this.DocumentID = "content_settings";
}
SettingsCategory.prototype.createCategoryHeadline = function (value) {
var element = document.createElement("H4");
element.innerHTML = value;
return element;
};
SettingsCategory.prototype.createHR = function () {
var element = document.createElement("HR");
return element;
};
SettingsCategory.prototype.createSettings = function (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 = "{{.settings.update.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "update", data.toString());
input.setAttribute("placeholder", "{{.settings.update.placeholder}}");
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 = "{{.settings.backupPath.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "backup.path", data);
input.setAttribute("placeholder", "{{.settings.backupPath.placeholder}}");
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 = "{{.settings.tempPath.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "temp.path", data);
input.setAttribute("placeholder", "{{.settings.tmpPath.placeholder}}");
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 = "{{.settings.userAgent.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "user.agent", data);
input.setAttribute("placeholder", "{{.settings.userAgent.placeholder}}");
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 = "{{.settings.plexURL.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "plex.url", data);
input.setAttribute("placeholder", "{{.settings.plexURL.placeholder}}");
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 = "{{.settings.plexToken.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("password", "plex.token", data);
input.setAttribute("placeholder", "{{.settings.plexToken.placeholder}}");
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 = "{{.settings.bufferTimeout.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "buffer.timeout", data);
input.setAttribute("placeholder", "{{.settings.bufferTimeout.placeholder}}");
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 = "{{.settings.ffmpegPath.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "ffmpeg.path", data);
input.setAttribute("placeholder", "{{.settings.ffmpegPath.placeholder}}");
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 = "{{.settings.ffmpegOptions.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "ffmpeg.options", data);
input.setAttribute("placeholder", "{{.settings.ffmpegOptions.placeholder}}");
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 = "{{.settings.vlcPath.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "vlc.path", data);
input.setAttribute("placeholder", "{{.settings.vlcPath.placeholder}}");
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 = "{{.settings.vlcOptions.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "vlc.options", data);
input.setAttribute("placeholder", "{{.settings.vlcOptions.placeholder}}");
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 = "{{.settings.authenticationWEB.title}}" + ":";
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 = "{{.settings.authenticationPMS.title}}" + ":";
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 = "{{.settings.authenticationM3U.title}}" + ":";
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 = "{{.settings.authenticationXML.title}}" + ":";
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 = "{{.settings.authenticationAPI.title}}" + ":";
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 = "{{.settings.filesUpdate.title}}" + ":";
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 = "{{.settings.cacheImages.title}}" + ":";
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 = "{{.settings.replaceEmptyImages.title}}" + ":";
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 = "{{.settings.api.title}}" + ":";
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 = "{{.settings.usePlexAPI.title}}" + ":";
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 = "{{.settings.xepgMissingEPGMode.title}}" + ":";
var tdRight = document.createElement("TD");
var text = ["{{.settings.xepgMissingEPGMode.info_strict}}", "{{.settings.xepgMissingEPGMode.info_relaxed}}"];
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 = "{{.settings.tuner.title}}" + ":";
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 = "{{.settings.epgSource.title}}" + ":";
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 = "{{.settings.backupKeep.title}}" + ":";
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 = "{{.settings.bufferSize.title}}" + ":";
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 = "{{.settings.streamBuffering.title}}" + ":";
var tdRight = document.createElement("TD");
var text = ["{{.settings.streamBuffering.info_false}}", "xTeVe: ({{.settings.streamBuffering.info_xteve}})", "FFmpeg: ({{.settings.streamBuffering.info_ffmpeg}})", "VLC: ({{.settings.streamBuffering.info_vlc}})"];
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 = "{{.settings.udpxy.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "udpxy", data);
input.setAttribute("placeholder", "{{.settings.udpxy.placeholder}}");
input.setAttribute("onchange", "javascript: this.className = 'changed'");
tdRight.appendChild(input);
setting.appendChild(tdLeft);
setting.appendChild(tdRight);
break;
}
return setting;
};
SettingsCategory.prototype.createDescription = function (settingsKey) {
var description = document.createElement("TR");
var text;
switch (settingsKey) {
case "authentication.web":
text = "{{.settings.authenticationWEB.description}}";
break;
case "authentication.m3u":
text = "{{.settings.authenticationM3U.description}}";
break;
case "authentication.pms":
text = "{{.settings.authenticationPMS.description}}";
break;
case "authentication.xml":
text = "{{.settings.authenticationXML.description}}";
break;
case "authentication.api":
if (SERVER["settings"]["authentication.web"] == true) {
text = "{{.settings.authenticationAPI.description}}";
}
break;
case "backup.keep":
text = "{{.settings.backupKeep.description}}";
break;
case "backup.path":
text = "{{.settings.backupPath.description}}";
break;
case "temp.path":
text = "{{.settings.tempPath.description}}";
break;
case "buffer":
text = "{{.settings.streamBuffering.description}}";
break;
case "buffer.size.kb":
text = "{{.settings.bufferSize.description}}";
break;
case "buffer.timeout":
text = "{{.settings.bufferTimeout.description}}";
break;
case "user.agent":
text = "{{.settings.userAgent.description}}";
break;
case "plex.url":
text = "{{.settings.plexURL.description}}";
break;
case "plex.token":
text = "{{.settings.plexToken.description}}";
break;
case "ffmpeg.path":
text = "{{.settings.ffmpegPath.description}}";
break;
case "ffmpeg.options":
text = "{{.settings.ffmpegOptions.description}}";
break;
case "vlc.path":
text = "{{.settings.vlcPath.description}}";
break;
case "vlc.options":
text = "{{.settings.vlcOptions.description}}";
break;
case "epgSource":
text = "{{.settings.epgSource.description}}";
break;
case "tuner":
text = "{{.settings.tuner.description}}";
break;
case "update":
text = "{{.settings.update.description}}";
break;
case "api":
text = "{{.settings.api.description}}";
break;
case "use_plexAPI":
text = "{{.settings.usePlexAPI.description}}";
break;
case "files.update":
text = "{{.settings.filesUpdate.description}}";
break;
case "cache.images":
text = "{{.settings.cacheImages.description}}";
break;
case "xepg.replace.missing.images":
text = "{{.settings.replaceEmptyImages.description}}";
break;
case "xepg.missing.epg.mode":
text = "{{.settings.xepgMissingEPGMode.description}}";
break;
case "udpxy":
text = "{{.settings.udpxy.description}}";
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;
};
return SettingsCategory;
}());
var SettingsCategoryItem = /** @class */ (function (_super) {
__extends(SettingsCategoryItem, _super);
function SettingsCategoryItem(headline, settingsKeys) {
var _this = _super.call(this) || this;
_this.headline = headline;
_this.settingsKeys = settingsKeys;
return _this;
}
SettingsCategoryItem.prototype.createCategory = function () {
var _this = this;
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(function (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());
};
return SettingsCategoryItem;
}(SettingsCategory));
function showSettings() {
console.log("SETTINGS");
for (var 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 (var 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);
}
-341
View File
@@ -1,341 +0,0 @@
function openUsers(elm) {
colomnSort = 0;
var newDiv = document.getElementById("settings");
var newEntry = new Object();
newEntry["_element"] = "HR";
newDiv.appendChild(createElement(newEntry));
var newEntry = new Object();
newEntry["_element"] = "INPUT";
newEntry["type"] = "button";
newEntry["class"] = "button";
newEntry["value"] = "New";
newEntry["onclick"] = "userDetail(0)";
newDiv.appendChild(createElement(newEntry));
var div = document.getElementById("settings");
// Build table
var newTable = new Object();
newTable["_element"] = "TABLE";
newTable["id"] = "id_mapping";
newTable["class"] = "table-mapping";
div.appendChild(createElement(newTable));
setTimeout(function(){
createUsersTable();
}, 10);
}
function createUsersTable() {
var table = document.getElementById("id_mapping");
table.innerHTML = "";
var newTR = new Object();
newTR["_element"] = "TR";
newTR["class"] = "table-mapping-header";
table.appendChild(createElement(newTR));
var tr = table.lastChild;
var trHeadlines = new Array("Username", "Password", "WEB", "PMS", "M3U", "XML", "API")
for (var i = 0; i < trHeadlines.length; i++) {
var newTD = new Object();
newTD["_element"] = "TD";
newTD["_text"] = trHeadlines[i];
tr.appendChild(createElement(newTD));
}
// Sort users
var userIds = getObjKeys(users);
var userObj = new Object();
for (var i = 0; i < userIds.length; i++) {
var username = users[userIds[i]]["data"]["username"];
userObj[username] = userIds[i];
}
var allUsers = getObjKeys(userObj);
allUsers.sort();
// --
for (var i = 0; i < allUsers.length; i++) {
var table = document.getElementById("id_mapping");
var userID = userObj[allUsers[i]];
var username = allUsers[i];
var item = users[userID]["data"];
// Create TR
var newTR = new Object();
newTR["_element"] = "TR";
newTR["class"] = "";
newTR["id"] = userID;
newTR["onclick"] = 'javascript: userDetail("' + userID + '");';
table.appendChild(createElement(newTR));
var tr = table.lastChild;
// Create username TD
var newTD = new Object();
newTD["_element"] = "P";
newTD["_text"] = username;
createNewTD(newTD, tr);
// Create password TD
var newTD = new Object();
newTD["_element"] = "P";
newTD["_text"] = ".....";
createNewTD(newTD, tr);
// Create web access
var newTD = new Object();
newTD["_element"] = "P";
switch(item["authentication.web"]){
case true: newTD["_text"] = "✓"; break;
default: newTD["_text"] = "-"; break;
}
createNewTD(newTD, tr);
// Create PMS access
var newTD = new Object();
newTD["_element"] = "P";
switch(item["authentication.pms"]){
case true: newTD["_text"] = "✓"; break;
default: newTD["_text"] = "-"; break;
}
createNewTD(newTD, tr);
// Create M3U access
var newTD = new Object();
newTD["_element"] = "P";
switch(item["authentication.m3u"]){
case true: newTD["_text"] = "✓"; break;
default: newTD["_text"] = "-"; break;
}
createNewTD(newTD, tr);
// Create XMLTV access
var newTD = new Object();
newTD["_element"] = "P";
switch(item["authentication.xml"]){
case true: newTD["_text"] = "✓"; break;
default: newTD["_text"] = "-"; break;
}
createNewTD(newTD, tr);
// Create API access
var newTD = new Object();
newTD["_element"] = "P";
switch(item["authentication.api"]){
case true: newTD["_text"] = "✓"; break;
default: newTD["_text"] = "-"; break;
}
createNewTD(newTD, tr);
}
// usage Info
var div = document.getElementById("settings");
switch(menu[activeMenu.id].hasOwnProperty("_usage")) {
case true:
var usageItem = new Object();
usageItem["_element"] = "PRE"
usageItem["_text"] = menu[activeMenu.id]["_usage"];
var newHR = new Object();
newHR["_element"] = "HR"
div.appendChild(createElement(newHR));
div.appendChild(createElement(usageItem));
}
sortTable(0);
}
function userDetail(userID) {
showPopUpElement('user-detail');
setTimeout(function(){
showElement("popup", true);
}, 10);
var defaultUser;
document.getElementById("saveUserDetail").setAttribute("onclick", 'javascript: saveUserDetail("' + userID + '", false)');
document.getElementById("deleteUserDetail").setAttribute("onclick", 'javascript: saveUserDetail("' + userID + '", true)');
var data = new Object();
switch(userID) {
case 0: // New User
data["username"] = "";
data["authentication.web"] = false;
data["authentication.pms"] = true;
data["authentication.xml"] = true;
data["authentication.m3u"] = false;
data["authentication.api"] = false;
data["defaultUser"] = false;
setTimeout(function(){
showElement("deleteUserDetail", false)
}, 1);
break;
default:
data = users[userID]["data"];
showElement("deleteUserDetail", true)
document.getElementById("deleteUserDetail").className = "delete";
break
}
var username = data["username"];
data["password"] = "";
data["confirm"] = "";
var keys = getObjKeys(data);
defaultUser = data["defaultUser"];
if (data.hasOwnProperty("defaultUser")) {
defaultUser = JSON.parse(data["defaultUser"]);
}
for (var i = 0; i < keys.length; i++) {
if(document.getElementById(keys[i])){
var td = document.getElementById(keys[i])
} else {
var td = undefined;
}
var newItem = new Object();
newItem["_element"] = "INPUT";
newItem["value"] = data[keys[i]];
newItem["name"] = keys[i];
switch(keys[i].indexOf("authentication")) {
case -1:
if (keys[i] == "password" || keys[i] == "confirm") {
newItem["type"] = "password";
} else {
newItem["type"] = "text";
}
break;
default:
newItem["type"] = "checkbox";
if (keys[i] == "authentication.web" && defaultUser == true) {
newItem["onclick"] = "return false";
}
if (data[keys[i]] == true) {
newItem["checked"] = data[keys[i]];
}
break;
}
switch(keys[i]) {
case "defaultUser":
//if (data[keys[i]] == true) {
newItem["type"] = "hidden";
//}
}
if (td != undefined) {
td.innerHTML = "";
var element = createNewElement(newItem)
//console.log(element);
td.appendChild(element);
}
}
if (defaultUser == true) {
showElement("deleteUserDetail", false)
} else {
showElement("deleteUserDetail", true)
document.getElementById("deleteUserDetail").className = "delete";
}
}
function saveUserDetail(userID, deleteUser) {
var inputs = document.getElementById("user-detail-table").getElementsByTagName("INPUT");
var newUserData = new Object();
for (var i = 0; i < inputs.length; i++) {
switch(inputs[i].type) {
case "checkbox": newUserData[inputs[i].name] = inputs[i].checked; break;
default: newUserData[inputs[i].name] = inputs[i].value; break;
}
if (inputs["username"].value.length == 0) {
inputs["username"].style.border = "solid 1px red";
return;
}
switch(userID) {
case "0":
if (inputs["password"].value.length == 0) {
console.log(inputs["password"].value.length);
inputs["password"].style.border = "solid 1px red";
return
}
break;
}
if (inputs["password"].value.length > 0) {
if (inputs["password"].value != inputs["confirm"].value) {
inputs["password"].style.border = "solid 1px red";
inputs["confirm"].style.border = "solid 1px red";
return;
}
}
}
var data = new Object();
switch(userID) {
case "0":
//data = newUserData
data["userData"] = newUserData
data["cmd"] = "saveNewUser"; break;
default:
var thisUser = new Object();
if (deleteUser == true) {
if (confirm('Delete the selected user?')) {
data["deleteUser"] = true;
} else {
showElement("popup", false);
return
}
}
thisUser[userID] = newUserData;
data["userData"] = thisUser;
data["cmd"] = "saveUserData"; break;
}
xTeVe(data);
//createUsersTable()
showElement("popup", false);
}
-569
View File
@@ -1,569 +0,0 @@
{
"mainMenu":
{
"item":
{
"playlist": "Playlist",
"pmsID": "PMS ID",
"filter": "Filter",
"xmltv": "XMLTV",
"mapping": "Mapping",
"users": "Users",
"settings": "Settings",
"log": "Log",
"logout": "Logout"
},
"headline":
{
"playlist": "Local or remote playlists",
"filter": "Filter playlist",
"xmltv": "Local or remote XMLTV files",
"mapping": "Map playlist channels to EPG channels",
"users": "User management",
"settings": "Settings",
"log": "Log",
"logout": "Logout"
}
},
"confirm":
{
"restore": "All data will be replaced with those from the backup. Should the files be restored?"
},
"alert":
{
"fileLoadingError": "File couldn't be loaded",
"invalidChannelNumber": "Invalid channel number",
"missingInput": "Missing input"
},
"button":
{
"back": "Back",
"backup": "Backup",
"bulkEdit": "Bulk Edit",
"cancel": "Cancel",
"edit": "Edit",
"delete": "Delete",
"done": "Done",
"login": "Login",
"new": "New",
"next": "Next",
"restore": "Restore",
"save": "Save",
"search": "Search",
"update": "Update",
"craeteAccount": "Create Account",
"resetLogs": "Reset Logs",
"uploadLogo": "Upload Logo"
},
"filter":
{
"table":
{
"name": "Filter Name",
"type": "Filter Type",
"filter": "Filter"
},
"custom": "Custom",
"group": "Group",
"name":
{
"title": "Filter Name",
"placeholder": "Filter name",
"description": ""
},
"description":
{
"title": "Description",
"placeholder": "Description",
"description": ""
},
"type":
{
"title": "Type",
"groupTitle": "Group Title",
"customFilter": "Custom Filter"
},
"caseSensitive":
{
"title": "Case Sensitive",
"placeholder": "",
"description": ""
},
"filterRule":
{
"title": "Filter Rule",
"placeholder": "Sport {HD} !{ES,IT}",
"description": ""
},
"filterGroup":
{
"title": "Group Title",
"placeholder": "",
"description": "Select a M3U group. (Counter)<br>Changing the group title in the M3U invalidates the filter."
},
"include":
{
"title": "Include",
"placeholder": "FHD,UHD",
"description": "Channel name must include.<br>(Comma separated) Comma means or"
},
"exclude":
{
"title": "Exclude",
"placeholder": "ES,IT",
"description": "Channel name must not contain.<br>(Comma separated) Comma means or"
}
},
"playlist":
{
"table":
{
"playlist": "Playlist",
"tuner": "Tuner",
"lastUpdate": "Last Update",
"availability": "Availability",
"type": "Type",
"streams": "Streams",
"groupTitle": "group-title",
"tvgID": "tvg-id",
"uniqueID": "Unique ID"
},
"playlistType":
{
"title": "Playlist type",
"placeholder": "",
"description": ""
},
"type":
{
"title": "Type",
"placeholder": "",
"description": ""
},
"name":
{
"title": "Name",
"placeholder": "Playlist name",
"description": ""
},
"description":
{
"title": "Description",
"placeholder": "Description",
"description": ""
},
"fileM3U":
{
"title": "M3U File",
"placeholder": "File path or URL of the M3U",
"description": ""
},
"fileHDHR":
{
"title": "HDHomeRun IP",
"placeholder": "IP address and port (192.168.1.10:5004)",
"description": ""
},
"tuner":
{
"title": "Tuner / Streams",
"placeholder": "",
"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."
}
},
"xmltv":
{
"table":
{
"guide": "Guide",
"lastUpdate": "Last Update",
"availability": "Availability",
"channels": "Channels",
"programs": "Programs"
},
"name":
{
"title": "Name",
"placeholder": "Guide name",
"description": ""
},
"description":
{
"title": "Description",
"placeholder": "Description",
"description": ""
},
"fileXMLTV":
{
"title": "XMLTV File",
"placeholder": "File path or URL of the XMLTV",
"description": ""
}
},
"mapping":
{
"table":
{
"chNo": "Ch. No.",
"logo": "Logo",
"channelName": "Channel Name",
"playlist": "Playlist",
"groupTitle": "Group Title",
"xmltvFile": "XMLTV File",
"xmltvID": "XMLTV ID",
"edit": "Edit"
},
"active":
{
"title": "Active",
"placeholder": "",
"description": ""
},
"channelName":
{
"title": "Channel Name",
"placeholder": "",
"description": ""
},
"description":
{
"title": "Channel Description",
"placeholder": "Used by the Dummy as an XML description",
"description": ""
},
"updateChannelName":
{
"title": "Update Channel Name",
"placeholder": "",
"description": ""
},
"channelLogo":
{
"title": "Logo URL",
"placeholder": "",
"description": ""
},
"updateChannelLogo":
{
"title": "Update Channel Logo",
"placeholder": "",
"description": ""
},
"epgCategory":
{
"title": "EPG Category",
"placeholder": "",
"description": ""
},
"m3uGroupTitle":
{
"title": "Group Title (xteve.m3u)",
"placeholder": "",
"description": ""
},
"xmltvFile":
{
"title": "XMLTV File",
"placeholder": "",
"description": ""
},
"xmltvChannel":
{
"title": "XMLTV Channel",
"placeholder": "",
"description": ""
}
},
"users":
{
"table":
{
"username": "Username",
"password": "Password",
"web": "WEB",
"pms": "PMS",
"m3u": "M3U",
"xml": "XML",
"api": "API"
},
"username":
{
"title": "Username",
"placeholder": "Username",
"description": ""
},
"password":
{
"title": "Password",
"placeholder": "Password",
"description": ""
},
"confirm":
{
"title": "Confirm",
"placeholder": "Password confirm",
"description": ""
},
"web":
{
"title": "Web Access",
"placeholder": "",
"description": ""
},
"pms":
{
"title": "PMS Access",
"placeholder": "",
"description": ""
},
"m3u":
{
"title": "M3U Access",
"placeholder": "",
"description": ""
},
"xml":
{
"title": "XML Access",
"placeholder": "",
"description": ""
},
"api":
{
"title": "API Access",
"placeholder": "",
"description": ""
}
},
"settings":
{
"category":
{
"general": "General",
"files": "Files",
"streaming": "Streaming",
"backup": "Backup",
"authentication": "Authentication"
},
"update":
{
"title": "Schedule for updating (Playlist, XMLTV, Backup)",
"placeholder": "0000,1000,2000",
"description": "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."
},
"api":
{
"title": "API Interface",
"description": "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>"
},
"usePlexAPI":
{
"title": "Use Plex API Refresh",
"description": "When enabled, xTeVe calls Plex directly to refresh DVR guide data after lineup or XEPG updates."
},
"plexURL":
{
"title": "Plex Server URL",
"description": "Base URL of your Plex server. Example: http://192.168.1.10:32400",
"placeholder": "http://plex-host:32400"
},
"plexToken":
{
"title": "Plex API Token",
"description": "Plex token used for authenticated API calls to refresh your DVR guide.",
"placeholder": "Plex X-Plex-Token"
},
"epgSource":
{
"title": "EPG Source",
"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)"
},
"tuner":
{
"title": "Number of Tuners",
"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."
},
"filesUpdate":
{
"title": "Updates all files at startup",
"description": "Updates all playlists, tuner and XMLTV files at startup."
},
"cacheImages":
{
"title": "Image Caching",
"description": "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."
},
"replaceEmptyImages":
{
"title": "Replace missing program images",
"description": "If the poster in the XMLTV program is missing, the channel logo will be used."
},
"xepgMissingEPGMode":
{
"title": "Missing EPG Handling",
"description": "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.",
"info_strict": "Strict (deactivate channels)",
"info_relaxed": "Relaxed (keep active / dummy guide)"
},
"streamBuffering":
{
"title": "Stream Buffer",
"description": "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",
"info_false": "No Buffer (Client connects to the streaming server)",
"info_xteve": "xTeVe connects to the streaming server",
"info_ffmpeg": "FFmpeg connects to the streaming server",
"info_vlc": "VLC connects to the streaming server"
},
"udpxy":
{
"title": "UDPxy address",
"description": "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.",
"placeholder": "host:port"
},
"ffmpegPath":
{
"title": "FFmpeg Binary Path",
"description": "Path to FFmpeg binary.",
"placeholder": "/path/to/ffmpeg"
},
"ffmpegOptions":
{
"title": "FFmpeg Options",
"description": "FFmpeg options.<br>Only change if you know what you are doing.<br>Leave blank to set default settings.",
"placeholder": "Leave blank to set default settings"
},
"vlcPath":
{
"title": "VLC / CVLC Binary Path",
"description": "Path to VLC / CVLC binary.",
"placeholder": "/path/to/cvlc"
},
"vlcOptions":
{
"title": "VLC / CVLC Options",
"description": "VLC / CVLC options.<br>Only change if you know what you are doing.<br>Leave blank to set default settings.",
"placeholder": "Leave blank to set default settings"
},
"bufferSize":
{
"title": "Buffer Size",
"description": "Buffer size in MB.<br>M3U8: If the TS segment smaller then the buffer size, the file size of the segment is used."
},
"bufferTimeout":
{
"title": "Timeout for new client connections",
"description": "The xTeVe buffer waits until new client connections are established. Helpful for fast channel switching. Value in milliseconds.",
"placeholder": "100"
},
"userAgent":
{
"title": "User Agent",
"description": "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.",
"placeholder": "xTeVe"
},
"backupPath":
{
"title": "Location for automatic backups",
"placeholder": "/mnt/data/backup/xteve/",
"description": "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."
},
"tempPath":
{
"title": "Location for the temporary files",
"placeholder": "/tmp/xteve/",
"description": "Location for the buffer files."
},
"backupKeep":
{
"title": "Number of backups to keep",
"description": "Number of backups to keep. Older backups are automatically deleted."
},
"authenticationWEB":
{
"title": "WEB Authentication",
"description": "Access to the web interface only possible with credentials."
},
"authenticationPMS":
{
"title": "PMS Authentication",
"description": "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."
},
"authenticationM3U":
{
"title": "M3U Authentication",
"description": "Downloading the xteve.m3u file via an HTTP request is only possible with authentication."
},
"authenticationXML":
{
"title": "XML Authentication",
"description": "Downloading the xteve.xml file via an HTTP request is only possible with authentication"
},
"authenticationAPI":
{
"title": "API Authentication",
"description": "Access to the API interface is only possible with authentication."
}
},
"wizard":
{
"epgSource":
{
"title": "EPG Source",
"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)"
},
"tuner":
{
"title": "Number of tuners",
"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."
},
"m3u":
{
"title": "M3U Playlist",
"placeholder": "File path or URL of the M3U",
"description": "Local or remote playlists"
},
"xmltv":
{
"title": "XMLTV File",
"placeholder": "File path or URL of the XMLTV",
"description": "Local or remote XMLTV file"
}
},
"login":
{
"failed": "User authentication failed",
"headline": "Login",
"username":
{
"title": "Username",
"placeholder": "Username"
},
"password":
{
"title": "Password",
"placeholder": "Password"
}
},
"account":
{
"failed": "Password does not match",
"headline": "Create user account",
"username":
{
"title": "Username",
"placeholder": "Username"
},
"password":
{
"title": "Password",
"placeholder": "Password"
},
"confirm":
{
"title": "Confirm",
"placeholder": "Confirm"
}
}
}
+5 -6
View File
@@ -6,8 +6,7 @@
<title>xTeVe</title>
<link rel="stylesheet" href="css/screen.css" type="text/css">
<link rel="stylesheet" href="css/base.css" type="text/css">
<script language="javascript" type="text/javascript" src="js/network_ts.js"></script>
<script language="javascript" type="text/javascript" src="js/authentication_ts.js"></script>
<script src="js/app.js"></script>
</head>
<body class="auth-screen">
@@ -17,7 +16,7 @@
<main id="box" role="main" aria-labelledby="head-text">
<div id="headline">
<h1 id="head-text" class="center">{{.login.headline}}</h1>
<h1 id="head-text" class="center">Login</h1>
</div>
<p id="err" class="errorMsg center" role="alert" aria-live="assertive" aria-atomic="true">{{.authenticationErr}}</p>
@@ -26,9 +25,9 @@
<form id="authentication" action="" method="post" aria-describedby="err" novalidate>
<label for="username">{{.login.username.title}}:</label>
<label for="username">Username:</label>
<input id="username" type="text" name="username" placeholder="Username" value="" autocomplete="username">
<label for="password">{{.login.password.title}}:</label>
<label for="password">Password:</label>
<input id="password" type="password" name="password" placeholder="Password" value="" autocomplete="current-password">
</form>
@@ -36,7 +35,7 @@
</div>
<div id="box-footer">
<input id="submit" class="" type="button" value="{{.button.login}}" aria-label="{{.button.login}}" onclick="javascript: login();">
<input id="submit" class="" type="button" value="Login" aria-label="Login" onclick="javascript: login();">
</div>
</main>