diff --git a/console.js b/console.js index 4fe0a0c..6fe3fc9 100644 --- a/console.js +++ b/console.js @@ -25,9 +25,9 @@ const logDebug = (...messages) => { 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 + logs.shift(); } - console.log(logMessage); + console.log(logMessage); } }; @@ -35,7 +35,7 @@ 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 + logs.shift(); } console.log(logMessage); }; @@ -45,9 +45,9 @@ const logFfmpeg = (...messages) => { const logMessage = `${getCurrentTime()} ${MESSAGE_PREFIX.FFMPEG} ${messages.join(' ')}`; logs.push(logMessage); if (logs.length > maxLogLines) { - logs.shift(); // Remove the oldest log if the array exceeds the maximum number of lines + logs.shift(); } - console.log(logMessage); + console.log(logMessage); } }; @@ -55,7 +55,7 @@ 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 + logs.shift(); } console.log(logMessage); }; @@ -64,7 +64,7 @@ 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 + logs.shift(); } console.log(logMessage); }; diff --git a/index.js b/index.js index f22eab3..82fcc80 100644 --- a/index.js +++ b/index.js @@ -121,7 +121,6 @@ function connectToXdrd() { const lines = receivedData.split('\n'); for (const line of lines) { - if (!authFlags.receivedPassword) { authFlags.receivedSalt = line.trim(); authenticateWithXdrd(client, authFlags.receivedSalt, serverConfig.xdrd.xdrdPassword); @@ -143,7 +142,7 @@ function connectToXdrd() { if (authFlags.authMsg && authFlags.firstClient) { client.write('T87500\n'); client.write('A0\n'); - client.write('G11\n'); + client.write('G00\n'); client.off('data', authDataHandler); return; } @@ -226,6 +225,17 @@ app.get('/static_data', (req, res) => { }); }); +app.get('/server_time', (req, res) => { + const serverTime = new Date().toISOString(); + res.json({ + serverTime + }); +}); + +app.get('/ping', (req, res) => { + res.send('pong'); +}); + /** * AUTHENTICATION BLOCK @@ -342,7 +352,6 @@ app.get('/getData', (req, res) => { app.get('/getDevices', (req, res) => { if (req.session.isAdminAuthenticated || !fs.existsSync('config.json')) { parseAudioDevice((result) => { - console.log(result); res.json(result); }); } else { diff --git a/web/css/modal.css b/web/css/modal.css index dc699c1..ec2c0bd 100644 --- a/web/css/modal.css +++ b/web/css/modal.css @@ -97,8 +97,7 @@ } .modal-panel-content .version-info { - position: absolute; - bottom: 0; + margin-top: 75px; width: 100%; } diff --git a/web/index.ejs b/web/index.ejs index e51913e..9e2d0b4 100644 --- a/web/index.ejs +++ b/web/index.ejs @@ -250,10 +250,16 @@ <% } %>
+ +Server:
+Local:
+ +FM-DX WebServer
by Noobish & the OpenRadio community.
librds & maps.fmdx.pl by Konrad Kosmatka
3LAS by JoJoBond
diff --git a/web/js/3las/fallback/formats/3las.formatreader.mpeg.js b/web/js/3las/fallback/formats/3las.formatreader.mpeg.js
index d676238..c64f53f 100644
--- a/web/js/3las/fallback/formats/3las.formatreader.mpeg.js
+++ b/web/js/3las/fallback/formats/3las.formatreader.mpeg.js
@@ -74,13 +74,17 @@ var AudioFormatReader_MPEG = /** @class */ (function (_super) {
// the full frame length by adding zeros.
var bufferLength = 0;
var expectedTotalPlayTime_1 = 0;
- expectedTotalPlayTime_1 += this.Frames[0].SampleCount / this.Frames[0].SampleRate / 2.0; // Only half of data is usable due to overlap
+ var firstGranulePlayTime_1 = 0;
+ var lastGranulePlayTime_1 = 0;
+ firstGranulePlayTime_1 = this.Frames[0].SampleCount / this.Frames[0].SampleRate / 2.0; // Only half of data is usable due to overlap
+ expectedTotalPlayTime_1 += firstGranulePlayTime_1;
bufferLength += this.Frames[0].Data.length;
for (var i = 1; i < this.Frames.length - 1; i++) {
expectedTotalPlayTime_1 += this.Frames[i].SampleCount / this.Frames[i].SampleRate;
bufferLength += this.Frames[i].Data.length;
}
- expectedTotalPlayTime_1 += this.Frames[this.Frames.length - 1].SampleCount / this.Frames[this.Frames.length - 1].SampleRate / 2.0; // Only half of data is usable due to overlap
+ lastGranulePlayTime_1 = this.Frames[this.Frames.length - 1].SampleCount / this.Frames[this.Frames.length - 1].SampleRate / 2.0; // Only half of data is usable due to overlap
+ expectedTotalPlayTime_1 += lastGranulePlayTime_1;
bufferLength += this.Frames[this.Frames.length - 1].Data.length;
// If needed, add some space for the ID3v2 tag
if (this.AddId3Tag) {
@@ -110,7 +114,9 @@ var AudioFormatReader_MPEG = /** @class */ (function (_super) {
this.Audio.decodeAudioData(decodeBuffer.buffer, (function (decodedData) {
var _id = id_1;
var _expectedTotalPlayTime = expectedTotalPlayTime_1;
- this._OnDecodeSuccess(decodedData, _id, _expectedTotalPlayTime);
+ var _firstGranulePlayTime = firstGranulePlayTime_1;
+ var _lastGranulePlayTime = lastGranulePlayTime_1;
+ this._OnDecodeSuccess(decodedData, _id, _expectedTotalPlayTime, _firstGranulePlayTime, _lastGranulePlayTime);
}).bind(this), this._OnDecodeError.bind(this));
}
};
@@ -187,9 +193,10 @@ var AudioFormatReader_MPEG = /** @class */ (function (_super) {
return new MPEGFrameInfo(new Uint8Array(frameArray), this.FrameSamples, this.FrameSampleRate);
};
// Is called if the decoding of the window succeeded
- AudioFormatReader_MPEG.prototype.OnDecodeSuccess = function (decodedData, id, expectedTotalPlayTime) {
+ AudioFormatReader_MPEG.prototype.OnDecodeSuccess = function (decodedData, id, expectedTotalPlayTime, firstGranulePlayTime, lastGranulePlayTime) {
var extractSampleCount;
var extractSampleOffset;
+ var delta = 0.001;
// Check if we got the expected number of samples
if (expectedTotalPlayTime > decodedData.duration) {
// We got less samples than expect, we suspect that they were truncated equally at start and end.
@@ -210,7 +217,34 @@ var AudioFormatReader_MPEG = /** @class */ (function (_super) {
extractSampleCount += budgetSamples;
this.TimeBudget -= (budgetSamples / decodedData.sampleRate);
}
- extractSampleOffset = Math.floor((decodedData.length - extractSampleCount) / 2);
+ var diff = decodedData.duration - expectedTotalPlayTime;
+ if ((diff - firstGranulePlayTime - lastGranulePlayTime) >= -delta) {
+ // Both first and last granule are present. Cut out middle section.
+ extractSampleOffset = Math.floor((decodedData.length - extractSampleCount) / 2);
+ }
+ if (Math.abs(firstGranulePlayTime - lastGranulePlayTime) <= delta) {
+ // First and last granule are equal. We need to make an educated guess which one is present.
+ if (isIOS || isIPadOS) {
+ // I don't know why, but Apple does things differently.
+ extractSampleOffset = Math.floor((decodedData.length - extractSampleCount) / 2);
+ }
+ else {
+ // Assume last granule is present.
+ extractSampleOffset = decodedData.length - extractSampleCount;
+ }
+ }
+ else if (Math.abs(diff - firstGranulePlayTime) <= delta) {
+ // Last granule is present.
+ extractSampleOffset = decodedData.length - extractSampleCount;
+ }
+ else if (Math.abs(diff - lastGranulePlayTime) <= delta) {
+ // First granule is present.
+ extractSampleOffset = 0;
+ }
+ else {
+ // The difference is not equal to neither the first, the last nor the sum of both granule. So we just use the middle.
+ extractSampleOffset = Math.floor((decodedData.length - extractSampleCount) / 2);
+ }
}
else {
// We got the expected number of samples, no adaption needed
diff --git a/web/js/main.js b/web/js/main.js
index 7e743e8..605fd9a 100644
--- a/web/js/main.js
+++ b/web/js/main.js
@@ -123,6 +123,11 @@ $(document).ready(function () {
return false;
});
+ setInterval(getServerTime, 10000);
+ getServerTime();
+ setInterval(sendPingRequest, 5000);
+ sendPingRequest();
+
var freqUpButton = $('#freq-up')[0];
var freqDownButton = $('#freq-down')[0];
var psContainer = $('#ps-container')[0];
@@ -167,6 +172,55 @@ function getInitialSettings() {
});
}
+function getLocalizedTime(serverTime) {
+ // Convert server time to a Date object
+ const serverDate = new Date(serverTime);
+
+ // Get local time zone offset
+ const localOffset = serverDate.getTimezoneOffset() * 60000; // Convert minutes to milliseconds
+
+ // Calculate local time by adding the offset
+ const localTime = new Date(serverDate.getTime() - localOffset);
+
+ // Format local time
+ const options = { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false };
+ const formattedLocalTime = localTime.toLocaleString('en-US', options);
+
+ return formattedLocalTime;
+}
+
+function getServerTime() {
+ $.ajax({
+ url: './server_time',
+ dataType: 'json',
+ success: function (data) {
+ // Convert server time to local time format
+ const localizedTimeServer = getLocalizedTime(data.serverTime);
+ const localizedTimeClient = getLocalizedTime(new Date().toISOString());
+
+ $('#server-time').text(localizedTimeServer);
+ $('#client-time').text(localizedTimeClient);
+ },
+ error: function (error) {
+ console.error('Error:', error);
+ }
+ });
+}
+
+function sendPingRequest() {
+ const startTime = new Date().getTime();
+
+ fetch('/ping')
+ .then(response => {
+ const endTime = new Date().getTime();
+ const pingTime = endTime - startTime;
+ $('#current-ping').text(`Ping: ${pingTime}ms`);
+ })
+ .catch(error => {
+ console.error('Error fetching ping:', error);
+ });
+}
+
function initCanvas(parsedData) {
signalToggle = $("#signal-units-toggle");
@@ -329,9 +383,8 @@ 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
+ if ($('#password:focus').length > 0) {
+ return;
}
getCurrentFreq();
@@ -538,7 +591,8 @@ function updateDataElements(parsedData) {
$('#data-ant input').val($('#data-ant li[data-value="' + parsedData.ant + '"]').text());
if (parsedData.txInfo.station.length > 1) {
- $('#data-station-name').text(decodeURIComponent(parsedData.txInfo.station.replace(/\u009e/g, '\u017E')));
+ const sanitizedStation = parsedData.txInfo.station.replace(/%/g, '%25');
+ $('#data-station-name').text(decodeURIComponent(sanitizedStation.replace(/\u009e/g, '\u017E')));
$('#data-station-erp').text(parsedData.txInfo.erp);
$('#data-station-city').text(parsedData.txInfo.city);
$('#data-station-itu').text(parsedData.txInfo.itu);
diff --git a/web/js/settings.js b/web/js/settings.js
index 5c79858..a7a550d 100644
--- a/web/js/settings.js
+++ b/web/js/settings.js
@@ -6,7 +6,7 @@
theme4: ['#0c1c1b', '#68f7ee'],
theme5: ['#171106', '#f5b642'],
theme6: ['#21091d', '#ed51d3'],
- theme7: ['#1d1838', '#8069fa'],
+ theme7: ['#0d0b1a', '#8069fa'],
theme8: ['#000', '#888'],
};