chore: update stuff

This commit is contained in:
MattTheTekie 2026-02-27 17:53:54 -05:00
commit 8b02a6ee14

View file

@ -1,164 +1,197 @@
// Volume adjustment for audio elements
document.querySelectorAll("audio").forEach((audio) => {
audio.volume = 0.5; // Volume range is from 0.0 (silent) to 1.0 (maximum)
});
// ===============================
// INITIAL SETUP
// ===============================
let currentSongIndex = 0;
let SONG_LINKS = [];
let PLAYLIST = document.getElementById("playlistLeft");
let AUDIO_PLAYER = document.getElementById("navMusic");
let TRACK_NAME_DISPLAY = document.getElementById("currentSongInfo");
// Shuffle Playlist (Fisher-Yates)
function fisherYatesShuffle(songs) {
for (let i = songs.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[songs[i], songs[j]] = [songs[j], songs[i]];
let NAV_PLAY = document.getElementById("navMusicPlay");
let NAV_PAUSE = document.getElementById("navMusicPause");
let NAV_NEXT = document.getElementById("navMusicNext");
let NAV_PREV = document.getElementById("navMusicPrevious");
// ===============================
// UNIVERSAL AUDIO URL SANITIZER
// ===============================
function sanitizeAudioUrl(raw) {
if (!raw) return null;
// Reject placeholders or HTML anchors
if (raw === "#" || raw === "/" || raw === "./" || raw === "../") return null;
// Allowed audio extensions
const audioExtensions = [
".mp3", ".ogg", ".wav", ".m4a", ".aac", ".flac", ".opus", ".webm"
];
const lower = raw.toLowerCase();
const isAudio = audioExtensions.some(ext => lower.endsWith(ext));
if (!isAudio) return null;
// Absolute URL
if (raw.startsWith("http")) return raw;
// JSON gives /music/... or /audio/...
if (raw.startsWith("/")) {
return "https://frutigeraeroarchive.org" + raw;
}
return songs;
// Otherwise treat as relative filename
return "https://frutigeraeroarchive.org/music/" + raw;
}
// Load the JSON file containing music data (using CORS proxy)
// ===============================
// LOAD MUSIC DATA (CORS PROXY)
// ===============================
async function loadMusicData() {
const corsProxyUrl = 'https://corsproxy.io/?url=';
const targetUrl = 'https://frutigeraeroarchive.org/data/music.min.json';
const response = await fetch(corsProxyUrl + encodeURIComponent(targetUrl));
const response = await fetch(
"http://chat.veltron.net"
);
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.');
// Safety check to prevent crashes
if (!data || !data.ols) {
console.error("Music JSON is invalid or blocked by CORS:", data);
return [];
}
// Map the songs into a simplified format with direct audio URLs
const baseUrl = "https://frutigeraeroarchive.org/music/"; // 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"] || ''
}));
const section = data.ols.find(item => item["@id"] === "frutigerAeroBliss");
if (!section) return [];
// Shuffle the playlist
return fisherYatesShuffle(playlist);
// KEEP JSON ORDER EXACTLY, but filter invalid URLs
return section.li
.map(item => {
const fixedUrl = sanitizeAudioUrl(item.a["@data-src-mp3"]);
if (!fixedUrl) return null;
return {
...item.a,
"@data-src-mp3": fixedUrl
};
})
.filter(Boolean);
}
// Define Music Player
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");
let songs = [];
let currentIndex = 0;
let currentTime = 0;
let isPlaying = false; // Track play/pause state
// ===============================
// CREATE PLAYLIST
// ===============================
function createAlbum(album) {
if (!PLAYLIST) return;
// Save state to sessionStorage
function saveState() {
sessionStorage.setItem("isPlaying", isPlaying);
}
const existing = PLAYLIST.querySelector("ol");
if (existing) existing.remove();
// Load state from sessionStorage
function loadState() {
const savedIsPlaying = sessionStorage.getItem("isPlaying");
const list = document.createElement("ol");
list.id = album["@id"];
if (savedIsPlaying !== null) {
isPlaying = savedIsPlaying === "true";
}
}
const title = document.createElement("span");
title.textContent = album.span;
list.appendChild(title);
// Load the current song
function loadSong(index) {
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}`;
NAV_MUSIC.load();
}
const small = document.createElement("small");
small.textContent = album.small;
list.appendChild(small);
// Update button states based on `isPlaying`
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");
}
}
// Build playlist ONLY from valid songs
album.li.forEach((song, index) => {
const li = document.createElement("li");
const a = document.createElement("a");
// Event listeners for playback controls
BUTTON_PLAY.addEventListener("click", function () {
isPlaying = true;
NAV_MUSIC.play();
updateButtonStates();
saveState();
});
a.textContent = song.a.title;
a.href = "#";
BUTTON_PAUSE.addEventListener("click", function () {
isPlaying = false;
NAV_MUSIC.pause();
updateButtonStates();
saveState();
});
BUTTON_PREVIOUS.addEventListener("click", function () {
currentIndex = currentIndex === 0 ? songs.length - 1 : currentIndex - 1;
currentTime = 0; // Reset time when switching songs
loadSong(currentIndex);
if (isPlaying) {
NAV_MUSIC.play();
}
updateButtonStates();
saveState();
});
BUTTON_NEXT.addEventListener("click", function () {
currentIndex = (currentIndex + 1) % songs.length;
currentTime = 0; // Reset time when switching songs
loadSong(currentIndex);
if (isPlaying) {
NAV_MUSIC.play();
}
updateButtonStates();
saveState();
});
// Autoplay next song when current ends
NAV_MUSIC.addEventListener("ended", function () {
currentIndex = (currentIndex + 1) % songs.length;
currentTime = 0; // Reset time when a new song starts
loadSong(currentIndex);
if (isPlaying) {
NAV_MUSIC.play();
}
saveState();
});
// Initial load
window.addEventListener("load", async () => {
songs = await loadMusicData();
if (songs.length > 0) {
loadState();
loadSong(currentIndex);
if (isPlaying) {
NAV_MUSIC.play();
}
updateButtonStates();
}
});
// Pause all audio if user presses play on another audio element
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) {
audios[i].pause();
for (const key in song.a) {
if (key.startsWith("@data-")) {
a.setAttribute(key.replace("@", ""), song.a[key]);
}
}
},
true
);
li.appendChild(a);
list.appendChild(li);
});
PLAYLIST.appendChild(list);
SONG_LINKS = PLAYLIST.querySelectorAll("a[data-src-mp3]");
SONG_LINKS.forEach((song, index) => {
song.addEventListener("click", (e) => {
e.preventDefault();
currentSongIndex = index;
updateSong(index);
});
});
currentSongIndex = 0;
updateSong(0);
}
// ===============================
// UPDATE SONG
// ===============================
function updateSong(index) {
SONG_LINKS.forEach((song, i) => {
song.classList.toggle("activeSong", i === index);
});
const song = SONG_LINKS[index];
const src = song.getAttribute("data-src-mp3");
if (!src) {
console.warn("Invalid song URL, skipping.");
return;
}
AUDIO_PLAYER.src = src;
TRACK_NAME_DISPLAY.textContent = song.getAttribute("data-title");
AUDIO_PLAYER.play().catch(console.error);
}
// ===============================
// NEXT / PREVIOUS
// ===============================
function nextTrack() {
currentSongIndex = (currentSongIndex + 1) % SONG_LINKS.length;
updateSong(currentSongIndex);
}
function previousTrack() {
currentSongIndex = (currentSongIndex - 1 + SONG_LINKS.length) % SONG_LINKS.length;
updateSong(currentSongIndex);
}
AUDIO_PLAYER.addEventListener("ended", nextTrack);
// ===============================
// NAV BUTTONS
// ===============================
NAV_PLAY.addEventListener("click", () => AUDIO_PLAYER.play());
NAV_PAUSE.addEventListener("click", () => AUDIO_PLAYER.pause());
NAV_NEXT.addEventListener("click", nextTrack);
NAV_PREV.addEventListener("click", previousTrack);
// ===============================
// LOAD ON STARTUP
// ===============================
window.addEventListener("load", async () => {
const songs = await loadMusicData();
if (songs.length > 0) {
createAlbum({
"@id": "frutigerAeroBliss",
span: "Frutiger Aero Bliss",
small: "Music that fits well with Frutiger Aero.",
li: songs.map(song => ({ a: song }))
});
}
});