let animeData = null; let extensionName = null; let animeId = null; const episodePagination = Object.create(PaginationManager); episodePagination.init(12, renderEpisodes); YouTubePlayerUtils.init('player'); document.addEventListener('DOMContentLoaded', () => { loadAnime(); setupDescriptionModal(); setupEpisodeSearch(); }); async function loadAnime() { try { const urlData = URLUtils.parseEntityPath('anime'); if (!urlData) { showError("Invalid URL"); return; } extensionName = urlData.extensionName; animeId = urlData.entityId; const fetchUrl = extensionName ? `/api/anime/${animeId}?source=${extensionName}` : `/api/anime/${animeId}?source=anilist`; const res = await fetch(fetchUrl, { headers: AuthUtils.getSimpleAuthHeaders() }); const data = await res.json(); if (data.error) { showError("Anime Not Found"); return; } animeData = data; const metadata = MediaMetadataUtils.formatAnimeData(data, !!extensionName); updatePageTitle(metadata.title); updateMetadata(metadata); updateDescription(data.description || data.summary); updateCharacters(metadata.characters); updateExtensionPill(); setupWatchButton(); const hasTrailer = YouTubePlayerUtils.playTrailer( metadata.trailer, 'player', metadata.banner ); setupEpisodes(metadata.episodes); await setupAddToListButton(); } catch (err) { console.error('Error loading anime:', err); showError("Error loading anime"); } } function updatePageTitle(title) { document.title = `${title} | WaifuBoard`; document.getElementById('title').innerText = title; } function updateMetadata(metadata) { if (metadata.poster) { document.getElementById('poster').src = metadata.poster; } document.getElementById('score').innerText = `${metadata.score}% Score`; document.getElementById('year').innerText = metadata.year; document.getElementById('genres').innerText = metadata.genres; document.getElementById('format').innerText = metadata.format; document.getElementById('status').innerText = metadata.status; document.getElementById('season').innerText = metadata.season; document.getElementById('studio').innerText = metadata.studio; document.getElementById('episodes').innerText = metadata.episodes; } function updateDescription(rawDescription) { const desc = MediaMetadataUtils.truncateDescription(rawDescription, 4); document.getElementById('description-preview').innerHTML = desc.short; document.getElementById('full-description').innerHTML = desc.full; const readMoreBtn = document.getElementById('read-more-btn'); if (desc.isTruncated) { readMoreBtn.style.display = 'inline-flex'; } else { readMoreBtn.style.display = 'none'; } } function updateCharacters(characters) { const container = document.getElementById('char-list'); container.innerHTML = ''; if (characters.length > 0) { characters.forEach(char => { container.innerHTML += `
${char.name}
`; }); } else { container.innerHTML = `
No character data available
`; } } function updateExtensionPill() { const pill = document.getElementById('extension-pill'); if (!pill) return; if (extensionName) { pill.textContent = extensionName.charAt(0).toUpperCase() + extensionName.slice(1).toLowerCase(); pill.style.display = 'inline-flex'; } else { pill.style.display = 'none'; } } function setupWatchButton() { const watchBtn = document.getElementById('watch-btn'); if (watchBtn) { watchBtn.onclick = () => { const url = URLUtils.buildWatchUrl(animeId, 1, extensionName); window.location.href = url; }; } } async function setupAddToListButton() { const btn = document.getElementById('add-to-list-btn'); if (!btn || !animeData) return; ListModalManager.currentData = animeData; const entryType = ListModalManager.getEntryType(animeData); await ListModalManager.checkIfInList(animeId, extensionName || 'anilist', entryType); const tempBtn = document.querySelector('.hero-buttons .btn-blur'); if (tempBtn) { ListModalManager.updateButton('.hero-buttons .btn-blur'); } else { updateCustomAddButton(); } btn.onclick = () => ListModalManager.open(animeData, extensionName || 'anilist'); } function updateCustomAddButton() { const btn = document.getElementById('add-to-list-btn'); if (!btn) return; if (ListModalManager.isInList) { btn.innerHTML = ` In Your List `; btn.style.background = 'rgba(34, 197, 94, 0.2)'; btn.style.color = '#22c55e'; btn.style.borderColor = 'rgba(34, 197, 94, 0.3)'; } else { btn.innerHTML = '+ Add to List'; btn.style.background = null; btn.style.color = null; btn.style.borderColor = null; } } function setupEpisodes(totalEpisodes) { const limitedTotal = Math.min(Math.max(totalEpisodes, 1), 5000); episodePagination.setTotalItems(limitedTotal); renderEpisodes(); } function renderEpisodes() { const grid = document.getElementById('episodes-grid'); if (!grid) return; grid.innerHTML = ''; const range = episodePagination.getPageRange(); const start = range.start + 1; const end = range.end; for (let i = start; i <= end; i++) { createEpisodeButton(i, grid); } episodePagination.renderControls( 'pagination-controls', 'page-info', 'prev-page', 'next-page' ); } function createEpisodeButton(num, container) { const btn = document.createElement('div'); btn.className = 'episode-btn'; btn.innerText = `Ep ${num}`; btn.onclick = () => { const url = URLUtils.buildWatchUrl(animeId, num, extensionName); window.location.href = url; }; container.appendChild(btn); } function setupDescriptionModal() { const modal = document.getElementById('desc-modal'); if (!modal) return; modal.addEventListener('click', (e) => { if (e.target.id === 'desc-modal') { closeDescriptionModal(); } }); } function openDescriptionModal() { document.getElementById('desc-modal').classList.add('active'); document.body.style.overflow = 'hidden'; } function closeDescriptionModal() { document.getElementById('desc-modal').classList.remove('active'); document.body.style.overflow = ''; } function setupEpisodeSearch() { const searchInput = document.getElementById('ep-search'); if (!searchInput) return; searchInput.addEventListener('input', (e) => { const val = parseInt(e.target.value); const grid = document.getElementById('episodes-grid'); const totalEpisodes = episodePagination.totalItems; if (val > 0 && val <= totalEpisodes) { grid.innerHTML = ''; createEpisodeButton(val, grid); document.getElementById('pagination-controls').style.display = 'none'; } else if (!e.target.value) { renderEpisodes(); } else { grid.innerHTML = '
Episode not found
'; document.getElementById('pagination-controls').style.display = 'none'; } }); } function showError(message) { document.getElementById('title').innerText = message; } function saveToList() { if (!animeId) return; ListModalManager.save(animeId, extensionName || 'anilist'); } function deleteFromList() { if (!animeId) return; ListModalManager.delete(animeId, extensionName || 'anilist'); } function closeAddToListModal() { ListModalManager.close(); } window.openDescriptionModal = openDescriptionModal; window.closeDescriptionModal = closeDescriptionModal; window.changePage = (delta) => { if (delta > 0) episodePagination.nextPage(); else episodePagination.prevPage(); };