Files
manga-mass-downloader/content.js
renato97 809d290a8a Add message listener logging
🔍 Now logs ALL messages received from popup.js:
- Logs when any message is received (with action type)
- Logs showProgress messages specifically
- Logs getSelectedMangas requests
- Logs getImageUrls requests
- Logs extractAllMangas requests
- Logs hideProgress requests

This will tell us if popup.js is actually sending messages to content script
2025-11-04 05:08:49 +00:00

519 lines
18 KiB
JavaScript
Raw 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 = '50%';
popup.style.left = '50%';
popup.style.transform = 'translate(-50%, -50%)';
popup.style.width = '450px';
popup.style.background = '#667eea';
popup.style.backgroundImage = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
popup.style.color = 'white';
popup.style.padding = '30px';
popup.style.borderRadius = '15px';
popup.style.boxShadow = '0 10px 50px rgba(0,0,0,0.6)';
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; margin-bottom: 20px;">
<h3 style="margin: 0 0 15px 0; font-size: 20px; font-weight: bold;">📦 Descargando Manga</h3>
<div id="progress-title" style="font-size: 16px; font-weight: bold; margin-bottom: 10px;">Preparando...</div>
</div>
<div style="background: rgba(255,255,255,0.4); height: 15px; border-radius: 8px; overflow: hidden; box-shadow: inset 0 2px 4px rgba(0,0,0,0.2);">
<div id="progress-bar-fill" style="height: 100%; width: 0%; background: white; transition: width 0.4s ease; box-shadow: 0 2px 8px rgba(255,255,255,0.5);"></div>
</div>
<div style="display: flex; justify-content: space-between; margin-top: 12px; font-size: 14px; font-weight: bold;">
<span id="progress-count">0 / 0</span>
<span id="progress-percent">0%</span>
</div>
<div id="progress-status" style="margin-top: 15px; font-size: 13px; text-align: center; opacity: 0.9;"></div>
`;
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}%`);
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() {
const popup = document.getElementById('mass-downloader-progress-popup');
if (popup) {
setTimeout(() => {
popup.style.opacity = '0';
popup.style.transition = 'opacity 0.5s ease';
setTimeout(() => {
popup.remove();
}, 500);
}, 1000);
}
}
// 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 {
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 - Múltiples patrones
let actualTotalPages = 1;
console.log('🔍 Iniciando detección de páginas para:', manga.title);
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`);
} else {
// Patrón 2: "5 pages" o "X pages"
pageMatch = pageText.match(/(\d+)\s+pages?/i);
if (pageMatch) {
actualTotalPages = parseInt(pageMatch[1]);
console.log(`✓ Patrón "pages": ${actualTotalPages} páginas`);
}
}
}
// Fallback: Buscar en todo el documento
if (actualTotalPages === 1) {
const allText = doc.body.textContent;
const pageMatch = allText.match(/(\d+)\s+pages?/i);
if (pageMatch) {
actualTotalPages = parseInt(pageMatch[1]);
console.log(`✓ Fallback: Encontradas ${actualTotalPages} páginas en el documento`);
} else {
console.log('⚠️ No se detectaron múltiples páginas, asumiendo 1 página');
}
}
console.log(`📄 Total páginas 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() {
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);
}
function init() {
if (window.location.href.includes('/g/')) return;
setTimeout(() => {
addCheckboxes();
addSelectAllButton();
}, 1000);
// TEST: Crear popup de prueba para verificar que funciona
console.log('🧪 Creando popup de prueba...');
setTimeout(() => {
updateProgress(1, 5, 'Prueba', 'Verificando si el popup funciona');
console.log('✅ Popup de prueba enviado');
}, 2000);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();