mirror of
https://github.com/TheBinaryNinja/tvapp2.git
synced 2026-06-04 08:55:41 -04:00
508 lines
28 KiB
HTML
508 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en" data-bs-theme="dark">
|
|
<head>
|
|
<title><%= appName %> - v<%= appVersion %></title>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/css/bootstrap.min.css" integrity="sha384-SgOJa3DmI69IUzQ2PVdRZhwQ+dy64/BUtbMJw1MZ8t5HZApcHrRKUc4W0kG879m7" crossorigin="anonymous">
|
|
<link rel="stylesheet" href="css/tvapp2.min.css">
|
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
|
<script src='https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/js/bootstrap.bundle.min.js' integrity='sha384-k6d4wzSIapyDyv1kpU366/PK5hCdSbCRGRCMv+eplOQJWyd1fbcAu9OCUj5zNLiq' crossorigin='anonymous'></script>
|
|
<script src=' https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js '></script>
|
|
<script src='js/tvapp2.min.js'></script>
|
|
</head>
|
|
<body>
|
|
<!-- Header -->
|
|
<div class="header">
|
|
<nav class="navbar sticky-top container">
|
|
<div class="navbar-brand">
|
|
<i data-bs-toggle="tooltip" title="v<%= appVersion %>" class="logo fa-sharp-duotone fa-regular fa-tv" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i>
|
|
<a class="header-name" href="<%= appUrlGithub %>">TVApp2 for Docker</a>
|
|
</div>
|
|
<div class="navbar-social">
|
|
<a href=""><i id="action-health" data-bs-toggle="tooltip" title="Health" class="heart logo health fa-duotone fa-solid fa-heart" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
|
|
<a href="javascript:runResync();"><i id="action-resync" data-bs-toggle="tooltip" title="Resync" class="restart fa-solid fa-rotate" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
|
|
<a target="_blank" href="<%= appUrlDocs %>"><i data-bs-toggle="tooltip" title="Documentation" class="logo fa-duotone fa-solid fa-book-open-cover" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
|
|
<a target="_blank" href="<%= appUrlGithub %>"><i data-bs-toggle="tooltip" title="Github" class="logo fa-logos fa-github" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
|
|
<a target="_blank" href="<%= appUrlDiscord %>"><i data-bs-toggle="tooltip" title="Discord" class="logo fa-logos fa-discord" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
|
|
<!-- Header Notification: description -->
|
|
<div class="container">
|
|
<div class="container header-container">
|
|
<div class="row">
|
|
<div class="col">
|
|
<div class="about">This page displays your most recent copies of the <code><%= fileM3U %></code> playlist and <code><%= fileXML %></code> EPG guide data. Right-click each file, select <span class="text-accent">Copy Link</span> and paste the URLs within an IPTV app such as Jellyfin. The <code><%= fileXML %></code> and <code><%= fileGZP %></code> have identical guide data, however the <code><%= fileGZP %></code> is compressed and will import into your IPTV application much faster.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Header Fontawesome Icons -->
|
|
<div class="container main-container">
|
|
<table id="list" class="table table-dark table-striped">
|
|
<thead>
|
|
<tr class="d-none d-md-table-row">
|
|
<td class="icon cell-icon"></td>
|
|
<th class="file cell-file">
|
|
File Name
|
|
</th>
|
|
<th class="link cell-link">
|
|
Download
|
|
</th>
|
|
<th class="size cell-size">
|
|
Size
|
|
</th>
|
|
<th class="date cell-size">
|
|
Date
|
|
</th>
|
|
<th class="desc cell-desc">
|
|
Description
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td class="icon cell-icon">
|
|
<svg class="svg-inline--fa fa-file-lines fa-fw" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-lines" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" data-fa-i2svg="">
|
|
<path fill="currentColor" d="M64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V160H256c-17.7 0-32-14.3-32-32V0H64zM256 0V128H384L256 0zM112 256H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16z"></path>
|
|
</svg>
|
|
<!-- <i class="fa fa-fw fa-solid fa-file-lines" aria-hidden="true"></i> -->
|
|
</td>
|
|
<td class="file cell-file">
|
|
<a id="m3u-name" target="_blank" data-bs-toggle="tooltip" title="IPTV channel list"></a>
|
|
</td>
|
|
<td class="link cell-link"><a id="m3u-link" target="_blank"></a></td>
|
|
<td class="size cell-size"><span id="m3u-size"></span></td>
|
|
<td class="date cell-date"><span id="m3u-date"></span></td>
|
|
<td class="desc cell-desc">M3U playlist which lists all channels, their associated group, and logo.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="icon cell-icon">
|
|
<svg class="svg-inline--fa fa-file-xml fa-fw" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-xml" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" data-fa-i2svg="">
|
|
<path fill="currentColor" d="M0 64C0 28.7 28.7 0 64 0H224V128c0 17.7 14.3 32 32 32H384V304H176c-35.3 0-64 28.7-64 64V512H64c-35.3 0-64-28.7-64-64V64zm384 64H256V0L384 128zM192 368c0 7.3 2.2 14.4 6.2 20.4l9.8 14.7 9.8-14.7c4-6.1 6.2-13.2 6.2-20.4c0-8.8 7.2-16 16-16s16 7.2 16 16c0 13.6-4 26.9-11.6 38.2L227.2 432l17.2 25.8C252 469.1 256 482.4 256 496c0 8.8-7.2 16-16 16s-16-7.2-16-16c0-7.3-2.2-14.4-6.2-20.4L208 460.8l-9.8 14.7c-4 6.1-6.2 13.2-6.2 20.4c0 8.8-7.2 16-16 16s-16-7.2-16-16c0-13.6 4-26.9 11.6-38.2L188.8 432l-17.2-25.8C164 394.9 160 381.6 160 368c0-8.8 7.2-16 16-16s16 7.2 16 16zM448 496V368c0-8.8 7.2-16 16-16s16 7.2 16 16V480h16c8.8 0 16 7.2 16 16s-7.2 16-16 16H464c-8.8 0-16-7.2-16-16zM299.7 352.6c6.9-1.9 14.3 1 18 7.2L352 416.9l34.3-57.1c3.7-6.2 11.1-9.1 18-7.2s11.7 8.2 11.7 15.4V496c0 8.8-7.2 16-16 16s-16-7.2-16-16V425.8l-18.3 30.5c-2.9 4.8-8.1 7.8-13.7 7.8s-10.8-2.9-13.7-7.8L320 425.8V496c0 8.8-7.2 16-16 16s-16-7.2-16-16V368c0-7.2 4.8-13.5 11.7-15.4z"></path>
|
|
</svg>
|
|
<!-- <i class="fa fa-fw fa-solid fa-file-lines" aria-hidden="true"></i> -->
|
|
</td>
|
|
<td class="file cell-file">
|
|
<a id="xml-name" target="_blank" data-bs-toggle="tooltip" title="Uncompressed TV guide data"></a>
|
|
</td>
|
|
<td class="link cell-link"><a id="xml-link" target="_blank"></a></td>
|
|
<td class="size cell-size"><span id="xml-size"></span></td>
|
|
<td class="date cell-date"><span id="xml-date"></span></td>
|
|
<td class="desc cell-desc">XML / EPG guide data <code>(uncompressed)</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="icon cell-icon">
|
|
<svg class="svg-inline--fa fa-file-zipper fa-fw" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-zipper" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" data-fa-i2svg="">
|
|
<path fill="currentColor" d="M64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V160H256c-17.7 0-32-14.3-32-32V0H64zM256 0V128H384L256 0zM96 48c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16zm0 64c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16zm0 64c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16zm-6.3 71.8c3.7-14 16.4-23.8 30.9-23.8h14.8c14.5 0 27.2 9.7 30.9 23.8l23.5 88.2c1.4 5.4 2.1 10.9 2.1 16.4c0 35.2-28.8 63.7-64 63.7s-64-28.5-64-63.7c0-5.5 .7-11.1 2.1-16.4l23.5-88.2zM112 336c-8.8 0-16 7.2-16 16s7.2 16 16 16h32c8.8 0 16-7.2 16-16s-7.2-16-16-16H112z"></path>
|
|
</svg>
|
|
<!-- <i class="fa fa-fw fa-solid fa-file-lines" aria-hidden="true"></i> -->
|
|
</td>
|
|
<td class="file cell-gzp">
|
|
<a id="gzp-name" target="_blank" data-bs-toggle="tooltip" title="Compressed TV guide data"></a>
|
|
</td>
|
|
<td class="link cell-link"><a id="gzp-link" target="_blank"></a></td>
|
|
<td class="size cell-size"><span id="gzp-size"></span></td>
|
|
<td class="date cell-date"><span id="gzp-date"></span></td>
|
|
<td class="desc cell-desc">XML / EPG guide data <code>(compressed)</code></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<footer class="footer">
|
|
<div class="container" style="padding-bottom:20px;">
|
|
<div id="ntfy-restart" class="ntfy ntfy-success sticky-bottom"></div>
|
|
<div id="ntfy-firewall" class="ntfy ntfy-warning sticky-bottom"></div>
|
|
<div id="ntfy-localhost" class="ntfy ntfy-danger sticky-bottom"></div>
|
|
</div>
|
|
<div class="footer-inner">
|
|
<div class="container">
|
|
<div class="col text-center text-muted text-small text-nowrap">
|
|
<small>Developed by BinaryNinja - <a data-bs-toggle="tooltip" title="<%= appRelease %> build" href="<%= appUrlGithub %>"><%= appName %> (<%= appRelease %>)</a> - v<%= appVersion %></small><br />
|
|
<small>This utility is for educational purposes only</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- Toast Notifications -->
|
|
<!-- <button type="button" class="btn btn-primary" id="btnTestToasts">Show toast</button> -->
|
|
<div style="z-index: 9999;" class="toast position-fixed bottom-0 end-0 p-8 m-3" id="tvapp2Toast" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="true" data-bs-delay="10000">
|
|
<div class="toast-body">
|
|
<div class="d-flex gap-4">
|
|
<span><i class="fa-solid fa-circle-check fa-lg icon-success"></i></span>
|
|
<div class="d-flex flex-column flex-grow-1 gap-2">
|
|
<div class="d-flex align-items-center">
|
|
<span id="toast-title" class="fw-semibold">Toast Title</span>
|
|
<button type="button" class="btn-close btn-close-sm ms-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
</div>
|
|
<span id="toast-message">Dismiss in 6 seconds</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal -->
|
|
<div class="modal fade" id="modalTvapp2" tabindex="-1" data-bs-backdrop="static" aria-labelledby="modalTvapp2Label" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="modalTvapp2Label">Modal title</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
...
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" id="btn-secondary" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" id="btn-primary" class="btn btn-primary">Save changes</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
/*
|
|
this is test code. enable the "Show Toast" button and then uncomment this code.
|
|
|
|
document.getElementById("btnTestToasts").onclick = function()
|
|
{
|
|
var toastElList = [].slice.call(document.querySelectorAll('.toast'))
|
|
var toastList = toastElList.map(function(toastEl)
|
|
{
|
|
return new bootstrap.Toast(toastEl)
|
|
});
|
|
|
|
toastList.forEach(toast => toast.show());
|
|
console.log(toastList);
|
|
};
|
|
*/
|
|
|
|
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
|
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
|
return new bootstrap.Tooltip(tooltipTriggerEl)
|
|
})
|
|
|
|
const urlBase = window.location.origin;
|
|
const urlM3U = urlBase + '/playlist';
|
|
const urlXML = urlBase + '/epg';
|
|
const urlGZP = urlBase + '/gzip';
|
|
|
|
document.getElementById('m3u-name').textContent = '<%= fileM3U %>';
|
|
document.getElementById('m3u-name').href = urlM3U;
|
|
document.getElementById('m3u-link').textContent = urlM3U;
|
|
document.getElementById('m3u-link').href = urlM3U;
|
|
document.getElementById('m3u-size').textContent = '<%= sizeM3U %>';
|
|
document.getElementById('m3u-date').textContent = '<%= dateM3U %>';
|
|
|
|
document.getElementById('xml-name').textContent = '<%= fileXML %>';
|
|
document.getElementById('xml-name').href = urlXML;
|
|
document.getElementById('xml-link').textContent = urlXML;
|
|
document.getElementById('xml-link').href = urlXML;
|
|
document.getElementById('xml-size').textContent = '<%= sizeXML %>';
|
|
document.getElementById('xml-date').textContent = '<%= dateXML %>';
|
|
|
|
document.getElementById('gzp-name').textContent = '<%= fileGZP %>';
|
|
document.getElementById('gzp-name').href = urlGZP;
|
|
document.getElementById('gzp-link').textContent = urlGZP;
|
|
document.getElementById('gzp-link').href = urlGZP;
|
|
document.getElementById('gzp-size').textContent = '<%= sizeGZP %>';
|
|
document.getElementById('gzp-date').textContent = '<%= dateGZP %>';
|
|
</script>
|
|
|
|
<script>
|
|
|
|
/*
|
|
Document Ready
|
|
*/
|
|
|
|
$(function(){
|
|
$("[data-bs-toggle=tooltip]").tooltip({ placement: 'bottom'});
|
|
});
|
|
|
|
/*
|
|
Action > DOM Status
|
|
*/
|
|
|
|
document.addEventListener("DOMContentReady", function() {
|
|
$("#tvapp2Toast").toast();
|
|
});
|
|
|
|
/*
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
$('#tvapp2Toast').toast("show");
|
|
});
|
|
*/
|
|
|
|
/*
|
|
Notify > Localhost
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const host = window.location.hostname;
|
|
const port = window.location.port || (window.location.protocol === 'https:' ? '443' : '80');
|
|
if (host === 'localhost' || host === '127.0.0.1')
|
|
{
|
|
const msg = "<p><span class='warning'>Warning</span> If you are accessing this page via 127.0.0.1 or localhost, proxying will not work on other devices.Please load \
|
|
this page using your computer's IP address (e.g., 192.168.x.x) and port in order to access the playlist from other devices on your network.</p> \
|
|
<br> \
|
|
<p> Learn how to locate your IP address on <a href='https://youtube.com/watch?v=UAhDHXN2c6E' target = '_blank' > Windows</a> or \
|
|
<a href='https://youtube.com/watch?v=gaIYP4TZfHI' target = '_blank' > Linux</a>.</p>";
|
|
|
|
document.getElementById('ntfy-localhost').innerHTML = msg;
|
|
document.getElementById('ntfy-localhost').style.display = 'block';
|
|
} else {
|
|
document.getElementById('ntfy-localhost').style.display = 'none';
|
|
}
|
|
});
|
|
|
|
/*
|
|
Notify > Firewall
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const port = window.location.port || (window.location.protocol === 'https:' ? '443' : '80');
|
|
const msg = "<p><span class='notice'>Notice</span> Port <strong> " + port + " </strong> must be open and allowed through your <a href='https://youtu.be/zOZWlTplrcA?si=nGXrHKU4sAQsy18e&t=18 target='_blank'>Windows</a> \
|
|
or <a href='https://youtu.be/7c_V_3nWWbA?si=Hkd_II9myn-AkNnS&t=12' target='_blank'>Linux</a> OS firewall settings \
|
|
This action enables devices such as Firestick or Android to connect to the server and request the playlist through the proxy.</p>";
|
|
|
|
document.getElementById('ntfy-firewall').innerHTML = msg;
|
|
document.getElementById('ntfy-firewall').style.display = 'block';
|
|
});
|
|
|
|
/*
|
|
Notify > Restart / Resync
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const port = window.location.port || (window.location.protocol === 'https:' ? '443' : '80');
|
|
const msg = "<p><span class='success'>Success</span> Your IPTV m3u channels and xml guide data has been successfully re-synced. \
|
|
Please refresh this window to see new data</p>";
|
|
|
|
document.getElementById('ntfy-restart').innerHTML = msg;
|
|
document.getElementById('ntfy-restart').style.display = 'none';
|
|
});
|
|
|
|
/*
|
|
Set initial health check sync time
|
|
|
|
first health check runs after 10 seconds
|
|
all future health checks run after <%= healthTimer %>
|
|
*/
|
|
|
|
let timerDelayMS = 10000;
|
|
let timerStartMS = Date.now(); // returns milliseconds
|
|
const timerHealthRun = '<%= healthTimer %>'; // time in milliseconds until health check ran AFTER initial run
|
|
|
|
/*
|
|
Action > Healthcheck
|
|
*/
|
|
|
|
function runHealthCheck()
|
|
{
|
|
const toastTypeClass = [];
|
|
toastTypeClass[ 'DEFAULT' ] = 'text-bg-primary';
|
|
toastTypeClass[ 'UNHEALTHY' ] = 'text-bg-warning';
|
|
toastTypeClass[ 'HEALTHY' ] = 'text-bg-success';
|
|
toastTypeClass[ 'ERROR' ] = 'text-bg-danger';
|
|
|
|
$.ajax(
|
|
{
|
|
url: 'api/health',
|
|
type: 'GET',
|
|
data: {
|
|
internal: 1
|
|
},
|
|
beforeSend: function( data )
|
|
{
|
|
console.log('Sending health check ...')
|
|
},
|
|
success: function( data )
|
|
{
|
|
const status = data.message;
|
|
const code = data.code;
|
|
if ( status )
|
|
{
|
|
const toastClass = toastTypeClass[status.toUpperCase()];
|
|
const toastElm = document.getElementById('tvapp2Toast');
|
|
toastElm.classList.add(toastClass);
|
|
|
|
$('.toast #toast-title').html(`<%= appName %> is ${ status }`);
|
|
$('.toast #toast-message').html(`Health check returned ${ status } (${ code })`);
|
|
$('#tvapp2Toast').toast('show');
|
|
}
|
|
|
|
},
|
|
error: function( data )
|
|
{
|
|
const toastClass = toastTypeClass['ERROR'];
|
|
const toastElm = document.getElementById('tvapp2Toast');
|
|
toastElm.classList.add(toastClass);
|
|
|
|
$('.toast #toast-title').html(`Could not connect to health check api`);
|
|
$('.toast #toast-message').html(`Failed to communicate with health check api. Try restarting the docker container to restore connection.`);
|
|
$('#tvapp2Toast').toast('show');
|
|
|
|
}
|
|
}).always(function()
|
|
{
|
|
timerDelayMS = parseInt(timerHealthRun);
|
|
timerStartMS = Date.now();
|
|
|
|
setTimeout(function()
|
|
{
|
|
runHealthCheck();
|
|
}, parseInt(timerHealthRun));
|
|
}).responseText;
|
|
}
|
|
|
|
/*
|
|
Action > Do Resync
|
|
*/
|
|
|
|
function runResync()
|
|
{
|
|
$.ajax(
|
|
{
|
|
url: 'api/restart',
|
|
type: 'GET',
|
|
data: {
|
|
internal: 1
|
|
},
|
|
beforeSend: function( data )
|
|
{
|
|
const dimmer = document.createElement('div');
|
|
dimmer.setAttribute('id', 'dimmer');
|
|
dimmer.style.visibility = 'visible';
|
|
dimmer.classList.add('dimmer-in');
|
|
document.getElementsByTagName('body')[0].appendChild(dimmer);
|
|
document.getElementById('ntfy-firewall').style.display = 'none';
|
|
document.getElementById('ntfy-localhost').style.display = 'none';
|
|
document.getElementById('ntfy-restart').style.display = 'none';
|
|
|
|
const iconResync = document.getElementsByClassName('fa-rotate');
|
|
iconResync[0].classList.remove('restart');
|
|
iconResync[0].classList.add('spin');
|
|
|
|
$('.modal-content .modal-body').html('<small>The M3U and EPG data will now be re-downloaded and synced with your TVApp2 container. Afterward, this page will be refreshed automatically.</small><br /><br /><small>Please wait...</small>')
|
|
$('.modal-content .modal-title').html('Resyncing Data')
|
|
$('#modalTvapp2').modal('show');
|
|
|
|
const modalBtnPrimary = document.querySelector('#btn-primary');
|
|
modalBtnPrimary.style.display = 'none';
|
|
modalBtnPrimary.style.visibility= 'hidden';
|
|
|
|
},
|
|
success: function( data )
|
|
{
|
|
|
|
/*
|
|
On successful restart, wait 1 second, remove dimmer, reload page in 5 seconds
|
|
*/
|
|
|
|
setTimeout( () =>
|
|
{
|
|
document.getElementById('ntfy-restart').style.display = 'block'
|
|
const dimmer = document.getElementById('dimmer');
|
|
dimmer.classList.remove('dimmer-in');
|
|
dimmer.classList.add('dimmer-out');
|
|
dimmer.remove();
|
|
|
|
setTimeout( function()
|
|
{
|
|
const iconResync = document.getElementsByClassName('fa-rotate'); // resync favicon
|
|
iconResync[0].classList.remove('spin'); // stop spinning
|
|
iconResync[0].classList.add('restart'); // normal spinner class
|
|
document.location.reload() // reload page
|
|
}, 5000 ); // how long until refresh page
|
|
}, 1000 ); // how long until dimmer is removed / reload page activated (also on delay)
|
|
}
|
|
});
|
|
}
|
|
|
|
/*
|
|
Health check > Show time remaining as tooltip
|
|
*/
|
|
|
|
function runTooltipCountdown( )
|
|
{
|
|
let timerHours, timerMins, timerRemainsLS;
|
|
|
|
function twoDigits( n )
|
|
{
|
|
return (n <= 9 ? "0" + n : n);
|
|
}
|
|
|
|
/*
|
|
Update Tooltip Countdown
|
|
|
|
MS = milliseconds
|
|
LS = long string (Wed Dec 31 1969 10:01:42 (Coordinated Universal Time))
|
|
*/
|
|
|
|
function updateTooltipCountdown()
|
|
{
|
|
const timerElapsedMS = Date.now() - timerStartMS; // ( 2091 )
|
|
const timerRemainsMS = timerDelayMS - timerElapsedMS; // ( 7909 ) divide by 1000 for seconds
|
|
|
|
timerRemainsLS = new Date( timerRemainsMS ); // (Wed Dec 31 1969 10:01:42 (Coordinated Universal Time))
|
|
timerHours = timerRemainsLS.getUTCHours(); // ( 0 )
|
|
timerMins = timerRemainsLS.getUTCMinutes(); // ( 9 )
|
|
const timeLeft = (timerHours ? timerHours + ':' + twoDigits( timerMins ) : timerMins) + ':' + twoDigits( timerRemainsLS.getUTCSeconds() );
|
|
|
|
jQuery(function($)
|
|
{
|
|
$(document.body).tooltip({ selector: "[title]" });
|
|
$('#action-health')
|
|
.attr('data-original-title', `Health check in ${ timeLeft }`)
|
|
.attr('aria-label', `Health check in ${ timeLeft }`)
|
|
.attr('data-bs-original-title', `Health check in ${ timeLeft }`)
|
|
});
|
|
|
|
const Heart = document.getElementsByClassName('fa-heart');
|
|
Heart[0].style.color = '#FFF';
|
|
|
|
setTimeout( function()
|
|
{
|
|
const Heart = document.getElementsByClassName('fa-heart');
|
|
Heart[0].style.color = '#FFF';
|
|
|
|
setTimeout( function()
|
|
{
|
|
Heart[0].style.color = '#FF6593';
|
|
}, timerRemainsLS.getUTCMilliseconds() + 100 );
|
|
|
|
}, timerRemainsLS.getUTCMilliseconds() + 500 );
|
|
|
|
|
|
setTimeout( function()
|
|
{
|
|
updateTooltipCountdown();
|
|
}, timerRemainsLS.getUTCMilliseconds() + 500 );
|
|
}
|
|
|
|
updateTooltipCountdown();
|
|
}
|
|
|
|
/*
|
|
Action > Healthcheck > Initialize
|
|
*/
|
|
|
|
setTimeout( function() { runHealthCheck(); }, timerDelayMS );
|
|
|
|
/*
|
|
Action > Tooltip Resync Timers
|
|
*/
|
|
|
|
runTooltipCountdown( );
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|