You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 22:13:53 +01:00
admin dashboard, bugfixes, cleanup
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,3 +1,3 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
/example.js
|
/*.json
|
||||||
/config.json
|
/ffmpeg.exe
|
||||||
79
index.js
79
index.js
@@ -281,9 +281,6 @@ app.get('/static_data', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.get('/server_time', (req, res) => {
|
app.get('/server_time', (req, res) => {
|
||||||
/*const serverTime = new Date().toISOString(); // Get server time in ISO format
|
|
||||||
const serverTimezoneOffset = new Date().getTimezoneOffset(); // Get server timezone offset in minutes*/
|
|
||||||
|
|
||||||
const serverTime = new Date(); // Get current server time
|
const serverTime = new Date(); // Get current server time
|
||||||
const serverTimeUTC = new Date(serverTime.getTime() - (serverTime.getTimezoneOffset() * 60000)); // Adjust server time to UTC
|
const serverTimeUTC = new Date(serverTime.getTime() - (serverTime.getTimezoneOffset() * 60000)); // Adjust server time to UTC
|
||||||
res.json({
|
res.json({
|
||||||
@@ -577,8 +574,6 @@ app.get('/getDevices', (req, res) => {
|
|||||||
/**
|
/**
|
||||||
* WEBSOCKET BLOCK
|
* WEBSOCKET BLOCK
|
||||||
*/
|
*/
|
||||||
let lastDisconnectTime = null;
|
|
||||||
|
|
||||||
wss.on('connection', (ws, request) => {
|
wss.on('connection', (ws, request) => {
|
||||||
const clientIp = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
|
const clientIp = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
|
||||||
currentUsers++;
|
currentUsers++;
|
||||||
@@ -618,40 +613,57 @@ wss.on('connection', (ws, request) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ws.on('message', (message) => {
|
ws.on('message', (message) => {
|
||||||
logDebug('Command received from \x1b[90m' + clientIp + '\x1b[0m:', message.toString());
|
const command = message.toString();
|
||||||
command = message.toString();
|
logDebug(`Command received from \x1b[90m${clientIp}\x1b[0m: ${command}`);
|
||||||
|
|
||||||
if(command.startsWith('X')) {
|
if (command.startsWith('X')) {
|
||||||
logWarn('Remote tuner shutdown attempted by \x1b[90m' + clientIp + '\x1b[0m. You may consider blocking this user.');
|
logWarn(`Remote tuner shutdown attempted by \x1b[90m${clientIp}\x1b[0m. You may consider blocking this user.`);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(command.includes('\'')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(command.startsWith('T')) {
|
|
||||||
let tuneFreq = Number(command.slice(1)) / 1000;
|
|
||||||
|
|
||||||
if(serverConfig.webserver.tuningLimit === true && (tuneFreq < serverConfig.webserver.tuningLowerLimit || tuneFreq > serverConfig.webserver.tuningUpperLimit) || isNaN(tuneFreq)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if((serverConfig.publicTuner === true) || (request.session && request.session.isTuneAuthenticated === true && serverConfig.xdrd.wirelessConnection)) {
|
if (command.includes("'")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(serverConfig.lockToAdmin === true) {
|
if (command.startsWith('w') && request.session.isAdminAuthenticated) {
|
||||||
if(request.session && request.session.isAdminAuthenticated === true) {
|
switch (command) {
|
||||||
serverConfig.xdrd.wirelessConnection === true ? client.write(command + "\n") : serialport.write(command + "\n");
|
case 'wL1':
|
||||||
} else {
|
serverConfig.lockToAdmin = true;
|
||||||
return;
|
break;
|
||||||
|
case 'wL0':
|
||||||
|
serverConfig.lockToAdmin = false;
|
||||||
|
break;
|
||||||
|
case 'wT0':
|
||||||
|
serverConfig.publicTuner = true;
|
||||||
|
break;
|
||||||
|
case 'wT1':
|
||||||
|
serverConfig.publicTuner = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
serverConfig.xdrd.wirelessConnection === true ? client.write(command + "\n") : serialport.write(command + "\n");
|
|
||||||
}
|
if (command.startsWith('T')) {
|
||||||
|
const tuneFreq = Number(command.slice(1)) / 1000;
|
||||||
|
const { tuningLimit, tuningLowerLimit, tuningUpperLimit } = serverConfig.webserver;
|
||||||
|
|
||||||
|
if (tuningLimit && (tuneFreq < tuningLowerLimit || tuneFreq > tuningUpperLimit) || isNaN(tuneFreq)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { isAdminAuthenticated, isTuneAuthenticated } = request.session || {};
|
||||||
|
const { wirelessConnection } = serverConfig.xdrd;
|
||||||
|
|
||||||
|
if ((serverConfig.publicTuner || (isTuneAuthenticated && wirelessConnection)) &&
|
||||||
|
(!serverConfig.lockToAdmin || isAdminAuthenticated)) {
|
||||||
|
const output = serverConfig.xdrd.wirelessConnection ? client : serialport;
|
||||||
|
output.write(`${command}\n`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
ws.on('close', (code, reason) => {
|
ws.on('close', (code, reason) => {
|
||||||
currentUsers--;
|
currentUsers--;
|
||||||
dataHandler.showOnlineUsers(currentUsers);
|
dataHandler.showOnlineUsers(currentUsers);
|
||||||
@@ -683,7 +695,6 @@ wss.on('connection', (ws, request) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// CHAT WEBSOCKET BLOCK
|
// CHAT WEBSOCKET BLOCK
|
||||||
// Assuming chatWss is your WebSocket server instance
|
|
||||||
// Initialize an array to store chat messages
|
// Initialize an array to store chat messages
|
||||||
let chatHistory = [];
|
let chatHistory = [];
|
||||||
|
|
||||||
@@ -713,22 +724,20 @@ chatWss.on('connection', (ws, request) => {
|
|||||||
messageData.time = `${hours}:${minutes}`; // Adding current time to the message object in hours:minutes format
|
messageData.time = `${hours}:${minutes}`; // Adding current time to the message object in hours:minutes format
|
||||||
|
|
||||||
if (serverConfig.webserver.banlist?.includes(clientIp)) {
|
if (serverConfig.webserver.banlist?.includes(clientIp)) {
|
||||||
return; // Do not proceed further if banned
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(request.session.isAdminAuthenticated === true) {
|
if(request.session.isAdminAuthenticated === true) {
|
||||||
messageData.admin = true;
|
messageData.admin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit message length to 255 characters
|
|
||||||
if (messageData.message.length > 255) {
|
if (messageData.message.length > 255) {
|
||||||
messageData.message = messageData.message.substring(0, 255);
|
messageData.message = messageData.message.substring(0, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the new message to chat history and keep only the latest 50 messages
|
|
||||||
chatHistory.push(messageData);
|
chatHistory.push(messageData);
|
||||||
if (chatHistory.length > 50) {
|
if (chatHistory.length > 50) {
|
||||||
chatHistory.shift(); // Remove the oldest message if the history exceeds 50 messages
|
chatHistory.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
const modifiedMessage = JSON.stringify(messageData);
|
const modifiedMessage = JSON.stringify(messageData);
|
||||||
|
|||||||
186
package-lock.json
generated
186
package-lock.json
generated
@@ -1,29 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name": "fm-dx-webserver",
|
"name": "fm-dx-webserver",
|
||||||
"version": "1.1.3",
|
"version": "1.1.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "fm-dx-webserver",
|
"name": "fm-dx-webserver",
|
||||||
"version": "1.1.3",
|
"version": "1.1.5",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/node-pre-gyp": "^1.0.11",
|
"@mapbox/node-pre-gyp": "1.0.11",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "1.20.2",
|
||||||
"command-exists-promise": "^2.0.2",
|
"command-exists-promise": "2.0.2",
|
||||||
"ejs": "^3.1.9",
|
"ejs": "3.1.9",
|
||||||
"express": "4.18.2",
|
"express": "4.18.3",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "1.18.0",
|
||||||
"http": "^0.0.1-security",
|
"http": "0.0.1-security",
|
||||||
"http-proxy": "^1.18.1",
|
"http-proxy": "1.18.1",
|
||||||
"https": "1.0.0",
|
"https": "1.0.0",
|
||||||
"koffi": "2.7.2",
|
"koffi": "2.7.2",
|
||||||
"net": "1.0.2",
|
"net": "1.0.2",
|
||||||
"serialport": "^12.0.0",
|
"serialport": "12.0.0",
|
||||||
"websocket": "1.0.34",
|
"wrtc": "0.4.7",
|
||||||
"wrtc": "^0.4.7",
|
"ws": "8.14.2"
|
||||||
"ws": "^8.14.2"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mapbox/node-pre-gyp": {
|
"node_modules/@mapbox/node-pre-gyp": {
|
||||||
@@ -447,6 +446,8 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
|
||||||
"integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
|
"integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-gyp-build": "^4.3.0"
|
"node-gyp-build": "^4.3.0"
|
||||||
},
|
},
|
||||||
@@ -572,15 +573,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||||
},
|
},
|
||||||
"node_modules/d": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
|
|
||||||
"dependencies": {
|
|
||||||
"es5-ext": "^0.10.50",
|
|
||||||
"type": "^1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
@@ -674,39 +666,6 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/es5-ext": {
|
|
||||||
"version": "0.10.62",
|
|
||||||
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
|
|
||||||
"integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"dependencies": {
|
|
||||||
"es6-iterator": "^2.0.3",
|
|
||||||
"es6-symbol": "^3.1.3",
|
|
||||||
"next-tick": "^1.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/es6-iterator": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
|
|
||||||
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
|
|
||||||
"dependencies": {
|
|
||||||
"d": "1",
|
|
||||||
"es5-ext": "^0.10.35",
|
|
||||||
"es6-symbol": "^3.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/es6-symbol": {
|
|
||||||
"version": "3.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
|
|
||||||
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
|
|
||||||
"dependencies": {
|
|
||||||
"d": "^1.0.1",
|
|
||||||
"ext": "^1.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/escape-html": {
|
"node_modules/escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
@@ -726,13 +685,13 @@
|
|||||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||||
},
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.18.2",
|
"version": "4.18.3",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz",
|
||||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
"integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "~1.3.8",
|
"accepts": "~1.3.8",
|
||||||
"array-flatten": "1.1.1",
|
"array-flatten": "1.1.1",
|
||||||
"body-parser": "1.20.1",
|
"body-parser": "1.20.2",
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "0.5.4",
|
||||||
"content-type": "~1.0.4",
|
"content-type": "~1.0.4",
|
||||||
"cookie": "0.5.0",
|
"cookie": "0.5.0",
|
||||||
@@ -797,56 +756,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
|
||||||
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="
|
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="
|
||||||
},
|
},
|
||||||
"node_modules/express/node_modules/body-parser": {
|
|
||||||
"version": "1.20.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
|
||||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
|
||||||
"dependencies": {
|
|
||||||
"bytes": "3.1.2",
|
|
||||||
"content-type": "~1.0.4",
|
|
||||||
"debug": "2.6.9",
|
|
||||||
"depd": "2.0.0",
|
|
||||||
"destroy": "1.2.0",
|
|
||||||
"http-errors": "2.0.0",
|
|
||||||
"iconv-lite": "0.4.24",
|
|
||||||
"on-finished": "2.4.1",
|
|
||||||
"qs": "6.11.0",
|
|
||||||
"raw-body": "2.5.1",
|
|
||||||
"type-is": "~1.6.18",
|
|
||||||
"unpipe": "1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8",
|
|
||||||
"npm": "1.2.8000 || >= 1.4.16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/express/node_modules/raw-body": {
|
|
||||||
"version": "2.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
|
||||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
|
||||||
"dependencies": {
|
|
||||||
"bytes": "3.1.2",
|
|
||||||
"http-errors": "2.0.0",
|
|
||||||
"iconv-lite": "0.4.24",
|
|
||||||
"unpipe": "1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ext": {
|
|
||||||
"version": "1.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
|
|
||||||
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
|
|
||||||
"dependencies": {
|
|
||||||
"type": "^2.7.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ext/node_modules/type": {
|
|
||||||
"version": "2.7.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
|
|
||||||
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
|
|
||||||
},
|
|
||||||
"node_modules/filelist": {
|
"node_modules/filelist": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
||||||
@@ -1193,11 +1102,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-typedarray": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
|
|
||||||
},
|
|
||||||
"node_modules/jake": {
|
"node_modules/jake": {
|
||||||
"version": "10.8.7",
|
"version": "10.8.7",
|
||||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
|
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
|
||||||
@@ -1376,11 +1280,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz",
|
||||||
"integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ=="
|
"integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ=="
|
||||||
},
|
},
|
||||||
"node_modules/next-tick": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
|
|
||||||
},
|
|
||||||
"node_modules/node-addon-api": {
|
"node_modules/node-addon-api": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz",
|
||||||
@@ -1409,6 +1308,8 @@
|
|||||||
"version": "4.6.1",
|
"version": "4.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz",
|
||||||
"integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==",
|
"integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==",
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"node-gyp-build": "bin.js",
|
"node-gyp-build": "bin.js",
|
||||||
"node-gyp-build-optional": "optional.js",
|
"node-gyp-build-optional": "optional.js",
|
||||||
@@ -1617,9 +1518,9 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.5.4",
|
"version": "7.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lru-cache": "^6.0.0"
|
"lru-cache": "^6.0.0"
|
||||||
},
|
},
|
||||||
@@ -1842,11 +1743,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||||
},
|
},
|
||||||
"node_modules/type": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
|
|
||||||
},
|
|
||||||
"node_modules/type-is": {
|
"node_modules/type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
@@ -1859,14 +1755,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typedarray-to-buffer": {
|
|
||||||
"version": "3.1.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
|
||||||
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"is-typedarray": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/uid-safe": {
|
"node_modules/uid-safe": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||||
@@ -1891,6 +1779,8 @@
|
|||||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
|
||||||
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
|
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-gyp-build": "^4.3.0"
|
"node-gyp-build": "^4.3.0"
|
||||||
},
|
},
|
||||||
@@ -1925,22 +1815,6 @@
|
|||||||
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
|
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/websocket": {
|
|
||||||
"version": "1.0.34",
|
|
||||||
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
|
|
||||||
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"bufferutil": "^4.0.1",
|
|
||||||
"debug": "^2.2.0",
|
|
||||||
"es5-ext": "^0.10.50",
|
|
||||||
"typedarray-to-buffer": "^3.1.5",
|
|
||||||
"utf-8-validate": "^5.0.2",
|
|
||||||
"yaeti": "^0.0.6"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/whatwg-url": {
|
"node_modules/whatwg-url": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
@@ -2006,14 +1880,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yaeti": {
|
|
||||||
"version": "0.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
|
|
||||||
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.32"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
|||||||
25
package.json
25
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fm-dx-webserver",
|
"name": "fm-dx-webserver",
|
||||||
"version": "1.1.4",
|
"version": "1.1.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -12,20 +12,19 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/node-pre-gyp": "^1.0.11",
|
"@mapbox/node-pre-gyp": "1.0.11",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "1.20.2",
|
||||||
"command-exists-promise": "^2.0.2",
|
"command-exists-promise": "2.0.2",
|
||||||
"ejs": "^3.1.9",
|
"ejs": "3.1.9",
|
||||||
"express": "4.18.2",
|
"express": "4.18.3",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "1.18.0",
|
||||||
"http": "^0.0.1-security",
|
"http": "0.0.1-security",
|
||||||
"http-proxy": "^1.18.1",
|
"http-proxy": "1.18.1",
|
||||||
"https": "1.0.0",
|
"https": "1.0.0",
|
||||||
"koffi": "2.7.2",
|
"koffi": "2.7.2",
|
||||||
"net": "1.0.2",
|
"net": "1.0.2",
|
||||||
"serialport": "^12.0.0",
|
"serialport": "12.0.0",
|
||||||
"websocket": "1.0.34",
|
"wrtc": "0.4.7",
|
||||||
"wrtc": "^0.4.7",
|
"ws": "8.14.2"
|
||||||
"ws": "^8.14.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function enableAudioStream() {
|
|||||||
ffmpegCommand = `${flags} -f dshow -audio_buffer_size 50 -i audio="${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node stream/3las.server.js -port ${serverConfig.webserver.webserverPort + 10} -samplerate 48000 -channels ${serverConfig.audio.audioChannels}`;
|
ffmpegCommand = `${flags} -f dshow -audio_buffer_size 50 -i audio="${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node stream/3las.server.js -port ${serverConfig.webserver.webserverPort + 10} -samplerate 48000 -channels ${serverConfig.audio.audioChannels}`;
|
||||||
} else {
|
} else {
|
||||||
// Linux
|
// Linux
|
||||||
ffmpegCommand = `${flags} -f alsa -i "${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node stream/3las.server.js -port ${serverConfig.webserver.webserverPort + 10} -samplerate 48000 -channels ${serverConfig.audio.audioChannels}`;
|
ffmpegCommand = `${flags} -f alsa -i "${serverConfig.audio.softwareMode && serverConfig.audio.softwareMode == true ? 'plug' : ''}${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node stream/3las.server.js -port ${serverConfig.webserver.webserverPort + 10} -samplerate 48000 -channels ${serverConfig.audio.audioChannels}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleCmd.logInfo("Using audio device: " + serverConfig.audio.audioDevice);
|
consoleCmd.logInfo("Using audio device: " + serverConfig.audio.audioDevice);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ h4 {
|
|||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
padding: 5px 25px;
|
padding: 5px 25px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
opacity:var(--color-main);
|
opacity: 0;
|
||||||
transition: opacity 0.3s ease-in-out;
|
transition: opacity 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +248,42 @@ label {
|
|||||||
opacity: 0; /* Make the overlay invisible */
|
opacity: 0; /* Make the overlay invisible */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-quick-dashboard {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: -96px;
|
||||||
|
width: 96px;
|
||||||
|
height: 286px;
|
||||||
|
background-color: var(--color-2);
|
||||||
|
margin: auto 0;
|
||||||
|
border-radius: 30px;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-quick-dashboard .icon {
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
margin: 10px auto;
|
||||||
|
color: var(--color-1);
|
||||||
|
background-color: var(--color-3);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 24px;
|
||||||
|
border-radius: 10px;
|
||||||
|
transition: 0.3s ease-in-out background-color;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-quick-dashboard .icon.active {
|
||||||
|
background-color: var(--color-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-quick-dashboard .icon:hover {
|
||||||
|
background-color: var(--color-5);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
canvas, #flags-container {
|
canvas, #flags-container {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -52,8 +52,10 @@
|
|||||||
<audio id="audioTag"></audio>
|
<audio id="audioTag"></audio>
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
<div class="panel-100 no-bg tuner-info">
|
<div class="panel-100 no-bg tuner-info">
|
||||||
<h1 id="tuner-name"><%= tunerName %> <% if (!publicTuner) { %><i class="fa-solid fa-key pointer" title="Only people with tune password can tune."></i>
|
<h1 id="tuner-name"><%= tunerName %>
|
||||||
<% } else if (tunerLock) { %><i class="fa-solid fa-lock pointer" title="Tuner is currently locked to admin."></i><% } %>
|
<% if (!publicTuner) { %><i class="fa-solid fa-key pointer tooltip" data-tooltip="Only people with tune password can tune."></i>
|
||||||
|
<% } if (tunerLock) { %><i class="fa-solid fa-lock pointer tooltip" data-tooltip="Tuner is currently locked to admin."></i>
|
||||||
|
<% } %>
|
||||||
</h1>
|
</h1>
|
||||||
<p id="tuner-desc">
|
<p id="tuner-desc">
|
||||||
<%- tunerDesc %>
|
<%- tunerDesc %>
|
||||||
@@ -74,7 +76,7 @@
|
|||||||
<div class="panel-10 no-bg h-100 m-0 m-right-20 hide-phone" style="width: 100px;margin-right: 20px !important;">
|
<div class="panel-10 no-bg h-100 m-0 m-right-20 hide-phone" style="width: 100px;margin-right: 20px !important;">
|
||||||
<button class="playbutton" aria-label="Play / Stop Button"><i class="fa-solid fa-play fa-lg"></i></button>
|
<button class="playbutton" aria-label="Play / Stop Button"><i class="fa-solid fa-play fa-lg"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-100 m-0 hover-brighten flex-center" id="ps-container" style="height: 90px;" data-tooltip="Clicking on the RDS PS will copy the RDS info into the clipboard.">
|
<div class="panel-100 m-0 hover-brighten flex-center tooltip" id="ps-container" style="height: 90px;" data-tooltip="Clicking on the RDS PS will copy the RDS info into the clipboard.">
|
||||||
<span class="text-big" id="data-ps"></span>
|
<span class="text-big" id="data-ps"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,7 +93,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<span id="stereo-container" class="pointer" style="position: relative;">
|
<span id="stereo-container" class="pointer" style="position: relative;">
|
||||||
<span style="margin-left: 20px;" class="data-st">ST</span>
|
<span style="margin-left: 20px;" class="data-st">ST</span>
|
||||||
<span class="overlay" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
|
<span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
|
||||||
</span>
|
</span>
|
||||||
<span style="margin-left: 15px;" class="data-ms">MS</span>
|
<span style="margin-left: 15px;" class="data-ms">MS</span>
|
||||||
</h3>
|
</h3>
|
||||||
@@ -99,7 +101,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<div class="panel-33 hover-brighten" id="pi-code-container" data-tooltip="Clicking on the PI code will show the current station on a map.">
|
<div class="panel-33 hover-brighten tooltip" id="pi-code-container" data-tooltip="Clicking on the PI code will show the current station on a map.">
|
||||||
<h2>PI CODE</h2>
|
<h2>PI CODE</h2>
|
||||||
<span id="data-pi" class="text-big text-uppercase"></span>
|
<span id="data-pi" class="text-big text-uppercase"></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -144,12 +146,12 @@
|
|||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<div class="panel-100 no-bg h-100 m-0 button-eq">
|
<div class="panel-100 no-bg h-100 m-0 button-eq">
|
||||||
<% if (device == 'tef') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" aria-label="EQ Filter" data-tooltip="<strong>The cEQ filter can reduce bandwidth below 56 KHz.</strong><br><br>Useful for weak stations next to strong ones,<br>although it may pick up more interference."><span class="text-bold">cEQ</span></button><% } %>
|
<% if (device == 'tef') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" class="tooltip" aria-label="EQ Filter" data-tooltip="<strong>The cEQ filter can reduce bandwidth below 56 KHz.</strong><br><br>Useful for weak stations next to strong ones,<br>although it may pick up more interference."><span class="text-bold">cEQ</span></button><% } %>
|
||||||
<% if (device == 'xdr') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" aria-label="RF+ Filter" data-tooltip="<strong>The RF+ filter increases gain by 5dB</strong>"><span class="text-bold">RF+</span></button><% } %>
|
<% if (device == 'xdr') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" class="tooltip" aria-label="RF+ Filter" data-tooltip="<strong>The RF+ filter increases gain by 5dB</strong>"><span class="text-bold">RF+</span></button><% } %>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-100 no-bg h-100 m-0 button-ims">
|
<div class="panel-100 no-bg h-100 m-0 button-ims">
|
||||||
<% if (device == 'tef') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" aria-label="iMS + Filter" data-tooltip="<strong>The iMS filter reduces multipath audio artifacts.</strong><br><br>It's recommended to leave it on most of the time."><span class="text-bold">iMS</span></button><% } %>
|
<% if (device == 'tef') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" class="tooltip" aria-label="iMS + Filter" data-tooltip="<strong>The iMS filter reduces multipath audio artifacts.</strong><br><br>It's recommended to leave it on most of the time."><span class="text-bold">iMS</span></button><% } %>
|
||||||
<% if (device == 'xdr') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" aria-label="IF+ Filter" data-tooltip="<strong>The IF+ filter increases gain by 6dB</strong>"><span class="text-bold">IF+</span></button><% } %>
|
<% if (device == 'xdr') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" class="tooltip" aria-label="IF+ Filter" data-tooltip="<strong>The IF+ filter increases gain by 6dB</strong>"><span class="text-bold">IF+</span></button><% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -173,7 +175,7 @@
|
|||||||
<hr class="hide-desktop">
|
<hr class="hide-desktop">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-33 hover-brighten" data-tooltip="This panel contains the current TX info when RDS is loaded.<br><strong>Clicking on this panel copies the info into the clipboard.</strong>">
|
<div class="panel-33 hover-brighten tooltip" data-tooltip="This panel contains the current TX info when RDS is loaded.<br><strong>Clicking on this panel copies the info into the clipboard.</strong>">
|
||||||
<div id="data-station-container">
|
<div id="data-station-container">
|
||||||
<h2 style="margin-top: 0;" class="mb-0">
|
<h2 style="margin-top: 0;" class="mb-0">
|
||||||
<span id="data-station-name"></span>
|
<span id="data-station-name"></span>
|
||||||
@@ -228,6 +230,20 @@
|
|||||||
<% } %>
|
<% } %>
|
||||||
<button id="users-online-container" class="hide-phone" aria-label="Online users"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
|
<button id="users-online-container" class="hide-phone" aria-label="Online users"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
|
||||||
|
|
||||||
|
<% if (isAdminAuthenticated) { %>
|
||||||
|
<div class="admin-quick-dashboard hide-phone">
|
||||||
|
<div class="icon tooltip <% if (tunerLock) { %>active<% } %>" id="dashboard-lock-admin" onClick="toggleAdminLock()" data-tooltip="Toggle admin lock<br>Lasts until restart">
|
||||||
|
<i class="fa-solid fa-lock"></i>
|
||||||
|
</div>
|
||||||
|
<div class="icon tooltip <% if (!publicTuner) { %>active<% } %>" id="dashboard-lock-tune" onClick="togglePasswordLock()" data-tooltip="Toggle password lock<br>Lasts until restart">
|
||||||
|
<i class="fa-solid fa-key"></i>
|
||||||
|
</div>
|
||||||
|
<div class="icon tooltip" data-tooltip="Go to admin menu" onClick="window.open('./setup', '_blank').focus();">
|
||||||
|
<i class="fa-solid fa-user"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<div id="myModal" class="modal">
|
<div id="myModal" class="modal">
|
||||||
<div class="modal-panel">
|
<div class="modal-panel">
|
||||||
<div class="flex-container flex-phone" style="height: calc(100% - 100px)">
|
<div class="flex-container flex-phone" style="height: calc(100% - 100px)">
|
||||||
@@ -285,7 +301,7 @@
|
|||||||
|
|
||||||
<% if (isAdminAuthenticated) { %>
|
<% if (isAdminAuthenticated) { %>
|
||||||
<p>You are logged in as an adminstrator.<br>
|
<p>You are logged in as an adminstrator.<br>
|
||||||
<a href="./setup">Setup</a> • <a class="logout-link" href="#">Logout</a>
|
<a href="./setup" target="_blank">Setup</a> • <a class="logout-link" href="#">Logout</a>
|
||||||
</p>
|
</p>
|
||||||
<% } else if (isTuneAuthenticated) { %>
|
<% } else if (isTuneAuthenticated) { %>
|
||||||
<p>You are logged in and can control the receiver.<br><a class="logout-link" href="#">Logout</a></p>
|
<p>You are logged in and can control the receiver.<br><a class="logout-link" href="#">Logout</a></p>
|
||||||
@@ -360,9 +376,5 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/webserver.js"></script>
|
<script src="js/webserver.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/screenshot-capture/2.0.0/screenshot-capture.min.js"></script>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ function submitData() {
|
|||||||
return $(this).text() === $('#device-type').val();
|
return $(this).text() === $('#device-type').val();
|
||||||
}).data('value') || "tef");
|
}).data('value') || "tef");
|
||||||
|
|
||||||
|
const softwareMode = $('#audio-software-mode').is("checked") || false;
|
||||||
|
|
||||||
const tunerName = $('#webserver-name').val() || 'FM Tuner';
|
const tunerName = $('#webserver-name').val() || 'FM Tuner';
|
||||||
const tunerDesc = $('#webserver-desc').val() || 'Default FM tuner description';
|
const tunerDesc = $('#webserver-desc').val() || 'Default FM tuner description';
|
||||||
const broadcastTuner = $("#broadcast-tuner").is(":checked");
|
const broadcastTuner = $("#broadcast-tuner").is(":checked");
|
||||||
@@ -84,6 +86,7 @@ function submitData() {
|
|||||||
audioDevice,
|
audioDevice,
|
||||||
audioChannels,
|
audioChannels,
|
||||||
audioBitrate,
|
audioBitrate,
|
||||||
|
softwareMode,
|
||||||
},
|
},
|
||||||
identification: {
|
identification: {
|
||||||
tunerName,
|
tunerName,
|
||||||
@@ -202,6 +205,8 @@ function submitData() {
|
|||||||
$("#audio-quality").val(selectedQuality.text());
|
$("#audio-quality").val(selectedQuality.text());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#audio-software-switch').prop("checked", data.audio.softwareMode || false);
|
||||||
|
|
||||||
$('#webserver-name').val(data.identification.tunerName);
|
$('#webserver-name').val(data.identification.tunerName);
|
||||||
$('#webserver-desc').val(data.identification.tunerDesc);
|
$('#webserver-desc').val(data.identification.tunerDesc);
|
||||||
$("#broadcast-tuner").prop("checked", data.identification.broadcastTuner);
|
$("#broadcast-tuner").prop("checked", data.identification.broadcastTuner);
|
||||||
|
|||||||
@@ -28,6 +28,21 @@ const usa_programmes = [
|
|||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var canvas = $('#signal-canvas')[0];
|
var canvas = $('#signal-canvas')[0];
|
||||||
|
|
||||||
|
var $panel = $('.admin-quick-dashboard');
|
||||||
|
var panelWidth = $panel.outerWidth();
|
||||||
|
|
||||||
|
$(document).mousemove(function(e) {
|
||||||
|
var mouseX = e.pageX;
|
||||||
|
var panelLeft = parseInt($panel.css('left'));
|
||||||
|
|
||||||
|
if (mouseX <= 10 || (panelLeft === 4 && mouseX <= 100)) {
|
||||||
|
$panel.css('left', '4px');
|
||||||
|
} else {
|
||||||
|
$panel.css('left', -panelWidth);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
canvas.width = canvas.parentElement.clientWidth;
|
canvas.width = canvas.parentElement.clientWidth;
|
||||||
canvas.height = canvas.parentElement.clientHeight;
|
canvas.height = canvas.parentElement.clientHeight;
|
||||||
|
|
||||||
@@ -49,9 +64,9 @@ $(document).ready(function () {
|
|||||||
const textInput = $('#commandinput');
|
const textInput = $('#commandinput');
|
||||||
|
|
||||||
textInput.on('change', function (event) {
|
textInput.on('change', function (event) {
|
||||||
const inputValue = textInput.val();
|
const inputValue = Number(textInput.val());
|
||||||
// Check if the user agent contains 'iPhone'
|
// Check if the user agent contains 'iPhone'
|
||||||
if (/iPhone/i.test(navigator.userAgent) && socket.readyState === WebSocket.OPEN) {
|
if (/iPhone/i.test(navigator.userAgent)) {
|
||||||
socket.send("T" + (inputValue * 1000));
|
socket.send("T" + (inputValue * 1000));
|
||||||
// Clear the input field if needed
|
// Clear the input field if needed
|
||||||
textInput.val('');
|
textInput.val('');
|
||||||
@@ -384,26 +399,7 @@ function checkKey(e) {
|
|||||||
case 82: // RDS Reset (R key)
|
case 82: // RDS Reset (R key)
|
||||||
tuneTo(Number(currentFreq));
|
tuneTo(Number(currentFreq));
|
||||||
break;
|
break;
|
||||||
case 83: // Screenshot (S key)
|
case 83: // Screenshot (S key)
|
||||||
screenshotCapture.capture().then(function (dataUrl) {
|
|
||||||
// Create an input element to hold the data URL temporarily
|
|
||||||
var aux = $('<input>').attr({
|
|
||||||
type: 'text',
|
|
||||||
value: dataUrl
|
|
||||||
});
|
|
||||||
|
|
||||||
// Append the input element to the body, select its contents, and copy them to the clipboard
|
|
||||||
$('body').append(aux);
|
|
||||||
aux.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
aux.remove();
|
|
||||||
|
|
||||||
// Alert the user that the screenshot has been copied to the clipboard
|
|
||||||
alert('Screenshot copied to clipboard!');
|
|
||||||
}).catch(function (error) {
|
|
||||||
console.error('Error capturing screenshot:', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 38:
|
case 38:
|
||||||
socket.send("T" + (Math.round(currentFreq*1000) + ((currentFreq > 30) ? 10 : 1)));
|
socket.send("T" + (Math.round(currentFreq*1000) + ((currentFreq > 30) ? 10 : 1)));
|
||||||
@@ -758,19 +754,51 @@ function toggleForcedStereo() {
|
|||||||
socket.send(message);
|
socket.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleAdminLock() {
|
||||||
|
let $adminLockButton = $('#dashboard-lock-admin');
|
||||||
|
|
||||||
|
if($adminLockButton.hasClass('active')) {
|
||||||
|
socket.send('wL0');
|
||||||
|
$adminLockButton.removeClass('active');
|
||||||
|
} else {
|
||||||
|
socket.send('wL1');
|
||||||
|
$adminLockButton.addClass('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function togglePasswordLock() {
|
||||||
|
let $passwordLockButton = $('#dashboard-lock-tune');
|
||||||
|
|
||||||
|
if($passwordLockButton.hasClass('active')) {
|
||||||
|
socket.send('wT0');
|
||||||
|
$passwordLockButton.removeClass('active');
|
||||||
|
} else {
|
||||||
|
socket.send('wT1');
|
||||||
|
$passwordLockButton.addClass('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initTooltips() {
|
function initTooltips() {
|
||||||
$('[data-tooltip]').hover(function(e){
|
$('.tooltip').hover(function(e){
|
||||||
var tooltipText = $(this).data('tooltip');
|
var tooltipText = $(this).data('tooltip');
|
||||||
var tooltip = $('<div class="tooltiptext"></div>').html(tooltipText);
|
|
||||||
$('body').append(tooltip);
|
// Add a delay of 500 milliseconds before creating and appending the tooltip
|
||||||
|
$(this).data('timeout', setTimeout(() => {
|
||||||
|
var tooltip = $('<div class="tooltiptext"></div>').html(tooltipText);
|
||||||
|
$('body').append(tooltip);
|
||||||
|
|
||||||
var tooltipWidth = tooltip.outerWidth();
|
var posX = e.pageX;
|
||||||
var tooltipHeight = tooltip.outerHeight();
|
var posY = e.pageY;
|
||||||
var posX = e.pageX - tooltipWidth / 2;
|
|
||||||
var posY = e.pageY - tooltipHeight - 10;
|
|
||||||
|
|
||||||
tooltip.css({ top: posY, left: posX, opacity: 0.9 });
|
var tooltipWidth = tooltip.outerWidth();
|
||||||
|
var tooltipHeight = tooltip.outerHeight();
|
||||||
|
posX -= tooltipWidth / 2;
|
||||||
|
posY -= tooltipHeight + 10;
|
||||||
|
tooltip.css({ top: posY, left: posX, opacity: 1 }); // Set opacity to 1
|
||||||
|
}, 500));
|
||||||
}, function() {
|
}, function() {
|
||||||
|
// Clear the timeout if the mouse leaves before the delay completes
|
||||||
|
clearTimeout($(this).data('timeout'));
|
||||||
$('.tooltiptext').remove();
|
$('.tooltiptext').remove();
|
||||||
}).mousemove(function(e){
|
}).mousemove(function(e){
|
||||||
var tooltipWidth = $('.tooltiptext').outerWidth();
|
var tooltipWidth = $('.tooltiptext').outerWidth();
|
||||||
@@ -780,4 +808,4 @@ function initTooltips() {
|
|||||||
|
|
||||||
$('.tooltiptext').css({ top: posY, left: posX });
|
$('.tooltiptext').css({ top: posY, left: posX });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ 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();
|
||||||
var formattedDate = day + '/' + month + '/' + year;
|
var formattedDate = day + '/' + month + '/' + year;
|
||||||
var currentVersion = 'v1.1.4 [' + formattedDate + ']';
|
var currentVersion = 'v1.1.5 [' + formattedDate + ']';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -237,6 +237,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group checkbox bottom-20">
|
||||||
|
<input type="checkbox" id="audio-software-switch">
|
||||||
|
<label for="audio-software-switch">ALSA software mode (plughw) - LINUX ONLY</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -352,6 +357,7 @@
|
|||||||
<li class="option" data-value="tef">TEF668x / TEA685x</li>
|
<li class="option" data-value="tef">TEF668x / TEA685x</li>
|
||||||
<li class="option" data-value="xdr">XDR (F1HD / S10HDiP)</li>
|
<li class="option" data-value="xdr">XDR (F1HD / S10HDiP)</li>
|
||||||
<li class="option" data-value="sdr">SDR (RTL-SDR / AirSpy)</li>
|
<li class="option" data-value="sdr">SDR (RTL-SDR / AirSpy)</li>
|
||||||
|
<li class="option" data-value="sdr">Other</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
<li class="option" data-value="tef">TEF668x / TEA685x</li>
|
<li class="option" data-value="tef">TEF668x / TEA685x</li>
|
||||||
<li class="option" data-value="xdr">XDR (F1HD / S10HDiP)</li>
|
<li class="option" data-value="xdr">XDR (F1HD / S10HDiP)</li>
|
||||||
<li class="option" data-value="sdr">SDR (RTL-SDR / AirSpy)</li>
|
<li class="option" data-value="sdr">SDR (RTL-SDR / AirSpy)</li>
|
||||||
|
<li class="option" data-value="other">Other</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user