From 0931db7cd5efe485cc45ad50d5bdf9009be07ffb Mon Sep 17 00:00:00 2001 From: MattTheTekie Date: Mon, 4 May 2026 20:05:35 -0400 Subject: [PATCH] chore: fixes --- javascript/nav-music.js | 230 +++++++++++++++++++++++++--------------- 1 file changed, 146 insertions(+), 84 deletions(-) diff --git a/javascript/nav-music.js b/javascript/nav-music.js index b7d6c6c..c0867f7 100644 --- a/javascript/nav-music.js +++ b/javascript/nav-music.js @@ -1,54 +1,87 @@ -// Volume adjustment for audio elements +// ============================ +// Volume adjustment +// ============================ document.querySelectorAll("audio").forEach((audio) => { - audio.volume = 0.5; // Volume range is from 0.0 (silent) to 1.0 (maximum) + audio.volume = 0.5; }); -// Shuffle Playlist (Fisher-Yates) -function fisherYatesShuffle(songs) { - for (let i = songs.length - 1; i > 0; i--) { +// ============================ +// Fisher-Yates Shuffle +// ============================ +function fisherYatesShuffle(arr) { + for (let i = arr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); - [songs[i], songs[j]] = [songs[j], songs[i]]; + [arr[i], arr[j]] = [arr[j], arr[i]]; } - return songs; + return arr; } -// Load the JSON file containing music data directly from chat.veltron.net +// ============================ +// Fetch & build playlist safely +// ============================ async function loadMusicData() { - const targetUrl = 'https://api.veltron.net'; // Directly use the target URL - const response = await fetch(targetUrl); + try { + const response = await fetch("https://api.veltron.net"); - // Check if the request was successful - if (!response.ok) { - console.error("Failed to fetch music data:", response.statusText); + 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 []; } - - const data = await response.json(); - - // Get the "frutigerAeroBliss" section from the JSON - const section = data.ols.find(item => item["@id"] === "frutigerAeroBliss"); - - if (!section) { - console.error('Section "frutigerAeroBliss" not found.'); - return []; - } - - // Map the songs into a simplified format with direct audio URLs - const baseUrl = "https://cdn.veltron.net/aero"; // Base URL for the music files - const playlist = section.li.map(item => ({ - title: item.a.title, - url: baseUrl + item.a["@data-src-mp3"].split("/").pop(), // Build the full URL from the base path - background: item.a["@data-background"] || '', // Optional background if available - artist: item.a["@data-artist"] || '', - spotifyLink: item.a["@data-spotify"] || '', - youtubeLink: item.a["@data-youtube"] || '' - })); - - // Shuffle the playlist - return fisherYatesShuffle(playlist); } -// Define Music Player +// ============================ +// DOM Elements +// ============================ const NAV_MUSIC = document.getElementById("navMusic"); const BUTTON_PLAY = document.getElementById("navMusicPlay"); const BUTTON_PAUSE = document.getElementById("navMusicPause"); @@ -56,34 +89,48 @@ 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 currentTime = 0; -let isPlaying = false; // Track play/pause state +let isPlaying = false; -// Save state to sessionStorage +// ============================ +// Persistence +// ============================ function saveState() { sessionStorage.setItem("isPlaying", isPlaying); } -// Load state from sessionStorage function loadState() { - const savedIsPlaying = sessionStorage.getItem("isPlaying"); - - if (savedIsPlaying !== null) { - isPlaying = savedIsPlaying === "true"; + const saved = sessionStorage.getItem("isPlaying"); + if (saved !== null) { + isPlaying = saved === "true"; } } -// Load the current song +// ============================ +// Load Song (SAFE) +// ============================ function loadSong(index) { + if (!songs?.length) return; if (index < 0 || index >= songs.length) return; - NAV_MUSIC.src = songs[index].url; // Directly set the audio URL (no proxy needed) - CURRENT_SONG_INFO.innerText = `Featured song: ${songs[index].title}`; + + 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(); } -// Update button states based on `isPlaying` +// ============================ +// UI State +// ============================ function updateButtonStates() { if (isPlaying) { BUTTON_PLAY.classList.add("active"); @@ -94,74 +141,89 @@ function updateButtonStates() { } } -// Event listeners for playback controls -BUTTON_PLAY.addEventListener("click", function () { +// ============================ +// Controls +// ============================ +BUTTON_PLAY.addEventListener("click", () => { + if (!songs.length) return; + isPlaying = true; NAV_MUSIC.play(); updateButtonStates(); saveState(); }); -BUTTON_PAUSE.addEventListener("click", function () { +BUTTON_PAUSE.addEventListener("click", () => { isPlaying = false; NAV_MUSIC.pause(); updateButtonStates(); saveState(); }); -BUTTON_PREVIOUS.addEventListener("click", function () { +BUTTON_PREVIOUS.addEventListener("click", () => { + if (!songs.length) return; + currentIndex = currentIndex === 0 ? songs.length - 1 : currentIndex - 1; - currentTime = 0; // Reset time when switching songs loadSong(currentIndex); - if (isPlaying) { - NAV_MUSIC.play(); - } - updateButtonStates(); + + if (isPlaying) NAV_MUSIC.play(); saveState(); }); -BUTTON_NEXT.addEventListener("click", function () { +BUTTON_NEXT.addEventListener("click", () => { + if (!songs.length) return; + currentIndex = (currentIndex + 1) % songs.length; - currentTime = 0; // Reset time when switching songs loadSong(currentIndex); - if (isPlaying) { - NAV_MUSIC.play(); - } - updateButtonStates(); + + if (isPlaying) NAV_MUSIC.play(); saveState(); }); -// Autoplay next song when current ends -NAV_MUSIC.addEventListener("ended", function () { +// ============================ +// Auto-next +// ============================ +NAV_MUSIC.addEventListener("ended", () => { + if (!songs.length) return; + currentIndex = (currentIndex + 1) % songs.length; - currentTime = 0; // Reset time when a new song starts loadSong(currentIndex); - if (isPlaying) { - NAV_MUSIC.play(); - } + + if (isPlaying) NAV_MUSIC.play(); saveState(); }); -// Initial load +// ============================ +// Init +// ============================ window.addEventListener("load", async () => { songs = await loadMusicData(); - if (songs.length > 0) { - loadState(); - loadSong(currentIndex); - if (isPlaying) { - NAV_MUSIC.play(); - } - updateButtonStates(); + + 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 all audio if user presses play on another audio element +// ============================ +// Pause other audio elements +// ============================ document.addEventListener( "play", - function (e) { - var audios = document.getElementsByTagName("audio"); - for (var i = 0, len = audios.length; i < len; i++) { - if (audios[i] != e.target) { + (e) => { + const audios = document.getElementsByTagName("audio"); + for (let i = 0; i < audios.length; i++) { + if (audios[i] !== e.target) { audios[i].pause(); } }