You've already forked fm-dx-webserver
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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%;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
|
||||
@@ -55,6 +55,11 @@ body {
|
||||
width: 1180px;
|
||||
max-width: 1180px;
|
||||
}
|
||||
#wrapper.setup-wrapper {
|
||||
margin: auto;
|
||||
position: static;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
#wrapper {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.panel-50 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.panel-75 {
|
||||
width: 68%;
|
||||
}
|
||||
|
||||
42
web/css/setup.css
Normal file
42
web/css/setup.css
Normal 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;
|
||||
}
|
||||
BIN
web/favicon.png
BIN
web/favicon.png
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 |
@@ -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> <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> <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>
|
||||
@@ -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);
|
||||
|
||||
@@ -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
243
web/js/setup.js
Normal 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='© <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
175
web/setup.ejs
Normal 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>
|
||||
Reference in New Issue
Block a user