const bookId = window.location.pathname.split('/').pop(); let allChapters = []; // Stores all fetched chapters let filteredChapters = []; // Stores currently displayed chapters (filtered) let currentPage = 1; const itemsPerPage = 12; async function init() { try { // 1. Load Metadata const res = await fetch(`/api/book/${bookId}`); const data = await res.json(); if (data.error) { const titleEl = document.getElementById('title'); if (titleEl) titleEl.innerText = "Book Not Found"; return; } // Populate Hero Elements const title = data.title.english || data.title.romaji; document.title = `${title} | StreamFlow Books`; const titleEl = document.getElementById('title'); if (titleEl) titleEl.innerText = title; const descEl = document.getElementById('description'); if (descEl) descEl.innerHTML = data.description || "No description available."; const scoreEl = document.getElementById('score'); if (scoreEl) scoreEl.innerText = (data.averageScore || '?') + '% Score'; const pubEl = document.getElementById('published-date'); if (pubEl) { if (data.startDate && data.startDate.year) { const y = data.startDate.year; const m = data.startDate.month ? `-${data.startDate.month.toString().padStart(2, '0')}` : ''; const d = data.startDate.day ? `-${data.startDate.day.toString().padStart(2, '0')}` : ''; pubEl.innerText = `${y}${m}${d}`; } else { pubEl.innerText = '????'; } } const statusEl = document.getElementById('status'); if (statusEl) statusEl.innerText = data.status || 'Unknown'; const formatEl = document.getElementById('format'); if (formatEl) formatEl.innerText = data.format || 'MANGA'; const chaptersEl = document.getElementById('chapters'); if (chaptersEl) chaptersEl.innerText = data.chapters || '?'; const genresEl = document.getElementById('genres'); if(genresEl && data.genres) { genresEl.innerText = data.genres.slice(0, 3).join(' • '); } const img = data.coverImage.extraLarge || data.coverImage.large; const posterEl = document.getElementById('poster'); if (posterEl) posterEl.src = img; const heroBgEl = document.getElementById('hero-bg'); if (heroBgEl) heroBgEl.src = data.bannerImage || img; // 2. Load Chapters loadChapters(); } catch (err) { console.error("Metadata Error:", err); } } async function loadChapters() { const tbody = document.getElementById('chapters-body'); if (!tbody) return; tbody.innerHTML = 'Searching extensions for chapters...'; try { const res = await fetch(`/api/book/${bookId}/chapters`); const data = await res.json(); allChapters = data.chapters || []; filteredChapters = [...allChapters]; // Initially, show all const totalEl = document.getElementById('total-chapters'); if (allChapters.length === 0) { tbody.innerHTML = 'No chapters found on loaded extensions.'; if (totalEl) totalEl.innerText = "0 Found"; return; } if (totalEl) totalEl.innerText = `${allChapters.length} Found`; // Populate Provider Filter populateProviderFilter(); // Read Button Action (Start at filtered Ch 1) const readBtn = document.getElementById('read-start-btn'); if (readBtn && filteredChapters.length > 0) { readBtn.onclick = () => openReader(filteredChapters[0].id); } renderTable(); } catch (err) { tbody.innerHTML = 'Error loading chapters.'; console.error(err); } } function populateProviderFilter() { const select = document.getElementById('provider-filter'); if (!select) return; // Extract unique providers const providers = [...new Set(allChapters.map(ch => ch.provider))]; // Only show filter if there are actual providers found if (providers.length > 0) { select.style.display = 'inline-block'; // Clear existing options except "All" select.innerHTML = ''; providers.forEach(prov => { const opt = document.createElement('option'); opt.value = prov; opt.innerText = prov; select.appendChild(opt); }); // Attach Event Listener select.onchange = (e) => { const selected = e.target.value; if (selected === 'all') { filteredChapters = [...allChapters]; } else { filteredChapters = allChapters.filter(ch => ch.provider === selected); } currentPage = 1; // Reset to page 1 on filter change renderTable(); }; } } function renderTable() { const tbody = document.getElementById('chapters-body'); if (!tbody) return; tbody.innerHTML = ''; if (filteredChapters.length === 0) { tbody.innerHTML = 'No chapters match this filter.'; updatePagination(); return; } const start = (currentPage - 1) * itemsPerPage; const end = start + itemsPerPage; const pageItems = filteredChapters.slice(start, end); pageItems.forEach((ch, idx) => { const realIndex = start + idx; const row = document.createElement('tr'); row.innerHTML = ` ${ch.number} ${ch.title || 'Chapter ' + ch.number} ${ch.provider} `; tbody.appendChild(row); }); updatePagination(); } function updatePagination() { const totalPages = Math.ceil(filteredChapters.length / itemsPerPage); const pagination = document.getElementById('pagination'); if (!pagination) return; if (totalPages <= 1) { pagination.style.display = 'none'; return; } pagination.style.display = 'flex'; document.getElementById('page-info').innerText = `Page ${currentPage} of ${totalPages}`; const prevBtn = document.getElementById('prev-page'); const nextBtn = document.getElementById('next-page'); prevBtn.disabled = currentPage === 1; nextBtn.disabled = currentPage >= totalPages; prevBtn.onclick = () => { currentPage--; renderTable(); }; nextBtn.onclick = () => { currentPage++; renderTable(); }; } function openReader(bookId, chapterId, provider) { localStorage.setItem('reader_prev_url', window.location.href); const c = encodeURIComponent(chapterId); const p = encodeURIComponent(provider); window.location.href = `/read/${bookId}/${c}/${p}`; } init();