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
Compare commits
4 Commits
d0a26d2346
...
03ff93cd39
| Author | SHA1 | Date | |
|---|---|---|---|
|
03ff93cd39
|
|||
|
ebe9c8bbe8
|
|||
|
df215edf9e
|
|||
|
410c39a6b8
|
@@ -31,9 +31,7 @@ FM-DX Webserver is a cross-platform web server designed for FM DXers who want to
|
|||||||
|
|
||||||
This project utilizes these libraries:
|
This project utilizes these libraries:
|
||||||
|
|
||||||
- [3LAS](https://github.com/jojobond/3LAS) library by JoJoBond for Low Latency Audio Streaming.
|
|
||||||
- [flat-flags](https://github.com/luishdez/flat-flags) library by luishdez for RDS country flags.
|
- [flat-flags](https://github.com/luishdez/flat-flags) library by luishdez for RDS country flags.
|
||||||
- [librdsparser](https://github.com/kkonradpl/librdsparser) library by Konrad Kosmatka for RDS parsing.
|
|
||||||
|
|
||||||
All of these libraries are already bundled with the webserver.
|
All of these libraries are already bundled with the webserver.
|
||||||
|
|
||||||
|
|||||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -16,7 +16,6 @@
|
|||||||
"express-session": "1.18.2",
|
"express-session": "1.18.2",
|
||||||
"ffmpeg-static": "5.2.0",
|
"ffmpeg-static": "5.2.0",
|
||||||
"http": "0.0.1-security",
|
"http": "0.0.1-security",
|
||||||
"koffi": "2.7.2",
|
|
||||||
"net": "1.0.2",
|
"net": "1.0.2",
|
||||||
"serialport": "12.0.0",
|
"serialport": "12.0.0",
|
||||||
"ws": "8.18.1"
|
"ws": "8.18.1"
|
||||||
@@ -1181,12 +1180,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/koffi": {
|
|
||||||
"version": "2.7.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/koffi/-/koffi-2.7.2.tgz",
|
|
||||||
"integrity": "sha512-AWcsEKETQuELxK0Wq/aXDkDiNFFY41TxZQSrKm2Nd6HO/KTHeohPOOIlh2OfQnBXJbRjx5etpWt8cbqMUZo2sg==",
|
|
||||||
"hasInstallScript": true
|
|
||||||
},
|
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
"express-session": "1.18.2",
|
"express-session": "1.18.2",
|
||||||
"ffmpeg-static": "5.2.0",
|
"ffmpeg-static": "5.2.0",
|
||||||
"http": "0.0.1-security",
|
"http": "0.0.1-security",
|
||||||
"koffi": "2.7.2",
|
|
||||||
"net": "1.0.2",
|
"net": "1.0.2",
|
||||||
"serialport": "12.0.0",
|
"serialport": "12.0.0",
|
||||||
"ws": "8.18.1"
|
"ws": "8.18.1"
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ function createChatServer(storage) {
|
|||||||
storage.chatHistory.forEach((message) => {
|
storage.chatHistory.forEach((message) => {
|
||||||
const historyMessage = { ...message, history: true };
|
const historyMessage = { ...message, history: true };
|
||||||
|
|
||||||
if (!request.session?.isAdminAuthenticated) {
|
if (!request.session?.isAdminAuthenticated) delete historyMessage.ip;
|
||||||
delete historyMessage.ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
ws.send(JSON.stringify(historyMessage));
|
ws.send(JSON.stringify(historyMessage));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,7 @@ const logMessage = (type, messages, verbose = false) => {
|
|||||||
console.log(logMessage);
|
console.log(logMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type !== 'FFMPEG') {
|
if(type !== 'FFMPEG') appendLogToBuffer(logMessage);
|
||||||
appendLogToBuffer(logMessage);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const logDebug = (...messages) => logMessage('DEBUG', messages, verboseMode);
|
const logDebug = (...messages) => logMessage('DEBUG', messages, verboseMode);
|
||||||
|
|||||||
@@ -1,213 +1,8 @@
|
|||||||
/* Libraries / Imports */
|
/* Libraries / Imports */
|
||||||
const fs = require('fs');
|
const RDSDecoder = require("./rds.js");
|
||||||
const https = require('https');
|
const { serverConfig } = require('./server_config');
|
||||||
const koffi = require('koffi');
|
|
||||||
const path = require('path');
|
|
||||||
const os = require('os');
|
|
||||||
const platform = os.platform();
|
|
||||||
const cpuArchitecture = os.arch();
|
|
||||||
const { configName, serverConfig, configUpdate, configSave } = require('./server_config');
|
|
||||||
let unicode_type;
|
|
||||||
let shared_Library;
|
|
||||||
|
|
||||||
if (platform === 'win32') {
|
|
||||||
unicode_type = 'int16_t';
|
|
||||||
arch_type = (cpuArchitecture === 'x64' ? 'mingw64' : 'mingw32');
|
|
||||||
shared_Library=path.join(__dirname, "libraries", arch_type, "librdsparser.dll");
|
|
||||||
} else if (platform === 'linux') {
|
|
||||||
unicode_type = 'int32_t';
|
|
||||||
arch_type = (cpuArchitecture === 'x64' ? 'x86_64' :
|
|
||||||
(cpuArchitecture === 'ia32' ? 'x86' :
|
|
||||||
(cpuArchitecture === 'arm64' ? 'aarch64' : cpuArchitecture)));
|
|
||||||
shared_Library=path.join(__dirname, "libraries", arch_type, "librdsparser.so");
|
|
||||||
} else if (platform === 'darwin') {
|
|
||||||
unicode_type = 'int32_t';
|
|
||||||
shared_Library=path.join(__dirname, "libraries", "macos", "librdsparser.dylib");
|
|
||||||
}
|
|
||||||
|
|
||||||
const lib = koffi.load(shared_Library);
|
|
||||||
const { fetchTx } = require('./tx_search.js');
|
const { fetchTx } = require('./tx_search.js');
|
||||||
|
|
||||||
koffi.proto('void callback_pi(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_pty(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_tp(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_ta(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_ms(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_ecc(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_country(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_af(void *rds, uint32_t af, void *user_data)');
|
|
||||||
koffi.proto('void callback_ps(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_rt(void *rds, int flag, void *user_data)');
|
|
||||||
koffi.proto('void callback_ptyn(void *rds, void *user_data)');
|
|
||||||
koffi.proto('void callback_ct(void *rds, void *ct, void *user_data)');
|
|
||||||
|
|
||||||
const rdsparser = {
|
|
||||||
new: lib.func('void* rdsparser_new()'),
|
|
||||||
free: lib.func('void rdsparser_free(void *rds)'),
|
|
||||||
clear: lib.func('void rdsparser_clear(void *rds)'),
|
|
||||||
parse_string: lib.func('bool rdsparser_parse_string(void *rds, const char *input)'),
|
|
||||||
set_text_correction: lib.func('void rdsparser_set_text_correction(void *rds, uint8_t text, uint8_t type, uint8_t error)'),
|
|
||||||
set_text_progressive: lib.func('void rdsparser_set_text_progressive(void *rds, uint8_t string, uint8_t state)'),
|
|
||||||
get_pi: lib.func('int32_t rdsparser_get_pi(void *rds)'),
|
|
||||||
get_pty: lib.func('int8_t rdsparser_get_pty(void *rds)'),
|
|
||||||
get_tp: lib.func('int8_t rdsparser_get_tp(void *rds)'),
|
|
||||||
get_ta: lib.func('int8_t rdsparser_get_ta(void *rds)'),
|
|
||||||
get_ms: lib.func('int8_t rdsparser_get_ms(void *rds)'),
|
|
||||||
get_ecc: lib.func('int16_t rdsparser_get_ecc(void *rds)'),
|
|
||||||
get_country: lib.func('int rdsparser_get_country(void *rds)'),
|
|
||||||
get_ps: lib.func('void* rdsparser_get_ps(void *rds)'),
|
|
||||||
get_rt: lib.func('void* rdsparser_get_rt(void *rds, int flag)'),
|
|
||||||
get_ptyn: lib.func('void* rdsparser_get_ptyn(void *rds)'),
|
|
||||||
register_pi: lib.func('void rdsparser_register_pi(void *rds, void *cb)'),
|
|
||||||
register_pty: lib.func('void rdsparser_register_pty(void *rds, void *cb)'),
|
|
||||||
register_tp: lib.func('void rdsparser_register_tp(void *rds, void *cb)'),
|
|
||||||
register_ta: lib.func('void rdsparser_register_ta(void *rds, void *cb)'),
|
|
||||||
register_ms: lib.func('void rdsparser_register_ms(void *rds, void *cb)'),
|
|
||||||
register_ecc: lib.func('void rdsparser_register_ecc(void *rds, void *cb)'),
|
|
||||||
register_country: lib.func('void rdsparser_register_country(void *rds, void *cb)'),
|
|
||||||
register_af: lib.func('void rdsparser_register_af(void *rds, void *cb)'),
|
|
||||||
register_ps: lib.func('void rdsparser_register_ps(void *rds, void *cb)'),
|
|
||||||
register_rt: lib.func('void rdsparser_register_rt(void *rds, void *cb)'),
|
|
||||||
register_ptyn: lib.func('void rdsparser_register_ptyn(void *rds, void *cb)'),
|
|
||||||
register_ct: lib.func('void rdsparser_register_ct(void *rds, void *cb)'),
|
|
||||||
string_get_content: lib.func(unicode_type + '* rdsparser_string_get_content(void *string)'),
|
|
||||||
string_get_errors: lib.func('uint8_t* rdsparser_string_get_errors(void *string)'),
|
|
||||||
string_get_length: lib.func('uint8_t rdsparser_string_get_length(void *string)'),
|
|
||||||
ct_get_year: lib.func('uint16_t rdsparser_ct_get_year(void *ct)'),
|
|
||||||
ct_get_month: lib.func('uint8_t rdsparser_ct_get_month(void *ct)'),
|
|
||||||
ct_get_day: lib.func('uint8_t rdsparser_ct_get_day(void *ct)'),
|
|
||||||
ct_get_hour: lib.func('uint8_t rdsparser_ct_get_hour(void *ct)'),
|
|
||||||
ct_get_minute: lib.func('uint8_t rdsparser_ct_get_minute(void *ct)'),
|
|
||||||
ct_get_offset: lib.func('int8_t rdsparser_ct_get_offset(void *ct)'),
|
|
||||||
pty_lookup_short: lib.func('const char* rdsparser_pty_lookup_short(int8_t pty, bool rbds)'),
|
|
||||||
pty_lookup_long: lib.func('const char* rdsparser_pty_lookup_long(int8_t pty, bool rbds)'),
|
|
||||||
country_lookup_name: lib.func('const char* rdsparser_country_lookup_name(int country)'),
|
|
||||||
country_lookup_iso: lib.func('const char* rdsparser_country_lookup_iso(int country)')
|
|
||||||
}
|
|
||||||
|
|
||||||
const callbacks = {
|
|
||||||
pi: koffi.register(rds => (
|
|
||||||
value = rdsparser.get_pi(rds)
|
|
||||||
//console.log('PI: ' + value.toString(16).toUpperCase())
|
|
||||||
), 'callback_pi*'),
|
|
||||||
|
|
||||||
pty: koffi.register(rds => (
|
|
||||||
value = rdsparser.get_pty(rds),
|
|
||||||
dataToSend.pty = value
|
|
||||||
), 'callback_pty*'),
|
|
||||||
|
|
||||||
tp: koffi.register(rds => (
|
|
||||||
value = rdsparser.get_tp(rds),
|
|
||||||
dataToSend.tp = value
|
|
||||||
), 'callback_tp*'),
|
|
||||||
|
|
||||||
ta: koffi.register(rds => (
|
|
||||||
value = rdsparser.get_ta(rds),
|
|
||||||
dataToSend.ta = value
|
|
||||||
), 'callback_ta*'),
|
|
||||||
|
|
||||||
ms: koffi.register(rds => (
|
|
||||||
value = rdsparser.get_ms(rds),
|
|
||||||
dataToSend.ms = value
|
|
||||||
), 'callback_ms*'),
|
|
||||||
|
|
||||||
af: koffi.register((rds, value) => (
|
|
||||||
dataToSend.af.push(value)
|
|
||||||
), 'callback_af*'),
|
|
||||||
|
|
||||||
ecc: koffi.register(rds => (
|
|
||||||
value = rdsparser.get_ecc(rds),
|
|
||||||
dataToSend.ecc = value
|
|
||||||
), 'callback_ecc*'),
|
|
||||||
|
|
||||||
country: koffi.register(rds => (
|
|
||||||
value = rdsparser.get_country(rds),
|
|
||||||
display = rdsparser.country_lookup_name(value),
|
|
||||||
iso = rdsparser.country_lookup_iso(value),
|
|
||||||
dataToSend.country_name = display,
|
|
||||||
dataToSend.country_iso = iso
|
|
||||||
), 'callback_country*'),
|
|
||||||
|
|
||||||
ps: koffi.register(rds => (
|
|
||||||
ps = rdsparser.get_ps(rds),
|
|
||||||
dataToSend.ps = decode_unicode(ps),
|
|
||||||
dataToSend.ps_errors = decode_errors(ps)
|
|
||||||
), 'callback_ps*'),
|
|
||||||
|
|
||||||
rt: koffi.register((rds, flag) => {
|
|
||||||
const rt = rdsparser.get_rt(rds, flag);
|
|
||||||
|
|
||||||
if (flag === 0) {
|
|
||||||
dataToSend.rt0 = decode_unicode(rt);
|
|
||||||
dataToSend.rt0_errors = decode_errors(rt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag === 1) {
|
|
||||||
dataToSend.rt1 = decode_unicode(rt);
|
|
||||||
dataToSend.rt1_errors = decode_errors(rt);
|
|
||||||
}
|
|
||||||
dataToSend.rt_flag = flag;
|
|
||||||
}, 'callback_rt*'),
|
|
||||||
|
|
||||||
ptyn: koffi.register((rds, flag) => (
|
|
||||||
value = decode_unicode(rdsparser.get_ptyn(rds))
|
|
||||||
/*console.log('PTYN: ' + value)*/
|
|
||||||
), 'callback_ptyn*'),
|
|
||||||
|
|
||||||
ct: koffi.register((rds, ct) => (
|
|
||||||
year = rdsparser.ct_get_year(ct),
|
|
||||||
month = String(rdsparser.ct_get_month(ct)).padStart(2, '0'),
|
|
||||||
day = String(rdsparser.ct_get_day(ct)).padStart(2, '0'),
|
|
||||||
hour = String(rdsparser.ct_get_hour(ct)).padStart(2, '0'),
|
|
||||||
minute = String(rdsparser.ct_get_minute(ct)).padStart(2, '0'),
|
|
||||||
offset = rdsparser.ct_get_offset(ct),
|
|
||||||
tz_sign = (offset >= 0 ? '+' : '-'),
|
|
||||||
tz_hour = String(Math.abs(Math.floor(offset / 60))).padStart(2, '0'),
|
|
||||||
tz_minute = String(Math.abs(offset % 60)).padStart(2, '0')
|
|
||||||
//console.log('CT: ' + year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ' (' + tz_sign + tz_hour + ':' + tz_minute + ')')
|
|
||||||
), 'callback_ct*')
|
|
||||||
};
|
|
||||||
|
|
||||||
let rds = rdsparser.new()
|
|
||||||
rdsparser.set_text_correction(rds, 0, 0, 2);
|
|
||||||
rdsparser.set_text_correction(rds, 0, 1, 2);
|
|
||||||
rdsparser.set_text_correction(rds, 1, 0, 2);
|
|
||||||
rdsparser.set_text_correction(rds, 1, 1, 2);
|
|
||||||
rdsparser.set_text_progressive(rds, 0, 1)
|
|
||||||
rdsparser.set_text_progressive(rds, 1, 1)
|
|
||||||
rdsparser.register_pi(rds, callbacks.pi);
|
|
||||||
rdsparser.register_pty(rds, callbacks.pty);
|
|
||||||
rdsparser.register_tp(rds, callbacks.tp);
|
|
||||||
rdsparser.register_ta(rds, callbacks.ta);
|
|
||||||
rdsparser.register_ms(rds, callbacks.ms);
|
|
||||||
rdsparser.register_ecc(rds, callbacks.ecc);
|
|
||||||
rdsparser.register_country(rds, callbacks.country);
|
|
||||||
rdsparser.register_af(rds, callbacks.af);
|
|
||||||
rdsparser.register_ps(rds, callbacks.ps);
|
|
||||||
rdsparser.register_rt(rds, callbacks.rt);
|
|
||||||
rdsparser.register_ptyn(rds, callbacks.ptyn);
|
|
||||||
rdsparser.register_ct(rds, callbacks.ct);
|
|
||||||
|
|
||||||
const decode_unicode = function(string) {
|
|
||||||
let length = rdsparser.string_get_length(string);
|
|
||||||
if (length) {
|
|
||||||
let content = rdsparser.string_get_content(string);
|
|
||||||
let array = koffi.decode(content, unicode_type + ' [' + length + ']');
|
|
||||||
return String.fromCodePoint.apply(String, array);
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const decode_errors = function(string) {
|
|
||||||
let length = rdsparser.string_get_length(string);
|
|
||||||
if (length) {
|
|
||||||
let errors = rdsparser.string_get_errors(string);
|
|
||||||
let array = koffi.decode(errors, 'uint8_t [' + length + ']');
|
|
||||||
return Uint8Array.from(array).toString();
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateInterval = 75;
|
const updateInterval = 75;
|
||||||
|
|
||||||
// Initialize the data object
|
// Initialize the data object
|
||||||
@@ -251,6 +46,8 @@ var dataToSend = {
|
|||||||
users: 0,
|
users: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const rdsdec = new RDSDecoder(dataToSend);
|
||||||
|
|
||||||
const filterMappings = {
|
const filterMappings = {
|
||||||
'G11': { eq: 1, ims: 1 },
|
'G11': { eq: 1, ims: 1 },
|
||||||
'G01': { eq: 0, ims: 1 },
|
'G01': { eq: 0, ims: 1 },
|
||||||
@@ -264,8 +61,6 @@ var lastUpdateTime = Date.now();
|
|||||||
const initialData = { ...dataToSend };
|
const initialData = { ...dataToSend };
|
||||||
const resetToDefault = dataToSend => Object.assign(dataToSend, initialData);
|
const resetToDefault = dataToSend => Object.assign(dataToSend, initialData);
|
||||||
|
|
||||||
// Serialport reconnect variables
|
|
||||||
const ServerStartTime = process.hrtime();
|
|
||||||
var serialportUpdateTime = process.hrtime();
|
var serialportUpdateTime = process.hrtime();
|
||||||
let checkSerialport = false;
|
let checkSerialport = false;
|
||||||
let rdsTimeoutTimer = null;
|
let rdsTimeoutTimer = null;
|
||||||
@@ -283,7 +78,7 @@ function rdsReceived() {
|
|||||||
function rdsReset() {
|
function rdsReset() {
|
||||||
resetToDefault(dataToSend);
|
resetToDefault(dataToSend);
|
||||||
dataToSend.af.length = 0;
|
dataToSend.af.length = 0;
|
||||||
rdsparser.clear(rds);
|
rdsdec.clear();
|
||||||
if (rdsTimeoutTimer) {
|
if (rdsTimeoutTimer) {
|
||||||
clearTimeout(rdsTimeoutTimer);
|
clearTimeout(rdsTimeoutTimer);
|
||||||
rdsTimeoutTimer = null;
|
rdsTimeoutTimer = null;
|
||||||
@@ -307,17 +102,13 @@ function handleData(wss, receivedData, rdsWss) {
|
|||||||
rdsReceived();
|
rdsReceived();
|
||||||
modifiedData = receivedLine.slice(1);
|
modifiedData = receivedLine.slice(1);
|
||||||
legacyRdsPiBuffer = modifiedData;
|
legacyRdsPiBuffer = modifiedData;
|
||||||
if (dataToSend.pi.length >= modifiedData.length || dataToSend.pi == '?') {
|
if (dataToSend.pi.length >= modifiedData.length || dataToSend.pi == '?') dataToSend.pi = modifiedData;
|
||||||
dataToSend.pi = modifiedData;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case receivedLine.startsWith('T'): // Frequency
|
case receivedLine.startsWith('T'): // Frequency
|
||||||
modifiedData = receivedLine.substring(1).split(",")[0];
|
modifiedData = receivedLine.substring(1).split(",")[0];
|
||||||
|
|
||||||
rdsReset();
|
rdsReset();
|
||||||
if((modifiedData / 1000).toFixed(3) == dataToSend.freq) {
|
if((modifiedData / 1000).toFixed(3) == dataToSend.freq) return; // Prevent tune spamming using scrollwheel
|
||||||
return; // Prevent tune spamming using scrollwheel
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedValue = parseFloat(modifiedData);
|
parsedValue = parseFloat(modifiedData);
|
||||||
|
|
||||||
@@ -372,8 +163,7 @@ function handleData(wss, receivedData, rdsWss) {
|
|||||||
var errorsNew = 0;
|
var errorsNew = 0;
|
||||||
var pi;
|
var pi;
|
||||||
|
|
||||||
if (legacyRdsPiBuffer !== null &&
|
if(legacyRdsPiBuffer !== null && legacyRdsPiBuffer.length >= 4) {
|
||||||
legacyRdsPiBuffer.length >= 4) {
|
|
||||||
pi = legacyRdsPiBuffer.slice(0, 4);
|
pi = legacyRdsPiBuffer.slice(0, 4);
|
||||||
// PI message does not carry explicit information about
|
// PI message does not carry explicit information about
|
||||||
// error correction, but this is a good substitute.
|
// error correction, but this is a good substitute.
|
||||||
@@ -404,7 +194,7 @@ function handleData(wss, receivedData, rdsWss) {
|
|||||||
client.send(finalBuffer);
|
client.send(finalBuffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
rdsparser.parse_string(rds, modifiedData);
|
rdsdec.decodeGroup(parseInt(modifiedData.slice(0, 4), 16), parseInt(modifiedData.slice(4, 8), 16), parseInt(modifiedData.slice(8, 12), 16), parseInt(modifiedData.slice(12, 16), 16));
|
||||||
legacyRdsPiBuffer = null;
|
legacyRdsPiBuffer = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -469,10 +259,7 @@ async function checkSerialPortStatus() {
|
|||||||
while (!checkSerialport) {
|
while (!checkSerialport) {
|
||||||
const ServerElapsedSeconds = process.hrtime(ServerStartTime)[0];
|
const ServerElapsedSeconds = process.hrtime(ServerStartTime)[0];
|
||||||
|
|
||||||
if (ServerElapsedSeconds > 10) {
|
if (ServerElapsedSeconds > 10) checkSerialport = true;
|
||||||
checkSerialport = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,13 +294,10 @@ function processSignal(receivedData, st, stForced) {
|
|||||||
|
|
||||||
// Convert highestSignal to a number for comparison
|
// Convert highestSignal to a number for comparison
|
||||||
var highestSignal = parseFloat(dataToSend.sigTop);
|
var highestSignal = parseFloat(dataToSend.sigTop);
|
||||||
if (signal > highestSignal) {
|
if (signal > highestSignal) dataToSend.sigTop = signal.toString(); // Convert back to string for consistency
|
||||||
dataToSend.sigTop = signal.toString(); // Convert back to string for consistency
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
handleData, showOnlineUsers, dataToSend, initialData, resetToDefault, state
|
handleData, showOnlineUsers, dataToSend, initialData, resetToDefault, state
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -463,6 +463,7 @@ router.get('/tunnelservers', async (req, res) => {
|
|||||||
{ value: "eu", host: "eu.fmtuner.org", label: "Europe" },
|
{ value: "eu", host: "eu.fmtuner.org", label: "Europe" },
|
||||||
{ value: "us", host: "us.fmtuner.org", label: "Americas" },
|
{ value: "us", host: "us.fmtuner.org", label: "Americas" },
|
||||||
{ value: "sg", host: "sg.fmtuner.org", label: "Asia & Oceania" },
|
{ value: "sg", host: "sg.fmtuner.org", label: "Asia & Oceania" },
|
||||||
|
{ value: "pldx", host: "pldx.fmtuner.org", label: "Poland (k201)" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
/* Libraries / Imports */
|
/* Libraries / Imports */
|
||||||
const fs = require('fs');
|
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
const { logDebug, logError, logInfo, logWarn } = require('./console');
|
const { logDebug, logInfo, logWarn } = require('./console');
|
||||||
const { serverConfig, configUpdate, configSave } = require('./server_config');
|
const { serverConfig, configSave } = require('./server_config');
|
||||||
var pjson = require('../package.json');
|
var pjson = require('../package.json');
|
||||||
var os = require('os');
|
var os = require('os');
|
||||||
|
|
||||||
@@ -23,23 +22,15 @@ function send(request) {
|
|||||||
fetch(url, options)
|
fetch(url, options)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success && data.token)
|
if (data.success && data.token) {
|
||||||
{
|
|
||||||
if (!serverConfig.identification.token)
|
if (!serverConfig.identification.token)
|
||||||
{
|
{
|
||||||
logInfo("Registered to FM-DX Server Map successfully.");
|
logInfo("Registered to FM-DX Server Map successfully.");
|
||||||
serverConfig.identification.token = data.token;
|
serverConfig.identification.token = data.token;
|
||||||
configSave();
|
configSave();
|
||||||
}
|
}
|
||||||
else
|
else logDebug("FM-DX Server Map update successful.");
|
||||||
{
|
} else logWarn("Failed to update FM-DX Server Map: " + (data.error ? data.error : 'unknown error'));
|
||||||
logDebug("FM-DX Server Map update successful.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logWarn("Failed to update FM-DX Server Map: " + (data.error ? data.error : 'unknown error'));
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
logWarn("Failed to update FM-DX Server Map: " + error);
|
logWarn("Failed to update FM-DX Server Map: " + error);
|
||||||
@@ -47,10 +38,7 @@ function send(request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendKeepalive() {
|
function sendKeepalive() {
|
||||||
if (!serverConfig.identification.token)
|
if (!serverConfig.identification.token) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const request = {
|
const request = {
|
||||||
token: serverConfig.identification.token,
|
token: serverConfig.identification.token,
|
||||||
@@ -64,9 +52,7 @@ function sendUpdate() {
|
|||||||
let currentOs = os.type() + ' ' + os.release();
|
let currentOs = os.type() + ' ' + os.release();
|
||||||
|
|
||||||
let bwLimit = '';
|
let bwLimit = '';
|
||||||
if (serverConfig.webserver.tuningLimit === true) {
|
if (serverConfig.webserver.tuningLimit === true) bwLimit = serverConfig.webserver.tuningLowerLimit + ' - ' + serverConfig.webserver.tuningUpperLimit + ' MHz';
|
||||||
bwLimit = serverConfig.webserver.tuningLowerLimit + ' - ' + serverConfig.webserver.tuningUpperLimit + ' MHz';
|
|
||||||
}
|
|
||||||
|
|
||||||
const request = {
|
const request = {
|
||||||
status: ((serverConfig.lockToAdmin == 'true' || serverConfig.publicTuner == 'false') ? 2 : 1),
|
status: ((serverConfig.lockToAdmin == 'true' || serverConfig.publicTuner == 'false') ? 2 : 1),
|
||||||
@@ -82,37 +68,20 @@ function sendUpdate() {
|
|||||||
version: pjson.version
|
version: pjson.version
|
||||||
};
|
};
|
||||||
|
|
||||||
if (serverConfig.identification.token)
|
if (serverConfig.identification.token) request.token = serverConfig.identification.token;
|
||||||
{
|
|
||||||
request.token = serverConfig.identification.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serverConfig.identification.proxyIp.length)
|
if (serverConfig.identification.proxyIp.length) request.url = serverConfig.identification.proxyIp;
|
||||||
{
|
else request.port = serverConfig.webserver.webserverPort;
|
||||||
request.url = serverConfig.identification.proxyIp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
request.port = serverConfig.webserver.webserverPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
send(request);
|
send(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
if (timeoutID !== null) {
|
if (timeoutID !== null) clearTimeout(timeoutID);
|
||||||
clearTimeout(timeoutID);
|
if (!serverConfig.identification.broadcastTuner) return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!serverConfig.identification.broadcastTuner)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendUpdate();
|
sendUpdate();
|
||||||
timeoutID = setInterval(sendKeepalive, 5 * 60 * 1000);
|
timeoutID = setInterval(sendKeepalive, 5 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports.update = update;
|
||||||
update
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -137,9 +137,7 @@ function processConnection(clientIp, locationInfo, currentUsers, ws, callback) {
|
|||||||
const normalizedClientIp = clientIp?.replace(/^::ffff:/, '');
|
const normalizedClientIp = clientIp?.replace(/^::ffff:/, '');
|
||||||
|
|
||||||
fetchBannedAS((error, bannedAS) => {
|
fetchBannedAS((error, bannedAS) => {
|
||||||
if (error) {
|
if (error) console.error("Error fetching banned AS list:", error);
|
||||||
console.error("Error fetching banned AS list:", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bannedAS.some((as) => locationInfo.as?.includes(as))) {
|
if (bannedAS.some((as) => locationInfo.as?.includes(as))) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
@@ -165,9 +163,7 @@ function processConnection(clientIp, locationInfo, currentUsers, ws, callback) {
|
|||||||
instance: ws,
|
instance: ws,
|
||||||
});
|
});
|
||||||
|
|
||||||
consoleCmd.logInfo(
|
consoleCmd.logInfo(`Web client \x1b[32mconnected\x1b[0m (${normalizedClientIp}) \x1b[90m[${currentUsers}]\x1b[0m Location: ${userLocation}`);
|
||||||
`Web client \x1b[32mconnected\x1b[0m (${normalizedClientIp}) \x1b[90m[${currentUsers}]\x1b[0m Location: ${userLocation}`
|
|
||||||
);
|
|
||||||
|
|
||||||
callback("User allowed");
|
callback("User allowed");
|
||||||
});
|
});
|
||||||
@@ -200,13 +196,9 @@ function resolveDataBuffer(data, wss, rdsWss) {
|
|||||||
incompleteDataBuffer = receivedData.slice(position + 1);
|
incompleteDataBuffer = receivedData.slice(position + 1);
|
||||||
receivedData = receivedData.slice(0, position + 1);
|
receivedData = receivedData.slice(0, position + 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else incompleteDataBuffer = '';
|
||||||
incompleteDataBuffer = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (receivedData.length) {
|
if (receivedData.length) dataHandler.handleData(wss, receivedData, rdsWss);
|
||||||
dataHandler.handleData(wss, receivedData, rdsWss);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function kickClient(ipAddress) {
|
function kickClient(ipAddress) {
|
||||||
@@ -221,9 +213,7 @@ function kickClient(ipAddress) {
|
|||||||
targetClient.instance.close();
|
targetClient.instance.close();
|
||||||
consoleCmd.logInfo(`Web client kicked (${ipAddress})`);
|
consoleCmd.logInfo(`Web client kicked (${ipAddress})`);
|
||||||
}, 500);
|
}, 500);
|
||||||
} else {
|
} else consoleCmd.logInfo(`Kicking client ${ipAddress} failed. No suitable client found.`);
|
||||||
consoleCmd.logInfo(`Kicking client ${ipAddress} failed. No suitable client found.`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkIPv6Support(callback) {
|
function checkIPv6Support(callback) {
|
||||||
@@ -232,11 +222,8 @@ function checkIPv6Support(callback) {
|
|||||||
server.listen(0, '::1', () => {
|
server.listen(0, '::1', () => {
|
||||||
server.close(() => callback(true));
|
server.close(() => callback(true));
|
||||||
}).on('error', (error) => {
|
}).on('error', (error) => {
|
||||||
if (error.code === 'EADDRNOTAVAIL') {
|
if (error.code === 'EADDRNOTAVAIL') callback(false);
|
||||||
callback(false);
|
else callback(false);
|
||||||
} else {
|
|
||||||
callback(false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,9 +259,7 @@ function antispamProtection(message, clientIp, ws, userCommands, lastWarn, userC
|
|||||||
if (endpointName === 'text') consoleCmd.logDebug(`Command received from \x1b[90m${clientIp}\x1b[0m: ${command}`);
|
if (endpointName === 'text') consoleCmd.logDebug(`Command received from \x1b[90m${clientIp}\x1b[0m: ${command}`);
|
||||||
|
|
||||||
// Initialize user command history if not present
|
// Initialize user command history if not present
|
||||||
if (!userCommandHistory[clientIp]) {
|
if (!userCommandHistory[clientIp]) userCommandHistory[clientIp] = [];
|
||||||
userCommandHistory[clientIp] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the current timestamp for the user
|
// Record the current timestamp for the user
|
||||||
userCommandHistory[clientIp].push(now);
|
userCommandHistory[clientIp].push(now);
|
||||||
|
|||||||
140
server/index.js
140
server/index.js
@@ -79,6 +79,7 @@ const terminalWidth = readline.createInterface({
|
|||||||
}).output.columns;
|
}).output.columns;
|
||||||
|
|
||||||
|
|
||||||
|
// Couldn't get figlet.js or something like that?
|
||||||
console.log(`\x1b[32m
|
console.log(`\x1b[32m
|
||||||
_____ __ __ ______ __ __ __ _
|
_____ __ __ ______ __ __ __ _
|
||||||
| ___| \\/ | | _ \\ \\/ / \\ \\ / /__| |__ ___ ___ _ ____ _____ _ __
|
| ___| \\/ | | _ \\ \\/ / \\ \\ / /__| |__ ___ ___ _ ____ _____ _ __
|
||||||
@@ -124,20 +125,16 @@ setInterval(() => {
|
|||||||
logWarn('Communication lost from ' + serverConfig.xdrd.comPort + ', force closing serialport.');
|
logWarn('Communication lost from ' + serverConfig.xdrd.comPort + ', force closing serialport.');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
serialport.close((err) => {
|
serialport.close((err) => {
|
||||||
if (err) {
|
if (err) logError('Error closing serialport: ', err.message);
|
||||||
logError('Error closing serialport: ', err.message);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else logWarn('Communication lost from ' + serverConfig.xdrd.comPort + '.');
|
||||||
logWarn('Communication lost from ' + serverConfig.xdrd.comPort + '.');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
// Serial Connection
|
// Serial Connection
|
||||||
function connectToSerial() {
|
function connectToSerial() {
|
||||||
if (serverConfig.xdrd.wirelessConnection === false) {
|
if (serverConfig.xdrd.wirelessConnection === true) return;
|
||||||
|
|
||||||
// Configure the SerialPort with DTR and RTS options
|
// Configure the SerialPort with DTR and RTS options
|
||||||
serialport = new SerialPort({
|
serialport = new SerialPort({
|
||||||
@@ -175,9 +172,7 @@ if (serverConfig.xdrd.wirelessConnection === false) {
|
|||||||
dataHandler.dataToSend.freq = Number(serverConfig.defaultFreq).toFixed(3);
|
dataHandler.dataToSend.freq = Number(serverConfig.defaultFreq).toFixed(3);
|
||||||
} else if (dataHandler.state.lastFrequencyAlive && dataHandler.state.isSerialportRetrying) { // Serialport retry code when port is open but communication is lost
|
} else if (dataHandler.state.lastFrequencyAlive && dataHandler.state.isSerialportRetrying) { // Serialport retry code when port is open but communication is lost
|
||||||
serialport.write('T' + (dataHandler.state.lastFrequencyAlive * 1000) + '\n');
|
serialport.write('T' + (dataHandler.state.lastFrequencyAlive * 1000) + '\n');
|
||||||
} else {
|
} else serialport.write('T87500\n');
|
||||||
serialport.write('T87500\n');
|
|
||||||
}
|
|
||||||
dataHandler.state.isSerialportRetrying = false;
|
dataHandler.state.isSerialportRetrying = false;
|
||||||
|
|
||||||
serialport.write('A0\n');
|
serialport.write('A0\n');
|
||||||
@@ -185,19 +180,12 @@ if (serverConfig.xdrd.wirelessConnection === false) {
|
|||||||
serialport.write('W0\n');
|
serialport.write('W0\n');
|
||||||
serverConfig.webserver.rdsMode ? serialport.write('D1\n') : serialport.write('D0\n');
|
serverConfig.webserver.rdsMode ? serialport.write('D1\n') : serialport.write('D0\n');
|
||||||
// cEQ and iMS combinations
|
// cEQ and iMS combinations
|
||||||
if (serverConfig.ceqStartup === "0" && serverConfig.imsStartup === "0") {
|
if (serverConfig.ceqStartup === "0" && serverConfig.imsStartup === "0") serialport.write("G00\n"); // Both Disabled
|
||||||
serialport.write("G00\n"); // Both Disabled
|
else if (serverConfig.ceqStartup === "1" && serverConfig.imsStartup === "0") serialport.write(`G10\n`);
|
||||||
} else if (serverConfig.ceqStartup === "1" && serverConfig.imsStartup === "0") {
|
else if (serverConfig.ceqStartup === "0" && serverConfig.imsStartup === "1") serialport.write(`G01\n`);
|
||||||
serialport.write(`G10\n`);
|
else if (serverConfig.ceqStartup === "1" && serverConfig.imsStartup === "1") serialport.write("G11\n"); // Both Enabled
|
||||||
} else if (serverConfig.ceqStartup === "0" && serverConfig.imsStartup === "1") {
|
|
||||||
serialport.write(`G01\n`);
|
|
||||||
} else if (serverConfig.ceqStartup === "1" && serverConfig.imsStartup === "1") {
|
|
||||||
serialport.write("G11\n"); // Both Enabled
|
|
||||||
}
|
|
||||||
// Handle stereo mode
|
// Handle stereo mode
|
||||||
if (serverConfig.stereoStartup === "1") {
|
if (serverConfig.stereoStartup === "1") serialport.write("B1\n"); // Mono
|
||||||
serialport.write("B1\n"); // Mono
|
|
||||||
}
|
|
||||||
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');
|
||||||
@@ -222,7 +210,6 @@ if (serverConfig.xdrd.wirelessConnection === false) {
|
|||||||
});
|
});
|
||||||
return serialport;
|
return serialport;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// xdrd connection
|
// xdrd connection
|
||||||
let authFlags = {};
|
let authFlags = {};
|
||||||
@@ -266,9 +253,8 @@ client.on('data', (data) => {
|
|||||||
if (line.startsWith('a')) {
|
if (line.startsWith('a')) {
|
||||||
authFlags.authMsg = true;
|
authFlags.authMsg = true;
|
||||||
logWarn('Authentication with xdrd failed. Is your password set correctly?');
|
logWarn('Authentication with xdrd failed. Is your password set correctly?');
|
||||||
} else if (line.startsWith('o1,')) {
|
} else if (line.startsWith('o1,')) authFlags.firstClient = true;
|
||||||
authFlags.firstClient = true;
|
else if (line.startsWith('T') && line.length <= 7) {
|
||||||
} else if (line.startsWith('T') && line.length <= 7) {
|
|
||||||
const freq = line.slice(1) / 1000;
|
const freq = line.slice(1) / 1000;
|
||||||
dataHandler.dataToSend.freq = freq.toFixed(3);
|
dataHandler.dataToSend.freq = freq.toFixed(3);
|
||||||
} else if (line.startsWith('OK')) {
|
} else if (line.startsWith('OK')) {
|
||||||
@@ -306,9 +292,7 @@ client.on('close', () => {
|
|||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
connectToXdrd();
|
connectToXdrd();
|
||||||
}, 2000)
|
}, 2000)
|
||||||
} else {
|
} else logWarn('Disconnected from xdrd.');
|
||||||
logWarn('Disconnected from xdrd.');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', (err) => {
|
client.on('error', (err) => {
|
||||||
@@ -369,9 +353,7 @@ wss.on('connection', (ws, request) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientIp && clientIp.includes(',')) {
|
if (clientIp && clientIp.includes(',')) clientIp = clientIp.split(',')[0].trim();
|
||||||
clientIp = clientIp.split(',')[0].trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Per-IP limit connection open
|
// Per-IP limit connection open
|
||||||
if (clientIp) {
|
if (clientIp) {
|
||||||
@@ -435,9 +417,7 @@ wss.on('connection', (ws, request) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.includes("\'")) {
|
if (command.includes("\'")) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { isAdminAuthenticated, isTuneAuthenticated } = request.session || {};
|
const { isAdminAuthenticated, isTuneAuthenticated } = request.session || {};
|
||||||
|
|
||||||
@@ -466,14 +446,10 @@ wss.on('connection', (ws, request) => {
|
|||||||
const tuneFreq = Number(command.slice(1)) / 1000;
|
const tuneFreq = Number(command.slice(1)) / 1000;
|
||||||
const { tuningLimit, tuningLowerLimit, tuningUpperLimit } = serverConfig.webserver;
|
const { tuningLimit, tuningLowerLimit, tuningUpperLimit } = serverConfig.webserver;
|
||||||
|
|
||||||
if (tuningLimit && (tuneFreq < tuningLowerLimit || tuneFreq > tuningUpperLimit) || isNaN(tuneFreq)) {
|
if (tuningLimit && (tuneFreq < tuningLowerLimit || tuneFreq > tuningUpperLimit) || isNaN(tuneFreq)) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((serverConfig.publicTuner && !serverConfig.lockToAdmin) || isAdminAuthenticated || (!serverConfig.publicTuner && !serverConfig.lockToAdmin && isTuneAuthenticated)) {
|
if ((serverConfig.publicTuner && !serverConfig.lockToAdmin) || isAdminAuthenticated || (!serverConfig.publicTuner && !serverConfig.lockToAdmin && isTuneAuthenticated)) output.write(`${command}\n`);
|
||||||
output.write(`${command}\n`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('close', (code, reason) => {
|
ws.on('close', (code, reason) => {
|
||||||
@@ -499,55 +475,34 @@ wss.on('connection', (ws, request) => {
|
|||||||
dataHandler.showOnlineUsers(currentUsers);
|
dataHandler.showOnlineUsers(currentUsers);
|
||||||
|
|
||||||
const index = storage.connectedUsers.findIndex(user => user.ip === clientIp);
|
const index = storage.connectedUsers.findIndex(user => user.ip === clientIp);
|
||||||
if (index !== -1) {
|
if (index !== -1) storage.connectedUsers.splice(index, 1);
|
||||||
storage.connectedUsers.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentUsers === 0) {
|
if (currentUsers === 0) {
|
||||||
storage.connectedUsers = [];
|
storage.connectedUsers = [];
|
||||||
|
|
||||||
if (serverConfig.bwAutoNoUsers === "1") {
|
if (serverConfig.bwAutoNoUsers === "1") output.write("W0\n"); // Auto BW 'Enabled'
|
||||||
output.write("W0\n"); // Auto BW 'Enabled'
|
|
||||||
}
|
|
||||||
|
|
||||||
// cEQ and iMS combinations
|
// cEQ and iMS combinations
|
||||||
if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "1") {
|
if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "1") output.write("G00\n"); // Both Disabled
|
||||||
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") {
|
else if (serverConfig.ceqNoUsers === "0" && serverConfig.imsNoUsers === "1") output.write(`G${dataHandler.dataToSend.eq}0\n`);
|
||||||
output.write(`G0${dataHandler.dataToSend.ims}\n`);
|
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "0") output.write(`G1${dataHandler.dataToSend.ims}\n`);
|
||||||
} else if (serverConfig.ceqNoUsers === "0" && serverConfig.imsNoUsers === "1") {
|
else if (serverConfig.ceqNoUsers === "0" && serverConfig.imsNoUsers === "2") output.write(`G${dataHandler.dataToSend.eq}1\n`);
|
||||||
output.write(`G${dataHandler.dataToSend.eq}0\n`);
|
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "1") output.write("G10\n"); // Only cEQ enabled
|
||||||
} else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "0") {
|
else if (serverConfig.ceqNoUsers === "1" && serverConfig.imsNoUsers === "2") output.write("G01\n"); // Only iMS enabled
|
||||||
output.write(`G1${dataHandler.dataToSend.ims}\n`);
|
else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "2") output.write("G11\n"); // Both Enabled
|
||||||
} else if (serverConfig.ceqNoUsers === "0" && serverConfig.imsNoUsers === "2") {
|
|
||||||
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 === "1" && serverConfig.imsNoUsers === "2") {
|
|
||||||
output.write("G01\n"); // Only iMS enabled
|
|
||||||
} else if (serverConfig.ceqNoUsers === "2" && serverConfig.imsNoUsers === "2") {
|
|
||||||
output.write("G11\n"); // Both Enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle stereo mode
|
// Handle stereo mode
|
||||||
if (serverConfig.stereoNoUsers === "1") {
|
if (serverConfig.stereoNoUsers === "1") output.write("B0\n");
|
||||||
output.write("B0\n");
|
else if (serverConfig.stereoNoUsers === "2") output.write("B1\n");
|
||||||
} else if (serverConfig.stereoNoUsers === "2") {
|
|
||||||
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") {
|
if (serverConfig.antennaNoUsers === "1") output.write("Z0\n");
|
||||||
output.write("Z0\n");
|
else if (serverConfig.antennaNoUsers === "2") output.write("Z1\n");
|
||||||
} else if (serverConfig.antennaNoUsers === "2") {
|
else if (serverConfig.antennaNoUsers === "3") output.write("Z2\n");
|
||||||
output.write("Z1\n");
|
else if (serverConfig.antennaNoUsers === "4") output.write("Z3\n");
|
||||||
} else if (serverConfig.antennaNoUsers === "3") {
|
|
||||||
output.write("Z2\n");
|
|
||||||
} else if (serverConfig.antennaNoUsers === "4") {
|
|
||||||
output.write("Z3\n");
|
|
||||||
}
|
|
||||||
}, serverConfig.antennaNoUsersDelay ? 15000 : 0);
|
}, serverConfig.antennaNoUsersDelay ? 15000 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,13 +525,9 @@ wss.on('connection', (ws, request) => {
|
|||||||
}, 10000);
|
}, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentUsers === 0 && serverConfig.autoShutdown === true && serverConfig.xdrd.wirelessConnection === true) {
|
if (currentUsers === 0 && serverConfig.autoShutdown === true && serverConfig.xdrd.wirelessConnection === true) client.write('X\n');
|
||||||
client.write('X\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code !== 1008) {
|
if (code !== 1008) logInfo(`Web client \x1b[31mdisconnected\x1b[0m (${normalizedClientIp}) \x1b[90m[${currentUsers}]`);
|
||||||
logInfo(`Web client \x1b[31mdisconnected\x1b[0m (${normalizedClientIp}) \x1b[90m[${currentUsers}]`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('error', console.error);
|
ws.on('error', console.error);
|
||||||
@@ -600,7 +551,7 @@ pluginsWss.on('connection', (ws, request) => {
|
|||||||
|
|
||||||
let messageData;
|
let messageData;
|
||||||
|
|
||||||
try {
|
try { // JS Requires the try statement to have braces, unlike the if statement. This extends the huge list of proofs that this is a fucking toy language
|
||||||
messageData = JSON.parse(message); // Attempt to parse the JSON
|
messageData = JSON.parse(message); // Attempt to parse the JSON
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.error("Failed to parse message:", error); // Log the error
|
// console.error("Failed to parse message:", error); // Log the error
|
||||||
@@ -611,9 +562,7 @@ pluginsWss.on('connection', (ws, request) => {
|
|||||||
|
|
||||||
// Broadcast the message to all other clients
|
// Broadcast the message to all other clients
|
||||||
pluginsWss.clients.forEach(client => {
|
pluginsWss.clients.forEach(client => {
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
if (client.readyState === WebSocket.OPEN) client.send(modifiedMessage); // Send the message to all clients
|
||||||
client.send(modifiedMessage); // Send the message to all clients
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -671,9 +620,7 @@ httpServer.on('upgrade', (request, socket, head) => {
|
|||||||
pluginsWss.emit('connection', ws, request);
|
pluginsWss.emit('connection', ws, request);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else socket.destroy();
|
||||||
socket.destroy();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(express.static(path.join(__dirname, '../web'))); // Serve the entire web folder to the user
|
app.use(express.static(path.join(__dirname, '../web'))); // Serve the entire web folder to the user
|
||||||
@@ -691,18 +638,13 @@ helpers.checkIPv6Support((isIPv6Supported) => {
|
|||||||
|
|
||||||
const startServer = (address, isIPv6) => {
|
const startServer = (address, isIPv6) => {
|
||||||
httpServer.listen(port, address, () => {
|
httpServer.listen(port, address, () => {
|
||||||
if (!isIPv6 && !configExists()) {
|
if (!isIPv6 && !configExists()) logInfo(`Open your browser and proceed to \x1b[34mhttp://${address}:${port}\x1b[0m to continue with setup.`);
|
||||||
logInfo(`Open your browser and proceed to \x1b[34mhttp://${address}:${port}\x1b[0m to continue with setup.`);
|
else logServerStart(address, isIPv6);
|
||||||
} else {
|
|
||||||
logServerStart(address, isIPv6);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isIPv6Supported) {
|
if (isIPv6Supported) {
|
||||||
startServer(ipv4Address, false); // Start on IPv4
|
startServer(ipv4Address, false); // Start on IPv4
|
||||||
startServer(ipv6Address, true); // Start on IPv6
|
startServer(ipv6Address, true); // Start on IPv6
|
||||||
} else {
|
} else startServer(ipv4Address, false); // Start only on IPv4
|
||||||
startServer(ipv4Address, false); // Start only on IPv4
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
184
server/rds.js
Normal file
184
server/rds.js
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
const { rdsEccLookup, iso, countries } = require("./rds_country.js")
|
||||||
|
|
||||||
|
class RDSDecoder {
|
||||||
|
constructor(data) {
|
||||||
|
this.data = data;
|
||||||
|
this.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.data.pi = '?';
|
||||||
|
this.ps = Array(8).fill(' ');
|
||||||
|
this.ps_errors = Array(8).fill("0");
|
||||||
|
this.rt0 = Array(64).fill(' ');
|
||||||
|
this.rt0_errors = Array(64).fill("0");
|
||||||
|
this.rt1 = Array(64).fill(' ');
|
||||||
|
this.rt1_errors = Array(64).fill("0");
|
||||||
|
this.data.ps = '';
|
||||||
|
this.data.rt1 = '';
|
||||||
|
this.data.rt0 = '';
|
||||||
|
this.data.pty = 0;
|
||||||
|
this.data.tp = 0;
|
||||||
|
this.data.ta = 0;
|
||||||
|
this.data.ms = -1;
|
||||||
|
this.data.rt_flag = 0;
|
||||||
|
this.rt1_to_clear = false;
|
||||||
|
this.rt0_to_clear = false;
|
||||||
|
this.data.ecc = null;
|
||||||
|
this.data.country_name = ""
|
||||||
|
this.data.country_iso = "UN"
|
||||||
|
|
||||||
|
this.af_len = 0;
|
||||||
|
this.data.af = []
|
||||||
|
this.af_am_follows = false;
|
||||||
|
|
||||||
|
this.last_pi_error = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeGroup(blockA, blockB, blockC, blockD, error) {
|
||||||
|
const a_error = (error & 0xC0) >> 6;
|
||||||
|
const b_error = (error & 0x30) >> 4;
|
||||||
|
const c_error = (error & 0xc) >> 2;
|
||||||
|
const d_error = error & 3;
|
||||||
|
|
||||||
|
if(this.last_pi_error > a_error) {
|
||||||
|
this.data.pi = blockA.toString(16).toUpperCase().padStart(4, '0');
|
||||||
|
this.last_pi_error = a_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b_error != 0) return; // B chooses what group this is, if this has errors, we are screwed
|
||||||
|
|
||||||
|
const group = (blockB >> 12) & 0xF;
|
||||||
|
const version = (blockB >> 11) & 0x1;
|
||||||
|
this.data.tp = Number((blockB >> 10) & 1);
|
||||||
|
this.data.pty = (blockB >> 5) & 0b11111;
|
||||||
|
|
||||||
|
if (group === 0) {
|
||||||
|
this.data.ta = (blockB >> 4) & 1;
|
||||||
|
this.data.ms = (blockB >> 3) & 1;
|
||||||
|
|
||||||
|
if(version === 0 && c_error !== 3) {
|
||||||
|
var af_high = blockC >> 8;
|
||||||
|
var af_low = blockC & 0xFF;
|
||||||
|
var BASE = 224;
|
||||||
|
var FILLER = 205;
|
||||||
|
var AM_FOLLOWS = 250;
|
||||||
|
|
||||||
|
if(af_high >= BASE && af_high <= (BASE+25)) {
|
||||||
|
this.af_len = af_high-BASE;
|
||||||
|
if(this.af_len !== this.data.af.length) {
|
||||||
|
this.data.af = [];
|
||||||
|
this.af_am_follows = false;
|
||||||
|
|
||||||
|
if(af_low != FILLER && af_low != AM_FOLLOWS) this.data.af.push((af_low+875)*100)
|
||||||
|
else if(af_low == AM_FOLLOWS) this.af_am_follows = true;
|
||||||
|
}
|
||||||
|
} else if(this.data.af.length != this.af_len) {
|
||||||
|
if(!(af_high == AM_FOLLOWS || this.af_am_follows)) {
|
||||||
|
var freq = (af_high+875)*100;
|
||||||
|
if(!this.data.af.includes(freq)) this.data.af.push(freq);
|
||||||
|
}
|
||||||
|
if(this.af_am_follows) this.af_am_follows = false;
|
||||||
|
if(!(af_high == AM_FOLLOWS || af_low == FILLER || af_low == AM_FOLLOWS)) {
|
||||||
|
var freq = (af_low+875)*100;
|
||||||
|
if(!this.data.af.includes(freq)) this.data.af.push(freq);
|
||||||
|
}
|
||||||
|
if(af_low == AM_FOLLOWS) this.af_am_follows = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d_error === 3) return; // Don't risk it
|
||||||
|
|
||||||
|
const idx = blockB & 0x3;
|
||||||
|
|
||||||
|
this.ps[idx * 2] = String.fromCharCode(blockD >> 8);
|
||||||
|
this.ps[idx * 2 + 1] = String.fromCharCode(blockD & 0xFF);
|
||||||
|
this.ps_errors[idx * 2] = error;
|
||||||
|
this.ps_errors[idx * 2 + 1] = error;
|
||||||
|
|
||||||
|
this.data.ps = this.ps.join('');
|
||||||
|
this.data.ps_errors = this.ps_errors.join(',');
|
||||||
|
} else if (group === 1 && version === 0) {
|
||||||
|
var variant_code = (blockC >> 12) & 0x7;
|
||||||
|
switch (variant_code) {
|
||||||
|
case 0:
|
||||||
|
this.data.ecc = blockC & 0xff;
|
||||||
|
this.data.country_name = rdsEccLookup(blockA, this.data.ecc);
|
||||||
|
if(this.data.country_name.length === 0) this.data.country_iso = "UN";
|
||||||
|
else this.data.country_iso = iso[countries.indexOf(this.data.country_name)]
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
} else if (group === 2) {
|
||||||
|
const idx = blockB & 0b1111;
|
||||||
|
this.rt_ab = Boolean((blockB >> 4) & 1);
|
||||||
|
var multiplier = (version == 0) ? 4 : 2;
|
||||||
|
if(this.rt_ab) {
|
||||||
|
if(this.rt1_to_clear) {
|
||||||
|
this.rt1 = Array(64).fill(' ');
|
||||||
|
this.rt1_errors = Array(64).fill("0");
|
||||||
|
this.rt1_to_clear = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c_error !== 3 && multiplier !== 2) {
|
||||||
|
this.rt1[idx * multiplier] = String.fromCharCode(blockC >> 8);
|
||||||
|
this.rt1[idx * multiplier + 1] = String.fromCharCode(blockC & 0xFF);
|
||||||
|
this.rt1_errors[idx * multiplier] = error;
|
||||||
|
this.rt1_errors[idx * multiplier + 1] = error;
|
||||||
|
}
|
||||||
|
if(d_error !== 3) {
|
||||||
|
var offset = (multiplier == 2) ? 0 : 2;
|
||||||
|
this.rt1[idx * multiplier + offset] = String.fromCharCode(blockD >> 8);
|
||||||
|
this.rt1[idx * multiplier + offset + 1] = String.fromCharCode(blockD & 0xFF);
|
||||||
|
this.rt1_errors[idx * multiplier + offset] = error;
|
||||||
|
this.rt1_errors[idx * multiplier + offset + 1] = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = this.rt1.indexOf("\r")
|
||||||
|
while(i != -1) {
|
||||||
|
this.rt1[i] = " ";
|
||||||
|
i = this.rt1.indexOf("\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.rt1 = this.rt1.join('');
|
||||||
|
this.data.rt1_errors = this.rt1_errors.join(',');
|
||||||
|
this.data.rt_flag = 1;
|
||||||
|
this.rt0_to_clear = true;
|
||||||
|
} else {
|
||||||
|
if(this.rt0_to_clear) {
|
||||||
|
this.rt0 = Array(64).fill(' ');
|
||||||
|
this.rt0_errors = Array(64).fill("0");
|
||||||
|
this.rt0_to_clear = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c_error !== 3 && multiplier !== 2) {
|
||||||
|
this.rt0[idx * multiplier] = String.fromCharCode(blockC >> 8);
|
||||||
|
this.rt0[idx * multiplier + 1] = String.fromCharCode(blockC & 0xFF);
|
||||||
|
this.rt0_errors[idx * multiplier] = error;
|
||||||
|
this.rt0_errors[idx * multiplier + 1] = error;
|
||||||
|
}
|
||||||
|
if(d_error !== 3) {
|
||||||
|
var offset = (multiplier == 2) ? 0 : 2;
|
||||||
|
this.rt0[idx * multiplier + offset] = String.fromCharCode(blockD >> 8);
|
||||||
|
this.rt0[idx * multiplier + offset + 1] = String.fromCharCode(blockD & 0xFF);
|
||||||
|
this.rt0_errors[idx * multiplier + offset] = error;
|
||||||
|
this.rt0_errors[idx * multiplier + offset + 1] = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = this.rt0.indexOf("\r");
|
||||||
|
while(i != -1) {
|
||||||
|
this.rt0[i] = " ";
|
||||||
|
i = this.rt0.indexOf("\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.rt0 = this.rt0.join('');
|
||||||
|
this.data.rt0_errors = this.rt0_errors.join(',');
|
||||||
|
this.data.rt_flag = 0;
|
||||||
|
this.rt1_to_clear = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// console.log(group, version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = RDSDecoder;
|
||||||
632
server/rds_country.js
Normal file
632
server/rds_country.js
Normal file
@@ -0,0 +1,632 @@
|
|||||||
|
var countries = [
|
||||||
|
"Albania",
|
||||||
|
"Estonia",
|
||||||
|
"Algeria",
|
||||||
|
"Ethiopia",
|
||||||
|
"Andorra",
|
||||||
|
"Angola",
|
||||||
|
"Finland",
|
||||||
|
"Armenia",
|
||||||
|
"France",
|
||||||
|
"Ascension Island",
|
||||||
|
"Gabon",
|
||||||
|
"Austria",
|
||||||
|
"Gambia",
|
||||||
|
"Azerbaijan",
|
||||||
|
"Georgia",
|
||||||
|
"Germany",
|
||||||
|
"Bahrein",
|
||||||
|
"Ghana",
|
||||||
|
"Belarus",
|
||||||
|
"Gibraltar",
|
||||||
|
"Belgium",
|
||||||
|
"Greece",
|
||||||
|
"Benin",
|
||||||
|
"Guinea",
|
||||||
|
"Bosnia Herzegovina",
|
||||||
|
"Guinea-Bissau",
|
||||||
|
"Botswana",
|
||||||
|
"Hungary",
|
||||||
|
"Bulgaria",
|
||||||
|
"Iceland",
|
||||||
|
"Burkina Faso",
|
||||||
|
"Iraq",
|
||||||
|
"Burundi",
|
||||||
|
"Ireland",
|
||||||
|
"Cabinda",
|
||||||
|
"Israel",
|
||||||
|
"Cameroon",
|
||||||
|
"Italy",
|
||||||
|
"Jordan",
|
||||||
|
"Cape Verde",
|
||||||
|
"Kazakhstan",
|
||||||
|
"Central African Republic",
|
||||||
|
"Kenya",
|
||||||
|
"Chad",
|
||||||
|
"Kosovo",
|
||||||
|
"Comoros",
|
||||||
|
"Kuwait",
|
||||||
|
"DR Congo",
|
||||||
|
"Kyrgyzstan",
|
||||||
|
"Republic of Congo",
|
||||||
|
"Latvia",
|
||||||
|
"Cote d'Ivoire",
|
||||||
|
"Lebanon",
|
||||||
|
"Croatia",
|
||||||
|
"Lesotho",
|
||||||
|
"Cyprus",
|
||||||
|
"Liberia",
|
||||||
|
"Czechia",
|
||||||
|
"Libya",
|
||||||
|
"Denmark",
|
||||||
|
"Liechtenstein",
|
||||||
|
"Djiboutia",
|
||||||
|
"Lithuania",
|
||||||
|
"Egypt",
|
||||||
|
"Luxembourg",
|
||||||
|
"Equatorial Guinea",
|
||||||
|
"Macedonia",
|
||||||
|
"Eritrea",
|
||||||
|
"Madagascar",
|
||||||
|
"Seychelles",
|
||||||
|
"Malawi",
|
||||||
|
"Sierra Leone",
|
||||||
|
"Mali",
|
||||||
|
"Slovakia",
|
||||||
|
"Malta",
|
||||||
|
"Slovenia",
|
||||||
|
"Mauritania",
|
||||||
|
"Somalia",
|
||||||
|
"Mauritius",
|
||||||
|
"South Africa",
|
||||||
|
"Moldova",
|
||||||
|
"South Sudan",
|
||||||
|
"Monaco",
|
||||||
|
"Spain",
|
||||||
|
"Mongolia",
|
||||||
|
"Sudan",
|
||||||
|
"Montenegro",
|
||||||
|
"Swaziland",
|
||||||
|
"Morocco",
|
||||||
|
"Sweden",
|
||||||
|
"Mozambique",
|
||||||
|
"Switzerland",
|
||||||
|
"Namibia",
|
||||||
|
"Syria",
|
||||||
|
"Netherlands",
|
||||||
|
"Tajikistan",
|
||||||
|
"Niger",
|
||||||
|
"Tanzania",
|
||||||
|
"Nigeria",
|
||||||
|
"Togo",
|
||||||
|
"Norway",
|
||||||
|
"Tunisia",
|
||||||
|
"Oman",
|
||||||
|
"Turkey",
|
||||||
|
"Palestine",
|
||||||
|
"Turkmenistan",
|
||||||
|
"Poland",
|
||||||
|
"Uganda",
|
||||||
|
"Portugal",
|
||||||
|
"Ukraine",
|
||||||
|
"Qatar",
|
||||||
|
"United Arab Emirates",
|
||||||
|
"Romania",
|
||||||
|
"United Kingdom",
|
||||||
|
"Russia",
|
||||||
|
"Uzbekistan",
|
||||||
|
"Rwanda",
|
||||||
|
"Vatican",
|
||||||
|
"San Marino",
|
||||||
|
"Western Sahara",
|
||||||
|
"Sao Tome and Principe",
|
||||||
|
"Yemen",
|
||||||
|
"Saudi Arabia",
|
||||||
|
"Zambia",
|
||||||
|
"Senegal",
|
||||||
|
"Zimbabwe",
|
||||||
|
"Serbia",
|
||||||
|
"Anguilla",
|
||||||
|
"Guyana",
|
||||||
|
"Antigua and Barbuda",
|
||||||
|
"Haiti",
|
||||||
|
"Argentina",
|
||||||
|
"Honduras",
|
||||||
|
"Aruba",
|
||||||
|
"Jamaica",
|
||||||
|
"Bahamas",
|
||||||
|
"Martinique",
|
||||||
|
"Barbados",
|
||||||
|
"Mexico",
|
||||||
|
"Belize",
|
||||||
|
"Montserrat",
|
||||||
|
"Brazil/Bermuda",
|
||||||
|
"Brazil/AN",
|
||||||
|
"Bolivia",
|
||||||
|
"Nicaragua",
|
||||||
|
"Brazil",
|
||||||
|
"Panama",
|
||||||
|
"Canada",
|
||||||
|
"Paraguay",
|
||||||
|
"Cayman Islands",
|
||||||
|
"Peru",
|
||||||
|
"Chile",
|
||||||
|
"USA/VI/PR",
|
||||||
|
"Colombia",
|
||||||
|
"St. Kitts",
|
||||||
|
"Costa Rica",
|
||||||
|
"St. Lucia",
|
||||||
|
"Cuba",
|
||||||
|
"St. Pierre and Miquelon",
|
||||||
|
"Dominica",
|
||||||
|
"St. Vincent",
|
||||||
|
"Dominican Republic",
|
||||||
|
"Suriname",
|
||||||
|
"El Salvador",
|
||||||
|
"Trinidad and Tobago",
|
||||||
|
"Turks and Caicos islands",
|
||||||
|
"Falkland Islands",
|
||||||
|
"Greenland",
|
||||||
|
"Uruguay",
|
||||||
|
"Grenada",
|
||||||
|
"Venezuela",
|
||||||
|
"Guadeloupe",
|
||||||
|
"Virgin Islands",
|
||||||
|
"Guatemala",
|
||||||
|
"Afghanistan",
|
||||||
|
"South Korea",
|
||||||
|
"Laos",
|
||||||
|
"Australia Capital Territory",
|
||||||
|
"Macao",
|
||||||
|
"Australia New South Wales",
|
||||||
|
"Malaysia",
|
||||||
|
"Australia Victoria",
|
||||||
|
"Maldives",
|
||||||
|
"Australia Queensland",
|
||||||
|
"Marshall Islands",
|
||||||
|
"Australia South Australia",
|
||||||
|
"Micronesia",
|
||||||
|
"Australia Western Australia",
|
||||||
|
"Myanmar",
|
||||||
|
"Australia Tasmania",
|
||||||
|
"Nauru",
|
||||||
|
"Australia Northern Territory",
|
||||||
|
"Nepal",
|
||||||
|
"Bangladesh",
|
||||||
|
"New Zealand",
|
||||||
|
"Bhutan",
|
||||||
|
"Pakistan",
|
||||||
|
"Brunei Darussalam",
|
||||||
|
"Papua New Guinea",
|
||||||
|
"Cambodia",
|
||||||
|
"Philippines",
|
||||||
|
"China",
|
||||||
|
"Samoa",
|
||||||
|
"Singapore",
|
||||||
|
"Solomon Islands",
|
||||||
|
"Fiji",
|
||||||
|
"Sri Lanka",
|
||||||
|
"Hong Kong",
|
||||||
|
"Taiwan",
|
||||||
|
"India",
|
||||||
|
"Thailand",
|
||||||
|
"Indonesia",
|
||||||
|
"Tonga",
|
||||||
|
"Iran",
|
||||||
|
"Vanuatu",
|
||||||
|
"Japan",
|
||||||
|
"Vietnam",
|
||||||
|
"Kiribati",
|
||||||
|
"North Korea",
|
||||||
|
"Brazil/Equator"
|
||||||
|
]
|
||||||
|
|
||||||
|
var iso = [
|
||||||
|
"AL",
|
||||||
|
"EE",
|
||||||
|
"DZ",
|
||||||
|
"ET",
|
||||||
|
"AD",
|
||||||
|
"AO",
|
||||||
|
"FI",
|
||||||
|
"AM",
|
||||||
|
"FR",
|
||||||
|
"SH",
|
||||||
|
"GA",
|
||||||
|
"AT",
|
||||||
|
"GM",
|
||||||
|
"AZ",
|
||||||
|
"GE",
|
||||||
|
"DE",
|
||||||
|
"BH",
|
||||||
|
"GH",
|
||||||
|
"BY",
|
||||||
|
"GI",
|
||||||
|
"BE",
|
||||||
|
"GR",
|
||||||
|
"BJ",
|
||||||
|
"GN",
|
||||||
|
"BA",
|
||||||
|
"GW",
|
||||||
|
"BW",
|
||||||
|
"HU",
|
||||||
|
"BG",
|
||||||
|
"IS",
|
||||||
|
"BF",
|
||||||
|
"IQ",
|
||||||
|
"BI",
|
||||||
|
"IE",
|
||||||
|
"--",
|
||||||
|
"IL",
|
||||||
|
"CM",
|
||||||
|
"IT",
|
||||||
|
"JO",
|
||||||
|
"CV",
|
||||||
|
"KZ",
|
||||||
|
"CF",
|
||||||
|
"KE",
|
||||||
|
"TD",
|
||||||
|
"XK",
|
||||||
|
"KM",
|
||||||
|
"KW",
|
||||||
|
"CD",
|
||||||
|
"KG",
|
||||||
|
"CG",
|
||||||
|
"LV",
|
||||||
|
"CI",
|
||||||
|
"LB",
|
||||||
|
"HR",
|
||||||
|
"LS",
|
||||||
|
"CY",
|
||||||
|
"LR",
|
||||||
|
"CZ",
|
||||||
|
"LY",
|
||||||
|
"DK",
|
||||||
|
"LI",
|
||||||
|
"DJ",
|
||||||
|
"LT",
|
||||||
|
"EG",
|
||||||
|
"LU",
|
||||||
|
"GQ",
|
||||||
|
"MK",
|
||||||
|
"ER",
|
||||||
|
"MG",
|
||||||
|
"SC",
|
||||||
|
"MW",
|
||||||
|
"SL",
|
||||||
|
"ML",
|
||||||
|
"SK",
|
||||||
|
"MT",
|
||||||
|
"SI",
|
||||||
|
"MR",
|
||||||
|
"SO",
|
||||||
|
"MU",
|
||||||
|
"ZA",
|
||||||
|
"MD",
|
||||||
|
"SS",
|
||||||
|
"MC",
|
||||||
|
"ES",
|
||||||
|
"MN",
|
||||||
|
"SD",
|
||||||
|
"ME",
|
||||||
|
"SZ",
|
||||||
|
"MA",
|
||||||
|
"SE",
|
||||||
|
"MZ",
|
||||||
|
"CH",
|
||||||
|
"NA",
|
||||||
|
"SY",
|
||||||
|
"NL",
|
||||||
|
"TJ",
|
||||||
|
"NE",
|
||||||
|
"TZ",
|
||||||
|
"NG",
|
||||||
|
"TG",
|
||||||
|
"NO",
|
||||||
|
"TN",
|
||||||
|
"OM",
|
||||||
|
"TR",
|
||||||
|
"PS",
|
||||||
|
"TM",
|
||||||
|
"PL",
|
||||||
|
"UG",
|
||||||
|
"PT",
|
||||||
|
"UA",
|
||||||
|
"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",
|
||||||
|
"--"
|
||||||
|
]
|
||||||
|
|
||||||
|
// RDS ECC Lookup Tables - Converted from C to JavaScript
|
||||||
|
|
||||||
|
const rdsEccA0A6Lut = [
|
||||||
|
// 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", null, "USA/VI/PR", "USA/VI/PR", null
|
||||||
|
],
|
||||||
|
// A1
|
||||||
|
[
|
||||||
|
null, null, null, null, null,
|
||||||
|
null, null, null, null, null,
|
||||||
|
"Canada", "Canada", "Canada", "Canada", "Greenland"
|
||||||
|
],
|
||||||
|
// A2
|
||||||
|
[
|
||||||
|
"Anguilla", "Antigua and Barbuda", "Brazil/Equator", "Falkland Islands", "Barbados",
|
||||||
|
"Belize", "Cayman Islands", "Costa Rica", "Cuba", "Argentina",
|
||||||
|
"Brazil", "Brazil/Bermuda", "Brazil/AN", "Guadeloupe", "Bahamas"
|
||||||
|
],
|
||||||
|
// A3
|
||||||
|
[
|
||||||
|
"Bolivia", "Colombia", "Jamaica", "Martinique", null,
|
||||||
|
"Paraguay", "Nicaragua", null, "Panama", "Dominica",
|
||||||
|
"Dominican Republic", "Chile", "Grenada", "Turks and Caicos islands", "Guyana"
|
||||||
|
],
|
||||||
|
// A4
|
||||||
|
[
|
||||||
|
"Guatemala", "Honduras", "Aruba", null, "Montserrat",
|
||||||
|
"Trinidad and Tobago", "Peru", "Suriname", "Uruguay", "St. Kitts",
|
||||||
|
"St. Lucia", "El Salvador", "Haiti", "Venezuela", "Virgin Islands"
|
||||||
|
],
|
||||||
|
// A5
|
||||||
|
[
|
||||||
|
null, null, null, null, null,
|
||||||
|
null, null, null, null, null,
|
||||||
|
"Mexico", "St. Vincent", "Mexico", "Mexico", "Mexico"
|
||||||
|
],
|
||||||
|
// A6
|
||||||
|
[
|
||||||
|
null, null, null, null, null,
|
||||||
|
null, null, null, null, null,
|
||||||
|
null, null, null, null, "St. Pierre and Miquelon"
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
const rdsEccD0D4Lut = [
|
||||||
|
// D0
|
||||||
|
[
|
||||||
|
"Cameroon", "Central African Republic", "Djiboutia", "Madagascar", "Mali",
|
||||||
|
"Angola", "Equatorial Guinea", "Gabon", "Guinea", "South Africa",
|
||||||
|
"Burkina Faso", "Republic of Congo", "Togo", "Benin", "Malawi"
|
||||||
|
],
|
||||||
|
// D1
|
||||||
|
[
|
||||||
|
"Namibia", "Liberia", "Ghana", "Mauritania", "Sao Tome and Principe",
|
||||||
|
"Cape Verde", "Senegal", "Gambia", "Burundi", "Ascension Island",
|
||||||
|
"Botswana", "Comoros", "Tanzania", "Ethiopia", "Nigeria"
|
||||||
|
],
|
||||||
|
// D2
|
||||||
|
[
|
||||||
|
"Sierra Leone", "Zimbabwe", "Mozambique", "Uganda", "Swaziland",
|
||||||
|
"Kenya", "Somalia", "Niger", "Chad", "Guinea-Bissau",
|
||||||
|
"DR Congo", "Cote d'Ivoire", null, "Zambia", "Eritrea"
|
||||||
|
],
|
||||||
|
// D3
|
||||||
|
[
|
||||||
|
null, null, "Western Sahara", "Cabinda", "Rwanda",
|
||||||
|
"Lesotho", null, "Seychelles", null, "Mauritius",
|
||||||
|
null, "Sudan", null, null, null
|
||||||
|
],
|
||||||
|
// D4
|
||||||
|
[
|
||||||
|
null, null, null, null, null,
|
||||||
|
null, null, null, null, "South Sudan",
|
||||||
|
null, null, null, null, null
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
const rdsEccE0E5Lut = [
|
||||||
|
// E0
|
||||||
|
[
|
||||||
|
"Germany", "Algeria", "Andorra", "Israel", "Italy",
|
||||||
|
"Belgium", "Russia", "Palestine", "Albania", "Austria",
|
||||||
|
"Hungary", "Malta", "Germany", null, "Egypt"
|
||||||
|
],
|
||||||
|
// E1
|
||||||
|
[
|
||||||
|
"Greece", "Cyprus", "San Marino", "Switzerland", "Jordan",
|
||||||
|
"Finland", "Luxembourg", "Bulgaria", "Denmark", "Gibraltar",
|
||||||
|
"Iraq", "United Kingdom", "Libya", "Romania", "France"
|
||||||
|
],
|
||||||
|
// E2
|
||||||
|
[
|
||||||
|
"Morocco", "Czechia", "Poland", "Vatican", "Slovakia",
|
||||||
|
"Syria", "Tunisia", null, "Liechtenstein", "Iceland",
|
||||||
|
"Monaco", "Lithuania", "Serbia", "Spain", "Norway"
|
||||||
|
],
|
||||||
|
// E3
|
||||||
|
[
|
||||||
|
"Montenegro", "Ireland", "Turkey", null, "Tajikistan",
|
||||||
|
null, null, "Netherlands", "Latvia", "Lebanon",
|
||||||
|
"Azerbaijan", "Croatia", "Kazakhstan", "Sweden", "Belarus"
|
||||||
|
],
|
||||||
|
// E4
|
||||||
|
[
|
||||||
|
"Moldova", "Estonia", "Macedonia", null, null,
|
||||||
|
"Ukraine", "Kosovo", "Portugal", "Slovenia", "Armenia",
|
||||||
|
"Uzbekistan", "Georgia", null, "Turkmenistan", "Bosnia Herzegovina"
|
||||||
|
],
|
||||||
|
// E5
|
||||||
|
[
|
||||||
|
null, null, "Kyrgyzstan", null, null,
|
||||||
|
null, null, null, null, null,
|
||||||
|
null, null, null, null, null
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
const rdsEccF0F4Lut = [
|
||||||
|
// F0
|
||||||
|
[
|
||||||
|
"Australia Capital Territory", "Australia New South Wales", "Australia Victoria", "Australia Queensland", "Australia South Australia",
|
||||||
|
"Australia Western Australia", "Australia Tasmania", "Australia Northern Territory", "Saudi Arabia", "Afghanistan",
|
||||||
|
"Myanmar", "China", "North Korea", "Bahrein", "Malaysia"
|
||||||
|
],
|
||||||
|
// F1
|
||||||
|
[
|
||||||
|
"Kiribati", "Bhutan", "Bangladesh", "Pakistan", "Fiji",
|
||||||
|
"Oman", "Nauru", "Iran", "New Zealand", "Solomon Islands",
|
||||||
|
"Brunei Darussalam", "Sri Lanka", "Taiwan", "South Korea", "Hong Kong"
|
||||||
|
],
|
||||||
|
// F2
|
||||||
|
[
|
||||||
|
"Kuwait", "Qatar", "Cambodia", "Samoa", "India",
|
||||||
|
"Macao", "Vietnam", "Philippines", "Japan", "Singapore",
|
||||||
|
"Maldives", "Indonesia", "United Arab Emirates", "Nepal", "Vanuatu"
|
||||||
|
],
|
||||||
|
// F3
|
||||||
|
[
|
||||||
|
"Laos", "Thailand", "Tonga", null, null,
|
||||||
|
null, null, "China", "Papua New Guinea", null,
|
||||||
|
"Yemen", null, null, "Micronesia", "Mongolia"
|
||||||
|
],
|
||||||
|
// F4
|
||||||
|
[
|
||||||
|
null, null, null, null, null,
|
||||||
|
null, null, null, "China", null,
|
||||||
|
"Marshall Islands", null, null, null, null
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
function rdsEccLookup(pi, ecc) {
|
||||||
|
const PI_UNKNOWN = -1;
|
||||||
|
|
||||||
|
const piCountry = (pi >> 12) & 0xF;
|
||||||
|
|
||||||
|
if (pi === PI_UNKNOWN || piCountry === 0) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const piId = piCountry - 1;
|
||||||
|
|
||||||
|
const eccRanges = [
|
||||||
|
{ min: 0xA0, max: 0xA6, lut: rdsEccA0A6Lut },
|
||||||
|
{ min: 0xD0, max: 0xD4, lut: rdsEccD0D4Lut },
|
||||||
|
{ min: 0xE0, max: 0xE5, lut: rdsEccE0E5Lut },
|
||||||
|
{ min: 0xF0, max: 0xF4, lut: rdsEccF0F4Lut }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Check each range
|
||||||
|
for (const range of eccRanges) {
|
||||||
|
if (ecc >= range.min && ecc <= range.max) {
|
||||||
|
const eccId = ecc - range.min;
|
||||||
|
return range.lut[eccId][piId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
rdsEccLookup,
|
||||||
|
iso,
|
||||||
|
countries
|
||||||
|
};
|
||||||
@@ -94,7 +94,7 @@ let serverConfig = {
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
username: "",
|
username: "",
|
||||||
token: "",
|
token: "",
|
||||||
region: "eu",
|
region: "pldx",
|
||||||
lowLatencyMode: false,
|
lowLatencyMode: false,
|
||||||
subdomain: "",
|
subdomain: "",
|
||||||
httpName: "",
|
httpName: "",
|
||||||
|
|||||||
@@ -11,11 +11,8 @@ function checkFFmpeg() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
checkFFmpegProcess.on('exit', (code) => {
|
checkFFmpegProcess.on('exit', (code) => {
|
||||||
if (code === 0) {
|
if (code === 0) resolve('ffmpeg');
|
||||||
resolve('ffmpeg');
|
else resolve(require('ffmpeg-static'));
|
||||||
} else {
|
|
||||||
resolve(require('ffmpeg-static'));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,9 +74,7 @@ function parseAudioDevice(options, callback) {
|
|||||||
if (platform === 'win32' && line.search(/Alternative\sname/) > -1) {
|
if (platform === 'win32' && line.search(/Alternative\sname/) > -1) {
|
||||||
const lastDevice = deviceList[deviceList.length - 1];
|
const lastDevice = deviceList[deviceList.length - 1];
|
||||||
const alt = line.match(alternativeName);
|
const alt = line.match(alternativeName);
|
||||||
if (lastDevice && alt) {
|
if (lastDevice && alt) lastDevice.alternativeName = alt[1];
|
||||||
lastDevice.alternativeName = alt[1];
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,11 +105,8 @@ function parseAudioDevice(options, callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (callbackExists) {
|
if (callbackExists) execute();
|
||||||
execute();
|
else return new Promise(execute);
|
||||||
} else {
|
|
||||||
return new Promise(execute);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { parseAudioDevice };
|
module.exports = { parseAudioDevice };
|
||||||
@@ -25,9 +25,7 @@ async function connect() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch('https://fmtuner.org/binaries/' + frpcFileName);
|
const res = await fetch('https://fmtuner.org/binaries/' + frpcFileName);
|
||||||
if (res.status === 404) {
|
if (res.status === 404) throw new Error('404 error');
|
||||||
throw new Error('404 error');
|
|
||||||
}
|
|
||||||
const stream = fs2.createWriteStream(frpcPath);
|
const stream = fs2.createWriteStream(frpcPath);
|
||||||
await finished(Readable.fromWeb(res.body).pipe(stream));
|
await finished(Readable.fromWeb(res.body).pipe(stream));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -41,7 +39,7 @@ async function connect() {
|
|||||||
}
|
}
|
||||||
const cfg = ejs.render(frpcConfigTemplate, {
|
const cfg = ejs.render(frpcConfigTemplate, {
|
||||||
cfg: serverConfig.tunnel,
|
cfg: serverConfig.tunnel,
|
||||||
host: serverConfig.tunnel.community.enabled ? serverConfig.tunnel.community.host : serverConfig.tunnel.region + ".fmtuner.org",
|
host: serverConfig.tunnel.community.enabled ? serverConfig.tunnel.community.host : ((serverConfig.tunnel.region == "pldx") ? "pldx.duckdns.org" : (serverConfig.tunnel.region + ".fmtuner.org")),
|
||||||
server: {
|
server: {
|
||||||
port: serverConfig.webserver.webserverPort
|
port: serverConfig.webserver.webserverPort
|
||||||
}
|
}
|
||||||
@@ -62,15 +60,10 @@ async function connect() {
|
|||||||
if (line.includes('connect to server error')) {
|
if (line.includes('connect to server error')) {
|
||||||
const reason = line.substring(line.indexOf(': ')+2);
|
const reason = line.substring(line.indexOf(': ')+2);
|
||||||
logError('Failed to connect to tunnel, reason: ' + reason);
|
logError('Failed to connect to tunnel, reason: ' + reason);
|
||||||
} else if (line.includes('invalid user or token')) {
|
} else if (line.includes('invalid user or token')) logError('Failed to connect to tunnel, reason: invalid user or token');
|
||||||
logError('Failed to connect to tunnel, reason: invalid user or token');
|
else if (line.includes('start proxy success')) logInfo('Tunnel established successfully');
|
||||||
} else if (line.includes('start proxy success')) {
|
else if (line.includes('login to server success')) logInfo('Connection to tunnel server was successful');
|
||||||
logInfo('Tunnel established successfully');
|
else logDebug('Tunnel log:', line);
|
||||||
} else if (line.includes('login to server success')) {
|
|
||||||
logInfo('Connection to tunnel server was successful');
|
|
||||||
} else {
|
|
||||||
logDebug('Tunnel log:', line);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
child.on('error', (err) => {
|
child.on('error', (err) => {
|
||||||
|
|||||||
@@ -116,11 +116,8 @@ function initBanlist() {
|
|||||||
data: { ip: ipAddress, reason: reason },
|
data: { ip: ipAddress, reason: reason },
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
// Refresh the page if the request was successful
|
// Refresh the page if the request was successful
|
||||||
if (response.success) {
|
if (response.success) location.reload();
|
||||||
location.reload();
|
else console.error('Failed to add to banlist');
|
||||||
} else {
|
|
||||||
console.error('Failed to add to banlist');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
console.error('Error occurred during the request');
|
console.error('Error occurred during the request');
|
||||||
|
|||||||
@@ -699,7 +699,8 @@
|
|||||||
<div class="panel-100 p-bottom-20">
|
<div class="panel-100 p-bottom-20">
|
||||||
<h3>Tunnel</h3>
|
<h3>Tunnel</h3>
|
||||||
<p>When you become an <a href="https://buymeacoffee.com/fmdx" target="_blank"><strong>FMDX.org supporter</strong></a>, you can host your webserver without the need of a public IP address & port forwarding.<br>
|
<p>When you become an <a href="https://buymeacoffee.com/fmdx" target="_blank"><strong>FMDX.org supporter</strong></a>, you can host your webserver without the need of a public IP address & port forwarding.<br>
|
||||||
When you become a supporter, you can message the Founders on Discord for your login details.</p>
|
When you become a supporter, you can message the Founders on Discord for your login details.</p><br>
|
||||||
|
<p>You can also get an tunnel from kuba201 discord, one of the contributors of this version of the application.</p>
|
||||||
<h4>Main tunnel settings</h4>
|
<h4>Main tunnel settings</h4>
|
||||||
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Enable tunnel', id: 'tunnel-enabled'}) %><br>
|
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Enable tunnel', id: 'tunnel-enabled'}) %><br>
|
||||||
<%- include('_components', { component: 'dropdown', id: 'tunnel-server', inputId: 'tunnel-serverSelect', label: 'Official server region', cssClass: '', placeholder: 'Europe',
|
<%- include('_components', { component: 'dropdown', id: 'tunnel-server', inputId: 'tunnel-serverSelect', label: 'Official server region', cssClass: '', placeholder: 'Europe',
|
||||||
@@ -707,6 +708,7 @@
|
|||||||
{ value: 'eu', label: 'Europe' },
|
{ value: 'eu', label: 'Europe' },
|
||||||
{ value: 'us', label: 'Americas' },
|
{ value: 'us', label: 'Americas' },
|
||||||
{ value: 'sg', label: 'Asia & Oceania' },
|
{ value: 'sg', label: 'Asia & Oceania' },
|
||||||
|
{ value: 'pldx', label: 'Poland (k201)' },
|
||||||
]
|
]
|
||||||
}) %>
|
}) %>
|
||||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Username', id: 'tunnel-username'}) %>
|
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Username', id: 'tunnel-username'}) %>
|
||||||
|
|||||||
Reference in New Issue
Block a user