Add LiveATC Tab #1

Merged
npease merged 11 commits from AAOnline into main 2024-01-29 15:39:39 -10:00
3 changed files with 354 additions and 12 deletions
+41 -5
View File
@@ -24,7 +24,7 @@
<meta name="theme-color" content="#ffffff" />
<!-- Styles -->
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.grey-teal.min.css" />
<script defer src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<link rel="stylesheet" href="style.css" />
@@ -40,14 +40,50 @@
<script defer src="./main.js"></script>
</head>
<body onload="onload()">
<div id="loading">
<div id="sidebar" style="display: none">
<div>
<span onclick="main()"><i class="material-icons" style="font-size: 30px;margin: 15px;" onmouseup="main()">arrow_back_ios_new</i></span>
<span style="font-size:30px;font-weight: bold;margin: 15px;">Aircraft Radio</span>
<span style="font-size: 14px;margin: auto;">Powered By LiveATC</span>
</div>
<div id="ATC_State_Information"></div>
<div id="ATC_Airport_Information"></div>
<hr>
<div id="ATC_Data">
<ul class="mdl-list" id="ATC_Data_List">
</ul>
</div>
</div>
<div id="loading" style="display: bl ock">
<img id="loading_icon" src="images/loading.gif">
<br>Connecting to Aviation Assistant<br>Please Wait.
</div>
<div id="header" style="left: 210px;display: none">
<button class="mdl-button mdl-js-button mdl-button--raised" onclick="main()">tar1090</button>
<button class="mdl-button mdl-js-button mdl-button--raised" onclick="window.location.href = 'shortcuts://run-shortcut?name=OpenADSBWebLaunch'">OpenADSB</button>
<button class="mdl-button mdl-js-button mdl-button--raised" onclick="settings()">Settings</button>
<div id="header_nav">
<button class="mdl-button mdl-js-button mdl-button--raised" onclick="main()">tar1090</button>
<button class="mdl-button mdl-js-button mdl-button--raised" onclick="window.location.href = 'shortcuts://run-shortcut?name=OpenADSBWebLaunch'">OpenADSB</button>
<button class="mdl-button mdl-js-button mdl-button--raised" onclick="ATC()" id="ATC_Button">LiveATC</button>
<button class="mdl-button mdl-js-button mdl-button--raised" onclick="settings()">Settings</button>
</div>
<div id="header_atc">
<table>
<tr>
<td>
<button class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab" id="ATC_Pause_Play" onmouseup="pausePlay()">
<i class="material-icons" id="ATC_Pause_Play_Icon">stop</i>
</button>
</td>
<td>
<span id="audioControl_CurrentFeedName">No Feed Loaded</span><br>
<span id="audioControl_CurrentFeedStatus" style="color:red;"></span><span id="audioControl_CurrentFeedStatusText">Disconnected</span> <span id="audioControl_CurrentFeedTimeFormatting">(<span id="audioControl_CurrentFeedTime">00:00:00</span>)</span>
<audio id="player">
<source type="audio/mpeg">
</audio>
</td>
</tr>
</table>
</div>
</div>
<div id="main_tab" style="display: none">
<iframe src="http://aa.local/tar1090"></iframe>
+194 -2
View File
@@ -1,23 +1,96 @@
ATC_AIRPORTS = {}
var usStates = {
'Alabama': 'AL',
'Alaska': 'AK',
'Arizona': 'AZ',
'Arkansas': 'AR',
'California': 'CA',
'Colorado': 'CO',
'Connecticut': 'CT',
'Delaware': 'DE',
'Florida': 'FL',
'Georgia': 'GA',
'Hawaii': 'HI',
'Idaho': 'ID',
'Illinois': 'IL',
'Indiana': 'IN',
'Iowa': 'IA',
'Kansas': 'KS',
'Kentucky': 'KY',
'Louisiana': 'LA',
'Maine': 'ME',
'Maryland': 'MD',
'Massachusetts': 'MA',
'Michigan': 'MI',
'Minnesota': 'MN',
'Mississippi': 'MS',
'Missouri': 'MO',
'Montana': 'MT',
'Nebraska': 'NE',
'Nevada': 'NV',
'New Hampshire': 'NH',
'New Jersey': 'NJ',
'New Mexico': 'NM',
'New York': 'NY',
'North Carolina': 'NC',
'North Dakota': 'ND',
'Ohio': 'OH',
'Oklahoma': 'OK',
'Oregon': 'OR',
'Pennsylvania': 'PA',
'Rhode Island': 'RI',
'South Carolina': 'SC',
'South Dakota': 'SD',
'Tennessee': 'TN',
'Texas': 'TX',
'Utah': 'UT',
'Vermont': 'VT',
'Virginia': 'VA',
'Washington': 'WA',
'West Virginia': 'WV',
'Wisconsin': 'WI',
'Wyoming': 'WY'
};
function main() {
document.getElementById("main_tab").style.display = "block";
document.getElementById("settings").style.display = "none";
document.getElementById("sidebar").style.display = "none";
document.getElementById("header_atc").style.visibility = "visible";
document.getElementById("ATC_Button").style.display = "inline-block";
document.getElementById("header").style.left = "210px"
}
function settings() {
document.getElementById("main_tab").style.display = "none";
document.getElementById("settings").style.display = "block";
document.getElementById("sidebar").style.display = "none";
document.getElementById("header_atc").style.visibility = "hidden";
document.getElementById("ATC_Button").style.display = "inline-block";
document.getElementById("header").style.left = "2%"
}
function ATC() {
document.getElementById("main_tab").style.display = "block";
document.getElementById("sidebar").style.display = "flex";
document.getElementById("ATC_Button").style.display = "none";
document.getElementById("settings").style.display = "none";
document.getElementById("header_atc").style.visibility = "visible";
document.getElementById("header").style.left = "10px"
}
function onload() {
document.getElementById("loading").style.display = "none"
document.getElementById("header").style.display = "block"
document.getElementById("main_tab").style.display = "block"
liveATCPreload()
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://aa.local:5000/alive", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status != 0) {
document.getElementById("loading").style.display = "none"
document.getElementById("header").style.display = "block"
document.getElementById("header").style.display = "block"
document.getElementById("main_tab").style.display = "block"
updateSettings()
setInterval(updateSettings, 10000)
@@ -27,7 +100,7 @@ function onload() {
}, 1000)
}
}
xhr.send();
xhr.send();
}
function updateSettings() {
@@ -82,4 +155,123 @@ function screenMessage(text) {
var snackbarContainer = document.querySelector('#toasts');
var data = {message: text};
snackbarContainer.MaterialSnackbar.showSnackbar(data);
}
function HHMMSS(time) {
var sec_num = parseInt(time, 10); // don't forget the second param
var hours = Math.floor(sec_num / 3600);
var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
var seconds = sec_num - (hours * 3600) - (minutes * 60);
if (hours < 10) {
hours = "0" + hours;
}
if (minutes < 10) {
minutes = "0" + minutes;
}
if (seconds < 10) {
seconds = "0" + seconds;
}
return hours + ':' + minutes + ':' + seconds;
}
function liveATCPreload() {
xhr = new XMLHttpRequest();
xhr.open("GET", "https://server1.nicholaspease.com/reports/liveatc.json", true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status != 0) {
ATC_AIRPORTS = JSON.parse(xhr.response)
listState()
}
}
xhr.send();
}
function listState() {
document.getElementById("ATC_Data_List").innerHTML = ""
document.getElementById("ATC_State_Information").setAttribute("onclick","")
document.getElementById("ATC_State_Information").style.display = "none"
document.getElementById("ATC_Airport_Information").style.display = "none"
for (state in ATC_AIRPORTS) {
node = document.createElement("div")
numOfFeeds = 0
numofAirports = 0
for (i in ATC_AIRPORTS[state].airports) {
numofAirports++
for (j in ATC_AIRPORTS[state].airports[i])
for (k in ATC_AIRPORTS[state].airports[i].feeds)
numOfFeeds++
}
node.innerHTML = '<li onclick="selectState(\''+state+'\')" class="mdl-list__item mdl-list__item--two-line"><span class="mdl-list__item-primary-content"><span style="font-size: 40px;font-weight:100;width:40px;height:40px;margin-right: 30px;">'+usStates[state]+'</span><span style="font-size: 24px">'+state+'</span><span class="mdl-list__item-sub-title">'+numofAirports+' Airports,<span style="margin-left: 5px;">'+numOfFeeds+' Feeds</span></span></span></li>'
document.getElementById("ATC_Data_List").appendChild(node)
}
}
function truncate(str, n){
return (str.length > n) ? str.slice(0, n-1) + '&hellip;' : str;
};
function selectState(state) {
document.getElementById("ATC_State_Information").style.display = "block"
document.getElementById("ATC_Airport_Information").style.display = "none"
document.getElementById("ATC_State_Information").setAttribute("onclick","listState()")
document.getElementById("ATC_State_Information").innerHTML = '<span style="font-size: 40px;font-weight:100;width:40px;height:40px;margin-right: 30px;">'+usStates[state]+'</span><span style="font-size: 24px">'+state+'</span>'
document.getElementById("ATC_Data_List").innerHTML = ""
for (airport in ATC_AIRPORTS[state].airports) {
node = document.createElement("div")
feeds = 0
for (i in ATC_AIRPORTS[state].airports[airport].feeds)
feeds++
node.innerHTML = '<li onclick="selectAirport(\''+state+'\',\''+airport+'\')" class="mdl-list__item mdl-list__item--two-line"><span class="mdl-list__item-primary-content"><span style="font-size: 40px;font-weight:100;width:40px;height:40px;margin-right: 30px;">'+airport+'</span><span style="font-size: 18px;text-overflow: ellipse;white-space: nowrap;overflow:hidden">'+truncate(ATC_AIRPORTS[state].airports[airport].name,30)+'</span><span class="mdl-list__item-sub-title">'+feeds+' Feeds</span></span></li>'
document.getElementById("ATC_Data_List").appendChild(node)
}
document.getElementById("ATC_Data").scrollTop = 0;
}
function selectAirport(state,airport) {
document.getElementById("ATC_State_Information").style.display = "block"
document.getElementById("ATC_Airport_Information").style.display = "block"
document.getElementById("ATC_Airport_Information").setAttribute("onclick","selectState('"+state+"')")
document.getElementById("ATC_Data_List").innerHTML = ""
document.getElementById("ATC_Airport_Information").innerHTML = '<span style="font-size: 40px;font-weight:100;width:40px;height:40px;margin-right: 30px;">'+airport+'</span><span style="font-size: 18px;text-overflow: ellipse;white-space: nowrap;overflow:hidden">'+truncate(ATC_AIRPORTS[state].airports[airport].name,30)+'</span>'
for (feed in ATC_AIRPORTS[state].airports[airport].feeds) {
node = document.createElement("div")
node.innerHTML = '<li onclick="selectFeed(\''+state+'\',\''+airport+'\',\''+feed+'\')" class="mdl-list__item mdl-list__item--two-line"><span class="mdl-list__item-primary-content"><span style="font-size: 26px;text-overflow: ellipse;white-space: nowrap;overflow:hidden">'+truncate(ATC_AIRPORTS[state].airports[airport].feeds[feed].name,30)+'</span><span class="mdl-list__item-sub-title">'+ATC_AIRPORTS[state].airports[airport].location+'</span></span></span></li>'
document.getElementById("ATC_Data_List").appendChild(node)
}
document.getElementById("ATC_Data").scrollTop = 0;
}
function selectFeed(state,airport,feed) {
feed = ATC_AIRPORTS[state].airports[airport].feeds[feed]
re = /\/[^/]*\/([^.]*)/
console.log(re.exec(feed.url)[1]) //http://d.liveatc.net/
document.getElementById("player").setAttribute("src", "http://d.liveatc.net/"+re.exec(feed.url)[1])
document.getElementById("player").play()
document.getElementById("audioControl_CurrentFeedName").innerHTML = feed.name
document.getElementById("audioControl_CurrentFeedStatus").style.color = "orange"
document.getElementById("audioControl_CurrentFeedStatusText").innerHTML = "Connecting"
document.getElementById("ATC_Pause_Play_Icon").innerHTML = "pause"
window.setInterval(function () {
if (document.getElementById("player").readyState === 3 || document.getElementById("player").readyState === 4) {
document.getElementById("audioControl_CurrentFeedStatus").style.color = "green"
document.getElementById("audioControl_CurrentFeedStatusText").innerHTML = "Connected"
} else {
document.getElementById("audioControl_CurrentFeedStatus").style.color = "orange"
document.getElementById("audioControl_CurrentFeedStatusText").innerHTML = "Connecting"
}
var time = document.getElementById("player").currentTime
document.getElementById("audioControl_CurrentFeedTime").innerHTML = HHMMSS(time)
}, 500)
}
function pausePlay() {
if (document.getElementById("ATC_Pause_Play_Icon").innerHTML == "pause") {
document.getElementById("player").pause()
document.getElementById("ATC_Pause_Play_Icon").innerHTML = "play_arrow"
} else if (document.getElementById("ATC_Pause_Play_Icon").innerHTML == "play_arrow") {
document.getElementById("player").play()
document.getElementById("ATC_Pause_Play_Icon").innerHTML = "pause"
}
}
+119 -5
View File
@@ -5,7 +5,7 @@
}
html * {
font-family: SF-Pro !important;
font-family: SF-Pro !important MaterialIcons;
}
#settings_logo {
@@ -16,6 +16,14 @@ html * {
margin-right: 10px;
}
#header > button {
margin-right: 15px;
}
#header > button:nth-last-child(1) {
margin-right: 0px;
}
html,
body {
background-color: white;
@@ -34,13 +42,19 @@ body {
#header {
position: absolute;
display: block;
top: 10px;
border-radius: 8px;
z-index: 1;
background-color: rgba(255, 255, 255, 0.7);
width: 800px;
top: 10px;
}
#header_nav {
display: inline-block;
position:relative;
background-color: rgba(255, 255, 255, 0.8);
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
border-radius: 8px;
padding: 10px;
top: -30px;
}
#main_tab {
@@ -103,4 +117,104 @@ body {
top: 50%;
text-align: center;
transform: translate(-50%, -50%);
}
/* ATC DATA */
#header_atc {
display: inline-block;
position: relative;
left: 30px;
background-color: rgba(255, 255, 255, 0.8);
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
border-radius: 8px;
padding-left: 5px;
padding-right: 5px;
}
#audioControl_CurrentFeedName {
font-size: 20px;
margin-left: 15px;
position: relative;
top: 5px;
}
#audioControl_CurrentFeedStatus {
font-size: 42px;
line-height: 8px;
margin-left: 15px;
position: relative;
top: 5px;
}
#audioControl_CurrentFeedStatusText {
margin-left: 5px;
line-height: 8px;
font-size: 12px;
position: relative;
top: -5px;
}
#audioControl_CurrentFeedTimeFormatting {
margin-left: 3px;
line-height: 8px;
font-size: 12px;
position: relative;
top: -5px;
}
#sidebar {
position: absolute;
top: 15px;
left: calc(100% - 475px);
height: calc(100% - 30px);
width: 450px;
background-color: rgba(255, 255, 255, 0.8);
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
border-radius: 8px;
line-height: 30px;
display: flex;
flex-direction: column;
}
.ATC_State {
background-color: rgba(255, 255, 255, 0.8);
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
border-radius: 8px;
width: 90px;
margin: 15px;
text-align: center;
padding: 10px;
display: inline-block;
}
.ATC_State_Name {
font-size: 26px;
}
#ATC_Data {
overflow: auto;
max-height: 100%;
height: 100%;
}
#ATC_Data > ul {
height: calc(100%);
}
#ATC_Data_List {
margin-top: 0px;
padding-top: 0px;
width: 100%;
}
#ATC_State_Information {
margin: 10px 0px 0px 10px;
}
#ATC_Airport_Information {
margin: 10px 10px 0px 10px;
}
#player {
display: none;
}