Now logs: - Every div that matches 'X pages' pattern - The text content of each match - The page count found - The div's className and ID - Whether it was ACCEPTED or REJECTED - All potential matches in an array - Why counts are rejected (out of range) This will show us exactly what's being detected as 213, 28, and 2832 pages!
780 lines
28 KiB
JavaScript
780 lines
28 KiB
JavaScript
// 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>
|
||
</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');
|
||
|
||
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!');
|
||
}
|
||
|
||
// 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);
|
||
}
|
||
|
||
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();
|
||
}
|
||
|
||
})();
|