Files
rx.scoreodonto.com/dental-server/recreate-all-thumbs.js
T
VPS 4 Deploy Agent 21f33c88a4
continuous-integration/webhook Deploy concluído (VPS4)
feat(storage): reorganiza Wasabi com estrutura clinic_name/pc_name/patient_name
- Adiciona coluna clinic_name em images (ALTER TABLE IF NOT EXISTS)
- Todas as funções de storage recebem clinicName como parâmetro: saveImage,
  getImageBuffer, getImageUrl, deleteImage, getDownloadPresignedUrl, getUploadPresignedUrl
- Chave Wasabi passa de pc_name/patient/arquivo → clinic_name/pc_name/patient/arquivo
- server.js: usa socket.user.clinicName (preenchido via machine_token auth do DB) como
  fonte primária do nome da clínica nos 3 handlers de upload e na rota thumbnail
- Todos os INSERTs em images passam a gravar clinic_name
- Corrige bug oculto: wipe de clínica agora apaga o prefixo correto no Wasabi
- Scripts utilitários atualizados: backfill-wasabi-thumbs, recreate-all-thumbs, migrate-to-wasabi
- client-monitor.js: envia clinicName no client-identify (fallback para clientes legados)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:56:18 +02:00

79 lines
2.5 KiB
JavaScript

const db = require('./database');
const storage = require('./storage');
const imageProcessor = require('./image-processor');
const fetch = require('node-fetch');
async function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function run() {
console.log('🚀 Iniciando compressão EXTREMA de TODAS as miniaturas...');
await db.initDatabase();
await storage.loadConfigFromDb();
// Buscar todas as imagens que possuem miniatura
const rows = await db.all(`
SELECT id, filename, thumb_filename, clinic_name, client_name, patient_name
FROM images
WHERE thumb_filename IS NOT NULL AND enabled = 1
`);
console.log(`🔍 Encontradas ${rows.length} imagens com miniatura para otimização.`);
let successCount = 0;
let failCount = 0;
for (const row of rows) {
console.log(`\n⚙️ Otimizando miniatura do ID ${row.id}: ${row.filename}`);
try {
// 1. Obter URL de download do Wasabi (baixar a ORIGINAL, não a miniatura pesada)
const url = await storage.getDownloadPresignedUrl(row.filename, row.clinic_name, row.client_name, row.patient_name);
if (!url) {
console.error(`❌ Não foi possível gerar URL para a imagem original ${row.filename}`);
failCount++;
continue;
}
// 2. Baixar a imagem original do Wasabi
const response = await fetch(url);
if (!response.ok) {
console.error(`❌ Erro ao baixar imagem original do Wasabi (${response.status})`);
failCount++;
continue;
}
const arrayBuffer = await response.arrayBuffer();
const imageBuffer = Buffer.from(arrayBuffer);
// 3. Gerar miniatura (agora com JPEG super comprimido)
const thumbBuffer = await imageProcessor.getThumbnail(imageBuffer, 400, 400);
// 4. Salvar miniatura substituindo a antiga
await storage.saveImage(row.thumb_filename, thumbBuffer, row.clinic_name, row.client_name, row.patient_name, false);
console.log(`✅ Miniatura ultra-leve gerada e salva com sucesso para ID ${row.id} (${thumbBuffer.length} bytes)`);
successCount++;
// Aguardar 500ms
await delay(500);
} catch (err) {
console.error(`❌ Erro ao processar ID ${row.id}:`, err.message);
failCount++;
}
}
console.log(`\n🎉 Processamento concluído!`);
console.log(`✅ Sucessos: ${successCount}`);
console.log(`❌ Falhas: ${failCount}`);
process.exit(0);
}
run().catch(err => {
console.error('❌ Erro crítico:', err);
process.exit(1);
});