1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-26 22:13:53 +01:00

ejs + webadmin + bugfixes

This commit is contained in:
NoobishSVK
2024-02-04 16:56:35 +01:00
parent d6b128c0bd
commit c848bef002
27 changed files with 1329 additions and 161 deletions

View File

@@ -1,3 +1,15 @@
h1 {
color: var(--color-4);
font-size: 52px;
font-weight: 300;
margin-top: 0;
margin-bottom: 0;
}
h1#tuner-name {
font-size: 32px;
}
h2 {
color: var(--color-4);
margin-bottom: 0;
@@ -8,9 +20,22 @@ h3 {
font-size: 22px;
}
p#tuner-desc {
margin: 0;
}
label {
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
display: block;
text-align: left;
color: var(--color-4);
}
.canvas-container {
width: 100%;
height: 200px;
height: 175px;
}
#data-ant {
@@ -36,7 +61,7 @@ h3 {
margin-right: 5px;
}
#color-settings, #settings {
#settings, #back-btn {
background: transparent;
border: 0;
color: white;
@@ -53,12 +78,13 @@ h3 {
cursor: pointer;
}
#color-settings {
top: 96px;
#settings:hover, #back-btn:hover {
background: var(--color-3);
}
#settings:hover, #color-settings:hover {
background: var(--color-3);
#back-btn {
left: 15px;
right: auto;
}
#af-list ul {
@@ -79,6 +105,49 @@ h3 {
display: none;
}
.checkbox input[type="checkbox"] {
padding: 0;
height: initial;
width: initial;
margin-bottom: 0;
display: none;
cursor: pointer;
}
.checkbox label {
position: relative;
cursor: pointer;
}
.checkbox label:before {
content:'';
appearance: none;
-webkit-appearance: none;
background-color: transparent;
border: 2px solid var(--color-4);
padding: 10px;
display: inline-block;
position: relative;
vertical-align: middle;
cursor: pointer;
margin-right: 5px;
}
.form-group input:checked + label:after {
content: '✓';
display: block;
position: absolute;
top: 2px;
left: 6px;
width: 16px;
height: 16px;
}
.tuner-info {
margin-top: 0px !important;
margin-bottom: 0px !important;
}
@media (max-width: 768px) {
canvas, #flags-container {
display: none;
@@ -153,6 +222,9 @@ h3 {
.button-ims {
order: 3;
}
.tuner-info {
margin-bottom: -60px !important;
}
}
@media only screen and (min-width: 960px) and (max-height: 860px) {
@@ -165,4 +237,13 @@ h3 {
.canvas-container {
height: 120px;
}
.tuner-info #tuner-name {
float: left;
font-size: 24px;
}
.tuner-info #tuner-desc {
float: right;
text-align: right;
}
}

View File

@@ -1,4 +1,4 @@
button {
button, input[type="submit"] {
width: 100%;
height: 100%;
border: 0;
@@ -18,6 +18,18 @@ button:hover {
opacity: 0.6;
}
input[type="text"], textarea, input[type="password"] {
width: 300px;
min-height: 46px;
padding-left: 20px;
box-sizing: border-box;
border: 2px solid transparent;
outline: 0;
color: white;
background-color: var(--color-1);
font-family: 'Titillium Web', sans-serif;
}
#tune-buttons input[type="text"] {
width: 50%;
height: 100%;

View File

@@ -53,8 +53,7 @@
border: none;
font-size: 16px;
overflow: hidden;
opacity: 0;
visibility: hidden;
display: none;
background: var(--color-main);
color: var(--color-4);
border: 1px solid var(--color-4);
@@ -70,9 +69,9 @@
background: var(--color-4);
}
.dropdown.opened .options {
opacity: 1;
visibility: visible;
display:block;
transform: translateY(0);
position:absolute;
}
.dropdown.opened::before {
transform: rotate(-225deg);

View File

@@ -6,4 +6,5 @@
@import url("dropdown.css"); /* Custom dropdown menus */
@import url("panels.css"); /* Different panels and their sizes */
@import url("modal.css"); /* Modal window */
@import url("setup.css"); /* Web setup interface */
@import url("helpers.css"); /* Stuff that is used often such as text changers etc */

View File

@@ -30,6 +30,10 @@
color: var(--color-4);
}
.br-0 {
border-radius: 0px;
}
.br-5 {
border-radius: 5px;
}
@@ -137,6 +141,14 @@
padding: 10px;
}
.p-bottom-20 {
padding-bottom: 20px;
}
.input-text {
background-color: var(--color-2) !important;
}
@media only screen and (max-width: 960px) {
.text-medium-big {
font-size: 32px;

View File

@@ -55,6 +55,11 @@ body {
width: 1180px;
max-width: 1180px;
}
#wrapper.setup-wrapper {
margin: auto;
position: static;
transform: none;
}
@media (max-width: 1180px) {
#wrapper {

View File

@@ -68,13 +68,6 @@
background: var(--color-5);
}
.modal label {
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
display: block;
}
@media only screen and (max-width: 768px) {
.modal-content {
min-width: 90% !important;

View File

@@ -17,6 +17,10 @@
width: 33%;
}
.panel-50 {
width: 50%;
}
.panel-75 {
width: 68%;
}

42
web/css/setup.css Normal file
View File

@@ -0,0 +1,42 @@
.setup-wrapper .form-group, .setup-wrapper textarea {
display: inline-block;
float: none;
}
.setup-wrapper .form-group {
margin-right: 5px;
margin-left: 5px;
}
.setup-wrapper textarea {
width: 100%;
max-width: 768px;
background-color: var(--color-2);
height: 100px;
font-size: 14px;
padding-top: 10px;
}
#map {
height:400px;
width:100%;
overflow: hidden;
max-width:800px;
margin: auto;
margin-bottom: 20px;
}
.setup-wrapper h3 {
font-weight: 300;
margin: 8px;
}
.w-150 {
width: 150px !important
}
.w-100 {
width: 100px !important;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>FM-DX Webserver</title>
<title>FM-DX Webserver [<%= tunerName %>]</title>
<link href="css/entry.css" type="text/css" rel="stylesheet">
<link href="css/flags.min.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">
@@ -9,6 +9,11 @@
<link rel="icon" type="image/png" href="favicon2.png" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta property="og:title" content="FM-DX WebServer">
<meta property="og:type" content="website">
<meta property="og:image" content="/favicon2.png">
<meta property="og:description" content="This server us running the FM-DX Webserver software by Noobish.">
<!-- 3LAS Scripts for Audio streaming -->
<script src="js/3las/util/3las.helpers.js"></script>
<script src="js/3las/util/3las.logging.js"></script>
@@ -44,6 +49,11 @@
<body>
<audio id="audioTag"></audio>
<div id="wrapper">
<div class="panel-100 no-bg tuner-info">
<h1 id="tuner-name"><%= tunerName %> <% if (tunerLock) { %><i class="fa-solid fa-lock" title="Tuner is currently locked to admin."></i><% } %></h1>
<p id="tuner-desc"><%= tunerDesc %></p>
<div style="clear: both"></div>
</div>
<div class="canvas-container hide-phone">
<canvas id="signal-canvas"></canvas>
</div>
@@ -187,17 +197,6 @@
<div class="form-group">
<label for="themes" style="margin-top: 50px;"><i class="fa-solid fa-palette"></i> Theme:</label>
<!--<select name="themes" style="margin-bottom: 15px;" id="theme-selector">
<option value="theme1">Monochrome</option>
<option value="theme2">Red</option>
<option value="theme3">Green</option>
<option value="theme4">Cyan</option>
<option value="theme5">Orange</option>
<option value="theme6">Pink</option>
<option value="theme7">Blurple</option>
<option value="theme8">AMOLED</option>
</select>-->
<div class="dropdown" id="theme-selector">
<input type="text" placeholder="Theme" readonly />
<ul class="options">
@@ -215,13 +214,8 @@
<div class="form-group">
<label for="signal" style="margin-top: 50px;"><i class="fa-solid fa-signal"></i> Signal units:</label>
<!--<select name="signal" style="margin-bottom: 15px;" id="signal-selector">
<option value="dbf">dBf</option>
<option value="dbuv">dBuV</option>
<option value="dbm">dBm</option>
</select>-->
<div class="dropdown" id="signal-selector">
<input type="text" placeholder="Theme" readonly />
<input type="text" placeholder="Signal Units" readonly />
<ul class="options">
<li class="option" data-value="dbf">dBf</li>
<li class="option" data-value="dbuv">dBuV</li>
@@ -234,13 +228,27 @@
<label for="themes"><i class="fa-solid fa-user"></i> Users online:</label>
<span id="users-online" name="users-online">0</span>
</div>
<% if (isAdminAuthenticated) { %>
<p>You are logged in as an adminstrator. <a href="/setup">Setup</a> | <a class="logout-link" href="#">Logout</a></p>
<% } else if (isTuneAuthenticated) { %>
<p>You are logged in and can control the receiver. <a class="logout-link" href="#">Logout</a></p>
<% } else { %>
<form action="/login" method="post" id="login-form">
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<button type="submit" class="br-0 w-100" style="height: 44px">Login</button>
</form>
<% } %>
<div id="login-message"></div>
<div class="flex-container flex-left text-left hover-brighten p-10 br-5" onclick="window.open('https://discord.com/invite/ZAVNdS74mC')">
<i class="fa-brands fa-discord"></i>&nbsp;<span>Join our <strong>OpenRadio Discord</strong> community!</span>
</div>
<div class="flex-container flex-left text-left bottom-20 hover-brighten p-10 br-5" onclick="window.open('https://buymeacoffee.com/noobish')">
<i class="fa-solid fa-hand-holding-medical"></i>&nbsp;<span><strong>Support</strong> the developer!</span>
</div>
<p class="text-small">FM-DX WebServer by <a href="https://noobish.eu" target="_blank">Noobish</a> & the OpenRadio community.</p>
<p class="text-small">FM-DX WebServer <span style="color: var(--color-3);">v1.0.0 [4/2/2024]</span> by <a href="https://noobish.eu" target="_blank">Noobish</a> & the OpenRadio community.</p>
<p class="text-small bottom-50">This app works thanks to these amazing projects: <br>
<span class="text-smaller">- librdsparser by <a href="https://fmdx.pl" target="_blank">Konrad Kosmatka</a></span><br>
<span class="text-smaller">- 3LAS by <a href="https://github.com/JoJoBond/3LAS" target="_blank">JoJoBond</a></span><br>

View File

@@ -127,11 +127,8 @@ function getInitialSettings() {
// Use the received data (data.qthLatitude, data.qthLongitude) as needed
localStorage.setItem('qthLatitude', data.qthLatitude);
localStorage.setItem('qthLongitude', data.qthLongitude);
localStorage.setItem('webServerName', data.webServerName);
localStorage.setItem('audioPort', data.audioPort);
localStorage.setItem('streamEnabled', data.streamEnabled);
document.title = 'FM-DX Webserver [' + data.webServerName + ']';
},
error: function(error) {
console.error('Error:', error);

View File

@@ -47,6 +47,63 @@
signalSelector.find('input').val($(event.target).text()); // Set the text of the clicked option to the input
localStorage.setItem('signalUnit', selectedSignalUnit);
});
$('#login-form').submit(function (event) {
event.preventDefault();
// Perform an AJAX request to the /login endpoint
$.ajax({
type: 'POST',
url: '/login',
data: $(this).serialize(),
success: function (data) {
// Update the content on the page with the message from the response
$('#login-message').text(data.message);
setTimeout(function () {
location.reload(true);
}, 1750);
},
error: function (xhr, status, error) {
// Handle error response
if (xhr.status === 403) {
// Update the content on the page with the message from the error response
$('#login-message').text(xhr.responseJSON.message);
} else {
// Handle other types of errors if needed
console.error('Error:', status, error);
}
}
});
});
// Assuming you have an anchor tag with id 'logout-link'
$('.logout-link').click(function (event) {
event.preventDefault();
// Perform an AJAX request to the /logout endpoint
$.ajax({
type: 'GET', // Assuming the logout is a GET request, adjust accordingly
url: '/logout',
success: function (data) {
// Update the content on the page with the message from the response
$('#login-message').text(data.message);
setTimeout(function () {
location.reload(true);
}, 1750);
},
error: function (xhr, status, error) {
// Handle error response
if (xhr.status === 403) {
// Update the content on the page with the message from the error response
$('#login-message').text(xhr.responseJSON.message);
} else {
// Handle other types of errors if needed
console.error('Error:', status, error);
}
}
});
});
});

243
web/js/setup.js Normal file
View File

@@ -0,0 +1,243 @@
var map;
var pin;
var tilesURL='https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}.png';
var mapAttrib='&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, Tiles by <a href="http://stadiamaps.com/" target="_blank">Stadiamaps</a>';
var hostParts = window.location.host.split(':');
var hostname = hostParts[0]; // Extract the hostname
var port = hostParts[1] || '80'; // Extract the port or use a default (e.g., 8080)
var serverAddress = 'http://' + hostname + ':' + port;
// add map container
$(document).ready(function() {
MapCreate();
fetchData();
map.on('click', function(ev) {
$('#lat').val((ev.latlng.lat).toFixed(6));
$('#lng').val((ev.latlng.lng).toFixed(6));
if (typeof pin == "object") {
pin.setLatLng(ev.latlng);
} else {
pin = L.marker(ev.latlng,{ riseOnHover:true,draggable:true });
pin.addTo(map);
pin.on('drag',function(ev) {
$('#lat').val((ev.latlng.lat).toFixed(6));
$('#lng').val((ev.latlng.lng).toFixed(6));
});
}
});
$('#login-form').submit(function (event) {
event.preventDefault();
// Perform an AJAX request to the /login endpoint
$.ajax({
type: 'POST',
url: '/login',
data: $(this).serialize(),
success: function (data) {
// Update the content on the page with the message from the response
$('#login-message').text(data.message);
setTimeout(function () {
location.reload(true);
}, 1750);
},
error: function (xhr, status, error) {
// Handle error response
if (xhr.status === 403) {
// Update the content on the page with the message from the error response
$('#login-message').text(xhr.responseJSON.message);
} else {
// Handle other types of errors if needed
console.error('Error:', status, error);
}
}
});
});
// Assuming you have an anchor tag with id 'logout-link'
$('.logout-link').click(function (event) {
event.preventDefault();
// Perform an AJAX request to the /logout endpoint
$.ajax({
type: 'GET', // Assuming the logout is a GET request, adjust accordingly
url: '/logout',
success: function (data) {
// Update the content on the page with the message from the response
$('#login-message').text(data.message);
setTimeout(function () {
location.reload(true);
}, 1750);
},
error: function (xhr, status, error) {
// Handle error response
if (xhr.status === 403) {
// Update the content on the page with the message from the error response
$('#login-message').text(xhr.responseJSON.message);
} else {
// Handle other types of errors if needed
console.error('Error:', status, error);
}
}
});
});
});
function MapCreate() {
// create map instance
if (!(typeof map == "object")) {
map = L.map('map', {
center: [40,0],
zoom: 3
});
}
else {
map.setZoom(3).panTo([40,0]);
}
// create the tile layer with correct attribution
L.tileLayer(tilesURL, {
attribution: mapAttrib,
maxZoom: 19
}).addTo(map);
}
function fetchData() {
// Make a GET request to retrieve the data.json file
fetch(serverAddress + "/getData")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
// Save the received JSON data to a local variable (you may want to handle this differently on the client)
console.log('Received data:', data);
$('#webserver-ip').val(data.webserver.webserverIp);
$('#webserver-port').val(data.webserver.webserverPort);
$('#audio-port').val(data.webserver.audioPort);
$('#xdrd-ip').val(data.xdrd.xdrdIp);
$('#xdrd-port').val(data.xdrd.xdrdPort);
$('#xdrd-password').val(data.xdrd.xdrdPassword);
$('#audio-devices').val(data.audio.audioDevice);
$('#audio-channels').val(data.audio.audioChannels);
$('#audio-quality').val(data.audio.audioBitrate);
$('#webserver-name').val(data.identification.tunerName);
$('#webserver-desc').val(data.identification.tunerDesc);
$('#lat').val(data.identification.lat);
$('#lng').val(data.identification.lon);
$('#tune-pass').val(data.password.tunePass);
$('#admin-pass').val(data.password.adminPass);
$("#tuner-public").prop("checked", data.publicTuner);
$("#tuner-lock").prop("checked", data.lockToAdmin);
// Check if latitude and longitude are present in the data
if (data.identification.lat && data.identification.lon) {
// Set the map's center to the received coordinates
map.setView([data.identification.lat, data.identification.lon], 13);
// Add a pin to the map
if (typeof pin == "object") {
pin.setLatLng([data.identification.lat, data.identification.lon]);
} else {
pin = L.marker([data.identification.lat, data.identification.lon], { riseOnHover:true, draggable:true });
pin.addTo(map);
pin.on('drag',function(ev) {
$('#lat').val((ev.latlng.lat).toFixed(6));
$('#lng').val((ev.latlng.lng).toFixed(6));
});
}
}
})
.catch(error => {
console.error('Error fetching data:', error.message);
});
}
function submitData() {
const webserverIp = $('#webserver-ip').val() || '0.0.0.0';
const webserverPort = $('#webserver-port').val() || '8080';
const audioPort = $('#audio-port').val() || '8081';
const xdrdIp = $('#xdrd-ip').val() || '127.0.0.1';
const xdrdPort = $('#xdrd-port').val() || '7373';
const xdrdPassword = $('#xdrd-password').val() || 'password';
const audioDevice = $('#audio-devices').val() || 'Microphone (High Definition Audio Device)';
const audioChannels = ($('.options .option').filter(function() {
return $(this).text() === $('#audio-channels').val();
}).data('value') || 2);
const audioBitrate = $('#audio-quality').val() || '192k';
const tunerName = $('#webserver-name').val() || 'FM Tuner';
const tunerDesc = $('#webserver-desc').val() || 'Default FM tuner description';
const lat = $('#lat').val();
const lon = $('#lng').val();
const tunePass = $('#tune-pass').val();
const adminPass = $('#admin-pass').val();
const publicTuner = $("#tuner-public").is(":checked");
const lockToAdmin = $("#tuner-lock").is(":checked");
const data = {
webserver: {
webserverIp,
webserverPort,
audioPort
},
xdrd: {
xdrdIp,
xdrdPort,
xdrdPassword
},
audio: {
audioDevice,
audioChannels,
audioBitrate,
},
identification: {
tunerName,
tunerDesc,
lat,
lon,
},
password: {
tunePass,
adminPass,
},
publicTuner,
lockToAdmin
};
if(adminPass.length < 1) {
alert('You need to fill in the admin password before continuing further.');
return;
}
// Send data to the server using jQuery
$.ajax({
url: serverAddress + '/saveData',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (message) {
alert(message);
},
error: function (error) {
console.error(error);
}
});
}

175
web/setup.ejs Normal file
View File

@@ -0,0 +1,175 @@
<!DOCTYPE html>
<html>
<head>
<title>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="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 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/png" href="favicon2.png" />
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="wrapper" class="setup-wrapper">
<% if (isAdminAuthenticated) { %>
<div class="panel-100 no-bg">
<h1>FM-DX WebServer</h1>
<h2>[ADMIN PANEL]</h2>
<p>This web setup allows you to set up your entire tuner. <br>Some settings will only change after a server restart.</p>
<p>In case you are setting up the webserver for the first time, we already filled fail-safe defaults for you.</p>
</div>
<div class="flex-container">
<div class="panel-50" style="min-height: 120px;margin-bottom: 0;">
<h2>BASIC SETTINGS</h2>
<h3>Connection to xdrd:</h3>
<div class="form-group">
<label for="xdrd-ip">xdrd ip address:</label>
<input class="input-text w-150" type="text" name="xdrd-ip" id="xdrd-ip" placeholder="127.0.0.1">
</div>
<div class="form-group">
<label for="xdrd-port">xdrd port:</label>
<input class="input-text w-100" type="text" name="xdrd-port" id="xdrd-port" placeholder="7373">
</div>
<div class="form-group">
<label for="xdrd-password">xdrd server password:</label>
<input class="input-text w-150" type="text" name="xdrd-password" id="xdrd-password">
</div>
<br>
<h3>Webserver connection:</h3>
<div class="form-group">
<label for="webserver-ip">Webserver IP:</label>
<input class="input-text w-150" type="text" name="webserver-ip" id="webserver-ip" placeholder="0.0.0.0">
</div>
<div class="form-group">
<label for="webserver-port">Webserver port:</label>
<input class="input-text w-100" type="text" name="webserver-port" id="webserver-port" placeholder="8080">
</div>
<div class="form-group">
<label for="audio-port">Audio port:</label>
<input class="input-text w-150" type="text" name="audio-port" id="audio-port" placeholder="8081">
</div>
<br>
<!--tune password, public/private tuner, admin password, verbose mode-->
</div>
<div class="panel-50" style="min-height: 120px;margin-bottom: 0;">
<h2>AUDIO SETTINGS</h2>
<div class="panel-100 p-bottom-20">
<div class="form-group">
<label for="audio-devices"><i class="fa-solid fa-headphones"></i> STREAM AUDIO FROM:</label>
<div class="dropdown" style="width: 300px;">
<input id="audio-devices" type="text" name="audio-devices" placeholder="Choose your audio device" readonly />
<ul class="options" id="deviceList">
<% videoDevices.forEach(device => { %>
<li data-value="<%= device.name %>" class="option"><%= device.name %></li>
<% }); %>
<% audioDevices.forEach(device => { %>
<li data-value="<%= device.name %>" class="option"><%= device.name %></li>
<% }); %>
</ul>
</div>
</div>
<div class="form-group">
<label for="audio-devices"><i class="fa-solid fa-microphone-lines"></i> AUDIO CHANNELS:</label>
<div class="dropdown" style="width: 300px;">
<input id="audio-channels" type="text" name="audio-channels" placeholder="Stereo" readonly />
<ul class="options">
<li data-value="2" class="option">Stereo</li>
<li data-value="1" class="option">Mono</li>
</ul>
</div>
</div>
<div class="form-group">
<label for="audio-quality"><i class="fa-solid fa-wave-square"></i> AUDIO QUALITY:</label>
<div class="dropdown" style="width: 300px;">
<input id="audio-quality" type="text" name="audio-quality" placeholder="128k (saves bandwidth)" readonly />
<ul class="options">
<li data-value="128k" class="option">128k (saves bandwidth)</li>
<li data-value="192k" class="option">192k (higher quality)</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="flex-container bottom-20">
<div class="panel-100" style="padding-bottom: 20px;">
<h2>TUNER IDENTIFICATION INFO</h2>
<div class="panel-100" style="padding-left: 20px; padding-right: 20px;">
<label for="webserver-name" style="width: 100%;max-width: 768px; margin:auto;">Webserver name:</label>
<input style="width: 100%; max-width: 768px;" class="input-text" type="text" name="webserver-name" id="webserver-name" placeholder="Fill your server name here.">
<br>
<label for="webserver-desc" style="width: 100%;max-width: 768px; margin: auto;">Webserver description:</label>
<textarea id="webserver-desc" name="webserver-desc" placeholder="Fill the server description here. You can put useful info here such as your antenna setup."></textarea>
</div>
<h3>Tuner location:</h3>
<div class="form-group">
<label for="lat">Latitude:</label>
<input class="input-text" type="text" name="lat" id="lat">
</div>
<div class="form-group">
<label for="lng">Longitude:</label>
<input class="input-text" type="text" name="lng" id="lng">
</div>
<div id="map"></div>
</div>
<div class="panel-33">
<h2>MAINTENANCE</h2>
<div class="form-group checkbox">
<input type="checkbox" id="tuner-public">
<label for="tuner-public">Public tuner</label>
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="tuner-lock">
<label for="tuner-lock">Lock to admin</label>
</div><br>
<div class="form-group">
<label for="tune-pass">Tune password:</label>
<input class="input-text w-150" type="text" name="tune-pass" id="tune-pass">
</div>
<div class="form-group" style="margin-bottom: 40px;">
<label for="admin-pass">Admin setup password:</label>
<input class="input-text w-150" type="text" name="admin-pass" id="admin-pass">
</div><br>
<button style="height:48px; width: 200px;margin-bottom:20px;" onclick="submitData();">Save settings</button>
<button style="height: 48px; width: 200px;background:var(--color-3)" class="logout-link">Logout</button>
<div id="login-message"></div>
</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>
<button onclick="document.location.href='/'" id="back-btn" aria-label="Go back to tuning"><i class="fa-solid fa-arrow-left"></i></button>
<% } else { %>
<div class="panel-100 no-bg">
<h1>FM-DX WebServer</h1>
<h2>[ADMIN PANEL]</h2>
<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">
<h2>LOGIN</h2>
<form action="/login" method="post" id="login-form">
<input style="background-color: var(--color-2);" type="password" id="password" name="password" required>
<button type="submit" class="br-0 w-100" style="height: 44px;">Login</button>
</form>
<div id="login-message"></div>
</div>
<% } %>
</div>
<script src="js/settings.js"></script>
<script src="js/dropdown.js"></script>
<script src="js/setup.js"></script>
</body>
</html>