const db = require('./database'); const storage = require('./storage'); const sharp = require('sharp'); // Limit of concurrency const CONCURRENCY = 15; async function runBackfill() { console.log('🚀 Iniciando backfill de thumbnails concorrido...'); // 1. Inicializar banco de dados await db.initDatabase(); console.log('✅ Banco de dados inicializado.'); // 2. Carregar configurações do Wasabi a partir do banco await storage.loadConfigFromDb(); console.log('✅ Configuração do Wasabi carregada.'); // 3. Buscar todas as imagens que não possuem thumb_filename const query = "SELECT id, filename, client_name, patient_name FROM images WHERE (thumb_filename IS NULL OR thumb_filename = '') AND enabled = 1"; const images = await db.all(query); console.log(`🔎 Encontradas ${images.length} imagens pendentes de thumbnail.`); let successCount = 0; let failCount = 0; // Worker function to process a single image async function processImage(img) { try { // a. Baixar imagem original do Wasabi const buffer = await storage.getImageBuffer(img.filename, img.client_name, img.patient_name, false); if (!buffer) { throw new Error(`Não foi possível obter o buffer para ${img.filename}`); } // b. Gerar thumbnail WebP const thumbBuffer = await sharp(buffer) .resize({ width: 400, height: 400, fit: 'inside', withoutEnlargement: true }) .webp({ quality: 80, effort: 4 }) .toBuffer(); // c. Salvar thumbnail no Wasabi const thumbFilename = `thumb_${Date.now()}_${img.id}.webp`; await storage.saveImage(thumbFilename, thumbBuffer, img.client_name, img.patient_name, false); // d. Atualizar no banco de dados await db.run('UPDATE images SET thumb_filename = ? WHERE id = ?', [thumbFilename, img.id]); console.log(`✅ [ID ${img.id}] Thumbnail salvo com sucesso: ${thumbFilename} (Paciente: ${img.patient_name})`); successCount++; } catch (err) { console.error(`❌ [ID ${img.id}] Erro no processamento da imagem:`, err.message); failCount++; } } // Concurrency queue const queue = [...images]; const workers = []; async function worker() { while (queue.length > 0) { const img = queue.shift(); if (!img) break; await processImage(img); } } // Start workers for (let i = 0; i < Math.min(CONCURRENCY, images.length); i++) { workers.push(worker()); } // Wait for all to complete await Promise.all(workers); console.log('\n========================================='); console.log('📊 Resumo do Backfill Concorrido:'); console.log(`- Sucesso: ${successCount}`); console.log(`- Falhas : ${failCount}`); console.log('========================================='); process.exit(0); } runBackfill().catch(err => { console.error('❌ Erro fatal no script de backfill:', err); process.exit(1); });