Files
rx.scoreodonto.com/dental-server/backfill-thumbs.js
T

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);
});