// ============================ // Volume adjustment // ============================ document.querySelectorAll("audio").forEach((audio) => { audio.volume = 0.5; }); // ============================ // Fisher-Yates Shuffle // ============================ function fisherYatesShuffle(arr) { 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 // ============================ async function loadMusicData() { try { const response = await fetch("https://api.veltron.net"); if (!response.ok) { console.error("HTTP error:", response.status); return []; } const text = await response.text(); let data; try { data = JSON.parse(text); } catch (e) { console.error("Invalid JSON returned from API"); return []; } if (!data?.ols || !Array.isArray(data.ols)) { console.error("Invalid API structure"); return []; } const section = data.ols.find( (item) => item?.["@id"] === "frutigerAeroBliss" ); if (!section?.li || !Array.isArray(section.li)) { console.error("Playlist section missing or invalid"); return []; } const baseUrl = "https://cdn.veltron.net/aero"; const playlist = section.li .map((item) => { const mp3 = item?.a?.["@data-src-mp3"]; const title = item?.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"] || "" }; }) .filter(Boolean); return fisherYatesShuffle(playlist); } catch (err) { console.error("Failed to load music data:", err); return []; } } // ============================ // DOM Elements // ============================ const NAV_MUSIC = document.getElementById("navMusic"); const BUTTON_PLAY = document.getElementById("navMusicPlay"); const BUTTON_PAUSE = document.getElementById("navMusicPause"); const BUTTON_PREVIOUS = document.getElementById("navMusicPrevious"); const BUTTON_NEXT = document.getElementById("navMusicNext"); const CURRENT_SONG_INFO = document.getElementById("currentSongInfo"); // ============================ // State // ============================ let songs = []; let currentIndex = 0; let isPlaying = false; // ============================ // Persistence // ============================ function saveState() { sessionStorage.setItem("isPlaying", isPlaying); } function loadState() { const saved = sessionStorage.getItem("isPlaying"); if (saved !== null) { isPlaying = saved === "true"; } } // ============================ // Load Song (SAFE) // ============================ function loadSong(index) { if (!songs?.length) return; if (index < 0 || index >= songs.length) return; const song = songs[index]; if (!song?.url) { console.warn("Skipping invalid song:", index); return; } NAV_MUSIC.src = song.url; CURRENT_SONG_INFO.innerText = `Featured song: ${song.title}`; NAV_MUSIC.load(); } // ============================ // UI State // ============================ 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"); } } // ============================ // Controls // ============================ BUTTON_PLAY.addEventListener("click", () => { if (!songs.length) return; isPlaying = true; NAV_MUSIC.play(); updateButtonStates(); saveState(); }); BUTTON_PAUSE.addEventListener("click", () => { isPlaying = false; NAV_MUSIC.pause(); updateButtonStates(); saveState(); }); BUTTON_PREVIOUS.addEventListener("click", () => { if (!songs.length) return; currentIndex = currentIndex === 0 ? songs.length - 1 : currentIndex - 1; loadSong(currentIndex); if (isPlaying) NAV_MUSIC.play(); saveState(); }); BUTTON_NEXT.addEventListener("click", () => { if (!songs.length) return; currentIndex = (currentIndex + 1) % songs.length; loadSong(currentIndex); if (isPlaying) NAV_MUSIC.play(); saveState(); }); // ============================ // Auto-next // ============================ NAV_MUSIC.addEventListener("ended", () => { if (!songs.length) return; currentIndex = (currentIndex + 1) % songs.length; loadSong(currentIndex); if (isPlaying) NAV_MUSIC.play(); saveState(); }); // ============================ // Init // ============================ window.addEventListener("load", async () => { songs = await loadMusicData(); if (!songs.length) { console.error("No songs loaded."); CURRENT_SONG_INFO.innerText = "No music available"; return; } loadState(); loadSong(currentIndex); if (isPlaying) { NAV_MUSIC.play().catch(() => {}); } updateButtonStates(); }); // ============================ // Pause other audio elements // ============================ 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(); } } }, true );