window.onload = async (e) => { const res = await (await fetch("https://www.nporadio2.nl/api/charts/npo-radio-2-top-2000-van-2025-12-25", {})).json(); window.ranking = res.positions; const offset = +window.location.search.slice(1); window.offset = offset; const now = Date.now() - offset * 1000; const curr = window.ranking.find(it => it.broadcastUnixTime < now); var current = curr.position.current; update(curr) setInterval(() => { const now = Date.now() - offset * 1000; const curr = window.ranking.find(it => it.broadcastUnixTime < now); if (curr.position.current != current) { current = curr.position.current; update(curr); } }, 1000); }; function update(curr) { console.log("Updating"); document.querySelector("#song-image").src = curr.track.coverUrl; const diff = document.querySelector("#song-diff"); diff.innerText = curr.position.label; diff.classList = curr.position.type; document.querySelector("#title").innerText = curr.track.title; document.querySelector("#artist").innerText = curr.track.artist; document.querySelector("#position").innerText = `Nummer ${curr.position.current}`; getGraph(curr.track.artist, curr.track.title); queue(curr.position.current); getTrivia(curr) } async function getGraph(artist, title) { const res = await (await fetch(`/graph/${artist.replace("?", "")}/${title}`, {})).json(); const width = 500; const labelSpace = 50; const barWidth = (width - labelSpace) / res.length; const height = 500; const cv = document.querySelector("#graph"); const ctx = cv.getContext('2d'); ctx.clearRect(0, 0, width, height); for (let i = 0; i <= 2000; i += 200) { const fraction = (i / 2000) * height; ctx.beginPath(); ctx.strokeStyle = "#808080"; ctx.lineWidth = 1; ctx.moveTo(labelSpace, fraction); ctx.lineTo(width, fraction); ctx.stroke(); ctx.font = "20px sans-serif"; ctx.fillStyle = "#808080"; ctx.fillText(i.toString(), 0, fraction); } for (let i = 0; i < res.length; i++) { const position = res[i].position; const fraction = (position / 2000) * height; // ctx.fillRect(barWidth * i, 0, barWidth, position / 10) ctx.beginPath(); ctx.fillStyle = "white"; ctx.arc(labelSpace + barWidth * i + 10, fraction, 2.5, 0, 2*Math.PI); ctx.fill(); } for (let i = 0; i < res.length-1; i++) { const curr = res[i].position; const next = res[i+1].position; const currFraction = (curr / 2000) * height; const nextFraction = (next / 2000) * height; // ctx.fillRect(barWidth * i, 0, barWidth, position / 10) ctx.beginPath(); ctx.strokeStyle = "white"; ctx.lineWidth = 5; ctx.lineCap = "round"; ctx.moveTo(labelSpace + barWidth * i + 10, currFraction); ctx.lineTo(labelSpace + barWidth * (i+1) + 10, nextFraction); ctx.stroke(); } } function queue(currPos) { const upcoming = window.ranking.filter(it => currPos - it.position.current < 10 && currPos - it.position.current >= -1) const queueEl = document.querySelector('#queue') queueEl.innerHTML = ""; for (const song of upcoming.reverse()) { const broadcastDT = new Date(song.broadcastUnixTime - offset * 1000); queueEl.innerHTML += `
${song.track.title}
${song.track.artist}
${broadcastDT.getHours().toString().padStart(2, "0")}:${broadcastDT.getMinutes().toString().padStart(2, "0")}