diff --git a/package.json b/package.json index 597c07f..6bc1bdb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fm-dx-webserver", - "version": "1.3.6", + "version": "1.3.6.1", "description": "FM DX Webserver", "main": "index.js", "scripts": { diff --git a/server/datahandler.js b/server/datahandler.js index 7467ab6..eac6735 100644 --- a/server/datahandler.js +++ b/server/datahandler.js @@ -206,7 +206,6 @@ const updateInterval = 75; var dataToSend = { pi: '?', freq: 87.500.toFixed(3), - prevFreq: 87.500.toFixed(3), sig: 0, sigRaw: '', sigTop: -Infinity, diff --git a/server/server_config.js b/server/server_config.js index ac72500..1be8796 100644 --- a/server/server_config.js +++ b/server/server_config.js @@ -43,6 +43,7 @@ let serverConfig = { audioDevice: "Microphone (High Definition Audio Device)", audioChannels: 2, audioBitrate: "128k", + audioBoost: false, softwareMode: false, startupVolume: "0.95" }, diff --git a/server/stream/index.js b/server/stream/index.js index 9979df9..32961a4 100644 --- a/server/stream/index.js +++ b/server/stream/index.js @@ -9,7 +9,7 @@ function enableAudioStream() { const flags = `-fflags +nobuffer+flush_packets -flags low_delay -rtbufsize 6192 -probesize 32`; const codec = `-acodec pcm_s16le -ar 48000 -ac ${serverConfig.audio.audioChannels}`; - const output = `-f s16le -fflags +nobuffer+flush_packets -packetsize 384 -flush_packets 1 -bufsize 960`; + const output = `${serverConfig.audio.audioBoost == true ? '$-af "volume=3.5"' : ''} -f s16le -fflags +nobuffer+flush_packets -packetsize 384 -flush_packets 1 -bufsize 960`; if (process.platform === 'win32') { // Windows diff --git a/server/tx_search.js b/server/tx_search.js index 895790f..38220e5 100644 --- a/server/tx_search.js +++ b/server/tx_search.js @@ -7,6 +7,8 @@ let lastFetchTime = 0; const fetchInterval = 1000; const esSwitchCache = {"lastCheck":0, "esSwitch":false}; const esFetchInterval = 300000; +var currentPiCode = ''; +var currentRdsPs = ''; const usStatesGeoJsonUrl = "https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json"; let usStatesGeoJson = null; // To cache the GeoJSON data for US states @@ -73,7 +75,11 @@ async function fetchTx(freq, piCode, rdsPs) { if (isNaN(freq)) { return; } - if (now - lastFetchTime < fetchInterval || serverConfig.identification.lat.length < 2 || freq < 87) { + if (now - lastFetchTime < fetchInterval + || serverConfig.identification.lat.length < 2 + || freq < 87 + || (currentPiCode == piCode && currentRdsPs == rdsPs)) + { return Promise.resolve(); } @@ -90,7 +96,7 @@ async function fetchTx(freq, piCode, rdsPs) { if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`); const data = await response.json(); cachedData[freq] = data; - await loadUsStatesGeoJson(); + if(serverConfig.webserver.rdsMode == true) await loadUsStatesGeoJson(); return processData(data, piCode, rdsPs); } catch (error) { console.error("Error fetching data:", error); @@ -106,6 +112,8 @@ async function processData(data, piCode, rdsPs) { let maxDistance; let esMode = checkEs(); let detectedByPireg = false; + currentPiCode = piCode; + currentRdsPs = rdsPs; function evaluateStation(station, city, distance) { let weightDistance = distance.distanceKm; diff --git a/web/css/helpers.css b/web/css/helpers.css index 6f846f2..9eae422 100644 --- a/web/css/helpers.css +++ b/web/css/helpers.css @@ -305,7 +305,7 @@ table .input-text { .hide-phone { display: none; } - .m-0 { + .m-0, .center-phone { margin: auto !important; } } diff --git a/web/css/main.css b/web/css/main.css index aa4a554..d4a4a60 100644 --- a/web/css/main.css +++ b/web/css/main.css @@ -105,6 +105,10 @@ a:hover { border-bottom: 1px solid var(--color-4); } +a.hide-underline:hover { + border-bottom: none; +} + hr { color: var(--color-4); } diff --git a/web/index.ejs b/web/index.ejs index 21887ed..45b3112 100644 --- a/web/index.ejs +++ b/web/index.ejs @@ -345,7 +345,8 @@
-
+

@@ -362,7 +363,7 @@

-
+

AF

diff --git a/web/js/3las/main.js b/web/js/3las/main.js index cff63df..f1dcaad 100644 --- a/web/js/3las/main.js +++ b/web/js/3las/main.js @@ -34,14 +34,20 @@ function OnConnectivityCallback(isConnected) { } } +function isIOS() { + return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; +} + function OnPlayButtonClick(_ev) { const $playbutton = $('.playbutton'); + const isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; + if (Stream) { console.log("Stopping stream..."); shouldReconnect = false; destroyStream(); $playbutton.find('.fa-solid').toggleClass('fa-stop fa-play'); - if ('audioSession' in navigator) { + if (isiOS && 'audioSession' in navigator) { navigator.audioSession.type = "none"; } } else { @@ -50,10 +56,11 @@ function OnPlayButtonClick(_ev) { createStream(); Stream.Start(); $playbutton.find('.fa-solid').toggleClass('fa-play fa-stop'); - if ('audioSession' in navigator) { - navigator.audioSession.type = "playback"; // Android background play fix + if (isiOS && 'audioSession' in navigator) { + navigator.audioSession.type = "playback"; } } + $playbutton.addClass('bg-gray').prop('disabled', true); setTimeout(() => { $playbutton.removeClass('bg-gray').prop('disabled', false); diff --git a/web/js/api.js b/web/js/api.js index eca1996..e9e120f 100644 --- a/web/js/api.js +++ b/web/js/api.js @@ -40,6 +40,7 @@ function tuneDown() { } function tuneTo(freq) { + previousFreq = getCurrentFreq(); socket.send("T" + ((freq).toFixed(1) * 1000)); } diff --git a/web/js/confighandler.js b/web/js/confighandler.js index 533b524..e7bac21 100644 --- a/web/js/confighandler.js +++ b/web/js/confighandler.js @@ -96,6 +96,8 @@ function populateFields(data, prefix = "") { $element.val(value); } }); + + updateIconState(); } function updateConfigData(data, prefix = "") { diff --git a/web/js/init.js b/web/js/init.js index 08d4429..e672142 100644 --- a/web/js/init.js +++ b/web/js/init.js @@ -1,9 +1,9 @@ -var currentDate = new Date('Feb 23, 2025 15:30:00'); +var currentDate = new Date('Apr 19, 2025 21:30:00'); var day = currentDate.getDate(); var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1 var year = currentDate.getFullYear(); var formattedDate = day + '/' + month + '/' + year; -var currentVersion = 'v1.3.6 [' + formattedDate + ']'; +var currentVersion = 'v1.3.6.1 [' + formattedDate + ']'; getInitialSettings(); removeUrlParameters(); diff --git a/web/js/main.js b/web/js/main.js index 18691a7..aca6157 100644 --- a/web/js/main.js +++ b/web/js/main.js @@ -722,7 +722,6 @@ function checkKey(e) { // Handle default case if needed break; } - previousFreq = currentFreq; } } @@ -1190,13 +1189,25 @@ function initTooltips(target = null) { }); } - function fillPresets() { + let hasAnyPreset = false; + for (let i = 1; i <= 4; i++) { let presetText = localStorage.getItem(`preset${i}`); - $(`#preset${i}-text`).text(presetText); - $(`#preset${i}`).click(function() { - tuneTo(Number(presetText)); - }); + + if (presetText != "null") { + hasAnyPreset = true; + $(`#preset${i}-text`).text(presetText); + $(`#preset${i}`).click(function() { + tuneTo(Number(presetText)); + }); + } else { + $(`#preset${i}`).hide(); + } } - } \ No newline at end of file + + if (!hasAnyPreset) { + $('#preset1').parent().hide(); + } + } + \ No newline at end of file diff --git a/web/js/settings.js b/web/js/settings.js index b97ff08..15d9ba1 100644 --- a/web/js/settings.js +++ b/web/js/settings.js @@ -166,12 +166,10 @@ $(document).ready(() => { $('.version-string').text(currentVersion); setBg(); - - updateIconState(); // Update icons when the checkbox state changes $('input[type="checkbox"]').change(function() { - updateIconState(); + updateIconState(this); }); }); @@ -180,15 +178,27 @@ function getQueryParameter(name) { return urlParams.get(name); } -function updateIconState() { - $('input[type="checkbox"]').each(function() { - var icon = $(this).siblings('label').find('i'); - if ($(this).is(':checked')) { +function updateIconState(el) { + // If an element is passed, update only that one + if (el) { + var $checkbox = $(el); + var icon = $checkbox.siblings('label').find('i'); + if ($checkbox.is(':checked')) { icon.removeClass('fa-toggle-off').addClass('fa-toggle-on'); } else { icon.removeClass('fa-toggle-on').addClass('fa-toggle-off'); } - }); + } else { + // Otherwise, update all checkboxes + $('input[type="checkbox"]').each(function() { + var icon = $(this).siblings('label').find('i'); + if ($(this).is(':checked')) { + icon.removeClass('fa-toggle-off').addClass('fa-toggle-on'); + } else { + icon.removeClass('fa-toggle-on').addClass('fa-toggle-off'); + } + }); + } } function setTheme(themeName) { diff --git a/web/setup.ejs b/web/setup.ejs index a53826e..f63edfd 100644 --- a/web/setup.ejs +++ b/web/setup.ejs @@ -85,8 +85,7 @@
-
-
+

Current users

@@ -120,7 +119,7 @@
-
+

Quick settings

<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Public Tuner', id: 'publicTuner'}) %> @@ -130,7 +129,6 @@ <%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Tune password', id: 'password-tunePass', password: true}) %> <%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Admin password', id: 'password-adminPass', password: true}) %>
-
@@ -208,8 +206,13 @@
-
-

Miscellaneous

+
+

Volume

+

This option will boost the audio volume globally, recommended for the Headless TEF.

+ <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Audio Boost', id: 'audio-audioBoost'}) %> +
+
+

Experimental

If you use an USB audio card on Linux, enabling this option might fix your audio issues.

<%- include('_components', {component: 'checkbox', cssClass: '', label: 'ALSA Software mode', id: 'audio-softwareMode'}) %>
@@ -524,7 +527,7 @@

Tunnel

-

When you become a FMDX.org supporter, you can host your webserver without the need of a public IP address.
+

When you become an FMDX.org supporter, you can host your webserver without the need of a public IP address & port forwarding.
When you become a supporter, you can message the Founders on Discord for your login details.

<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Enable tunnel', id: 'tunnel-enabled'}) %>