var player; var canvasCtx; var audioCtx; var analyser; var audio_data; var draw_loop; var vol_prev; function init() { player = document.querySelector('#player'); canvasCtx = document.querySelector('#visualizer').getContext('2d'); player.addEventListener('ended', nextTrack); player.addEventListener('loadedmetadata', display_duration); player.addEventListener('timeupdate', update_position); navigator.mediaSession.setActionHandler('play', playTrack); navigator.mediaSession.setActionHandler('pause', pauseTrack); navigator.mediaSession.setActionHandler('stop', stopTrack); navigator.mediaSession.setActionHandler('previoustrack', prevTrack); navigator.mediaSession.setActionHandler('nexttrack', nextTrack); let seek = document.querySelector('#seek-slider'); seek.addEventListener('input', function(){ player.currentTime = seek.value; display_current_time(); }); let vol = document.querySelector('#volume-slider'); vol.addEventListener('input', function(){ player.volume = vol.value/100; if (vol.value == 0) { document.querySelector('#vol-btn').style.display = 'none'; document.querySelector('#vol-off-btn').style.display = 'initial'; } else { document.querySelector('#vol-btn').style.display = 'initial'; document.querySelector('#vol-off-btn').style.display = 'none'; } }); //init_analyzer(); } async function get_rand_track() { let res = await fetch("./rand_track/") let data = await res.json(); return data; } async function nextTrack() { track = await get_rand_track(); player.src = track.source; update_now_playing(track); playTrack(); } function prevTrack() { // TODO: implement a history array } async function playTrack() { if (!player.src) { return nextTrack(); } player.play(); navigator.mediaSession.playbackState = "playing"; if (!audioCtx) { init_analyzer(); } document.querySelector("#play-btn").style.display = "none"; document.querySelector("#pause-btn").style.display = "initial"; } function pauseTrack() { player.pause(); navigator.mediaSession.playbackState = "paused"; document.querySelector("#play-btn").style.display = "initial"; document.querySelector("#pause-btn").style.display = "none"; } function stopTrack() { player.pause(); player.load(); navigator.mediaSession.playbackState = "none"; document.querySelector("#play-btn").style.display = "initial"; document.querySelector("#pause-btn").style.display = "none"; } function setMediaSession(track) { navigator.mediaSession.metadata = new MediaMetadata({ title: track.title, artist: track.artist, album: track.album, artwork: track.artwork }); } function update_now_playing(track) { track.artwork.pop(1); // remove lower resolution option document.querySelector('#now_playing_artist').textContent = track.artist; document.querySelector('#now_playing_album').textContent = track.album; document.querySelector('#now_playing_title').textContent = track.title; document.querySelector('#cover_art').firstChild.src = track.artwork[0].src; setMediaSession(track); } function update_position() { if (!player.duration){return;} navigator.mediaSession.setPositionState({ duration: Math.floor(player.duration), playbackRate: player.playbackRate, position: Math.floor(player.currentTime) }); //analyser.getByteTimeDomainData(audio_data); document.querySelector('#seek-slider').value = Math.floor(player.currentTime); display_current_time(); } function calculate_time(raw_secs) { let mins = Math.floor(raw_secs / 60); let secs = Math.round(raw_secs % 60); let ret = mins + ':' + String(secs).padStart(2,'0'); return ret; } function display_duration() { let dur = document.querySelector('#duration'); dur.textContent = calculate_time(player.duration); document.querySelector('#seek-slider').max = Math.floor(player.duration); } function display_current_time() { cur = document.querySelector('#current-time'); cur.textContent = calculate_time(player.currentTime); } function volume_off() { let vol = document.querySelector('#volume-slider'); vol_prev = vol.value; vol.value = 0; player.volume = 0; document.querySelector('#vol-btn').style.display = 'none'; document.querySelector('#vol-off-btn').style.display = 'initial'; } function volume_restore() { let vol = document.querySelector('#volume-slider'); vol.value = vol_prev; player.volume = vol_prev / 100; document.querySelector('#vol-btn').style.display = 'initial'; document.querySelector('#vol-off-btn').style.display = 'none'; } function init_analyzer() { audioCtx = new AudioContext(); analyser = audioCtx.createAnalyser(); let source = audioCtx.createMediaElementSource(player); source.connect(analyser); source.connect(audioCtx.destination); analyser.fftSize = 256; analyser.minDecibels = -90; analyser.maxDecibels = -10; analyser.smoothingTimeConstant = 0.85; audio_data = new Uint8Array(analyser.frequencyBinCount); let canvas = document.querySelector('#visualizer'); canvasCtx.clearRect(0, 0, canvas.width, canvas.height); draw(); } function draw() { draw_loop = requestAnimationFrame(draw); analyser.getByteTimeDomainData(audio_data); let canvas = document.querySelector('#visualizer'); canvasCtx.fillStyle = "rgb(0 0 0)"; canvasCtx.fillRect(0, 0, canvas.width, canvas.height); const barWidth = (canvas.width / analyser.frequencyBinCount) * 2.5; let barHeight; let x = 0; for (let i = 0; i < analyser.frequencyBinCount; i++) { barHeight = audio_data[i]; canvasCtx.fillStyle = `rgb(${barHeight + 100} 50 50)`; canvasCtx.fillRect(x, canvas.height - barHeight, barWidth, barHeight); x += barWidth + 1; } }