📻 NTS Live Widget - Listen to NTS Radio 🎶

CleanShot 2022-10-11 at 10 38 18

Creates a little sticky widget to play NTS live on either channel 1 or 2

NTS live: https://www.nts.live/

Install on Script Kit

Thx to @joshdavenport for the improvement adding the channel info! 💯


// Name: NTS Live
// Description: Stream NTS Live Channel 1 or 2
// Author: Vogelino, extended by Josh Davenport-Smith
// Twitter: @soyvogelino
// Shortcut:
import "@johnlindquist/kit";
const PLAYER_HEIGHT = 76;
const PLAYER_WIDTH = 205;
const getLogoSVG = (color) => `
<svg width="32px" height="32px" style="fill:${color};" viewBox="0 0 26 26"><path d="M22.7 6.9L22.3 9h-1.5l.5-2c.1-.6.1-1.1-.6-1.1s-1 .5-1.1 1.1l-.4 1.7c-.1.5-.1 1 0 1.5l1.4 4.1c.2.6.3 1.3.1 2l-.6 2.6c-.4 1.5-1.5 2.4-2.9 2.4-1.6 0-2.3-.7-1.9-2.4l.5-2.2h1.5l-.5 2.1c-.2.8 0 1.2.7 1.2.6 0 1-.5 1.2-1.2l.5-2.3c.1-.5.1-1.1-.1-1.6l-1.3-3.8c-.2-.7-.3-1.2-.2-2.1l.4-2c.4-1.6 1.4-2.4 2.9-2.4 1.7 0 2.2.8 1.8 2.3zM11.2 21.1L14.6 6H13l.3-1.3h4.8L17.8 6h-1.7l-3.4 15.1h-1.5zm-4.5 0L8.1 6.6 4.8 21.1H3.5L7.2 4.8h2.2L8 18.7l3.2-14h1.3L8.8 21.1H6.7zM0 26h26V0H0v26z"></path></svg>
`;
const getCloseIconSVG = (color) => `
<svg id="x" class="ml-1" width="32px" height="32px" viewBox="0 0 24 24" fill="${color}" class="pointer-event-none">
<path id="x" fill-rule="evenodd" d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm-1.72 6.97a.75.75 0 10-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 101.06 1.06L12 13.06l1.72 1.72a.75.75 0 101.06-1.06L13.06 12l1.72-1.72a.75.75 0 10-1.06-1.06L12 10.94l-1.72-1.72z" clip-rule="evenodd"/>
</svg>
`;
const btnCommonClasses = `px-4 text-center text-xl italic font-light cursor-default`;
const getJavascriptCode = () => `
const channels = {
one: { url: "https://stream-relay-geo.ntslive.net/stream2?client=NTSWebApp&t=1663096772944", apiIndex: 0 },
two: { url: "https://stream-relay-geo.ntslive.net/stream?client=NTSWebApp&t=1663095867072", apiIndex: 1 },
};
let currentChannel = channels.one;
function updateNowPlaying() {
if (!currentChannel) {
now.innterHTML = '';
return;
}
fetch('https://www.nts.live/api/v2/live')
.then(res => res.json())
.then(ntsLive => {
if (!ntsLive || !ntsLive.results) {
now.innterHTML = '';
return;
}
const channelData = ntsLive.results[currentChannel.apiIndex];
if (channelData && channelData.now && channelData.now.broadcast_title) {
const now = document.getElementById('now');
now.innerHTML = channelData.now.broadcast_title;
} else {
now.innterHTML = '';
}
});
}
function setChannel(channelKey) {
const audio = document.getElementById('audioPlayer');
const source = document.getElementById('audioSource');
currentChannel = channels[channelKey];
source.src = currentChannel.url;
audio.load();
audio.play();
updateNowPlaying();
}
function setActiveClasses(btnEl) {
btnEl.classList.add("font-bold")
btnEl.classList.remove("text-white")
btnEl.classList.add("bg-white")
btnEl.classList.add("text-black")
}
function setInactiveClasses(btnEl) {
btnEl.classList.remove("font-bold")
btnEl.classList.add("text-white")
btnEl.classList.remove("bg-white")
btnEl.classList.remove("text-black")
}
const btnOne = document.getElementById('channelOneButton');
btnOne.addEventListener('click', () => {
setActiveClasses(btnOne);
setInactiveClasses(btnTwo);
setChannel("one");
}, false);
const btnTwo = document.getElementById('channelTwoButton');
btnTwo.addEventListener('click', () => {
setActiveClasses(btnTwo);
setInactiveClasses(btnOne);
setChannel("two");
}, false);
setActiveClasses(btnOne);
setInactiveClasses(btnTwo);
setChannel("one");
`;
const wgt = await widget(
`
<div class="bg-black p-3 text-white">
<table>
<tr>
<td width="32px" class="pl-2 pr-4">${getLogoSVG("white")}</td>
<td id="channelOneButton" class="${btnCommonClasses}">1</td>
<td id="channelTwoButton" class="${btnCommonClasses}">2</td>
<td id="x" class="pl-2">${getCloseIconSVG("white")}</td>
</tr>
<tr>
<td colspan="4" class="text-xxs pt-2 pl-2 text-white">
<div id="now" class="w-48 whitespace-nowrap text-ellipsis overflow-hidden">Loading Show Info...</div>
</td>
</tr>
</table>
<audio id="audioPlayer" class="hidden" controls controlslist="nofullscreen nodownload noremoteplayback noplaybackrate">
<source id="audioSource">
</audio>
</div>
<script type="text/javascript">${getJavascriptCode()}</script>
`,
{ alwaysOnTop: true, state: { channelKey: "one" } }
);
wgt.setSize(PLAYER_WIDTH, PLAYER_HEIGHT);
wgt.onClick((event) => event.targetId === "x" && wgt.close());
wgt.onResized(() => wgt.setSize(PLAYER_WIDTH, PLAYER_HEIGHT));