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

ui changes + map preparation + bugfixes

This commit is contained in:
NoobishSVK
2024-02-08 16:48:55 +01:00
parent 8ad8015ae7
commit 0453cdc75a
8 changed files with 231 additions and 94 deletions

View File

@@ -48,7 +48,9 @@ let serverConfig = {
tunerName: "",
tunerDesc: "",
lat: "0",
lon: "0"
lon: "0",
broadcastTuner: false,
proxyIp: "",
},
password: {
tunePass: "",
@@ -404,6 +406,7 @@ wss.on('connection', (ws, request) => {
ws.on('close', (code, reason) => {
currentUsers--;
dataHandler.showOnlineUsers(currentUsers);
logInfo(`Web client \x1b[31mdisconnected\x1b[0m (${clientIp}) \x1b[90m[${currentUsers}]`);
});

View File

@@ -22,9 +22,9 @@ const fetchInterval = 3000;
// Fetch data from maps
function fetchTx(freq, piCode, rdsPs) {
const now = Date.now();
freq = parseFloat(freq);
// Check if it's been at least 3 seconds since the last fetch and if the QTH is correct
if (now - lastFetchTime < fetchInterval || serverConfig.identification.lat.length < 2) {
if (now - lastFetchTime < fetchInterval || serverConfig.identification.lat.length < 2 || freq < 87) {
return Promise.resolve();
}

View File

@@ -137,6 +137,10 @@
margin-top: 10px;
}
.top-25 {
margin-top: 25px;
}
.bottom-20 {
margin-bottom: 20px;
}

View File

@@ -68,6 +68,60 @@
background: var(--color-5);
}
.modal-panel {
width: 450px;
height: 100%;
position: absolute;
right: 0;
text-align: center;
background-color: var(--color-main);
}
.modal-panel .flex-container {
align-items: stretch;
}
.modal-panel h1 {
font-size: 42px;
}
.modal-panel-sidebar {
width: 64px;
background-color: var(--color-1);
cursor: pointer;
}
.modal-panel-content {
flex: 1;
position: relative;
}
.modal-panel-content .version-info {
position: absolute;
bottom: 0;
width: 100%;
}
.modal-panel-footer {
width: 450px;
height: 100px;
background-color: var(--color-main);
vertical-align: bottom;
}
.modal-panel .form-group {
float: none !important;
}
.modal-panel .dropdown {
margin: auto;
}
.modal-panel label {
width: 200px;
margin: auto;
}
@media only screen and (max-width: 768px) {
.modal-content {
min-width: 90% !important;
@@ -83,4 +137,17 @@
#closeModalButton {
position: static;
}
.modal-panel {
width: 100%;
}
}
@media only screen and (max-height: 768px) {
.modal-panel .version-info {
position: static;
bottom: auto;
}
.modal-panel-content {
overflow-y: auto;
}
}

View File

@@ -195,13 +195,15 @@
<button id="settings" aria-label="Settings"><i class="fa-solid fa-gear"></i></button>
<button id="users-online-container" class="hide-phone" aria-label="Online users"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
<div id="myModal" class="modal">
<div class="modal-content">
<span class="modal-title">Settings</span>
<span class="close" id="closeModal"><i class="fa-solid fa-xmark"></i></span>
<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" id="closeModal"><i class="fa-solid fa-chevron-right"></i></div>
<div class="modal-panel-content">
<h1 class="top-25">Settings</h1>
<div class="form-group">
<label for="themes" style="margin-top: 50px;"><i class="fa-solid fa-palette"></i> Theme:</label>
<div class="form-group top-25">
<label for="themes"><i class="fa-solid fa-palette"></i> Theme:</label>
<div class="dropdown" id="theme-selector">
<input type="text" placeholder="Theme" readonly />
<ul class="options">
@@ -216,9 +218,9 @@
</ul>
</div>
</div>
<div class="form-group">
<label for="signal" style="margin-top: 50px;"><i class="fa-solid fa-signal"></i> Signal units:</label>
<div class="form-group top-25">
<label for="signal"><i class="fa-solid fa-signal"></i> Signal units:</label>
<div class="dropdown" id="signal-selector">
<input type="text" placeholder="Signal Units" readonly />
<ul class="options">
@@ -228,39 +230,60 @@
</ul>
</div>
</div>
<div class="form-group bottom-20 hide-desktop" style="float: none;">
<label for="themes"><i class="fa-solid fa-user"></i> Users online:</label>
<span class="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 <span style="color: var(--color-3);">v1.0.3 [7/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 & maps.fmdx.pl 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>
<span class="text-smaller">- flat-flags by <a href="https://github.com/luishdez/flat-flags/tree/master" target="_blank">luishdez</a></span><br></p>
<button class="button-close" id="closeModalButton">Close</button>
<p>You are logged in as an adminstrator.<br>
<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" class="top-25">
<label for="password">Password:</label>
<input type="password" id="password" name="password" style="width: 200px;" required><br>
<button type="submit" class="br-0 w-100 top-10" style="height: 44px">Login</button>
</form>
<% } %>
<div id="login-message"></div>
<div class="version-info">
<p class="text-small">FM-DX WebServer <br>by <a href="https://noobish.eu" target="_blank">Noobish</a> & the OpenRadio community.</p>
<span style="color: var(--color-3);">v1.0.4 [8/2/2024]</span>
<p class="text-small bottom-50">
<span class="text-smaller">librds & maps.fmdx.pl 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>
<span class="text-smaller">flat-flags by <a href="https://github.com/luishdez/flat-flags/tree/master" target="_blank">luishdez</a></span><br>
</p>
</div>
</div>
</div>
<script src="js/webserver.js"></script>
<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" style="height: 50px;padding:12px;" onclick="window.open('https://buymeacoffee.com/noobish')">
<strong>Support</strong> the developer!
</div>
<div class="hover-brighten br-0" style="height: 50px;padding:12px;"onclick="window.open('https://discord.com/invite/ZAVNdS74mC')">
Join our <strong>OpenRadio Discord</strong> community!
</div>
</div>
</div>
</div>
</div>
<script src="js/webserver.js"></script>
</body>
</html>

View File

@@ -39,6 +39,23 @@ $(document).ready(function() {
signalText.text('dBm');
}
});
var input = $("#tuner-desc").text();
var parsed = input;
var grayTextRegex = /--(.*?)--/g;
parsed = parsed.replace(grayTextRegex, '<span class="text-gray">$1</span>');
var boldRegex = /\*\*(.*?)\*\*/g;
parsed = parsed.replace(boldRegex, '<strong>$1</strong>');
var italicRegex = /\*(.*?)\*/g;
parsed = parsed.replace(italicRegex, '<em>$1</em>');
var breakLineRegex = /\\n/g;
parsed = parsed.replace(breakLineRegex, '<br>');
$("#tuner-desc").html(parsed);
const textInput = $('#commandinput');
@@ -298,24 +315,34 @@ function getCurrentFreq() {
function checkKey(e) {
e = e || window.event;
// Check if any input element is focused using jQuery
if ($('input:focus').length > 0) {
return; // Do nothing if an input is focused
}
getCurrentFreq();
if (socket.readyState === WebSocket.OPEN) {
if (e.keyCode == '82') { // RDS Reset (R key)
socket.send("T" + (currentFreq.toFixed(1) * 1000));
}
if (e.keyCode == '38') {
socket.send("T" + ((currentFreq + 0.01).toFixed(2) * 1000));
}
else if (e.keyCode == '40') {
socket.send("T" + ((currentFreq - 0.01).toFixed(2) * 1000));
}
else if (e.keyCode == '37') {
tuneDown();
}
else if (e.keyCode == '39') {
tuneUp();
switch (e.keyCode) {
case 82: // RDS Reset (R key)
socket.send("T" + (currentFreq.toFixed(1) * 1000));
break;
case 38:
socket.send("T" + ((currentFreq + 0.01).toFixed(2) * 1000));
break;
case 40:
socket.send("T" + ((currentFreq - 0.01).toFixed(2) * 1000));
break;
case 37:
tuneDown();
break;
case 39:
tuneUp();
break;
default:
// Handle default case if needed
break;
}
}
}

View File

@@ -6,14 +6,14 @@ var mapAttrib='&copy; <a href="http://www.openstreetmap.org/copyright">OpenStree
// add map container
$(document).ready(function() {
MapCreate();
fetchData();
map.on('click', function(ev) {
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 {
@@ -81,7 +81,31 @@ $(document).ready(function() {
}
});
});
function stripAnsi(str) {
return str.replace(/\u001b\[\d+m/g, '');
}
$("pre").html(function(_, html) {
html = stripAnsi(html);
return html.replace(/\[(\d{2}:\d{2})\]|\[(INFO|DEBUG|WARN|ERROR)\]/g, function(match, time, level) {
if (time) {
return "<span style='color: gray;'>" + match + "</span>";
} else if (level === "INFO") {
return "<span style='color: lime;'>" + match + "</span>";
} else if (level === "DEBUG") {
return "<span style='color: cyan;'>" + match + "</span>";
} else if (level === "WARN") {
return "<span style='color: yellow;'>" + match + "</span>";
} else if (level === "ERROR") {
return "<span style='color: red;'>" + match + "</span>";
} else {
return "<span style='color: white;'>" + match + "</span>";
}
});
});
$("#console-output").scrollTop($("#console-output")[0].scrollHeight);
});
function MapCreate() {
@@ -112,9 +136,6 @@ function fetchData() {
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);
@@ -131,6 +152,8 @@ function fetchData() {
$('#webserver-desc').val(data.identification.tunerDesc);
$('#lat').val(data.identification.lat);
$('#lng').val(data.identification.lon);
$("#broadcast-tuner").prop("checked", data.identification.broadcastTuner);
$("#broadcast-address").val(data.identification.proxyIp);
$('#tune-pass').val(data.password.tunePass);
$('#admin-pass').val(data.password.adminPass);
@@ -183,6 +206,8 @@ function submitData() {
const tunerDesc = $('#webserver-desc').val() || 'Default FM tuner description';
const lat = $('#lat').val();
const lon = $('#lng').val();
const broadcastTuner = $("#broadcast-tuner").is(":checked");
const proxyIp = $("#broadcast-address").val();
const tunePass = $('#tune-pass').val();
const adminPass = $('#admin-pass').val();
@@ -211,6 +236,8 @@ function submitData() {
tunerDesc,
lat,
lon,
broadcastTuner,
proxyIp
},
password: {
tunePass,
@@ -239,3 +266,6 @@ function submitData() {
}
});
}

View File

@@ -106,7 +106,18 @@
<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>
<textarea id="webserver-desc" 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."></textarea>
</div>
<h3>Map broadcast:</h3>
<p>If your tuner is set to public and other information is filled, you can add your tuner to a public map.</p>
<div class="form-group checkbox">
<input type="checkbox" id="broadcast-tuner">
<label for="broadcast-tuner">Broadcast to map</label>
</div><br>
<div class="form-group">
<label for="broadcast-address">Broadcast address (if using a proxy):</label>
<input class="input-text" type="text" name="broadcast-address" id="broadcast-address">
</div>
<h3>Tuner location:</h3>
@@ -181,34 +192,6 @@
</div>
<% } %>
</div>
<script>
$(document).ready(function() {
function stripAnsi(str) {
return str.replace(/\u001b\[\d+m/g, '');
}
$("pre").html(function(_, html) {
html = stripAnsi(html);
return html.replace(/\[(\d{2}:\d{2})\]|\[(INFO|DEBUG|WARN|ERROR)\]/g, function(match, time, level) {
if (time) {
return "<span style='color: gray;'>" + match + "</span>";
} else if (level === "INFO") {
return "<span style='color: lime;'>" + match + "</span>";
} else if (level === "DEBUG") {
return "<span style='color: cyan;'>" + match + "</span>";
} else if (level === "WARN") {
return "<span style='color: yellow;'>" + match + "</span>";
} else if (level === "ERROR") {
return "<span style='color: red;'>" + match + "</span>";
} else {
return "<span style='color: white;'>" + match + "</span>";
}
});
});
$("#console-output").scrollTop($("#console-output")[0].scrollHeight);
});
</script>
<script src="js/settings.js"></script>
<script src="js/dropdown.js"></script>
<script src="js/setup.js"></script>