emptyfm

Listen to your favorite FM Radio station from your browser.
Log | Files | Refs | README | LICENSE

commit 27356c5db4baa5202d967e5de1ebf69444782317
parent 00c576c75b4a7bc15b47ff3ef702197b600e94d3
Author: Nirmal Kumar R <tildezero@gmail.com>
Date:   Sun, 19 May 2024 19:58:52 +0530

Enhance with Recents playlist

Diffstat:
Memptyfm.js | 221+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mindex.html | 45++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 172 insertions(+), 94 deletions(-)

diff --git a/emptyfm.js b/emptyfm.js @@ -1,112 +1,155 @@ let player; - -// document.addEventListener('DOMContentLoaded', function () { -// player = videojs('emptyfm'); -// player.play(); -// }); +let recents; async function fetchFMStations() { - let countrySelect = document.getElementById("countryCode"); - let countryCode = countrySelect.value; - - let languagesSelect = document.getElementById("languages"); - let langCode = languagesSelect.value; - - let queryParams; - - if (!countryCode && !langCode) { - alert("You must choose either country or language, or both if you wish."); - return; - } - else if (!countryCode) { - queryParams = "language=" + langCode + "&hidebroken=true&order=clickcount&reverse=true" - } - else if (!langCode) { - queryParams = "countrycode=" + countryCode + "&hidebroken=true&order=clickcount&reverse=true" - } - else { - queryParams = "countrycode=" + countryCode + "&language=" + langCode + "&hidebroken=true&order=clickcount&reverse=true" - } - - const response = await fetch("https://de1.api.radio-browser.info/json/stations/search?" + queryParams); - const stations = await response.json(); - - let fmList = document.getElementById("fmlist"); - - fmList.innerHTML = ""; - for (var k in stations) { - let atag = document.createElement("a"); - atag.className = "fmitem"; - atag.href = stations[k].url; - atag.innerText = stations[k].name; - atag.onclick = (e) => { - e.preventDefault(); - changeSource(atag.href); + let countrySelect = document.getElementById("countryCode"); + let countryCode = countrySelect.value; + + let languagesSelect = document.getElementById("languages"); + let langCode = languagesSelect.value; + + let queryParams; + + if (!countryCode && !langCode) { + alert("You must choose either country or language, or both if you wish."); + return; + } else if (!countryCode) { + queryParams = "language=" + langCode + "&hidebroken=true&order=clickcount&reverse=true" + } else if (!langCode) { + queryParams = "countrycode=" + countryCode + "&hidebroken=true&order=clickcount&reverse=true" + } else { + queryParams = "countrycode=" + countryCode + "&language=" + langCode + "&hidebroken=true&order=clickcount&reverse=true" } - fmList.appendChild(atag); - } + const response = await fetch("https://de1.api.radio-browser.info/json/stations/search?" + queryParams); + const stations = await response.json(); + + let fmList = document.getElementById("fmlist"); + + fmList.innerHTML = ""; + for (var k in stations) { + let atag = document.createElement("a"); + atag.className = "fmitem"; + atag.href = stations[k].url; + atag.innerText = stations[k].name; + atag.onclick = (e) => { + e.preventDefault(); + let found = recents.find(({ + name + }) => name === atag.innerText); + if (!found) { + addToRecents(recents, atag.innerText, atag.href); + } + + changeSource(atag.href); + } + + fmList.appendChild(atag); + } +} + +function populateRecents() { + let saved = localStorage.getItem('emptyfm') ?? '{ "recents": [] }'; + let savedObj = JSON.parse(saved); + recents = savedObj["recents"]; + + for (recent of recents) { + constructRecentEl(recent.name, recent.url); + } +} + +function constructRecentEl(name, url) { + let recentsEl = document.getElementById("recentList"); + let litag = document.createElement("li"); + let atag = document.createElement("a"); + atag.href = url; + atag.innerText = name; + atag.onclick = (e) => { + e.preventDefault(); + changeSource(atag.href); + }; + + litag.appendChild(atag); + recentsEl.appendChild(litag); +} + +function addToRecents(savedObj, name, url) { + let recentObj = { + name: name, + url: url + }; + + recents.push(recentObj); + + let recentsStr = JSON.stringify({ recents: recents }); + localStorage.setItem('emptyfm', recentsStr); + + constructRecentEl(name, url); } function changeSource(url) { - player = videojs('emptyfm'); - mediaType = fetchMediaType(url); - player.src({ type: mediaType, src: url }); - player.play(); + player = videojs('emptyfm'); + mediaType = fetchMediaType(url); + player.src({ + type: mediaType, + src: url + }); + player.play(); } function fetchMediaType(url) { - last = url.split("/").pop(); - switch (last) { - case "stream": - return "audio/mpeg"; - default: - ext = last.split(".").pop(); - switch (ext) { - case "m3u8": - return "application/x-mpegURL"; + last = url.split("/").pop(); + switch (last) { + case "stream": + return "audio/mpeg"; default: - return "audio/mpeg"; - } - } + ext = last.split(".").pop(); + switch (ext) { + case "m3u8": + return "application/x-mpegURL"; + default: + return "audio/mpeg"; + } + } } function listCountries() { - fetch('./iso-3166-1-alpha2-countrycode.json') - .then((response) => response.json()) - .then((json) => { - let selectElem = document.getElementById("countryCode"); - - for (var k in json) { - if (json.hasOwnProperty(k)) { - let option = document.createElement("option"); - option.text = json[k]; - option.value = k; - - selectElem.appendChild(option); - } - } - }) + fetch('./iso-3166-1-alpha2-countrycode.json') + .then((response) => response.json()) + .then((json) => { + let selectElem = document.getElementById("countryCode"); + + for (var k in json) { + if (json.hasOwnProperty(k)) { + let option = document.createElement("option"); + option.text = json[k]; + option.value = k; + + selectElem.appendChild(option); + } + } + }) } function listLanguages() { - fetch('./iso-639-lang.json') - .then((response) => response.json()) - .then((json) => { - let selectElem = document.getElementById("languages"); - - for (var k in json) { - if (json.hasOwnProperty(k)) { - let option = document.createElement("option"); - option.text = json[k]; - option.value = k; - - selectElem.appendChild(option); - } - } - }) + fetch('./iso-639-lang.json') + .then((response) => response.json()) + .then((json) => { + let selectElem = document.getElementById("languages"); + + for (var k in json) { + if (json.hasOwnProperty(k)) { + let option = document.createElement("option"); + option.text = json[k]; + option.value = k; + + selectElem.appendChild(option); + } + } + }) } +populateRecents(); listCountries(); listLanguages(); diff --git a/index.html b/index.html @@ -24,13 +24,13 @@ } body { - font-size: 14px; + font-size: 17px; line-height: 1.5; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; padding: 0 2em; - margin: 3em auto; + margin: 2em auto; background-color: var(--bg); color: var(--fg); font-family: 'JetBrains Mono', monospace; @@ -40,6 +40,7 @@ .logo { display: block; + font-size: 1.2rem; margin-bottom: 2em; } @@ -50,16 +51,22 @@ text-decoration-thickness: 1px } + h3 { + font-size: 1rem; + } + select, button { width: 100%; height: 32px; - font-size: 14px; + font-size: 1rem; box-sizing: border-box; margin-bottom: 1em; } button { + font-family: 'JetBrains Mono', monospace; + font-size: 1.2rem; padding: 0 1em; background: #15C; border: 1px solid var(--fg); @@ -89,6 +96,30 @@ z-index: 1; } + .recents { + background: #efefef; + margin: 0 0 2rem; + } + + .recents ul { + max-height: 14em; + overflow-x: hidden; + overflow-y: auto; + margin: 0; + } + + .recents li { + margin: 1em 0; + } + + .recents h3 { + background: #666; + color: white; + margin: 0; + padding: 0 0.7em; + font-size: 1rem; + } + .video-js { background: transparent; } @@ -119,6 +150,11 @@ <a class="logo" href="/">emptyfm</a> <header> + <div class="recents"> + <h3>Recents</h3> + <ul id="recentList"></ul> + </div> + <div class="form-item"> <label for="countryCode">Choose a country:</label> <select name="country_code" id="countryCode"> @@ -149,4 +185,4 @@ <script src="emptyfm.js"></script> </body> -</html> -\ No newline at end of file +</html>