diff --git a/javascript/music-player.js b/javascript/music-player.js index cb4e2dc..1069bff 100644 --- a/javascript/music-player.js +++ b/javascript/music-player.js @@ -14,21 +14,27 @@ let NAV_PREV = document.getElementById("navMusicPrevious"); // =============================== -// URL SANITIZER +// UNIVERSAL AUDIO URL SANITIZER // =============================== -function sanitizeMp3Url(raw) { +function sanitizeAudioUrl(raw) { if (!raw) return null; - // Reject invalid placeholders + // Reject placeholders or HTML anchors if (raw === "#" || raw === "/" || raw === "./" || raw === "../") return null; - // Reject URLs that are not MP3 files - if (!raw.endsWith(".mp3")) return null; + // Allowed audio extensions + const audioExtensions = [ + ".mp3", ".ogg", ".wav", ".m4a", ".aac", ".flac", ".opus", ".webm" + ]; - // If JSON gives absolute URL + const lower = raw.toLowerCase(); + const isAudio = audioExtensions.some(ext => lower.endsWith(ext)); + if (!isAudio) return null; + + // Absolute URL if (raw.startsWith("http")) return raw; - // If JSON gives /music/... or /audio/... + // JSON gives /music/... or /audio/... if (raw.startsWith("/")) { return "https://frutigeraeroarchive.org" + raw; } @@ -39,10 +45,13 @@ function sanitizeMp3Url(raw) { // =============================== -// LOAD MUSIC DATA +// LOAD MUSIC DATA (CORS PROXY) // =============================== async function loadMusicData() { - const response = await fetch("https://frutigeraeroarchive.org/data/music.min.json"); + const response = await fetch( + "https://corsproxy.io/?url=https%3A%2F%2Ffrutigeraeroarchive.org%2Fdata%2Fmusic.min.json" + ); + const data = await response.json(); const section = data.ols.find(item => item["@id"] === "frutigerAeroBliss"); @@ -51,22 +60,15 @@ async function loadMusicData() { // KEEP JSON ORDER EXACTLY, but filter invalid URLs return section.li .map(item => { - const fixedUrl = sanitizeMp3Url(item.a["@data-src-mp3"]); + const fixedUrl = sanitizeAudioUrl(item.a["@data-src-mp3"]); if (!fixedUrl) return null; return { - title: item.a.title, - url: fixedUrl, - background: item.a["@data-background"] || "", - artist: item.a["@data-artist"] || "", - spotify: item.a["@data-spotify"] || "", - youtube: item.a["@data-youtube"] || "", - description: item.a["@data-description"] || "", - copyright: item.a["@data-copyright"] || "", - date: item.a["@data-date"] || "" + ...item.a, + "@data-src-mp3": fixedUrl }; }) - .filter(Boolean); // remove null entries + .filter(Boolean); } @@ -90,7 +92,7 @@ function createAlbum(album) { small.textContent = album.small; list.appendChild(small); - // Build playlist in EXACT JSON ORDER + // Build playlist ONLY from valid songs album.li.forEach((song, index) => { const li = document.createElement("li"); const a = document.createElement("a"); @@ -98,7 +100,6 @@ function createAlbum(album) { a.textContent = song.a.title; a.href = "#"; - // Apply metadata for (const key in song.a) { if (key.startsWith("@data-")) { a.setAttribute(key.replace("@", ""), song.a[key]); @@ -121,7 +122,6 @@ function createAlbum(album) { }); }); - // ALWAYS START AT SONG 0 currentSongIndex = 0; updateSong(0); }