Initial commit: Manga Mass Downloader Chrome Extension
✨ Features: - Multi-selection checkboxes on manga listings - Batch download selected manga or all manga from page - Optimized parallel downloading (20ms delays, 5 concurrent) - Visual progress tracking - Popup UI for easy control - Fixed duplicate checkbox issue with deduplication logic 📁 Files: - manifest.json: Extension configuration - content.js: Checkbox injection & manga detection - background.js: Optimized download engine - popup.html/js: User interface - README.md: Complete documentation
This commit is contained in:
224
popup.js
Normal file
224
popup.js
Normal file
@@ -0,0 +1,224 @@
|
||||
// Popup JavaScript para Manga Mass Downloader
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const selectedCountElement = document.getElementById('selectedCount');
|
||||
const downloadSelectedBtn = document.getElementById('downloadSelected');
|
||||
const downloadAllBtn = document.getElementById('downloadAll');
|
||||
const clearSelectionBtn = document.getElementById('clearSelection');
|
||||
const progressDiv = document.getElementById('progress');
|
||||
const progressFill = document.getElementById('progressFill');
|
||||
const statusElement = document.getElementById('status');
|
||||
|
||||
let selectedMangas = [];
|
||||
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||
|
||||
// Obtener manga seleccionados del content script
|
||||
async function getSelectedMangas() {
|
||||
if (!tab.url.includes('e-hentai.org')) {
|
||||
selectedCountElement.textContent = '0';
|
||||
return [];
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
chrome.tabs.sendMessage(tab.id, { action: 'getSelectedMangas' }, (response) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error('Error:', chrome.runtime.lastError);
|
||||
selectedCountElement.textContent = '0';
|
||||
resolve([]);
|
||||
return;
|
||||
}
|
||||
|
||||
selectedMangas = response ? response.mangas : [];
|
||||
selectedCountElement.textContent = selectedMangas.length;
|
||||
resolve(selectedMangas);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Actualizar contador
|
||||
async function updateSelectedCount() {
|
||||
await getSelectedMangas();
|
||||
}
|
||||
|
||||
// Mostrar progreso
|
||||
function showProgress(current, total, status) {
|
||||
progressDiv.style.display = 'block';
|
||||
const percentage = total > 0 ? Math.round((current / total) * 100) : 0;
|
||||
progressFill.style.width = percentage + '%';
|
||||
statusElement.textContent = status || `${current}/${total}`;
|
||||
}
|
||||
|
||||
// Ocultar progreso
|
||||
function hideProgress() {
|
||||
progressDiv.style.display = 'none';
|
||||
progressFill.style.width = '0%';
|
||||
statusElement.textContent = '';
|
||||
}
|
||||
|
||||
// Descargar manga seleccionados
|
||||
downloadSelectedBtn.addEventListener('click', async () => {
|
||||
await getSelectedMangas();
|
||||
|
||||
if (selectedMangas.length === 0) {
|
||||
alert('No hay manga seleccionados. Ve a la página y selecciona algunos manga.');
|
||||
return;
|
||||
}
|
||||
|
||||
downloadSelectedBtn.disabled = true;
|
||||
downloadAllBtn.disabled = true;
|
||||
clearSelectionBtn.disabled = true;
|
||||
|
||||
showProgress(0, selectedMangas.length, 'Iniciando descargas...');
|
||||
|
||||
try {
|
||||
// Descargar cada manga secuencialmente
|
||||
for (let i = 0; i < selectedMangas.length; i++) {
|
||||
const manga = selectedMangas[i];
|
||||
showProgress(i + 1, selectedMangas.length, `Descargando: ${manga.title.substring(0, 30)}...`);
|
||||
|
||||
try {
|
||||
// Obtener URLs de imágenes
|
||||
const imageUrls = await getImageUrls(manga);
|
||||
|
||||
// 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);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error en manga ${manga.title}:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
showProgress(selectedMangas.length, selectedMangas.length, '¡Completado!');
|
||||
statusElement.className = 'status success';
|
||||
|
||||
// Limpiar selección después de 3 segundos
|
||||
setTimeout(() => {
|
||||
chrome.tabs.sendMessage(tab.id, { action: 'clearSelection' }, async () => {
|
||||
await updateSelectedCount();
|
||||
});
|
||||
}, 3000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error general:', error);
|
||||
statusElement.textContent = 'Error: ' + error.message;
|
||||
statusElement.className = 'status error';
|
||||
} finally {
|
||||
downloadSelectedBtn.disabled = false;
|
||||
downloadAllBtn.disabled = false;
|
||||
clearSelectionBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Descargar TODOS los manga de la página
|
||||
downloadAllBtn.addEventListener('click', async () => {
|
||||
if (!tab.url.includes('e-hentai.org')) {
|
||||
alert('Esta extensión solo funciona en e-hentai.org');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm('¿Descargar TODOS los manga de esta página?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
downloadSelectedBtn.disabled = true;
|
||||
downloadAllBtn.disabled = true;
|
||||
clearSelectionBtn.disabled = true;
|
||||
|
||||
showProgress(0, 100, 'Obteniendo lista de manga...');
|
||||
|
||||
try {
|
||||
// Pedir al content script que extraiga todos los manga
|
||||
const result = await new Promise((resolve) => {
|
||||
chrome.tabs.sendMessage(tab.id, { action: 'extractAllMangas' }, (response) => {
|
||||
resolve(response || { mangas: [] });
|
||||
});
|
||||
});
|
||||
|
||||
const allMangas = result.mangas || [];
|
||||
showProgress(0, allMangas.length, `Encontrados ${allMangas.length} manga`);
|
||||
|
||||
// Descargar cada manga
|
||||
for (let i = 0; i < allMangas.length; i++) {
|
||||
const manga = allMangas[i];
|
||||
showProgress(i + 1, allMangas.length, `Descargando: ${manga.title.substring(0, 30)}...`);
|
||||
|
||||
try {
|
||||
const imageUrls = await getImageUrls(manga);
|
||||
|
||||
const response = await chrome.runtime.sendMessage({
|
||||
action: 'downloadManga',
|
||||
metadata: manga,
|
||||
imageUrls: imageUrls
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
console.error(`Error descargando ${manga.title}:`, response.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error en manga ${manga.title}:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
showProgress(allMangas.length, allMangas.length, '¡Completado!');
|
||||
statusElement.className = 'status success';
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error general:', error);
|
||||
statusElement.textContent = 'Error: ' + error.message;
|
||||
statusElement.className = 'status error';
|
||||
} finally {
|
||||
downloadSelectedBtn.disabled = false;
|
||||
downloadAllBtn.disabled = false;
|
||||
clearSelectionBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Limpiar selección
|
||||
clearSelectionBtn.addEventListener('click', async () => {
|
||||
chrome.tabs.sendMessage(tab.id, { action: 'clearSelection' }, async () => {
|
||||
await updateSelectedCount();
|
||||
hideProgress();
|
||||
});
|
||||
});
|
||||
|
||||
// Obtener URLs para un manga específico
|
||||
async function getImageUrls(manga) {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.tabs.sendMessage(
|
||||
tab.id,
|
||||
{ action: 'getImageUrls', manga: manga },
|
||||
(response) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(chrome.runtime.lastError);
|
||||
return;
|
||||
}
|
||||
if (response.error) {
|
||||
reject(new Error(response.error));
|
||||
return;
|
||||
}
|
||||
resolve(response.imageUrls);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Escuchar mensajes del background
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
if (request.action === 'updateSelectedCount') {
|
||||
selectedCountElement.textContent = request.count;
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar
|
||||
updateSelectedCount();
|
||||
|
||||
// Actualizar contador cada 2 segundos
|
||||
setInterval(updateSelectedCount, 2000);
|
||||
});
|
||||
Reference in New Issue
Block a user