// GridTracker Copyright © 2024 GridTracker.org // All rights reserved. // See LICENSE for more information. GT.alerts = Object(); GT.classicAlerts = Object(); GT.phonetics = Object(); GT.enums = Object(); GT.speechSettings = Object(); GT.audioSettings = Object(); GT.speechAvailable = false; GT.alertSettings = Object(); function loadAlerts() { if (typeof localStorage.classicAlertsVersion == "undefined") { GT.classicAlerts = { huntCallsign: false, huntGrid: false, huntDXCC: false, huntCQz: false, huntITUz: false, huntStates: false, huntCallsignNeed: "worked", huntGridNeed: "confirmed", huntDXCCNeed: "confirmed", huntCQzNeed: "confirmed", huntITUzNeed: "confirmed", huntStatesNeed: "confirmed", huntCallsignNotify: "1", huntGridNotify: "1", huntDXCCNotify: "1", huntCQzNotify: "1", huntITUzNotify: "1", huntStatesNotify: "1", huntCallsignNotifyWord: "Wanted Call", huntGridNotifyWord: "Wanted Grid", huntDXCCNotifyWord: "Wanted DXCC", huntCQzNotifyWord: "Wanted CQ Zone", huntITUzNotifyWord: "Wanted I-T-U Zone", huntStatesNotifyWord: "Wanted State", huntCallsignNotifyMedia: "none", huntGridNotifyMedia: "none", huntDXCCNotifyMedia: "none", huntCQzNotifyMedia: "none", huntITUzNotifyMedia: "none", huntStatesNotifyMedia: "none" }; localStorage.classicAlerts = JSON.stringify(GT.classicAlerts); GT.alertSettings = Object(); GT.alertSettings.requireGrid = true; GT.alertSettings.wantMaxDT = false; GT.alertSettings.wantMinDB = false; GT.alertSettings.wantMinFreq = false; GT.alertSettings.wantMaxFreq = false; GT.alertSettings.maxDT = 0.5; GT.alertSettings.minDb = -24; GT.alertSettings.minFreq = 400; GT.alertSettings.maxFreq = 3500; GT.alertSettings.noMyDxcc = false; GT.alertSettings.onlyMyDxcc = false; GT.alertSettings.noRoundUp = false; GT.alertSettings.onlyRoundUp = false; GT.alertSettings.cqOnly = true; GT.alertSettings.usesLoTW = false; GT.alertSettings.useseQSL = false; GT.alertSettings.reference = 0; GT.alertSettings.logEventMedia = "Ping-coin.mp3"; localStorage.alertSettings = JSON.stringify(GT.alertSettings); localStorage.classicAlertsVersion = gtVersion; } else { GT.classicAlerts = JSON.parse(localStorage.classicAlerts); GT.alertSettings = JSON.parse(localStorage.alertSettings); } if (typeof GT.alertSettings.reference == "undefined") { GT.alertSettings.reference = 0; localStorage.alertSettings = JSON.stringify(GT.alertSettings); } if (typeof GT.alertSettings.logEventMedia == "undefined") { GT.alertSettings.logEventMedia = "Ping-coin.mp3"; localStorage.alertSettings = JSON.stringify(GT.alertSettings); } if (typeof GT.classicAlerts.huntRoster == "undefined") { GT.classicAlerts.huntRoster = false; GT.classicAlerts.huntRosterNotify = 1; GT.classicAlerts.huntRosterNotifyWord = "New hit"; GT.classicAlerts.huntRosterNotifyMedia = "none"; localStorage.classicAlerts = JSON.stringify(GT.classicAlerts); } loadClassicAlertView(); if (typeof localStorage.savedAlerts == "undefined") { GT.alerts = { popup: { value: "QRZ", type: "4", notify: "2", repeat: "2", filename: "", shortname: "", lastMessage: "", lastTime: 0, fired: 0, needAck: 0 } }; GT.speechSettings = Object(); GT.audioSettings = Object(); GT.speechSettings.rate = 1; GT.speechSettings.pitch = 1; GT.speechSettings.volume = 1; GT.speechSettings.voice = 0; GT.speechSettings.phonetics = true; GT.audioSettings.volume = 1; saveAlerts(); } else { GT.alerts = JSON.parse(localStorage.savedAlerts); for (var key in GT.alerts) { if ( GT.alerts[key].type != 0 && GT.alerts[key].type != 2 && GT.alerts[key].type != 4 && GT.alerts[key].type != 5 && GT.alerts[key].type != 6 ) { delete GT.alerts[key]; } if (GT.alerts[key].repeat == 3) delete GT.alerts[key]; } GT.speechSettings = JSON.parse(localStorage.speechSettings); GT.audioSettings = JSON.parse(localStorage.audioSettings); } if (GT.speechSettings.voice > 0) { alertVoiceInput.value = GT.speechSettings.voice - 1; } speechVolume.value = GT.speechSettings.volume; speechPitch.value = GT.speechSettings.pitch; speechRate.value = GT.speechSettings.rate; speechPhonetics.checked = GT.speechSettings.phonetics; speechVolumeTd.innerText = speechVolume.value; speechPitchTd.innerText = speechPitch.value; speechRateTd.innerText = speechRate.value; audioVolume.value = GT.audioSettings.volume; audioVolumeTd.innerText = parseInt(audioVolume.value * 100) + "%"; wantGrid.checked = GT.alertSettings.requireGrid; wantMaxDT.checked = GT.alertSettings.wantMaxDT; wantMinDB.checked = GT.alertSettings.wantMinDB; wantMinFreq.checked = GT.alertSettings.wantMinFreq; wantMaxFreq.checked = GT.alertSettings.wantMaxFreq; maxDTView.innerHTML = maxDT.value = GT.alertSettings.maxDT; minDbView.innerHTML = minDb.value = GT.alertSettings.minDb; minFreqView.innerHTML = minFreq.value = GT.alertSettings.minFreq; maxFreqView.innerHTML = maxFreq.value = GT.alertSettings.maxFreq; cqOnly.checked = GT.alertSettings.cqOnly; noMyDxcc.checked = GT.alertSettings.noMyDxcc; onlyMyDxcc.checked = GT.alertSettings.onlyMyDxcc; noRoundUp.checked = GT.alertSettings.noRoundUp; onlyRoundUp.checked = GT.alertSettings.onlyRoundUp; usesLoTW.checked = GT.alertSettings.usesLoTW; useseQSL.checked = GT.alertSettings.useseQSL; referenceNeed.value = GT.alertSettings.reference; logEventMedia.value = GT.alertSettings.logEventMedia; setAlertVisual(); } function newLogEventSetting(obj) { GT.alertSettings.logEventMedia = obj.value; localStorage.alertSettings = JSON.stringify(GT.alertSettings); } function exceptionValuesChanged() { setAlertVisual(); GT.alertSettings.requireGrid = wantGrid.checked; GT.alertSettings.wantMaxDT = wantMaxDT.checked; GT.alertSettings.wantMinDB = wantMinDB.checked; GT.alertSettings.wantMinFreq = wantMinFreq.checked; GT.alertSettings.wantMaxFreq = wantMaxFreq.checked; maxDTView.innerHTML = GT.alertSettings.maxDT = maxDT.value; minDbView.innerHTML = GT.alertSettings.minDb = minDb.value; minFreqView.innerHTML = GT.alertSettings.minFreq = minFreq.value; maxFreqView.innerHTML = GT.alertSettings.maxFreq = maxFreq.value; GT.alertSettings.cqOnly = cqOnly.checked; GT.alertSettings.noMyDxcc = noMyDxcc.checked; GT.alertSettings.onlyMyDxcc = onlyMyDxcc.checked; GT.alertSettings.noRoundUp = noRoundUp.checked; GT.alertSettings.onlyRoundUp = onlyRoundUp.checked; GT.alertSettings.usesLoTW = usesLoTW.checked; GT.alertSettings.useseQSL = useseQSL.checked; GT.alertSettings.reference = referenceNeed.value; localStorage.alertSettings = JSON.stringify(GT.alertSettings); } function hashMaker(band, mode) { // "Current Band & Mode" if (GT.alertSettings.reference == 0) return band + mode; // "Current Band, Any Mode" if (GT.alertSettings.reference == 1) return band; // "Current Band, Any Digi Mode" if (GT.alertSettings.reference == 2) return band + "dg"; // "Current Mode, Any Band" if (GT.alertSettings.reference == 3) return mode; // "Any Band, Any Mode" if (GT.alertSettings.reference == 4) return ""; // "Any Band, Any Digit Mode" if (GT.alertSettings.reference == 5) return "dg"; } function setAlertVisual() { if (wantMaxDT.checked == true) { maxDT.style.display = "block"; maxDTView.style.display = "block"; } else { maxDT.style.display = "none"; maxDTView.style.display = "none"; } if (wantMinDB.checked == true) { minDb.style.display = "block"; minDbView.style.display = "block"; } else { minDb.style.display = "none"; minDbView.style.display = "none"; } if (wantMinFreq.checked == true) { minFreq.style.display = "block"; minFreqView.style.display = "block"; } else { minFreq.style.display = "none"; minFreqView.style.display = "none"; } if (wantMaxFreq.checked == true) { maxFreq.style.display = "block"; maxFreqView.style.display = "block"; } else { maxFreq.style.display = "none"; maxFreqView.style.display = "none"; } if (GT.callsignLookups.lotwUseEnable == true) { usesLoTWDiv.style.display = "block"; } else usesLoTWDiv.style.display = "none"; if (GT.callsignLookups.eqslUseEnable == true) { useseQSLDiv.style.display = "block"; } else useseQSLDiv.style.display = "none"; } function saveAlertSettings() { localStorage.speechSettings = JSON.stringify(GT.speechSettings); localStorage.audioSettings = JSON.stringify(GT.audioSettings); } function saveAlerts() { localStorage.savedAlerts = JSON.stringify(GT.alerts); saveAlertSettings(); } GT.testAudioTimer = null; function changeAudioValues() { if (GT.testAudioTimer) nodeTimers.clearTimeout(GT.testAudioTimer); GT.audioSettings.volume = audioVolume.value; audioVolumeTd.innerText = parseInt(audioVolume.value * 100) + "%"; GT.testAudioTimer = nodeTimers.setTimeout(playTestFile, 200); saveAlertSettings(); } function playTestFile() { playAlertMediaFile("Sysenter-7.mp3"); } function changeSpeechValues() { chrome.tts.stop(); GT.speechSettings.volume = speechVolume.value; GT.speechSettings.pitch = speechPitch.value; GT.speechSettings.rate = speechRate.value; GT.speechSettings.phonetics = speechPhonetics.checked; speechVolumeTd.innerText = speechVolume.value; speechPitchTd.innerText = speechPitch.value; speechRateTd.innerText = speechRate.value; saveAlertSettings(); } function addNewAlert() { var error = "Added"; var valid = true; var filename = ""; var shortname = ""; if (alertNotifySelect.value == 0) { if (alertMediaSelect.value == "none") { valid = false; error = $.i18n("alerts.addNew.SelectFile"); } else { filename = alertMediaSelect.value; shortname = alertMediaSelect.selectedOptions[0].innerText; } } if (valid) { if (alertTypeSelect.value == 0 || alertTypeSelect.value == 5) { valid = ValidateCallsign(alertValueInput, null); if (!valid) { error = "Invalid Callsign"; } } } if (valid) { valid = addAlert( alertValueInput.value, alertTypeSelect.value, alertNotifySelect.value, alertRepeatSelect.value, filename, shortname ); if (!valid) { error = "Duplicate!"; } } addError.innerHTML = error; displayAlerts(); } function addAlert(value, type, notify, repeat, filename, shortname) { var newKey = unique(value + type + notify + repeat + filename); if (!GT.alerts.hasOwnProperty(newKey)) { var alertItem = Object(); alertItem.value = value; alertItem.type = type; alertItem.notify = notify; alertItem.repeat = repeat; alertItem.filename = filename; alertItem.shortname = shortname; alertItem.lastMessage = ""; alertItem.lastTime = 0; alertItem.fired = 0; alertItem.needAck = 0; GT.alerts[newKey] = alertItem; saveAlerts(); return true; } return false; // we have this alert already } function deleteAlert(key) { delete GT.alerts[key]; saveAlerts(); displayAlerts(); } function resetAlert(key) { GT.alerts[key].lastMessage = ""; GT.alerts[key].lastTime = 0; GT.alerts[key].fired = 0; GT.alerts[key].needAck = 0; displayAlerts(); } function processAlertMessage(decodeWords, message, band, mode) { if (Object.keys(GT.alerts).length == 0) { // no alerts, don't bother return false; } else { var CQ = false; var validQTH = false; var theirGrid = null; var msgDEcallsign = ""; var found_callsign = null; // Grab the last word in the decoded message var grid = decodeWords[decodeWords.length - 1].trim(); if (grid.length == 4) { // maybe it's a grid var LETTERS = grid.substr(0, 2); var NUMBERS = grid.substr(2, 2); if (/^[A-R]+$/.test(LETTERS) && /^[0-9]+$/.test(NUMBERS)) { theirGrid = LETTERS + NUMBERS; if (theirGrid != "RR73") { validQTH = true; } else { theirGrid = null; validQTH = false; } } } if (validQTH) msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); if (validQTH == false && decodeWords.length == 3) { msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); } if (validQTH == false && decodeWords.length == 2) { msgDEcallsign = decodeWords[decodeWords.length - 1].trim(); } if (decodeWords[0] == "CQ") { CQ = true; } if (decodeWords.length >= 3 && CQ == true && validQTH == false) { if (validateNumAndLetter(decodeWords[decodeWords.length - 1].trim())) { msgDEcallsign = decodeWords[decodeWords.length - 1].trim(); } else msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); } if (decodeWords.length >= 4 && CQ == false) { msgDEcallsign = decodeWords[1]; } var okayToAlert = true; if (msgDEcallsign + band + mode in GT.liveCallsigns) { found_callsign = GT.liveCallsigns[msgDEcallsign + band + mode]; } if (okayToAlert == true) { return checkAlerts(msgDEcallsign, theirGrid, message, found_callsign); } } return false; } function checkAlerts( DEcallsign, grid, originalMessage, callsignRecord, band, mode ) { var hadAlert = false; for (var key in GT.alerts) { var nalert = GT.alerts[key]; if (nalert.type == 0) { // callsign exatch match if (DEcallsign == nalert.value) { handleAlert(nalert, DEcallsign, originalMessage, callsignRecord); hadAlert = true; } } else if (grid && nalert.type == 2) { // gridsquare if ( !(DEcallsign + band + mode in GT.tracker.worked.call) && grid.indexOf(nalert.value) == 0 ) { handleAlert(nalert, DEcallsign, originalMessage, callsignRecord, grid); hadAlert = true; } } else if (nalert.type == 4) { // QRZ if (GT.appSettings.myCall.length > 0 && originalMessage.indexOf(GT.appSettings.myCall + " ") == 0) { handleAlert(nalert, DEcallsign, originalMessage, callsignRecord); hadAlert = true; } } else if (nalert.type == 5) { // callsign partial if ( !(DEcallsign + band + mode in GT.tracker.worked.call) && DEcallsign.indexOf(nalert.value) == 0 ) { handleAlert(nalert, DEcallsign, originalMessage, callsignRecord); hadAlert = true; } } else if (nalert.type == 6) { // callsign regex try { if ( !(DEcallsign + band + mode in GT.tracker.worked.call) && DEcallsign.match(nalert.value) ) { handleAlert(nalert, DEcallsign, originalMessage, callsignRecord); hadAlert = true; } } catch (e) {} } } if (hadAlert) { displayAlerts(); return true; } return false; } function handleAlert(nAlert, target, lastMessage, callsignRecord, grid) { if (nAlert.fired > 0 && nAlert.repeat == 0) return; if (nAlert.fired == 1 && nAlert.repeat == 1) return; nAlert.lastMessage = lastMessage; nAlert.lastTime = timeNowSec(); if (callsignRecord != null) { if ( typeof callsignRecord.rect != "undefined" && callsignRecord.rect != null && nAlert.notify == 3 ) { // Fix me GT.map .getView() .setCenter( ol.extent.getCenter(callsignRecord.rect.getGeometry().getExtent()) ); } } if (nAlert.notify == 2) nAlert.needAck = 1; if (nAlert.type == 0 || nAlert.type == 5 || nAlert.type == 6) { if (nAlert.notify == 0) playAlertMediaFile(nAlert.filename); if (nAlert.notify == 1) speakAlertString("Callsign", target, null); if (nAlert.notify == 2) displayAlertPopUp("Seeking", target, null); } if (nAlert.type == 2) { if (nAlert.notify == 0) playAlertMediaFile(nAlert.filename); if (nAlert.notify == 1) speakAlertString("Grid square", grid, null); if (nAlert.notify == 2) displayAlertPopUp("Gridsquare", grid, target); } if (nAlert.type == 4) { if (nAlert.notify == 0) playAlertMediaFile(nAlert.filename); if (nAlert.notify == 1) speakQRZString(target, "Calling", GT.appSettings.myCall); if (nAlert.notify == 2) displayAlertPopUp("QRZ", null, null); } nAlert.fired++; } function playAlertMediaFile(filename, overrideMute) { if (GT.appSettings.alertMute && !overrideMute) return; // check if this is an alert stored with an older version of GT // which has a full file path given. if (path.isAbsolute(filename) && !fs.existsSync(filename)) { // full alert file name stored with old GT version referencing // the user media dir. determine basename of the file and try // constructing the path filename = path.basename(filename); } // construct the path from the user media dir or // fall back on the global media dir var fpath = path.join(GT.userMediaDir, filename); if (!fs.existsSync(fpath)) fpath = path.join(GT.gtMediaDir, filename); var audio = document.createElement("audio"); audio.src = "file://" + fpath; audio.setSinkId(GT.soundCard); audio.volume = GT.audioSettings.volume; audio.play(); } function stringToPhonetics(string) { var newMsg = ""; for (var x = 0; x < string.length; x++) { if (GT.speechSettings.phonetics == true) { newMsg += GT.phonetics[string.substr(x, 1)]; } else { if (string.substr(x, 1) == " ") newMsg += ", "; else newMsg += string.substr(x, 1); } if (x != string.length - 1) newMsg += " "; } return newMsg; } function speakQRZString(caller, words, you) { if (GT.appSettings.alertMute == 0) { var sCaller = ""; var sYou = ""; if (caller) sCaller = stringToPhonetics(caller); if (you) sYou = stringToPhonetics(you); if (GT.speechAvailable) { var speak = sCaller.trim() + ", " + words.trim() + ", " + sYou.trim(); var msg = new SpeechSynthesisUtterance(speak); msg.lang = GT.localeString; if (GT.speechSettings.voice > 0) { msg.voice = GT.voices[GT.speechSettings.voice - 1]; } msg.rate = GT.speechSettings.rate; msg.pitch = GT.speechSettings.pitch; msg.volume = GT.speechSettings.volume; window.speechSynthesis.speak(msg); } } } function speakAlertString(what, message, target) { if (GT.appSettings.alertMute == 0) { var sMsg = ""; var sTarget = ""; if (message) sMsg = stringToPhonetics(message); if (target) sTarget = stringToPhonetics(target); if (GT.speechAvailable) { var speak = what.trim() + ", " + sMsg.trim() + ", " + sTarget.trim(); var msg = new SpeechSynthesisUtterance(speak); msg.lang = GT.localeString; if (GT.speechSettings.voice > 0) { msg.voice = GT.voices[GT.speechSettings.voice - 1]; } msg.rate = GT.speechSettings.rate; msg.pitch = GT.speechSettings.pitch; msg.volume = GT.speechSettings.volume; window.speechSynthesis.speak(msg); } } } function displayAlertPopUp(what, message, target) { if (GT.alertWindowInitialized == false) return; var worker = ""; var acount = 0; if (Object.keys(GT.alerts).length > 0) { for (var key in GT.alerts) { if (GT.alerts[key].needAck) acount++; } worker += "
Type | "; worker += "Value | "; worker += "Notify | "; worker += "Repeat | "; worker += "Filename | "; worker += "Alerted | "; worker += "Last Message | "; worker += "When | "; worker += "||||
---|---|---|---|---|---|---|---|---|---|---|---|
" + GT.alertTypeOptions[GT.alerts[key].type] + " | "; if (GT.alerts[key].type == 0) { worker += "" + GT.alerts[key].value + " | "; } if (GT.alerts[key].type == 2) { worker += "" + GT.alerts[key].value + " | "; } if (GT.alerts[key].type == 4) { worker += "" + GT.appSettings.myCall + " | "; } if (GT.alerts[key].type == 5) { worker += "" + GT.alerts[key].value + "* | "; } if (GT.alerts[key].type == 6) { worker += "" + GT.alerts[key].value + " | "; } worker += "" + GT.alertValueOptions[GT.alerts[key].notify] + " | "; worker += "" + GT.alertRepeatOptions[GT.alerts[key].repeat] + " | "; worker += "" + (GT.alerts[key].shortname.length > 0 ? GT.alerts[key].shortname : "-") + " | "; worker += "" + (GT.alerts[key].fired > 0 ? "Yes" : "No") + " | "; worker += "" + (GT.alerts[key].lastMessage.length > 0 ? GT.alerts[key].lastMessage : "-") + " | "; ageString = userTimeString(GT.alerts[key].lastTime * 1000); worker += "" + (GT.alerts[key].lastTime > 0 ? ageString : "-") + " | "; worker += "