1//VARIABLES 2 3const imageDepotBase = "https://lccibackend.com/merlin/imageDepot/"; 4const url = new URL(location); 5let grabbedPages = []; 6let activePage = ""; 7 8let pages = { 9 "home":{"url":"pages/home.html", "script":"assets/scripts/home.js"}, 10 "djs":{"url":"pages/djs.html", "script":"assets/scripts/djs.js"}, 11 "schedule":{"url":"pages/schedule.html", "script":"assets/scripts/schedule.js"}, 12 "features":{"url":"pages/features.html", "script":"assets/scripts/features.js"}, 13 "playlist":{"url":"pages/playlist.html", "script":"assets/scripts/playlist.js"}, 14 "contact":{"url":"pages/contact.html"}, 15 "eeo":{"url":"pages/eeo.html"}, 16 "fcc":{"url":"pages/fcc.html"}, 17 "contestrules":{"url":"pages/contestrules.html"}, 18}; 19 20// const storedVotes = localStorage.getItem("storedVotes"); 21// let sentVotes = []; 22// if(storedVotes != null){ sentVotes = JSON.parse(storedVotes); } 23 24let sentVotes = (localStorage.getItem("storedVotes")) ? JSON.parse(localStorage.getItem("storedVotes")) : []; 25 26//DOM HOOKS 27 28const dialogs = { 29 "lccFamily":{ 30 "modal":document.getElementById("lccfamily-dialog"), 31 "closeButton":document.getElementById("lccfamily-dialog-close-button"), 32 } 33}; 34 35const nav = { 36 "home":document.getElementById("home-nav-button"), 37 "djs":document.getElementById("djs-nav-button"), 38 "schedule":document.getElementById("schedule-nav-button"), 39 "features":document.getElementById("features-nav-button"), 40 "playlist":document.getElementById("playlist-nav-button"), 41 "contact":document.getElementById("contact-nav-button"), 42 "goodTimeGuide":document.getElementById("goodtimeguide-nav-button"), 43 "swag":document.getElementById("swag-nav-button"), 44 "facebook":document.getElementById("facebook-nav-button"), 45 "instagram":document.getElementById("instagram-nav-button"), 46 "twitter":document.getElementById("twitter-nav-button") 47}; 48 49const nowPlaying = { 50 "section":document.getElementById("nowplaying-section"), 51 "audio":document.getElementById("nowplaying-audio"), 52 "placeholder":document.getElementById("nowplaying-placeholder"), 53 "controller":document.getElementById("nowplaying-controller-div"), 54 "tuneInButton":document.getElementById("tunein-button"), 55 "albumCover":document.getElementById("nowplaying-img"), 56 "info":document.getElementById("nowplaying-info"), 57 "title":document.getElementById("nowplaying-title"), 58 "artist":document.getElementById("nowplaying-artist"), 59 "volumeslider":document.getElementById("nowplaying-volume-slider"), 60 "volumeTrack":document.getElementById("nowplaying-volume-track"), 61 "upVoteButton":document.getElementById("nowplaying-upvote-button"), 62 "upVoteSpan":document.getElementById("nowplaying-upvote-span"), 63 "downVoteButton":document.getElementById("nowplaying-downvote-button"), 64 "downVoteSpan":document.getElementById("nowplaying-downvote-span"), 65 "currentSong":{}, 66 "isSetUp":false, 67}; 68 69const recentlyPlayed = { 70 "placeholder":document.getElementById("recentlyplayed-placeholder"), 71 "info":document.getElementById("recentlyplayed-info"), 72 "entry1":document.getElementById("recentlyplayed1-entry"), 73 "title1":document.getElementById("recentlyplayed1-title"), 74 "artist1":document.getElementById("recentlyplayed1-artist"), 75 "time1":document.getElementById("recentlyplayed1-time"), 76 "entry2":document.getElementById("recentlyplayed2-entry"), 77 "title2":document.getElementById("recentlyplayed2-title"), 78 "artist2":document.getElementById("recentlyplayed2-artist"), 79 "time2":document.getElementById("recentlyplayed2-time"), 80 "entry3":document.getElementById("recentlyplayed3-entry"), 81 "title3":document.getElementById("recentlyplayed3-title"), 82 "artist3":document.getElementById("recentlyplayed3-artist"), 83 "time3":document.getElementById("recentlyplayed3-time"), 84 "recentSongs":[], 85 "isSetUp":false, 86}; 87 88const footer = { 89 "pawscauseButton":document.getElementById("pawscause-footer-button"), 90 "lccfamilyButton":document.getElementById("lccfamily-footer-button"), 91 "eeoButton":document.getElementById("eeo-footer-button"), 92 "fccButton":document.getElementById("fcc-footer-button"), 93 "contestrulesButton":document.getElementById("contestrules-footer-button"), 94 "publicfileButton":document.getElementById("publicfile-footer-button"), 95 "copyrightYear":document.getElementById("copyright-year"), 96}; 97 98const mobile = { 99 "menu":document.getElementById("mobile-menu"), 100 "toggle":document.getElementById("mobile-menu-toggle"), 101 "nowPlayingWrapper":document.getElementById("mobile-now-playing-wrapper"), 102}; 103 104//DOM FUNCTIONS 105 106function simpleDate(_input){ 107 let dateObject = new Date(Date.parse(_input)); 108 let output = ""; 109 let ampm = "PM"; 110 if(dateObject.getHours() > 12 ){ 111 output = output + (dateObject.getHours() - 12); 112 if(dateObject.getHours() == 12){ 113 output = output + (dateObject.getHours()); 114 ampm = "AM"; 115 } 116 } else { 117 output = output + (dateObject.getHours()); 118 ampm = "AM"; 119 } 120 if(dateObject.getMinutes() < 10){ 121 output = output + ":0"; 122 } else { 123 output = output + ":"; 124 } 125 output = output + dateObject.getMinutes() + ampm; 126 return output; 127} 128 129function displayRecentlyPlayed(){ 130 if(!recentlyPlayed.isSetUp){ return; } 131 recentlyPlayed.title1.textContent = recentlyPlayed.recentSongs[0].title; 132 recentlyPlayed.artist1.textContent = "By: " + recentlyPlayed.recentSongs[0].artist; 133 recentlyPlayed.time1.textContent = simpleDate(recentlyPlayed.recentSongs[0].time); 134 recentlyPlayed.title2.textContent = recentlyPlayed.recentSongs[1].title; 135 recentlyPlayed.artist2.textContent = "By: " + recentlyPlayed.recentSongs[1].artist; 136 recentlyPlayed.time2.textContent = simpleDate(recentlyPlayed.recentSongs[1].time); 137 recentlyPlayed.title3.textContent = recentlyPlayed.recentSongs[2].title; 138 recentlyPlayed.artist3.textContent = "By: " + recentlyPlayed.recentSongs[2].artist; 139 recentlyPlayed.time3.textContent = simpleDate(recentlyPlayed.recentSongs[2].time); 140} 141 142function displayCurrentSong(){ 143 if(!nowPlaying.isSetUp){ return; } 144 if(nowPlaying.currentSong.cover_art_url == ""){ 145 nowPlaying.albumCover.src = "assets/images/khum-missing.jpg"; 146 } else { 147 nowPlaying.albumCover.src = nowPlaying.currentSong.cover_art_url; 148 } 149 nowPlaying.title.textContent = nowPlaying.currentSong.title; 150 nowPlaying.artist.textContent = "By: " + nowPlaying.currentSong.artist; 151 nowPlaying.upVoteSpan.textContent = nowPlaying.currentSong.up; 152 nowPlaying.downVoteSpan.textContent = nowPlaying.currentSong.down; 153} 154 155function assignPage(_pageLabel){ 156 url.searchParams.set("page", _pageLabel); 157 history.replaceState({},"",url); 158} 159 160//ASYNC FUNCTIONS 161 162async function getRecentlyPlayed(){ 163 let payload = new FormData; 164 const url="/common/scripts/fetch/fetch_recently_played.php?station=KHUM"; 165 const response = await fetch(url, { 166 method: "POST", 167 body: payload, 168 }).then(_response => { 169 return _response.json(); 170 }).then(_message => { 171 if(_message.success){ 172 nowPlaying.currentSong = JSON.parse(_message.currentSong); 173 recentlyPlayed.recentSongs = JSON.parse(_message.recentSongs); 174 nowPlaying.isSetUp = true; 175 recentlyPlayed.isSetUp = true; 176 displayRecentlyPlayed(); 177 displayCurrentSong(); 178 recentlyPlayed.placeholder.classList.add("hidden"); 179 recentlyPlayed.info.hidden = false; 180 nowPlaying.placeholder.classList.add("hidden"); 181 nowPlaying.info.hidden = false; 182 } else { 183 alert(_message.message); 184 } 185 });
186} 187 188async function loadPage(_pageKey){ 189 let _url = pages[_pageKey].url; 190 let _label = _pageKey; 191 let _scriptUrl = (pages[_pageKey].script) ? pages[_pageKey].script : ""; 192 193 mobile.menu.classList.remove("open"); 194 mobile.toggle.textContent = "="; 195 196 if(activePage == _label){ return; } //If we're already seeing that page, do nothing 197 198 assignPage(_label); 199 200 document.querySelectorAll("[data-pagekey]").forEach(_pageButton=>{ _pageButton.disabled = false; }); 201 document.querySelectorAll("[data-pagekey="+_label+"]").forEach(_button=>{ _button.disabled = true; }); 202 203 if(grabbedPages.includes(_label)){ //If we've already grabbed that page, just show it 204 document.querySelectorAll(".page").forEach(_page=>{ _page.classList.add("hidden"); }); 205 document.getElementById(_label).classList.remove("hidden"); 206 activePage = _label; 207 return; 208 } 209 210 //otherwise, fetch it and show it. 211 212 fetch(_url).then(function(response) { 213 return response.text(); 214 }).then(function(_html){ 215 const newPage = document.createElement("div"); 216 newPage.classList.add("page");
217 newPage.id = _label; 218 newPage.innerHTML = _html; 219 if(_scriptUrl != ""){ 220 let runtimeScript = document.createElement("script"); 221 runtimeScript.defer = true; 222 runtimeScript.src = _scriptUrl; 223 newPage.appendChild(runtimeScript); 224 } 225 let pages = document.querySelectorAll(".page"); 226 pages.forEach(_page=>{ 227 _page.classList.add("hidden"); 228 }); 229 grabbedPages.push(_label); 230 activePage = _label; 231 document.querySelector("main").appendChild(newPage); 232 }) 233} 234 235async function sendVote(_songId, _isUpVote){ 236 //send vote off 237 let payload = new FormData; 238 239 payload.set("song_id", _songId); 240 payload.set("station", 2); 241 if(_isUpVote){ 242 payload.set("up", 1); 243 payload.set("down", 0); 244 } else { 245 payload.set("up", 0); 246 payload.set("down", 1); 247 } 248 249 const url="https://lccibackend.com/vote_receiver.php"; 250 const myHeaders = new Headers(); 251 myHeaders.append("Access-Control-Allow-Origin","https://khum.com"); 252 myHeaders.append("Access-Control-Allow-Credentials", "true"); 253 254 const response = await fetch(url, { 255 method: "POST", 256 // headers: myHeaders, 257 body: payload 258 }).then(_response => { 259 return _response.json(); 260 }).then(_message => { 261 if(!_message.success){ 262 alert(_message.message); 263 } 264 }); 265} 266 267//EVENT LISTENERS 268 269document.addEventListener("voteSent",_event=>{ 270 if(!sentVotes.includes(_event.detail.songId)){ 271 sendVote(_event.detail.songId, _event.detail.isUpVote); 272 sentVotes.push(_event.detail.songId); 273 localStorage.setItem("storedVotes", JSON.stringify(sentVotes)); 274 } 275 if(_event.detail.isUpVote){ 276 nowPlaying.currentSong.up ++; 277 } else { 278 nowPlaying.currentSong.down ++; 279 } 280 nowPlaying.upVoteSpan.textContent = nowPlaying.currentSong.up; 281 nowPlaying.downVoteSpan.textContent = nowPlaying.currentSong.down; 282}); 283 284nowPlaying.tuneInButton.addEventListener("click",_event=>{ 285 nowPlaying.audio.play(); 286 nowPlaying.tuneInButton.classList.add("hidden"); 287 nowPlaying.albumCover.hidden = false; 288 nowPlaying.controller.classList.remove("hidden"); 289}); 290 291recentlyPlayed.entry1.addEventListener("click",_event=>{ loadPage("playlist"); }); 292recentlyPlayed.entry2.addEventListener("click",_event=>{ loadPage("playlist"); }); 293recentlyPlayed.entry3.addEventListener("click",_event=>{ loadPage("playlist"); }); 294 295nav.goodTimeGuide.addEventListener("click",_event=>{ window.open("https://lostcoastoutpost.com/lowdown/"); }); 296nav.swag.addEventListener("click",_event=>{ window.open("https://lccswag.myspreadshop.com/KHUM"); }); 297nav.facebook.addEventListener("click",_event=>{ window.open("https://www.facebook.com/KHUMradio/"); }); 298nav.instagram.addEventListener("click",_event=>{ window.open("https://www.instagram.com/khumradio/"); }); 299nav.twitter.addEventListener("click",_event=>{ window.open("https://x.com/KHUMradio"); }); 300 301footer.lccfamilyButton.addEventListener("click",_event=>{ dialogs.lccFamily.modal.showModal(); }); 302footer.pawscauseButton.addEventListener("click",_event=>{ window.open("http://humboldtpawscause.com/"); }); 303footer.publicfileButton.addEventListener("click",_event=>{ window.open("https://publicfiles.fcc.gov/fm-profile/khum"); }); 304 305dialogs.lccFamily.closeButton.addEventListener("click",_event=>{ dialogs.lccFamily.modal.close(); }); 306 307//NOW PLAYING SET-UP 308 309const eSource = new EventSource("https://lccibackend.com/lcc_sse.php?station=2"); 310eSource.addEventListener("message",_event=>{ 311 document.dispatchEvent(new CustomEvent("newSong", { detail:JSON.parse(_event.data) })); 312}); 313 314document.addEventListener("newSong", _event=>{ 315 if(_event.detail.title != nowPlaying.currentSong.title){ 316 if(!_event.detail.up){ _event.detail.up = 0; } 317 if(!_event.detail.down){ _event.detail.down = 0; } 318 _event.detail.time = _event.detail.play_date; 319 320 recentlyPlayed.recentSongs.unshift(nowPlaying.currentSong); 321 recentlyPlayed.recentSongs.pop(); 322 nowPlaying.currentSong = _event.detail; 323 324 displayCurrentSong(); 325 displayRecentlyPlayed(); 326 nowPlaying.upVoteButton.disabled = false; 327 nowPlaying.downVoteButton.disabled = false; 328 } 329}); 330 331let sliding = false; 332let volume = 50; 333nowPlaying.audio.volume = 0.5; 334 335nowPlaying.volumeslider.addEventListener("touchstart",_event=>{ sliding = true; }); 336document.addEventListener("touchmove",_event=>{ 337 if(sliding){ 338 volume = (_event.touches[0].clientX - nowPlaying.volumeTrack.getBoundingClientRect().x) / nowPlaying.volumeTrack.getBoundingClientRect().width * 100; 339 if(volume > 100) { volume = 100; } 340 if(volume < 0) { volume = 0; } 341 nowPlaying.volumeslider.style.left = ((volume / 100) * nowPlaying.volumeTrack.getBoundingClientRect().width) + "px"; 342 nowPlaying.audio.volume = volume/100; 343 } 344}); 345document.addEventListener("touchend",_event=>{ sliding = false; }); 346nowPlaying.volumeslider.addEventListener("mousedown",_event=>{ sliding = true; }); 347document.addEventListener("mousemove",_event=>{ 348 if(sliding){ 349 volume = (_event.clientX - nowPlaying.volumeTrack.getBoundingClientRect().x) / nowPlaying.volumeTrack.getBoundingClientRect().width * 100; 350 if(volume > 100) { volume = 100; } 351 if(volume < 0) { volume = 0; } 352 nowPlaying.volumeslider.style.left = ((volume / 100) * nowPlaying.volumeTrack.getBoundingClientRect().width) + "px"; 353 nowPlaying.audio.volume = volume/100; 354 if(_event.buttons == 0){ sliding = false; } 355 } 356}); 357 358nowPlaying.upVoteButton.addEventListener("click",_event=>{ 359 document.dispatchEvent(new CustomEvent("voteSent", { detail:{ songId:nowPlaying.currentSong.song_id, isUpVote:true } })); 360 nowPlaying.upVoteButton.disabled = true; 361 nowPlaying.downVoteButton.disabled = true; 362}); 363 364nowPlaying.downVoteButton.addEventListener("click",_event=>{ 365 document.dispatchEvent(new CustomEvent("voteSent", { detail:{ songId:nowPlaying.currentSong.song_id, isUpVote:false } })); 366 nowPlaying.upVoteButton.disabled = true; 367 nowPlaying.downVoteButton.disabled = true; 368}); 369 370mobile.toggle.addEventListener("click",_event=>{ 371 if(mobile.menu.classList.contains("open")){ 372 mobile.menu.classList.remove("open"); 373 mobile.toggle.textContent = "="; 374 } else { 375 mobile.menu.classList.add("open"); 376 mobile.toggle.textContent = "X"; 377 } 378}); 379 380//SET-UP 381 382document.querySelectorAll('[data-pagekey]').forEach(_pageButton=>{ 383 _pageButton.addEventListener("click",_event=>{ 384 loadPage(_pageButton.dataset.pagekey); 385 });
386}); 387 388footer.copyrightYear.textContent = (new Date).getFullYear(); 389 390let startingPage = (window.location.search) ? window.location.search.substring(1).split("=")[1] : "home"; 391 392getRecentlyPlayed(); 393 394document.addEventListener('DOMContentLoaded', function(){ 395 loadPage(startingPage); 396 if(screen.orientation.type == "portrait-primary" || screen.orientation.type == "portrait-secondary"){ 397 mobile.nowPlayingWrapper.appendChild(nowPlaying.section); 398 } 399});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.