mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-07-31 09:19:16 +02:00
Compare commits
16
Commits
887cf6331e
...
97b087bb5e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97b087bb5e
|
||
|
|
6f34ec23af
|
||
|
|
eee092abbe
|
||
|
|
be6aca5dc2
|
||
|
|
5025b5cfb9
|
||
|
|
e28e258ce9
|
||
|
|
5d0e5f92d2
|
||
|
|
c9c05d8d01
|
||
|
|
810965a682
|
||
|
|
7d9bda114a
|
||
|
|
72a468d5fe
|
||
|
|
561f002140
|
||
|
|
b617f98aec
|
||
|
|
b749c8178f
|
||
|
|
65f01462b0
|
||
|
|
94e108205d
|
@@ -209,8 +209,7 @@ function handleData(wss, receivedData, rdsWss) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the received TX info
|
// Get the received TX info
|
||||||
fetchTx(parseFloat(dataToSend.freq).toFixed(1), dataToSend.pi, dataToSend.ps)
|
fetchTx(parseFloat(dataToSend.freq).toFixed(1), dataToSend.pi, dataToSend.ps).then((currentTx) => {
|
||||||
.then((currentTx) => {
|
|
||||||
if (currentTx && currentTx.station !== undefined && parseInt(currentTx.distance) < 4000) {
|
if (currentTx && currentTx.station !== undefined && parseInt(currentTx.distance) < 4000) {
|
||||||
dataToSend.txInfo = {
|
dataToSend.txInfo = {
|
||||||
tx: currentTx.station,
|
tx: currentTx.station,
|
||||||
@@ -227,8 +226,7 @@ function handleData(wss, receivedData, rdsWss) {
|
|||||||
score: currentTx.score,
|
score: currentTx.score,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})
|
}).catch((error) => console.log("Error fetching Tx info:", error));
|
||||||
.catch((error) => console.log("Error fetching Tx info:", error));
|
|
||||||
|
|
||||||
// Send the updated data to the client
|
// Send the updated data to the client
|
||||||
const dataToSendJSON = JSON.stringify(dataToSend);
|
const dataToSendJSON = JSON.stringify(dataToSend);
|
||||||
|
|||||||
+2
-4
@@ -42,9 +42,7 @@ function connectToSerial() {
|
|||||||
serialport.open((err) => {
|
serialport.open((err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
logError('Error opening port: ' + err.message);
|
logError('Error opening port: ' + err.message);
|
||||||
setTimeout(() => {
|
setTimeout(connectToSerial, 5000);
|
||||||
connectToSerial();
|
|
||||||
}, 5000);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +76,7 @@ function connectToSerial() {
|
|||||||
serverConfig.audio.startupVolume
|
serverConfig.audio.startupVolume
|
||||||
? serialport.write('Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n')
|
? serialport.write('Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n')
|
||||||
: serialport.write('Y100\n');
|
: serialport.write('Y100\n');
|
||||||
}, 6000);
|
}, 2000);
|
||||||
|
|
||||||
serialport.on('data', helpers.resolveDataBuffer);
|
serialport.on('data', helpers.resolveDataBuffer);
|
||||||
serialport.on('error', (error) => logError(error.message));
|
serialport.on('error', (error) => logError(error.message));
|
||||||
|
|||||||
+21
-47
@@ -36,8 +36,7 @@ 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,
|
||||||
@@ -49,7 +48,6 @@ router.get('/', (req, res) => {
|
|||||||
videoDevices: result.audioDevices,
|
videoDevices: result.audioDevices,
|
||||||
audioDevices: result.videoDevices,
|
audioDevices: result.videoDevices,
|
||||||
serialPorts: serialPorts,
|
serialPorts: serialPorts,
|
||||||
serialPorts: serialPorts,
|
|
||||||
tunerProfiles: tunerProfiles.map((profile) => ({
|
tunerProfiles: tunerProfiles.map((profile) => ({
|
||||||
id: profile.id,
|
id: profile.id,
|
||||||
label: profile.label,
|
label: profile.label,
|
||||||
@@ -90,9 +88,7 @@ router.get('/403', (req, res) => {
|
|||||||
res.render('403', { reason });
|
res.render('403', { reason });
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/audioonly', (req, res) => {
|
router.get('/audioonly', (req, res) => res.render('audioonly'))
|
||||||
res.render('audioonly');
|
|
||||||
})
|
|
||||||
|
|
||||||
router.get('/wizard', (req, res) => {
|
router.get('/wizard', (req, res) => {
|
||||||
let serialPorts;
|
let serialPorts;
|
||||||
@@ -102,8 +98,7 @@ router.get('/wizard', (req, res) => {
|
|||||||
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,
|
||||||
@@ -176,15 +171,6 @@ router.get('/setup', (req, res) => {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
router.get('/rds', (req, res) => {
|
|
||||||
res.send('Please connect using a WebSocket compatible app to obtain the RDS stream.');
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get('/rdsspy', (req, res) => {
|
|
||||||
res.send('Please connect using a WebSocket compatible app to obtain the RDS stream.');
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get('/api', (req, res) => {
|
router.get('/api', (req, res) => {
|
||||||
const { ps_errors, rt0_errors, rt1_errors, ims, eq, ant, st_forced, previousFreq, txInfo, rdsMode, ...dataToSend } = dataHandler.dataToSend;
|
const { ps_errors, rt0_errors, rt1_errors, ims, eq, ant, st_forced, previousFreq, txInfo, rdsMode, ...dataToSend } = dataHandler.dataToSend;
|
||||||
res.json({
|
res.json({
|
||||||
@@ -196,9 +182,8 @@ 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 = 8;
|
||||||
const WINDOW_MS = 15 * 60 * 1000;
|
const WINDOW_MS = 15 * 60 * 1000;
|
||||||
|
|
||||||
const authenticate = (req, res, next) => {
|
const authenticate = (req, res, next) => {
|
||||||
@@ -242,9 +227,7 @@ router.post('/login', authenticate, (req, res) => {
|
|||||||
|
|
||||||
router.get('/logout', (req, res) => {
|
router.get('/logout', (req, res) => {
|
||||||
// Clear the session and redirect to the main page
|
// Clear the session and redirect to the main page
|
||||||
req.session.destroy(() => {
|
req.session.destroy(() => res.status(200).json({ message: 'Logged out successfully, refreshing the page...' }));
|
||||||
res.status(200).json({ message: 'Logged out successfully, refreshing the page...' });
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/kick', (req, res) => {
|
router.get('/kick', (req, res) => {
|
||||||
@@ -254,9 +237,7 @@ router.get('/kick', (req, res) => {
|
|||||||
res.status(403);
|
res.status(403);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(res.redirect, 500, "/setup");
|
||||||
res.redirect('/setup');
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/addToBanlist', (req, res) => {
|
router.get('/addToBanlist', (req, res) => {
|
||||||
@@ -300,7 +281,6 @@ router.get('/removeFromBanlist', (req, res) => {
|
|||||||
res.json({ success: true, message: 'IP address removed from banlist.' });
|
res.json({ success: true, message: 'IP address removed from banlist.' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
router.post('/saveData', (req, res) => {
|
router.post('/saveData', (req, res) => {
|
||||||
const data = req.body;
|
const data = req.body;
|
||||||
let firstSetup;
|
let firstSetup;
|
||||||
@@ -331,11 +311,8 @@ router.get('/getData', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/getDevices', (req, res) => {
|
router.get('/getDevices', (req, res) => {
|
||||||
if (req.session.isAdminAuthenticated || !fs.existsSync(configName + '.json')) {
|
if (req.session.isAdminAuthenticated || !fs.existsSync(configName + '.json')) parseAudioDevice(res.json);
|
||||||
parseAudioDevice((result) => {
|
else res.status(403).json({ error: 'Unauthorized' });
|
||||||
res.json(result);
|
|
||||||
});
|
|
||||||
} else res.status(403).json({ error: 'Unauthorized' });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Static data are being sent through here on connection - these don't change when the server is running */
|
/* Static data are being sent through here on connection - these don't change when the server is running */
|
||||||
@@ -360,8 +337,15 @@ router.get('/server_time', (req, res) => {
|
|||||||
res.json({ serverTime: serverTimeUTC });
|
res.json({ serverTime: serverTimeUTC });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/ping', (req, res) => {
|
router.get('/ping', (req, res) => res.send('pong'));
|
||||||
res.send('pong');
|
|
||||||
|
router.get('/webrtc-audio-flags.json', (req, res) => res.json(serverConfig.webRtc.flags));
|
||||||
|
router.get('/webrtc-audio.conf', (req, res) => {
|
||||||
|
let out = "";
|
||||||
|
for (const [endpoint, bitrate] of Object.entries(serverConfig.webRtc.audio)) {
|
||||||
|
out += `${bitrate * 1000}:${endpoint};`;
|
||||||
|
}
|
||||||
|
res.send(out);
|
||||||
});
|
});
|
||||||
|
|
||||||
const logHistory = {};
|
const logHistory = {};
|
||||||
@@ -369,13 +353,11 @@ const logHistory = {};
|
|||||||
// Function to check if the ID has been logged within the last 60 minutes
|
// Function to check if the ID has been logged within the last 60 minutes
|
||||||
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;
|
||||||
|
|
||||||
// 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
|
||||||
@@ -440,16 +422,8 @@ router.get('/log_fmlist', (req, res) => {
|
|||||||
|
|
||||||
const request = https.request(options, (response) => {
|
const request = https.request(options, (response) => {
|
||||||
let data = '';
|
let data = '';
|
||||||
|
response.on('data', (chunk) => data += chunk);
|
||||||
// Collect response chunks
|
response.on('end', () => res.status(200).send(data));
|
||||||
response.on('data', (chunk) => {
|
|
||||||
data += chunk;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Response ended
|
|
||||||
response.on('end', () => {
|
|
||||||
res.status(200).send(data);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle errors in the request
|
// Handle errors in the request
|
||||||
|
|||||||
+2
-4
@@ -57,8 +57,7 @@ function authenticateWithXdrd(client, salt, password) {
|
|||||||
sha1.update(saltBuffer);
|
sha1.update(saltBuffer);
|
||||||
sha1.update(passwordBuffer);
|
sha1.update(passwordBuffer);
|
||||||
|
|
||||||
const hashedPassword = sha1.digest('hex');
|
client.write(sha1.digest('hex') + '\n');
|
||||||
client.write(hashedPassword + '\n');
|
|
||||||
client.write('x\n');
|
client.write('x\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,8 +119,7 @@ function handleConnect(clientIp, currentUsers, ws, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ipInfoInFlight.has(clientIp)) {
|
if (ipInfoInFlight.has(clientIp)) {
|
||||||
ipInfoInFlight
|
ipInfoInFlight.get(clientIp)
|
||||||
.get(clientIp)
|
|
||||||
.then((info) => processConnection(clientIp, info, currentUsers, ws, callback))
|
.then((info) => processConnection(clientIp, info, currentUsers, ws, callback))
|
||||||
.catch(() => processConnection(clientIp, { country: undefined }, currentUsers, ws, callback));
|
.catch(() => processConnection(clientIp, { country: undefined }, currentUsers, ws, callback));
|
||||||
return;
|
return;
|
||||||
|
|||||||
+3
-3
@@ -11,15 +11,15 @@ tunnel.download();
|
|||||||
|
|
||||||
require("./device");
|
require("./device");
|
||||||
|
|
||||||
|
require('./stream/index');
|
||||||
|
const startServer = require("./web");
|
||||||
|
|
||||||
{
|
{
|
||||||
const helpers = require('./helpers');
|
const helpers = require('./helpers');
|
||||||
const plugins = helpers.findServerFiles(serverConfig.plugins);
|
const plugins = helpers.findServerFiles(serverConfig.plugins);
|
||||||
if (plugins.length > 0) setTimeout(helpers.startPluginsWithDelay, 3000, plugins, 3000);
|
if (plugins.length > 0) setTimeout(helpers.startPluginsWithDelay, 3000, plugins, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
require('./stream/index');
|
|
||||||
const startServer = require("./web");
|
|
||||||
|
|
||||||
startServer(serverConfig.webserver.webserverIp === '0.0.0.0' ? 'localhost' : serverConfig.webserver.webserverIp);
|
startServer(serverConfig.webserver.webserverIp === '0.0.0.0' ? 'localhost' : serverConfig.webserver.webserverIp);
|
||||||
|
|
||||||
tunnel.connect();
|
tunnel.connect();
|
||||||
|
|||||||
+118
-241
@@ -222,271 +222,148 @@ var countries = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
var iso = [
|
var iso = [
|
||||||
"AL",
|
"AL", "EE",
|
||||||
"EE",
|
"DZ", "ET",
|
||||||
"DZ",
|
"AD", "AO",
|
||||||
"ET",
|
"FI", "AM",
|
||||||
"AD",
|
"FR", "SH",
|
||||||
"AO",
|
"GA", "AT",
|
||||||
"FI",
|
"GM", "AZ",
|
||||||
"AM",
|
"GE", "DE",
|
||||||
"FR",
|
"BH", "GH",
|
||||||
"SH",
|
"BY", "GI",
|
||||||
"GA",
|
"BE", "GR",
|
||||||
"AT",
|
"BJ", "GN",
|
||||||
"GM",
|
"BA", "GW",
|
||||||
"AZ",
|
"BW", "HU",
|
||||||
"GE",
|
"BG", "IS",
|
||||||
"DE",
|
"BF", "IQ",
|
||||||
"BH",
|
"BI", "IE",
|
||||||
"GH",
|
"--", "IL",
|
||||||
"BY",
|
"CM", "IT",
|
||||||
"GI",
|
"JO", "CV",
|
||||||
"BE",
|
"KZ", "CF",
|
||||||
"GR",
|
"KE", "TD",
|
||||||
"BJ",
|
"XK", "KM",
|
||||||
"GN",
|
"KW", "CD",
|
||||||
"BA",
|
"KG", "CG",
|
||||||
"GW",
|
"LV", "CI",
|
||||||
"BW",
|
"LB", "HR",
|
||||||
"HU",
|
"LS", "CY",
|
||||||
"BG",
|
"LR", "CZ",
|
||||||
"IS",
|
"LY", "DK",
|
||||||
"BF",
|
"LI", "DJ",
|
||||||
"IQ",
|
"LT", "EG",
|
||||||
"BI",
|
"LU", "GQ",
|
||||||
"IE",
|
"MK", "ER",
|
||||||
"--",
|
"MG", "SC",
|
||||||
"IL",
|
"MW", "SL",
|
||||||
"CM",
|
"ML", "SK",
|
||||||
"IT",
|
"MT", "SI",
|
||||||
"JO",
|
"MR", "SO",
|
||||||
"CV",
|
"MU", "ZA",
|
||||||
"KZ",
|
"MD", "SS",
|
||||||
"CF",
|
"MC", "ES",
|
||||||
"KE",
|
"MN", "SD",
|
||||||
"TD",
|
"ME", "SZ",
|
||||||
"XK",
|
"MA", "SE",
|
||||||
"KM",
|
"MZ", "CH",
|
||||||
"KW",
|
"NA", "SY",
|
||||||
"CD",
|
"NL", "TJ",
|
||||||
"KG",
|
"NE", "TZ",
|
||||||
"CG",
|
"NG", "TG",
|
||||||
"LV",
|
"NO", "TN",
|
||||||
"CI",
|
"OM", "TR",
|
||||||
"LB",
|
"PS", "TM",
|
||||||
"HR",
|
"PL", "UG",
|
||||||
"LS",
|
"PT", "UA",
|
||||||
"CY",
|
"QA", "AE",
|
||||||
"LR",
|
"RO", "GB",
|
||||||
"CZ",
|
"RU", "UZ",
|
||||||
"LY",
|
"RW", "VA",
|
||||||
"DK",
|
"SM", "EH",
|
||||||
"LI",
|
"ST", "YE",
|
||||||
"DJ",
|
"SA", "ZM",
|
||||||
"LT",
|
"SN", "ZW",
|
||||||
"EG",
|
"RS", "AI",
|
||||||
"LU",
|
"GY", "AG",
|
||||||
"GQ",
|
"HT", "AR",
|
||||||
"MK",
|
"HN", "AW",
|
||||||
"ER",
|
"JM", "BS",
|
||||||
"MG",
|
"MQ", "BB",
|
||||||
"SC",
|
"MX", "BZ",
|
||||||
"MW",
|
"MS", "--",
|
||||||
"SL",
|
"--", "BO",
|
||||||
"ML",
|
"NI", "BR",
|
||||||
"SK",
|
"PA", "CA",
|
||||||
"MT",
|
"PY", "KY",
|
||||||
"SI",
|
"PE", "CL",
|
||||||
"MR",
|
"--", "CO",
|
||||||
"SO",
|
"KN", "CR",
|
||||||
"MU",
|
"LC", "CU",
|
||||||
"ZA",
|
"PM", "DM",
|
||||||
"MD",
|
"VC", "DO",
|
||||||
"SS",
|
"SR", "SN",
|
||||||
"MC",
|
"TT", "TB",
|
||||||
"ES",
|
"FK", "GL",
|
||||||
"MN",
|
"UY", "GD",
|
||||||
"SD",
|
"VE", "GP",
|
||||||
"ME",
|
"VG", "GT",
|
||||||
"SZ",
|
"AF", "KR",
|
||||||
"MA",
|
"LA", "AU",
|
||||||
"SE",
|
"MO", "AU",
|
||||||
"MZ",
|
"MY", "AU",
|
||||||
"CH",
|
"MV", "AU",
|
||||||
"NA",
|
"MH", "AU",
|
||||||
"SY",
|
"FM", "AU",
|
||||||
"NL",
|
"MM", "AU",
|
||||||
"TJ",
|
"NR", "AU",
|
||||||
"NE",
|
"NP", "BD",
|
||||||
"TZ",
|
"NZ", "BT",
|
||||||
"NG",
|
"PK", "BN",
|
||||||
"TG",
|
"PG", "KH",
|
||||||
"NO",
|
"PH", "CN",
|
||||||
"TN",
|
"WS", "SG",
|
||||||
"OM",
|
"SB", "FJ",
|
||||||
"TR",
|
"LK", "HK",
|
||||||
"PS",
|
"TW", "IN",
|
||||||
"TM",
|
"TH", "ID",
|
||||||
"PL",
|
"TO", "IR",
|
||||||
"UG",
|
"VU", "JP",
|
||||||
"PT",
|
"VN", "KI",
|
||||||
"UA",
|
"KP", "--"
|
||||||
"QA",
|
|
||||||
"AE",
|
|
||||||
"RO",
|
|
||||||
"GB",
|
|
||||||
"RU",
|
|
||||||
"UZ",
|
|
||||||
"RW",
|
|
||||||
"VA",
|
|
||||||
"SM",
|
|
||||||
"EH",
|
|
||||||
"ST",
|
|
||||||
"YE",
|
|
||||||
"SA",
|
|
||||||
"ZM",
|
|
||||||
"SN",
|
|
||||||
"ZW",
|
|
||||||
"RS",
|
|
||||||
"AI",
|
|
||||||
"GY",
|
|
||||||
"AG",
|
|
||||||
"HT",
|
|
||||||
"AR",
|
|
||||||
"HN",
|
|
||||||
"AW",
|
|
||||||
"JM",
|
|
||||||
"BS",
|
|
||||||
"MQ",
|
|
||||||
"BB",
|
|
||||||
"MX",
|
|
||||||
"BZ",
|
|
||||||
"MS",
|
|
||||||
"--",
|
|
||||||
"--",
|
|
||||||
"BO",
|
|
||||||
"NI",
|
|
||||||
"BR",
|
|
||||||
"PA",
|
|
||||||
"CA",
|
|
||||||
"PY",
|
|
||||||
"KY",
|
|
||||||
"PE",
|
|
||||||
"CL",
|
|
||||||
"--",
|
|
||||||
"CO",
|
|
||||||
"KN",
|
|
||||||
"CR",
|
|
||||||
"LC",
|
|
||||||
"CU",
|
|
||||||
"PM",
|
|
||||||
"DM",
|
|
||||||
"VC",
|
|
||||||
"DO",
|
|
||||||
"SR",
|
|
||||||
"SN",
|
|
||||||
"TT",
|
|
||||||
"TB",
|
|
||||||
"FK",
|
|
||||||
"GL",
|
|
||||||
"UY",
|
|
||||||
"GD",
|
|
||||||
"VE",
|
|
||||||
"GP",
|
|
||||||
"VG",
|
|
||||||
"GT",
|
|
||||||
"AF",
|
|
||||||
"KR",
|
|
||||||
"LA",
|
|
||||||
"AU",
|
|
||||||
"MO",
|
|
||||||
"AU",
|
|
||||||
"MY",
|
|
||||||
"AU",
|
|
||||||
"MV",
|
|
||||||
"AU",
|
|
||||||
"MH",
|
|
||||||
"AU",
|
|
||||||
"FM",
|
|
||||||
"AU",
|
|
||||||
"MM",
|
|
||||||
"AU",
|
|
||||||
"NR",
|
|
||||||
"AU",
|
|
||||||
"NP",
|
|
||||||
"BD",
|
|
||||||
"NZ",
|
|
||||||
"BT",
|
|
||||||
"PK",
|
|
||||||
"BN",
|
|
||||||
"PG",
|
|
||||||
"KH",
|
|
||||||
"PH",
|
|
||||||
"CN",
|
|
||||||
"WS",
|
|
||||||
"SG",
|
|
||||||
"SB",
|
|
||||||
"FJ",
|
|
||||||
"LK",
|
|
||||||
"HK",
|
|
||||||
"TW",
|
|
||||||
"IN",
|
|
||||||
"TH",
|
|
||||||
"ID",
|
|
||||||
"TO",
|
|
||||||
"IR",
|
|
||||||
"VU",
|
|
||||||
"JP",
|
|
||||||
"VN",
|
|
||||||
"KI",
|
|
||||||
"KP",
|
|
||||||
"--"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const rdsEccA0A6Lut = [
|
const rdsEccA0A6Lut = [
|
||||||
// A0
|
// A0
|
||||||
[
|
[ "USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR",
|
||||||
"USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR",
|
|
||||||
"USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR",
|
"USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR",
|
||||||
"USA/VI/PR", "", "USA/VI/PR", "USA/VI/PR", ""
|
"USA/VI/PR", "", "USA/VI/PR", "USA/VI/PR", ""
|
||||||
],
|
],
|
||||||
// A1
|
// A1
|
||||||
[
|
[ "", "", "", "", "", "", "", "", "", "",
|
||||||
"", "", "", "", "",
|
|
||||||
"", "", "", "", "",
|
|
||||||
"Canada", "Canada", "Canada", "Canada", "Greenland"
|
"Canada", "Canada", "Canada", "Canada", "Greenland"
|
||||||
],
|
],
|
||||||
// A2
|
// A2
|
||||||
[
|
[ "Anguilla", "Antigua and Barbuda", "Brazil/Equador", "Falkland Islands", "Barbados",
|
||||||
"Anguilla", "Antigua and Barbuda", "Brazil/Equador", "Falkland Islands", "Barbados",
|
|
||||||
"Belize", "Cayman Islands", "Costa Rica", "Cuba", "Argentina",
|
"Belize", "Cayman Islands", "Costa Rica", "Cuba", "Argentina",
|
||||||
"Brazil", "Brazil/Bermuda", "Brazil/AN", "Guadeloupe", "Bahamas"
|
"Brazil", "Brazil/Bermuda", "Brazil/AN", "Guadeloupe", "Bahamas"
|
||||||
],
|
],
|
||||||
// A3
|
// A3
|
||||||
[
|
[ "Bolivia", "Colombia", "Jamaica", "Martinique", "",
|
||||||
"Bolivia", "Colombia", "Jamaica", "Martinique", "",
|
|
||||||
"Paraguay", "Nicaragua", "", "Panama", "Dominica",
|
"Paraguay", "Nicaragua", "", "Panama", "Dominica",
|
||||||
"Dominican Republic", "Chile", "Grenada", "Turks and Caicos islands", "Guyana"
|
"Dominican Republic", "Chile", "Grenada", "Turks and Caicos islands", "Guyana"
|
||||||
],
|
],
|
||||||
// A4
|
// A4
|
||||||
[
|
[ "Guatemala", "Honduras", "Aruba", "", "Montserrat",
|
||||||
"Guatemala", "Honduras", "Aruba", "", "Montserrat",
|
|
||||||
"Trinidad and Tobago", "Peru", "Suriname", "Uruguay", "St. Kitts",
|
"Trinidad and Tobago", "Peru", "Suriname", "Uruguay", "St. Kitts",
|
||||||
"St. Lucia", "El Salvador", "Haiti", "Venezuela", "Virgin Islands"
|
"St. Lucia", "El Salvador", "Haiti", "Venezuela", "Virgin Islands"
|
||||||
],
|
],
|
||||||
// A5
|
// A5
|
||||||
[
|
[ "", "", "", "", "", "", "", "", "", "",
|
||||||
"", "", "", "", "",
|
"Mexico", "St. Vincent", "Mexico", "Mexico", "Mexico"],
|
||||||
"", "", "", "", "",
|
|
||||||
"Mexico", "St. Vincent", "Mexico", "Mexico", "Mexico"
|
|
||||||
],
|
|
||||||
// A6
|
// A6
|
||||||
[
|
["", "", "", "", "", "", "", "", "", "", "", "", "", "", "St. Pierre and Miquelon"]
|
||||||
"", "", "", "", "",
|
|
||||||
"", "", "", "", "",
|
|
||||||
"", "", "", "", "St. Pierre and Miquelon"
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const rdsEccD0D4Lut = [
|
const rdsEccD0D4Lut = [
|
||||||
|
|||||||
@@ -123,7 +123,13 @@ let serverConfig = {
|
|||||||
antennaStartup: "0",
|
antennaStartup: "0",
|
||||||
antennaNoUsers: "0",
|
antennaNoUsers: "0",
|
||||||
antennaNoUsersDelay: false,
|
antennaNoUsersDelay: false,
|
||||||
trustedProxies: []
|
trustedProxies: [],
|
||||||
|
webRtc: {
|
||||||
|
flags: {
|
||||||
|
disable3las: false
|
||||||
|
},
|
||||||
|
audio: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to add missing fields without overwriting existing values
|
// Function to add missing fields without overwriting existing values
|
||||||
|
|||||||
+21
-24
@@ -61,15 +61,12 @@ let currentUsers = 0;
|
|||||||
let timeoutAntenna;
|
let timeoutAntenna;
|
||||||
|
|
||||||
wss.on('connection', (ws, request) => {
|
wss.on('connection', (ws, request) => {
|
||||||
const output = storage.ctl_output;
|
|
||||||
let clientIp = helpers.getIpAddress(request);
|
let clientIp = helpers.getIpAddress(request);
|
||||||
const userCommandHistory = {};
|
const userCommandHistory = {};
|
||||||
|
|
||||||
// Per-IP limit connection open
|
// Per-IP limit connection open
|
||||||
if (clientIp) {
|
if (clientIp) {
|
||||||
const isLocalIp = (
|
const isLocalIp = (clientIp === '127.0.0.1' || clientIp === '::1' || clientIp.startsWith('192.168.') || clientIp.startsWith('10.') || clientIp.startsWith('172.16.'));
|
||||||
clientIp === '127.0.0.1' || clientIp === '::1' ||
|
|
||||||
clientIp.startsWith('192.168.') || clientIp.startsWith('10.') || clientIp.startsWith('172.16.'));
|
|
||||||
if (!isLocalIp) {
|
if (!isLocalIp) {
|
||||||
if (!ipConnectionCounts.has(clientIp)) ipConnectionCounts.set(clientIp, 0);
|
if (!ipConnectionCounts.has(clientIp)) ipConnectionCounts.set(clientIp, 0);
|
||||||
const currentCount = ipConnectionCounts.get(clientIp);
|
const currentCount = ipConnectionCounts.get(clientIp);
|
||||||
@@ -160,7 +157,7 @@ wss.on('connection', (ws, request) => {
|
|||||||
if (tuningLimit && (tuneFreq < tuningLowerLimit || tuneFreq > tuningUpperLimit) || isNaN(tuneFreq)) return;
|
if (tuningLimit && (tuneFreq < tuningLowerLimit || tuneFreq > tuningUpperLimit) || isNaN(tuneFreq)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((serverConfig.publicTuner && !serverConfig.lockToAdmin) || isAdminAuthenticated || (!serverConfig.publicTuner && !serverConfig.lockToAdmin && isTuneAuthenticated)) output.write(`${command}\n`);
|
if ((serverConfig.publicTuner && !serverConfig.lockToAdmin) || isAdminAuthenticated || (!serverConfig.publicTuner && !serverConfig.lockToAdmin && isTuneAuthenticated)) storage.ctl_output.write(`${command}\n`);
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('close', (code) => {
|
ws.on('close', (code) => {
|
||||||
@@ -191,35 +188,34 @@ wss.on('connection', (ws, request) => {
|
|||||||
if (currentUsers === 0) {
|
if (currentUsers === 0) {
|
||||||
storage.connectedUsers = [];
|
storage.connectedUsers = [];
|
||||||
|
|
||||||
if (serverConfig.bwAutoNoUsers === "1") output.write("W0\n"); // Auto BW 'Enabled'
|
if (serverConfig.bwAutoNoUsers === "1") storage.ctl_output.write("W0\n"); // Auto BW 'Enabled'
|
||||||
|
|
||||||
// cEQ and iMS combinations
|
// cEQ and iMS combinations
|
||||||
if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "1") output.write("G00\n"); // Both Disabled
|
if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "1") storage.ctl_output.write("G00\n"); // Both Disabled
|
||||||
else if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "0") output.write(`G0${dataHandler.dataToSend.ims}\n`);
|
else if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "0") storage.ctl_output.write(`G0${dataHandler.dataToSend.ims}\n`);
|
||||||
else if (serverConfig.ceqNoUsers === "0" && serverConfig.imsNoUsers === "1") output.write(`G${dataHandler.dataToSend.eq}0\n`);
|
else if (serverConfig.ceqNoUsers === "0" && serverConfig.imsNoUsers === "1") storage.ctl_output.write(`G${dataHandler.dataToSend.eq}0\n`);
|
||||||
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "0") output.write(`G1${dataHandler.dataToSend.ims}\n`);
|
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "0") storage.ctl_output.write(`G1${dataHandler.dataToSend.ims}\n`);
|
||||||
else if (serverConfig.ceqNoUsers === "0" && serverConfig.imsNoUsers === "2") output.write(`G${dataHandler.dataToSend.eq}1\n`);
|
else if (serverConfig.ceqNoUsers === "0" && serverConfig.imsNoUsers === "2") storage.ctl_output.write(`G${dataHandler.dataToSend.eq}1\n`);
|
||||||
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "1") output.write("G10\n"); // Only cEQ enabled
|
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "1") storage.ctl_output.write("G10\n"); // Only cEQ enabled
|
||||||
else if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "2") output.write("G01\n"); // Only iMS enabled
|
else if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "2") storage.ctl_output.write("G01\n"); // Only iMS enabled
|
||||||
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "2") output.write("G11\n"); // Both Enabled
|
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "2") storage.ctl_output.write("G11\n"); // Both Enabled
|
||||||
|
|
||||||
// Handle stereo mode
|
// Handle stereo mode
|
||||||
if (serverConfig.stereoNoUsers === "1") output.write("B0\n");
|
if (serverConfig.stereoNoUsers === "1") storage.ctl_output.write("B0\n");
|
||||||
else if (serverConfig.stereoNoUsers === "2") output.write("B1\n");
|
else if (serverConfig.stereoNoUsers === "2") storage.ctl_output.write("B1\n");
|
||||||
|
|
||||||
// Handle Antenna selection
|
// Handle Antenna selection
|
||||||
if (timeoutAntenna) clearTimeout(timeoutAntenna);
|
if (timeoutAntenna) clearTimeout(timeoutAntenna);
|
||||||
timeoutAntenna = setTimeout(() => {
|
timeoutAntenna = setTimeout(() => {
|
||||||
if (serverConfig.antennaNoUsers === "1") output.write("Z0\n");
|
if (serverConfig.antennaNoUsers === "1") storage.ctl_output.write("Z0\n");
|
||||||
else if (serverConfig.antennaNoUsers === "2") output.write("Z1\n");
|
else if (serverConfig.antennaNoUsers === "2") storage.ctl_output.write("Z1\n");
|
||||||
else if (serverConfig.antennaNoUsers === "3") output.write("Z2\n");
|
else if (serverConfig.antennaNoUsers === "3") storage.ctl_output.write("Z2\n");
|
||||||
else if (serverConfig.antennaNoUsers === "4") output.write("Z3\n");
|
else if (serverConfig.antennaNoUsers === "4") storage.ctl_output.write("Z3\n");
|
||||||
}, serverConfig.antennaNoUsersDelay ? 15000 : 0);
|
}, serverConfig.antennaNoUsersDelay ? 15000 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tunerLockTracker.has(ws)) {
|
if (tunerLockTracker.has(ws)) {
|
||||||
logInfo(`User who locked the tuner left. Unlocking the tuner.`);
|
logInfo(`User who locked the tuner left. Unlocking the tuner.`);
|
||||||
output.write('wT0\n') // Why are we telling the tuner that?
|
|
||||||
tunerLockTracker.delete(ws);
|
tunerLockTracker.delete(ws);
|
||||||
serverConfig.publicTuner = true;
|
serverConfig.publicTuner = true;
|
||||||
}
|
}
|
||||||
@@ -228,7 +224,7 @@ wss.on('connection', (ws, request) => {
|
|||||||
serverConfig.autoShutdown !== true && serverConfig.xdrd.wirelessConnection === true) {
|
serverConfig.autoShutdown !== true && serverConfig.xdrd.wirelessConnection === true) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
if (currentUsers === 0) {
|
if (currentUsers === 0) {
|
||||||
output.write('T' + Math.round(serverConfig.defaultFreq * 1000) + '\n');
|
storage.ctl_output.write('T' + Math.round(serverConfig.defaultFreq * 1000) + '\n');
|
||||||
dataHandler.resetToDefault(dataHandler.dataToSend);
|
dataHandler.resetToDefault(dataHandler.dataToSend);
|
||||||
dataHandler.dataToSend.freq = Number(serverConfig.defaultFreq).toFixed(3);
|
dataHandler.dataToSend.freq = Number(serverConfig.defaultFreq).toFixed(3);
|
||||||
dataHandler.initialData.freq = Number(serverConfig.defaultFreq).toFixed(3);
|
dataHandler.initialData.freq = Number(serverConfig.defaultFreq).toFixed(3);
|
||||||
@@ -254,10 +250,11 @@ pluginsWss.on('connection', (ws, request) => {
|
|||||||
|
|
||||||
ws.on('message', message => {
|
ws.on('message', message => {
|
||||||
// Anti-spam
|
// Anti-spam
|
||||||
helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '10', 'data_plugins');
|
const msg2 = helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '10', 'data_plugins');
|
||||||
|
if(!msg2) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let messageData = JSON.parse(message); // Attempt to parse the JSON. This code will attemp to parse json using the JSON.parse which coincidentally actually parses the json
|
let messageData = JSON.parse(msg2); // Attempt to parse the JSON. This code will attemp to parse json using the JSON.parse which coincidentally actually parses the json
|
||||||
|
|
||||||
if (messageData.type === "GPS" && messageData.value) {
|
if (messageData.type === "GPS" && messageData.value) {
|
||||||
const gpsData = messageData.value;
|
const gpsData = messageData.value;
|
||||||
|
|||||||
+65
-2
@@ -18,9 +18,72 @@
|
|||||||
<script src="js/3las/fallback/3las.fallback.js"></script>
|
<script src="js/3las/fallback/3las.fallback.js"></script>
|
||||||
<script src="js/3las/3las.js"></script>
|
<script src="js/3las/3las.js"></script>
|
||||||
<script src="js/audio.js"></script>
|
<script src="js/audio.js"></script>
|
||||||
|
<script src="js/rtc-audio.js"></script>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #111;
|
||||||
|
color: #eee;
|
||||||
|
font-family: sans-serif;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100vh;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playbutton {
|
||||||
|
background-color: #222;
|
||||||
|
color: #eee;
|
||||||
|
border: 1px solid #444;
|
||||||
|
padding: 10px 24px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playbutton:hover {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playbutton:active {
|
||||||
|
background-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
#volumeSlider {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 800px;
|
||||||
|
accent-color: #4af;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fmdx-webrtc-playbutton-host .fmdx-webrtc-playbutton {
|
||||||
|
background-color: #222;
|
||||||
|
color: #eee;
|
||||||
|
height: auto !important;
|
||||||
|
min-height: unset !important;
|
||||||
|
padding: 10px 24px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<button class="playbutton">Start / Stop</button>
|
<div class="hide-phone">
|
||||||
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="1">
|
<div class="panel-10">
|
||||||
|
<button class="playbutton">
|
||||||
|
<i class="fa fa-play"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="range" id="volumeSlider" min="0" max="1" step="0.001" value="1">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+2
-1
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<meta property="og:title" content="FM-DX WebServer [<%= tunerName %>]">
|
<meta property="og:title" content="FM-DX WebServer [<%= tunerName %>]">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:image" content="https://fmdx.org/img/webserver_icon.png">
|
<meta property="og:image" content="https://flerken.zapto.org:5000/img/webserver_icon.png">
|
||||||
<meta property="og:description" content="Server description: <%= tunerDescMeta %>.">
|
<meta property="og:description" content="Server description: <%= tunerDescMeta %>.">
|
||||||
|
|
||||||
<script src="js/3las/util/3las.helpers.js"></script>
|
<script src="js/3las/util/3las.helpers.js"></script>
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
<script src="js/3las/fallback/3las.fallback.js"></script>
|
<script src="js/3las/fallback/3las.fallback.js"></script>
|
||||||
<script src="js/3las/3las.js"></script>
|
<script src="js/3las/3las.js"></script>
|
||||||
<script src="js/audio.js"></script>
|
<script src="js/audio.js"></script>
|
||||||
|
<script src="js/rtc-audio.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
document.ontouchmove = function(e) {
|
document.ontouchmove = function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
+10
-28
@@ -1,27 +1,16 @@
|
|||||||
var audioStreamRestartInterval;
|
var audioStreamRestartInterval;
|
||||||
var elapsedTimeConnectionWatchdog;
|
var elapsedTimeConnectionWatchdog;
|
||||||
var _3LAS_Settings = /** @class */ (function () {
|
|
||||||
function _3LAS_Settings() {
|
|
||||||
this.SocketHost = location.hostname ? location.hostname : "127.0.0.1";
|
|
||||||
this.SocketPort = location.port;
|
|
||||||
this.SocketPath = "/";
|
|
||||||
this.Fallback = new Fallback_Settings();
|
|
||||||
}
|
|
||||||
return _3LAS_Settings;
|
|
||||||
}());
|
|
||||||
var _3LAS = /** @class */ (function () {
|
var _3LAS = /** @class */ (function () {
|
||||||
function _3LAS(logger, settings) {
|
function _3LAS(url, logger) {
|
||||||
|
this.wsurl = url;
|
||||||
this.Logger = logger;
|
this.Logger = logger;
|
||||||
if (!this.Logger) {
|
if (!this.Logger) this.Logger = new Logging(null, null);
|
||||||
this.Logger = new Logging(null, null);
|
|
||||||
}
|
|
||||||
this.Settings = settings;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.Fallback = new Fallback(this.Logger, this.Settings.Fallback);
|
this.Fallback_Settings = new Fallback_Settings();
|
||||||
|
this.Fallback = new Fallback(this.Logger, this.Fallback_Settings);
|
||||||
this.Fallback.ActivityCallback = this.OnActivity.bind(this);
|
this.Fallback.ActivityCallback = this.OnActivity.bind(this);
|
||||||
}
|
} catch (_b) {
|
||||||
catch (_b) {
|
|
||||||
this.Fallback = null;
|
this.Fallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,9 +18,7 @@ var _3LAS = /** @class */ (function () {
|
|||||||
this.Logger.Log('3LAS: Browser does not support either media handling methods.');
|
this.Logger.Log('3LAS: Browser does not support either media handling methods.');
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
if (isAndroid) {
|
if (isAndroid) this.WakeLock = new WakeLock(this.Logger);
|
||||||
this.WakeLock = new WakeLock(this.Logger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Object.defineProperty(_3LAS.prototype, "Volume", {
|
Object.defineProperty(_3LAS.prototype, "Volume", {
|
||||||
get: function () {
|
get: function () {
|
||||||
@@ -52,9 +39,7 @@ var _3LAS = /** @class */ (function () {
|
|||||||
|
|
||||||
// Restart audio stream if radio data connection was reestablished
|
// Restart audio stream if radio data connection was reestablished
|
||||||
// to prevent stuttering audio in some cases
|
// to prevent stuttering audio in some cases
|
||||||
if (audioStreamRestartInterval) {
|
if (audioStreamRestartInterval) clearInterval(audioStreamRestartInterval);
|
||||||
clearInterval(audioStreamRestartInterval);
|
|
||||||
}
|
|
||||||
audioStreamRestartInterval = setInterval(() => {
|
audioStreamRestartInterval = setInterval(() => {
|
||||||
if (requiresAudioStreamRestart) {
|
if (requiresAudioStreamRestart) {
|
||||||
requiresAudioStreamRestart = false;
|
requiresAudioStreamRestart = false;
|
||||||
@@ -90,12 +75,9 @@ var _3LAS = /** @class */ (function () {
|
|||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
// This is stupid, but required for Android.... thanks Google :(
|
// This is stupid, but required for Android.... thanks Google :(
|
||||||
if (this.WakeLock)
|
if (this.WakeLock) this.WakeLock.Begin();
|
||||||
this.WakeLock.Begin();
|
|
||||||
try {
|
try {
|
||||||
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
this.WebSocket = new WebSocketClient(this.Logger, this.wsurl , this.OnSocketError.bind(this), this.OnSocketConnect.bind(this), this.OnSocketDataReady.bind(this), this.OnSocketDisconnect.bind(this));
|
||||||
const url = `${wsProtocol}//${location.hostname}/audio`;
|
|
||||||
this.WebSocket = new WebSocketClient(this.Logger, url , this.OnSocketError.bind(this), this.OnSocketConnect.bind(this), this.OnSocketDataReady.bind(this), this.OnSocketDisconnect.bind(this));
|
|
||||||
this.Logger.Log("Init of WebSocketClient succeeded");
|
this.Logger.Log("Init of WebSocketClient succeeded");
|
||||||
this.Logger.Log("Trying to connect to server.");
|
this.Logger.Log("Trying to connect to server.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,11 @@ var Fallback_Settings = /** @class */ (function () {
|
|||||||
var Fallback = /** @class */ (function () {
|
var Fallback = /** @class */ (function () {
|
||||||
function Fallback(logger, settings) {
|
function Fallback(logger, settings) {
|
||||||
this.Logger = logger;
|
this.Logger = logger;
|
||||||
if (!this.Logger) {
|
if (!this.Logger) this.Logger = new Logging(null, null);
|
||||||
this.Logger = new Logging(null, null);
|
|
||||||
}
|
|
||||||
// Create audio context
|
// Create audio context
|
||||||
if (typeof AudioContext !== "undefined")
|
if (typeof AudioContext !== "undefined") this.Audio = new AudioContext();
|
||||||
this.Audio = new AudioContext();
|
else if (typeof webkitAudioContext !== "undefined") this.Audio = new webkitAudioContext();
|
||||||
else if (typeof webkitAudioContext !== "undefined")
|
else if (typeof mozAudioContext !== "undefined") this.Audio = new mozAudioContext();
|
||||||
this.Audio = new webkitAudioContext();
|
|
||||||
else if (typeof mozAudioContext !== "undefined")
|
|
||||||
this.Audio = new mozAudioContext();
|
|
||||||
else {
|
else {
|
||||||
this.Logger.Log('3LAS: Browser does not support "AudioContext".');
|
this.Logger.Log('3LAS: Browser does not support "AudioContext".');
|
||||||
throw new Error();
|
throw new Error();
|
||||||
@@ -120,17 +115,13 @@ var Fallback = /** @class */ (function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Callback function from socket connection
|
// Callback function from socket connection
|
||||||
Fallback.prototype.OnSocketError = function (message) {
|
Fallback.prototype.OnSocketError = function (message) {};
|
||||||
};
|
Fallback.prototype.OnSocketConnect = function () {};
|
||||||
Fallback.prototype.OnSocketConnect = function () {
|
Fallback.prototype.OnSocketDisconnect = function () {};
|
||||||
};
|
|
||||||
Fallback.prototype.OnSocketDisconnect = function () {
|
|
||||||
};
|
|
||||||
Fallback.prototype.OnSocketDataReady = function (data) {
|
Fallback.prototype.OnSocketDataReady = function (data) {
|
||||||
this.PacketModCounter++;
|
this.PacketModCounter++;
|
||||||
if (this.PacketModCounter > 100) {
|
if (this.PacketModCounter > 100) {
|
||||||
if (this.ActivityCallback)
|
if (this.ActivityCallback) this.ActivityCallback();
|
||||||
this.ActivityCallback();
|
|
||||||
this.PacketModCounter = 0;
|
this.PacketModCounter = 0;
|
||||||
}
|
}
|
||||||
this.FormatReader.PushData(new Uint8Array(data));
|
this.FormatReader.PushData(new Uint8Array(data));
|
||||||
|
|||||||
@@ -88,9 +88,7 @@ var AudioFormatReader_MPEG = /** @class */ (function (_super) {
|
|||||||
expectedTotalPlayTime_1 += lastGranulePlayTime_1;
|
expectedTotalPlayTime_1 += lastGranulePlayTime_1;
|
||||||
bufferLength += this.Frames[this.Frames.length - 1].Data.length;
|
bufferLength += this.Frames[this.Frames.length - 1].Data.length;
|
||||||
// If needed, add some space for the ID3v2 tag
|
// If needed, add some space for the ID3v2 tag
|
||||||
if (this.AddId3Tag) {
|
if (this.AddId3Tag) bufferLength += AudioFormatReader_MPEG.Id3v2Tag.length;
|
||||||
bufferLength += AudioFormatReader_MPEG.Id3v2Tag.length;
|
|
||||||
}
|
|
||||||
// Create a buffer long enough to hold everything
|
// Create a buffer long enough to hold everything
|
||||||
var decodeBuffer = new Uint8Array(bufferLength);
|
var decodeBuffer = new Uint8Array(bufferLength);
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
@@ -109,8 +107,7 @@ var AudioFormatReader_MPEG = /** @class */ (function (_super) {
|
|||||||
// Increment Id
|
// Increment Id
|
||||||
var id_1 = this.Id++;
|
var id_1 = this.Id++;
|
||||||
// Check if decoded frames might be too far back in the past
|
// Check if decoded frames might be too far back in the past
|
||||||
if (!this.OnBeforeDecode(id_1, expectedTotalPlayTime_1))
|
if (!this.OnBeforeDecode(id_1, expectedTotalPlayTime_1)) return;
|
||||||
return;
|
|
||||||
// Push window to the decoder
|
// Push window to the decoder
|
||||||
this.Audio.decodeAudioData(decodeBuffer.buffer, (function (decodedData) {
|
this.Audio.decodeAudioData(decodeBuffer.buffer, (function (decodedData) {
|
||||||
var _id = id_1;
|
var _id = id_1;
|
||||||
@@ -133,8 +130,7 @@ var AudioFormatReader_MPEG = /** @class */ (function (_super) {
|
|||||||
// Sync found, set frame start
|
// Sync found, set frame start
|
||||||
this.FrameStartIdx = i;
|
this.FrameStartIdx = i;
|
||||||
break;
|
break;
|
||||||
}
|
} i++;
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Find frame end
|
// Find frame end
|
||||||
@@ -172,22 +168,17 @@ var AudioFormatReader_MPEG = /** @class */ (function (_super) {
|
|||||||
};
|
};
|
||||||
// Checks if there is a frame ready to be extracted
|
// Checks if there is a frame ready to be extracted
|
||||||
AudioFormatReader_MPEG.prototype.CanExtractFrame = function () {
|
AudioFormatReader_MPEG.prototype.CanExtractFrame = function () {
|
||||||
if (this.FrameStartIdx < 0 || this.FrameEndIdx < 0)
|
if (this.FrameStartIdx < 0 || this.FrameEndIdx < 0) return false;
|
||||||
return false;
|
else if (this.FrameEndIdx <= this.DataBuffer.length) return true;
|
||||||
else if (this.FrameEndIdx <= this.DataBuffer.length)
|
else return false;
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
// Extract a single frame from the buffer
|
// Extract a single frame from the buffer
|
||||||
AudioFormatReader_MPEG.prototype.ExtractFrame = function () {
|
AudioFormatReader_MPEG.prototype.ExtractFrame = function () {
|
||||||
// Extract frame data from buffer
|
// Extract frame data from buffer
|
||||||
var frameArray = this.DataBuffer.buffer.slice(this.FrameStartIdx, this.FrameEndIdx);
|
var frameArray = this.DataBuffer.buffer.slice(this.FrameStartIdx, this.FrameEndIdx);
|
||||||
// Remove frame from buffer
|
// Remove frame from buffer
|
||||||
if ((this.FrameEndIdx + 1) < this.DataBuffer.length)
|
if ((this.FrameEndIdx + 1) < this.DataBuffer.length) this.DataBuffer = new Uint8Array(this.DataBuffer.buffer.slice(this.FrameEndIdx));
|
||||||
this.DataBuffer = new Uint8Array(this.DataBuffer.buffer.slice(this.FrameEndIdx));
|
else this.DataBuffer = new Uint8Array(0);
|
||||||
else
|
|
||||||
this.DataBuffer = new Uint8Array(0);
|
|
||||||
// Reset Start/End indices
|
// Reset Start/End indices
|
||||||
this.FrameStartIdx = 0;
|
this.FrameStartIdx = 0;
|
||||||
this.FrameEndIdx = -1;
|
this.FrameEndIdx = -1;
|
||||||
|
|||||||
+16
-20
@@ -7,6 +7,7 @@ class WebSocketAudioPlayer {
|
|||||||
this.sourceBuffer = null;
|
this.sourceBuffer = null;
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
this.started = false;
|
this.started = false;
|
||||||
|
this._volume = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
supported() {
|
supported() {
|
||||||
@@ -21,7 +22,7 @@ class WebSocketAudioPlayer {
|
|||||||
const liveEdge = buffered.end(buffered.length - 1);
|
const liveEdge = buffered.end(buffered.length - 1);
|
||||||
const lag = liveEdge - this.audio.currentTime;
|
const lag = liveEdge - this.audio.currentTime;
|
||||||
|
|
||||||
if (lag > .9) this.audio.currentTime = liveEdge - 0.2; // snap to near live edge
|
if (lag > 1) this.audio.currentTime = liveEdge - 0.25; // snap to near live edge
|
||||||
}
|
}
|
||||||
|
|
||||||
Start() {
|
Start() {
|
||||||
@@ -59,8 +60,13 @@ class WebSocketAudioPlayer {
|
|||||||
this.started = false;
|
this.started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setVolume(v) {
|
get Volume() {
|
||||||
if (this.audio) this.audio.volume = Math.max(0, Math.min(1, v));
|
return this._volume;
|
||||||
|
}
|
||||||
|
set Volume(v) {
|
||||||
|
const actual = Math.max(0, Math.min(1, v))
|
||||||
|
if (this.audio) this.audio.volume = actual;
|
||||||
|
this._volume = actual;
|
||||||
}
|
}
|
||||||
|
|
||||||
_appendNext() {
|
_appendNext() {
|
||||||
@@ -87,16 +93,12 @@ function createStream() {
|
|||||||
if (MediaSource.isTypeSupported("audio/mpeg")) {
|
if (MediaSource.isTypeSupported("audio/mpeg")) {
|
||||||
firefox = false;
|
firefox = false;
|
||||||
Stream = new WebSocketAudioPlayer(url);
|
Stream = new WebSocketAudioPlayer(url);
|
||||||
Stream.setVolume($('#volumeSlider').val());
|
|
||||||
} else {
|
} else {
|
||||||
firefox = true;
|
firefox = true;
|
||||||
alert("Your browser does not support MP3 over MSE, meaning we have to use 3LAS which is terrible and gives terrible audio quality. If you want better sound, switch to anything chromium based")
|
alert("Your browser does not support MP3 over MSE, meaning we have to use 3LAS which is terrible and gives terrible audio quality. If you want better sound, switch to anything chromium based")
|
||||||
const settings = new _3LAS_Settings();
|
Stream = new _3LAS(url, null);
|
||||||
Stream = new _3LAS(null, settings);
|
|
||||||
Stream.Volume = $('#volumeSlider').val();
|
|
||||||
Stream.ConnectivityCallback = OnConnectivityCallback;
|
|
||||||
}
|
}
|
||||||
|
Stream.Volume = $('#volumeSlider').val();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Initialization Error: ", error);
|
console.error("Initialization Error: ", error);
|
||||||
}
|
}
|
||||||
@@ -130,22 +132,16 @@ function OnPlayButtonClick(_ev) {
|
|||||||
|
|
||||||
$playbutton.addClass('bg-gray').prop('disabled', true);
|
$playbutton.addClass('bg-gray').prop('disabled', true);
|
||||||
setTimeout(() => $playbutton.removeClass('bg-gray').prop('disabled', false), 2000);
|
setTimeout(() => $playbutton.removeClass('bg-gray').prop('disabled', false), 2000);
|
||||||
if (Stream && firefox) Stream.setVolume($("#volumeSlider").val());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVolume() {
|
function updateVolume() {
|
||||||
if(!firefox) {
|
|
||||||
const newVolume = $(this).val();
|
const newVolume = $(this).val();
|
||||||
if (Stream) Stream.setVolume(newVolume);
|
if(!Stream) {
|
||||||
else console.warn("Stream is not initialized.");
|
console.warn("Stream is not initialized.");
|
||||||
} else {
|
return;
|
||||||
if(Stream) {
|
|
||||||
const newVolume = $(this).val();
|
|
||||||
newVolumeGlobal = newVolume;
|
|
||||||
console.log("Volume updated to:", newVolume);
|
|
||||||
Stream.Volume = newVolume;
|
|
||||||
} else console.warn("Stream is not initialized.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stream.Volume = newVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(Init);
|
$(document).ready(Init);
|
||||||
|
|||||||
+1336
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user