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
Merge branch 'NoobishSVK:main' into main
This commit is contained in:
47
console.js
47
console.js
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
17
index.js
17
index.js
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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": {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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> <span><strong>Support</strong> the developer!</span>
|
<i class="fa-solid fa-hand-holding-medical"></i> <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>
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user