lazy loading of chapters on book page
This commit is contained in:
@@ -87,15 +87,16 @@ export async function getChapters(req: any, reply: FastifyReply) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const source = req.query.source || 'anilist';
|
||||
const provider = req.query.provider;
|
||||
|
||||
const isExternal = source !== 'anilist';
|
||||
return await booksService.getChaptersForBook(id, isExternal);
|
||||
} catch {
|
||||
return await booksService.getChaptersForBook(id, isExternal, provider);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return { chapters: [] };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function getChapterContent(req: any, reply: FastifyReply) {
|
||||
try {
|
||||
const { bookId, chapter, provider } = req.params;
|
||||
|
||||
@@ -6,6 +6,8 @@ let bookSlug = null;
|
||||
let allChapters = [];
|
||||
let filteredChapters = [];
|
||||
|
||||
let availableExtensions = [];
|
||||
|
||||
const chapterPagination = Object.create(PaginationManager);
|
||||
chapterPagination.init(12, () => renderChapterTable());
|
||||
|
||||
@@ -16,7 +18,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
async function init() {
|
||||
try {
|
||||
|
||||
const urlData = URLUtils.parseEntityPath('book');
|
||||
if (!urlData) {
|
||||
showError("Book Not Found");
|
||||
@@ -29,6 +30,7 @@ async function init() {
|
||||
|
||||
await loadBookMetadata();
|
||||
|
||||
await loadAvailableExtensions();
|
||||
await loadChapters();
|
||||
|
||||
await setupAddToListButton();
|
||||
@@ -39,11 +41,23 @@ async function init() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadAvailableExtensions() {
|
||||
try {
|
||||
const res = await fetch('/api/extensions/book');
|
||||
const data = await res.json();
|
||||
availableExtensions = data.extensions || [];
|
||||
|
||||
setupProviderFilter();
|
||||
} catch (err) {
|
||||
console.error("Error fetching extensions:", err);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadBookMetadata() {
|
||||
const source = extensionName || 'anilist';
|
||||
const fetchUrl = `/api/book/${bookId}?source=${source}`;
|
||||
|
||||
const res = await fetch(fetchUrl, { headers: AuthUtils.getSimpleAuthHeaders() });
|
||||
const res = await fetch(fetchUrl);
|
||||
const data = await res.json();
|
||||
|
||||
if (data.error || !data) {
|
||||
@@ -154,17 +168,27 @@ function updateCustomAddButton() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadChapters() {
|
||||
async function loadChapters(targetProvider = null) {
|
||||
const tbody = document.getElementById('chapters-body');
|
||||
if (!tbody) return;
|
||||
|
||||
tbody.innerHTML = '<tr><td colspan="4" style="text-align:center; padding: 2rem;">Searching extensions for chapters...</td></tr>';
|
||||
// Si no se pasa provider, intentamos pillar el del select o el primero disponible
|
||||
if (!targetProvider) {
|
||||
const select = document.getElementById('provider-filter');
|
||||
targetProvider = select ? select.value : (availableExtensions[0] || 'all');
|
||||
}
|
||||
|
||||
tbody.innerHTML = '<tr><td colspan="4" style="text-align:center; padding: 2rem;">Searching extension for chapters...</td></tr>';
|
||||
|
||||
try {
|
||||
const source = extensionName || 'anilist';
|
||||
const fetchUrl = `/api/book/${bookId}/chapters?source=${source}`;
|
||||
// Añadimos el query param 'provider' para que el backend filtre
|
||||
let fetchUrl = `/api/book/${bookId}/chapters?source=${source}`;
|
||||
if (targetProvider !== 'all') {
|
||||
fetchUrl += `&provider=${targetProvider}`;
|
||||
}
|
||||
|
||||
const res = await fetch(fetchUrl, { headers: AuthUtils.getSimpleAuthHeaders() });
|
||||
const res = await fetch(fetchUrl);
|
||||
const data = await res.json();
|
||||
|
||||
allChapters = data.chapters || [];
|
||||
@@ -175,18 +199,17 @@ async function loadChapters() {
|
||||
const totalEl = document.getElementById('total-chapters');
|
||||
|
||||
if (allChapters.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" style="text-align:center; padding: 2rem;">No chapters found on loaded extensions.</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="4" style="text-align:center; padding: 2rem;">No chapters found.</td></tr>';
|
||||
if (totalEl) totalEl.innerText = "0 Found";
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalEl) totalEl.innerText = `${allChapters.length} Found`;
|
||||
|
||||
setupProviderFilter();
|
||||
|
||||
setupReadButton();
|
||||
|
||||
chapterPagination.setTotalItems(filteredChapters.length);
|
||||
chapterPagination.reset();
|
||||
renderChapterTable();
|
||||
|
||||
} catch (err) {
|
||||
@@ -211,44 +234,31 @@ function applyChapterFilter() {
|
||||
|
||||
function setupProviderFilter() {
|
||||
const select = document.getElementById('provider-filter');
|
||||
if (!select) return;
|
||||
|
||||
const providers = [...new Set(allChapters.map(ch => ch.provider))];
|
||||
|
||||
if (providers.length === 0) return;
|
||||
if (!select || availableExtensions.length === 0) return;
|
||||
|
||||
select.style.display = 'inline-block';
|
||||
select.innerHTML = '<option value="all">All Providers</option>';
|
||||
select.innerHTML = '';
|
||||
|
||||
providers.forEach(prov => {
|
||||
const allOpt = document.createElement('option');
|
||||
allOpt.value = 'all';
|
||||
allOpt.innerText = 'Load All (Slower)';
|
||||
select.appendChild(allOpt);
|
||||
|
||||
availableExtensions.forEach(ext => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = prov;
|
||||
opt.innerText = prov;
|
||||
opt.value = ext;
|
||||
opt.innerText = ext.charAt(0).toUpperCase() + ext.slice(1);
|
||||
select.appendChild(opt);
|
||||
});
|
||||
|
||||
if (extensionName) {
|
||||
const extensionProvider = providers.find(
|
||||
p => p.toLowerCase() === extensionName.toLowerCase()
|
||||
);
|
||||
|
||||
if (extensionProvider) {
|
||||
select.value = extensionProvider;
|
||||
filteredChapters = allChapters.filter(ch => ch.provider === extensionProvider);
|
||||
}
|
||||
if (extensionName && availableExtensions.includes(extensionName)) {
|
||||
select.value = extensionName;
|
||||
} else if (availableExtensions.length > 0) {
|
||||
select.value = availableExtensions[0];
|
||||
}
|
||||
|
||||
select.onchange = (e) => {
|
||||
const selected = e.target.value;
|
||||
if (selected === 'all') {
|
||||
filteredChapters = [...allChapters];
|
||||
} else {
|
||||
filteredChapters = allChapters.filter(ch => ch.provider === selected);
|
||||
}
|
||||
|
||||
chapterPagination.reset();
|
||||
chapterPagination.setTotalItems(filteredChapters.length);
|
||||
renderChapterTable();
|
||||
select.onchange = () => {
|
||||
loadChapters(select.value);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user