class SettingsCategory { DocumentID:string = "content_settings" createCategoryHeadline(value:string):any { var element = document.createElement("H4") element.innerHTML = value return element } createHR():any { var element = document.createElement("HR") return element } createSettings(settingsKey:string):any { var setting = document.createElement("TR") var content:PopupContent = new PopupContent() var data = SERVER["settings"][settingsKey] switch (settingsKey) { // Texteingaben case "update": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Schedule for updating (Playlist, XMLTV, Backup)" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "update", data.toString()) input.setAttribute("placeholder", "0000,1000,2000") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "backup.path": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Location for automatic backups" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "backup.path", data) input.setAttribute("placeholder", "/mnt/data/backup/xteve/") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "temp.path": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Location for the temporary files" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "temp.path", data) input.setAttribute("placeholder", "/tmp/xteve/") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "user.agent": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "User Agent" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "user.agent", data) input.setAttribute("placeholder", "xTeVe") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "plex.url": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Plex Server URL" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "plex.url", data) input.setAttribute("placeholder", "http://plex-host:32400") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "plex.token": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Plex API Token" + ":" var tdRight = document.createElement("TD") var input = content.createInput("password", "plex.token", data) input.setAttribute("placeholder", "Plex X-Plex-Token") input.setAttribute("autocomplete", "off") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "buffer.timeout": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Timeout for new client connections" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "buffer.timeout", data) input.setAttribute("placeholder", "100") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "ffmpeg.path": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "FFmpeg Binary Path" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "ffmpeg.path", data) input.setAttribute("placeholder", "/path/to/ffmpeg") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "ffmpeg.options": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "FFmpeg Options" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "ffmpeg.options", data) input.setAttribute("placeholder", "Leave blank to set default settings") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "vlc.path": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "VLC / CVLC Binary Path" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "vlc.path", data) input.setAttribute("placeholder", "/path/to/cvlc") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "vlc.options": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "VLC / CVLC Options" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "vlc.options", data) input.setAttribute("placeholder", "Leave blank to set default settings") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break // Checkboxen case "authentication.web": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "WEB Authentication" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "authentication.pms": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "PMS Authentication" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "authentication.m3u": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "M3U Authentication" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "authentication.xml": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "XML Authentication" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "authentication.api": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "API Authentication" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "files.update": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Updates all files at startup" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "cache.images": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Image Caching" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "xepg.replace.missing.images": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Replace missing program images" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "api": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "API Interface" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "use_plexAPI": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Use Plex API Refresh" + ":" var tdRight = document.createElement("TD") var input = content.createCheckbox(settingsKey) input.checked = data input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break // Select case "xepg.missing.epg.mode": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Missing EPG Handling" + ":" var tdRight = document.createElement("TD") var text:any[] = ["Strict (deactivate channels)", "Relaxed (keep active / dummy guide)"] var values:any[] = ["strict", "relaxed"] var select = content.createSelect(text, values, data, settingsKey) select.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(select) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "tuner": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Number of Tuners" + ":" var tdRight = document.createElement("TD") var text = new Array() var values = new Array() for (var i = 1; i <= 100; i++) { text.push(i) values.push(i) } var select = content.createSelect(text, values, data, settingsKey) select.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(select) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "epgSource": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "EPG Source" + ":" var tdRight = document.createElement("TD") var text:any[] = ["PMS", "XEPG"] var values:any[] = ["PMS", "XEPG"] var select = content.createSelect(text, values, data, settingsKey) select.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(select) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "backup.keep": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Number of backups to keep" + ":" var tdRight = document.createElement("TD") var text:any[] = ["5", "10", "20", "30", "40", "50"] var values:any[] = ["5", "10", "20", "30", "40", "50"] var select = content.createSelect(text, values, data, settingsKey) select.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(select) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "buffer.size.kb": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Buffer Size" + ":" var tdRight = document.createElement("TD") var text:any[] = ["0.5 MB", "1 MB", "2 MB", "3 MB", "4 MB", "5 MB", "6 MB", "7 MB", "8 MB"] var values:any[] = ["512", "1024", "2048", "3072", "4096", "5120", "6144", "7168", "8192"] var select = content.createSelect(text, values, data, settingsKey) select.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(select) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "buffer": var tdLeft = document.createElement("TD") tdLeft.innerHTML = "Stream Buffer" + ":" var tdRight = document.createElement("TD") var text:any[] = ["No Buffer (Client connects to the streaming server)", "xTeVe: (xTeVe connects to the streaming server)", "FFmpeg: (FFmpeg connects to the streaming server)", "VLC: (VLC connects to the streaming server)"] var values:any[] = ["-", "xteve", "ffmpeg", "vlc"] var select = content.createSelect(text, values, data, settingsKey) select.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(select) setting.appendChild(tdLeft) setting.appendChild(tdRight) break case "udpxy": var tdLeft = document.createElement("TD"); tdLeft.innerHTML = "UDPxy address" + ":" var tdRight = document.createElement("TD") var input = content.createInput("text", "udpxy", data) input.setAttribute("placeholder", "host:port") input.setAttribute("onchange", "javascript: this.className = 'changed'") tdRight.appendChild(input) setting.appendChild(tdLeft) setting.appendChild(tdRight) break } return setting } createDescription(settingsKey:string):any { var description = document.createElement("TR") var text:string switch (settingsKey) { case "authentication.web": text = "Access to the web interface only possible with credentials." break case "authentication.m3u": text = "Downloading the xteve.m3u file via an HTTP request is only possible with authentication." break case "authentication.pms": text = "Plex requests are only possible with authentication.
Warning!!! After activating this function xTeVe must be delete in the PMS DVR settings and set up again." break case "authentication.xml": text = "Downloading the xteve.xml file via an HTTP request is only possible with authentication" break case "authentication.api": if (SERVER["settings"]["authentication.web"] == true) { text = "Access to the API interface is only possible with authentication." } break case "backup.keep": text = "Number of backups to keep. Older backups are automatically deleted." break case "backup.path": text = "Before any update of the provider data by the schedule, xTeVe creates a backup. The path for the automatic backups can be changed. xTeVe requires write permission for this folder." break case "temp.path": text = "Location for the buffer files." break case "buffer": text = "Functions of the buffer:
- The stream is passed from xTeVe, FFmpeg or VLC to Plex, Emby or M3U Player
- Small jerking of the streams can be compensated
- HLS / M3U8 support
- RTP / RTPS support (only FFmpeg or VLC)
- Re-streaming
- Separate tuner limit for each playlist" break case "buffer.size.kb": text = "Buffer size in MB.
M3U8: If the TS segment smaller then the buffer size, the file size of the segment is used." break case "buffer.timeout": text = "The xTeVe buffer waits until new client connections are established. Helpful for fast channel switching. Value in milliseconds." break case "user.agent": text = "User Agent for HTTP requests. For every HTTP connection, this value is used for the user agent. Should only be changed if xTeVe is blocked." break case "plex.url": text = "Base URL of your Plex server. Example: http://192.168.1.10:32400" break case "plex.token": text = "Plex token used for authenticated API calls to refresh your DVR guide." break case "ffmpeg.path": text = "Path to FFmpeg binary." break case "ffmpeg.options": text = "FFmpeg options.
Only change if you know what you are doing.
Leave blank to set default settings." break case "vlc.path": text = "Path to VLC / CVLC binary." break case "vlc.options": text = "VLC / CVLC options.
Only change if you know what you are doing.
Leave blank to set default settings." break case "epgSource": text = "PMS:
- Use EPG data from Plex or Emby

XEPG:
- Use of one or more XMLTV files
- Channel management
- M3U / XMLTV export (HTTP link for IPTV apps)" break case "tuner": text = "Number of parallel connections that can be established to the provider.
Available for: Plex, Emby (HDHR), M3U (with active buffer).
After a change, xTeVe must be delete in the Plex / Emby DVR settings and set up again." break case "update": text = "Time in 24 hour format (0800 = 8:00 am). More times can be entered comma separated. Leave this field empty if no updates are to be carried out." break case "api": text = "Via API interface it is possible to send commands to xTeVe. API documentation is here" break case "use_plexAPI": text = "When enabled, xTeVe calls Plex directly to refresh DVR guide data after lineup or XEPG updates." break case "files.update": text = "Updates all playlists, tuner and XMLTV files at startup." break case "cache.images": text = "All images from the XMLTV file are cached, allowing faster rendering of the grid in the client.
Downloading the images may take a while and will be done in the background." break case "xepg.replace.missing.images": text = "If the poster in the XMLTV program is missing, the channel logo will be used." break case "xepg.missing.epg.mode": text = "Strict: channels are deactivated when XMLTV mappings disappear.
Relaxed: channels stay active with last-known mappings and fall back to a dummy guide whenever guide data cannot be resolved." break case "udpxy": text = "The address of your UDPxy server. If set, and the channel URLs in the m3u is multicast, xTeVe will rewrite it so that it is accessed via the UDPxy service." break default: text = "" break } var tdLeft = document.createElement("TD") tdLeft.innerHTML = "" var tdRight = document.createElement("TD") var pre = document.createElement("PRE") pre.innerHTML = text tdRight.appendChild(pre) description.appendChild(tdLeft) description.appendChild(tdRight) return description } } class SettingsCategoryItem extends SettingsCategory { headline:string settingsKeys:string constructor(headline:string, settingsKeys:string) { super() this.headline = headline this.settingsKeys = settingsKeys } createCategory():void { var headline = this.createCategoryHeadline(this.headline) var settingsKeys = this.settingsKeys var doc = document.getElementById(this.DocumentID) doc.appendChild(headline) // Tabelle für die Kategorie erstellen var table = document.createElement("TABLE") var keys = settingsKeys.split(",") keys.forEach(settingsKey => { switch (settingsKey) { case "authentication.pms": case "authentication.m3u": case "authentication.xml": case "authentication.api": if (SERVER["settings"]["authentication.web"] == false) { break } default: var item = this.createSettings(settingsKey) var description = this.createDescription(settingsKey) table.appendChild(item) table.appendChild(description) break } }); doc.appendChild(table) doc.appendChild(this.createHR()) } } function showSettings() { console.log("SETTINGS"); for (let i = 0; i < settingsCategory.length; i++) { settingsCategory[i].createCategory() } } function saveSettings() { console.log("Save Settings"); var cmd = "saveSettings" var div = document.getElementById("content_settings") var settings = div.getElementsByClassName("changed") var newSettings = new Object(); for (let i = 0; i < settings.length; i++) { var name:string var value:any switch (settings[i].tagName) { case "INPUT": switch ((settings[i] as HTMLInputElement).type) { case "checkbox": name = (settings[i] as HTMLInputElement).name value = (settings[i] as HTMLInputElement).checked newSettings[name] = value break case "text": name = (settings[i] as HTMLInputElement).name value = (settings[i] as HTMLInputElement).value switch (name) { case "update": value = value.split(",") value = value.filter(function(e:any) { return e}) break case "buffer.timeout": value = parseFloat(value) } newSettings[name] = value break } break case "SELECT": name = (settings[i] as HTMLSelectElement).name value = (settings[i] as HTMLSelectElement).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:Server = new Server(cmd) server.request(data) }