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
TX ID, UI fixes
This commit is contained in:
@@ -7,6 +7,7 @@ const os = require('os');
|
||||
const win32 = (os.platform() == "win32");
|
||||
const unicode_type = (win32 ? 'int16_t' : 'int32_t');
|
||||
const lib = koffi.load(path.join(__dirname, "librdsparser." + (win32 ? "dll" : "so")));
|
||||
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)');
|
||||
@@ -206,6 +207,15 @@ var dataToSend = {
|
||||
ims: 0,
|
||||
eq: 0,
|
||||
ant: 0,
|
||||
txInfo: {
|
||||
station: '',
|
||||
pol: '',
|
||||
erp: '',
|
||||
city: '',
|
||||
itu: '',
|
||||
distance: '',
|
||||
azimuth: ''
|
||||
},
|
||||
country_name: '',
|
||||
country_iso: 'UN',
|
||||
users: '',
|
||||
@@ -215,6 +225,7 @@ var legacyRdsPiBuffer = null;
|
||||
const initialData = { ...dataToSend };
|
||||
const resetToDefault = dataToSend => Object.assign(dataToSend, initialData);
|
||||
|
||||
|
||||
function handleData(ws, receivedData) {
|
||||
// Retrieve the last update time for this client
|
||||
let lastUpdateTime = clientUpdateIntervals.get(ws) || 0;
|
||||
@@ -329,6 +340,20 @@ function handleData(ws, receivedData) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get the received TX info
|
||||
const currentTx = fetchTx(dataToSend.freq, dataToSend.pi, dataToSend.ps);
|
||||
if(currentTx.station !== undefined) {
|
||||
dataToSend.txInfo = {
|
||||
station: currentTx.station,
|
||||
pol: currentTx.pol,
|
||||
erp: currentTx.erp,
|
||||
city: currentTx.city,
|
||||
itu: currentTx.itu,
|
||||
distance: currentTx.distance,
|
||||
azimuth: currentTx.azimuth
|
||||
}
|
||||
}
|
||||
|
||||
// Send the updated data to the client
|
||||
const dataToSendJSON = JSON.stringify(dataToSend);
|
||||
if (currentTime - lastUpdateTime >= updateInterval) {
|
||||
|
||||
131
index.js
131
index.js
@@ -10,7 +10,6 @@ const http = require('http');
|
||||
const https = require('https');
|
||||
const app = express();
|
||||
const httpServer = http.createServer(app);
|
||||
const ejs = require('ejs');
|
||||
|
||||
// Websocket handling
|
||||
const WebSocket = require('ws');
|
||||
@@ -43,13 +42,13 @@ let serverConfig = {
|
||||
xdrd: {
|
||||
xdrdIp: "127.0.0.1",
|
||||
xdrdPort: "7373",
|
||||
xdrdPassword: "password"
|
||||
xdrdPassword: ""
|
||||
},
|
||||
identification: {
|
||||
tunerName: "",
|
||||
tunerDesc: "",
|
||||
lat: "",
|
||||
lon: ""
|
||||
lat: "0",
|
||||
lon: "0"
|
||||
},
|
||||
password: {
|
||||
tunePass: "",
|
||||
@@ -102,78 +101,80 @@ function authenticateWithXdrd(client, salt, password) {
|
||||
}
|
||||
|
||||
// xdrd connection
|
||||
client.connect(serverConfig.xdrd.xdrdPort, serverConfig.xdrd.xdrdIp, () => {
|
||||
logInfo('Connection to xdrd established successfully.');
|
||||
if (serverConfig.xdrd.xdrdPassword.length > 1) {
|
||||
client.connect(serverConfig.xdrd.xdrdPort, serverConfig.xdrd.xdrdIp, () => {
|
||||
logInfo('Connection to xdrd established successfully.');
|
||||
|
||||
const authFlags = {
|
||||
authMsg: false,
|
||||
firstClient: false,
|
||||
receivedPassword: false
|
||||
};
|
||||
const authFlags = {
|
||||
authMsg: false,
|
||||
firstClient: false,
|
||||
receivedPassword: false
|
||||
};
|
||||
|
||||
const authDataHandler = (data) => {
|
||||
const receivedData = data.toString();
|
||||
const lines = receivedData.split('\n');
|
||||
const authDataHandler = (data) => {
|
||||
const receivedData = data.toString();
|
||||
const lines = receivedData.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
for (const line of lines) {
|
||||
|
||||
if (!authFlags.receivedPassword) {
|
||||
authFlags.receivedSalt = line.trim();
|
||||
authenticateWithXdrd(client, authFlags.receivedSalt, serverConfig.xdrd.xdrdPassword);
|
||||
authFlags.receivedPassword = true;
|
||||
} else {
|
||||
if (line.startsWith('a')) {
|
||||
authFlags.authMsg = true;
|
||||
logWarn('Authentication with xdrd failed. Is your password set correctly?');
|
||||
} else if (line.startsWith('o1,')) {
|
||||
authFlags.firstClient = true;
|
||||
} else if (line.startsWith('T') && line.length <= 7) {
|
||||
const freq = line.slice(1) / 1000;
|
||||
dataHandler.dataToSend.freq = freq.toFixed(3);
|
||||
} else if (line.startsWith('OK')) {
|
||||
authFlags.authMsg = true;
|
||||
logInfo('Authentication with xdrd successful.');
|
||||
}
|
||||
if (!authFlags.receivedPassword) {
|
||||
authFlags.receivedSalt = line.trim();
|
||||
authenticateWithXdrd(client, authFlags.receivedSalt, serverConfig.xdrd.xdrdPassword);
|
||||
authFlags.receivedPassword = true;
|
||||
} else {
|
||||
if (line.startsWith('a')) {
|
||||
authFlags.authMsg = true;
|
||||
logWarn('Authentication with xdrd failed. Is your password set correctly?');
|
||||
} else if (line.startsWith('o1,')) {
|
||||
authFlags.firstClient = true;
|
||||
} else if (line.startsWith('T') && line.length <= 7) {
|
||||
const freq = line.slice(1) / 1000;
|
||||
dataHandler.dataToSend.freq = freq.toFixed(3);
|
||||
} else if (line.startsWith('OK')) {
|
||||
authFlags.authMsg = true;
|
||||
logInfo('Authentication with xdrd successful.');
|
||||
}
|
||||
|
||||
if (authFlags.authMsg && authFlags.firstClient) {
|
||||
client.write('T87500\n');
|
||||
client.write('A0\n');
|
||||
client.write('G11\n');
|
||||
client.off('data', authDataHandler);
|
||||
return;
|
||||
if (authFlags.authMsg && authFlags.firstClient) {
|
||||
client.write('T87500\n');
|
||||
client.write('A0\n');
|
||||
client.write('G11\n');
|
||||
client.off('data', authDataHandler);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
client.on('data', (data) => {
|
||||
var receivedData = incompleteDataBuffer + data.toString();
|
||||
const isIncomplete = (receivedData.slice(-1) != '\n');
|
||||
client.on('data', (data) => {
|
||||
var receivedData = incompleteDataBuffer + data.toString();
|
||||
const isIncomplete = (receivedData.slice(-1) != '\n');
|
||||
|
||||
if (isIncomplete) {
|
||||
const position = receivedData.lastIndexOf('\n');
|
||||
if (position < 0) {
|
||||
incompleteDataBuffer = receivedData;
|
||||
receivedData = '';
|
||||
} else {
|
||||
incompleteDataBuffer = receivedData.slice(position + 1);
|
||||
receivedData = receivedData.slice(0, position + 1);
|
||||
}
|
||||
} else {
|
||||
incompleteDataBuffer = '';
|
||||
}
|
||||
|
||||
if (receivedData.length) {
|
||||
wss.clients.forEach((client) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
dataHandler.handleData(client, receivedData);
|
||||
if (isIncomplete) {
|
||||
const position = receivedData.lastIndexOf('\n');
|
||||
if (position < 0) {
|
||||
incompleteDataBuffer = receivedData;
|
||||
receivedData = '';
|
||||
} else {
|
||||
incompleteDataBuffer = receivedData.slice(position + 1);
|
||||
receivedData = receivedData.slice(0, position + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
incompleteDataBuffer = '';
|
||||
}
|
||||
|
||||
if (receivedData.length) {
|
||||
wss.clients.forEach((client) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
dataHandler.handleData(client, receivedData);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
client.on('data', authDataHandler);
|
||||
});
|
||||
|
||||
client.on('data', authDataHandler);
|
||||
});
|
||||
}
|
||||
|
||||
client.on('close', () => {
|
||||
logWarn('Disconnected from xdrd.');
|
||||
|
||||
@@ -23,15 +23,15 @@ function enableAudioStream() {
|
||||
// Specify the command and its arguments
|
||||
const command = 'ffmpeg';
|
||||
const flags = `-fflags +nobuffer+flush_packets -flags low_delay -rtbufsize 6192 -probesize 32`;
|
||||
const codec = `-acodec pcm_s16le -ar 32000 -ac ${serverConfig.audio.audioChannels}`;
|
||||
const codec = `-acodec pcm_s16le -ar 48000 -ac ${serverConfig.audio.audioChannels}`;
|
||||
const output = `-f s16le -fflags +nobuffer+flush_packets -packetsize 384 -flush_packets 1 -bufsize 960`;
|
||||
// Combine all the settings for the ffmpeg command
|
||||
if (process.platform === 'win32') {
|
||||
// Windows
|
||||
ffmpegCommand = `${flags} -f dshow -i audio="${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node stream/3las.server.js -port ${serverConfig.webserver.audioPort} -samplerate 32000 -channels ${serverConfig.audio.audioChannels}`;
|
||||
ffmpegCommand = `${flags} -f dshow -i audio="${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node stream/3las.server.js -port ${serverConfig.webserver.audioPort} -samplerate 48000 -channels ${serverConfig.audio.audioChannels}`;
|
||||
} else {
|
||||
// Linux
|
||||
ffmpegCommand = `${flags} -f alsa -i "${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node stream/3las.server.js -port ${serverConfig.webserver.audioPort} -samplerate 32000 -channels ${serverConfig.audio.audioChannels}`;
|
||||
ffmpegCommand = `${flags} -f alsa -i "${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node stream/3las.server.js -port ${serverConfig.webserver.audioPort} -samplerate 48000 -channels ${serverConfig.audio.audioChannels}`;
|
||||
}
|
||||
|
||||
consoleCmd.logInfo("Using audio device: " + serverConfig.audio.audioDevice);
|
||||
|
||||
127
tx_search.js
Normal file
127
tx_search.js
Normal file
@@ -0,0 +1,127 @@
|
||||
const fetch = require('node-fetch');
|
||||
var fs = require('fs');
|
||||
|
||||
let cachedData = {};
|
||||
|
||||
let serverConfig = {
|
||||
identification: {
|
||||
lat: 0,
|
||||
lon: 0
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
if(fs.existsSync('config.json')) {
|
||||
const configFileContents = fs.readFileSync('config.json', 'utf8');
|
||||
serverConfig = JSON.parse(configFileContents);
|
||||
}
|
||||
|
||||
let lastFetchTime = 0;
|
||||
const fetchInterval = 3000;
|
||||
|
||||
// Fetch data from maps
|
||||
function fetchTx(freq, piCode, rdsPs) {
|
||||
const now = Date.now();
|
||||
|
||||
// Check if it's been at least 3 seconds since the last fetch and if the QTH is correct
|
||||
if (now - lastFetchTime < fetchInterval || serverConfig.identification.lat.length < 2) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
lastFetchTime = now;
|
||||
|
||||
// Check if data for the given frequency is already cached
|
||||
if (cachedData[freq]) {
|
||||
return processData(cachedData[freq], piCode, rdsPs);
|
||||
}
|
||||
|
||||
const url = "https://maps.fmdx.pl/controller.php?freq=" + freq;
|
||||
|
||||
return fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Cache the fetched data for the specific frequency
|
||||
cachedData[freq] = data;
|
||||
return processData(data, piCode, rdsPs);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error fetching data:", error);
|
||||
});
|
||||
}
|
||||
|
||||
function processData(data, piCode, rdsPs) {
|
||||
let matchingStation = null;
|
||||
let matchingCity = null;
|
||||
let minDistance = Infinity;
|
||||
let txAzimuth;
|
||||
|
||||
for (const cityId in data.locations) {
|
||||
const city = data.locations[cityId];
|
||||
if (city.stations) {
|
||||
for (const station of city.stations) {
|
||||
if (station.pi === piCode && station.ps.includes(rdsPs.replace(/ /g, '_'))) {
|
||||
const distance = haversine(serverConfig.identification.lat, serverConfig.identification.lon, city.lat, city.lon);
|
||||
if (distance.distanceKm < minDistance) {
|
||||
minDistance = distance.distanceKm;
|
||||
txAzimuth = distance.azimuth;
|
||||
matchingStation = station;
|
||||
matchingCity = city;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingStation) {
|
||||
return {
|
||||
station: matchingStation.station.replace("R.", "Radio "),
|
||||
pol: matchingStation.pol.toUpperCase(),
|
||||
erp: matchingStation.erp,
|
||||
city: matchingCity.name,
|
||||
itu: matchingCity.itu,
|
||||
distance: minDistance.toFixed(0),
|
||||
azimuth: txAzimuth.toFixed(0),
|
||||
foundStation: true
|
||||
};
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function haversine(lat1, lon1, lat2, lon2) {
|
||||
const R = 6371; // Earth radius in kilometers
|
||||
const dLat = deg2rad(lat2 - lat1);
|
||||
const dLon = deg2rad(lon2 - lon1);
|
||||
|
||||
const a =
|
||||
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
||||
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
|
||||
// Distance in kilometers
|
||||
const distance = R * c;
|
||||
|
||||
// Azimuth calculation
|
||||
const y = Math.sin(dLon) * Math.cos(deg2rad(lat2));
|
||||
const x = Math.cos(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) -
|
||||
Math.sin(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(dLon);
|
||||
const azimuth = Math.atan2(y, x);
|
||||
|
||||
// Convert azimuth from radians to degrees
|
||||
const azimuthDegrees = (azimuth * 180 / Math.PI + 360) % 360;
|
||||
|
||||
return {
|
||||
distanceKm: distance,
|
||||
azimuth: azimuthDegrees
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function deg2rad(deg) {
|
||||
return deg * (Math.PI / 180);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchTx
|
||||
};
|
||||
@@ -20,6 +20,12 @@ h3 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
p#tuner-desc {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -54,6 +60,10 @@ label {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#data-station-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
float: left;
|
||||
margin-bottom: 10px;
|
||||
|
||||
@@ -58,6 +58,14 @@
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.opacity-full {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.opacity-half {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
<link rel="icon" type="image/png" href="favicon2.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<meta property="og:title" content="FM-DX WebServer">
|
||||
<meta property="og:title" content="FM-DX WebServer [<%= tunerName %>]">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:image" content="favicon2.png">
|
||||
<meta property="og:description" content="This server us running the FM-DX Webserver software by Noobish.">
|
||||
<meta property="og:description" content="Server description: <%= tunerDesc %>.">
|
||||
|
||||
<!-- 3LAS Scripts for Audio streaming -->
|
||||
<script src="js/3las/util/3las.helpers.js"></script>
|
||||
@@ -27,18 +27,6 @@
|
||||
<script src="js/3las/3las.js"></script>
|
||||
<script src="js/3las/main.js"></script>
|
||||
<script type="text/javascript">
|
||||
var RtcConfig = {
|
||||
|
||||
iceServers: [
|
||||
{
|
||||
urls: "turns:turnserver.example.org",
|
||||
},
|
||||
{
|
||||
urls: "stun.l.google.com:19302"
|
||||
}
|
||||
]
|
||||
|
||||
};
|
||||
var AudioTagId = "audioTag";
|
||||
window.addEventListener('load', Init, false);
|
||||
document.ontouchmove = function(e){
|
||||
@@ -74,14 +62,14 @@
|
||||
<h2 class="show-phone">
|
||||
<div class="data-pty" style="color:white;"></div>
|
||||
</h2>
|
||||
<h3 style="margin-top:0;margin-bottom:0;" class="flex-center">
|
||||
<span class="data-tp color-4">TP</span>
|
||||
<span style="margin-left: 15px;" class="data-ta color-4">TA</span>
|
||||
<h3 style="margin-top:0;margin-bottom:0;" class="color-4 flex-center">
|
||||
<span class="data-tp">TP</span>
|
||||
<span style="margin-left: 15px;" class="data-ta">TA</span>
|
||||
<div style="display:inline-block">
|
||||
<span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span>
|
||||
</div>
|
||||
<span style="margin-left: 20px; color: #ff5776;" class="data-st"></span>
|
||||
<span style="margin-left: 15px;" class="data-ms"><span style="color: #ff5776">M</span><span class="text-gray">S</span></span>
|
||||
<span style="margin-left: 20px;" class="data-st">ST</span>
|
||||
<span style="margin-left: 15px;" class="data-ms">MS</span>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
@@ -144,18 +132,22 @@
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="panel-75 hover-brighten" id="rt-container" style="height: 110px;">
|
||||
<h2 style="margin: 0;">RADIOTEXT</h2>
|
||||
<h2 style="margin-top: 4px;">RADIOTEXT</h2>
|
||||
<div id="data-rt0"></div>
|
||||
<div id="data-rt1"></div>
|
||||
<div id="data-container" style="display: none;"></div>
|
||||
</div>
|
||||
|
||||
<div class="panel-33">
|
||||
<h2>
|
||||
<div style="color:white;"></div>
|
||||
</h2>
|
||||
<h3 style="margin-top:0;" class="flex-center">
|
||||
</h3>
|
||||
<div class="panel-33 hover-brighten">
|
||||
<div id="data-station-container">
|
||||
<h2 style="margin-top: 4px;">
|
||||
<span id="data-station-name"></span>
|
||||
</h2>
|
||||
<h4 class="m-0">
|
||||
<span id="data-station-city"></span>, <span id="data-station-itu"></span>
|
||||
</h4>
|
||||
<span id="data-station-erp"></span> kW [<span id="data-station-pol"></span>] <span class="text-gray">•</span> <span id="data-station-distance"></span> km <span class="text-gray">•</span> <span id="data-station-azimuth"></span>°
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -176,14 +168,14 @@
|
||||
<h2 class="show-phone">
|
||||
<div class="data-pty" style="color:white;"></div>
|
||||
</h2>
|
||||
<h3 style="margin-top:0;margin-bottom:0;" class="flex-center">
|
||||
<span class="data-tp color-4">TP</span>
|
||||
<span style="margin-left: 15px;" class="data-ta color-4">TA</span>
|
||||
<h3 style="margin-top:0;margin-bottom:0;" class="color-4 flex-center">
|
||||
<span class="data-tp">TP</span>
|
||||
<span style="margin-left: 15px;" class="data-ta">TA</span>
|
||||
<div style="display:inline-block">
|
||||
<span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span>
|
||||
</div>
|
||||
<span style="margin-left: 20px; color: #ff5776;" class="data-st"></span>
|
||||
<span style="margin-left: 15px;" class="data-ms"><span style="color: #ff5776">M</span><span class="text-gray">S</span></span>
|
||||
<span style="margin-left: 20px;" class="data-st"></span>
|
||||
<span style="margin-left: 15px;" class="data-ms">MS</span>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
@@ -248,9 +240,9 @@
|
||||
<div class="flex-container flex-left text-left bottom-20 hover-brighten p-10 br-5" onclick="window.open('https://buymeacoffee.com/noobish')">
|
||||
<i class="fa-solid fa-hand-holding-medical"></i> <span><strong>Support</strong> the developer!</span>
|
||||
</div>
|
||||
<p class="text-small">FM-DX WebServer <span style="color: var(--color-3);">v1.0.0 [4/2/2024]</span> by <a href="https://noobish.eu" target="_blank">Noobish</a> & the OpenRadio community.</p>
|
||||
<p class="text-small">FM-DX WebServer <span style="color: var(--color-3);">v1.0.1 [5/2/2024]</span> by <a href="https://noobish.eu" target="_blank">Noobish</a> & the OpenRadio community.</p>
|
||||
<p class="text-small bottom-50">This app works thanks to these amazing projects: <br>
|
||||
<span class="text-smaller">- librdsparser by <a href="https://fmdx.pl" target="_blank">Konrad Kosmatka</a></span><br>
|
||||
<span class="text-smaller">- librdsparser & maps.fmdx.pl by <a href="https://fmdx.pl" target="_blank">Konrad Kosmatka</a></span><br>
|
||||
<span class="text-smaller">- 3LAS by <a href="https://github.com/JoJoBond/3LAS" target="_blank">JoJoBond</a></span><br>
|
||||
<span class="text-smaller">- flat-flags by <a href="https://github.com/luishdez/flat-flags/tree/master" target="_blank">luishdez</a></span><br></p>
|
||||
<button class="button-close" id="closeModalButton">Close</button>
|
||||
|
||||
@@ -99,6 +99,7 @@ $(document).ready(function() {
|
||||
var rtContainer = $('#rt-container')[0];
|
||||
var piCodeContainer = $('#pi-code-container')[0];
|
||||
var freqContainer = $('#freq-container')[0];
|
||||
var txContainer = $('#data-station-container')[0];
|
||||
|
||||
$("#data-eq").click(function () {
|
||||
toggleButtonState("eq");
|
||||
@@ -112,6 +113,7 @@ $(document).ready(function() {
|
||||
$(freqDownButton).on("click", tuneDown);
|
||||
$(psContainer).on("click", copyPs);
|
||||
$(rtContainer).on("click", copyRt);
|
||||
$(txContainer).on("click", copyTx);
|
||||
$(piCodeContainer).on("click", findOnMaps);
|
||||
$(freqContainer).on("click", function() {
|
||||
textInput.focus();
|
||||
@@ -353,6 +355,22 @@ async function copyPs() {
|
||||
}
|
||||
}
|
||||
|
||||
async function copyTx() {
|
||||
const frequency = $('#data-frequency').text();
|
||||
const pi = $('#data-pi').text();
|
||||
const stationName = $('#data-station-name').text();
|
||||
const stationCity = $('#data-station-city').text();
|
||||
const stationItu = $('#data-station-itu').text();
|
||||
const stationDistance = $('#data-station-distance').text();
|
||||
const stationErp = $('#data-station-erp').text();
|
||||
|
||||
try {
|
||||
await copyToClipboard(frequency + " - " + pi + " | " + stationName + " [" + stationCity + ", " + stationItu + "] - " + stationDistance + " km | " + stationErp + " kW");
|
||||
} catch(error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function copyRt() {
|
||||
var rt0 = $('#data-rt0').text();
|
||||
var rt1 = $('#data-rt1').text();
|
||||
@@ -434,15 +452,15 @@ function updateSignalUnits(parsedData) {
|
||||
|
||||
function updateDataElements(parsedData) {
|
||||
$('#data-frequency').text(parsedData.freq);
|
||||
$('#data-pi').html(parsedData.pi === '?' ? "<span class='text-gray'>?</span>" : parsedData.pi);
|
||||
$('#data-ps').html(parsedData.ps === '?' ? "<span class='text-gray'>?</span>" : processString(parsedData.ps, parsedData.ps_errors));
|
||||
$('.data-tp').html(parsedData.tp === false ? "<span class='text-gray'>TP</span>" : "TP");
|
||||
$('.data-ta').html(parsedData.ta === 0 ? "<span class='text-gray'>TA</span>" : "TA");
|
||||
$('#data-pi').html(parsedData.pi === '?' ? "<span class='opacity-half'>?</span>" : parsedData.pi);
|
||||
$('#data-ps').html(parsedData.ps === '?' ? "<span class='opacity-half'>?</span>" : processString(parsedData.ps, parsedData.ps_errors));
|
||||
$('.data-tp').html(parsedData.tp === false ? "<span class='opacity-half'>TP</span>" : "TP");
|
||||
$('.data-ta').html(parsedData.ta === 0 ? "<span class='opacity-half'>TA</span>" : "TA");
|
||||
$('.data-ms').html(parsedData.ms === 0
|
||||
? "<span class='text-gray'>M</span><span class='text-red'>S</span>"
|
||||
? "<span class='opacity-half'>M</span><span class='opacity-full'>S</span>"
|
||||
: (parsedData.ms === -1
|
||||
? "<span class='text-gray'>M</span><span class='text-gray'>S</span>"
|
||||
: "<span class='text-red'>M</span><span class='text-gray'>S</span>"
|
||||
? "<span class='opacity-half'>M</span><span class='opacity-half'>S</span>"
|
||||
: "<span class='opacity-full'>M</span><span class='opacity-half'>S</span>"
|
||||
)
|
||||
);
|
||||
$('.data-pty').html(europe_programmes[parsedData.pty]);
|
||||
@@ -451,6 +469,19 @@ function updateDataElements(parsedData) {
|
||||
$('#data-rt1').html(processString(parsedData.rt1, parsedData.rt1_errors));
|
||||
$('.data-flag').html(`<i title="${parsedData.country_name}" class="flag-sm flag-sm-${parsedData.country_iso}"></i>`);
|
||||
$('#data-ant input').val($('#data-ant li[data-value="' + parsedData.ant + '"]').text());
|
||||
|
||||
if(parsedData.txInfo.station.length > 1) {
|
||||
$('#data-station-name').text(decodeURIComponent(parsedData.txInfo.station.replace(/\u009e/g, '\u017E')));
|
||||
$('#data-station-erp').text(parsedData.txInfo.erp);
|
||||
$('#data-station-city').text(parsedData.txInfo.city);
|
||||
$('#data-station-itu').text(parsedData.txInfo.itu);
|
||||
$('#data-station-pol').text(parsedData.txInfo.pol);
|
||||
$('#data-station-distance').text(parsedData.txInfo.distance);
|
||||
$('#data-station-azimuth').text(parsedData.txInfo.azimuth);
|
||||
$('#data-station-container').css('display', 'block');
|
||||
} else {
|
||||
$('#data-station-container').removeAttr('style');
|
||||
}
|
||||
}
|
||||
|
||||
let isEventListenerAdded = false;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="xdrd-password">xdrd server password:</label>
|
||||
<input class="input-text w-150" type="text" name="xdrd-password" id="xdrd-password">
|
||||
<input class="input-text w-150" type="password" name="xdrd-password" id="xdrd-password">
|
||||
</div>
|
||||
<br>
|
||||
<h3>Webserver connection:</h3>
|
||||
@@ -136,11 +136,11 @@
|
||||
</div><br>
|
||||
<div class="form-group">
|
||||
<label for="tune-pass">Tune password:</label>
|
||||
<input class="input-text w-150" type="text" name="tune-pass" id="tune-pass">
|
||||
<input class="input-text w-150" type="password" name="tune-pass" id="tune-pass">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 40px;">
|
||||
<label for="admin-pass">Admin setup password:</label>
|
||||
<input class="input-text w-150" type="text" name="admin-pass" id="admin-pass">
|
||||
<input class="input-text w-150" type="password" name="admin-pass" id="admin-pass">
|
||||
</div><br>
|
||||
<button style="height:48px; width: 200px;margin-bottom:20px;" onclick="submitData();">Save settings</button>
|
||||
<button style="height: 48px; width: 200px;background:var(--color-3)" class="logout-link">Logout</button>
|
||||
|
||||
Reference in New Issue
Block a user