You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-27 06:23:53 +01:00
bugfixes
This commit is contained in:
@@ -5,7 +5,7 @@ FM-DX Webserver is a cross-platform web server designed for FM DXers who want to
|
|||||||
# Officially supported devices
|
# Officially supported devices
|
||||||
- **TEF668x:** Supported with PE5PVB's and Konrad's FM-DX Tuner firmware, although Arduino versions with other firmwares will work too
|
- **TEF668x:** Supported with PE5PVB's and Konrad's FM-DX Tuner firmware, although Arduino versions with other firmwares will work too
|
||||||
- **XDR F1HD:** Officially supported, works best with Konrad's FM-DX Tuner firmware
|
- **XDR F1HD:** Officially supported, works best with Konrad's FM-DX Tuner firmware
|
||||||
- **SDR (AirSpy / RTL-SDR):** Supported unofficially via SDRSharp and XDR-GTK plugin
|
- **SDR (AirSpy / RTL-SDR):** Supported unofficially via SDRSharp and the XDR-GTK plugin
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- **Web-Based Control:** Access and control your TEF6686 / F1HD receiver from any device with a web browser.
|
- **Web-Based Control:** Access and control your TEF6686 / F1HD receiver from any device with a web browser.
|
||||||
@@ -20,7 +20,7 @@ Check [here](https://trello.com/b/OAKo7n0Q/fm-dx-webserver) for an up to date ta
|
|||||||
Join our **Discord community** to get the latest development update info, share feedback and receive support.
|
Join our **Discord community** to get the latest development update info, share feedback and receive support.
|
||||||
[<img alt="Join the OpenRadio Discord community!" src="https://i.imgur.com/lI9Tuxf.png" height="120">](https://discord.gg/ZAVNdS74mC)
|
[<img alt="Join the OpenRadio Discord community!" src="https://i.imgur.com/lI9Tuxf.png" height="120">](https://discord.gg/ZAVNdS74mC)
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started (Windows)
|
||||||
|
|
||||||
1. Install node.js from here:
|
1. Install node.js from here:
|
||||||
```bash
|
```bash
|
||||||
@@ -46,6 +46,9 @@ Join our **Discord community** to get the latest development update info, share
|
|||||||
|
|
||||||
5. Open your web browser and navigate to `http:/localhost:8080` to access the web interface.
|
5. Open your web browser and navigate to `http:/localhost:8080` to access the web interface.
|
||||||
|
|
||||||
|
## Getting Started (Linux)
|
||||||
|
[Click here for the Linux installation tutorial.](https://gist.github.com/bkram/788098558312d2fa71c07dc443e03d10)
|
||||||
|
|
||||||
## Utilized projects
|
## Utilized projects
|
||||||
|
|
||||||
This project utilizes these libraries:
|
This project utilizes these libraries:
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ function handleData(ws, receivedData) {
|
|||||||
if((modifiedData / 1000).toFixed(3) == dataToSend.freq) {
|
if((modifiedData / 1000).toFixed(3) == dataToSend.freq) {
|
||||||
resetToDefault(dataToSend);
|
resetToDefault(dataToSend);
|
||||||
rdsparser.clear(rds);
|
rdsparser.clear(rds);
|
||||||
|
dataToSend.af = [];
|
||||||
return; // Prevent tune spamming using scrollwheel
|
return; // Prevent tune spamming using scrollwheel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,15 +141,11 @@ function connectToXdrd() {
|
|||||||
authFlags.authMsg = true;
|
authFlags.authMsg = true;
|
||||||
logInfo('Authentication with xdrd successful.');
|
logInfo('Authentication with xdrd successful.');
|
||||||
} else if (line.startsWith('G')) {
|
} else if (line.startsWith('G')) {
|
||||||
const [command, value] = line.split('');
|
const value = line.substring(1);
|
||||||
switch (command) {
|
dataHandler.initialData.eq = value.charAt(0);
|
||||||
case 'G':
|
dataHandler.dataToSend.eq = value.charAt(0);
|
||||||
dataHandler.initialData.eq = value[1];
|
dataHandler.initialData.ims = value.charAt(1);
|
||||||
dataHandler.dataToSend.eq = value[1];
|
dataHandler.dataToSend.ims = value.charAt(1);
|
||||||
dataHandler.initialData.ims = value[0];
|
|
||||||
dataHandler.dataToSend.ims = value[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (line.startsWith('Z')) {
|
} else if (line.startsWith('Z')) {
|
||||||
let modifiedLine = line.slice(1);
|
let modifiedLine = line.slice(1);
|
||||||
dataHandler.initialData.ant = modifiedLine;
|
dataHandler.initialData.ant = modifiedLine;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function enableAudioStream() {
|
|||||||
childProcess.stderr.on('data', (data) => {
|
childProcess.stderr.on('data', (data) => {
|
||||||
logFfmpeg(`stderr: ${data}`);
|
logFfmpeg(`stderr: ${data}`);
|
||||||
if(data.includes('I/O error')) {
|
if(data.includes('I/O error')) {
|
||||||
logError('Audio device \x1b[35m' + serverConfig.audio.audioDevice + '\x1b[0m failed to start. Start server with the command \x1b[33mnode . --ffmpegdebug \x1b[0mfor more info.')
|
logError('Audio device \x1b[35m' + serverConfig.audio.audioDevice + '\x1b[0m failed to start. Start server with the command \x1b[33mnode . --ffmpegdebug \x1b[0mfor more info.');
|
||||||
}
|
}
|
||||||
if(data.includes('size=') && startupSuccess === false) {
|
if(data.includes('size=') && startupSuccess === false) {
|
||||||
logInfo('Audio stream started up successfully.');
|
logInfo('Audio stream started up successfully.');
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
top: 18px;
|
top: 18px;
|
||||||
z-index: 9999;
|
z-index: 100;
|
||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
border: 1px solid var(--color-main);
|
border: 1px solid var(--color-main);
|
||||||
|
|||||||
@@ -420,7 +420,7 @@
|
|||||||
<br>
|
<br>
|
||||||
<% if(ownerContact){ %>
|
<% if(ownerContact){ %>
|
||||||
<span>Owner contact:</span><br>
|
<span>Owner contact:</span><br>
|
||||||
<span class="text-small m-0"><%= ownerContact %></span>
|
<span class="text-small m-0 bottom-20"><%= ownerContact %></span>
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -452,7 +452,7 @@
|
|||||||
<input type="text" id="chat-nickname" name="chat-nickname" placeholder="Nickname">
|
<input type="text" id="chat-nickname" name="chat-nickname" placeholder="Nickname">
|
||||||
<button class="br-0 w-100 top-10" style="height: 44px" id="chat-nickname-save">Save</button>
|
<button class="br-0 w-100 top-10" style="height: 44px" id="chat-nickname-save">Save</button>
|
||||||
<p style="margin: 5px;">
|
<p style="margin: 5px;">
|
||||||
Current identity: <span style="color: #bada55;" id="chat-admin"></span> <strong id="chat-identity-nickname">Anonymous User</strong>
|
Current identity: <span style="color: #bada55;" id="chat-admin"></span> <strong id="chat-identity-nickname"></strong>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
chatSocket.onmessage = function(event) {
|
chatSocket.onmessage = function(event) {
|
||||||
const messageData = JSON.parse(event.data);
|
const messageData = JSON.parse(event.data);
|
||||||
const isAdmin = messageData.admin ? '<span style="color: lime">[ADMIN]</span>' : '';
|
const isAdmin = messageData.admin ? '<span style="color: #bada55">[ADMIN]</span>' : '';
|
||||||
|
|
||||||
if (messageData.type === 'clientIp') {
|
if (messageData.type === 'clientIp') {
|
||||||
chatIdentityNickname.html(isAdmin + " " + savedNickname.length > 0 ? savedNickname : 'Anonymous User');
|
chatIdentityNickname.html(isAdmin + " " + (savedNickname.length > 0 ? savedNickname : 'Anonymous User'));
|
||||||
chatIdentityNickname.attr('title', messageData.ip);
|
chatIdentityNickname.attr('title', messageData.ip);
|
||||||
} else {
|
} else {
|
||||||
const chatMessage = `
|
const chatMessage = `
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ function submitData() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#audio-software-mode').prop("checked", data.audio.softwareMode || false);
|
$('#audio-software-mode').prop("checked", data.audio.softwareMode || false);
|
||||||
$('#startup-volume').val(data.audio.startupVolume || 100);
|
$('#startup-volume').val(data.audio.startupVolume || 1);
|
||||||
$('#volume-percentage-value').text(data.audio.startupVolume !== undefined ? (data.audio.startupVolume * 100).toFixed(0) + '%' : '100%');
|
$('#volume-percentage-value').text(data.audio.startupVolume !== undefined ? (data.audio.startupVolume * 100).toFixed(0) + '%' : '100%');
|
||||||
|
|
||||||
$('#webserver-name').val(data.identification.tunerName);
|
$('#webserver-name').val(data.identification.tunerName);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
var currentDate = new Date('March 28, 2024 22:00:00');
|
var currentDate = new Date('April 6, 2024 01:00:00');
|
||||||
var day = currentDate.getDate();
|
var day = currentDate.getDate();
|
||||||
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
|
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
|
||||||
var year = currentDate.getFullYear();
|
var year = currentDate.getFullYear();
|
||||||
@@ -12,10 +12,8 @@ function getInitialSettings() {
|
|||||||
url: './static_data',
|
url: './static_data',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
// Use the received data (data.qthLatitude, data.qthLongitude) as needed
|
|
||||||
localStorage.setItem('qthLatitude', data.qthLatitude);
|
localStorage.setItem('qthLatitude', data.qthLatitude);
|
||||||
localStorage.setItem('qthLongitude', data.qthLongitude);
|
localStorage.setItem('qthLongitude', data.qthLongitude);
|
||||||
localStorage.setItem('streamEnabled', data.streamEnabled);
|
|
||||||
localStorage.setItem('defaultTheme', data.defaultTheme);
|
localStorage.setItem('defaultTheme', data.defaultTheme);
|
||||||
localStorage.setItem('preset1', data.presets[0]);
|
localStorage.setItem('preset1', data.presets[0]);
|
||||||
localStorage.setItem('preset2', data.presets[1]);
|
localStorage.setItem('preset2', data.presets[1]);
|
||||||
|
|||||||
@@ -805,10 +805,10 @@ function createListItem(element) {
|
|||||||
|
|
||||||
function updateButtonState(buttonId, value) {
|
function updateButtonState(buttonId, value) {
|
||||||
var button = $("#" + buttonId);
|
var button = $("#" + buttonId);
|
||||||
if (value === 0) {
|
if (value == 0) {
|
||||||
button.addClass("btn-disabled");
|
button.hasClass("btn-disabled") ? null : button.addClass("btn-disabled");
|
||||||
} else {
|
} else {
|
||||||
button.removeClass("btn-disabled");
|
button.hasClass("btn-disabled") ? button.removeClass("btn-disabled") : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ const signalUnits = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
// Theme Selector
|
|
||||||
const themeSelector = $('#theme-selector');
|
const themeSelector = $('#theme-selector');
|
||||||
const savedTheme = localStorage.getItem('theme');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
const defaultTheme = localStorage.getItem('defaultTheme');
|
const defaultTheme = localStorage.getItem('defaultTheme');
|
||||||
@@ -47,7 +46,6 @@ $(document).ready(() => {
|
|||||||
setBg();
|
setBg();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Signal Selector
|
|
||||||
const signalSelector = $('#signal-selector');
|
const signalSelector = $('#signal-selector');
|
||||||
|
|
||||||
if (localStorage.getItem('signalUnit')) {
|
if (localStorage.getItem('signalUnit')) {
|
||||||
@@ -88,7 +86,6 @@ $(document).ready(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assuming you have an anchor tag with id 'logout-link'
|
|
||||||
$('.logout-link').click(function (event) {
|
$('.logout-link').click(function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@@ -97,11 +94,10 @@ $(document).ready(() => {
|
|||||||
type: 'GET', // Assuming the logout is a GET request, adjust accordingly
|
type: 'GET', // Assuming the logout is a GET request, adjust accordingly
|
||||||
url: './logout',
|
url: './logout',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
// Update the content on the page with the message from the response
|
|
||||||
$('#login-message').text(data.message);
|
$('#login-message').text(data.message);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
location.reload(true);
|
location.reload(true);
|
||||||
}, 1750);
|
}, 1000);
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
// Handle error response
|
// Handle error response
|
||||||
@@ -121,7 +117,6 @@ $(document).ready(() => {
|
|||||||
$("#extended-frequency-range").prop("checked", true);
|
$("#extended-frequency-range").prop("checked", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the value of the checkbox into local storage when its state changes
|
|
||||||
$("#extended-frequency-range").change(function() {
|
$("#extended-frequency-range").change(function() {
|
||||||
var isChecked = $(this).is(":checked");
|
var isChecked = $(this).is(":checked");
|
||||||
localStorage.setItem("extendedFreqRange", isChecked);
|
localStorage.setItem("extendedFreqRange", isChecked);
|
||||||
@@ -137,7 +132,6 @@ $(document).ready(() => {
|
|||||||
$("#smooth-signal").prop("checked", true);
|
$("#smooth-signal").prop("checked", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the value of the checkbox into local storage when its state changes
|
|
||||||
$("#ps-underscores").change(function() {
|
$("#ps-underscores").change(function() {
|
||||||
var isChecked = $(this).is(":checked");
|
var isChecked = $(this).is(":checked");
|
||||||
localStorage.setItem("psUnderscores", isChecked);
|
localStorage.setItem("psUnderscores", isChecked);
|
||||||
@@ -160,7 +154,6 @@ function setTheme(themeName) {
|
|||||||
// Extracting the RGBA components and opacity value
|
// Extracting the RGBA components and opacity value
|
||||||
const rgbaComponents = themeColors[2].match(/(\d+(\.\d+)?)/g);
|
const rgbaComponents = themeColors[2].match(/(\d+(\.\d+)?)/g);
|
||||||
const opacity = parseFloat(rgbaComponents[3]);
|
const opacity = parseFloat(rgbaComponents[3]);
|
||||||
// Calculating 80% of the opacity
|
|
||||||
const newOpacity = opacity * 0.75;
|
const newOpacity = opacity * 0.75;
|
||||||
// Constructing the new RGBA string with the adjusted opacity
|
// Constructing the new RGBA string with the adjusted opacity
|
||||||
const textColor2 = `rgba(${rgbaComponents[0]}, ${rgbaComponents[1]}, ${rgbaComponents[2]}, ${newOpacity})`;
|
const textColor2 = `rgba(${rgbaComponents[0]}, ${rgbaComponents[1]}, ${rgbaComponents[2]}, ${newOpacity})`;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ $(document).ready(function() {
|
|||||||
fetchData();
|
fetchData();
|
||||||
|
|
||||||
$('#startup-volume').on('change', function() {
|
$('#startup-volume').on('change', function() {
|
||||||
console.log('changed');
|
|
||||||
var value = $(this).val(); // Get the value of the range input
|
var value = $(this).val(); // Get the value of the range input
|
||||||
var percentage = value * 100; // Convert to percentage
|
var percentage = value * 100; // Convert to percentage
|
||||||
$('#volume-percentage-value').text(percentage.toFixed(0) + '%'); // Display the percentage value
|
$('#volume-percentage-value').text(percentage.toFixed(0) + '%'); // Display the percentage value
|
||||||
|
|||||||
@@ -423,7 +423,7 @@
|
|||||||
<div class="panel-75 auto" style="height: 48px;">
|
<div class="panel-75 auto" style="height: 48px;">
|
||||||
<input type="range" id="startup-volume" min="0" max="1" step="0.01" value="1" aria-label="Startup Volume slider">
|
<input type="range" id="startup-volume" min="0" max="1" step="0.01" value="1" aria-label="Startup Volume slider">
|
||||||
</div>
|
</div>
|
||||||
<h3 class="top-25" id="volume-percentage-value">asdf</hš>
|
<h3 class="top-25" id="volume-percentage-value"></h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user