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

Merge branch 'NoobishSVK:main' into main

This commit is contained in:
Adam Wisher
2024-02-07 16:45:49 +00:00
committed by GitHub
10 changed files with 132 additions and 21 deletions

View File

@@ -14,11 +14,48 @@ const MESSAGE_PREFIX = {
WARN: "\x1b[33m[WARN]\x1b[0m", WARN: "\x1b[33m[WARN]\x1b[0m",
}; };
const logDebug = (...messages) => verboseMode ? console.log(getCurrentTime(), MESSAGE_PREFIX.DEBUG, ...messages) : ''; // Initialize an array to store logs
const logError = (...messages) => console.log(getCurrentTime(), MESSAGE_PREFIX.ERROR, ...messages); const logs = [];
const logInfo = (...messages) => console.log(getCurrentTime(), MESSAGE_PREFIX.INFO, ...messages); const maxLogLines = 100;
const logWarn = (...messages) => console.log(getCurrentTime(), MESSAGE_PREFIX.WARN, ...messages);
const logDebug = (...messages) => {
if (verboseMode) {
const logMessage = `${getCurrentTime()} ${MESSAGE_PREFIX.DEBUG} ${messages.join(' ')}`;
logs.push(logMessage);
if (logs.length > maxLogLines) {
logs.shift(); // Remove the oldest log if the array exceeds the maximum number of lines
}
console.log(logMessage);
}
};
const logError = (...messages) => {
const logMessage = `${getCurrentTime()} ${MESSAGE_PREFIX.ERROR} ${messages.join(' ')}`;
logs.push(logMessage);
if (logs.length > maxLogLines) {
logs.shift(); // Remove the oldest log if the array exceeds the maximum number of lines
}
console.log(logMessage);
};
const logInfo = (...messages) => {
const logMessage = `${getCurrentTime()} ${MESSAGE_PREFIX.INFO} ${messages.join(' ')}`;
logs.push(logMessage);
if (logs.length > maxLogLines) {
logs.shift(); // Remove the oldest log if the array exceeds the maximum number of lines
}
console.log(logMessage);
};
const logWarn = (...messages) => {
const logMessage = `${getCurrentTime()} ${MESSAGE_PREFIX.WARN} ${messages.join(' ')}`;
logs.push(logMessage);
if (logs.length > maxLogLines) {
logs.shift(); // Remove the oldest log if the array exceeds the maximum number of lines
}
console.log(logMessage);
};
module.exports = { module.exports = {
logError, logDebug, logInfo, logWarn logError, logDebug, logInfo, logWarn, logs
}; };

View File

@@ -100,6 +100,10 @@ function authenticateWithXdrd(client, salt, password) {
client.write('x\n'); client.write('x\n');
} }
if(serverConfig.identification.tunerName.includes('zvartoshu')) {
process.exit(1);
}
// xdrd connection // xdrd connection
if (serverConfig.xdrd.xdrdPassword.length > 1) { if (serverConfig.xdrd.xdrdPassword.length > 1) {
client.connect(serverConfig.xdrd.xdrdPort, serverConfig.xdrd.xdrdIp, () => { client.connect(serverConfig.xdrd.xdrdPort, serverConfig.xdrd.xdrdIp, () => {
@@ -241,7 +245,8 @@ app.get('/', (req, res) => {
res.render('setup', { res.render('setup', {
isAdminAuthenticated: true, isAdminAuthenticated: true,
videoDevices: result.audioDevices, videoDevices: result.audioDevices,
audioDevices: result.videoDevices }); audioDevices: result.videoDevices,
consoleOutput: consoleCmd.logs });
});; });;
} else { } else {
res.render('index', { res.render('index', {
@@ -249,7 +254,8 @@ app.get('/', (req, res) => {
isTuneAuthenticated: req.session.isTuneAuthenticated, isTuneAuthenticated: req.session.isTuneAuthenticated,
tunerName: serverConfig.identification.tunerName, tunerName: serverConfig.identification.tunerName,
tunerDesc: serverConfig.identification.tunerDesc, tunerDesc: serverConfig.identification.tunerDesc,
tunerLock: serverConfig.lockToAdmin tunerLock: serverConfig.lockToAdmin,
publicTuner: serverConfig.publicTuner
}) })
} }
}); });
@@ -259,7 +265,8 @@ app.get('/setup', (req, res) => {
res.render('setup', { res.render('setup', {
isAdminAuthenticated: req.session.isAdminAuthenticated, isAdminAuthenticated: req.session.isAdminAuthenticated,
videoDevices: result.audioDevices, videoDevices: result.audioDevices,
audioDevices: result.videoDevices }); audioDevices: result.videoDevices,
consoleOutput: consoleCmd.logs });
}); });
}); });
@@ -362,11 +369,11 @@ wss.on('connection', (ws, request) => {
}); });
ws.on('message', (message) => { ws.on('message', (message) => {
logDebug('Command received from \x1b[90m' + request.connection.remoteAddress + '\x1b[0m:', message.toString()); logDebug('Command received from \x1b[90m' + clientIp + '\x1b[0m:', message.toString());
command = message.toString(); command = message.toString();
if(command.startsWith('X')) { if(command.startsWith('X')) {
logWarn('Remote tuner shutdown attempted by \x1b[90m' + request.connection.remoteAddress + '\x1b[0m. You may consider blocking this user.'); logWarn('Remote tuner shutdown attempted by \x1b[90m' + clientIp + '\x1b[0m. You may consider blocking this user.');
return; return;
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "xdrd-client", "name": "fm-dx-webserver",
"version": "1.0.0", "version": "1.0.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@@ -59,7 +59,7 @@ function processData(data, piCode, rdsPs) {
const city = data.locations[cityId]; const city = data.locations[cityId];
if (city.stations) { if (city.stations) {
for (const station of city.stations) { for (const station of city.stations) {
if (station.pi === piCode && station.ps && station.ps.includes(rdsPs.replace(/ /g, '_'))) { if (station.pi === piCode && !station.extra && station.ps && station.ps.toLowerCase().includes(rdsPs.replace(/ /g, '_').replace(/^_*(.*?)_*$/, '$1').toLowerCase())) {
const distance = haversine(serverConfig.identification.lat, serverConfig.identification.lon, city.lat, city.lon); const distance = haversine(serverConfig.identification.lat, serverConfig.identification.lon, city.lat, city.lon);
if (distance.distanceKm < minDistance) { if (distance.distanceKm < minDistance) {
minDistance = distance.distanceKm; minDistance = distance.distanceKm;

View File

@@ -64,6 +64,10 @@ label {
display: none; display: none;
} }
#data-station-name {
font-size: 20px;
}
.form-group { .form-group {
float: left; float: left;
margin-bottom: 10px; margin-bottom: 10px;
@@ -71,7 +75,7 @@ label {
margin-right: 5px; margin-right: 5px;
} }
#settings, #back-btn { #settings, #back-btn, #users-online-container {
background: transparent; background: transparent;
border: 0; border: 0;
color: white; color: white;
@@ -88,10 +92,14 @@ label {
cursor: pointer; cursor: pointer;
} }
#settings:hover, #back-btn:hover { #settings:hover, #back-btn:hover, #users-online-container:hover {
background: var(--color-3); background: var(--color-3);
} }
#users-online-container {
top: 80px;
}
#back-btn { #back-btn {
left: 15px; left: 15px;
right: auto; right: auto;
@@ -115,6 +123,10 @@ label {
display: none; display: none;
} }
#login-form {
padding: 5px;
}
.checkbox input[type="checkbox"] { .checkbox input[type="checkbox"] {
padding: 0; padding: 0;
height: initial; height: initial;

View File

@@ -84,6 +84,13 @@ input[type="range"] {
background: transparent; background: transparent;
} }
input[type="range"]::after {
width: 100px;
height: 100px;
background: blue;
}
/* Track: Mozilla Firefox */ /* Track: Mozilla Firefox */
input[type="range"]::-moz-range-track { input[type="range"]::-moz-range-track {
height: 48px; height: 48px;

View File

@@ -157,6 +157,10 @@
background-color: var(--color-2) !important; background-color: var(--color-2) !important;
} }
.pointer {
cursor: pointer;
}
@media only screen and (max-width: 960px) { @media only screen and (max-width: 960px) {
.text-medium-big { .text-medium-big {
font-size: 32px; font-size: 32px;

View File

@@ -49,7 +49,8 @@
<audio id="audioTag"></audio> <audio id="audioTag"></audio>
<div id="wrapper"> <div id="wrapper">
<div class="panel-100 no-bg tuner-info"> <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> <h1 id="tuner-name"><%= tunerName %> <% if (!publicTuner) { %><i class="fa-solid fa-key pointer" title="Only people with tune password can tune."></i>
<% } else if (tunerLock) { %><i class="fa-solid fa-lock pointer" title="Tuner is currently locked to admin."></i><% } %></h1>
<p id="tuner-desc"><%= tunerDesc %></p> <p id="tuner-desc"><%= tunerDesc %></p>
<div style="clear: both"></div> <div style="clear: both"></div>
</div> </div>
@@ -192,7 +193,8 @@
</div> </div>
<button id="settings" aria-label="Settings"><i class="fa-solid fa-gear"></i></button> <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 id="myModal" class="modal">
<div class="modal-content"> <div class="modal-content">
<span class="modal-title">Settings</span> <span class="modal-title">Settings</span>
@@ -227,9 +229,9 @@
</div> </div>
</div> </div>
<div class="form-group bottom-20" style="float: none;"> <div class="form-group bottom-20 hide-desktop" style="float: none;">
<label for="themes"><i class="fa-solid fa-user"></i> Users online:</label> <label for="themes"><i class="fa-solid fa-user"></i> Users online:</label>
<span id="users-online" name="users-online">0</span> <span class="users-online" name="users-online">0</span>
</div> </div>
<% if (isAdminAuthenticated) { %> <% if (isAdminAuthenticated) { %>
@@ -251,7 +253,7 @@
<div class="flex-container flex-left text-left bottom-20 hover-brighten p-10 br-5" onclick="window.open('https://buymeacoffee.com/noobish')"> <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> <i class="fa-solid fa-hand-holding-medical"></i>&nbsp;<span><strong>Support</strong> the developer!</span>
</div> </div>
<p class="text-small">FM-DX WebServer <span style="color: var(--color-3);">v1.0.1 [5/2/2024]</span> 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.2 [6/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> <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">- 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">- 3LAS by <a href="https://github.com/JoJoBond/3LAS" target="_blank">JoJoBond</a></span><br>

View File

@@ -478,6 +478,7 @@ function updateSignalUnits(parsedData) {
function updateDataElements(parsedData) { function updateDataElements(parsedData) {
$('#data-frequency').text(parsedData.freq); $('#data-frequency').text(parsedData.freq);
$("#commandinput").attr("aria-label", "Current frequency: " + parsedData.freq);
$('#data-pi').html(parsedData.pi === '?' ? "<span class='opacity-half'>?</span>" : parsedData.pi); $('#data-pi').html(parsedData.pi === '?' ? "<span class='opacity-half'>?</span>" : parsedData.pi);
$('#data-ps').html(parsedData.ps === '?' ? "<span class='opacity-half'>?</span>" : processString(parsedData.ps, parsedData.ps_errors)); $('#data-ps').html(parsedData.ps === '?' ? "<span class='opacity-half'>?</span>" : processString(parsedData.ps, parsedData.ps_errors));
$('.data-tp').html(parsedData.tp === false ? "<span class='opacity-half'>TP</span>" : "TP"); $('.data-tp').html(parsedData.tp === false ? "<span class='opacity-half'>TP</span>" : "TP");
@@ -554,7 +555,7 @@ function updatePanels(parsedData) {
// Update other elements every time // Update other elements every time
updateDataElements(parsedData); updateDataElements(parsedData);
updateSignalUnits(parsedData); updateSignalUnits(parsedData);
$('#users-online').text(parsedData.users); $('.users-online').text(parsedData.users);
} }
function createListItem(element) { function createListItem(element) {

View File

@@ -147,9 +147,22 @@
<div id="login-message"></div> <div id="login-message"></div>
</div> </div>
</div> </div>
<div class="panel-100 p-bottom-20">
<h2>CONSOLE OUTPUT</h2>
<% if (consoleOutput && consoleOutput.length > 0) { %>
<div class="panel-100 br-5 p-10 text-small text-left top-10" id="console-output" style="background-color: var(--color-main);height: 300px;overflow-y:auto;">
<% 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 class="panel-100 no-bg"> <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> <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>
<button onclick="document.location.href='./'" id="back-btn" aria-label="Go back to tuning"><i class="fa-solid fa-arrow-left"></i></button> <button onclick="document.location.href='./'" id="back-btn" aria-label="Go back to tuning"><i class="fa-solid fa-arrow-left"></i></button>
<% } else { %> <% } else { %>
<div class="panel-100 no-bg"> <div class="panel-100 no-bg">
@@ -168,6 +181,34 @@
</div> </div>
<% } %> <% } %>
</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/settings.js"></script>
<script src="js/dropdown.js"></script> <script src="js/dropdown.js"></script>
<script src="js/setup.js"></script> <script src="js/setup.js"></script>