let allRotations = []; let currentIndex = 0; const ITEMS_PER_PAGE = 5; let observer; window.loadHeader(function(headerContainer) { const stageButton = headerContainer.querySelector('.menu-item.stage'); if (stageButton) { stageButton.classList.add('active'); } if (typeof CONFIG !== 'undefined') { const apiBase = CONFIG.API_BASE_URL.replace(/\/$/, ""); const logoutForm = document.getElementById("logout-form"); if (logoutForm) { logoutForm.action = apiBase + "/api/v1/spfn/logout"; const originInput = document.getElementById("logout_frontend_origin"); if (originInput) originInput.value = window.location.origin; logoutForm.addEventListener('submit', () => { sessionStorage.removeItem('user_cache'); }); } const renderData = (data) => { if (typeof data === 'string') { try { data = JSON.parse(data); } catch (e) { console.error(e); } } const nameEl = document.getElementById('mii-name'); const imgEl = document.getElementById('mii-img'); if (nameEl) { nameEl.textContent = (data.mii && data.mii.name) || data.nickname || data.user_id || data.username || "User"; } if (imgEl) { const miiBlob = (data.mii && data.mii.data) || data.mii_data; if (miiBlob) { imgEl.src = `https://mii-unsecure.ariankordi.net/miis/image.png?erri=s6u7r-rsp&data=${encodeURIComponent(miiBlob)}&type=face&width=270`; imgEl.style.display = 'block'; } } }; const cached = sessionStorage.getItem('user_cache'); if (cached) renderData(JSON.parse(cached)); fetch(apiBase + "/api/v1/me", { credentials: 'include' }) .then(res => res.ok ? res.json() : Promise.reject(res)) .then(data => { sessionStorage.setItem('user_cache', JSON.stringify(data)); renderData(data); }) .catch(err => { if (!cached) { const nameEl = document.getElementById('mii-name'); if (nameEl) nameEl.textContent = "Guest"; } console.error(err); }); } renderStages(); }); const API_URL = `${CONFIG.API_BASE_URL}/api/v1/boss`; function stageNames(stages, lang = "en-US") { return stages.map(s => s.translatedNames[lang]); } function getStageClass(stageName) { const name = stageName.toLowerCase(); if (name.includes("ancho-v")) return "sprite-ancho-v"; if (name.includes("arowana")) return "sprite-arowana"; if (name.includes("blackbelly")) return "sprite-blackbelly"; if (name.includes("bluefin")) return "sprite-bluefin"; if (name.includes("camp")) return "sprite-camp"; if (name.includes("flounder")) return "sprite-flounder"; if (name.includes("hammerhead")) return "sprite-hammerhead"; if (name.includes("kelp")) return "sprite-kelp"; if (name.includes("mahi-mahi")) return "sprite-mahi-mahi"; if (name.includes("moray")) return "sprite-moray"; if (name.includes("museum")) return "sprite-museum"; if (name.includes("piranha")) return "sprite-piranha"; if (name.includes("port")) return "sprite-port"; if (name.includes("saltspray")) return "sprite-saltspray"; if (name.includes("urchin")) return "sprite-urchin"; if (name.includes("walleye")) return "sprite-walleye"; return "sprite"; } async function fetchRotations() { try { const res = await fetch(API_URL); if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`); const data = await res.json(); const rotations = data?.pretendo?.rotations ?? {}; const timestamps = Object.keys(rotations).sort((a, b) => Number(a) - Number(b)); const result = []; for (const ts of timestamps) { const start = new Date(Number(ts)); const end = new Date(start.getTime() + 2 * 60 * 60 * 1000); const r = rotations[ts]; result.push({ turf: stageNames(r.turfStages), ranked: stageNames(r.rankedStages), ranked_mode: r.rankedMode.replace(/([a-z])([A-Z])/g, "$1 $2"), startTime: start, endTime: end, }); } return result; } catch (error) { console.error(error); return []; } } async function renderStages() { const container = document.getElementById("stages-container"); const loadingOverlay = document.getElementById("loading-overlay"); try { allRotations = await fetchRotations(); if (!allRotations.length) { container.innerHTML = `