diff options
author | Indrajith K L | 2025-06-30 02:37:28 +0530 |
---|---|---|
committer | Indrajith K L | 2025-06-30 02:37:28 +0530 |
commit | ae44e79a15b2257c3034b272ccdf2d69b01c6455 (patch) | |
tree | 6f12ddf42914cbc68a9467b946d37083458510e3 /player.js | |
parent | c708bb42da85c880fd472217d853a5c99189b6b5 (diff) | |
download | retrowave-player-ae44e79a15b2257c3034b272ccdf2d69b01c6455.tar.gz retrowave-player-ae44e79a15b2257c3034b272ccdf2d69b01c6455.tar.bz2 retrowave-player-ae44e79a15b2257c3034b272ccdf2d69b01c6455.zip |
New Features and Cosmetics
* Adds option to toggle fullscreen
* Adds option to hide controls and hide music player(just visualization only)
* Font Changes
* Adds Stylized tooltips
Diffstat (limited to 'player.js')
-rw-r--r-- | player.js | 589 |
1 files changed, 336 insertions, 253 deletions
@@ -1,293 +1,376 @@ (function () { - let isPlaying = false; - let currentTracks = []; - let cursor = 0; - let howlerInstance; - const retroWaveRu = "https://retrowave.ru"; - let titleEl = document.getElementById("track-name"); - let coverArtEl = document.getElementsByClassName("music-player")[0]; - let refreshBtn = document.querySelector(".refresh"); - const modalEl = document.getElementById("intro-modal"); - // const uploadInfoEl = document.getElementById("upload-info"); - const fileUploadEl = document.getElementById("file-upload"); - let volume = 1; - let effectCanvas; - let starField; - let line3D; - const synthwaveColor = 0xff2975; - - openDialog(); - getMusic(); - listenUploadFileChange(); - - coverArtEl.addEventListener("click", (event) => { - const isNoPause = event.target.classList.contains("no-pause"); - if (howlerInstance && !isNoPause) { - togglePlay(); + let isPlaying = false; + let currentTracks = []; + let cursor = 0; + let howlerInstance; + const retroWaveRu = "https://retrowave.ru"; + let titleEl = document.getElementById("track-name"); + let coverArtEl = document.getElementsByClassName("music-player")[0]; + let refreshBtn = document.querySelector(".refresh"); + let ovr = document.querySelector(".OVR"); + let fullScreenBtn = document.querySelector(".fullscreen"); + const modalEl = document.getElementById("intro-modal"); + // const uploadInfoEl = document.getElementById("upload-info"); + const fileUploadEl = document.getElementById("file-upload"); + let volume = 1; + let effectCanvas; + let starField; + let line3D; + const synthwaveColor = 0xff2975; + + openDialog(); + getMusic(); + listenUploadFileChange(); + + function initDynamicTooltips() { + document.querySelectorAll("[title]").forEach((element) => { + const title = element.getAttribute("title"); + element.removeAttribute("title"); + element.setAttribute("data-title", title); + + element.addEventListener("mouseenter", function (e) { + const tooltip = document.createElement("div"); + tooltip.textContent = this.getAttribute("data-title"); + tooltip.style.cssText = ` + font-family: "VCR", sans-serif; + position: fixed; + background:rgb(255, 255, 255); + color: #000000; + border: 1px solidrgb(0, 0, 0); + padding: 4px 8px; + font-size: 12px; + border-radius: 3px; + z-index: 10000; + pointer-events: none; + white-space: nowrap; + `; + + document.body.appendChild(tooltip); + this.tooltipEl = tooltip; + + const rect = this.getBoundingClientRect(); + tooltip.style.left = + rect.left + rect.width / 2 - tooltip.offsetWidth / 2 + "px"; + tooltip.style.top = rect.top - tooltip.offsetHeight - 8 + "px"; + }); + + element.addEventListener("mouseleave", function () { + if (this.tooltipEl) { + document.body.removeChild(this.tooltipEl); + this.tooltipEl = null; } + }); }); + } - // uploadInfoEl.addEventListener("click", () => { - // const confirmText = `Do you really want to change your playlist?\nThis will replace all your retrowave music history.\nIf you are sure about this, make sure to upload a valid json file probably downloaded using history link.`; - - // if (confirm(confirmText)) { - // fileUploadEl.click(); - // } - // }); - - function listenUploadFileChange() { - fileUploadEl.onchange = function () { - const selectedFile = fileUploadEl.files[0]; - const reader = new FileReader(); - reader.readAsText(selectedFile, "UTF-8"); - reader.onload = function (event) { - try { - const uploadedPlaylist = JSON.parse(event.target.result); - localStorage.setItem("retrowave-history", event.target.result); - - } catch (error) { - alert("malformed/invalid json file"); - } - }; - }; - } - - document.getElementById("initButton")?.addEventListener("click", () => { - var hydra = new Hydra({ detectAudio: false }) - modalEl.classList.remove("open"); - playMusic(); - initHydra(); - initControls(); - }); - - document.getElementById("history").addEventListener("click", () => { - downloadHistory(); - }); - - document.addEventListener("keyup", (event) => { - const { key } = event; - console.log("key pressed", key); - switch (key) { - case " ": - togglePlay(); - break; - case "a": - break; - case "d": - break; - case "w": - volumeUp(); - break; - case "s": - volumeDown(); - break; - case "n": - playNextTrack(); - break; - - } - }); + document.addEventListener("DOMContentLoaded", initDynamicTooltips); - let touchstartX = 0; - let touchendX = 0; - let touchstartY = 0; - let touchendY = 0; - const musixPlayerEl = document.getElementsByClassName("music-player")[0]; - if (musixPlayerEl) { - musixPlayerEl.addEventListener("touchstart", (e) => { - touchstartX = e.changedTouches[0].screenX; - touchstartY = e.changedTouches[0].screenY; - }); - - musixPlayerEl.addEventListener("touchend", (e) => { - touchendX = e.changedTouches[0].screenX; - touchendY = e.changedTouches[0].screenY; - checkDirection(); - }); + coverArtEl.addEventListener("click", (event) => { + const isNoPause = event.target.classList.contains("no-pause"); + if (howlerInstance && !isNoPause) { + togglePlay(); } - - function checkDirection() { - if (touchendX < touchstartX) { - // Swipe Left - } - if (touchendX > touchstartX) { - // Swipe Right - } - - if (touchendY < touchstartY) { - volumeUp(); - } - if (touchendY > touchstartY) { - volumeDown(); + }); + + // uploadInfoEl.addEventListener("click", () => { + // const confirmText = `Do you really want to change your playlist?\nThis will replace all your retrowave music history.\nIf you are sure about this, make sure to upload a valid json file probably downloaded using history link.`; + + // if (confirm(confirmText)) { + // fileUploadEl.click(); + // } + // }); + + function listenUploadFileChange() { + fileUploadEl.onchange = function () { + const selectedFile = fileUploadEl.files[0]; + const reader = new FileReader(); + reader.readAsText(selectedFile, "UTF-8"); + reader.onload = function (event) { + try { + const uploadedPlaylist = JSON.parse(event.target.result); + localStorage.setItem("retrowave-history", event.target.result); + } catch (error) { + alert("malformed/invalid json file"); } + }; + }; + } + + document.getElementById("initButton")?.addEventListener("click", () => { + var hydra = new Hydra({ detectAudio: false }); + modalEl.classList.remove("open"); + playMusic(); + initHydra(); + initControls(); + }); + + document.getElementById("history").addEventListener("click", () => { + downloadHistory(); + }); + + document.addEventListener("keyup", (event) => { + const { key } = event; + switch (key) { + case " ": + togglePlay(); + break; + case "a": + break; + case "d": + break; + case "w": + volumeUp(); + break; + case "s": + volumeDown(); + break; + case "n": + playNextTrack(); + break; + case "f": + toggleFullScreen(); + break; + case "h": + toggleControls(); + break; + case 'x': + toggleEverything(); } + }); + + let touchstartX = 0; + let touchendX = 0; + let touchstartY = 0; + let touchendY = 0; + const musixPlayerEl = document.getElementsByClassName("music-player")[0]; + if (musixPlayerEl) { + musixPlayerEl.addEventListener("touchstart", (e) => { + touchstartX = e.changedTouches[0].screenX; + touchstartY = e.changedTouches[0].screenY; + }); - function openDialog() { - modalEl.classList.add("open"); - } + musixPlayerEl.addEventListener("touchend", (e) => { + touchendX = e.changedTouches[0].screenX; + touchendY = e.changedTouches[0].screenY; + checkDirection(); + }); + } - async function getMusic() { - const res = await fetch( - `https://retrowave.ru/api/v1/tracks?limit=10&cursor=${cursor}` - ).then((res) => res.json()); - const { - body: { tracks, cursor: currentCursor }, - } = res; - cursor = currentCursor; - currentTracks = tracks; + function checkDirection() { + if (touchendX < touchstartX) { + // Swipe Left } - - function initPlayer() { } - - function playMusic() { - const currentTrack = currentTracks[0]; - const singleTrack = currentTrack.streamUrl; - const fullTrack = `${retroWaveRu}${singleTrack}`; - howlerInstance = new Howl({ - src: [fullTrack], - html5: true, - onend: function () { - playNextTrack(); - }, - }); - setVolume(); - isPlaying = true; - window.hw = howlerInstance - - updateInfo(currentTrack); - - addToHistory(currentTrack); - howlerInstance.play(); + if (touchendX > touchstartX) { + // Swipe Right } - function volumeDown() { - console.log(volume); - if (volume > 0.1) { - volume -= 0.1; - } - setVolume(); + if (touchendY < touchstartY) { + volumeUp(); } - - function volumeUp() { - if (volume < 1) { - volume += 0.1; - } - setVolume(); + if (touchendY > touchstartY) { + volumeDown(); } + } + + function openDialog() { + modalEl.classList.add("open"); + } + + async function getMusic() { + const res = await fetch( + `https://retrowave.ru/api/v1/tracks?limit=10&cursor=${cursor}` + ).then((res) => res.json()); + const { + body: { tracks, cursor: currentCursor }, + } = res; + cursor = currentCursor; + currentTracks = tracks; + } + + function initPlayer() {} + + function playMusic() { + const currentTrack = currentTracks[0]; + const singleTrack = currentTrack.streamUrl; + const fullTrack = `${retroWaveRu}${singleTrack}`; + howlerInstance = new Howl({ + src: [fullTrack], + html5: true, + onend: function () { + playNextTrack(); + }, + }); + setVolume(); + isPlaying = true; + window.hw = howlerInstance; - function setVolume() { - howlerInstance.volume(volume); - } + updateInfo(currentTrack); - function togglePlay() { - isPlaying = !isPlaying; + addToHistory(currentTrack); + howlerInstance.play(); + } - if (isPlaying) { - howlerInstance.play(); - } else { - howlerInstance.pause(); - } + function volumeDown() { + if (volume > 0.1) { + volume -= 0.1; } + setVolume(); + } - function updateInfo(trackDetails) { - titleEl.innerText = trackDetails.title; - document.title = `Now Playing... ${trackDetails.title}`; - coverArtEl.style.backgroundImage = `url("${retroWaveRu}${trackDetails.artworkUrl}")`; + function volumeUp() { + if (volume < 1) { + volume += 0.1; } + setVolume(); + } - function getHistory() { - let localHistoryStore = localStorage.getItem("retrowave-history") || "[]"; - let historyArray = JSON.parse(localHistoryStore); - return historyArray; - } + function setVolume() { + howlerInstance.volume(volume); + } - function addToHistory(trackDetails) { - let historyArray = getHistory(); - historyArray.push(trackDetails); - localStorage.setItem("retrowave-history", JSON.stringify(historyArray)); - } + function togglePlay() { + isPlaying = !isPlaying; - function downloadHistory() { - const historyArray = getHistory(); - let element = document.createElement("a"); - let playListData = '#EXTM3U'; - historyArray.forEach((musicData) => { - playListData = `${playListData} + if (isPlaying) { + howlerInstance.play(); + } else { + howlerInstance.pause(); + } + } + + function updateInfo(trackDetails) { + titleEl.innerText = trackDetails.title; + document.title = `Now Playing... ${trackDetails.title}`; + coverArtEl.style.backgroundImage = `url("${retroWaveRu}${trackDetails.artworkUrl}")`; + ovr.innerHTML = `${trackDetails.title}` + } + + function getHistory() { + let localHistoryStore = localStorage.getItem("retrowave-history") || "[]"; + let historyArray = JSON.parse(localHistoryStore); + return historyArray; + } + + function addToHistory(trackDetails) { + let historyArray = getHistory(); + historyArray.push(trackDetails); + localStorage.setItem("retrowave-history", JSON.stringify(historyArray)); + } + + function downloadHistory() { + const historyArray = getHistory(); + let element = document.createElement("a"); + let playListData = "#EXTM3U"; + historyArray.forEach((musicData) => { + playListData = `${playListData} #EXTINF:${Math.ceil(musicData.duration / 1000)}, ${musicData.title} https://retrowave.ru/${musicData.streamUrl} `; - }); + }); - element.setAttribute( - "href", - "data:audio/x-mpegurl;;charset=utf-8," + - encodeURIComponent(playListData) - ); - element.setAttribute("download", "retrowave_playlist.m3u"); + element.setAttribute( + "href", + "data:audio/x-mpegurl;;charset=utf-8," + encodeURIComponent(playListData) + ); + element.setAttribute("download", "retrowave_playlist.m3u"); - element.style.display = "none"; - document.body.appendChild(element); + element.style.display = "none"; + document.body.appendChild(element); - element.click(); + element.click(); - document.body.removeChild(element); - } + document.body.removeChild(element); + } - function playNextTrack() { - resetHowler(); - currentTracks.shift(); - if (currentTracks.length <= 3) { - getMusic(); - } - playMusic(); + function playNextTrack() { + resetHowler(); + currentTracks.shift(); + if (currentTracks.length <= 3) { + getMusic(); } - - function resetHowler(destroy = false) { - howlerInstance.stop(); - if (destroy) { - howlerInstance.unload(); - howlerInstance = null; - } + playMusic(); + } + + function resetHowler(destroy = false) { + howlerInstance.stop(); + if (destroy) { + howlerInstance.unload(); + howlerInstance = null; } + } - function initControls() { - refreshBtn.addEventListener("click", () => { - playNextTrack(); - }); + function initControls() { + refreshBtn.addEventListener("click", () => { + playNextTrack(); + }); + + fullScreenBtn.addEventListener("click", () => { + toggleFullScreen(); + }); + } + + function toggleFullScreen() { + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen(); + } else { + if (document.exitFullscreen) { + document.exitFullscreen(); + } } + } - // function initCodef() { - // const width = window.innerWidth; - // const height = window.innerHeight; - // effectCanvas = new canvas(width, height, 'codef-canvas'); - // starField = new starfield3D(effectCanvas, 500, 2, width, height, width/2, height/2, '#ffffff', 100, 0, 0); - // line3D = new codef3D(effectCanvas, 320, 75, 1, 1500 ); - // line3D.line({x:-320, y:0, z:0},{x:320, y:0, z:0}, new LineBasicMaterial({ color: synthwaveColor, linewidth:2})); - // line3D.line({x: 0, y:-240, z:0},{x:0, y:240, z:0}, new LineBasicMaterial({ color: synthwaveColor, linewidth:2})); - // renderCodeFx(); - // } - - // function renderCodeFx() { - // effectCanvas.fill('#000000'); - // line3D.group.rotation.x+=0.01; - // line3D.group.rotation.y+=0.02; - // line3D.group.rotation.z+=0.04; - // starField.draw(); - // line3D.draw(); - // requestAnimationFrame(renderCodeFx); - // } - - function initHydra() { - voronoi(350, 0.15) - .modulateScale(osc(8).rotate(Math.sin(time)), .5) - .thresh(.8) - .modulateRotate(osc(7), .4) - .thresh(.7) - .diff(src(o0).scale(1.8)) - .modulateScale(osc(2).modulateRotate(o0, .74)) - .diff(src(o0).rotate([-.012, .01, -.002, 0]).scrollY(0, [-1 / 199800, 0].fast(0.7))) - .brightness([-.02, -.17].smooth().fast(.5))//.modulate(o0, () => a.fft[1] * .2) - .out() + function toggleControls() { + const toggleableElements = document.querySelectorAll(".toggleable"); + toggleableElements.forEach((el) => { + el.classList.toggle("hidden"); + }); + } + + function toggleEverything() { + musixPlayerEl.classList.toggle("hidden"); + ovr.classList.toggle("hidden"); + } + + // function initCodef() { + // const width = window.innerWidth; + // const height = window.innerHeight; + // effectCanvas = new canvas(width, height, 'codef-canvas'); + // starField = new starfield3D(effectCanvas, 500, 2, width, height, width/2, height/2, '#ffffff', 100, 0, 0); + // line3D = new codef3D(effectCanvas, 320, 75, 1, 1500 ); + // line3D.line({x:-320, y:0, z:0},{x:320, y:0, z:0}, new LineBasicMaterial({ color: synthwaveColor, linewidth:2})); + // line3D.line({x: 0, y:-240, z:0},{x:0, y:240, z:0}, new LineBasicMaterial({ color: synthwaveColor, linewidth:2})); + // renderCodeFx(); + // } + + // function renderCodeFx() { + // effectCanvas.fill('#000000'); + // line3D.group.rotation.x+=0.01; + // line3D.group.rotation.y+=0.02; + // line3D.group.rotation.z+=0.04; + // starField.draw(); + // line3D.draw(); + // requestAnimationFrame(renderCodeFx); + // } + + function initHydra() { + try { + voronoi(350, 0.15) + .modulateScale(osc(8).rotate(Math.sin(time)), 0.5) + .thresh(0.8) + .modulateRotate(osc(7), 0.4) + .thresh(0.7) + .diff(src(o0).scale(1.8)) + .modulateScale(osc(2).modulateRotate(o0, 0.74)) + .diff( + src(o0) + .rotate([-0.012, 0.01, -0.002, 0]) + .scrollY(0, [-1 / 199800, 0].fast(0.7)) + ) + .brightness([-0.02, -0.17].smooth().fast(0.5)) //.modulate(o0, () => a.fft[1] * .2) + .out(); + } catch (error) { + console.error("Hydra initialization failed:", error); } + } })(); |