90 lines
2.9 KiB
JavaScript
90 lines
2.9 KiB
JavaScript
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);
|
|
});
|