v2.0.0.0000

This commit is contained in:
marmei
2019-08-02 20:12:09 +02:00
parent e396af91cb
commit e001b06b62
85 changed files with 22786 additions and 2 deletions

58
html/configuration.html Normal file
View File

@@ -0,0 +1,58 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
</head>
<body onload="javascript: readyForConfiguration(0);">
<div id="loading" class="block">
<div class="loader"></div>
</div>
<div id="header" class="imgCenter"></div>
<div id="box">
<table id="clientInfo" class="visible">
<tr>
<td class="tdKey">Version:</td>
<td id="version" class="tdVal">&nbsp;</td>
<td class="tdKey">OS:</td>
<td id="os" class="tdVal">&nbsp;</td>
</tr>
<tr>
<td class="tdKey">UUID:</td>
<td id="uuid" class="tdVal">&nbsp;</td>
<td class="tdKey">Arch:</td>
<td id="arch" class="tdVal">&nbsp;</td>
</tr>
<tr>
<td class="tdKey">Streams:</td>
<td id="streams" class="tdVal">&nbsp;</td>
<td class="tdKey">DVR:</td>
<td id="DVR" class="tdVal">&nbsp;</td>
</tr>
</table>
<div id="headline">
<h1 id="head-text" class="center">Configuration</h1>
</div>
<p id="err" class="errorMsg center"></p>
<div id="content">
</div>
<div id="box-footer">
<input id="next" class="" type="button" name="next" value="Next" onclick="javascript: saveWizard();">
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,47 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
</head>
<body>
<div id="header" class="imgCenter"></div>
<div id="box">
<div id="headline">
<h1 id="head-text" class="center">{{.account.headline}}</h1>
</div>
<p id="err" class="errorMsg center"></p>
<div id="content">
<form id="authentication" action="/web/" method="post">
<h5>{{.account.username.title}}:</h5>
<input id="username" type="text" name="username" placeholder="Username" value="">
<h5>{{.account.password.title}}:</h5>
<input id="password" type="password" name="password" placeholder="Password" value="">
<h5>{{.account.confirm.title}}:</h5>
<input id="confirm" type="password" name="confirm" placeholder="Confirm" value="">
</form>
</div>
<div id="box-footer">
<input id="submit" class="" type="button" value="{{.button.craeteAccount}}" onclick="javascript: login();">
</div>
</div>
</body>
</html>

448
html/css/base.css Normal file
View File

@@ -0,0 +1,448 @@
* {
-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
font-family: "Arial", sans-serif;
letter-spacing: 2px;
}
/*
::-webkit-scrollbar {
display: none;
}
*/
::-webkit-scrollbar {
width: 12px;
height: 12px;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
border-radius: 5px;
}
::-webkit-scrollbar-thumb {
border-radius: 5px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0,0.6);
background-color: #444;
}
::-webkit-scrollbar-thumb:hover {
background: #333;
}
::-webkit-scrollbar-corner {
background: transparent;
}
a {
color: #00E6FF;
}
html, body {
color: #fff;
margin: 0px auto;
height: 100%;
font-size: 14px;
}
h2 {
font-size: 24px;
letter-spacing: 2px;
}
h3 {
font-size: 22px;
letter-spacing: 1px;
}
h4 {
font-size: 20px;
letter-spacing: 1px;
line-height: 1.5em;
}
h5 {
font-size: 16px;
letter-spacing: 1px;
line-height: 1.2em;
margin: 25px 0px 10px 0px;
}
hr {
border: 0;
height: 1px;
background: #333;
margin: 10px 0px;
}
p {
margin: 2px;
padding: 2px 5px;
}
pre {
margin: 0px 0px 5px 0px;
font-size: 12px;
color: #ddd;
letter-spacing: 1px;
white-space: pre-wrap;
font-family: monospace;
font-size: 12px;
font-style: normal;
font-variant: normal;
line-height: 1.6em;
}
label {
margin-bottom: 20px;
display: block;
}
li {
list-style-type: none;
background-color: #111;
padding: 10px 20px;
cursor: pointer;
border-left: solid 2px #111;
transition: all 0.3;
}
li:hover {
border-color: #00E6FF
}
select {
cursor: pointer;
width: calc(100% + 2px);
border: solid 0px #00E6FF;
border-radius: 0px;
outline: none;
color: #fff;
padding: 9px 10px;
display:block;
background-color: #333;
font-size: 14px;
margin: 5px 0px 5px 0px;
}
select:focus {
outline: none;
}
input {
-webkit-appearance: none;
margin: 5px 0px;
padding: 2.5px 10px;
outline: none;
font-size: 14px;
}
input[type=button], input[type=submit] {
cursor: pointer;
background-color: #000;
margin: 10px 10px;
padding: 10px 25px;
border: solid 0px;
border-color: #000;
border-radius: 3px;
outline: none;
color: #fff;
}
input[type=button]:focus {
outline: none;
}
input[type=button]:hover {
background-color: #00E6FF;
color: #000;
}
input[type=button]:hover.delete {
background-color: red;
color: #fff;
}
input[type=text], input[type=search], input[type=password] {
color: #fff;
width: -webkit-calc(100% - 0px);
width: -moz-calc(100% - 0px);
width: calc(100% - 0px);
outline: none;
border: solid 1px transparent;
background-color: transparent;
border-bottom-color: #555;
border-radius: 0px;
padding: 8px 10px;
}
input[type="checkbox"] {
border: solid 1px #00E6FF;
background-color: #333;
height: 25px;
width: 25px;
cursor: pointer;
/*
-webkit-appearance: checkbox;
*/
}
input[type="checkbox"]:checked {
color: #fff;
background-color: #00E6FF;
/*display: inline-block;*/
}
input[type="checkbox"]:before {
position: initial;
left: 0px;
margin-left: -4px;
content: " ";
}
input[type="checkbox"]:checked:before {
position: initial;
left: 0px;
margin-left: -3px;
content: "✓";
color: #000;
}
input[type=button].cancel {
background-color: transparent;
border-color: red;
}
input[type=button].save{
background-color: #111;
float: right;
}
input[type=button].black, input[type=submit].black{
background-color: #000;
border-color: #000;
}
input[type=button].center{
margin-right: auto;
margin-left: auto;
background-color: #000;
border-color: #000;
}
.pointer {
cursor: pointer;
}
.pointer:hover {
color: #00E6FF;
cursor: pointer;
}
.sortThis {
color: #00E6FF;
}
.w40px {
max-width: 40px;
}
.w50px {
max-width: 50px;
}
.w80px {
max-width: 80px;
}
.w150px {
max-width: 150px;
}
.w200px {
max-width: 200px;
min-width: 100px;
width: 200px;
overflow-x: hidden;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.w300px {
max-width: 300px;
}
.w220px {
max-width: 220px;
cursor: alias;
}
.footer {
font-size: 10px;
}
.center {
text-align: center;
}
.screenLogHidden {
transform: translate(0px, -110px);
}
.borderSpace {
margin-bottom: 30px;
}
.block {
}
.none {
display: none;
}
.notVisible {
height: 0px;
display: none;
opacity: 0;
border-bottom: #000 solid 0px;
}
.visible {
opacity: 1;
display: block;
border-bottom: #444 solid 1px;
padding: 10px;
}
.floatRight {
float: right;
}
.floatLeft {
float: left;
}
.menu-active {
background-color: #00E6FF;
}
.menu-notActive {
}
#branch {
display: table;
margin: auto;
color: red;
}
#interaction {
margin-bottom: 100px;
text-align: center;
border-bottom: solid 0px #777;
}
.half {
display: block;
width: 45%;
}
.menu {
border: solid 1px #00E6FF;
}
.infoMsg {
color: #aaa;
}
.errorMsg {
color: red;
}
.warningMsg {
color: yellow;
}
.debugMsg {
color: magenta;
}
.News, .Movie, .Series, .Sports, .Kids {
border-left: solid 2px
}
.News {
border-color: tomato
}
.Movie {
border-color: royalblue;
}
.Series {
border-color: gold;
}
.Sports {
border-color: yellowgreen;
}
.Kids {
border-color: mediumpurple;
}
/* Loading */
#loading {
left: 0px;
top: 0px;
z-index: 10000;
position: absolute;
background-color: rgba(0,0,0, 0.8);
margin: auto;
width: 100%;
height: 100%;
}
.loader {
border: 5px solid transparent;
border-radius: 50%;
border-top: 5px solid #00E6FF;
border-bottom: 5px solid #00E6FF;
width: 50px;
height: 50px;
-webkit-animation: spin 1.2s linear infinite;
animation: spin 1.2s linear infinite;
position: fixed;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

540
html/css/screen.css Normal file
View File

@@ -0,0 +1,540 @@
nav img {
display: block;
max-height: 20px;
max-width: 20px;
float: left;
}
nav p {
text-align: left;
padding: 0px 30px;
}
#layout {
display: block;
height: 100%;
}
.layout-left {
display: block;
min-width: 150px;
max-width: 20%;
background-color: #111;
height: inherit;
float: left;
}
.layout-right {
display: block;
background-color: #444;
}
#menu-wrapper {
height: 100%;
}
#logo {
display: block;
min-width: 180px;
width: 100%;
height: 100px;
background: url("../img/logo_w_600x200.png");
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
}
#page {
max-width: 950px;
margin: auto;
background-color: #444;
/*
height: -webkit-calc(100% - 130px);
height: -moz-calc(100% - 130px);
height: calc(100% - 130px);
*/
min-height: -webkit-calc(100% - 120px);
min-height: -moz-calc(100% - 120px);
min-height: calc(100% - 120px);
box-shadow: 0px 5px 5px #222;
}
#uiSetting {
float: right;
margin-right: 25px;
}
#box input[type=text], #box input[type=password] {
width: -webkit-calc(100% - 20px);
width: -moz-calc(100% - 20px);
width: calc(100% - 20px);
}
#box input[type=submit]{
margin: 50px auto;
}
#settings {
display: block;
padding: 10px 10px;
}
#settings h5 {
margin: 50px 0px 10px 0px;
}
#content-interaction .search {
width: 200px;
border: 1px solid #000;
padding: 9px;
background-color: #333;
margin: 10px;
float: right;
border-radius: 3px;
}
#myStreams {
position: fixed;
bottom: 0px;
background-color: #111;
width: 100%;
max-width: 950px;
/*
max-height: 100px;
*/
margin-bottom: 0px;
}
#myStreams img {
width: 4%;
padding: 2px 5px;
cursor: pointer;
float: right;
}
#settings-footer {
}
/* Wizard*/
#box {
background-color: #444;
min-height: 400px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
#box p{
padding: 10px 0px;
}
#box-footer {
margin-top: auto;
}
#box-footer {
margin: auto;
padding: 10px;
}
#headline {
background-color: #222;
border-bottom: solid 2px #222;
transition: all 0.5s;
padding: 10px 0px;
display: block;
}
#content {
display: block;
overflow: auto;
padding: 10px;
}
/* --- */
#clientInfo, #activeStreams, #inactiveStreams {
font-family: monospace;
display: block;
font-size: 9px;
background-color: #111;
color: #00E6FF;
border-bottom: solid 0px;;
padding: 0px;
letter-spacing: 1px;
overflow-x: hidden;
border-spacing: 4px 4px;
border-bottom: solid 1px #444;
}
#myStreamsBox {
position: relative;
padding: 0px;
/*height: 100px;*/
max-height: 150px;
background-color: #111;
color: white;
display:flex;
justify-content:center;
align-items:center;
}
#openStreams {
width: 20px;
height: 20px;
cursor: pointer;
float: right;
position: absolute;
right: 0px;
bottom: 0px;
background: url("../img/touch.png");
background-color: #111;
background-position: bottom right;
}
#allStreams {
width: 100%;
height: 100%;
padding: 2px;
}
#activeStreams, #inactiveStreams {
overflow-y: scroll;
width: 50%;
max-height: 100px;
float: left;
}
#activeStreams .tdKey, #inactiveStreams .tdKey {
width: 75px;
}
#inactiveStreams .tdKey {
color: red;
}
#clientInfo .tdVal, #logInfo .tdVal, #activeStreams .tdVal, #inactiveStreams .tdVal, #mappingInfo .tdVal{
color: #aaa;
white-space: inherit;
}
#box-wrapper {
display: inline-block;
width: 100%;
overflow-y: scroll;
}
#content_table, #mapping-detail-table, #content_table {
display: table;
border-collapse: collapse;
overflow-y: scroll;
width: 100%;
}
#content_table .content_table_header {
background-color: #333;
height: 50px;
border-bottom: solid 1px #111;
border-left: solid 3px #333;
cursor: auto;
}
tbody {
width: 100%;
}
.tableEllipsis {
width: 150px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#content_table img {
display: block;
max-height: 28px;
margin-left: auto;
margin-right: auto;
max-width: 30px;
}
#content_table tr{
border-left: solid 3px 444;
border-bottom: solid 1px #333;
cursor: pointer;
}
#content_table tr:hover {
background-color: #333;
}
#content_table td {
padding: 0px 2px;
}
#content_table input[type=text]{
width: 80%;
border: 0px;
background-color: #333;
margin-left: 5px;
text-align: left;
}
#content_table input[type=checkbox]{
max-width: 25px;
margin: auto;
}
.showBulk {
display: block;
}
.hideBulk {
display: none;
}
.noBulk {
}
#content_table tr.activeEPG{
border-left: solid 3px lawngreen;
}
#content_table tr.notActiveEPG{
border-left: solid 3px red;
}
#logScreen p{
white-space: pre;
font-size: 10px;
/*
line-height: 1.6em;
font-family: "Arial", sans-serif;
*/
letter-spacing: 1px;
font-family: monospace;
font-size: 12px;
font-style: normal;
font-variant: normal;
line-height: 1.6em;
}
#popup {
background-color: rgba(0, 0, 0, 0.4);
position: fixed;
left: 0px;
width: 100%;
z-index: 100;
height: 100%;
}
#mapping-detail, #user-detail, #file-detail, #popup-custom {
box-shadow: 0px 5px 40px #000;
margin-top: 20px;
margin-left: auto;
margin-right: auto;
max-width: 600px;
background-color: #222;
padding: 10px;
overflow:auto;
}
#popup-custom h3 {
text-align: center;
}
#file-detail input[type=text] {
width: -webkit-calc(100% - 20px);
width: -moz-calc(100% - 20px);
width: calc(100% - 20px);
}
#mapping-detail img {
display: block;
max-height: 30px;
margin-bottom: 20px;
margin-left: auto;
margin-right: auto;
}
#popup-custom input[type=text], #popup-custom input[type=password], #mapping-detail input[type=text], #content_settings input[type=text], #content_settings input[type=password]{
border: solid 1px;
border-color: transparent;
background-color: #333;
text-align: left;
width: -webkit-calc(100% - 20px);
width: -moz-calc(100% - 20px);
width: calc(100% - 20px);
}
#popup-custom input[type=text].notAvailable {
border-color: red;
color: #666;
cursor: not-allowed;
}
#mapping-detail-table, #user-detail-table {
display: inline-table;
width: 100%;
}
#popup-custom table, #content_settings table {
display: inline-table;
table-layout: fixed;
width: 100%;
}
#mapping-detail-table td, #user-detail-table td {
padding: 10px 0px;
}
#mapping-detail-table td.left, #user-detail-table td.left, #popup-custom td.left {
width: 38%;
}
.interaction, #interaction {
margin-top: 20px;
display: inline-flex;
float: right;
}
.interaction input[type=button], .interaction input[type=submit] {
background-color: #000;
min-width: 100px;
margin: 0px 10px;
text-align: center;
}
#notification {
display: block;
position: fixed;
right: 0px;
height: 100%;
width: 250px;
background-color: #222;
box-shadow: 0px 0px 20px #000;
}
#notification h5 {
background-color: #121212;
padding: 5px 10px 5px 10px;
}
#notification pre {
padding: 0px 10px 0px 10px;
}
#notification p {
font-size: 10 px;
margin: 0px;
padding: 0px 10px 5px 10px;
}
#notification .element {
/*padding: 0px 5px;*/
margin: 5px 5px;
border-radius: 5px;
background-color: #181818;
border-left: 10px solid green;
}
@media only screen and (min-width: 620px){
body {
width: 100%;
background-color: #444;
}
h1 {
font-size: 26px;
letter-spacing: 3px;
}
nav p {
display: block;
}
#header_config {
display: block;
height: 100px;
background: url("../img/logo_w_600x200.png");
background-repeat: no-repeat;
background-size: 300px 100px;
}
#screenLog {
margin-left: 300px;
transition: none;
background-color: transparent;
border-bottom: solid 1px transparent;
box-shadow: 0px 0px 0px #222;
}
#settings {
/*
height: -webkit-calc(100% - 100px);
height: -moz-calc(100% - 100px);
height: calc(100% - 100px);
*/
position: relative;
overflow: auto;
}
.screenLogHidden {
transform: translate(0px, 0px);
}
#box {
display: block;
min-height: 500px;
max-width: 500px;
margin: 10px auto;
background-color: #444;
box-shadow: 0px 5px 5px #222;
display: flex;
flex-direction: column;
}
#settings, #settings-footer {
}
}

3
html/css/screen2.css Normal file
View File

@@ -0,0 +1,3 @@
h1 {
color: green;
}

BIN
html/img/BC-QR.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
html/img/filter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
html/img/log.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
html/img/logo_w_600x200.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
html/img/logout.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
html/img/m3u.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
html/img/mapping.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
html/img/settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
html/img/stream-limit.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
html/img/users.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
html/img/x_ transparent.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
html/img/x_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
html/img/x_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
html/img/xmltv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

108
html/index.html Normal file
View File

@@ -0,0 +1,108 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<!---
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
-->
<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>
</head>
<body onload="javascript: PageReady();">
<div id="loading" class="none">
<div class="loader"></div>
</div>
<div id="popup" class="none">
<div id="popup-custom"></div>
</div>
<div id="layout">
<!--
<div id="notification">
<div class="element">
<h5>XEPG</h5>
<pre>11.05.2019 - 20:21</pre>
<hr>
<p>Hallo das ist ein Test. Und noch mehr Text.</p>
</div>
</div>
-->
<div id="menu-wrapper" class="layout-left">
<div id= "branch"></div>
<div id="logo"></div>
<nav id="main-menu"></nav>
</div>
<div class="layout-right">
<table id="clientInfo" class="">
<tr>
<td class="tdKey">xTeVe:</td>
<td id="version" class="tdVal">&nbsp;</td>
<td class="tdKey">OS:</td>
<td id="os" class="tdVal">&nbsp;</td>
<td class="tdKey phone">DVR IP:</td>
<td id="DVR" class="tdVal phone">&nbsp;</td>
</tr>
<tr>
<td class="tdKey">UUID:</td>
<td id="uuid" class="tdVal">&nbsp;</td>
<td class="tdKey">Arch:</td>
<td id="arch" class="tdVal">&nbsp;</td>
<td class="tdKey phone">M3U URL:</td>
<td id="m3u-url" class="tdVal phone">&nbsp;</td>
</tr>
<tr>
<td class="tdKey">Available Streams:</td>
<td id="streams" class="tdVal">&nbsp;</td>
<td class="tdKey">EPG Source:</td>
<td id="epgSource" class="tdVal">&nbsp;</td>
<td class="tdKey phone">XEPG URL:</td>
<td id="xepg-url" class="tdVal phone">&nbsp;</td>
</tr>
<tr>
<td class="tdKey">XEPG Channels:</td>
<td id="xepg" class="tdVal">&nbsp;</td>
<td class="tdKey">Errors:</td>
<td id="errors" class="tdVal">&nbsp;</td>
<td class="tdKey">Warnings:</td>
<td id="warnings" class="tdVal">&nbsp;</td>
</tr>
</table>
<div id="myStreamsBox" class="notVisible">
<div id="allStreams">
<table id="activeStreams"></table>
<table id="inactiveStreams"></table>
</div>
</div>
<div id="content" class=""></div>
</div>
</div>
</body>
</html>

42
html/js/authentication.js Normal file
View File

@@ -0,0 +1,42 @@
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;
}

View File

@@ -0,0 +1,32 @@
function login() {
var err = false;
var data = new Object();
var div = document.getElementById("content");
var form = document.getElementById("authentication");
var inputs = div.getElementsByTagName("INPUT");
console.log(inputs);
for (var i = inputs.length - 1; i >= 0; i--) {
var key = inputs[i].name;
var value = inputs[i].value;
if (value.length == 0) {
inputs[i].style.borderColor = "red";
err = true;
}
data[key] = value;
}
if (err == true) {
data = new Object();
return;
}
if (data.hasOwnProperty("confirm")) {
if (data["confirm"] != data["password"]) {
alert("sdafsd");
document.getElementById('password').style.borderColor = "red";
document.getElementById('confirm').style.borderColor = "red";
document.getElementById("err").innerHTML = "{{.account.failed}}";
return;
}
}
console.log(data);
form.submit();
}

331
html/js/base.js Normal file
View File

@@ -0,0 +1,331 @@
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
}

473
html/js/base_ts.js Normal file
View File

@@ -0,0 +1,473 @@
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;
// Menü
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}}", "xteveAutoUpdate,tuner,epgSource,api"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.files}}", "update,files.update,temp.path,cache.images,xepg.replace.missing.images"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.streaming}}", "buffer,buffer.size.kb,buffer.timeout,user.agent"));
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;
}
document.getElementById(elmID).className = cssClass;
}
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 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;
}
}
}
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;
}
return;
}
function sortTable(column) {
//console.log(columm);
if (column == COLUMN_TO_SORT) {
return;
}
var table = document.getElementById("content_table");
var tableHead = table.getElementsByTagName("TR")[0];
var tableItems = tableHead.getElementsByTagName("TD");
var sortObj = new Object();
var x, xValue;
var tableHeader;
var sortByString = false;
if (column > 0 && COLUMN_TO_SORT > 0) {
tableItems[COLUMN_TO_SORT].className = "pointer";
tableItems[column].className = "sortThis";
}
COLUMN_TO_SORT = column;
var rows = table.rows;
if (rows[1] != undefined) {
tableHeader = rows[0];
x = rows[1].getElementsByTagName("TD")[column];
for (i = 1; i < rows.length; i++) {
x = rows[i].getElementsByTagName("TD")[column];
switch (x.childNodes[0].tagName.toLowerCase()) {
case "input":
xValue = x.getElementsByTagName("INPUT")[0].value.toLowerCase();
break;
case "p":
xValue = x.getElementsByTagName("P")[0].innerText.toLowerCase();
break;
default: console.log(x.childNodes[0].tagName);
}
if (xValue == "" || 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"];
channels.forEach(function (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 {
SEARCH_MAPPING[id] = SEARCH_MAPPING[id] + data[id][key] + " ";
}
});
});
return;
}
function searchInMapping() {
var searchValue = document.getElementById("searchMapping").value;
var trs = document.getElementById("content_table").getElementsByTagName("TR");
for (var i = 1; i < trs.length; ++i) {
var id = trs[i].getAttribute("id");
var element = SEARCH_MAPPING[id];
switch (element.toLowerCase().includes(searchValue.toLowerCase())) {
case true:
document.getElementById(id).style.display = "";
break;
case false:
document.getElementById(id).style.display = "none";
break;
}
}
return;
}
function calculateWrapperHeight() {
if (document.getElementById("box-wrapper")) {
var elm = document.getElementById("box-wrapper");
var divs = new Array("myStreamsBox", "clientInfo", "content");
var elementsHeight = 0 - elm.offsetHeight;
for (var i = 0; i < divs.length; i++) {
elementsHeight = elementsHeight + document.getElementById(divs[i]).offsetHeight;
}
elm.style.height = window.innerHeight - elementsHeight + "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
html/js/classes_ts.js Normal file
View File

@@ -0,0 +1,40 @@
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
html/js/configuaration.js Normal file
View File

@@ -0,0 +1,294 @@
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;
}

140
html/js/configuration_ts.js Normal file
View File

@@ -0,0 +1,140 @@
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 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 doc = document.getElementById(this.DocumentID);
doc.innerHTML = "";
doc.appendChild(headline);
switch (key) {
case "tuner":
var text = new Array();
var values = new Array();
for (var i = 1; i <= 100; i++) {
text.push(i);
values.push(i);
}
var select = content.createSelect(text, values, "1", key);
select.setAttribute("class", "wizard");
select.id = key;
doc.appendChild(select);
description = "{{.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);
description = "{{.wizard.epgSource.description}}";
break;
case "m3u":
var input = content.createInput("text", key, "");
input.setAttribute("class", "wizard");
input.id = key;
doc.appendChild(input);
description = "{{.wizard.m3u.description}}";
break;
case "xmltv":
var input = content.createInput("text", key, "");
input.setAttribute("class", "wizard");
input.id = key;
doc.appendChild(input);
description = "{{.wizard.xmltv.description}}";
break;
default:
console.log(key);
break;
}
var pre = document.createElement("PRE");
pre.innerHTML = description;
doc.appendChild(pre);
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;
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}}"));

329
html/js/data.js Normal file
View File

@@ -0,0 +1,329 @@
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
html/js/files.js Normal file
View File

@@ -0,0 +1,379 @@
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
html/js/log.js Normal file
View File

@@ -0,0 +1,114 @@
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;
}
}

42
html/js/logs_ts.js Normal file
View File

@@ -0,0 +1,42 @@
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");
div.innerHTML = "";
var keys = getObjKeys(logs);
keys.forEach(function (logID) {
var entry = log.createLog(logs[logID]);
div.append(entry);
});
setTimeout(function () {
if (bottom == true) {
var wrapper = document.getElementById("box-wrapper");
wrapper.scrollTop = wrapper.scrollHeight;
}
}, 10);
}
function resetLogs() {
var cmd = "resetLogs";
var data = new Object();
var server = new Server(cmd);
server.request(data);
}

1466
html/js/mapping-editor.js Normal file

File diff suppressed because it is too large Load Diff

754
html/js/menu.js Normal file
View File

@@ -0,0 +1,754 @@
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);
}
}

1747
html/js/menu_ts.js Normal file

File diff suppressed because it is too large Load Diff

105
html/js/network_ts.js Normal file
View File

@@ -0,0 +1,105 @@
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();
}
switch (window.location.protocol) {
case "http:":
this.protocol = "ws://";
break;
case "https://":
this.protocol = "wss://";
break;
}
var url = this.protocol + window.location.hostname + ":" + window.location.port + "/data/" + "?Token=" + getCookie("Token");
data["cmd"] = this.cmd;
var ws = new WebSocket(url);
ws.onopen = function () {
WS_AVAILABLE = true;
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.");
SERVER_CONNECTION = false;
if (WS_AVAILABLE == false) {
alert("No websocket connection to xTeVe could be established. Check your network configuration.");
}
};
ws.onmessage = function (e) {
SERVER_CONNECTION = false;
showElement("loading", false);
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) {
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();
};
};
return Server;
}());
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2)
return parts.pop().split(";").shift();
}

442
html/js/settings_ts.js Normal file
View File

@@ -0,0 +1,442 @@
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 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 "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;
// 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 "xteveAutoUpdate":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.xteveAutoUpdate.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 "buffer":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.streamBuffering.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;
// Select
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;
}
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 "xteveAutoUpdate":
text = "{{.settings.xteveAutoUpdate.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 "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 "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;
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
html/js/users.js Normal file
View File

@@ -0,0 +1,341 @@
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);
}

419
html/lang/en.json Normal file
View File

@@ -0,0 +1,419 @@
{
"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"
},
"button":{
"back": "Back",
"backup": "Backup",
"bulkEdit": "Bulk Edit",
"cancel": "Cancel",
"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"
},
"active": {
"title": "Active",
"placeholder": "",
"description": ""
},
"channelName": {
"title": "Channel Name",
"placeholder": "",
"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": "Passoword",
"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."
},
"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>"
},
"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."
},
"xteveAutoUpdate": {
"title": "Automatic update of xTeVe",
"description": "If a new version of xTeVe is available, it will be automatically installed. The updates are downloaded from GitHub."
},
"streamBuffering": {
"title": "Stream Buffer",
"description": "- The stream is passed from xTeVe to Plex / Emby / M3U Player<br>- Small jerking of the streams can be compensated<br>- HLS / M3U8 support"
},
"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",
"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",
"description": "Local or remote playlists"
},
"xmltv": {
"title": "XMLTV File",
"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"
}
}
}

46
html/login.html Normal file
View File

@@ -0,0 +1,46 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
</head>
<body>
<div id="header" class="imgCenter"></div>
<div id="box">
<div id="headline">
<h1 id="head-text" class="center">{{.login.headline}}</h1>
</div>
<p id="err" class="errorMsg center">{{.authenticationErr}}</p>
<div id="content">
<form id="authentication" action="/web/" method="post">
<h5>{{.login.username.title}}:</h5>
<input id="username" type="text" name="username" placeholder="Username" value="">
<h5>{{.login.password.title}}:</h5>
<input id="password" type="password" name="password" placeholder="Password" value="">
</form>
</div>
<div id="box-footer">
<input id="submit" class="" type="button" value="{{.button.login}}" onclick="javascript: login();">
</div>
</div>
</body>
</html>

30
html/maintenance.html Normal file
View File

@@ -0,0 +1,30 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>xTeVe</title>
<link rel="stylesheet" href="css/screen.css" type="text/css">
<link rel="stylesheet" href="css/base.css" type="text/css">
</head>
<body>
<div id="header" class="imgCenter"></div>
<div id="box">
<div id="headline">
<h1 id="head-text" class="center">Maintenance</h1>
</div>
<div id="content">
xTeVe is updating the database, please try again later.
</div>
<div id="box-footer"></div>
</div>
</body>
</html>

BIN
html/video/stream-limit.ts Normal file

Binary file not shown.