mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-07-29 16:29:19 +02:00
change some stuff
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Unauthorized - FM-DX Webserver</title>
|
||||
<link href="css/entry.css" type="text/css" rel="stylesheet">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" type="text/css"
|
||||
rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"
|
||||
integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<link rel="icon" type="image/png" href="favicon2.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper" class="auto">
|
||||
<div class="panel-100 no-bg">
|
||||
<img class="top-10" src="./images/openradio_logo_neutral.png" height="64px">
|
||||
<h2 class="text-monospace text-light text-center">[403]</h2>
|
||||
|
||||
<div class="panel-100 p-10">
|
||||
<br>
|
||||
<i class="text-big fa-solid fa-exclamation-triangle color-4"></i>
|
||||
<p>
|
||||
The service has rejected you.<br>
|
||||
Please try again later.</p>
|
||||
|
||||
<% if (reason) { %>
|
||||
<p><strong>Reason:</strong> <%= reason %></p>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/settings.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,20 @@
|
||||
<%
|
||||
let options = [];
|
||||
|
||||
const profile = Array.isArray(tunerProfiles)
|
||||
? tunerProfiles.find((item) => item.id === device)
|
||||
: null;
|
||||
|
||||
if (Array.isArray(profile?.fmBandwidths)) {
|
||||
options = profile.fmBandwidths;
|
||||
}
|
||||
%>
|
||||
|
||||
<div class="no-bg dropdown data-bw <%= cssClass %>" id="<%= id %>">
|
||||
<input type="text" placeholder="Auto" readonly tabindex="0">
|
||||
<ul class="options <%= cssClassOptions %>" tabindex="-1">
|
||||
<% options.forEach(function(opt) { %>
|
||||
<li class="option" tabindex="0" data-value="<%= opt.value %>" <%= opt.value2 !== undefined ? 'data-value2="' + opt.value2 + '"' : '' %>><%= opt.label %></li>
|
||||
<% }); %>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,77 @@
|
||||
<%
|
||||
switch (component) {
|
||||
/**
|
||||
* Text input & password input tag
|
||||
* @param label Label text
|
||||
* @param id Unique element ID
|
||||
* @param password If true, the element will be rendered as a password instead of plain text input
|
||||
* @param placeholder Placeholder text
|
||||
* @param cssClass Custom CSS class if needed
|
||||
*/
|
||||
case 'text':
|
||||
%>
|
||||
<div class="form-group">
|
||||
<label for="<%= id %>"><%= label %></label>
|
||||
<input class="input-text <%= cssClass %>"
|
||||
type="<%= (typeof password !== 'undefined' && password == true) ? 'password' : 'text' %>"
|
||||
placeholder="<%= typeof placeholder !== 'undefined' ? placeholder : '' %>"
|
||||
name="<%= id %>"
|
||||
id="<%= id %>">
|
||||
</div>
|
||||
<%
|
||||
break;
|
||||
|
||||
/**
|
||||
* Checkbox (toggle button) tag
|
||||
* @param label Label text
|
||||
* @param id Unique element ID
|
||||
* @param iconClass Additional CSS Class for the icon inside the button
|
||||
* @param cssClass Custom CSS class if needed
|
||||
*/
|
||||
case 'checkbox':
|
||||
%>
|
||||
<div class="form-group">
|
||||
<div class="switch flex-container flex-phone flex-phone-column flex-phone-center">
|
||||
<input type="checkbox" tabindex="0" id="<%= id %>" aria-label="<%= label %>" />
|
||||
<label for="<%= id %>"></label>
|
||||
<span class="text-smaller text-uppercase text-bold color-4 p-10"><%= label %></span>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
break;
|
||||
|
||||
/**
|
||||
* Dropdown menus
|
||||
* @param inputId Unique ID for the hidden text input of the dropdown
|
||||
* @param id Unique element ID
|
||||
* @param iconClass Additional CSS Class for the icon next to the title (if you want to have one)
|
||||
* @param placeholder Placeholder text
|
||||
* @param cssClass Custom CSS class for the dropdown menu itself if needed
|
||||
*/
|
||||
case 'dropdown':
|
||||
%>
|
||||
<div class="form-group">
|
||||
<label for="<%= inputId %>"><i class="<%= typeof iconClass !== 'undefined' ? iconClass : '' %>"></i> <%= label %></label>
|
||||
<div class="dropdown <%= cssClass %>" id="<%= id %>" style="margin-right: 0;">
|
||||
<input type="text" placeholder="<%= placeholder %>" id="<%= inputId %>" readonly tabindex="0">
|
||||
<ul class="options" tabindex="0">
|
||||
<%
|
||||
options.forEach(function(option) {
|
||||
%>
|
||||
<li class="option" tabindex="0" data-value="<%= option.value %>"><%= option.label %></li>
|
||||
<%
|
||||
});
|
||||
%>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
break;
|
||||
|
||||
default:
|
||||
%>
|
||||
<p>Unknown component: <%= component %></p>
|
||||
<%
|
||||
break;
|
||||
}
|
||||
%>
|
||||
+583
@@ -0,0 +1,583 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title><%= tunerName %> - FM-DX Webserver</title>
|
||||
<link href="css/entry.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/flags.min.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/libs/fontawesome.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/libs/jquery-ui.min.css" type="text/css" rel="stylesheet">
|
||||
<!--<link href="css/libs/jquery-ui.theme.min.css" type="text/css" rel="stylesheet">-->
|
||||
<script src="js/libs/jquery.min.js"></script>
|
||||
<script src="js/libs/jquery-ui.min.js"></script>
|
||||
<script src="js/libs/chart.umd.min.js"></script>
|
||||
<script src="js/libs/luxon.min.js"></script>
|
||||
<script src="js/libs/chartjs-adapter-luxon.umd.min.js"></script>
|
||||
<script src="js/libs/chartjs-plugin-streaming.min.js"></script>
|
||||
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<meta property="og:title" content="FM-DX WebServer [<%= tunerName %>]">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:image" content="https://fmdx.org/img/webserver_icon.png">
|
||||
<meta property="og:description" content="Server description: <%= tunerDescMeta %>.">
|
||||
|
||||
<!-- 3LAS Scripts for Audio streaming -->
|
||||
<script src="js/3las/util/3las.helpers.js"></script>
|
||||
<script src="js/3las/util/3las.logging.js"></script>
|
||||
<script src="js/3las/fallback/3las.liveaudioplayer.js"></script>
|
||||
<script src="js/3las/fallback/3las.formatreader.js"></script>
|
||||
<script src="js/3las/fallback/formats/3las.formatreader.mpeg.js"></script>
|
||||
<script src="js/3las/fallback/formats/3las.formatreader.wav.js"></script>
|
||||
<script src="js/3las/util/3las.websocketclient.js"></script>
|
||||
<script src="js/3las/fallback/3las.fallback.js"></script>
|
||||
<script src="js/3las/3las.js"></script>
|
||||
<script src="js/3las/main.js"></script>
|
||||
<script type="text/javascript">
|
||||
window.addEventListener('load', Init, false);
|
||||
document.ontouchmove = function(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper-outer dashboard-panel" style="padding-top: 20px; z-index: 10; position: relative;">
|
||||
<div class="panel-100-real m-0 flex-container bg-phone flex-phone-column" style="min-height: 64px; max-width: 1160px; margin-top: 10px;align-items: center; justify-content: space-between; padding-left: 20px;padding-right: 10px;">
|
||||
<h1 id="tuner-name" class="text-left flex-container flex-phone flex-center" style="padding-bottom: 3px; padding-right: 5px;height: 64px;">
|
||||
<span class="text-200-px" style="max-width: 450px;padding-right: 10px;"><%= tunerName %></span> <i class="fa-solid fa-chevron-down" style="font-size: 15px;"></i>
|
||||
</h1>
|
||||
<% if(!publicTuner || tunerLock) { %>
|
||||
<div class="tuner-status p-10 color-3">
|
||||
<% if (!publicTuner) { %><i class="fa-solid fa-key pointer tooltip fa-lg" aria-label="Only people with tune password can tune." data-tooltip="Only people with tune password can tune."></i>
|
||||
<% } if (tunerLock) { %><i class="fa-solid fa-lock pointer tooltip fa-lg" aria-label="Tuner is currently locked to admin." data-tooltip="Tuner is currently locked to admin."></i>
|
||||
<% } %>
|
||||
</div>
|
||||
<% } %>
|
||||
<div class="flex-container flex-phone" style="flex: 1;overflow-x: auto;align-items: center;">
|
||||
<div class="plugin-list scroll-left">
|
||||
<i class="fa-solid fa-chevron-left fa-lg color-4"></i>
|
||||
</div>
|
||||
<div class="dashboard-panel-plugin-list flex-container hide-phone" style="flex: 1;overflow-x: auto;">
|
||||
<div class="flex-container scrollable-container"></div>
|
||||
</div>
|
||||
<div class="plugin-list scroll-right">
|
||||
<i class="fa-solid fa-chevron-right fa-lg color-4"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left: auto;" class="dashboard-panel-plugin-content"></div>
|
||||
<div>
|
||||
<button class="users-online-container hide-phone" aria-label="Online users"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
|
||||
<% if (chatEnabled) { %>
|
||||
<button class="chatbutton hide-phone" aria-label="Chatbox"><i class="fa-solid fa-message"></i></button>
|
||||
<% } %>
|
||||
<button aria-label="Settings" class="hide-phone settings"><i class="fa-solid fa-bars"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="dashboard-panel-description" class="hidden-panel">
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="tuner-desc">
|
||||
<%- tunerDesc %>
|
||||
<% if(tuningLimit && tuningLimit == true){ %>
|
||||
<br><span class="text-small">Limit: <span class="color-4"><%= tuningLowerLimit %> MHz - <%= tuningUpperLimit %> MHz</span></span><br>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<div class="flex-phone" style="margin-left: auto;flex-direction: row-reverse;justify-content: space-around;min-width: 200px;">
|
||||
<div class="flex-container flex-phone" style="text-align: right;justify-content: right;align-items: center; height: 64px;">
|
||||
<div>
|
||||
<span class="">Device</span><br>
|
||||
<span class="text-small color-4">
|
||||
<% if (device == 'tef') { %>TEF668x<% } %>
|
||||
<% if (device == 'xdr') { %>Sony XDR<% } %>
|
||||
<% if (device == 'sdr') { %>SDR<% } %>
|
||||
<% if (device == 'si47xx') { %>SI47XX<% } %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="color-3 m-10 text-medium">
|
||||
<i class="fa-solid fa-fw fa-radio"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container flex-phone" style="text-align: right;justify-content: right;align-items: center; height: 64px;">
|
||||
<div>
|
||||
<span class="">Server time</span><br>
|
||||
<span class="text-small color-4" id="server-time"></span>
|
||||
</div>
|
||||
<div class="color-3 m-10 text-medium">
|
||||
<i class="fa-solid fa-fw fa-stopwatch"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="width: 1px;background: var(--color-2);" class="m-10 hide-phone"></div>
|
||||
|
||||
<div>
|
||||
<% const presets = [1, 2, 3, 4]; %>
|
||||
|
||||
<div style="height: 64px;" class="flex-center flex-phone">
|
||||
<% presets.forEach(preset => { %>
|
||||
<button class="no-bg color-4 hover-brighten" id="preset<%= preset %>" style="padding: 6px; width: 64px; min-width: 64px;">
|
||||
<i class="fa-solid fa-wave-square fa-lg top-10"></i><br>
|
||||
<span style="font-size: 10px; color: var(--color-text);" id="preset<%= preset %>-text"></span>
|
||||
</button>
|
||||
<% }); %>
|
||||
</div>
|
||||
|
||||
<div class="flex-container flex-phone" style="align-items: center; height: 64px;">
|
||||
<div class="color-3 m-10 text-medium">
|
||||
<i class="fa-solid fa-fw fa-user-tie"></i>
|
||||
</div>
|
||||
<div>
|
||||
<span class="">Owner contact</span><br>
|
||||
<span class="text-small color-4 text-200-px tooltip" data-tooltip="<%= ownerContact %>" data-tooltip-placement="bottom"><%= ownerContact %></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper-outer main-content" style="z-index: 100;">
|
||||
<div id="wrapper">
|
||||
<div class="canvas-container hide-phone">
|
||||
<canvas id="signal-canvas"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-100 no-bg" style="margin-top: 0; margin-left: 0;">
|
||||
<div class="flex-container">
|
||||
<div class="panel-75 flex-container no-bg">
|
||||
<div class="panel-10 no-bg h-100 m-0 m-right-20 hide-phone" style="width: 100px;margin-right: 20px !important;">
|
||||
<button class="playbutton" aria-label="Play / Stop"><i class="fa-solid fa-play fa-lg"></i></button>
|
||||
</div>
|
||||
<div class="panel-100 m-0 hover-brighten flex-center tooltip" id="ps-container" style="height: 90px;" data-tooltip="Clicking on the RDS PS will copy the RDS info into the clipboard.">
|
||||
<span class="text-big" id="data-ps"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="flags-container-desktop" class="panel-33 user-select-none">
|
||||
<h2 class="show-phone">
|
||||
<div class="data-pty color-4"></div>
|
||||
</h2>
|
||||
<h3 style="margin-top:0;margin-bottom:0;" class="text-color-default flex-center">
|
||||
<span class="data-tp">TP</span>
|
||||
<span style="margin-left: 15px;" class="data-ta">TA</span>
|
||||
<div style="display:inline-block">
|
||||
<span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span>
|
||||
</div>
|
||||
<span class="pointer stereo-container" style="position: relative; margin-left: 20px;" role="button" aria-label="Stereo / Mono toggle" tabindex="0">
|
||||
<div class="circle-container">
|
||||
<div class="circle data-st circle1"></div>
|
||||
<div class="circle data-st circle2"></div>
|
||||
</div>
|
||||
<span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
|
||||
</span>
|
||||
<span style="margin-left: 15px;" class="data-ms">MS</span>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-33 hover-brighten tooltip no-bg-phone" id="pi-code-container" data-tooltip="Clicking on the PI code will show the current station on a map.">
|
||||
<h2 class="signal-heading">PI CODE</h2>
|
||||
<div class="text-small text-gray highest-signal-container">
|
||||
<span id="data-regular-pi"> </span>
|
||||
</div>
|
||||
<span id="data-pi" class="text-big text-uppercase"></span>
|
||||
</div>
|
||||
|
||||
<div class="panel-33 hover-brighten no-bg-phone" id="freq-container">
|
||||
<h2>FREQUENCY</h2>
|
||||
<span id="data-frequency" class="text-big"></span>
|
||||
</div>
|
||||
|
||||
<div class="panel-33 no-bg-phone">
|
||||
<h2 class="signal-heading">SIGNAL</h2>
|
||||
<div class="text-small text-gray highest-signal-container">
|
||||
<i class="fa-solid fa-arrow-up"></i>
|
||||
<span id="data-signal-highest"></span>
|
||||
<% if (device == 'sdr') { %> <span>dB SNR</span> <% } else { %> <span class="signal-units"></span> <% } %>
|
||||
</div>
|
||||
<div class="text-big">
|
||||
<span id="data-signal"></span><!--
|
||||
--><span id="data-signal-decimal" class="text-medium-big" style="opacity:0.7;"></span>
|
||||
<% if (device == 'sdr') { %> <span class="text-medium">dB SNR</span> <% } else { %> <span class="signal-units text-medium">dBf</span> <% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-33 no-bg filter-controls hide-phone" style="height: 48px;">
|
||||
<div class="flex-container no-filter flex-phone h-100">
|
||||
|
||||
<% if (antennas.enabled == true) { %>
|
||||
<div class="panel-50 no-bg h-100 br-0 m-0 dropdown dropdown-up data-ant" id="data-ant" style="margin-right: 15px !important;">
|
||||
<input type="text" placeholder="Ant A" readonly tabindex="0">
|
||||
<ul class="options open-top" tabindex="-1">
|
||||
<% if(antennas.ant1.enabled == true) { %><li data-value="0" class="option" tabindex="0"><%= antennas.ant1.name %></li><% } %>
|
||||
<% if(antennas.ant2.enabled == true) { %><li data-value="1" class="option" tabindex="0"><%= antennas.ant2.name %></li><% } %>
|
||||
<% if(antennas.ant3.enabled == true) { %><li data-value="2" class="option" tabindex="0"><%= antennas.ant3.name %></li><% } %>
|
||||
<% if(antennas.ant4.enabled == true) { %><li data-value="3" class="option" tabindex="0"><%= antennas.ant4.name %></li><% } %>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div class="panel-50 no-bg br-0 h-100 m-0 button-eq">
|
||||
<% if (device == 'tef') { %><button style="border-radius: 15px 0px 0px 15px;" class="data-eq hide-phone tooltip" aria-label="EQ Filter" data-tooltip="<strong>The cEQ filter can reduce bandwidth below 56 kHz.</strong><br><br>Useful for weak stations next to strong ones,<br>although it may pick up more interference."><span class="text-bold">cEQ</span></button><% } %>
|
||||
<% if (device == 'xdr') { %><button style="border-radius: 15px 0px 0px 15px;" class="data-eq hide-phone tooltip" aria-label="RF+ Filter" data-tooltip="<strong>The RF+ filter increases gain by 5dB</strong>"><span class="text-bold">RF+</span></button><% } %>
|
||||
<% if (device == 'si47xx' && si47xxAgcControl) { %>
|
||||
<div class="no-bg dropdown dropdown-up data-agc hide-phone w-150" id="data-agc" style="margin-right: 15px !important;">
|
||||
<input type="text" placeholder="AGC" readonly tabindex="0">
|
||||
<ul class="options open-top" tabindex="-1">
|
||||
<li data-value="0" class="option" tabindex="0">Auto AGC</li>
|
||||
<li data-value="1" class="option" tabindex="0">High</li>
|
||||
<li data-value="3" class="option" tabindex="0">Medium</li>
|
||||
<li data-value="2" class="option" tabindex="0">Low</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="panel-50 no-bg br-0 h-100 m-0 button-ims">
|
||||
<% if (device == 'tef') { %><button style="border-radius: 0px 15px 15px 0px;" class="data-ims hide-phone tooltip" aria-label="iMS + Filter" data-tooltip="<strong>The iMS filter reduces multipath audio artifacts.</strong><br><br>It's recommended to leave it on most of the time."><span class="text-bold">iMS</span></button><% } %>
|
||||
<% if (device == 'xdr') { %><button style="border-radius: 0px 15px 15px 0px;" class="data-ims hide-phone tooltip" aria-label="IF+ Filter" data-tooltip="<strong>The IF+ filter increases gain by 6dB</strong>"><span class="text-bold">IF+</span></button><% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-33 flex-container flex-phone no-bg" id="tune-buttons">
|
||||
<button id="freq-down" aria-label="Tune down"><i class="fa-solid fa-chevron-left"></i></button>
|
||||
<input type="text" id="commandinput" inputmode="numeric" placeholder="Frequency" autocomplete="off" aria-label="Current frequency: ">
|
||||
<button id="freq-up" aria-label="Tune up"><i class="fa-solid fa-chevron-right"></i></button>
|
||||
</div>
|
||||
|
||||
<div class="panel-33 hide-phone no-bg">
|
||||
<div class="flex-container">
|
||||
<span class="panel-100-real m-0" style="height: 48px;">
|
||||
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="1" aria-label="Volume slider">
|
||||
</span>
|
||||
<% if (bwSwitch) { %>
|
||||
<%- include('_bwSwitch', { device: device, tunerProfiles: tunerProfiles, id: 'data-bw', cssClass: 'panel-50 dropdown-up m-0 w-150 m-left-15', cssClassOptions: 'open-top' }) %>
|
||||
<% } %>
|
||||
<% if (fmlist_integration == true && (fmlist_adminOnly == false || isTuneAuthenticated)) { %>
|
||||
<button class="tooltip bg-color-4 mini-popup log-fmlist" data-tooltip="<strong>LOG TO FMLIST</strong><br>Clicking this button logs the current station to FMLIST's visual logbook." aria-label="Log to FMLIST" style="width: 80px; height: 48px;margin-left: 15px !important;">
|
||||
<i class="fa-solid fa-flag fa-lg"></i>
|
||||
<span class="mini-popup-content">
|
||||
Choose the DX propagation type:<br>
|
||||
<a class="top-10 bg-color-3 text-bold log-fmlist-tropo" style="padding: 10px; border-radius: 15px 0 0 15px; display: inline-block;">Tropo</a><!--
|
||||
--><a class="top-10 bg-color-3 text-bold log-fmlist-sporadice" style="padding: 10px; border-radius: 0 15px 15px 0; display: inline-block;">Sporadic-E</a>
|
||||
</span>
|
||||
</button>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container flex-phone flex-phone-column">
|
||||
<div id="data-ant-container" class="hide-desktop" style="padding-left: 18px;padding-right: 18px;margin-top: -20px;">
|
||||
<% if (antennas.enabled == true) { %>
|
||||
<div class="panel-100-real no-bg h-100 br-0 dropdown data-ant" id="data-ant-phone" style="max-height: 48px;width: 50%;">
|
||||
<input type="text" placeholder="Ant A" readonly tabindex="0" style="border-radius: 0 0 15px 15px;">
|
||||
<ul class="options open-top" tabindex="-1">
|
||||
<% if(antennas.ant1.enabled == true) { %><li data-value="0" class="option" tabindex="0"><%= antennas.ant1.name %></li><% } %>
|
||||
<% if(antennas.ant2.enabled == true) { %><li data-value="1" class="option" tabindex="0"><%= antennas.ant2.name %></li><% } %>
|
||||
<% if(antennas.ant3.enabled == true) { %><li data-value="2" class="option" tabindex="0"><%= antennas.ant3.name %></li><% } %>
|
||||
<% if(antennas.ant4.enabled == true) { %><li data-value="3" class="option" tabindex="0"><%= antennas.ant4.name %></li><% } %>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="panel-75 hover-brighten no-bg-phone" id="rt-container" style="height: 100px;">
|
||||
<h2 style="margin-top: 4px;">RADIOTEXT</h2>
|
||||
<div id="data-rt0">
|
||||
<span></span>
|
||||
</div>
|
||||
<div id="data-rt1">
|
||||
<span></span>
|
||||
</div>
|
||||
<hr class="hide-desktop">
|
||||
</div>
|
||||
|
||||
<div class="panel-33 hover-brighten tooltip no-bg-phone" style="min-height: 91px;" data-tooltip="This panel contains the current TX info when RDS is loaded.<br><strong>Clicking on this panel copies the info into the clipboard.</strong>">
|
||||
<div id="data-station-container" data-score="0">
|
||||
<h2 style="margin-top: 0;" class="mb-0">
|
||||
<span id="data-station-name"></span>
|
||||
</h2>
|
||||
<h4 class="m-0">
|
||||
<span id="data-station-city" style="font-size: 16px;"></span> <span class="text-small">[<span id="data-station-itu"></span>]</span>
|
||||
</h4>
|
||||
<span class="text-small">
|
||||
<span id="data-station-erp"></span> kW [<span id="data-station-pol"></span>] <span class="text-gray">•</span> <span id="data-station-distance"></span> <span class="text-gray">•</span> <span id="data-station-azimuth"></span> <span id="data-station-others" class="hide-phone" style="opacity: 0.7;"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="panel-10 no-bg center-phone" style="margin-left: 0; margin-top: 0; margin-right: 0;display:flex;">
|
||||
<div class="panel-100 no-bg-phone" style="margin-left: 0;">
|
||||
<h2 class="bottom-10">AF</h2>
|
||||
<div id="af-list" style="text-align: center;">
|
||||
<ul> </ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="flags-container-phone" class="panel-33 no-bg-phone" style="margin-bottom: 110px !important;">
|
||||
<h2 class="show-phone">
|
||||
<div class="data-pty color-4"></div>
|
||||
</h2>
|
||||
<h3 style="margin-top:0;margin-bottom:0;" class="text-color-default flex-center">
|
||||
<span class="data-tp">TP</span>
|
||||
<span style="margin-left: 15px;" class="data-ta">TA</span>
|
||||
<div style="display:inline-block">
|
||||
<span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span>
|
||||
</div>
|
||||
<span class="pointer stereo-container" style="position: relative; margin-left: 20px;" role="button" aria-label="Stereo / Mono toggle" tabindex="0">
|
||||
<div class="circle-container">
|
||||
<div class="circle data-st circle1"></div>
|
||||
<div class="circle data-st circle2"></div>
|
||||
</div>
|
||||
<span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
|
||||
</span>
|
||||
<span style="margin-left: 15px;" class="data-ms">MS</span>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="popup-window" id="popup-panel-mobile-settings" style="overflow:visible;">
|
||||
<div class="flex-container flex-column flex-phone flex-phone-column" style="height: calc(100%);">
|
||||
<div class="popup-header hover-brighten flex-center">
|
||||
<p class="color-4" style="margin: 0; padding-left: 10px;">Quick tools</p>
|
||||
<button class="popup-close">✖</button>
|
||||
</div>
|
||||
<div class="popup-content text-left flex-container flex-phone flex-column p-10" style="flex: 1;">
|
||||
|
||||
<% if (bwSwitch || antennas.enabled) { %>
|
||||
<p class="flex-phone flex-center">Bandwidth & Antennas</p>
|
||||
<% } %>
|
||||
|
||||
<div class="flex-phone">
|
||||
<% if (bwSwitch) { %>
|
||||
<div style="max-height: 48px;width: 50%;margin-right: 5px;">
|
||||
<%- include('_bwSwitch', { device: device, tunerProfiles: tunerProfiles, id: 'data-bw-phone', cssClass: 'panel-100-real', cssClassOptions: 'text-center open-bottom' }) %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
</div>
|
||||
|
||||
<p class="flex-phone flex-center">Filters</p>
|
||||
<div class="flex-container flex-phone flex-center">
|
||||
<% if (device == 'tef') { %><button class="data-eq tooltip p-10 m-right-5" style="height: 48px" aria-label="EQ Filter" data-tooltip="<strong>The cEQ filter can reduce bandwidth below 56 kHz.</strong><br><br>Useful for weak stations next to strong ones,<br>although it may pick up more interference."><span class="text-bold">cEQ</span></button><% } %>
|
||||
<% if (device == 'xdr') { %><button class="data-eq tooltip p-10 m-right-5" aria-label="RF+ Filter" data-tooltip="<strong>The RF+ filter increases gain by 5dB</strong>"><span class="text-bold">RF+</span></button><% } %>
|
||||
<% if (device == 'si47xx' && si47xxAgcControl) { %>
|
||||
<div class="no-bg dropdown data-agc w-150" id="data-agc-phone" style="max-height: 48px;">
|
||||
<input type="text" placeholder="AGC" readonly tabindex="0" style="border-radius: 15px;">
|
||||
<ul class="options open-top" tabindex="-1">
|
||||
<li data-value="0" class="option" tabindex="0">Auto AGC</li>
|
||||
<li data-value="1" class="option" tabindex="0">High</li>
|
||||
<li data-value="3" class="option" tabindex="0">Medium</li>
|
||||
<li data-value="2" class="option" tabindex="0">Low</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
<% if (device == 'tef') { %><button class="data-ims tooltip p-10 m-left-5" style="height: 48px;" aria-label="iMS + Filter" data-tooltip="<strong>The iMS filter reduces multipath audio artifacts.</strong><br><br>It's recommended to leave it on most of the time."><span class="text-bold">iMS</span></button><% } %>
|
||||
<% if (device == 'xdr') { %><button class="data-ims tooltip p-10 m-left-5" aria-label="IF+ Filter" data-tooltip="<strong>The IF+ filter increases gain by 6dB</strong>"><span class="text-bold">IF+</span></button><% } %>
|
||||
</div>
|
||||
|
||||
<% if (fmlist_integration == true && (fmlist_adminOnly == false || isTuneAuthenticated)) { %>
|
||||
<p class="flex-phone flex-center">Logging</p>
|
||||
<button class="tooltip bg-color-4 mini-popup log-fmlist" data-tooltip="<strong>LOG TO FMLIST</strong><br>Clicking this button logs the current station to FMLIST's visual logbook." aria-label="Log to FMLIST" style="width: calc(100%); height: 48px;">
|
||||
<i class="fa-solid fa-flag fa-lg"></i>
|
||||
<span class="mini-popup-content">
|
||||
Choose the DX propagation type:<br>
|
||||
<a class="top-10 bg-color-3 text-bold log-fmlist-tropo" style="padding: 10px; border-radius: 15px 0 0 15px; display: inline-block;">Tropo</a><!--
|
||||
--><a class="top-10 bg-color-3 text-bold log-fmlist-sporadice" style="padding: 10px; border-radius: 0 15px 15px 0; display: inline-block;">Sporadic-E</a>
|
||||
</span>
|
||||
</button>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="popup-window" id="popup-panel-chat">
|
||||
<div class="flex-container flex-column flex-phone flex-phone-column" style="height: calc(100%);">
|
||||
<div class="popup-header hover-brighten flex-center">
|
||||
<p class="color-4" style="margin: 0; padding-left: 10px;">Chat • <span style="color: #bada55;" id="chat-admin"></span> <strong id="chat-identity-nickname"></strong></p>
|
||||
<button class="popup-close">✖</button>
|
||||
</div>
|
||||
<div class="popup-content text-left flex-container flex-phone flex-column" style="flex: 1;">
|
||||
<div style="text-align: center;white-space-collapse: collapse;">
|
||||
<div class="flex-phone flex-container flex-center top-10 bottom-10">
|
||||
<input type="text" id="chat-nickname" name="chat-nickname" placeholder="Nickname" style="width: 150px;border-radius: 15px 0 0 15px;padding-top:0;padding-bottom:0;border: 2px solid var(--color-4)">
|
||||
<button class="br-0 w-100" style="height: 48px; border-radius: 0 15px 15px 0;margin-left:-3px;" id="chat-nickname-save">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="chat-chatbox" class="bg-color-1" style="padding: 10px; overflow-y: auto; flex-grow: 1; min-height: 0; flex-basis: 0; min-height: 180px;"></div>
|
||||
|
||||
<div class="flex-container flex-phone">
|
||||
<input class="bg-color-2" type="text" id="chat-send-message" name="chat-send-message" placeholder="Send message..." style="background-color: var(--color-2);width: 100%;">
|
||||
<button aria-label="Send message" class="chat-send-message-btn br-0" style="width: 80px; height: 48px;"><i class="fa-solid fa-paper-plane"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="popup-window" id="popup-panel-transmitters">
|
||||
<div class="flex-container flex-column flex-phone flex-phone-column" style="height: calc(100%);">
|
||||
<div class="popup-header hover-brighten flex-center">
|
||||
<p class="color-4" style="margin: 0; padding-left: 10px;">Other possible transmitters</p>
|
||||
<button class="popup-close">✖</button>
|
||||
</div>
|
||||
<div id="alternative-txes" class="popup-content text-left flex-container flex-phone flex-column" style="flex: 1;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mobileTray" class="hide-desktop">
|
||||
<button class="playbutton" aria-label="Play / Stop" style="width: 64px; height: 64px; position:absolute;display: block;top: -50%;left: 50%; transform: translateX(-50%);"><i class="fa-solid fa-play fa-lg"></i></button>
|
||||
|
||||
<div style="width: calc(50% - 32px);text-align: center;">
|
||||
<button class="users-online-container" aria-label="Online users" style="display: inline-block;"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
|
||||
|
||||
<% if (chatEnabled) { %>
|
||||
<button class="chatbutton m-10" aria-label="Chatbox" style="display: inline-block;"><i class="fa-solid fa-message"></i></button>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<div style="width: 64px;text-align: center;">
|
||||
|
||||
</div>
|
||||
|
||||
<div style="width: calc(50% - 32px);text-align: center;">
|
||||
<button class="m-10 button-dark tuner-mobile-settings" aria-label="Advanced tuner settings" style="display: inline-block;"><i class="fa-solid fa-toolbox"></i></button>
|
||||
<button class="settings m-10" aria-label="Settings" style="display: inline-block;"><i class="fa-solid fa-bars"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="myModal" class="modal">
|
||||
<div class="modal-panel">
|
||||
<div class="flex-container flex-phone" style="height: calc(100% - 100px)">
|
||||
<div class="modal-panel-sidebar hover-brighten flex-center text-medium-big closeModal" role="button" aria-label="Close settings" tabindex="0"><i class="fa-solid fa-chevron-right"></i></div>
|
||||
<div class="modal-panel-content">
|
||||
<h1 class="top-25">Settings</h1>
|
||||
|
||||
<div class="panel-full flex-center no-bg m-0">
|
||||
<%- include('_components', { component: 'dropdown', id: 'theme-selector', inputId: 'theme-selector-input', label: 'Theme', cssClass: '', placeholder: 'Default',
|
||||
options: [
|
||||
{ value: 'theme1', label: 'Mint' },
|
||||
{ value: 'theme2', label: 'Cappuccino' },
|
||||
{ value: 'theme3', label: 'Nature' },
|
||||
{ value: 'theme4', label: 'Ocean' },
|
||||
{ value: 'theme5', label: 'Terminal' },
|
||||
{ value: 'theme6', label: 'Nightlife' },
|
||||
{ value: 'theme7', label: 'Blurple' },
|
||||
{ value: 'theme8', label: 'Construction' },
|
||||
{ value: 'theme9', label: 'Amoled' },
|
||||
]
|
||||
}) %>
|
||||
</div>
|
||||
|
||||
<% if (device !== 'sdr') { %>
|
||||
<div class="panel-full flex-center no-bg m-0">
|
||||
<%- include('_components', { component: 'dropdown', id: 'signal-selector', inputId: 'signal-selector-input', label: 'Signal units', cssClass: '', placeholder: 'dBf',
|
||||
options: [
|
||||
{ value: 'dbf', label: 'dBf' },
|
||||
{ value: 'dbuv', label: 'dBuV' },
|
||||
{ value: 'dbm', label: 'dBm' },
|
||||
]
|
||||
}) %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div class="auto" style="max-width: 215px;">
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'top-25', label: 'Manual decimals', id: 'extended-frequency-range'}) %>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'RDS PS Underscores', id: 'ps-underscores'}) %>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Imperial units', id: 'imperial-units'}) %>
|
||||
</div>
|
||||
|
||||
<% if (isAdminAuthenticated) { %>
|
||||
<p class="color-3">You are logged in as an adminstrator.</p>
|
||||
<div class="admin-quick-dashboard">
|
||||
<div class="icon tooltip <% if (tunerLock) { %>active<% } %>" id="dashboard-lock-admin" onClick="toggleLock('#dashboard-lock-admin', 'wL1', 'wL0', 'Unlock Tuner (Admin)', 'Lock Tuner (Admin)');" role="button" aria-label="Toggle admin lock until restart" tabindex="0" data-tooltip="Toggle admin lock<br>Lasts until restart">
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
</div>
|
||||
<div class="icon tooltip <% if (!publicTuner) { %>active<% } %>" id="dashboard-lock-tune" onClick="toggleLock('#dashboard-lock-tune', 'wT1', 'wT0', 'Unlock Tuner (Password tune)', 'Lock Tuner (Password tune)');" role="button" aria-label="Toggle password lock until restart" tabindex="0" data-tooltip="Toggle password lock<br>Lasts until restart">
|
||||
<i class="fa-solid fa-key"></i>
|
||||
</div>
|
||||
<div class="icon tooltip" role="button" aria-label="Go to admin panel" tabindex="0" data-tooltip="Go to admin panel" onClick="window.open('./setup', '_blank').focus();">
|
||||
<i class="fa-solid fa-user"></i>
|
||||
</div>
|
||||
<div class="icon tooltip logout-link" role="button" aria-label="Sign out" tabindex="0" data-tooltip="Sign out">
|
||||
<i class="fa-solid fa-sign-out"></i>
|
||||
</div>
|
||||
</div>
|
||||
<% } else if (isTuneAuthenticated) { %>
|
||||
<p class="color-3">You are logged in and can control the receiver.</p>
|
||||
<div class="admin-quick-dashboard">
|
||||
<div class="icon tooltip <% if (!publicTuner) { %>active<% } %>" id="dashboard-lock-tune" onClick="toggleLock('#dashboard-lock-tune', 'wT1', 'wT0', 'Unlock Tuner (Password tune)', 'Lock Tuner (Password tune)');" role="button" aria-label="Toggle password lock until disconnect" tabindex="0" data-tooltip="Toggle password lock<br>Lasts until disconnect">
|
||||
<i class="fa-solid fa-key"></i>
|
||||
</div>
|
||||
<div class="icon tooltip logout-link" role="button" aria-label="Sign out" tabindex="0" data-tooltip="Sign out">
|
||||
<i class="fa-solid fa-sign-out"></i>
|
||||
</div>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<form action="./login" method="post" id="login-form" class="top-25">
|
||||
<input type="password" id="password" name="password" placeholder="Password" style="width: 145px; border-radius: 15px 0 0 15px" required>
|
||||
<button type="submit" class="br-0 top-10 tooltip" style="height: 46px; width: 50px; margin-left: -2px;border-radius: 0 15px 15px 0;" role="button" aria-label="Log in" tabindex="0" data-tooltip="Log in">
|
||||
<i class="fa-solid fa-right-to-bracket"></i>
|
||||
</button>
|
||||
</form>
|
||||
<% } %>
|
||||
<div id="login-message" class="color-3"> </div>
|
||||
|
||||
<div class="version-info">
|
||||
<p class="m-0">
|
||||
FM-DX Webserver <span style="color: var(--color-3);" class="version-string"></span>
|
||||
</p>
|
||||
<p class="text-small m-0 color-3">by <a href="https://fmdx.org" target="_blank">FMDX.org</a></p>
|
||||
<span class="text-small" style="color: var(--color-3);">[<a href="https://servers.fmdx.org/" target="_blank">Receiver Map</a>]</span>
|
||||
<br>
|
||||
<p class="text-small color-3" id="current-ping"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-panel-footer flex-container flex-phone">
|
||||
<div class="modal-panel-sidebar" style="font-size: 22px;">
|
||||
<div class="flex-center" style="height: 50px">
|
||||
<i class="fa-solid fa-hand-holding-medical"></i>
|
||||
</div>
|
||||
<div class="flex-center" style="height: 50px">
|
||||
<i class="fa-brands fa-discord"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-panel-content">
|
||||
<div class="hover-brighten br-0 bg-color-1" style="height: 50px;padding:12px;" onclick="window.open('https://buymeacoffee.com/noobish')">
|
||||
<strong>Support</strong> the developer!
|
||||
</div>
|
||||
<div class="hover-brighten br-0 bg-color-1" style="height: 50px;padding:12px;" onclick="window.open('https://discord.gg/cY66nt6UhV')">
|
||||
Join our <strong>FMDX.org Discord</strong> community!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="toast-container" aria-live="polite"></div>
|
||||
<script src="js/websocket.js"></script>
|
||||
<script src="js/webserver.js"></script>
|
||||
<% if (!noPlugins) { %>
|
||||
<% plugins?.forEach(function(plugin) { %>
|
||||
<script src="js/plugins/<%= plugin %>"></script>
|
||||
<% }); %>
|
||||
<% } %>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Login - FM-DX Webserver</title>
|
||||
<link href="css/entry.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/flags.min.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/libs/fontawesome.css" type="text/css" rel="stylesheet">
|
||||
<script src="js/libs/jquery.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" type="text/css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<div id="toast-container"></div>
|
||||
<div class="wrapper-outer wrapper-full">
|
||||
<div id="wrapper">
|
||||
<div class="panel-100 no-bg">
|
||||
<img class="top-25" src="favicon.svg" height="64px">
|
||||
<p>You are currently not logged in as an administrator and therefore can't change the settings.</p>
|
||||
<p>Please login below.</p>
|
||||
</div>
|
||||
<div class="panel-100 p-bottom-20">
|
||||
<h1 class="text-light">Login</h1>
|
||||
<form action="./login" method="post" id="login-form">
|
||||
<input type="password" id="password" name="password" placeholder="Password" style="width: 250px; background-color: var(--color-2); height: 48px; border-radius: 15px 0 0 15px" required>
|
||||
<button type="submit" class="br-0 top-10 tooltip" style="height: 48px; width: 50px; margin-left: -4px;border-radius: 0 15px 15px 0;" role="button" aria-label="Log in" tabindex="0" data-tooltip="Log in">
|
||||
<i class="fa-solid fa-right-to-bracket"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/settings.js"></script>
|
||||
<script src="js/toast.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
+751
@@ -0,0 +1,751 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Setup - FM-DX Webserver</title>
|
||||
<link href="css/entry.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/flags.min.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/libs/fontawesome.css" type="text/css" rel="stylesheet">
|
||||
<script src="js/libs/jquery.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" type="text/css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<div id="toast-container"></div>
|
||||
<div class="wrapper-outer wrapper-full wrapper-outer-static">
|
||||
<div id="navigation" class="sidenav flex-container flex-phone">
|
||||
<div class="sidenav-content">
|
||||
<h1 class="top-25">Settings</h1>
|
||||
<ul class="nav" role="tablist" style="border-radius: 15px 15px 0 0;">
|
||||
<li role="tab" data-panel="dashboard" aria-selected="true" tabindex="0">
|
||||
<a href="#" role="tab" aria-controls="dashboard"><i class="fa-solid fa-fw fa-chart-line"></i> Dashboard</a>
|
||||
</li>
|
||||
<li role="tab" data-panel="tuner" tabindex="0">
|
||||
<a href="#" role="tab" tabindex="-1" aria-controls="tuner"><i class="fa-solid fa-fw fa-radio"></i> Tuner</a>
|
||||
</li>
|
||||
<li role="tab" data-panel="audio" tabindex="0">
|
||||
<a href="#" role="tab" tabindex="-1" aria-controls="audio"><i class="fa-solid fa-fw fa-volume-high"></i> Audio</a>
|
||||
</li>
|
||||
<li role="tab" data-panel="webserver" tabindex="0">
|
||||
<a href="#" role="tab" tabindex="-1" aria-controls="webserver"><i class="fa-solid fa-fw fa-server"></i> Webserver</a>
|
||||
</li>
|
||||
<li role="tab" data-panel="identification" tabindex="0">
|
||||
<a href="#" role="tab" tabindex="-1" aria-controls="identification"><i class="fa-solid fa-fw fa-circle-info"></i> Identification & Map</a>
|
||||
</li>
|
||||
<li role="tab" data-panel="plugins-tab" tabindex="0">
|
||||
<a href="#" role="tab" tabindex="-1" aria-controls="plugins-tab"><i class="fa-solid fa-fw fa-puzzle-piece"></i> Plugins</a>
|
||||
</li>
|
||||
<li role="tab" data-panel="users" tabindex="0">
|
||||
<a href="#" role="tab" tabindex="-1" aria-controls="users"><i class="fa-solid fa-fw fa-user"></i> User management</a>
|
||||
</li>
|
||||
<li role="tab" data-panel="startup" tabindex="0">
|
||||
<a href="#" role="tab" tabindex="-1" aria-controls="startup"><i class="fa-solid fa-fw fa-plug"></i> Startup</a>
|
||||
</li>
|
||||
<li role="tab" data-panel="extras" tabindex="0">
|
||||
<a href="#" role="tab" tabindex="-1" aria-controls="extras"><i class="fa-solid fa-fw fa-star"></i> Extras</a>
|
||||
</li>
|
||||
|
||||
<div class="admin-quick-dashboard top-25">
|
||||
<div class="icon tooltip" role="button" aria-label="Go back to the main screen" tabindex="0" data-tooltip="Go back to the main screen" onclick="document.location.href='./'">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
</div>
|
||||
<div class="icon tooltip" id="submit-config" role="button" aria-label="Save settings" tabindex="0" data-tooltip="Save settings" onclick="submitConfig()">
|
||||
<i class="fa-solid fa-save"></i>
|
||||
</div>
|
||||
<div class="icon tooltip logout-link" role="button" aria-label="Sign out" tabindex="0" data-tooltip="Sign out">
|
||||
<i class="fa-solid fa-sign-out"></i>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="panel-100-real m-0 p-10 no-bg">
|
||||
<p class="color-4">Feel free to contact us on <a href="https://discord.gg/ZAVNdS74mC" target="_blank"><strong class="color-5"><i class="fa-brands fa-discord"></i> Discord</strong></a> for community support.</p>
|
||||
<a href="https://github.com/noobishsvk/fm-dx-webserver" target="_blank" class="text-small">Version: <span class="version-string color-4"></span></a>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sidenav-close text-medium-big hover-brighten flex-center color-4 modal-panel-sidebar" role="button" onclick="toggleNav()" aria-label="Toggle navigation" tabindex="0"><i class="fa-solid fa-chevron-left"></i></div>
|
||||
</div>
|
||||
<div id="wrapper" class="setup-wrapper admin-wrapper panel-full">
|
||||
<div class="panel-full" style="margin-top: -20px; border-radius: 0; padding-left: 20px;padding-right: 20px;">
|
||||
<div class="panel-full tab-content no-bg m-0" id="dashboard" role="tabpanel">
|
||||
<h2>Dashboard</h2>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-33 p-20">
|
||||
<span class="text-medium-big color-5"><%= onlineUsers %></span>
|
||||
<p>Online users</p>
|
||||
</div>
|
||||
|
||||
<div class="panel-33 p-20">
|
||||
<span class="text-medium-big color-5"><%= memoryUsage %></span>
|
||||
<span class="text-small color-4" style="display: block; font-size: 1em; font-weight: 600; line-height: 0;">(<%= memoryHeap %> heap)</span>
|
||||
<p>Memory usage</p>
|
||||
</div>
|
||||
|
||||
<div class="panel-33 p-20">
|
||||
<span class="text-medium-big color-5"><%= processUptime %></span>
|
||||
<p >Uptime</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-100-real p-bottom-20" style="overflow-x: auto;">
|
||||
<h3>Current users</h3>
|
||||
<table class="table-big">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP Address</th>
|
||||
<th>Location</th>
|
||||
<th>Online since</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% if (connectedUsers.length > 0) { %>
|
||||
<% connectedUsers.forEach(user => { %>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://dnschecker.org/ip-location.php?ip=<%= user.ip.replace('::ffff:', '') %>" target="_blank">
|
||||
<%= user.ip.replace('::ffff:', '') %>
|
||||
</a>
|
||||
</td>
|
||||
<td><%= user.location %></td>
|
||||
<td><%= user.time %></td>
|
||||
<td><a href="./kick?ip=<%= user.ip %>">Kick</a></td>
|
||||
</tr>
|
||||
<% }); %>
|
||||
<% } else { %>
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center">No users online</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-100-real p-bottom-20">
|
||||
<h3>Quick settings</h3>
|
||||
<div class="flex-container flex-center" style="margin: 30px;">
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Unlocked Tuner', id: 'publicTuner'}) %>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Admin lock', id: 'lockToAdmin'}) %><br>
|
||||
</div>
|
||||
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Tune password', id: 'password-tunePass', password: true}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Admin password', id: 'password-adminPass', password: true}) %><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-100-real p-bottom-20 bottom-20">
|
||||
<h3>Console</h3>
|
||||
<% if (consoleOutput && consoleOutput.length > 0) { %>
|
||||
<div class="panel-100 auto br-5 p-10 text-small text-left top-10" id="console-output">
|
||||
<% consoleOutput.forEach(function(log) { %>
|
||||
<pre class="m-0" style="white-space:pre-wrap;"><%= log %></pre>
|
||||
<% }); %>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<p>No console output available.</p>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-full tab-content no-bg m-0" id="audio" role="tabpanel">
|
||||
<h2>Audio settings</h2>
|
||||
|
||||
<div class="flex-container contains-dropdown">
|
||||
<div class="panel-33 p-bottom-20">
|
||||
<h3>Device</h3>
|
||||
<p>Your audio device port.<br>
|
||||
<span class="text-gray">This is where your tuner is plugged in.</span>
|
||||
</p>
|
||||
|
||||
<%- include('_components', {
|
||||
component: 'dropdown',
|
||||
id: 'audioList',
|
||||
inputId: 'audio-audioDevice',
|
||||
label: 'Audio device',
|
||||
cssClass: '',
|
||||
placeholder: 'Choose your audio device',
|
||||
options: [
|
||||
...videoDevices.map(device => ({
|
||||
value: device.name,
|
||||
label: `${device.name}`
|
||||
})),
|
||||
...audioDevices.map(device => ({
|
||||
value: device.name,
|
||||
label: `${device.name}`
|
||||
}))
|
||||
]
|
||||
}) %>
|
||||
</div>
|
||||
<div class="panel-33 p-bottom-20">
|
||||
<h3>Channels</h3>
|
||||
<p>Audio channel count.<br>
|
||||
<span class="text-gray">Choose between Mono / Stereo.</span>
|
||||
</p>
|
||||
<%- include('_components', { component: 'dropdown', id: 'audio-channels-dropdown', inputId: 'audio-audioChannels', label: 'Audio channels', cssClass: '', placeholder: 'Stereo',
|
||||
options: [
|
||||
{ value: '2', label: 'Stereo' },
|
||||
{ value: '1', label: 'Mono' }
|
||||
]
|
||||
}) %><br>
|
||||
</div>
|
||||
<div class="panel-33 p-bottom-20">
|
||||
<h3>Bitrate</h3>
|
||||
<p>The bitrate of the mp3 audio.<br>
|
||||
<span class="text-gray">Minimum: 64 Kbps • Maximum: 320 Kbps</span>
|
||||
</p>
|
||||
<%- include('_components', { component: 'dropdown', id: 'audio-quality-dropdown', inputId: 'audio-audioBitrate', label: 'Audio quality', cssClass: '', placeholder: '128kbps (standard)',
|
||||
options: [
|
||||
{ value: '64k', label: '64kbps (lowest quality)' },
|
||||
{ value: '96k', label: '96kbps (low quality)' },
|
||||
{ value: '128k', label: '128kbps (standard)' },
|
||||
{ value: '192k', label: '192kbps (high quality)' },
|
||||
{ value: '256k', label: '256kbps (very high quality)' },
|
||||
{ value: '320k', label: '320kbps (ultra quality)' }
|
||||
]
|
||||
}) %><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-50 p-bottom-20">
|
||||
<h3>Audio boost</h3>
|
||||
<p>This option will boost the audio volume. Use if the output is too quiet.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Audio Boost', id: 'audio-audioBoost'}) %>
|
||||
</div>
|
||||
<div class="panel-50 p-bottom-20">
|
||||
<h3>Experimental</h3>
|
||||
<p>If you use a USB audio card on Linux, enabling this option might fix your audio issues.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'ALSA Software mode', id: 'audio-softwareMode'}) %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="panel-50 p-bottom-20 bottom-20">
|
||||
<h3>FFmpeg</h3>
|
||||
<p>Legacy option for Linux / macOS that could resolve audio issues, but will consume additional CPU and RAM usage.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Additional FFmpeg', id: 'audio-ffmpeg'}) %>
|
||||
</div>
|
||||
<div class="panel-50 p-bottom-20 bottom-20">
|
||||
<h3>Sample rate offset</h3>
|
||||
<p>Using a negative value could eliminate audio buffering issues during long periods of listening. <br>
|
||||
However, a value that’s too low might increase the buffer over time.</p>
|
||||
<p><input class="panel-33 input-text w-100 auto" type="number" style="min-height: 40px; color: var(--color-text); padding: 10px; padding-left: 10px; box-sizing: border-box; border: 2px solid transparent; font-family: 'Titillium Web', sans-serif;" id="audio-samplerateOffset" min="-10" max="10" step="1" value="0" aria-label="Samplerate offset"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-full m-0 tab-content no-bg" id="webserver" role="tabpanel">
|
||||
<h2>Webserver settings</h2>
|
||||
<div class="flex-container contains-dropdown">
|
||||
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px;">
|
||||
<h3>Connection</h3>
|
||||
<p class="text-gray">Leave the IP at 0.0.0.0 unless you explicitly know you have to change it.<br>Don't enter your public IP here.</p>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '0.0.0.0', label: 'Webserver IP', id: 'webserver-webserverIp'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '8080', label: 'Webserver port', id: 'webserver-webserverPort'}) %><br>
|
||||
</div>
|
||||
<div class="panel-50 p-bottom-20">
|
||||
<h3>Design</h3>
|
||||
<h4>Background image</h4>
|
||||
<%- include('_components', {component: 'text', cssClass: 'br-15', placeholder: 'Direct image link', label: 'Image link', id: 'webserver-bgImage'}) %><br>
|
||||
|
||||
<h4 class="top-25">Themes</h4>
|
||||
<%- include('_components', { component: 'dropdown', id: 'server-theme-selector', inputId: 'webserver-defaultTheme', label: 'Default server theme', cssClass: '', placeholder: 'Default',
|
||||
options: [
|
||||
{ value: 'theme1', label: 'Mint' },
|
||||
{ value: 'theme2', label: 'Cappuccino' },
|
||||
{ value: 'theme3', label: 'Nature' },
|
||||
{ value: 'theme4', label: 'Ocean' },
|
||||
{ value: 'theme5', label: 'Terminal' },
|
||||
{ value: 'theme6', label: 'Nightlife' },
|
||||
{ value: 'theme7', label: 'Blurple' },
|
||||
{ value: 'theme8', label: 'Construction' },
|
||||
{ value: 'theme9', label: 'Amoled' },
|
||||
]
|
||||
}) %><br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="panel-100-real p-bottom-20">
|
||||
<h3>Antennas</h3>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'bottom-20', label: 'Antenna switch', id: 'antennas-enabled'}) %><br>
|
||||
|
||||
<div class="flex-container flex-center p-20">
|
||||
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 1', id: 'antennas-ant1-enabled'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant A', label: 'Antenna 1 name', id: 'antennas-ant1-name'}) %><br>
|
||||
</div>
|
||||
|
||||
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'top-25', label: 'Antenna 2', id: 'antennas-ant2-enabled'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant B', label: 'Antenna 2 name', id: 'antennas-ant2-name'}) %><br>
|
||||
</div>
|
||||
|
||||
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 3', id: 'antennas-ant3-enabled'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant C', label: 'Antenna 3 name', id: 'antennas-ant3-name'}) %><br>
|
||||
</div>
|
||||
|
||||
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 4', id: 'antennas-ant4-enabled'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant D', label: 'Antenna 4 name', id: 'antennas-ant4-name'}) %><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-50" style="padding-left: 20px; padding-right: 20px;">
|
||||
<h3>Tuning options</h3>
|
||||
<p>If you want to limit which frequencies the users can tune to,<br>you can set the lower and upper limit here.<br>
|
||||
<span class="text-gray">Enter frequencies in MHz.</span>
|
||||
</p>
|
||||
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Limit tuning', id: 'webserver-tuningLimit'}) %><br>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '0', label: 'Lower limit', id: 'webserver-tuningLowerLimit'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '108', label: 'Upper limit', id: 'webserver-tuningUpperLimit'}) %>
|
||||
</div>
|
||||
|
||||
<div class="panel-50 p-bottom-20">
|
||||
<h3>Presets</h3>
|
||||
<p>You can set up to 4 presets.<br>These presets are accessible with the F1-F4 buttons.<br>
|
||||
<span class="text-gray">Enter frequencies in MHz.</span></p>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '87.5', label: 'Preset 1', id: 'webserver-presets-1'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '87.5', label: 'Preset 2', id: 'webserver-presets-2'}) %>
|
||||
<br>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '87.5', label: 'Preset 3', id: 'webserver-presets-3'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '87.5', label: 'Preset 4', id: 'webserver-presets-4'}) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container p-bottom-20">
|
||||
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px;">
|
||||
<h3>RDS Mode</h3>
|
||||
<p>You can switch between American (RBDS) / Global (RDS) mode here.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'bottom-20', iconClass: '', label: 'American RDS mode (RBDS)', id: 'webserver-rdsMode'}) %>
|
||||
<h3>RDS Timeout</h3>
|
||||
<p>If no data is received, RDS will be automatically cleared after a timeout.<br>
|
||||
<span class="text-gray">Enter timeout in seconds or 0 to disable.</span><br></p>
|
||||
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '0', label: 'RDS Timeout', id: 'webserver-rdsTimeout'}) %>
|
||||
</div>
|
||||
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px; padding-bottom: 80px;">
|
||||
<h3>Transmitter Search Algorithm</h3>
|
||||
<p>Different modes may help with more accurate transmitter identification depending on your region.</p>
|
||||
<%- include('_components', { component: 'dropdown', id: 'server-tx-id-algo', inputId: 'webserver-txIdAlgorithm', label: 'Transmitter ID Algorithm', cssClass: '', placeholder: 'Algorithm 1',
|
||||
options: [
|
||||
{ value: '0', label: 'Algorithm 1' },
|
||||
{ value: '1', label: 'Algorithm 2' },
|
||||
{ value: '2', label: 'Algorithm 3' },
|
||||
]
|
||||
}) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="panel-full m-0 tab-content no-bg" id="tuner" role="tabpanel">
|
||||
<h2>Tuner settings</h2>
|
||||
<div class="panel-100 p-bottom-20 contains-dropdown" style="z-index: 991;">
|
||||
<h3>Device type</h3>
|
||||
<div class="flex-center" style="max-width: 520px; margin: 10px auto 0;">
|
||||
<%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x',
|
||||
options: tunerProfiles.map(profile => ({
|
||||
value: profile.id,
|
||||
label: profile.label
|
||||
}))
|
||||
}) %><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container contains-dropdown">
|
||||
<div class="panel-100 p-bottom-20" style="padding-right: 20px; padding-left: 20px;">
|
||||
<h3>Connection type</h3>
|
||||
<p class="text-gray">If you want to choose the serial port directly, choose "Direct".<br>If you use xdrd or your receiver is connected via Wi-Fi, choose TCP/IP.</p>
|
||||
<div class="auto top-10">
|
||||
<label class="toggleSwitch nolabel" onclick="">
|
||||
<input id="xdrd-wirelessConnection" type="checkbox" tabindex="0" aria-label="Connection type"/>
|
||||
<a></a>
|
||||
<span>
|
||||
<span class="left-span">Direct</span>
|
||||
<span class="right-span">TCP/IP</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="tuner-usb">
|
||||
<p class="text-gray">Choose your desired <strong>serial port</strong><br> </p>
|
||||
<%- include('_components', {
|
||||
component: 'dropdown',
|
||||
id: 'deviceList',
|
||||
inputId: 'xdrd-comPort',
|
||||
label: 'Serial port',
|
||||
cssClass: '',
|
||||
placeholder: 'Choose your serial port',
|
||||
options: serialPorts.map(serialPort => ({
|
||||
value: serialPort.path,
|
||||
label: `${serialPort.path} - ${serialPort.friendlyName}`
|
||||
}))
|
||||
}) %>
|
||||
</div>
|
||||
|
||||
<div id="tuner-wireless">
|
||||
<p class="text-gray">If you are connecting your tuner <strong>wirelessly</strong>, enter the tuner IP. <br> If you use <strong>xdrd</strong>, use 127.0.0.1 as your IP.</p>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', label: 'xdrd IP address', id: 'xdrd-xdrdIp'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', label: 'xdrd port', id: 'xdrd-xdrdPort'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', label: 'xdrd password', id: 'xdrd-xdrdPassword', password: true}) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="panel-50 p-bottom-20">
|
||||
<h3>Startup</h3>
|
||||
<h4>Startup volume</h4>
|
||||
<div class="panel-75 auto" style="height: 48px;">
|
||||
<input type="range" id="audio-startupVolume" min="0" max="1" step="0.01" value="1" aria-label="Startup Volume slider">
|
||||
</div>
|
||||
<h4 class="top-10 text-gray" id="volume-percentage-value"></h4>
|
||||
|
||||
<hr>
|
||||
<h4 class="bottom-20">Default frequency</h4>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Default frequency for first client', id: 'enableDefaultFreq'}) %><br>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '87.5', label: 'Default frequency', id: 'defaultFreq'}) %>
|
||||
</div>
|
||||
<div class="panel-50 p-bottom-20">
|
||||
<h3>Miscellaneous</h3>
|
||||
<div class="flex-container">
|
||||
<div class="panel-50 no-bg">
|
||||
<h4>Bandwidth switch</h4>
|
||||
<p>Bandwidth switch allows the user to set the bandwidth manually.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Bandwidth switch', id: 'bwSwitch'}) %><br>
|
||||
</div>
|
||||
<div class="panel-50 no-bg">
|
||||
<h4>Automatic shutdown</h4>
|
||||
<p>Toggling this option will put the tuner to sleep when no clients are connected.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Auto-shutdown', id: 'autoShutdown'}) %><br>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="panel-50 no-bg">
|
||||
<h4>SI47XX AGC control</h4>
|
||||
<p>Allow users to change SI47XX AGC mode from the main UI.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Enable AGC control', id: 'si47xx-agcControl'}) %><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-full m-0 tab-content no-bg" id="plugins-tab" role="tabpanel">
|
||||
<h2>Plugins</h2>
|
||||
<div class="panel-100 p-bottom-20">
|
||||
<h3>Plugin list</h3>
|
||||
<p>Any compatible <strong>.js</strong> plugin, which is in the "plugins" folder, will be listed here.<br>
|
||||
Click on the individual plugins to enable/disable them.</p>
|
||||
<select id="plugins" class="multiselect" multiple>
|
||||
<% plugins.forEach(function(plugin) { %>
|
||||
<option data-name="<%= plugin.frontEndPath %>" title="<%= plugin.name %> by <%= plugin.author %> [v<%= plugin.version %>]">
|
||||
<%= plugin.name %> by <%= plugin.author %> [v<%= plugin.version %>]
|
||||
</option>
|
||||
<% }); %>
|
||||
</select><br><br>
|
||||
<a href="https://github.com/NoobishSVK/fm-dx-webserver/wiki/Plugin-List" target="_blank">Download new plugins here!</a>
|
||||
</div>
|
||||
|
||||
<div class="panel-100 p-bottom-20">
|
||||
<h3>Plugin settings</h3>
|
||||
<div id="plugin-settings">No plugin settings are available.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-full m-0 tab-content no-bg" id="identification" role="tabpanel">
|
||||
<h2>Identification & Map</h2>
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-50 p-bottom-20">
|
||||
<h3>Basic info</h3>
|
||||
|
||||
<p>Set your tuner name and description here.<br>This info will be visible to anyone who tunes in. </p>
|
||||
<div class="panel-full no-bg" style="padding-left: 20px; padding-right: 20px;">
|
||||
<label for="identification-tunerName" style="width: 100%;max-width: 768px; margin:auto;">Webserver name:</label>
|
||||
<input style="width: 100%; max-width: 768px;" class="input-text br-15" type="text" name="identification-tunerName" id="identification-tunerName" placeholder="Fill your server name here." maxlength="32">
|
||||
<br>
|
||||
<label for="identification-tunerDesc" style="width: 100%;max-width: 768px; margin: auto;">Webserver description:</label>
|
||||
<textarea id="identification-tunerDesc" class="br-15" name="webserver-desc" placeholder="Fill the server description here. You can put useful info here such as your antenna setup. You can use simple markdown." maxlength="255"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-50">
|
||||
<h3>Online map</h3>
|
||||
<p>If your location information is filled,<br>you can add your tuner to a public list.</p>
|
||||
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Broadcast to map', id: 'identification-broadcastTuner'}) %><br>
|
||||
<%- include('_components', {component: 'text', cssClass: 'br-15', placeholder: 'Your e-mail or Discord...', label: 'Owner contact', id: 'identification-contact'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'br-15', label: 'Proxy address', id: 'identification-proxyIp'}) %>
|
||||
|
||||
<p>Check your tuner at <strong><a href="https://servers.fmdx.org" target="_blank" class="color-4">servers.fmdx.org</a></strong>.</p>
|
||||
<p class="text-small text-gray">By activating the <strong>Broadcast to map</strong> option,<br>you agree to the <a href="https://fmdx.org/projects/webserver.php#rules" target="_blank">Terms of Service</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-100">
|
||||
<h3>Location</h3>
|
||||
<p class="text-gray">Location info is useful for automatic identification of stations using RDS.</p>
|
||||
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Latitude', id: 'identification-lat'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Longitude', id: 'identification-lon'}) %>
|
||||
|
||||
<div id="map"></div>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-full m-0 tab-content no-bg" id="users" role="tabpanel">
|
||||
<h2>User management</h2>
|
||||
<div class="panel-100">
|
||||
<h3>Chat options</h3>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Chat', id: 'webserver-chatEnabled'}) %>
|
||||
</div>
|
||||
|
||||
<div class="panel-100 p-bottom-20">
|
||||
<h3>Banlist</h3>
|
||||
<p>If you have users that don't behave on your server, you can choose to ban them by their IP address.<br>
|
||||
<span class="text-gray">You can see their IP address by hovering over their nickname. One IP per row.</span></p>
|
||||
|
||||
<table class="table-big">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP Address</th>
|
||||
<th>Location</th>
|
||||
<th>Ban date</th>
|
||||
<th>Reason</th>
|
||||
<th class="color-5"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'IP address', label: '', id: 'banlist-add-ip'}) %></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: 'Ban reason (note)', label: '', id: 'banlist-add-reason'}) %></td>
|
||||
<td class="color-5">
|
||||
<a href="#" id="banlist-add-link"><i class="fa-solid fa-plus-circle banlist-add"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
<% if (banlist.length > 0) { %>
|
||||
<% banlist.forEach(bannedUser => { %>
|
||||
<tr>
|
||||
<% if (Array.isArray(bannedUser)) { %>
|
||||
<!-- If it's an array, use its values -->
|
||||
<td style="text-align: center !important;"><a href="https://dnschecker.org/ip-location.php?ip=<%= bannedUser[0] %>" target="_blank"><%= bannedUser[0] %></a></td>
|
||||
<td><%= bannedUser[1] %></td>
|
||||
<td class="text-bold"><%= new Date(parseInt(bannedUser[2])).toLocaleString() %></td> <!-- Assuming the ban date is a timestamp in seconds -->
|
||||
<td><%= bannedUser[3] %></td>
|
||||
<% } else { %>
|
||||
<!-- If it's just an IP address without additional data, show it as is -->
|
||||
<td style="text-align: center !important;"><a href="https://dnschecker.org/ip-location.php?ip=<%= bannedUser %>" target="_blank"><%= bannedUser %></a></td>
|
||||
<td>Unknown</td>
|
||||
<td class="text-bold">Unknown</td>
|
||||
<td>Unknown</td>
|
||||
<% } %>
|
||||
<td><a href="#" class="banlist-remove"><i class="fa-solid fa-lock-open text-gray"></i></a></td>
|
||||
</tr>
|
||||
<% }); %>
|
||||
<% } else { %>
|
||||
<tr>
|
||||
<td colspan="5" style="text-align: center">The banlist is empty.</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-full m-0 tab-content no-bg" id="startup" role="tabpanel">
|
||||
<h2>Startup settings</h2>
|
||||
<div class="flex-container">
|
||||
<div class="panel-100-real p-bottom-20" style="z-index: 10; padding-bottom: 120px;">
|
||||
<h3>On startup</h3>
|
||||
<p>These settings will be applied after a server launch or restart.</p>
|
||||
<div class="flex-container flex-center p-20">
|
||||
<% if (device === 'tef') { %>
|
||||
<%- include('_components', { component: 'dropdown', id: 'ceqStartup-dropdown', inputId: 'ceqStartup', label: 'cEQ', cssClass: '', placeholder: 'Disabled',
|
||||
options: [
|
||||
{ value: '0', label: 'Disabled' },
|
||||
{ value: '1', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<%- include('_components', { component: 'dropdown', id: 'imsStartup-dropdown', inputId: 'imsStartup', label: 'iMS', cssClass: '', placeholder: 'Disabled',
|
||||
options: [
|
||||
{ value: '0', label: 'Disabled' },
|
||||
{ value: '1', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<% } else if (device === 'xdr') { %>
|
||||
<%- include('_components', { component: 'dropdown', id: 'rfStartup-dropdown', inputId: 'ceqStartup', label: 'RF+', cssClass: '', placeholder: 'Disabled',
|
||||
options: [
|
||||
{ value: '0', label: 'Disabled' },
|
||||
{ value: '1', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<%- include('_components', { component: 'dropdown', id: 'ifStartup-dropdown', inputId: 'imsStartup', label: 'IF+', cssClass: '', placeholder: 'Disabled',
|
||||
options: [
|
||||
{ value: '0', label: 'Disabled' },
|
||||
{ value: '1', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<% } %>
|
||||
<%- include('_components', { component: 'dropdown', id: 'stereoStartup-dropdown', inputId: 'stereoStartup', label: 'Stereo Mode', cssClass: '', placeholder: 'Stereo (Default)',
|
||||
options: [
|
||||
{ value: '0', label: 'Stereo (Default)' },
|
||||
{ value: '1', label: 'Mono' },
|
||||
]
|
||||
}) %><br>
|
||||
</div>
|
||||
<div class="panel-100-real p-bottom-20 no-bg">
|
||||
<%- include('_components', { component: 'dropdown', id: 'antennaStartup-dropdown', inputId: 'antennaStartup', label: 'Antenna', cssClass: '', placeholder: 'Antenna 0 (Default)',
|
||||
options: [
|
||||
{ value: '0', label: 'Antenna 0 (Default)' },
|
||||
{ value: '1', label: 'Antenna 1' },
|
||||
{ value: '2', label: 'Antenna 2' },
|
||||
{ value: '3', label: 'Antenna 3' },
|
||||
]
|
||||
}) %><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="panel-100-real p-bottom-20 bottom-20" style="z-index: 9; padding-bottom: 180px;">
|
||||
<h3>Empty server defaults</h3>
|
||||
<p>These settings will apply once the last user disconnects from the server, so the server can be ready for a new user with default settings.</p>
|
||||
<div class="flex-container flex-center p-20">
|
||||
<%- include('_components', { component: 'dropdown', id: 'bwAutoNoUsers-dropdown', inputId: 'bwAutoNoUsers', label: 'Auto BW', cssClass: '', placeholder: 'Unchanged',
|
||||
options: [
|
||||
{ value: '0', label: 'Unchanged' },
|
||||
{ value: '1', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<% if (device === 'tef') { %>
|
||||
<%- include('_components', { component: 'dropdown', id: 'ceqNoUsers-dropdown', inputId: 'ceqNoUsers', label: 'cEQ', cssClass: '', placeholder: 'Unchanged',
|
||||
options: [
|
||||
{ value: '0', label: 'Unchanged' },
|
||||
{ value: '1', label: 'Disabled' },
|
||||
{ value: '2', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<%- include('_components', { component: 'dropdown', id: 'imsNoUsers-dropdown', inputId: 'imsNoUsers', label: 'iMS', cssClass: '', placeholder: 'Unchanged',
|
||||
options: [
|
||||
{ value: '0', label: 'Unchanged' },
|
||||
{ value: '1', label: 'Disabled' },
|
||||
{ value: '2', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<% } else if (device === 'xdr') { %>
|
||||
<%- include('_components', { component: 'dropdown', id: 'rfNoUsers-dropdown', inputId: 'ceqNoUsers', label: 'RF+', cssClass: '', placeholder: 'Unchanged',
|
||||
options: [
|
||||
{ value: '0', label: 'Unchanged' },
|
||||
{ value: '1', label: 'Disabled' },
|
||||
{ value: '2', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<%- include('_components', { component: 'dropdown', id: 'ifNoUsers-dropdown', inputId: 'imsNoUsers', label: 'IF+', cssClass: '', placeholder: 'Unchanged',
|
||||
options: [
|
||||
{ value: '0', label: 'Unchanged' },
|
||||
{ value: '1', label: 'Disabled' },
|
||||
{ value: '2', label: 'Enabled' },
|
||||
]
|
||||
}) %><br>
|
||||
<% } %>
|
||||
<%- include('_components', { component: 'dropdown', id: 'stereoNoUsers-dropdown', inputId: 'stereoNoUsers', label: 'Stereo Mode', cssClass: '', placeholder: 'Unchanged',
|
||||
options: [
|
||||
{ value: '0', label: 'Unchanged' },
|
||||
{ value: '1', label: 'Stereo' },
|
||||
{ value: '2', label: 'Mono' },
|
||||
]
|
||||
}) %><br>
|
||||
</div>
|
||||
<div class="panel-100-real p-bottom-20 no-bg">
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Delayed Antenna Change', id: 'antennaNoUsersDelay'}) %><br>
|
||||
<%- include('_components', { component: 'dropdown', id: 'antennaNoUsers-dropdown', inputId: 'antennaNoUsers', label: 'Antenna', cssClass: '', placeholder: 'Unchanged',
|
||||
options: [
|
||||
{ value: '0', label: 'Unchanged' },
|
||||
{ value: '1', label: 'Antenna 0' },
|
||||
{ value: '2', label: 'Antenna 1' },
|
||||
{ value: '3', label: 'Antenna 2' },
|
||||
{ value: '4', label: 'Antenna 3' },
|
||||
]
|
||||
}) %>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-full m-0 tab-content no-bg" id="extras" role="tabpanel">
|
||||
<h2>Extras</h2>
|
||||
<div class="panel-100 p-bottom-20">
|
||||
<h3>FMLIST Integration</h3>
|
||||
<p>FMLIST integration allows you to get potential DXes logged on the <a href="http://fmlist.org/fm_logmap.php?hours=900" target="_blank" class="text-bold color-4">FMLIST Visual Logbook</a>.<br>
|
||||
Your server also needs to have a valid UUID, which is obtained by registering on maps in the <strong>Identification & Map</strong> tab.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'FMLIST integration', id: 'extras-fmlistIntegration'}) %><br>
|
||||
<p>If you don't feel comfortable with the general public logging on your server, you can make this feature available only for people with a password</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Admin-only logging', id: 'extras-fmlistAdminOnly'}) %><br>
|
||||
|
||||
<p>You can also fill in your OMID from FMLIST.org, if you want the logs to be saved to your account.</p>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '', label: 'OMID', id: 'extras-fmlistOmid'}) %>
|
||||
</div>
|
||||
<div class="panel-100 p-bottom-20">
|
||||
<h3>Tunnel</h3>
|
||||
<p>When you become an <a href="https://buymeacoffee.com/fmdx" target="_blank"><strong>FMDX.org supporter</strong></a>, you can host your webserver without the need of a public IP address & port forwarding.<br>
|
||||
When you become a supporter, you can message the Founders on Discord for your login details.</p><br>
|
||||
<p>You can also get an tunnel from kuba201 discord, one of the contributors of this version of the application.</p>
|
||||
<h4>Main tunnel settings</h4>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Enable tunnel', id: 'tunnel-enabled'}) %><br>
|
||||
<%- include('_components', { component: 'dropdown', id: 'tunnel-regionSelect', inputId: 'tunnel-region', label: 'Official server region', cssClass: '', placeholder: 'Europe',
|
||||
options: [
|
||||
{ value: 'eu', label: 'Europe' },
|
||||
{ value: 'us', label: 'Americas' },
|
||||
{ value: 'sg', label: 'Asia & Oceania' },
|
||||
{ value: 'pldx', label: 'Poland (k201)' },
|
||||
]
|
||||
}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Username', id: 'tunnel-username'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-250 br-15', password: true, placeholder: '', label: 'Token', id: 'tunnel-token'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Subdomain name', id: 'tunnel-subdomain'}) %><br>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Low latency mode', id: 'tunnel-lowLatencyMode'}) %><br>
|
||||
<p>Enabling low latency mode may provide better experience, however it will also use more bandwidth.</p>
|
||||
|
||||
<h4 class="top-25">Community tunnel settings</h4>
|
||||
<p>You can also self-host or ask other people to provide you a token. In this case, the server owner is responsible for any potential security issues.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Use a community tunnel', id: 'tunnel-community-enabled'}) %><br>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-250 br-15', placeholder: '', label: 'Community Tunnel host (IP or hostname)', id: 'tunnel-community-host'}) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/ver.js"></script>
|
||||
<script src="js/toast.js"></script>
|
||||
<script src="js/settings.js"></script>
|
||||
<script src="js/dropdown.js"></script>
|
||||
<script src="js/setup.js"></script>
|
||||
<script src="js/confighandler.js"></script>
|
||||
<% enabledPlugins?.forEach(function(plugin) { %>
|
||||
<script src="js/plugins/<%= plugin %>"></script>
|
||||
<% }); %>
|
||||
|
||||
<script>
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.ctrlKey && event.key === 's') {
|
||||
event.preventDefault();
|
||||
if (event.repeat) return;
|
||||
submitConfig();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,228 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Wizard - FM-DX Webserver</title>
|
||||
<link href="css/entry.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/flags.min.css" type="text/css" rel="stylesheet">
|
||||
<link href="css/libs/fontawesome.css" type="text/css" rel="stylesheet">
|
||||
<script src="js/libs/jquery.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" type="text/css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<div id="toast-container" style="position: fixed; top: 20px; right: 20px; z-index: 9999;"></div>
|
||||
<div class="wrapper-outer wrapper-full">
|
||||
<div id="wrapper">
|
||||
<div class="panel-100 no-bg">
|
||||
<img class="top-10" src="../images/openradio_logo_neutral.png" height="64px">
|
||||
<h2 class="text-monospace text-light text-gray">[SETUP WIZARD]</h2>
|
||||
</div>
|
||||
<div class="panel-100 no-bg flex-container flex-center flex-phone">
|
||||
<div class="btn-rounded-cube activated">1</div>
|
||||
<div class="btn-rounded-cube">2</div>
|
||||
<div class="btn-rounded-cube">3</div>
|
||||
<div class="btn-rounded-cube">4</div>
|
||||
<div class="btn-rounded-cube">5</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-100">
|
||||
<!-- BASIC SETTINGS -->
|
||||
<div class="panel-100 step no-bg" id="step1">
|
||||
<h2 class="settings-heading">Basic settings</h2>
|
||||
<p class="m-0">Welcome to the setup wizard! Let's set up some basic things.</p>
|
||||
|
||||
<h3 class="settings-heading">Webserver connection</h3>
|
||||
<p class="m-0">Leave the IP at 0.0.0.0 unless you explicitly know you have to change it.<br>DO NOT enter your public IP here.</p>
|
||||
<div class="flex-center top-25">
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '0.0.0.0', label: 'Webserver IP', id: 'webserver-webserverIp'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '8080', label: 'Webserver port', id: 'webserver-webserverPort'}) %><br>
|
||||
</div>
|
||||
</div>
|
||||
<!-- BASIC SETTINGS END -->
|
||||
<!-- TUNER SETTINGS -->
|
||||
<div id="step2" class="step" style="display: none">
|
||||
<h2 class="settings-heading">Tuner settings</h2>
|
||||
|
||||
<h3 class="settings-heading">Tuner type</h3>
|
||||
<p class="m-0">Settings a proper device type ensures that the correct interface and settings will load.</p>
|
||||
<div class="panel-100 no-bg flex-center" style="max-width: 520px; margin: 10px auto 0;">
|
||||
<%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x',
|
||||
options: tunerProfiles.map(profile => ({
|
||||
value: profile.id,
|
||||
label: profile.label
|
||||
}))
|
||||
}) %><br>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<h3 class="settings-heading">Tuner connection</h3>
|
||||
<div style="width: 300px;" class="auto top-10">
|
||||
<label class="toggleSwitch nolabel" onclick="">
|
||||
<input id="xdrd-wirelessConnection" type="checkbox" aria-label="Tuner connection type"/>
|
||||
<a></a>
|
||||
<span>
|
||||
<span class="left-span">Direct</span>
|
||||
<span class="right-span">TCP/IP</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="tuner-usb" class="top-25">
|
||||
<p>It's time to choose your serial port.</p>
|
||||
|
||||
<div class="panel-100 no-bg flex-center">
|
||||
<%- include('_components', {
|
||||
component: 'dropdown',
|
||||
id: 'deviceList',
|
||||
inputId: 'xdrd-comPort',
|
||||
label: 'Serial port',
|
||||
cssClass: '',
|
||||
placeholder: 'Choose your serial port',
|
||||
options: serialPorts.map(serialPort => ({
|
||||
value: serialPort.path,
|
||||
label: `${serialPort.path} - ${serialPort.friendlyName}`
|
||||
}))
|
||||
}) %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div id="tuner-wireless" class="top-25">
|
||||
<p class="m-0">If you are connecting your tuner <strong>wirelessly</strong>, enter the tuner IP. <br> If you use <strong>xdrd</strong>, use 127.0.0.1 as your IP.</p>
|
||||
<div class="flex-center top-25">
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', label: 'xdrd IP address', id: 'xdrd-xdrdIp'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', label: 'xdrd port', id: 'xdrd-xdrdPort'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', label: 'xdrd password', id: 'xdrd-xdrdPassword', password: true}) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TUNER SETTINGS END -->
|
||||
<!-- AUDIO SETTINGS -->
|
||||
<div id="step3" class="step" style="display: none;">
|
||||
<div class="panel-100 no-bg" style="min-height: 120px;margin-bottom: 0;">
|
||||
<h2 class="settings-heading">Audio settings</h2>
|
||||
<p class="m-0">In this section, we will set up the audio.<br>
|
||||
Choose the audio port your tuner is connected to and desired audio settings here.</p>
|
||||
<p class="text-gray">Recommended defaults have already been set for the audio quality, you can keep them as-is.</p>
|
||||
|
||||
<div class="panel-100 no-bg p-bottom-20 flex-container flex-center">
|
||||
<%- include('_components', {
|
||||
component: 'dropdown',
|
||||
id: 'audioList',
|
||||
inputId: 'audio-audioDevice',
|
||||
label: 'Audio device',
|
||||
cssClass: '',
|
||||
placeholder: 'Choose your audio device',
|
||||
options: [
|
||||
...videoDevices.map(device => ({
|
||||
value: device.name,
|
||||
label: `${device.name}`
|
||||
})),
|
||||
...audioDevices.map(device => ({
|
||||
value: device.name,
|
||||
label: `${device.name}`
|
||||
}))
|
||||
]
|
||||
}) %>
|
||||
|
||||
<%- include('_components', { component: 'dropdown', id: 'audio-channels-dropdown', inputId: 'audio-audioChannels', label: 'Audio channels', cssClass: '', placeholder: 'Stereo',
|
||||
options: [
|
||||
{ value: '2', label: 'Stereo' },
|
||||
{ value: '1', label: 'Mono' }
|
||||
]
|
||||
}) %>
|
||||
|
||||
<%- include('_components', { component: 'dropdown', id: 'audio-quality-dropdown', inputId: 'audio-audioBitrate', label: 'Audio quality', cssClass: '', placeholder: '128kbps (standard)',
|
||||
options: [
|
||||
{ value: '64k', label: '64kbps (lowest quality)' },
|
||||
{ value: '96k', label: '96kbps (low quality)' },
|
||||
{ value: '128k', label: '128kbps (standard)' },
|
||||
{ value: '192k', label: '192kbps (high quality)' },
|
||||
{ value: '256k', label: '256kbps (very high quality)' },
|
||||
{ value: '320k', label: '320kbps (ultra quality)' }
|
||||
]
|
||||
}) %>
|
||||
</div>
|
||||
|
||||
<div class="panel-100 no-bg text-center">
|
||||
<div class="flex-container">
|
||||
<div class="panel-50 no-bg">
|
||||
<p>If you use an USB audio card on Linux, enabling this option might fix your audio issues.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'panel-100 flex-container flex-center', label: 'ALSA Software mode', id: 'audio-softwareMode'}) %>
|
||||
</div>
|
||||
<div class="panel-50 no-bg">
|
||||
<p>Legacy option for Linux / macOS that could resolve audio issues, but will consume additional CPU and RAM usage.</p>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: 'panel-100 flex-container flex-center', label: 'Additional FFmpeg', id: 'audio-ffmpeg'}) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- AUDIO SETTINGS END -->
|
||||
<!-- IDENTIFICATION START -->
|
||||
<div id="step4" class="step" style="display: none;">
|
||||
<div class="panel-100 no-bg" style="padding-bottom: 20px;">
|
||||
<h2 class="settings-heading">Webserver info</h2>
|
||||
<p class="m-0">In this part, we will set up your webserver info, such as the server name, description and location.</p>
|
||||
<label for="identification-tunerName" style="width: 100%;max-width: 768px; margin:auto;">Webserver name:</label>
|
||||
<input style="width: 100%; max-width: 768px;" class="input-text br-15" type="text" name="identification-tunerName" id="identification-tunerName" placeholder="Fill your server name here." maxlength="32">
|
||||
<br>
|
||||
<label for="identification-tunerDesc" style="width: 100%;max-width: 768px; margin: auto;">Webserver description:</label>
|
||||
<textarea id="identification-tunerDesc" name="webserver-desc" class="br-15" placeholder="Fill the server description here. You can put useful info here such as your antenna setup. You can use simple markdown." maxlength="255"></textarea>
|
||||
|
||||
<h3 class="settings-heading">Location</h3>
|
||||
<p>Location info is useful for automatic identification of stations using RDS.</p>
|
||||
<div class="panel-100 no-bg flex-container flex-center">
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-250 br-15', placeholder: '', label: 'Latitude', id: 'identification-lat'}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-250 br-15', placeholder: '', label: 'Longitude', id: 'identification-lon'}) %>
|
||||
</div>
|
||||
<div id="map"></div>
|
||||
|
||||
<h3 class="settings-heading">Map broadcast</h3>
|
||||
<p class="m-0">If your location info is filled, you can add your tuner to a public list.</p>
|
||||
<p class="m-0">The list is available at <strong><a href="https://servers.fmdx.org" target="_blank" class="color-4">servers.fmdx.org</a></strong>.</p>
|
||||
<p class="text-small text-gray">By activating the <strong>Broadcast to map</strong> option, you agree to the <a href="https://fmdx.org/projects/webserver.php#rules" target="_blank">Terms of Service</a>.</p>
|
||||
|
||||
<div class="panel-100 no-bg flex-container flex-center">
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Broadcast to map', id: 'identification-broadcastTuner'}) %><br>
|
||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Allow tuning without password', id: 'publicTuner'}) %>
|
||||
</div>
|
||||
|
||||
<p class="text-gray">If you use a proxy / tunnel service, enter the access link here. If you don't know what a proxy is, leave it empty.</p>
|
||||
|
||||
<div class="panel-100 no-bg flex-container flex-center">
|
||||
<%- include('_components', {component: 'text', cssClass: 'br-15', label: 'Broadcast address (if using a proxy)', id: 'identification-proxyIp'}) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- IDENTIFICATION END -->
|
||||
<!-- ADMIN SETTINGS START -->
|
||||
<div id="step5" class="step" style="display: none;">
|
||||
<h2 class="settings-heading">Admin panel settings</h2>
|
||||
<p>We are at the last and final step of the wizard.</p>
|
||||
|
||||
<p>Here we can set the password. Tune password is optional.<br>Setting an admin password allows you to change settings later and setting one up is mandatory.</p>
|
||||
<div class="flex-container flex-center">
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Tune password', id: 'password-tunePass', password: true}) %>
|
||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Admin password', id: 'password-adminPass', password: true}) %><br>
|
||||
</div>
|
||||
<p>You can now click the <strong>save button</strong> to save your settings. After that, you will need to restart the webserver.</p>
|
||||
</div>
|
||||
|
||||
<div class="panel-100 no-bg">
|
||||
<button class="btn-prev"><i class="fa-solid fa-arrow-left"></i></button>
|
||||
<button class="btn-next">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-100 no-bg">
|
||||
<p>Feel free to contact us on <a href="https://discord.gg/ZAVNdS74mC" target="_blank"><strong><i class="fa-brands fa-discord"></i> Discord</strong></a> for community support.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/settings.js"></script>
|
||||
<script src="js/dropdown.js"></script>
|
||||
<script src="js/toast.js"></script>
|
||||
<script src="js/setup.js"></script>
|
||||
<script src="js/wizard.js"></script>
|
||||
<script src="js/confighandler.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user