diff --git a/javascript/nav-music.js b/javascript/nav-music.js index c0867f7..069343c 100644 --- a/javascript/nav-music.js +++ b/javascript/nav-music.js @@ -1,5 +1,5 @@ // ============================ -// Volume adjustment +// Volume normalization // ============================ document.querySelectorAll("audio").forEach((audio) => { audio.volume = 0.5; @@ -9,17 +9,20 @@ document.querySelectorAll("audio").forEach((audio) => { // Fisher-Yates Shuffle // ============================ function fisherYatesShuffle(arr) { + if (!Array.isArray(arr)) return []; + for (let i = arr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [arr[i], arr[j]] = [arr[j], arr[i]]; } + return arr; } // ============================ -// Fetch & build playlist safely +// Fetch music data (SAFE) // ============================ -async function loadMusicData() { +async function loadMusicData(category = "frutigerAeroBliss") { try { const response = await fetch("https://api.veltron.net"); @@ -28,27 +31,18 @@ async function loadMusicData() { return []; } - const text = await response.text(); - - let data; - try { - data = JSON.parse(text); - } catch (e) { - console.error("Invalid JSON returned from API"); - return []; - } + const data = await response.json(); if (!data?.ols || !Array.isArray(data.ols)) { - console.error("Invalid API structure"); + console.error("Invalid API structure:", data); return []; } - const section = data.ols.find( - (item) => item?.["@id"] === "frutigerAeroBliss" - ); + const section = + data.ols.find((item) => item?.["@id"] === category) || data.ols[0]; if (!section?.li || !Array.isArray(section.li)) { - console.error("Playlist section missing or invalid"); + console.error("Missing playlist section:", category); return []; } @@ -56,25 +50,25 @@ async function loadMusicData() { const playlist = section.li .map((item) => { - const mp3 = item?.a?.["@data-src-mp3"]; - const title = item?.a?.title; + const a = item?.a; + const mp3 = a?.["@data-src-mp3"]; + const title = a?.title; if (!mp3 || !title) return null; return { title, url: baseUrl + mp3.split("/").pop(), - background: item.a["@data-background"] || "", - artist: item.a["@data-artist"] || "", - spotifyLink: item.a["@data-spotify"] || "", - youtubeLink: item.a["@data-youtube"] || "" + background: a["@data-background"] || "", + artist: a["@data-artist"] || "", + youtubeLink: a["@data-youtube"] || "" }; }) .filter(Boolean); return fisherYatesShuffle(playlist); } catch (err) { - console.error("Failed to load music data:", err); + console.error("Failed to load music:", err); return []; } } @@ -97,29 +91,31 @@ let currentIndex = 0; let isPlaying = false; // ============================ -// Persistence +// Session persistence // ============================ function saveState() { - sessionStorage.setItem("isPlaying", isPlaying); + sessionStorage.setItem("isPlaying", JSON.stringify(isPlaying)); } function loadState() { const saved = sessionStorage.getItem("isPlaying"); if (saved !== null) { - isPlaying = saved === "true"; + isPlaying = JSON.parse(saved); } } // ============================ -// Load Song (SAFE) +// Safe song loader // ============================ function loadSong(index) { - if (!songs?.length) return; + if (!Array.isArray(songs) || songs.length === 0) return; + if (index < 0 || index >= songs.length) return; const song = songs[index]; + if (!song?.url) { - console.warn("Skipping invalid song:", index); + console.warn("Skipping invalid song at index:", index); return; } @@ -129,16 +125,11 @@ function loadSong(index) { } // ============================ -// UI State +// UI state sync // ============================ function updateButtonStates() { - if (isPlaying) { - BUTTON_PLAY.classList.add("active"); - BUTTON_PAUSE.classList.remove("active"); - } else { - BUTTON_PAUSE.classList.add("active"); - BUTTON_PLAY.classList.remove("active"); - } + BUTTON_PLAY.classList.toggle("active", isPlaying); + BUTTON_PAUSE.classList.toggle("active", !isPlaying); } // ============================ @@ -148,7 +139,7 @@ BUTTON_PLAY.addEventListener("click", () => { if (!songs.length) return; isPlaying = true; - NAV_MUSIC.play(); + NAV_MUSIC.play().catch(() => {}); updateButtonStates(); saveState(); }); @@ -166,7 +157,7 @@ BUTTON_PREVIOUS.addEventListener("click", () => { currentIndex = currentIndex === 0 ? songs.length - 1 : currentIndex - 1; loadSong(currentIndex); - if (isPlaying) NAV_MUSIC.play(); + if (isPlaying) NAV_MUSIC.play().catch(() => {}); saveState(); }); @@ -176,12 +167,12 @@ BUTTON_NEXT.addEventListener("click", () => { currentIndex = (currentIndex + 1) % songs.length; loadSong(currentIndex); - if (isPlaying) NAV_MUSIC.play(); + if (isPlaying) NAV_MUSIC.play().catch(() => {}); saveState(); }); // ============================ -// Auto-next +// Auto next track // ============================ NAV_MUSIC.addEventListener("ended", () => { if (!songs.length) return; @@ -189,7 +180,7 @@ NAV_MUSIC.addEventListener("ended", () => { currentIndex = (currentIndex + 1) % songs.length; loadSong(currentIndex); - if (isPlaying) NAV_MUSIC.play(); + if (isPlaying) NAV_MUSIC.play().catch(() => {}); saveState(); }); @@ -197,11 +188,11 @@ NAV_MUSIC.addEventListener("ended", () => { // Init // ============================ window.addEventListener("load", async () => { - songs = await loadMusicData(); + songs = await loadMusicData("frutigerAeroBliss"); if (!songs.length) { - console.error("No songs loaded."); CURRENT_SONG_INFO.innerText = "No music available"; + console.error("Playlist empty or failed to load"); return; } @@ -216,12 +207,13 @@ window.addEventListener("load", async () => { }); // ============================ -// Pause other audio elements +// Prevent multiple audio overlap // ============================ document.addEventListener( "play", (e) => { const audios = document.getElementsByTagName("audio"); + for (let i = 0; i < audios.length; i++) { if (audios[i] !== e.target) { audios[i].pause();