var SERVER = new Object() var BULK_EDIT:Boolean = false var COLUMN_TO_SORT:number var SEARCH_MAPPING = new Object() var UNDO = new Object() var WS_AVAILABLE = false var ACTIVE_MENU_ID:string = "" var LAST_BULK_CHECKBOX:HTMLInputElement = null // Menü var menuItems = new Array() menuItems.push(new MainMenuItem("playlist", "Playlist", "m3u.png", "Local or remote playlists")) //menuItems.push(new MainMenuItem("pmsID", "PMS ID", "number.png", "")) menuItems.push(new MainMenuItem("filter", "Filter", "filter.png", "Filter playlist")) menuItems.push(new MainMenuItem("xmltv", "XMLTV", "xmltv.png", "Local or remote XMLTV files")) menuItems.push(new MainMenuItem("mapping", "Mapping", "mapping.png", "Map playlist channels to EPG channels")) menuItems.push(new MainMenuItem("users", "Users", "users.png", "User management")) menuItems.push(new MainMenuItem("settings", "Settings", "settings.png", "Settings")) menuItems.push(new MainMenuItem("log", "Log", "log.png", "Log")) menuItems.push(new MainMenuItem("logout", "Logout", "logout.png", "Logout")) // Kategorien für die Einstellungen var settingsCategory = new Array() settingsCategory.push(new SettingsCategoryItem("General", "tuner,epgSource,api,use_plexAPI,plex.url,plex.token"));settingsCategory.push(new SettingsCategoryItem("Files", "update,files.update,temp.path,cache.images,xepg.missing.epg.mode,xepg.replace.missing.images")) settingsCategory.push(new SettingsCategoryItem("Streaming", "buffer,udpxy,buffer.size.kb,buffer.timeout,user.agent,ffmpeg.path,ffmpeg.options,vlc.path,vlc.options")) settingsCategory.push(new SettingsCategoryItem("Backup", "backup.path,backup.keep")) settingsCategory.push(new SettingsCategoryItem("Authentication", "authentication.web,authentication.pms,authentication.m3u,authentication.xml,authentication.api")) function showPopUpElement(elm) { var allElements = new Array("popup-custom"); for (var i = 0; i < allElements.length; i++) { showElement(allElements[i], false) } showElement(elm, true) setTimeout(function(){ showElement("popup", true); }, 10); return } function showElement(elmID, type) { var cssClass:string switch(type) { case true: cssClass = "block"; break; case false: cssClass = "none"; break; } var element = document.getElementById(elmID) if (element == null) { return } element.className = cssClass; } function setConnectionState(state:string, text:string = "") { var label:string = text if (label == undefined || label.length == 0) { switch (state) { case "online": label = "Connected" break case "busy": label = "Syncing" break case "offline": label = "Offline" break default: label = "Connecting" break } } var indicator = document.getElementById("connection-indicator") if (indicator == null) { return } indicator.className = "status-" + state indicator.innerText = label } function changeButtonAction(element, buttonID, attribute) { var value = element.options[element.selectedIndex].value; document.getElementById(buttonID).setAttribute(attribute, value) } function getLocalData(dataType, id):object { 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():string[] { var channels:string[] = 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] as HTMLElement).style.display != "none") { if ((trs[i].firstChild.firstChild as HTMLInputElement).checked == true) { channels.push(trs[i].id) } } } return channels } function scheduleChannelRangeSelection(checkbox:HTMLInputElement, event:MouseEvent) { 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:HTMLInputElement, shiftPressed:boolean) { 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:HTMLInputElement[] = new Array() for (var i = 1; i < trs.length; i++) { if ((trs[i] as HTMLElement).style.display != "none") { var bulkCheckbox = (trs[i] as HTMLTableRowElement).querySelector("input.bulk") as HTMLInputElement 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:Boolean = false var trs = document.getElementById("content_table").getElementsByTagName("TR") if ((trs[0].firstChild.firstChild as HTMLInputElement).checked == true) { bulk = true } for (var i = 1; i < trs.length; i++) { if ((trs[i] as HTMLElement).style.display != "none") { switch (bulk) { case true: (trs[i].firstChild.firstChild as HTMLInputElement).checked = true break case false: (trs[i].firstChild.firstChild as HTMLInputElement).checked = false break } } } LAST_BULK_CHECKBOX = null return } function bulkEdit() { BULK_EDIT = !BULK_EDIT var className:string 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] as HTMLInputElement).checked = false } LAST_BULK_CHECKBOX = null return } function sortTable(column) { //console.log(columm); if (column == COLUMN_TO_SORT) { return; } var table = document.getElementById("content_table"); var tableHead = table.getElementsByTagName("TR")[0]; var tableItems = tableHead.getElementsByTagName("TD"); var sortObj = new Object(); var x, xValue; var tableHeader var sortByString = false if (column > 0 && COLUMN_TO_SORT > 0) { tableItems[COLUMN_TO_SORT].className = "pointer"; tableItems[column].className = "sortThis"; } COLUMN_TO_SORT = column; var rows = (table as HTMLTableElement).rows; if (rows[1] != undefined) { tableHeader = rows[0] x = rows[1].getElementsByTagName("TD")[column]; for (i = 1; i < rows.length; i++) { x = rows[i].getElementsByTagName("TD")[column]; switch(x.childNodes[0].tagName.toLowerCase()) { case "input": xValue = x.getElementsByTagName("INPUT")[0].value.toLowerCase(); break; case "p": xValue = x.getElementsByTagName("P")[0].innerText.toLowerCase(); break; default: console.log(x.childNodes[0].tagName); } if (xValue == "" || Number.isNaN(xValue)) { xValue = i sortObj[i] = rows[i]; } else { switch(isNaN(xValue)) { case false: xValue = parseFloat(xValue); sortObj[xValue] = rows[i] break; case true: sortByString = true sortObj[xValue.toLowerCase() + i] = rows[i] break; } } } while (table.firstChild) { table.removeChild(table.firstChild); } var sortValues = getObjKeys(sortObj) if (sortByString == true) { sortValues.sort() console.log(sortValues); } else { function sortFloat(a, b) { return a - b; } sortValues.sort(sortFloat); } table.appendChild(tableHeader) for (var i = 0; i < sortValues.length; i++) { table.appendChild(sortObj[sortValues[i]]) } } return } function createSearchObj() { SEARCH_MAPPING = new Object() var data = SERVER["xepg"]["epgMapping"] var channels = getObjKeys(data) var channelKeys:string[] = ["x-active", "x-channelID", "x-name", "_file.m3u.name", "x-group-title", "x-xmltv-file"] channels.forEach(id => { channelKeys.forEach(key => { if (key == "x-active") { switch (data[id][key]) { case true: SEARCH_MAPPING[id] = "online " break; case false: SEARCH_MAPPING[id] = "offline " break; } } else { if (key == "x-xmltv-file") { var xmltvFile = getValueFromProviderFile(data[id][key], "xmltv", "name") if (xmltvFile != undefined) { SEARCH_MAPPING[id] = SEARCH_MAPPING[id] + xmltvFile + " " } } else { SEARCH_MAPPING[id] = SEARCH_MAPPING[id] + data[id][key] + " " } } }) }) return } function searchInMapping() { var searchValue = (document.getElementById("searchMapping") as HTMLInputElement).value; var trs = document.getElementById("content_table").getElementsByTagName("TR") for (var i = 1; i < trs.length; ++i) { var id = trs[i].getAttribute("id") var element = SEARCH_MAPPING[id] switch (element.toLowerCase().includes(searchValue.toLowerCase())) { case true: document.getElementById(id).style.display = "" break; case false: document.getElementById(id).style.display = "none" break; } } return } function calculateWrapperHeight() { var elm = document.getElementById("box-wrapper"); var content = document.getElementById("content"); if (elm != null && content != null){ var contentTop = content.getBoundingClientRect().top var freeSpace = window.innerHeight - contentTop - 26 if (freeSpace < 180) { freeSpace = 180 } elm.style.height = freeSpace + "px"; } return } function changeChannelNumber(element) { var dbID = element.parentNode.parentNode.id var newNumber:number = parseFloat(element.value) var channelNumbers:number[] = [] var data = SERVER["xepg"]["epgMapping"] var channels = getObjKeys(data) if (isNaN(newNumber)) { alert("Invalid channel number") return } channels.forEach(id => { var channelNumber = parseFloat(data[id]["x-channelID"]) channelNumbers.push(channelNumber) }) for (var i = 0; i < channelNumbers.length; i++) { if (channelNumbers.indexOf(newNumber) == -1) { break } if (Math.floor(newNumber) == newNumber) { newNumber = newNumber + 1 } else { newNumber = newNumber + 0.1; newNumber.toFixed(1) newNumber = Math.round(newNumber * 10) / 10 } } data[dbID]["x-channelID"] = newNumber.toString() element.value = newNumber console.log(data[dbID]["x-channelID"]) if (COLUMN_TO_SORT == 1) { COLUMN_TO_SORT = -1 sortTable(1) } return } function backup() { var data = new Object() console.log("Backup data") var cmd = "xteveBackup" console.log("SEND TO SERVER"); console.log(data) var server:Server = new Server(cmd) server.request(data) return } function toggleChannelStatus(id:string) { var element:any var status:boolean if(document.getElementById("active")) { var checkbox = (document.getElementById("active") as HTMLInputElement) status = (checkbox).checked } var ids:string[] = getAllSelectedChannels() if (ids.length == 0) { ids.push(id) } ids.forEach(id => { var channel = SERVER["xepg"]["epgMapping"][id] channel["x-active"] = status switch (channel["x-active"]) { case true: if (channel["x-xmltv-file"] == "-" || channel["x-mapping"] == "-") { if (BULK_EDIT == false) { alert(channel["x-name"] + ": Missing XMLTV file / channel") checkbox.checked = false } channel["x-active"] = false } break case false: // code... break; } if (channel["x-active"] == false) { document.getElementById(id).className = "notActiveEPG" } else { document.getElementById(id).className = "activeEPG" } }); } function restore() { if (document.getElementById('upload')) { document.getElementById('upload').remove() } var restore = document.createElement("INPUT"); restore.setAttribute("type", "file"); restore.setAttribute("class", "notVisible"); restore.setAttribute("name", ""); restore.id = "upload"; document.body.appendChild(restore); restore.click(); restore.onchange = function() { var filename = (restore as HTMLInputElement).files[0].name var check = confirm("File: " + filename + "\nAll data will be replaced with those from the backup. Should the files be restored?"); if (check == true) { var reader = new FileReader(); var file = (document.querySelector('input[type=file]') as HTMLInputElement).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: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 as HTMLInputElement).files[0].name var reader = new FileReader(); var file = (document.querySelector('input[type=file]') as HTMLInputElement).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:Server = new Server(cmd) server.request(data) var updateLogo = (document.getElementById('update-icon') as HTMLInputElement) updateLogo.checked = false updateLogo.className = "changed" }; } else { alert("File could not be loaded") } upload.remove() return } } function checkUndo(key:string) { 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 0) elem.options[0] = null; var newSelectedIndex = 0; for (var i=0;i