Files
manga-mass-downloader/content.js
renato97 aa45241525 Fix metadata storage for selected manga
- Added mangaMetadata Map to store full manga objects with title, token, url, baseUrl
- Modified getSelectedMangas to return full manga objects instead of just IDs
- Fixed substring error when downloading selected manga
- Enhanced checkbox creation to save metadata during initialization
- Improved logging for selection/deselection events

Resolves: Error: Cannot read properties of undefined (reading 'substring')
2025-11-04 04:32:16 +00:00

338 lines
10 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();
// Escuchar mensajes del popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
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);
}
});
sendResponse({ mangas: selectedObjects });
} else if (request.action === 'clearSelection') {
selectedMangas.clear();
updateSelectedCount();
sendResponse({ success: true });
} else if (request.action === 'getImageUrls') {
getImageUrlsForManga(request.manga)
.then(imageUrls => sendResponse({ imageUrls }))
.catch(error => sendResponse({ error: error.message }));
return true;
} else if (request.action === 'extractAllMangas') {
const allMangas = extractAllMangasFromPage();
sendResponse({ mangas: allMangas });
}
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
let actualTotalPages = 1;
const pageInfo = doc.querySelector('.gpc, .gt, #gdn + span');
if (pageInfo) {
const pageText = pageInfo.textContent.trim();
const 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);
}
}
// Procesar todas las páginas
for (let page = 1; page <= actualTotalPages; page++) {
const pageUrl = page === 1 ? baseUrl : `${baseUrl}?p=${page}`;
const pageResponse = await fetch(pageUrl, {
credentials: 'include'
});
if (!pageResponse.ok) continue;
const pageHtml = await pageResponse.text();
const pageDoc = parser.parseFromString(pageHtml, 'text/html');
const links = pageDoc.querySelectorAll('a[href*="/s/"]');
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));
}
}
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);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();