mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-07-30 08:49:16 +02:00
audioonly
This commit is contained in:
+30
-26
@@ -22,9 +22,9 @@ router.get('/', (req, res) => {
|
|||||||
let requestIp = helpers.getIpAddress(req);
|
let requestIp = helpers.getIpAddress(req);
|
||||||
|
|
||||||
const ipList = (requestIp || '').split(',').map(ip => ip.trim()).filter(Boolean); // in case there are multiple IPs (proxy), we need to check all of them (No we don't)
|
const ipList = (requestIp || '').split(',').map(ip => ip.trim()).filter(Boolean); // in case there are multiple IPs (proxy), we need to check all of them (No we don't)
|
||||||
|
|
||||||
const banEntry = serverConfig.webserver.banlist.find(banEntry => ipList.includes(banEntry[0]));
|
const banEntry = serverConfig.webserver.banlist.find(banEntry => ipList.includes(banEntry[0]));
|
||||||
|
|
||||||
if (banEntry) {
|
if (banEntry) {
|
||||||
const reason = banEntry[3];
|
const reason = banEntry[3];
|
||||||
res.render('403', { reason });
|
res.render('403', { reason });
|
||||||
@@ -36,14 +36,14 @@ router.get('/', (req, res) => {
|
|||||||
|
|
||||||
if (configExists() === false) {
|
if (configExists() === false) {
|
||||||
let serialPorts;
|
let serialPorts;
|
||||||
|
|
||||||
SerialPort.list()
|
SerialPort.list()
|
||||||
.then((deviceList) => {
|
.then((deviceList) => {
|
||||||
serialPorts = deviceList.map(port => ({
|
serialPorts = deviceList.map(port => ({
|
||||||
path: port.path,
|
path: port.path,
|
||||||
friendlyName: port.friendlyName,
|
friendlyName: port.friendlyName,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
parseAudioDevice((result) => {
|
parseAudioDevice((result) => {
|
||||||
res.render('wizard', { // Magical utility wizard
|
res.render('wizard', { // Magical utility wizard
|
||||||
isAdminAuthenticated: true,
|
isAdminAuthenticated: true,
|
||||||
@@ -91,9 +91,13 @@ router.get('/403', (req, res) => {
|
|||||||
res.render('403', { reason });
|
res.render('403', { reason });
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.get('/audioonly', (req, res) => {
|
||||||
|
res.render('audioonly');
|
||||||
|
})
|
||||||
|
|
||||||
router.get('/wizard', (req, res) => {
|
router.get('/wizard', (req, res) => {
|
||||||
let serialPorts;
|
let serialPorts;
|
||||||
|
|
||||||
if(!req.session.isAdminAuthenticated) {
|
if(!req.session.isAdminAuthenticated) {
|
||||||
res.render('login');
|
res.render('login');
|
||||||
return;
|
return;
|
||||||
@@ -105,7 +109,7 @@ router.get('/wizard', (req, res) => {
|
|||||||
path: port.path,
|
path: port.path,
|
||||||
friendlyName: port.friendlyName,
|
friendlyName: port.friendlyName,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
parseAudioDevice((result) => {
|
parseAudioDevice((result) => {
|
||||||
res.render('wizard', {
|
res.render('wizard', {
|
||||||
isAdminAuthenticated: req.session.isAdminAuthenticated,
|
isAdminAuthenticated: req.session.isAdminAuthenticated,
|
||||||
@@ -121,9 +125,9 @@ router.get('/wizard', (req, res) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/setup', (req, res) => {
|
router.get('/setup', (req, res) => {
|
||||||
let serialPorts;
|
let serialPorts;
|
||||||
function loadConfig() {
|
function loadConfig() {
|
||||||
if (fs.existsSync(configPath)) {
|
if (fs.existsSync(configPath)) {
|
||||||
const configFileContents = fs.readFileSync(configPath, 'utf8');
|
const configFileContents = fs.readFileSync(configPath, 'utf8');
|
||||||
@@ -136,18 +140,18 @@ router.get('/setup', (req, res) => {
|
|||||||
res.render('login');
|
res.render('login');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialPort.list()
|
SerialPort.list()
|
||||||
.then((deviceList) => {
|
.then((deviceList) => {
|
||||||
serialPorts = deviceList.map(port => ({
|
serialPorts = deviceList.map(port => ({
|
||||||
path: port.path,
|
path: port.path,
|
||||||
friendlyName: port.friendlyName,
|
friendlyName: port.friendlyName,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
parseAudioDevice((result) => {
|
parseAudioDevice((result) => {
|
||||||
const processUptimeInSeconds = Math.floor(process.uptime());
|
const processUptimeInSeconds = Math.floor(process.uptime());
|
||||||
const formattedProcessUptime = helpers.formatUptime(processUptimeInSeconds);
|
const formattedProcessUptime = helpers.formatUptime(processUptimeInSeconds);
|
||||||
|
|
||||||
const updatedConfig = loadConfig(); // Reload the config every time
|
const updatedConfig = loadConfig(); // Reload the config every time
|
||||||
res.render('setup', {
|
res.render('setup', {
|
||||||
isAdminAuthenticated: req.session.isAdminAuthenticated,
|
isAdminAuthenticated: req.session.isAdminAuthenticated,
|
||||||
@@ -171,9 +175,9 @@ router.get('/setup', (req, res) => {
|
|||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
router.get('/rds', (req, res) => {
|
router.get('/rds', (req, res) => {
|
||||||
res.send('Please connect using a WebSocket compatible app to obtain the RDS stream.');
|
res.send('Please connect using a WebSocket compatible app to obtain the RDS stream.');
|
||||||
@@ -197,7 +201,7 @@ router.get('/api', (req, res) => {
|
|||||||
|
|
||||||
const loginAttempts = {}; // Format: { 'ip': { count: 1, lastAttempt: 1234567890 } }
|
const loginAttempts = {}; // Format: { 'ip': { count: 1, lastAttempt: 1234567890 } }
|
||||||
const MAX_ATTEMPTS = 10;
|
const MAX_ATTEMPTS = 10;
|
||||||
const WINDOW_MS = 15 * 60 * 1000;
|
const WINDOW_MS = 15 * 60 * 1000;
|
||||||
|
|
||||||
const authenticate = (req, res, next) => {
|
const authenticate = (req, res, next) => {
|
||||||
const ip = helpers.getIpAddress(req);
|
const ip = helpers.getIpAddress(req);
|
||||||
@@ -305,7 +309,7 @@ router.post('/saveData', (req, res) => {
|
|||||||
if(req.session.isAdminAuthenticated || !configExists()) {
|
if(req.session.isAdminAuthenticated || !configExists()) {
|
||||||
configUpdate(data);
|
configUpdate(data);
|
||||||
fmdxList.update();
|
fmdxList.update();
|
||||||
|
|
||||||
if(!configExists()) firstSetup = true;
|
if(!configExists()) firstSetup = true;
|
||||||
logInfo('Server config changed successfully.');
|
logInfo('Server config changed successfully.');
|
||||||
if(firstSetup === true) res.status(200).send('Data saved successfully!\nPlease, restart the server to load your configuration.');
|
if(firstSetup === true) res.status(200).send('Data saved successfully!\nPlease, restart the server to load your configuration.');
|
||||||
@@ -313,9 +317,9 @@ router.post('/saveData', (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/getData', (req, res) => {
|
router.get('/getData', (req, res) => {
|
||||||
if (configExists() === false) res.json(serverConfig);
|
if (configExists() === false) res.json(serverConfig);
|
||||||
|
|
||||||
if(req.session.isAdminAuthenticated) {
|
if(req.session.isAdminAuthenticated) {
|
||||||
// Check if the file exists
|
// Check if the file exists
|
||||||
fs.access(configPath, fs.constants.F_OK, (err) => {
|
fs.access(configPath, fs.constants.F_OK, (err) => {
|
||||||
@@ -360,7 +364,7 @@ router.get('/server_time', (req, res) => {
|
|||||||
|
|
||||||
router.get('/ping', (req, res) => {
|
router.get('/ping', (req, res) => {
|
||||||
res.send('pong');
|
res.send('pong');
|
||||||
});
|
});
|
||||||
|
|
||||||
const logHistory = {};
|
const logHistory = {};
|
||||||
|
|
||||||
@@ -368,27 +372,27 @@ const logHistory = {};
|
|||||||
function canLog(id) {
|
function canLog(id) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const sixtyMinutes = 60 * 60 * 1000; // 60 minutes in milliseconds
|
const sixtyMinutes = 60 * 60 * 1000; // 60 minutes in milliseconds
|
||||||
|
|
||||||
// Remove expired entries
|
// Remove expired entries
|
||||||
for (const [entryId, timestamp] of Object.entries(logHistory)) {
|
for (const [entryId, timestamp] of Object.entries(logHistory)) {
|
||||||
if ((now - timestamp) >= sixtyMinutes) {
|
if ((now - timestamp) >= sixtyMinutes) {
|
||||||
delete logHistory[entryId];
|
delete logHistory[entryId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logHistory[id] && (now - logHistory[id]) < sixtyMinutes) return false; // Deny logging if less than 60 minutes have passed
|
if (logHistory[id] && (now - logHistory[id]) < sixtyMinutes) return false; // Deny logging if less than 60 minutes have passed
|
||||||
logHistory[id] = now; // Update with the current timestamp
|
logHistory[id] = now; // Update with the current timestamp
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
router.get('/log_fmlist', (req, res) => {
|
router.get('/log_fmlist', (req, res) => {
|
||||||
if (dataHandler.dataToSend.txInfo.tx.length === 0) {
|
if (serverConfig.extras.fmlistIntegration === false || (serverConfig.extras.fmlistAdminOnly && !req.session.isTuneAuthenticated)) {
|
||||||
res.status(500).send('No suitable transmitter to log.');
|
res.status(500).send('FMLIST Integration is not available.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serverConfig.extras.fmlistIntegration === false || (serverConfig.extras.fmlistAdminOnly && !req.session.isTuneAuthenticated)) {
|
if (dataHandler.dataToSend.txInfo.tx.length === 0) {
|
||||||
res.status(500).send('FMLIST Integration is not available.');
|
res.status(500).send('No suitable transmitter to log.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,7 +472,7 @@ router.get('/tunnelservers', async (req, res) => {
|
|||||||
{ value: "sg", host: "sg.fmtuner.org", label: "Asia & Oceania" },
|
{ value: "sg", host: "sg.fmtuner.org", label: "Asia & Oceania" },
|
||||||
{ value: "pldx", host: "pldx.duckdns.org", label: "Poland (k201)" },
|
{ value: "pldx", host: "pldx.duckdns.org", label: "Poland (k201)" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
servers.map(async s => {
|
servers.map(async s => {
|
||||||
const latency = await helpers.checkLatency(s.host);
|
const latency = await helpers.checkLatency(s.host);
|
||||||
@@ -478,7 +482,7 @@ router.get('/tunnelservers', async (req, res) => {
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
res.json(results);
|
res.json(results);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -319,7 +319,7 @@ wss.on('connection', (ws, request) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientIp !== '::ffff:127.0.0.1' ||
|
if (clientIp !== '127.0.0.1' ||
|
||||||
(request.socket && request.socket.remoteAddress && request.socket.remoteAddress !== '::ffff:127.0.0.1') ||
|
(request.socket && request.socket.remoteAddress && request.socket.remoteAddress !== '::ffff:127.0.0.1') ||
|
||||||
(request.headers && request.headers['origin'] && request.headers['origin'].trim() !== '')) {
|
(request.headers && request.headers['origin'] && request.headers['origin'].trim() !== '')) {
|
||||||
currentUsers++;
|
currentUsers++;
|
||||||
@@ -392,7 +392,6 @@ wss.on('connection', (ws, request) => {
|
|||||||
const isLocalIp = (
|
const isLocalIp = (
|
||||||
clientIp === '127.0.0.1' ||
|
clientIp === '127.0.0.1' ||
|
||||||
clientIp === '::1' ||
|
clientIp === '::1' ||
|
||||||
clientIp === '::ffff:127.0.0.1' ||
|
|
||||||
clientIp.startsWith('192.168.') ||
|
clientIp.startsWith('192.168.') ||
|
||||||
clientIp.startsWith('10.') ||
|
clientIp.startsWith('10.') ||
|
||||||
clientIp.startsWith('172.16.')
|
clientIp.startsWith('172.16.')
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>FM-DX Webserver (Audio)</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<script src="js/audio.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button class="playbutton">start</button>
|
||||||
|
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="1">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -539,9 +539,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-panel-footer flex-container flex-phone">
|
<div class="modal-panel-footer flex-container flex-phone">
|
||||||
<div class="modal-panel-sidebar" style="font-size: 22px;">
|
<div class="modal-panel-sidebar" style="font-size: 22px;">
|
||||||
<div class="flex-center" style="height: 50px">
|
|
||||||
<i class="fa-solid fa-hand-holding-medical"></i>
|
|
||||||
</div>
|
|
||||||
<div class="flex-center" style="height: 50px">
|
<div class="flex-center" style="height: 50px">
|
||||||
<i class="fa-brands fa-discord"></i>
|
<i class="fa-brands fa-discord"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+3
-4
@@ -77,8 +77,7 @@ function Init(_ev) {
|
|||||||
function createStream() {
|
function createStream() {
|
||||||
try {
|
try {
|
||||||
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
const audioUrl = `${wsProtocol}//${location.hostname}/audio`;
|
Stream = new WebSocketAudioPlayer(`${wsProtocol}//${location.hostname}/audio`);
|
||||||
Stream = new WebSocketAudioPlayer(audioUrl);
|
|
||||||
Stream.setVolume($('#volumeSlider').val());
|
Stream.setVolume($('#volumeSlider').val());
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Initialization Error: ", error);
|
console.error("Initialization Error: ", error);
|
||||||
@@ -100,14 +99,14 @@ function OnPlayButtonClick(_ev) {
|
|||||||
console.log("Stopping stream...");
|
console.log("Stopping stream...");
|
||||||
shouldReconnect = false;
|
shouldReconnect = false;
|
||||||
destroyStream();
|
destroyStream();
|
||||||
$playbutton.find('.fa-solid').toggleClass('fa-stop fa-play');
|
$playbutton.find('.fa-solid')?.toggleClass('fa-stop fa-play');
|
||||||
if (isAppleiOS && 'audioSession' in navigator) navigator.audioSession.type = "none";
|
if (isAppleiOS && 'audioSession' in navigator) navigator.audioSession.type = "none";
|
||||||
} else {
|
} else {
|
||||||
console.log("Starting stream...");
|
console.log("Starting stream...");
|
||||||
shouldReconnect = true;
|
shouldReconnect = true;
|
||||||
createStream();
|
createStream();
|
||||||
Stream.start();
|
Stream.start();
|
||||||
$playbutton.find('.fa-solid').toggleClass('fa-play fa-stop');
|
$playbutton.find('.fa-solid')?.toggleClass('fa-play fa-stop');
|
||||||
if (isAppleiOS && 'audioSession' in navigator) navigator.audioSession.type = "playback";
|
if (isAppleiOS && 'audioSession' in navigator) navigator.audioSession.type = "playback";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user