Files
manga-mass-downloader/content.js
renato97 423f8ecbc4 Fix regex pattern for page detection
Changed from:
  /^(\d+)\s+pages?$/i  (exact match only)
To:
  /(\d+)\s+pages?/i    (matches anywhere in text)

Added:
- Shows ALL text matches found
- Logs which div contains the match
- Searches in body text as fallback
- Better visibility into what text exists

This will reveal why page detection is failing!
2025-11-04 05:43:41 +00:00

890 lines
32 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Content Script para Manga Mass Downloader
// Basado en addon original - SIMPLIFICADO
(function() {
'use strict';
let selectedMangas = new Set();
let checkboxesAdded = false;
// Map para almacenar metadatos completos de manga por ID
let mangaMetadata = new Map();
// Crear popup flotante de progreso
function createFloatingProgressPopup() {
console.log('🎨 Creando popup de progreso...');
// Remover popup anterior si existe
const existingPopup = document.getElementById('mass-downloader-progress-popup');
if (existingPopup) {
console.log('🗑️ Removiendo popup anterior');
existingPopup.remove();
}
const popup = document.createElement('div');
popup.id = 'mass-downloader-progress-popup';
// Estilos inline para máxima compatibilidad
popup.style.position = 'fixed';
popup.style.top = '20px';
popup.style.right = '20px';
popup.style.width = '320px';
popup.style.background = '#667eea';
popup.style.backgroundImage = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
popup.style.color = 'white';
popup.style.padding = '20px';
popup.style.borderRadius = '12px';
popup.style.boxShadow = '0 8px 32px rgba(0,0,0,0.5)';
popup.style.zIndex = '999999'; // ¡Muy alto!
popup.style.fontFamily = 'Arial, sans-serif';
popup.style.display = 'block'; // Visible por defecto
popup.style.backdropFilter = 'blur(10px)';
popup.innerHTML = `
<div style="text-align: center;">
<h3 style="margin: 0 0 15px 0; font-size: 18px; font-weight: bold;">📦 Mass Downloader</h3>
<!-- Panel de control (cuando no está descargando) -->
<div id="control-panel" style="display: block;">
<div style="font-size: 12px; margin-bottom: 10px; opacity: 0.9;">
Seleccionados: <span id="selected-count">0</span>
</div>
<button id="btn-download-selected" style="width: 100%; padding: 10px; margin: 5px 0; background: #4CAF50; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: bold;">⬇️ Descargar Seleccionados</button>
<button id="btn-download-all" style="width: 100%; padding: 10px; margin: 5px 0; background: #2196F3; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: bold;">📚 Descargar TODOS</button>
<button id="btn-clear-selection" style="width: 100%; padding: 10px; margin: 5px 0; background: #ff9800; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: bold;">🗑️ Limpiar Selección</button>
<button id="btn-debug-pages" style="width: 100%; padding: 10px; margin: 5px 0; background: #9C27B0; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: bold; font-size: 11px;">🔍 Debug: Contar Páginas</button>
</div>
<!-- Panel de progreso (cuando está descargando) -->
<div id="progress-panel" style="display: none;">
<div id="progress-title" style="font-size: 14px; font-weight: bold; margin: 10px 0;">Preparando...</div>
<div style="background: rgba(255,255,255,0.4); height: 12px; border-radius: 6px; overflow: hidden;">
<div id="progress-bar-fill" style="height: 100%; width: 0%; background: white; transition: width 0.3s ease;"></div>
</div>
<div style="display: flex; justify-content: space-between; margin-top: 8px; font-size: 12px; font-weight: bold;">
<span id="progress-count">0 / 0</span>
<span id="progress-percent">0%</span>
</div>
<div id="progress-status" style="margin-top: 10px; font-size: 11px; opacity: 0.9;"></div>
</div>
</div>
`;
// Agregar event listeners a los botones
setTimeout(() => {
const btnDownloadSelected = document.getElementById('btn-download-selected');
const btnDownloadAll = document.getElementById('btn-download-all');
const btnClearSelection = document.getElementById('btn-clear-selection');
const btnDebugPages = document.getElementById('btn-debug-pages');
if (btnDownloadSelected) {
btnDownloadSelected.addEventListener('click', (e) => {
console.log('🎯 BUTTON CLICKED: Descargar Seleccionados');
console.log('📊 selectedMangas Set contents:', selectedMangas);
console.log('📊 selectedMangas size:', selectedMangas.size);
downloadSelectedMangas();
});
} else {
console.error('❌ btnDownloadSelected not found!');
}
if (btnDownloadAll) {
btnDownloadAll.addEventListener('click', (e) => {
console.log('🎯 BUTTON CLICKED: Descargar TODOS');
downloadAllMangas();
});
} else {
console.error('❌ btnDownloadAll not found!');
}
if (btnClearSelection) {
btnClearSelection.addEventListener('click', (e) => {
console.log('🎯 BUTTON CLICKED: Limpiar Selección');
selectedMangas.clear();
updateSelectedCount();
const countEl = document.getElementById('selected-count');
if (countEl) countEl.textContent = '0';
});
} else {
console.error('❌ btnClearSelection not found!');
}
if (btnDebugPages) {
btnDebugPages.addEventListener('click', (e) => {
console.log('🎯 BUTTON CLICKED: Debug Contar Páginas');
console.log('📝 Button element:', btnDebugPages);
try {
debugCountPagesForAllManga();
} catch (error) {
console.error('❌❌❌ Error in debugCountPagesForAllManga:', error);
console.error('Stack:', error.stack);
}
});
} else {
console.error('❌ btnDebugPages not found!');
}
// Actualizar contador inicialmente
const countEl = document.getElementById('selected-count');
if (countEl) countEl.textContent = selectedMangas.size.toString();
}, 100);
console.log('✅ Popup creado, agregando al DOM...');
document.body.appendChild(popup);
console.log('✅ Popup agregado al DOM:', popup);
return popup;
}
// Actualizar progreso
function updateProgress(current, total, title, status) {
console.log('📊 updateProgress() llamado:', { current, total, title, status });
let popup = document.getElementById('mass-downloader-progress-popup');
if (!popup) {
console.log('⚠️ Popup no existe, creando uno nuevo...');
popup = createFloatingProgressPopup();
} else {
console.log('✅ Popup existe, actualizando...');
}
const percent = total > 0 ? Math.round((current / total) * 100) : 0;
console.log(`📈 Porcentaje calculado: ${percent}%`);
// Cambiar a panel de progreso
const controlPanel = document.getElementById('control-panel');
const progressPanel = document.getElementById('progress-panel');
if (controlPanel && progressPanel) {
controlPanel.style.display = 'none';
progressPanel.style.display = 'block';
console.log('🔄 Cambiado a panel de progreso');
}
const titleEl = document.getElementById('progress-title');
const countEl = document.getElementById('progress-count');
const percentEl = document.getElementById('progress-percent');
const statusEl = document.getElementById('progress-status');
const barEl = document.getElementById('progress-bar-fill');
console.log('🔍 Elementos encontrados:', {
titleEl: !!titleEl,
countEl: !!countEl,
percentEl: !!percentEl,
statusEl: !!statusEl,
barEl: !!barEl
});
if (titleEl) {
titleEl.textContent = title || 'Descargando...';
console.log('📝 Título actualizado:', titleEl.textContent);
}
if (countEl) {
countEl.textContent = `${current} / ${total}`;
console.log('🔢 Contador actualizado:', countEl.textContent);
}
if (percentEl) {
percentEl.textContent = `${percent}%`;
console.log('📊 Porcentaje actualizado:', percentEl.textContent);
}
if (statusEl) {
statusEl.textContent = status || '';
console.log('💬 Status actualizado:', statusEl.textContent);
}
if (barEl) {
barEl.style.width = `${percent}%`;
console.log('📊 Barra actualizada:', `${percent}%`);
}
popup.style.display = 'block';
popup.style.opacity = '1';
console.log('✅ Popup visible, display:', popup.style.display);
console.log('✅ Popup en pantalla:', popup.getBoundingClientRect());
}
// Ocultar progreso
function hideProgress() {
console.log('🙈 hideProgress() llamado');
const popup = document.getElementById('mass-downloader-progress-popup');
if (popup) {
// Cambiar de vuelta al panel de control
const controlPanel = document.getElementById('control-panel');
const progressPanel = document.getElementById('progress-panel');
if (controlPanel && progressPanel) {
progressPanel.style.display = 'none';
controlPanel.style.display = 'block';
console.log('🔄 Cambiado a panel de control');
// Actualizar contador
const countEl = document.getElementById('selected-count');
if (countEl) {
countEl.textContent = selectedMangas.size.toString();
console.log('🔢 Contador actualizado:', countEl.textContent);
}
}
// NO remover el popup, solo cambiar de panel
}
}
// Escuchar mensajes del popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('📨 MENSAJE RECIBIDO:', request.action, request);
if (request.action === 'getSelectedMangas') {
// Devolver objetos completos en lugar de solo IDs
const selectedObjects = [];
selectedMangas.forEach(id => {
const mangaObj = mangaMetadata.get(id);
if (mangaObj) {
selectedObjects.push(mangaObj);
}
});
console.log('📤 Enviando mangas seleccionados:', selectedObjects.length);
sendResponse({ mangas: selectedObjects });
} else if (request.action === 'clearSelection') {
selectedMangas.clear();
updateSelectedCount();
sendResponse({ success: true });
} else if (request.action === 'getImageUrls') {
console.log('📸 Solicitando URLs de imágenes para:', request.manga.title);
getImageUrlsForManga(request.manga)
.then(imageUrls => sendResponse({ imageUrls }))
.catch(error => sendResponse({ error: error.message }));
return true;
} else if (request.action === 'extractAllMangas') {
const allMangas = extractAllMangasFromPage();
console.log('📤 Enviando todos los mangas:', allMangas.length);
sendResponse({ mangas: allMangas });
} else if (request.action === 'showProgress') {
console.log('📊 Mostrando progreso:', request);
updateProgress(request.current, request.total, request.title, request.status);
sendResponse({ success: true });
} else if (request.action === 'hideProgress') {
console.log('🙈 Ocultando progreso');
hideProgress();
sendResponse({ success: true });
} else if (request.action === 'updateSelectedCount') {
const countEl = document.getElementById('selected-count');
if (countEl) {
countEl.textContent = request.count.toString();
console.log('🔢 Contador actualizado:', countEl.textContent);
}
sendResponse({ success: true });
} else if (request.action === 'triggerDownloadSelected') {
console.log('🎯 Trigger: Descargar Seleccionados');
downloadSelectedMangas();
sendResponse({ success: true });
} else if (request.action === 'triggerDownloadAll') {
console.log('🎯 Trigger: Descargar TODOS');
downloadAllMangas();
sendResponse({ success: true });
} else {
console.log('❓ Acción desconocida:', request.action);
}
return true;
});
// Extraer TODOS los manga de la página
function extractAllMangasFromPage() {
const mangas = [];
const links = document.querySelectorAll('a[href*="/g/"]');
links.forEach(link => {
const href = link.href;
const match = href.match(/\/g\/(\d+)\/([a-f0-9]+)/);
if (match) {
const title = link.textContent.trim() || 'Untitled';
mangas.push({
id: match[1],
token: match[2],
title: title,
url: href,
baseUrl: `https://e-hentai.org/g/${match[1]}/${match[2]}/`
});
}
});
return mangas;
}
// Obtener URLs de imágenes para un manga
async function getImageUrlsForManga(manga) {
const imageUrls = [];
const baseUrl = manga.baseUrl;
try {
const response = await fetch(baseUrl, {
credentials: 'include'
});
if (!response.ok) {
throw new Error(`Error ${response.status}`);
}
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Detectar páginas - Patrón ESPECÍFICO para galerías
let actualTotalPages = 1;
console.log('🔍 Iniciando detección de páginas para:', manga.title);
// Buscar en TODOS los divs para encontrar el conteo de páginas
let foundPageCount = false;
const allDivs = doc.querySelectorAll('div');
console.log(`🔍 Buscando en ${allDivs.length} divs...`);
const potentialMatches = [];
for (let div of allDivs) {
const text = div.textContent.trim();
// Patrón específico: número seguido de "pages" o "page"
const pageMatch = text.match(/^(\d+)\s+pages?$/i);
if (pageMatch) {
const pageCount = parseInt(pageMatch[1]);
potentialMatches.push({
div: div,
text: text,
count: pageCount,
className: div.className,
id: div.id
});
console.log(`🔍 Found potential match: "${text}" -> ${pageCount} pages (class: ${div.className}, id: ${div.id})`);
// Validar que sea un número razonable (1-100 páginas)
if (pageCount > 0 && pageCount <= 100) {
actualTotalPages = pageCount;
foundPageCount = true;
console.log(`✓✅ ACCEPTED: "${text}" -> ${actualTotalPages} páginas (class: ${div.className})`);
break;
} else {
console.log(`❌ REJECTED: ${pageCount} pages (out of range 1-100)`);
}
}
}
console.log(`📊 Total potential matches found: ${potentialMatches.length}`);
if (potentialMatches.length > 0) {
console.log('📋 All matches:', potentialMatches);
}
// Si no se encontró, usar patrones alternativos
if (!foundPageCount) {
console.log('⚠️ No se encontró patrón específico, buscando alternativas...');
const pageInfo = doc.querySelector('.gpc, .gt, #gdn + span');
if (pageInfo) {
const pageText = pageInfo.textContent.trim();
console.log('🔍 Page info encontrado:', pageText);
// Patrón 1: "Showing 1 - 20 of 220 images"
let pageMatch = pageText.match(/Showing\s+1\s*-\s*\d+\s+of\s+(\d+)\s+images/i);
if (pageMatch) {
const totalImages = parseInt(pageMatch[1]);
actualTotalPages = Math.ceil(totalImages / 20);
console.log(`✓ Patrón "Showing": ${totalImages} imágenes = ${actualTotalPages} páginas`);
foundPageCount = true;
}
}
}
// FALLBACK: Solo si no se encontró nada específico
if (!foundPageCount) {
console.log('⚠️ Usando fallback (puede ser impreciso)');
const allText = doc.body.textContent;
// Buscar "Length: X pages" o similar
const lengthMatch = allText.match(/Length[:\s]+(\d+)\s*pages?/i);
if (lengthMatch) {
actualTotalPages = parseInt(lengthMatch[1]);
console.log(`✓ Fallback "Length": ${actualTotalPages} páginas`);
} else {
// Si no hay información, asumir 1 página
console.log('⚠️ No se pudo detectar página count, asumiendo 1 página');
actualTotalPages = 1;
}
}
console.log(`📄 Total páginas final a procesar: ${actualTotalPages}`);
// Procesar todas las páginas
for (let page = 1; page <= actualTotalPages; page++) {
const pageUrl = page === 1 ? baseUrl : `${baseUrl}?p=${page}`;
console.log(`📄 Procesando página ${page}/${actualTotalPages}: ${pageUrl}`);
const pageResponse = await fetch(pageUrl, {
credentials: 'include'
});
if (!pageResponse.ok) {
console.error(`❌ Error ${pageResponse.status} en página ${page}`);
continue;
}
const pageHtml = await pageResponse.text();
const pageDoc = parser.parseFromString(pageHtml, 'text/html');
const links = pageDoc.querySelectorAll('a[href*="/s/"]');
console.log(`✓ Página ${page}: Encontrados ${links.length} enlaces de imagen`);
links.forEach(link => {
const href = link.href;
if (href && href.includes('/s/')) {
imageUrls.push({
url: href,
index: imageUrls.length
});
}
});
if (page < actualTotalPages) {
await new Promise(resolve => setTimeout(resolve, 20));
}
}
console.log(`✅ Total de imágenes encontradas: ${imageUrls.length}`);
return imageUrls;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
// Agregar checkbox a enlaces de galerías
function addCheckboxes() {
console.log('\n==== addCheckboxes() INICIADO ====');
console.log('Timestamp:', new Date().toLocaleTimeString());
const existingCheckboxes = document.querySelectorAll('.mass-downloader-checkbox').length;
console.log('📊 Checkboxes existentes antes de limpiar:', existingCheckboxes);
// SOLUCIÓN DEFINITIVA: Limpiar TODOS los checkboxes existentes
document.querySelectorAll('.mass-downloader-checkbox').forEach(cb => cb.remove());
selectedMangas.clear();
console.log('🧹 Checkboxes limpiados');
// Obtener TODOS los enlaces
const allLinks = document.querySelectorAll('a[href*="/g/"]');
console.log('🔍 Total enlaces encontrados:', allLinks.length);
// Log detallado de todos los enlaces
const allLinkData = [];
allLinks.forEach((link, index) => {
const match = link.href.match(/\/g\/(\d+)\/([a-f0-9]+)/);
if (match) {
allLinkData.push({
index: index,
id: match[1],
href: link.href.substring(0, 60) + '...',
parentTag: link.parentElement.tagName,
parentClass: link.parentElement.className
});
}
});
console.log('📋 Detalle de enlaces (primeros 5):', allLinkData.slice(0, 5));
// DEDUPLICACIÓN ROBUSTA: Trackear IDs únicos durante la iteración
const seenIds = new Set();
const uniqueLinks = [];
allLinks.forEach(link => {
const match = link.href.match(/\/g\/(\d+)/);
if (match) {
const galleryId = match[1];
if (!seenIds.has(galleryId)) {
seenIds.add(galleryId);
uniqueLinks.push(link);
console.log(` ID único encontrado: ${galleryId} (href: ${link.href.substring(0, 50)}...)`);
} else {
console.log(` ⏭️ ID duplicado omitido: ${galleryId}`);
}
}
});
console.log('✅ Total IDs únicos (sin duplicados):', uniqueLinks.length);
console.log('✅ Set "seenIds" size:', seenIds.size);
// Crear checkboxes SOLO para enlaces únicos
let count = 0;
console.log('\n🎯 CREANDO CHECKBOXES:');
uniqueLinks.forEach((link, index) => {
const match = link.href.match(/\/g\/(\d+)\/([a-f0-9]+)/);
const parent = link.parentElement;
// Verificar que este parent no tenga ya un checkbox
if (parent.querySelector('.mass-downloader-checkbox')) {
console.log(` ⚠️ [${index}] Parent ya tiene checkbox, saltando...`);
return;
}
const mangaId = match ? match[1] : null;
const token = match ? match[2] : null;
const title = link.textContent.trim() || 'Untitled';
console.log(` 📝 [${index}] Creando checkbox para manga ID: ${mangaId}`);
// Guardar metadatos completos en el Map
if (mangaId && token) {
const metadata = {
id: mangaId,
token: token,
title: title,
url: link.href,
baseUrl: `https://e-hentai.org/g/${mangaId}/${token}/`
};
mangaMetadata.set(mangaId, metadata);
console.log(` 💾 Metadatos guardados para ID ${mangaId}: ${title.substring(0, 30)}...`);
}
// Crear checkbox
const container = document.createElement('div');
container.className = 'mass-downloader-checkbox';
container.style.cssText = `
position: absolute;
top: 5px;
left: 5px;
z-index: 9999;
background: rgba(0,0,0,0.8);
padding: 4px 8px;
border-radius: 4px;
`;
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.style.cssText = 'width: 16px; height: 16px;';
const label = document.createElement('label');
label.textContent = 'Select';
label.style.cssText = 'color: white; font-size: 11px; margin-left: 4px;';
checkbox.addEventListener('change', (e) => {
e.stopPropagation();
if (mangaId) {
if (checkbox.checked) {
selectedMangas.add(mangaId);
console.log(` ☑️ Manga ${mangaId} seleccionado`);
} else {
selectedMangas.delete(mangaId);
console.log(` ☐ Manga ${mangaId} deseleccionado`);
}
updateSelectedCount();
}
});
container.appendChild(checkbox);
container.appendChild(label);
// Agregar al parent
if (getComputedStyle(parent).position === 'static') {
parent.style.position = 'relative';
}
parent.appendChild(container);
count++;
console.log(` ✅ Checkbox ${count} agregado y appendeado al parent <${parent.tagName}>`);
});
console.log('\n==== RESUMEN FINAL ====');
console.log('🎉 Total checkboxes CREADOS:', count);
console.log('📊 Total checkboxes en DOM:', document.querySelectorAll('.mass-downloader-checkbox').length);
console.log('📊 Set selectedMangas size:', selectedMangas.size);
console.log('==== addCheckboxes() COMPLETADO ====\n');
checkboxesAdded = true;
}
function updateSelectedCount() {
// Actualizar contador en el control panel
const countEl = document.getElementById('selected-count');
if (countEl) {
countEl.textContent = selectedMangas.size.toString();
console.log('🔢 Control panel actualizado:', selectedMangas.size);
}
// También enviar al popup (para compatibilidad)
chrome.runtime.sendMessage({
action: 'updateSelectedCount',
count: selectedMangas.size
}).catch(() => {});
}
function addSelectAllButton() {
if (document.querySelector('.mass-downloader-select-all')) return;
const button = document.createElement('button');
button.className = 'mass-downloader-select-all';
button.textContent = 'Select All';
button.style.cssText = `
position: fixed;
bottom: 20px;
left: 20px;
padding: 10px 20px;
background: #667eea;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
z-index: 10000;
`;
let allSelected = false;
button.addEventListener('click', () => {
allSelected = !allSelected;
const checkboxes = document.querySelectorAll('.mass-downloader-checkbox input');
if (allSelected) {
checkboxes.forEach(cb => {
cb.checked = true;
const match = cb.closest('div').parentElement.querySelector('a[href*="/g/"]').href.match(/\/g\/(\d+)/);
if (match) selectedMangas.add(match[1]);
});
button.textContent = 'Deselect All';
} else {
checkboxes.forEach(cb => cb.checked = false);
selectedMangas.clear();
button.textContent = 'Select All';
}
updateSelectedCount();
});
document.body.appendChild(button);
}
// Descargar manga seleccionados
async function downloadSelectedMangas() {
console.log('\n========== 🔥 DOWNLOAD SELECTED MANGAS STARTED ==========');
console.log('🔍 Function called!');
console.log('📊 selectedMangas Set:', selectedMangas);
console.log('📊 selectedMangas size:', selectedMangas.size);
console.log('📊 mangaMetadata Map size:', mangaMetadata.size);
const selectedObjects = [];
selectedMangas.forEach(id => {
const mangaObj = mangaMetadata.get(id);
console.log(`📝 Checking ID ${id}:`, mangaObj);
if (mangaObj) {
selectedObjects.push(mangaObj);
}
});
console.log(`📦 Final selectedObjects array length: ${selectedObjects.length}`);
console.log('📦 selectedObjects contents:', selectedObjects);
if (selectedObjects.length === 0) {
console.log('❌ No manga selected, showing alert');
alert('No hay manga seleccionados. Selecciona algunos manga primero.');
return;
}
console.log(`✅ Proceeding with download of ${selectedObjects.length} manga...`);
// Descargar cada manga
console.log(`🔄 Starting download loop for ${selectedObjects.length} manga...`);
for (let i = 0; i < selectedObjects.length; i++) {
const manga = selectedObjects[i];
const title = manga.title ? manga.title.substring(0, 50) : 'Manga sin título';
console.log(`\n--- 📦 MANGA ${i + 1}/${selectedObjects.length}: ${title} ---`);
updateProgress(i, selectedObjects.length, title, `Descargando manga ${i + 1} de ${selectedObjects.length}...`);
try {
// Obtener URLs de imágenes
console.log(`🔍 Getting image URLs for manga ID: ${manga.id}`);
const imageUrls = await getImageUrlsForManga(manga);
console.log(`${manga.title}: ${imageUrls.length} imágenes encontradas`);
// Enviar al background para descarga
console.log(`📨 Sending to background script...`);
const response = await chrome.runtime.sendMessage({
action: 'downloadManga',
metadata: manga,
imageUrls: imageUrls
});
console.log(`📨 Background response:`, response);
if (!response || !response.success) {
console.error(`❌ Error descargando ${manga.title}:`, response ? response.error : 'No response');
} else {
console.log(`✅ Descargado exitosamente: ${manga.title}`);
}
} catch (error) {
console.error(`❌❌❌ EXCEPTION in manga ${manga.title}:`, error);
console.error(`Stack trace:`, error.stack);
// Continue with next manga even if this one fails
}
console.log(`--- ✅ Finished manga ${i + 1} ---\n`);
}
console.log('🔄 Download loop completed!');
updateProgress(selectedObjects.length, selectedObjects.length, '¡Completado!', 'Descarga finalizada');
setTimeout(() => {
hideProgress();
}, 2000);
}
// Descargar TODOS los manga de la página
async function downloadAllMangas() {
console.log('📥 Iniciando descarga de TODOS los manga...');
const allMangas = extractAllMangasFromPage();
if (allMangas.length === 0) {
alert('No se encontraron manga en esta página.');
return;
}
console.log(`📦 Manga encontrados: ${allMangas.length}`);
// Descargar cada manga
for (let i = 0; i < allMangas.length; i++) {
const manga = allMangas[i];
const title = manga.title ? manga.title.substring(0, 50) : 'Manga sin título';
updateProgress(i, allMangas.length, title, `Descargando manga ${i + 1} de ${allMangas.length}...`);
try {
// Obtener URLs de imágenes
const imageUrls = await getImageUrlsForManga(manga);
console.log(`${manga.title}: ${imageUrls.length} imágenes encontradas`);
// Enviar al background para descarga
const response = await chrome.runtime.sendMessage({
action: 'downloadManga',
metadata: manga,
imageUrls: imageUrls
});
if (!response.success) {
console.error(`❌ Error descargando ${manga.title}:`, response.error);
} else {
console.log(`✅ Descargado: ${manga.title}`);
}
} catch (error) {
console.error(`❌ Error en manga ${manga.title}:`, error.message);
}
}
updateProgress(allMangas.length, allMangas.length, '¡Completado!', 'Descarga finalizada');
setTimeout(() => {
hideProgress();
}, 2000);
}
// Debug: Contar páginas para todos los manga en la página
async function debugCountPagesForAllManga() {
console.log('\n========== 🔍 DEBUG: PAGE COUNT DETECTION ==========');
console.log('🔍 Scanning all manga on page...');
const allMangas = extractAllMangasFromPage();
console.log(`📦 Found ${allMangas.length} manga on page`);
const results = [];
for (let i = 0; i < allMangas.length; i++) {
const manga = allMangas[i];
console.log(`\n--- 🔍 MANGA ${i + 1}/${allMangas.length}: ${manga.title} ---`);
console.log(`🔗 URL: ${manga.baseUrl}`);
try {
const response = await fetch(manga.baseUrl, {
credentials: 'include'
});
if (!response.ok) {
console.error(`❌ Error ${response.status} fetching page`);
continue;
}
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Usar la misma lógica de detección
let detectedPages = 'UNKNOWN';
const allDivs = doc.querySelectorAll('div');
const allText = doc.body.textContent;
console.log('🔍 Searching in all divs...');
const textMatches = [];
for (let div of allDivs) {
const text = div.textContent.trim();
// Buscar CUALQUIER número seguido de "pages" o "page"
const pageMatch = text.match(/(\d+)\s+pages?/i);
if (pageMatch) {
const count = parseInt(pageMatch[1]);
textMatches.push({
text: text,
count: count,
className: div.className
});
console.log(`🔍 Found text "${text}" = ${count} pages (class: ${div.className})`);
}
}
console.log(`📊 Total text matches found: ${textMatches.length}`);
if (textMatches.length > 0) {
textMatches.forEach((match, idx) => {
console.log(` ${idx + 1}. "${match.text}" -> ${match.count} pages (class: ${match.className})`);
});
// Usar el primer match
detectedPages = textMatches[0].count;
console.log(`✅ Using: ${detectedPages} pages from "${textMatches[0].text}"`);
} else {
console.log('❌ No matches found in divs');
// Buscar en todo el texto
const bodyMatch = allText.match(/(\d+)\s+pages?/i);
if (bodyMatch) {
const count = parseInt(bodyMatch[1]);
console.log(`⚠️ Found in body text: ${count} pages`);
detectedPages = count;
} else {
console.log('❌ No page count found anywhere!');
}
}
results.push({
title: manga.title,
url: manga.baseUrl,
pages: detectedPages
});
console.log(`📊 Result: ${detectedPages} pages`);
} catch (error) {
console.error(`❌ Error processing manga:`, error);
}
}
console.log('\n========== 📊 FINAL RESULTS ==========');
results.forEach((result, idx) => {
console.log(`${idx + 1}. ${result.pages} pages - ${result.title}`);
});
console.log('========================================\n');
}
function init() {
if (window.location.href.includes('/g/')) return;
setTimeout(() => {
addCheckboxes();
addSelectAllButton();
createFloatingProgressPopup(); // Crear control panel automáticamente
}, 1000);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();